flowstack-sdk 0.2.1 → 0.2.3

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.js CHANGED
@@ -276,7 +276,25 @@ async function executeQueryWithConfig(credentials, query, workspaceId, options,
276
276
  })
277
277
  });
278
278
  if (!response.ok) {
279
- throw new Error(`Query failed: ${response.statusText}`);
279
+ let message = response.statusText || "request failed";
280
+ let code;
281
+ let body;
282
+ try {
283
+ body = await response.clone().json();
284
+ const payload = body && typeof body === "object" && "detail" in body && typeof body.detail === "object" ? body.detail : body;
285
+ if (payload && typeof payload === "object") {
286
+ code = payload.code;
287
+ message = payload.error || payload.message || payload.detail || message;
288
+ } else if (typeof payload === "string") {
289
+ message = payload;
290
+ }
291
+ } catch {
292
+ }
293
+ const err = new Error(`Query failed: ${message}`);
294
+ err.status = response.status;
295
+ err.code = code;
296
+ err.body = body;
297
+ throw err;
280
298
  }
281
299
  return response;
282
300
  }
@@ -344,6 +362,63 @@ async function deleteDocuments(credentials, collection, filter, config, layer) {
344
362
  config
345
363
  );
346
364
  }
365
+ function dmPairKey(a, b) {
366
+ return [a, b].sort().join("::");
367
+ }
368
+ function requireAppScope(config) {
369
+ const scope = config?.appScope;
370
+ if (!scope) {
371
+ throw new Error("Private messaging requires an app scope (built-app context).");
372
+ }
373
+ return scope;
374
+ }
375
+ async function listThreads(credentials, config) {
376
+ const scope = requireAppScope(config);
377
+ return flowstackFetch(
378
+ `/apps/${encodeURIComponent(scope)}/threads`,
379
+ { credentials },
380
+ config
381
+ );
382
+ }
383
+ async function listMessages(credentials, withUserKey, options, config) {
384
+ const scope = requireAppScope(config);
385
+ const params = new URLSearchParams();
386
+ params.set("with", withUserKey);
387
+ if (options?.limit) params.set("limit", String(options.limit));
388
+ if (options?.before) params.set("before", options.before);
389
+ return flowstackFetch(
390
+ `/apps/${encodeURIComponent(scope)}/messages?${params.toString()}`,
391
+ { credentials },
392
+ config
393
+ );
394
+ }
395
+ async function sendMessage(credentials, toUserKey, body, config) {
396
+ const scope = requireAppScope(config);
397
+ return flowstackFetch(
398
+ `/apps/${encodeURIComponent(scope)}/messages`,
399
+ { method: "POST", credentials, body: { to_user_key: toUserKey, body } },
400
+ config
401
+ );
402
+ }
403
+ async function openThread(credentials, withUserKey, config) {
404
+ const scope = requireAppScope(config);
405
+ const me = credentials.userId;
406
+ if (!me) throw new Error("openThread requires an authenticated user.");
407
+ const pk = dmPairKey(me, withUserKey);
408
+ return flowstackFetch(
409
+ `/apps/${encodeURIComponent(scope)}/threads/${encodeURIComponent(pk)}/consent`,
410
+ { method: "POST", credentials },
411
+ config
412
+ );
413
+ }
414
+ async function markMessageRead(credentials, messageId, config) {
415
+ const scope = requireAppScope(config);
416
+ return flowstackFetch(
417
+ `/apps/${encodeURIComponent(scope)}/messages/${encodeURIComponent(messageId)}/read`,
418
+ { method: "POST", credentials },
419
+ config
420
+ );
421
+ }
347
422
  async function invokeTool(credentials, agentName, toolName, kwargs = {}, config) {
348
423
  return flowstackFetch(
349
424
  "/tool/invoke",
@@ -6178,6 +6253,124 @@ function useConnections() {
6178
6253
  }, [credentials, config.baseUrl, config.tenantId, refresh]);
6179
6254
  return { connections, isLoading, error, connect, disconnect, refresh };
6180
6255
  }
