@sinas/sdk 0.1.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/index.cjs ADDED
@@ -0,0 +1,678 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ SinasAuthError: () => SinasAuthError,
34
+ SinasClient: () => SinasClient,
35
+ SinasError: () => SinasError,
36
+ SinasNotFoundError: () => SinasNotFoundError,
37
+ SinasPermissionError: () => SinasPermissionError,
38
+ SinasProvider: () => SinasProvider,
39
+ SinasTimeoutError: () => SinasTimeoutError,
40
+ createChat: () => createChat,
41
+ executeFunction: () => executeFunction,
42
+ executeQuery: () => executeQuery,
43
+ sendMessage: () => sendMessage,
44
+ stateDelete: () => stateDelete,
45
+ stateGet: () => stateGet,
46
+ stateList: () => stateList,
47
+ stateSet: () => stateSet,
48
+ streamMessage: () => streamMessage,
49
+ useChat: () => useChat,
50
+ useExecute: () => useExecute,
51
+ useQuery: () => useQuery,
52
+ useSinas: () => useSinas,
53
+ useStateStore: () => useStateStore
54
+ });
55
+ module.exports = __toCommonJS(src_exports);
56
+
57
+ // src/client/errors.ts
58
+ var SinasError = class extends Error {
59
+ constructor(message, status = 0, detail) {
60
+ super(message);
61
+ this.name = "SinasError";
62
+ this.status = status;
63
+ this.detail = detail || message;
64
+ }
65
+ };
66
+ var SinasAuthError = class extends SinasError {
67
+ constructor(message = "Authentication required") {
68
+ super(message, 401);
69
+ this.name = "SinasAuthError";
70
+ }
71
+ };
72
+ var SinasPermissionError = class extends SinasError {
73
+ constructor(message = "Permission denied") {
74
+ super(message, 403);
75
+ this.name = "SinasPermissionError";
76
+ }
77
+ };
78
+ var SinasNotFoundError = class extends SinasError {
79
+ constructor(resource) {
80
+ super(`${resource} not found`, 404);
81
+ this.name = "SinasNotFoundError";
82
+ }
83
+ };
84
+ var SinasTimeoutError = class extends SinasError {
85
+ constructor(message = "Request timed out") {
86
+ super(message, 408);
87
+ this.name = "SinasTimeoutError";
88
+ }
89
+ };
90
+
91
+ // src/client/SinasClient.ts
92
+ var SinasClient = class {
93
+ constructor(config) {
94
+ this.configOverride = config;
95
+ }
96
+ getConfig() {
97
+ const config = this.configOverride || window.__SINAS_CONFIG__;
98
+ if (!config) {
99
+ return {
100
+ apiBase: "",
101
+ component: { namespace: "", name: "", version: "" },
102
+ resources: {
103
+ enabledAgents: [],
104
+ enabledFunctions: [],
105
+ enabledQueries: [],
106
+ enabledComponents: [],
107
+ stateNamespacesReadonly: [],
108
+ stateNamespacesReadwrite: []
109
+ },
110
+ input: {}
111
+ };
112
+ }
113
+ return config;
114
+ }
115
+ getInput() {
116
+ return this.getConfig().input || {};
117
+ }
118
+ getAuthHeaders() {
119
+ const token = window.__SINAS_AUTH_TOKEN__;
120
+ const headers = { "Content-Type": "application/json" };
121
+ if (token) {
122
+ headers["Authorization"] = `Bearer ${token}`;
123
+ }
124
+ return headers;
125
+ }
126
+ getProxyBase() {
127
+ const config = this.getConfig();
128
+ const comp = config.component;
129
+ return `${config.apiBase}/components/${comp.namespace}/${comp.name}/proxy`;
130
+ }
131
+ async fetch(url, options = {}) {
132
+ const res = await fetch(url, {
133
+ ...options,
134
+ headers: {
135
+ ...this.getAuthHeaders(),
136
+ ...options.headers || {}
137
+ }
138
+ });
139
+ if (!res.ok) {
140
+ const body = await res.json().catch(() => ({ detail: res.statusText }));
141
+ const message = body.detail || body.message || res.statusText;
142
+ if (res.status === 401) throw new SinasAuthError(message);
143
+ if (res.status === 403) throw new SinasPermissionError(message);
144
+ if (res.status === 404) throw new SinasNotFoundError(message);
145
+ throw new SinasError(message, res.status);
146
+ }
147
+ return res;
148
+ }
149
+ };
150
+
151
+ // src/client/queries.ts
152
+ function parseRef(ref) {
153
+ const parts = ref.split("/");
154
+ if (parts.length !== 2) {
155
+ throw new Error(`Invalid query ref "${ref}": expected "namespace/name"`);
156
+ }
157
+ return [parts[0], parts[1]];
158
+ }
159
+ async function executeQuery(client, ref, input = {}) {
160
+ const [ns, name] = parseRef(ref);
161
+ const base = client.getProxyBase();
162
+ const res = await client.fetch(`${base}/queries/${ns}/${name}/execute`, {
163
+ method: "POST",
164
+ body: JSON.stringify({ input })
165
+ });
166
+ const data = await res.json();
167
+ return {
168
+ success: data.success,
169
+ operation: data.operation,
170
+ data: data.data,
171
+ rowCount: data.row_count,
172
+ affectedRows: data.affected_rows,
173
+ durationMs: data.duration_ms
174
+ };
175
+ }
176
+
177
+ // src/client/functions.ts
178
+ function parseRef2(ref) {
179
+ const parts = ref.split("/");
180
+ if (parts.length !== 2) {
181
+ throw new Error(`Invalid function ref "${ref}": expected "namespace/name"`);
182
+ }
183
+ return [parts[0], parts[1]];
184
+ }
185
+ async function executeFunction(client, ref, input = {}, timeout) {
186
+ const [ns, name] = parseRef2(ref);
187
+ const base = client.getProxyBase();
188
+ const body = { input };
189
+ if (timeout !== void 0) {
190
+ body.timeout = timeout;
191
+ }
192
+ const res = await client.fetch(`${base}/functions/${ns}/${name}/execute`, {
193
+ method: "POST",
194
+ body: JSON.stringify(body)
195
+ });
196
+ const data = await res.json();
197
+ return {
198
+ status: data.status,
199
+ executionId: data.execution_id,
200
+ result: data.result,
201
+ error: data.error
202
+ };
203
+ }
204
+
205
+ // src/client/states.ts
206
+ async function stateGet(client, ns, key) {
207
+ const base = client.getProxyBase();
208
+ const res = await client.fetch(`${base}/states/${ns}`, {
209
+ method: "POST",
210
+ body: JSON.stringify({ action: "get", key })
211
+ });
212
+ return res.json();
213
+ }
214
+ async function stateSet(client, ns, key, value, visibility = "private") {
215
+ const base = client.getProxyBase();
216
+ await client.fetch(`${base}/states/${ns}`, {
217
+ method: "POST",
218
+ body: JSON.stringify({ action: "set", key, value, visibility })
219
+ });
220
+ }
221
+ async function stateDelete(client, ns, key) {
222
+ const base = client.getProxyBase();
223
+ await client.fetch(`${base}/states/${ns}`, {
224
+ method: "POST",
225
+ body: JSON.stringify({ action: "delete", key })
226
+ });
227
+ }
228
+ async function stateList(client, ns) {
229
+ const base = client.getProxyBase();
230
+ const res = await client.fetch(`${base}/states/${ns}`, {
231
+ method: "POST",
232
+ body: JSON.stringify({ action: "list" })
233
+ });
234
+ return res.json();
235
+ }
236
+
237
+ // src/client/chat.ts
238
+ async function createChat(client, agentRef, input) {
239
+ const [ns, name] = agentRef.split("/");
240
+ if (!ns || !name) {
241
+ throw new Error(`Invalid agent ref "${agentRef}": expected "namespace/name"`);
242
+ }
243
+ const config = client.getConfig();
244
+ const res = await client.fetch(`${config.apiBase}/agents/${ns}/${name}/chats`, {
245
+ method: "POST",
246
+ body: JSON.stringify({ input: input || {} })
247
+ });
248
+ const data = await res.json();
249
+ return {
250
+ id: data.id,
251
+ agentNamespace: data.agent_namespace,
252
+ agentName: data.agent_name,
253
+ title: data.title
254
+ };
255
+ }
256
+ async function sendMessage(client, chatId, content) {
257
+ const config = client.getConfig();
258
+ const res = await client.fetch(`${config.apiBase}/chats/${chatId}/messages`, {
259
+ method: "POST",
260
+ body: JSON.stringify({ content })
261
+ });
262
+ const data = await res.json();
263
+ return {
264
+ id: data.id,
265
+ chatId: data.chat_id,
266
+ role: data.role,
267
+ content: data.content,
268
+ createdAt: data.created_at
269
+ };
270
+ }
271
+ function parseSSE(buffer) {
272
+ const chunks = [];
273
+ const lines = buffer.split("\n");
274
+ let event = "";
275
+ let data = "";
276
+ let remaining = "";
277
+ for (let i = 0; i < lines.length; i++) {
278
+ const line = lines[i];
279
+ if (i === lines.length - 1 && !buffer.endsWith("\n")) {
280
+ remaining = line;
281
+ break;
282
+ }
283
+ if (line.startsWith("event:")) {
284
+ event = line.slice(6).trim();
285
+ } else if (line.startsWith("data:")) {
286
+ data = line.slice(5).trim();
287
+ } else if (line === "") {
288
+ if (event || data) {
289
+ chunks.push({ event: event || "message", data });
290
+ event = "";
291
+ data = "";
292
+ }
293
+ }
294
+ }
295
+ return { chunks, remaining };
296
+ }
297
+ function streamMessage(client, chatId, content, onChunk, onDone, onError) {
298
+ const controller = new AbortController();
299
+ const config = client.getConfig();
300
+ (async () => {
301
+ try {
302
+ const res = await fetch(`${config.apiBase}/chats/${chatId}/messages/stream`, {
303
+ method: "POST",
304
+ headers: client.getAuthHeaders(),
305
+ body: JSON.stringify({ content }),
306
+ signal: controller.signal
307
+ });
308
+ if (!res.ok) {
309
+ const body = await res.json().catch(() => ({ detail: res.statusText }));
310
+ throw new Error(body.detail || "Stream request failed");
311
+ }
312
+ const reader = res.body.getReader();
313
+ const decoder = new TextDecoder();
314
+ let buffer = "";
315
+ while (true) {
316
+ const { done, value } = await reader.read();
317
+ if (done) break;
318
+ buffer += decoder.decode(value, { stream: true });
319
+ const { chunks, remaining } = parseSSE(buffer);
320
+ buffer = remaining;
321
+ for (const chunk of chunks) {
322
+ onChunk(chunk);
323
+ if (chunk.event === "done") {
324
+ onDone?.();
325
+ return;
326
+ }
327
+ }
328
+ }
329
+ if (buffer.trim()) {
330
+ const { chunks } = parseSSE(buffer + "\n\n");
331
+ for (const chunk of chunks) {
332
+ onChunk(chunk);
333
+ }
334
+ }
335
+ onDone?.();
336
+ } catch (err) {
337
+ if (err.name === "AbortError") return;
338
+ onError?.(err);
339
+ }
340
+ })();
341
+ return controller;
342
+ }
343
+
344
+ // src/hooks/useQuery.ts
345
+ var import_react2 = __toESM(require("react"), 1);
346
+
347
+ // src/hooks/context.ts
348
+ var import_react = __toESM(require("react"), 1);
349
+ var SinasContext = import_react.default.createContext(null);
350
+ function SinasProvider({ client, children }) {
351
+ const value = import_react.default.useMemo(() => client || new SinasClient(), [client]);
352
+ return import_react.default.createElement(SinasContext.Provider, { value }, children);
353
+ }
354
+ function useClient() {
355
+ const client = import_react.default.useContext(SinasContext);
356
+ if (client) return client;
357
+ return defaultClient;
358
+ }
359
+ var defaultClient = new SinasClient();
360
+
361
+ // src/hooks/useQuery.ts
362
+ function useQuery(ref, input = {}, options = {}) {
363
+ const client = useClient();
364
+ const { enabled = true, refetchInterval = null } = options;
365
+ const [data, setData] = import_react2.default.useState(null);
366
+ const [loading, setLoading] = import_react2.default.useState(false);
367
+ const [error, setError] = import_react2.default.useState(null);
368
+ const [rowCount, setRowCount] = import_react2.default.useState(null);
369
+ const abortRef = import_react2.default.useRef(null);
370
+ const inputJson = JSON.stringify(input);
371
+ const execute = import_react2.default.useCallback(
372
+ async (overrideInput) => {
373
+ abortRef.current?.abort();
374
+ const controller = new AbortController();
375
+ abortRef.current = controller;
376
+ setLoading(true);
377
+ setError(null);
378
+ try {
379
+ const result = await executeQuery(
380
+ client,
381
+ ref,
382
+ overrideInput || JSON.parse(inputJson)
383
+ );
384
+ if (!controller.signal.aborted) {
385
+ setData(result.data || null);
386
+ setRowCount(result.rowCount ?? result.affectedRows ?? null);
387
+ }
388
+ return result;
389
+ } catch (e) {
390
+ if (!controller.signal.aborted) {
391
+ setError(e.message);
392
+ }
393
+ } finally {
394
+ if (!controller.signal.aborted) {
395
+ setLoading(false);
396
+ }
397
+ }
398
+ },
399
+ [client, ref, inputJson]
400
+ );
401
+ import_react2.default.useEffect(() => {
402
+ if (enabled) {
403
+ execute();
404
+ }
405
+ return () => {
406
+ abortRef.current?.abort();
407
+ };
408
+ }, [enabled, execute]);
409
+ import_react2.default.useEffect(() => {
410
+ if (refetchInterval && enabled) {
411
+ const id = setInterval(execute, refetchInterval);
412
+ return () => clearInterval(id);
413
+ }
414
+ }, [refetchInterval, enabled, execute]);
415
+ return { data, loading, error, rowCount, refetch: execute };
416
+ }
417
+
418
+ // src/hooks/useExecute.ts
419
+ var import_react3 = __toESM(require("react"), 1);
420
+ function useExecute(ref) {
421
+ const client = useClient();
422
+ const [result, setResult] = import_react3.default.useState(null);
423
+ const [loading, setLoading] = import_react3.default.useState(false);
424
+ const [error, setError] = import_react3.default.useState(null);
425
+ const [executionId, setExecutionId] = import_react3.default.useState(null);
426
+ const execute = import_react3.default.useCallback(
427
+ async (input = {}, timeout) => {
428
+ setLoading(true);
429
+ setError(null);
430
+ try {
431
+ const data = await executeFunction(client, ref, input, timeout);
432
+ setResult(data.result);
433
+ setExecutionId(data.executionId);
434
+ if (data.status === "error") {
435
+ setError(data.error || "Function execution failed");
436
+ } else if (data.status === "timeout") {
437
+ setError("Function execution timed out");
438
+ }
439
+ return data;
440
+ } catch (e) {
441
+ setError(e.message);
442
+ } finally {
443
+ setLoading(false);
444
+ }
445
+ },
446
+ [client, ref]
447
+ );
448
+ return { execute, result, loading, error, executionId };
449
+ }
450
+
451
+ // src/hooks/useStateStore.ts
452
+ var import_react4 = __toESM(require("react"), 1);
453
+ function useStateStore(ns, key) {
454
+ const client = useClient();
455
+ const [value, setValue] = import_react4.default.useState(null);
456
+ const [loading, setLoading] = import_react4.default.useState(true);
457
+ const [error, setError] = import_react4.default.useState(null);
458
+ const load = import_react4.default.useCallback(async () => {
459
+ if (!key) {
460
+ setLoading(false);
461
+ return;
462
+ }
463
+ setLoading(true);
464
+ setError(null);
465
+ try {
466
+ const result = await stateGet(client, ns, key);
467
+ if (result.found) {
468
+ setValue(result.value);
469
+ } else {
470
+ setValue(null);
471
+ }
472
+ } catch (e) {
473
+ setError(e.message);
474
+ } finally {
475
+ setLoading(false);
476
+ }
477
+ }, [client, ns, key]);
478
+ const save = import_react4.default.useCallback(
479
+ async (newValue, opts) => {
480
+ if (!key) throw new Error("Cannot save without a key");
481
+ setValue(newValue);
482
+ setError(null);
483
+ try {
484
+ await stateSet(client, ns, key, newValue, opts?.visibility);
485
+ } catch (e) {
486
+ setError(e.message);
487
+ throw e;
488
+ }
489
+ },
490
+ [client, ns, key]
491
+ );
492
+ const remove = import_react4.default.useCallback(async () => {
493
+ if (!key) throw new Error("Cannot delete without a key");
494
+ setValue(null);
495
+ setError(null);
496
+ try {
497
+ await stateDelete(client, ns, key);
498
+ } catch (e) {
499
+ setError(e.message);
500
+ throw e;
501
+ }
502
+ }, [client, ns, key]);
503
+ const list = import_react4.default.useCallback(async () => {
504
+ setError(null);
505
+ try {
506
+ return await stateList(client, ns);
507
+ } catch (e) {
508
+ setError(e.message);
509
+ }
510
+ }, [client, ns]);
511
+ import_react4.default.useEffect(() => {
512
+ load();
513
+ }, [load]);
514
+ return { value, loading, error, save, remove, refetch: load, list };
515
+ }
516
+
517
+ // src/hooks/useChat.ts
518
+ var import_react5 = __toESM(require("react"), 1);
519
+ function useChat(agentRef) {
520
+ const client = useClient();
521
+ const [chatId, setChatId] = import_react5.default.useState(null);
522
+ const [messages, setMessages] = import_react5.default.useState([]);
523
+ const [loading, setLoading] = import_react5.default.useState(false);
524
+ const [streaming, setStreaming] = import_react5.default.useState(false);
525
+ const [error, setError] = import_react5.default.useState(null);
526
+ const abortRef = import_react5.default.useRef(null);
527
+ import_react5.default.useEffect(() => {
528
+ return () => {
529
+ abortRef.current?.abort();
530
+ };
531
+ }, []);
532
+ const doCreateChat = import_react5.default.useCallback(
533
+ async (input) => {
534
+ setLoading(true);
535
+ setError(null);
536
+ try {
537
+ const result = await createChat(client, agentRef, input);
538
+ setChatId(result.id);
539
+ setMessages([]);
540
+ return result.id;
541
+ } catch (e) {
542
+ setError(e.message);
543
+ } finally {
544
+ setLoading(false);
545
+ }
546
+ },
547
+ [client, agentRef]
548
+ );
549
+ const doSendMessage = import_react5.default.useCallback(
550
+ async (content) => {
551
+ if (!chatId) {
552
+ setError("No active chat. Call createChat first.");
553
+ return;
554
+ }
555
+ setLoading(true);
556
+ setError(null);
557
+ const userMsg = {
558
+ id: `tmp-${Date.now()}`,
559
+ chatId,
560
+ role: "user",
561
+ content,
562
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
563
+ };
564
+ setMessages((prev) => [...prev, userMsg]);
565
+ try {
566
+ const msg = await sendMessage(client, chatId, content);
567
+ setMessages((prev) => [...prev, msg]);
568
+ return msg;
569
+ } catch (e) {
570
+ setError(e.message);
571
+ } finally {
572
+ setLoading(false);
573
+ }
574
+ },
575
+ [client, chatId]
576
+ );
577
+ const doStreamMessage = import_react5.default.useCallback(
578
+ (content) => {
579
+ if (!chatId) {
580
+ setError("No active chat. Call createChat first.");
581
+ return;
582
+ }
583
+ abortRef.current?.abort();
584
+ setStreaming(true);
585
+ setError(null);
586
+ const userMsg = {
587
+ id: `tmp-${Date.now()}`,
588
+ chatId,
589
+ role: "user",
590
+ content,
591
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
592
+ };
593
+ setMessages((prev) => [...prev, userMsg]);
594
+ const assistantId = `stream-${Date.now()}`;
595
+ const assistantMsg = {
596
+ id: assistantId,
597
+ chatId,
598
+ role: "assistant",
599
+ content: "",
600
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
601
+ };
602
+ setMessages((prev) => [...prev, assistantMsg]);
603
+ const controller = streamMessage(
604
+ client,
605
+ chatId,
606
+ content,
607
+ (chunk) => {
608
+ if (chunk.event === "content" || chunk.event === "message") {
609
+ setMessages(
610
+ (prev) => prev.map(
611
+ (m) => m.id === assistantId ? { ...m, content: m.content + chunk.data } : m
612
+ )
613
+ );
614
+ }
615
+ },
616
+ () => {
617
+ setStreaming(false);
618
+ },
619
+ (err) => {
620
+ setError(err.message);
621
+ setStreaming(false);
622
+ }
623
+ );
624
+ abortRef.current = controller;
625
+ return controller;
626
+ },
627
+ [client, chatId]
628
+ );
629
+ return {
630
+ chatId,
631
+ messages,
632
+ loading,
633
+ streaming,
634
+ error,
635
+ createChat: doCreateChat,
636
+ sendMessage: doSendMessage,
637
+ streamMessage: doStreamMessage
638
+ };
639
+ }
640
+
641
+ // src/hooks/useSinas.ts
642
+ function useSinas() {
643
+ const client = useClient();
644
+ return {
645
+ config: client.getConfig(),
646
+ input: client.getInput(),
647
+ client,
648
+ useQuery,
649
+ useExecute,
650
+ useStateStore,
651
+ useChat
652
+ };
653
+ }
654
+ // Annotate the CommonJS export names for ESM import in node:
655
+ 0 && (module.exports = {
656
+ SinasAuthError,
657
+ SinasClient,
658
+ SinasError,
659
+ SinasNotFoundError,
660
+ SinasPermissionError,
661
+ SinasProvider,
662
+ SinasTimeoutError,
663
+ createChat,
664
+ executeFunction,
665
+ executeQuery,
666
+ sendMessage,
667
+ stateDelete,
668
+ stateGet,
669
+ stateList,
670
+ stateSet,
671
+ streamMessage,
672
+ useChat,
673
+ useExecute,
674
+ useQuery,
675
+ useSinas,
676
+ useStateStore
677
+ });
678
+ //# sourceMappingURL=index.cjs.map