flowstack-sdk 0.2.1

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.
@@ -0,0 +1,977 @@
1
+ // src/api/client.ts
2
+ var DEFAULT_BASE_URL = "https://sage-api.flowstack.fun";
3
+ var DEFAULT_TENANT_ID = "";
4
+ async function flowstackFetch(endpoint, options, config) {
5
+ const { method = "GET", body, headers = {}, credentials } = options;
6
+ const baseUrl = config?.baseUrl || DEFAULT_BASE_URL;
7
+ const enforceUserScope = config?.enforceUserScope !== false;
8
+ const { apiKey, tenantId, userId } = credentials;
9
+ if (enforceUserScope && !userId) {
10
+ console.error("[FlowstackClient] CRITICAL: No user ID provided!");
11
+ throw new Error("SECURITY: User ID is required for all API requests.");
12
+ }
13
+ const url = new URL(`${baseUrl}${endpoint}`);
14
+ if (method === "GET" && userId) {
15
+ url.searchParams.set("user_id", userId);
16
+ }
17
+ const requestHeaders = {
18
+ "Authorization": `Bearer ${apiKey}`,
19
+ "X-Tenant-ID": tenantId || config?.tenantId || DEFAULT_TENANT_ID,
20
+ "X-User-ID": userId || "",
21
+ ...headers
22
+ };
23
+ if (body && !requestHeaders["Content-Type"]) {
24
+ requestHeaders["Content-Type"] = "application/json";
25
+ }
26
+ try {
27
+ const response = await fetch(url.toString(), {
28
+ method,
29
+ headers: requestHeaders,
30
+ body: body ? JSON.stringify(body) : void 0
31
+ });
32
+ if (!response.ok) {
33
+ const errorText = await response.text();
34
+ console.error(`[FlowstackClient] Error ${response.status}:`, errorText);
35
+ return {
36
+ ok: false,
37
+ status: response.status,
38
+ error: errorText
39
+ };
40
+ }
41
+ const data = await response.json();
42
+ return {
43
+ ok: true,
44
+ status: response.status,
45
+ data
46
+ };
47
+ } catch (error) {
48
+ console.error("[FlowstackClient] Request failed:", error);
49
+ return {
50
+ ok: false,
51
+ status: 500,
52
+ error: error instanceof Error ? error.message : "Unknown error"
53
+ };
54
+ }
55
+ }
56
+ async function listWorkspaces(credentials, limit = 50, config) {
57
+ const tenantId = credentials.tenantId || config?.tenantId || DEFAULT_TENANT_ID;
58
+ return flowstackFetch(`/tenants/${tenantId}/workspaces?limit=${limit}`, {
59
+ credentials
60
+ }, config);
61
+ }
62
+ async function createWorkspace(credentials, name, description, config) {
63
+ const tenantId = credentials.tenantId || config?.tenantId || DEFAULT_TENANT_ID;
64
+ return flowstackFetch(`/tenants/${tenantId}/workspaces`, {
65
+ method: "POST",
66
+ credentials,
67
+ body: {
68
+ name,
69
+ workspace_name: name,
70
+ description,
71
+ user_id: credentials.userId
72
+ }
73
+ }, config);
74
+ }
75
+ async function getWorkspace(credentials, workspaceId, config) {
76
+ const tenantId = credentials.tenantId || config?.tenantId || DEFAULT_TENANT_ID;
77
+ return flowstackFetch(`/tenants/${tenantId}/workspaces/${workspaceId}`, {
78
+ credentials
79
+ }, config);
80
+ }
81
+ async function listDatasets(credentials, workspaceId, config) {
82
+ const query = workspaceId ? `?workspace_id=${workspaceId}&session_id=${workspaceId}` : "";
83
+ return flowstackFetch(`/datasets${query}`, {
84
+ credentials
85
+ }, config);
86
+ }
87
+ async function getDataset(credentials, datasetName, config) {
88
+ return flowstackFetch(`/datasets/${datasetName}/download`, {
89
+ credentials
90
+ }, config);
91
+ }
92
+ async function getDatasetPreview(credentials, datasetName, workspaceId, config) {
93
+ return flowstackFetch(`/datasets/${datasetName}/preview?workspace_id=${workspaceId}&session_id=${workspaceId}&limit=50`, {
94
+ credentials
95
+ }, config);
96
+ }
97
+ async function deleteDataset(_credentials, _datasetName, _config) {
98
+ return {
99
+ ok: false,
100
+ status: 501,
101
+ error: "Dataset deletion is handled through the agent chat interface. Use the /stream endpoint to request deletion."
102
+ };
103
+ }
104
+ async function listVisualizations(credentials, workspaceId, config) {
105
+ return flowstackFetch(`/visualizations?workspace_id=${workspaceId}&session_id=${workspaceId}`, {
106
+ credentials
107
+ }, config);
108
+ }
109
+ async function listReports(credentials, workspaceId, config) {
110
+ return flowstackFetch(`/reports?workspace_id=${workspaceId}&session_id=${workspaceId}`, {
111
+ credentials
112
+ }, config);
113
+ }
114
+ async function listModels(credentials, workspaceId, config) {
115
+ return flowstackFetch(`/models?workspace_id=${workspaceId}&session_id=${workspaceId}`, {
116
+ credentials
117
+ }, config);
118
+ }
119
+ async function getModel(credentials, workspaceId, modelName, config) {
120
+ return flowstackFetch(`/models/${modelName}?workspace_id=${workspaceId}&session_id=${workspaceId}`, {
121
+ credentials
122
+ }, config);
123
+ }
124
+ async function listScripts(credentials, workspaceId, config) {
125
+ return flowstackFetch(`/scripts/detailed?workspace_id=${workspaceId}&session_id=${workspaceId}`, {
126
+ credentials
127
+ }, config);
128
+ }
129
+ async function listDataSources(credentials, config, options) {
130
+ const qs = options?.includeProvenance ? "?include_provenance=true" : "";
131
+ return flowstackFetch(`/data-sources${qs}`, {
132
+ credentials
133
+ }, config);
134
+ }
135
+ async function createDataSource(credentials, sourceConfig, config) {
136
+ return flowstackFetch("/data-sources", {
137
+ method: "POST",
138
+ credentials,
139
+ body: {
140
+ source_type: sourceConfig.type,
141
+ name: sourceConfig.name,
142
+ auth_method: sourceConfig.auth_method || "connection_string",
143
+ credentials: sourceConfig.credentials || {
144
+ connection_string: sourceConfig.connectionString
145
+ },
146
+ metadata: sourceConfig.metadata,
147
+ is_tenant_wide: sourceConfig.is_tenant_wide || false
148
+ }
149
+ }, config);
150
+ }
151
+ async function testDataSource(credentials, sourceId, config) {
152
+ return flowstackFetch(`/data-sources/${sourceId}/test`, {
153
+ method: "POST",
154
+ credentials
155
+ }, config);
156
+ }
157
+ async function deleteDataSource(credentials, sourceId, config) {
158
+ return flowstackFetch(`/data-sources/${sourceId}`, {
159
+ method: "DELETE",
160
+ credentials
161
+ }, config);
162
+ }
163
+ async function listAgents(config) {
164
+ const baseUrl = config?.baseUrl || DEFAULT_BASE_URL;
165
+ try {
166
+ const response = await fetch(`${baseUrl}/agents`, {
167
+ method: "GET",
168
+ headers: { "Accept": "application/json" }
169
+ });
170
+ if (!response.ok) {
171
+ const errorText = await response.text();
172
+ return { ok: false, status: response.status, error: errorText };
173
+ }
174
+ const data = await response.json();
175
+ return { ok: true, status: response.status, data };
176
+ } catch (error) {
177
+ return {
178
+ ok: false,
179
+ status: 500,
180
+ error: error instanceof Error ? error.message : "Failed to fetch agents"
181
+ };
182
+ }
183
+ }
184
+ async function executeQuery(credentials, query, workspaceId, options, config) {
185
+ const baseUrl = config?.baseUrl || DEFAULT_BASE_URL;
186
+ const tenantId = credentials.tenantId || config?.tenantId || DEFAULT_TENANT_ID;
187
+ const response = await fetch(`${baseUrl}/stream`, {
188
+ method: "POST",
189
+ headers: {
190
+ "Content-Type": "application/json",
191
+ "Authorization": `Bearer ${credentials.apiKey}`,
192
+ "X-Tenant-ID": tenantId,
193
+ "X-User-ID": credentials.userId || "",
194
+ "Accept": "text/event-stream"
195
+ },
196
+ body: JSON.stringify({
197
+ query,
198
+ workspace_id: workspaceId,
199
+ session_id: options?.sessionId || void 0,
200
+ force_new_session: options?.forceNewSession || void 0,
201
+ tenant_id: tenantId,
202
+ user_id: credentials.userId,
203
+ code_interpreter_network_mode: options?.networkMode || "SANDBOX",
204
+ // P0-80: capabilities replaces target_agents on the wire. Deprecated
205
+ // target_agents/target_agent are intentionally NOT forwarded — they
206
+ // were no-ops post-P0-73 and forwarding them just added noise to logs.
207
+ capabilities: options?.capabilities && options.capabilities.length > 0 ? options.capabilities : void 0
208
+ })
209
+ });
210
+ if (!response.ok) {
211
+ if (response.status === 402) {
212
+ let body = {};
213
+ try {
214
+ body = await response.json();
215
+ } catch {
216
+ }
217
+ const err = new Error(body?.message || "Out of credits \u2014 top up to continue");
218
+ err.status = 402;
219
+ err.code = "INSUFFICIENT_CREDITS";
220
+ err.body = body;
221
+ throw err;
222
+ }
223
+ let detail = response.statusText;
224
+ try {
225
+ const body = await response.json();
226
+ detail = body?.detail || body?.error || body?.message || detail;
227
+ } catch {
228
+ }
229
+ throw new Error(`Query failed: ${detail}`);
230
+ }
231
+ return response;
232
+ }
233
+ async function executeQueryWithConfig(credentials, query, workspaceId, options, config) {
234
+ const baseUrl = config?.baseUrl || DEFAULT_BASE_URL;
235
+ const tenantId = credentials.tenantId || config?.tenantId || DEFAULT_TENANT_ID;
236
+ const response = await fetch(`${baseUrl}/stream`, {
237
+ method: "POST",
238
+ headers: {
239
+ "Content-Type": "application/json",
240
+ "Authorization": `Bearer ${credentials.apiKey}`,
241
+ "X-Tenant-ID": tenantId,
242
+ "X-User-ID": credentials.userId || "",
243
+ "Accept": "text/event-stream"
244
+ },
245
+ body: JSON.stringify({
246
+ query,
247
+ workspace_id: workspaceId,
248
+ session_id: options?.sessionId || void 0,
249
+ force_new_session: options?.forceNewSession || void 0,
250
+ tenant_id: tenantId,
251
+ user_id: credentials.userId,
252
+ code_interpreter_network_mode: options?.networkMode || "SANDBOX",
253
+ // P0-80: capabilities replaces target_agents on the wire.
254
+ capabilities: options?.capabilities && options.capabilities.length > 0 ? options.capabilities : void 0,
255
+ system_prompt_override: options?.systemPrompt,
256
+ tool_whitelist: options?.tools,
257
+ allowed_terms: options?.allowedTerms || void 0,
258
+ // P0-132 (G4): persona selection → target_agents. The backend persona
259
+ // resolver honors request.target_agents and otherwise auto-selects the
260
+ // first registered subagent. Only sent when a persona is requested.
261
+ target_agents: options?.persona ? [options.persona] : void 0
262
+ })
263
+ });
264
+ if (!response.ok) {
265
+ throw new Error(`Query failed: ${response.statusText}`);
266
+ }
267
+ return response;
268
+ }
269
+ async function queryCollection(credentials, collection, options, config) {
270
+ const params = new URLSearchParams();
271
+ params.set("collection", collection);
272
+ if (options?.filter) params.set("filter", JSON.stringify(options.filter));
273
+ if (options?.limit) params.set("limit", String(options.limit));
274
+ if (options?.skip) params.set("skip", String(options.skip));
275
+ if (options?.sort) params.set("sort", JSON.stringify(options.sort));
276
+ if (options?.projection) params.set("projection", JSON.stringify(options.projection));
277
+ if (options?.layer) params.set("layer", options.layer);
278
+ if (options?.includeProvenance) params.set("include_provenance", "true");
279
+ return flowstackFetch(
280
+ `/collections/query?${params.toString()}`,
281
+ { credentials },
282
+ config
283
+ );
284
+ }
285
+ async function insertDocuments(credentials, collection, documents, config, layer) {
286
+ const isArray = Array.isArray(documents);
287
+ return flowstackFetch(
288
+ "/collections/insert",
289
+ {
290
+ method: "POST",
291
+ credentials,
292
+ body: {
293
+ collection,
294
+ ...isArray ? { documents } : { document: documents },
295
+ ...layer ? { layer } : {}
296
+ }
297
+ },
298
+ config
299
+ );
300
+ }
301
+ async function updateDocuments(credentials, collection, filter, update, options, config, layer) {
302
+ return flowstackFetch(
303
+ "/collections/update",
304
+ {
305
+ method: "POST",
306
+ credentials,
307
+ body: {
308
+ collection,
309
+ filter,
310
+ update,
311
+ upsert: options?.upsert ?? false,
312
+ ...layer ? { layer } : {}
313
+ }
314
+ },
315
+ config
316
+ );
317
+ }
318
+ async function deleteDocuments(credentials, collection, filter, config, layer) {
319
+ return flowstackFetch(
320
+ "/collections/delete",
321
+ {
322
+ method: "POST",
323
+ credentials,
324
+ body: {
325
+ collection,
326
+ filter,
327
+ ...layer ? { layer } : {}
328
+ }
329
+ },
330
+ config
331
+ );
332
+ }
333
+ async function invokeTool(credentials, agentName, toolName, kwargs = {}, config) {
334
+ return flowstackFetch(
335
+ "/tool/invoke",
336
+ {
337
+ method: "POST",
338
+ credentials,
339
+ body: {
340
+ agent_name: agentName,
341
+ tool_name: toolName,
342
+ kwargs
343
+ }
344
+ },
345
+ config
346
+ );
347
+ }
348
+ async function uploadFile(credentials, workspaceId, file, name, config) {
349
+ const baseUrl = config?.baseUrl || DEFAULT_BASE_URL;
350
+ const tenantId = credentials.tenantId || config?.tenantId || DEFAULT_TENANT_ID;
351
+ const formData = new FormData();
352
+ formData.append("file", file);
353
+ formData.append("workspace_id", workspaceId);
354
+ if (name) {
355
+ formData.append("name", name);
356
+ formData.append("dataset_name", name);
357
+ }
358
+ try {
359
+ const response = await fetch(`${baseUrl}/upload`, {
360
+ method: "POST",
361
+ headers: {
362
+ "Authorization": `Bearer ${credentials.apiKey}`,
363
+ "X-Tenant-ID": tenantId,
364
+ "X-User-ID": credentials.userId || "",
365
+ "X-Session-ID": workspaceId
366
+ },
367
+ body: formData
368
+ });
369
+ if (!response.ok) {
370
+ const errorText = await response.text();
371
+ return {
372
+ ok: false,
373
+ status: response.status,
374
+ error: errorText
375
+ };
376
+ }
377
+ const data = await response.json();
378
+ return {
379
+ ok: true,
380
+ status: response.status,
381
+ data
382
+ };
383
+ } catch (error) {
384
+ return {
385
+ ok: false,
386
+ status: 500,
387
+ error: error instanceof Error ? error.message : "Upload failed"
388
+ };
389
+ }
390
+ }
391
+ async function uploadDocument(credentials, workspaceId, file, documentName, config) {
392
+ const baseUrl = config?.baseUrl || DEFAULT_BASE_URL;
393
+ const tenantId = credentials.tenantId || config?.tenantId || DEFAULT_TENANT_ID;
394
+ const formData = new FormData();
395
+ formData.append("file", file);
396
+ formData.append("workspace_id", workspaceId);
397
+ if (documentName) formData.append("document_name", documentName);
398
+ try {
399
+ const response = await fetch(`${baseUrl}/upload-document`, {
400
+ method: "POST",
401
+ headers: {
402
+ "Authorization": `Bearer ${credentials.apiKey}`,
403
+ "X-Tenant-ID": tenantId,
404
+ "X-User-ID": credentials.userId || "",
405
+ "X-Session-ID": workspaceId
406
+ },
407
+ body: formData
408
+ });
409
+ if (!response.ok) {
410
+ const errorText = await response.text();
411
+ return { ok: false, status: response.status, error: errorText };
412
+ }
413
+ const data = await response.json();
414
+ return { ok: true, status: response.status, data };
415
+ } catch (error) {
416
+ return {
417
+ ok: false,
418
+ status: 500,
419
+ error: error instanceof Error ? error.message : "Document upload failed"
420
+ };
421
+ }
422
+ }
423
+ async function login(email, password, config) {
424
+ const baseUrl = config?.baseUrl || DEFAULT_BASE_URL;
425
+ try {
426
+ const response = await fetch(`${baseUrl}/auth/user/login`, {
427
+ method: "POST",
428
+ headers: {
429
+ "Content-Type": "application/json",
430
+ ...config?.tenantId ? { "X-Tenant-ID": config.tenantId } : {}
431
+ },
432
+ body: JSON.stringify({
433
+ email,
434
+ password,
435
+ ...config?.appScope ? { app_scope: config.appScope } : {}
436
+ })
437
+ });
438
+ if (!response.ok) {
439
+ const errorText = await response.text();
440
+ return {
441
+ ok: false,
442
+ status: response.status,
443
+ error: errorText
444
+ };
445
+ }
446
+ const data = await response.json();
447
+ return {
448
+ ok: true,
449
+ status: response.status,
450
+ data
451
+ };
452
+ } catch (error) {
453
+ return {
454
+ ok: false,
455
+ status: 500,
456
+ error: error instanceof Error ? error.message : "Login failed"
457
+ };
458
+ }
459
+ }
460
+ async function register(email, password, config) {
461
+ const baseUrl = config?.baseUrl || DEFAULT_BASE_URL;
462
+ try {
463
+ const response = await fetch(`${baseUrl}/auth/user/register`, {
464
+ method: "POST",
465
+ headers: {
466
+ "Content-Type": "application/json",
467
+ ...config?.tenantId ? { "X-Tenant-ID": config.tenantId } : {}
468
+ },
469
+ body: JSON.stringify({
470
+ email,
471
+ password,
472
+ skip_email_verification: true,
473
+ ...config?.appScope ? { app_scope: config.appScope } : {}
474
+ })
475
+ });
476
+ if (!response.ok) {
477
+ const errorText = await response.text();
478
+ return {
479
+ ok: false,
480
+ status: response.status,
481
+ error: errorText
482
+ };
483
+ }
484
+ const data = await response.json();
485
+ return {
486
+ ok: true,
487
+ status: response.status,
488
+ data
489
+ };
490
+ } catch (error) {
491
+ return {
492
+ ok: false,
493
+ status: 500,
494
+ error: error instanceof Error ? error.message : "Registration failed"
495
+ };
496
+ }
497
+ }
498
+ async function googleLogin(code, redirectUri, config) {
499
+ const baseUrl = config?.baseUrl || DEFAULT_BASE_URL;
500
+ try {
501
+ const response = await fetch(`${baseUrl}/auth/google/login`, {
502
+ method: "POST",
503
+ headers: {
504
+ "Content-Type": "application/json",
505
+ ...config?.tenantId ? { "X-Tenant-ID": config.tenantId } : {}
506
+ },
507
+ body: JSON.stringify({ code, redirect_uri: redirectUri })
508
+ });
509
+ if (!response.ok) {
510
+ const errorText = await response.text();
511
+ return {
512
+ ok: false,
513
+ status: response.status,
514
+ error: errorText
515
+ };
516
+ }
517
+ const data = await response.json();
518
+ return {
519
+ ok: true,
520
+ status: response.status,
521
+ data
522
+ };
523
+ } catch (error) {
524
+ return {
525
+ ok: false,
526
+ status: 500,
527
+ error: error instanceof Error ? error.message : "Google login failed"
528
+ };
529
+ }
530
+ }
531
+ async function listUsers(credentials, params, config) {
532
+ const tenantId = credentials.tenantId || config?.tenantId || DEFAULT_TENANT_ID;
533
+ const queryParams = new URLSearchParams();
534
+ if (params?.page) queryParams.set("page", String(params.page));
535
+ if (params?.limit) queryParams.set("limit", String(params.limit));
536
+ if (params?.search) queryParams.set("search", params.search);
537
+ if (params?.role) queryParams.set("role", params.role);
538
+ if (params?.status) queryParams.set("status", params.status);
539
+ if (params?.sortBy) queryParams.set("sort_by", params.sortBy);
540
+ if (params?.sortOrder) queryParams.set("sort_order", params.sortOrder);
541
+ const queryString = queryParams.toString();
542
+ const endpoint = `/tenants/${tenantId}/users${queryString ? `?${queryString}` : ""}`;
543
+ return flowstackFetch(endpoint, { credentials }, config);
544
+ }
545
+ async function getUser(credentials, userId, config) {
546
+ const tenantId = credentials.tenantId || config?.tenantId || DEFAULT_TENANT_ID;
547
+ return flowstackFetch(`/tenants/${tenantId}/users/${userId}`, { credentials }, config);
548
+ }
549
+ async function updateUser(credentials, userId, updates, config) {
550
+ const tenantId = credentials.tenantId || config?.tenantId || DEFAULT_TENANT_ID;
551
+ return flowstackFetch(`/tenants/${tenantId}/users/${userId}`, {
552
+ method: "PATCH",
553
+ credentials,
554
+ body: updates
555
+ }, config);
556
+ }
557
+ async function deleteUser(credentials, userId, config) {
558
+ const tenantId = credentials.tenantId || config?.tenantId || DEFAULT_TENANT_ID;
559
+ return flowstackFetch(`/tenants/${tenantId}/users/${userId}`, {
560
+ method: "DELETE",
561
+ credentials
562
+ }, config);
563
+ }
564
+ async function suspendUser(credentials, userId, reason, config) {
565
+ const tenantId = credentials.tenantId || config?.tenantId || DEFAULT_TENANT_ID;
566
+ return flowstackFetch(`/tenants/${tenantId}/users/${userId}/suspend`, {
567
+ method: "POST",
568
+ credentials,
569
+ body: reason ? { reason } : void 0
570
+ }, config);
571
+ }
572
+ async function reactivateUser(credentials, userId, config) {
573
+ const tenantId = credentials.tenantId || config?.tenantId || DEFAULT_TENANT_ID;
574
+ return flowstackFetch(`/tenants/${tenantId}/users/${userId}/reactivate`, {
575
+ method: "POST",
576
+ credentials
577
+ }, config);
578
+ }
579
+ async function getUserActivity(credentials, userId, limit = 50, config) {
580
+ const tenantId = credentials.tenantId || config?.tenantId || DEFAULT_TENANT_ID;
581
+ return flowstackFetch(`/tenants/${tenantId}/users/${userId}/activity?limit=${limit}`, {
582
+ credentials
583
+ }, config);
584
+ }
585
+ async function getUserStats(credentials, config) {
586
+ const tenantId = credentials.tenantId || config?.tenantId || DEFAULT_TENANT_ID;
587
+ return flowstackFetch(`/tenants/${tenantId}/users/stats`, { credentials }, config);
588
+ }
589
+ async function checkAdminPermissions(credentials, config) {
590
+ const tenantId = credentials.tenantId || config?.tenantId || DEFAULT_TENANT_ID;
591
+ return flowstackFetch(`/tenants/${tenantId}/users/me/permissions`, { credentials }, config);
592
+ }
593
+ async function getConversationHistory(credentials, workspaceId, options, config) {
594
+ const params = new URLSearchParams();
595
+ params.set("session_id", workspaceId);
596
+ if (options?.limit) params.set("limit", String(options.limit));
597
+ if (options?.offset) params.set("offset", String(options.offset));
598
+ return flowstackFetch(
599
+ `/conversations?${params.toString()}`,
600
+ { method: "GET", credentials },
601
+ config
602
+ );
603
+ }
604
+ async function listSites(credentials, config) {
605
+ return flowstackFetch("/api/v1/sites", { method: "GET", credentials }, config);
606
+ }
607
+ async function getSite(credentials, siteId, config) {
608
+ return flowstackFetch(`/api/v1/sites/${siteId}`, { method: "GET", credentials }, config);
609
+ }
610
+ async function createSite(credentials, params, config) {
611
+ return flowstackFetch("/api/v1/sites", {
612
+ method: "POST",
613
+ credentials,
614
+ body: {
615
+ site_name: params.name,
616
+ site_type: params.siteType || "on_demand",
617
+ description: params.description,
618
+ files: params.files
619
+ }
620
+ }, config);
621
+ }
622
+ async function addSiteFile(credentials, siteId, filePath, content, config) {
623
+ return flowstackFetch(`/api/v1/sites/${siteId}/files/${filePath}`, {
624
+ method: "PUT",
625
+ credentials,
626
+ body: { content }
627
+ }, config);
628
+ }
629
+ async function publishStagedSite(credentials, siteId, config) {
630
+ return flowstackFetch(`/api/v1/sites/${siteId}/publish`, {
631
+ method: "POST",
632
+ credentials
633
+ }, config);
634
+ }
635
+ async function deleteSite(credentials, siteId, config) {
636
+ return flowstackFetch(`/api/v1/sites/${siteId}`, {
637
+ method: "DELETE",
638
+ credentials
639
+ }, config);
640
+ }
641
+ async function getSiteVersions(credentials, siteId, config) {
642
+ return flowstackFetch(`/api/v1/sites/${siteId}/versions`, {
643
+ method: "GET",
644
+ credentials
645
+ }, config);
646
+ }
647
+ async function promoteSiteVersion(credentials, siteId, version, config) {
648
+ return flowstackFetch(`/api/v1/sites/${siteId}/promote`, {
649
+ method: "POST",
650
+ credentials,
651
+ body: { version }
652
+ }, config);
653
+ }
654
+ async function deleteSiteVersion(credentials, siteId, version, config) {
655
+ return flowstackFetch(`/api/v1/sites/${siteId}/versions/${version}`, {
656
+ method: "DELETE",
657
+ credentials
658
+ }, config);
659
+ }
660
+ async function setSiteAlias(credentials, siteId, alias, config) {
661
+ return flowstackFetch(`/api/v1/sites/${siteId}/alias`, {
662
+ method: "POST",
663
+ credentials,
664
+ body: { alias }
665
+ }, config);
666
+ }
667
+ async function removeSiteAlias(credentials, siteId, config) {
668
+ return flowstackFetch(`/api/v1/sites/${siteId}/alias`, {
669
+ method: "DELETE",
670
+ credentials
671
+ }, config);
672
+ }
673
+ async function publishToGitHub(credentials, siteId, params, config) {
674
+ return flowstackFetch(`/api/v1/sites/${siteId}/publish-github`, {
675
+ method: "POST",
676
+ credentials,
677
+ body: {
678
+ repo_name: params.repoName,
679
+ private: params.isPrivate ?? true,
680
+ ...params.version != null ? { version: params.version } : {}
681
+ }
682
+ }, config);
683
+ }
684
+ async function listGitHubRepos(credentials, config) {
685
+ return flowstackFetch("/api/v1/github/repos", {
686
+ credentials
687
+ }, config);
688
+ }
689
+ async function importFromGitHub(credentials, params, config) {
690
+ return flowstackFetch("/api/v1/github/import", {
691
+ method: "POST",
692
+ credentials,
693
+ body: params
694
+ }, config);
695
+ }
696
+ async function getPiiSettings(credentials, workspaceId, config) {
697
+ return flowstackFetch(`/api/v1/workspaces/${workspaceId}/pii-settings`, {
698
+ credentials
699
+ }, config);
700
+ }
701
+ async function updatePiiSettings(credentials, workspaceId, settings, config) {
702
+ return flowstackFetch(`/api/v1/workspaces/${workspaceId}/pii-settings`, {
703
+ method: "PUT",
704
+ credentials,
705
+ body: settings
706
+ }, config);
707
+ }
708
+ async function previewPiiMasking(credentials, query, config) {
709
+ if (!credentials?.apiKey || credentials.apiKey.split(".").length !== 3) {
710
+ return { ok: false, error: "Not authenticated", status: 401 };
711
+ }
712
+ return flowstackFetch("/stream/pii-preview", {
713
+ method: "POST",
714
+ credentials,
715
+ body: { query }
716
+ }, config);
717
+ }
718
+ async function getPiiAllowlist(credentials, workspaceId, config) {
719
+ return flowstackFetch(`/api/v1/workspaces/${workspaceId}/pii-allowlist`, {
720
+ credentials
721
+ }, config);
722
+ }
723
+ async function addPiiAllowlistTerm(credentials, workspaceId, term, entityType, config) {
724
+ return flowstackFetch(`/api/v1/workspaces/${workspaceId}/pii-allowlist`, {
725
+ method: "POST",
726
+ credentials,
727
+ body: { term, entity_type: entityType }
728
+ }, config);
729
+ }
730
+ async function removePiiAllowlistTerm(credentials, workspaceId, term, config) {
731
+ return flowstackFetch(`/api/v1/workspaces/${workspaceId}/pii-allowlist`, {
732
+ method: "DELETE",
733
+ credentials,
734
+ body: { term }
735
+ }, config);
736
+ }
737
+ async function getUserDataOverview(credentials, config) {
738
+ return flowstackFetch("/api/v1/user/data-overview", {
739
+ credentials
740
+ }, config);
741
+ }
742
+ async function getUserCollections(credentials, params, config) {
743
+ const query = new URLSearchParams();
744
+ if (params?.siteId) query.set("site_id", params.siteId);
745
+ if (params?.includeSchema) query.set("include_schema", "true");
746
+ const qs = query.toString();
747
+ return flowstackFetch(`/api/v1/user/collections${qs ? `?${qs}` : ""}`, {
748
+ credentials
749
+ }, config);
750
+ }
751
+ async function getUserCollectionDocuments(credentials, collection, params, config) {
752
+ const query = new URLSearchParams();
753
+ if (params?.filter) query.set("filter", JSON.stringify(params.filter));
754
+ if (params?.limit != null) query.set("limit", String(params.limit));
755
+ if (params?.skip != null) query.set("skip", String(params.skip));
756
+ if (params?.sort) query.set("sort", JSON.stringify(params.sort));
757
+ if (params?.database) query.set("database", params.database);
758
+ const qs = query.toString();
759
+ return flowstackFetch(`/api/v1/user/collections/${encodeURIComponent(collection)}/documents${qs ? `?${qs}` : ""}`, {
760
+ credentials
761
+ }, config);
762
+ }
763
+ async function getUserCollectionSchema(credentials, collection, params, config) {
764
+ const query = new URLSearchParams();
765
+ if (params?.database) query.set("database", params.database);
766
+ if (params?.sampleSize != null) query.set("sample_size", String(params.sampleSize));
767
+ const qs = query.toString();
768
+ return flowstackFetch(`/api/v1/user/collections/${encodeURIComponent(collection)}/schema${qs ? `?${qs}` : ""}`, {
769
+ credentials
770
+ }, config);
771
+ }
772
+ async function deleteUserCollection(credentials, collection, config) {
773
+ return flowstackFetch(`/api/v1/user/collections/${encodeURIComponent(collection)}?confirm=true`, {
774
+ method: "DELETE",
775
+ credentials
776
+ }, config);
777
+ }
778
+ async function exportUserCollection(credentials, collection, params, config) {
779
+ const query = new URLSearchParams();
780
+ if (params?.database) query.set("database", params.database);
781
+ const qs = query.toString();
782
+ return flowstackFetch(`/api/v1/user/collections/${encodeURIComponent(collection)}/export${qs ? `?${qs}` : ""}`, {
783
+ method: "POST",
784
+ credentials,
785
+ body: {
786
+ format: params?.format || "json",
787
+ filter: params?.filter || null
788
+ }
789
+ }, config);
790
+ }
791
+
792
+ // src/api/cache.ts
793
+ var CACHE_TTL = {
794
+ WORKSPACES: 300,
795
+ // 5 minutes
796
+ DATASETS: 60,
797
+ // 1 minute
798
+ VISUALIZATIONS: 60,
799
+ // 1 minute
800
+ REPORTS: 60,
801
+ // 1 minute
802
+ SITES: 120,
803
+ // 2 minutes
804
+ MESSAGES: 0,
805
+ // No expiry
806
+ SESSION: 86400
807
+ // 24 hours
808
+ };
809
+ var NAMESPACE = "flowstack";
810
+ function createRedisClient(config) {
811
+ const { url, token } = config;
812
+ return {
813
+ async get(key) {
814
+ try {
815
+ const response = await fetch(`${url}/get/${key}`, {
816
+ headers: { Authorization: `Bearer ${token}` }
817
+ });
818
+ if (!response.ok) return null;
819
+ const data = await response.json();
820
+ return data.result ? JSON.parse(data.result) : null;
821
+ } catch {
822
+ return null;
823
+ }
824
+ },
825
+ async set(key, value, ttl) {
826
+ try {
827
+ const body = ttl ? ["SET", key, JSON.stringify(value), "EX", ttl.toString()] : ["SET", key, JSON.stringify(value)];
828
+ const response = await fetch(url, {
829
+ method: "POST",
830
+ headers: {
831
+ Authorization: `Bearer ${token}`,
832
+ "Content-Type": "application/json"
833
+ },
834
+ body: JSON.stringify(body)
835
+ });
836
+ return response.ok;
837
+ } catch {
838
+ return false;
839
+ }
840
+ },
841
+ async del(key) {
842
+ try {
843
+ const response = await fetch(`${url}/del/${key}`, {
844
+ method: "POST",
845
+ headers: { Authorization: `Bearer ${token}` }
846
+ });
847
+ return response.ok;
848
+ } catch {
849
+ return false;
850
+ }
851
+ },
852
+ async keys(pattern) {
853
+ try {
854
+ const response = await fetch(`${url}/keys/${pattern}`, {
855
+ headers: { Authorization: `Bearer ${token}` }
856
+ });
857
+ if (!response.ok) return [];
858
+ const data = await response.json();
859
+ return data.result || [];
860
+ } catch {
861
+ return [];
862
+ }
863
+ }
864
+ };
865
+ }
866
+ function getCacheKey(type, credentials, ...parts) {
867
+ const userId = credentials.userId || "anonymous";
868
+ const tenantId = credentials.tenantId;
869
+ const key = [NAMESPACE, type, tenantId, userId, ...parts].filter(Boolean).join(":");
870
+ return key;
871
+ }
872
+ async function getCachedWorkspaces(credentials, config) {
873
+ const client = createRedisClient(config);
874
+ const key = getCacheKey("workspaces", credentials);
875
+ return client.get(key);
876
+ }
877
+ async function setCachedWorkspaces(credentials, workspaces, config) {
878
+ const client = createRedisClient(config);
879
+ const key = getCacheKey("workspaces", credentials);
880
+ return client.set(key, workspaces, CACHE_TTL.WORKSPACES);
881
+ }
882
+ async function invalidateWorkspacesCache(credentials, config) {
883
+ const client = createRedisClient(config);
884
+ const key = getCacheKey("workspaces", credentials);
885
+ return client.del(key);
886
+ }
887
+ async function getCachedDatasets(credentials, workspaceId, config) {
888
+ const client = createRedisClient(config);
889
+ const key = getCacheKey("datasets", credentials, workspaceId);
890
+ return client.get(key);
891
+ }
892
+ async function setCachedDatasets(credentials, workspaceId, datasets, config) {
893
+ const client = createRedisClient(config);
894
+ const key = getCacheKey("datasets", credentials, workspaceId);
895
+ return client.set(key, datasets, CACHE_TTL.DATASETS);
896
+ }
897
+ async function invalidateDatasetsCache(credentials, workspaceId, config) {
898
+ const client = createRedisClient(config);
899
+ const key = getCacheKey("datasets", credentials, workspaceId);
900
+ return client.del(key);
901
+ }
902
+ async function getCachedVisualizations(credentials, workspaceId, config) {
903
+ const client = createRedisClient(config);
904
+ const key = getCacheKey("visualizations", credentials, workspaceId);
905
+ return client.get(key);
906
+ }
907
+ async function setCachedVisualizations(credentials, workspaceId, visualizations, config) {
908
+ const client = createRedisClient(config);
909
+ const key = getCacheKey("visualizations", credentials, workspaceId);
910
+ return client.set(key, visualizations, CACHE_TTL.VISUALIZATIONS);
911
+ }
912
+ async function invalidateVisualizationsCache(credentials, workspaceId, config) {
913
+ const client = createRedisClient(config);
914
+ const key = getCacheKey("visualizations", credentials, workspaceId);
915
+ return client.del(key);
916
+ }
917
+ async function getCachedReports(credentials, workspaceId, config) {
918
+ const client = createRedisClient(config);
919
+ const key = getCacheKey("reports", credentials, workspaceId);
920
+ return client.get(key);
921
+ }
922
+ async function setCachedReports(credentials, workspaceId, reports, config) {
923
+ const client = createRedisClient(config);
924
+ const key = getCacheKey("reports", credentials, workspaceId);
925
+ return client.set(key, reports, CACHE_TTL.REPORTS);
926
+ }
927
+ async function invalidateReportsCache(credentials, workspaceId, config) {
928
+ const client = createRedisClient(config);
929
+ const key = getCacheKey("reports", credentials, workspaceId);
930
+ return client.del(key);
931
+ }
932
+ async function invalidateWorkspaceArtifacts(credentials, workspaceId, config) {
933
+ await Promise.all([
934
+ invalidateDatasetsCache(credentials, workspaceId, config),
935
+ invalidateVisualizationsCache(credentials, workspaceId, config),
936
+ invalidateReportsCache(credentials, workspaceId, config)
937
+ ]);
938
+ }
939
+ async function invalidateAllUserCache(credentials, config) {
940
+ const client = createRedisClient(config);
941
+ const userId = credentials.userId || "anonymous";
942
+ const tenantId = credentials.tenantId;
943
+ const pattern = `${NAMESPACE}:*:${tenantId}:${userId}:*`;
944
+ const keys = await client.keys(pattern);
945
+ await Promise.all(keys.map((key) => client.del(key)));
946
+ }
947
+ async function getCached(key, config) {
948
+ const client = createRedisClient(config);
949
+ return client.get(`${NAMESPACE}:${key}`);
950
+ }
951
+ async function setCached(key, value, ttl, config) {
952
+ const client = createRedisClient(config);
953
+ return client.set(`${NAMESPACE}:${key}`, value, ttl);
954
+ }
955
+ async function deleteCached(key, config) {
956
+ const client = createRedisClient(config);
957
+ return client.del(`${NAMESPACE}:${key}`);
958
+ }
959
+ async function getCachedSites(credentials, config) {
960
+ const client = createRedisClient(config);
961
+ const key = getCacheKey("sites", credentials);
962
+ return client.get(key);
963
+ }
964
+ async function setCachedSites(credentials, sites, config) {
965
+ const client = createRedisClient(config);
966
+ const key = getCacheKey("sites", credentials);
967
+ return client.set(key, sites, CACHE_TTL.SITES);
968
+ }
969
+ async function invalidateSitesCache(credentials, config) {
970
+ const client = createRedisClient(config);
971
+ const key = getCacheKey("sites", credentials);
972
+ return client.del(key);
973
+ }
974
+
975
+ export { CACHE_TTL, addPiiAllowlistTerm, addSiteFile, checkAdminPermissions, createDataSource, createSite, createWorkspace, deleteCached, deleteDataSource, deleteDataset, deleteDocuments, deleteSite, deleteSiteVersion, deleteUser, deleteUserCollection, executeQuery, executeQueryWithConfig, exportUserCollection, flowstackFetch, getCached, getCachedDatasets, getCachedReports, getCachedSites, getCachedVisualizations, getCachedWorkspaces, getConversationHistory, getDataset, getDatasetPreview, getModel, getPiiAllowlist, getPiiSettings, getSite, getSiteVersions, getUser, getUserActivity, getUserCollectionDocuments, getUserCollectionSchema, getUserCollections, getUserDataOverview, getUserStats, getWorkspace, googleLogin, importFromGitHub, insertDocuments, invalidateAllUserCache, invalidateDatasetsCache, invalidateReportsCache, invalidateSitesCache, invalidateVisualizationsCache, invalidateWorkspaceArtifacts, invalidateWorkspacesCache, invokeTool, listAgents, listDataSources, listDatasets, listGitHubRepos, listModels, listReports, listScripts, listSites, listUsers, listVisualizations, listWorkspaces, login, previewPiiMasking, promoteSiteVersion, publishStagedSite, publishToGitHub, queryCollection, reactivateUser, register, removePiiAllowlistTerm, removeSiteAlias, setCached, setCachedDatasets, setCachedReports, setCachedSites, setCachedVisualizations, setCachedWorkspaces, setSiteAlias, suspendUser, testDataSource, updateDocuments, updatePiiSettings, updateUser, uploadDocument, uploadFile };
976
+ //# sourceMappingURL=index.mjs.map
977
+ //# sourceMappingURL=index.mjs.map