6256
+ function useThreads(options) {
6257
+ const { credentials, config } = useFlowstack();
6258
+ const [threads, setThreads] = react.useState([]);
6259
+ const [isLoading, setIsLoading] = react.useState(false);
6260
+ const [error, setError] = react.useState(null);
6261
+ const enabled = options?.enabled !== false;
6262
+ const clientConfig = {
6263
+ baseUrl: config.baseUrl,
6264
+ tenantId: config.tenantId,
6265
+ appScope: config.appScope
6266
+ };
6267
+ const refresh = react.useCallback(async () => {
6268
+ if (!credentials || !enabled) return;
6269
+ setIsLoading(true);
6270
+ setError(null);
6271
+ try {
6272
+ const res = await listThreads(credentials, clientConfig);
6273
+ if (res.ok && res.data) {
6274
+ setThreads(res.data.threads);
6275
+ } else {
6276
+ setError(res.error || "Failed to load threads");
6277
+ }
6278
+ } catch (err) {
6279
+ setError(err?.message || "Failed to load threads");
6280
+ } finally {
6281
+ setIsLoading(false);
6282
+ }
6283
+ }, [credentials, config.baseUrl, config.tenantId, config.appScope, enabled]);
6284
+ react.useEffect(() => {
6285
+ refresh();
6286
+ }, [refresh]);
6287
+ const intervalRef = react.useRef(null);
6288
+ react.useEffect(() => {
6289
+ if (!options?.refreshInterval || !enabled) return;
6290
+ intervalRef.current = setInterval(refresh, options.refreshInterval);
6291
+ return () => {
6292
+ if (intervalRef.current) clearInterval(intervalRef.current);
6293
+ };
6294
+ }, [options?.refreshInterval, enabled, refresh]);
6295
+ const openThread2 = react.useCallback(
6296
+ async (withUserKey) => {
6297
+ if (!credentials || !withUserKey) return null;
6298
+ const res = await openThread(credentials, withUserKey, clientConfig);
6299
+ if (res.ok && res.data) {
6300
+ await refresh();
6301
+ return res.data.status;
6302
+ }
6303
+ setError(res.error || "Failed to open thread");
6304
+ return null;
6305
+ },
6306
+ // eslint-disable-next-line react-hooks/exhaustive-deps
6307
+ [credentials, config.baseUrl, config.tenantId, config.appScope, refresh]
6308
+ );
6309
+ return { threads, isLoading, error, refresh, openThread: openThread2 };
6310
+ }
6311
+ function useMessages(withUserKey, options) {
6312
+ const { credentials, config } = useFlowstack();
6313
+ const [messages, setMessages] = react.useState([]);
6314
+ const [isLoading, setIsLoading] = react.useState(false);
6315
+ const [error, setError] = react.useState(null);
6316
+ const enabled = options?.enabled !== false && !!withUserKey;
6317
+ const clientConfig = {
6318
+ baseUrl: config.baseUrl,
6319
+ tenantId: config.tenantId,
6320
+ appScope: config.appScope
6321
+ };
6322
+ const refresh = react.useCallback(async () => {
6323
+ if (!credentials || !withUserKey || !enabled) return;
6324
+ setIsLoading(true);
6325
+ setError(null);
6326
+ try {
6327
+ const res = await listMessages(
6328
+ credentials,
6329
+ withUserKey,
6330
+ { limit: options?.limit },
6331
+ clientConfig
6332
+ );
6333
+ if (res.ok && res.data) {
6334
+ setMessages(res.data.messages);
6335
+ } else {
6336
+ setError(res.error || "Failed to load messages");
6337
+ }
6338
+ } catch (err) {
6339
+ setError(err?.message || "Failed to load messages");
6340
+ } finally {
6341
+ setIsLoading(false);
6342
+ }
6343
+ }, [credentials, withUserKey, config.baseUrl, config.tenantId, config.appScope, enabled, options?.limit]);
6344
+ react.useEffect(() => {
6345
+ refresh();
6346
+ }, [refresh]);
6347
+ const intervalRef = react.useRef(null);
6348
+ react.useEffect(() => {
6349
+ if (!options?.refreshInterval || !enabled) return;
6350
+ intervalRef.current = setInterval(refresh, options.refreshInterval);
6351
+ return () => {
6352
+ if (intervalRef.current) clearInterval(intervalRef.current);
6353
+ };
6354
+ }, [options?.refreshInterval, enabled, refresh]);
6355
+ const send = react.useCallback(
6356
+ async (body) => {
6357
+ if (!credentials) throw new Error("Not authenticated");
6358
+ if (!withUserKey) throw new Error("No counterpart selected");
6359
+ if (!body || !body.trim()) return;
6360
+ setError(null);
6361
+ const res = await sendMessage(credentials, withUserKey, body, clientConfig);
6362
+ if (!res.ok) {
6363
+ const msg = res.error || "Failed to send message";
6364
+ setError(msg);
6365
+ throw new Error(msg);
6366
+ }
6367
+ await refresh();
6368
+ },
6369
+ // eslint-disable-next-line react-hooks/exhaustive-deps
6370
+ [credentials, withUserKey, config.baseUrl, config.tenantId, config.appScope, refresh]
6371
+ );
6372
+ return { messages, isLoading, error, send, refresh };
6373
+ }
6181
6374
  function normalizeVersion(raw) {
6182
6375
  return {
6183
6376
  version: raw.version || 0,
@@ -6922,7 +7115,7 @@ function useAutomations() {
6922
7115
  return;
6923
7116
  }
6924
7117
  const data = await res.json();
6925
- setAutomations(data.automations ?? []);
7118
+ setAutomations(Array.isArray(data) ? data : data.automations ?? []);
6926
7119
  } catch (e) {
6927
7120
  setError(e.message || "Failed to load automations");
6928
7121
  } finally {
@@ -7021,7 +7214,7 @@ function useAutomations() {
7021
7214
  const res = await fetch(url, { headers: headers() });
7022
7215
  if (!res.ok) return [];
7023
7216
  const data = await res.json();
7024
- return data.runs ?? [];
7217
+ return Array.isArray(data) ? data : data.runs ?? [];
7025
7218
  } catch {
7026
7219
  return [];
7027
7220
  }
@@ -8567,7 +8760,11 @@ function MermaidDiagram({ code }) {
8567
8760
  let cancelled = false;
8568
8761
  async function render() {
8569
8762
  try {
8570
- const mermaid = (await import('mermaid')).default;
8763
+ const mermaidPkg = "mermaid";
8764
+ const mermaid = (await import(
8765
+ /* @vite-ignore */
8766
+ mermaidPkg
8767
+ )).default;
8571
8768
  if (!mermaidInitialized) {
8572
8769
  mermaid.initialize({
8573
8770
  startOnLoad: false,
@@ -10663,6 +10860,7 @@ exports.deleteSite = deleteSite;
10663
10860
  exports.deleteSiteVersion = deleteSiteVersion;
10664
10861
  exports.deleteUser = deleteUser;
10665
10862
  exports.deleteUserCollection = deleteUserCollection;
10863
+ exports.dmPairKey = dmPairKey;
10666
10864
  exports.executeQuery = executeQuery;
10667
10865
  exports.executeQueryWithConfig = executeQueryWithConfig;
10668
10866
  exports.exportUserCollection = exportUserCollection;
@@ -10714,10 +10912,12 @@ exports.listDataSources = listDataSources;
10714
10912
  exports.listDatasets = listDatasets;
10715
10913
  exports.listGitHubRepos = listGitHubRepos;
10716
10914
  exports.listLibraryItems = listLibraryItems;
10915
+ exports.listMessages = listMessages;
10717
10916
  exports.listModels = listModels;
10718
10917
  exports.listReports = listReports;
10719
10918
  exports.listScripts = listScripts;
10720
10919
  exports.listSites = listSites;
10920
+ exports.listThreads = listThreads;
10721
10921
  exports.listUsers = listUsers;
10722
10922
  exports.listVisualizations = listVisualizations;
10723
10923
  exports.listWorkspaces = listWorkspaces;
@@ -10725,6 +10925,7 @@ exports.loadCredentials = loadCredentials;
10725
10925
  exports.loadMessages = loadMessages;
10726
10926
  exports.loadSelectedWorkspace = loadSelectedWorkspace;
10727
10927
  exports.login = login;
10928
+ exports.markMessageRead = markMessageRead;
10728
10929
  exports.marketingTemplate = marketingTemplate;
10729
10930
  exports.mockChatHistory = mockChatHistory;
10730
10931
  exports.mockCredentials = mockCredentials;
@@ -10737,6 +10938,7 @@ exports.mockUserActivity = mockUserActivity;
10737
10938
  exports.mockUserStats = mockUserStats;
10738
10939
  exports.mockVisualizations = mockVisualizations;
10739
10940
  exports.mockWorkspaces = mockWorkspaces;
10941
+ exports.openThread = openThread;
10740
10942
  exports.parseSSELine = parseSSELine;
10741
10943
  exports.parseSSEStream = parseSSEStream;
10742
10944
  exports.previewPiiMasking = previewPiiMasking;
@@ -10753,6 +10955,7 @@ exports.sanitizeMermaidCode = sanitizeMermaidCode;
10753
10955
  exports.saveCredentials = saveCredentials;
10754
10956
  exports.saveMessages = saveMessages;
10755
10957
  exports.saveSelectedWorkspace = saveSelectedWorkspace;
10958
+ exports.sendMessage = sendMessage;
10756
10959
  exports.setCached = setCached;
10757
10960
  exports.setCachedDatasets = setCachedDatasets;
10758
10961
  exports.setCachedReports = setCachedReports;
@@ -10793,6 +10996,7 @@ exports.useLibrary = useLibrary;
10793
10996
  exports.useLibraryConversations = useLibraryConversations;
10794
10997
  exports.useLibrarySearch = useLibrarySearch;
10795
10998
  exports.useLibraryTrash = useLibraryTrash;
10999
+ exports.useMessages = useMessages;
10796
11000
  exports.useModelPreference = useModelPreference;
10797
11001
  exports.useModels = useModels;
10798
11002
  exports.useOllamaDetection = useOllamaDetection;
@@ -10805,6 +11009,7 @@ exports.useSiteVersions = useSiteVersions;
10805
11009
  exports.useSites = useSites;
10806
11010
  exports.useSubagentInvoke = useSubagentInvoke;
10807
11011
  exports.useSubagents = useSubagents;
11012
+ exports.useThreads = useThreads;
10808
11013
  exports.useToolInvocation = useToolInvocation;
10809
11014
  exports.useUserCollections = useUserCollections;
10810
11015
  exports.useUserManagement = useUserManagement;