@shuffleio/shuffle-mcps 0.0.34 → 0.0.36

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.
@@ -2,7 +2,7 @@ import {
2
2
  fetchApps,
3
3
  fetchAppsViaApiConfig,
4
4
  invalidateAppsCache
5
- } from "./chunk-B4JFC2JU.mjs";
5
+ } from "./chunk-IABSYB2J.mjs";
6
6
  export {
7
7
  fetchApps,
8
8
  fetchAppsViaApiConfig,
@@ -1,7 +1,9 @@
1
1
  // fetchBreaker.ts
2
2
  var FAIL_THRESHOLD = 12;
3
3
  var ROLLING_WINDOW_MS = 5e3;
4
- var COOLDOWN_MS = 3e4;
4
+ var COOLDOWN_MS = 1e4;
5
+ var PROBE_AFTER_MS = 1500;
6
+ var MAX_PROBE_BACKOFF_MS = 5e3;
5
7
  var HARD_BURST_THRESHOLD = 30;
6
8
  var HARD_BURST_WINDOW_MS = 1e3;
7
9
  var state = /* @__PURE__ */ new Map();
@@ -10,11 +12,24 @@ var allowedOrigins = /* @__PURE__ */ new Set();
10
12
  var getEntry = (key) => {
11
13
  let entry = state.get(key);
12
14
  if (!entry) {
13
- entry = { failures: [], attempts: [], blockedUntil: 0, warned: false };
15
+ entry = { failures: [], attempts: [], blockedUntil: 0, probeAfter: 0, probing: false, warned: false };
14
16
  state.set(key, entry);
15
17
  }
16
18
  return entry;
17
19
  };
20
+ var trip = (entry, now, cooldownMs = COOLDOWN_MS) => {
21
+ entry.blockedUntil = now + cooldownMs;
22
+ entry.probeAfter = now + PROBE_AFTER_MS;
23
+ entry.probing = false;
24
+ };
25
+ var reset = (entry) => {
26
+ entry.failures.length = 0;
27
+ entry.attempts.length = 0;
28
+ entry.blockedUntil = 0;
29
+ entry.probeAfter = 0;
30
+ entry.probing = false;
31
+ entry.warned = false;
32
+ };
18
33
  var prune = (arr, now, windowMs) => {
19
34
  const cutoff = now - windowMs;
20
35
  while (arr.length && arr[0] < cutoff) arr.shift();
@@ -64,21 +79,35 @@ var installFetchBreaker = () => {
64
79
  if (!key) return original(input, init);
65
80
  const entry = getEntry(key);
66
81
  const now = Date.now();
82
+ let isProbe = false;
67
83
  if (entry.blockedUntil > now) {
68
- return synthetic503(key, entry.blockedUntil - now);
84
+ if (!entry.probing && now >= entry.probeAfter) {
85
+ entry.probing = true;
86
+ isProbe = true;
87
+ } else {
88
+ return synthetic503(key, entry.blockedUntil - now);
89
+ }
69
90
  }
70
- entry.attempts.push(now);
71
- prune(entry.attempts, now, HARD_BURST_WINDOW_MS);
72
- if (entry.attempts.length > HARD_BURST_THRESHOLD) {
73
- entry.blockedUntil = now + COOLDOWN_MS;
74
- if (!entry.warned) {
75
- entry.warned = true;
76
- console.error(
77
- `[fetchBreaker] Burst detected on ${key} (${entry.attempts.length} calls / ${HARD_BURST_WINDOW_MS}ms). Blocking for ${COOLDOWN_MS / 1e3}s. Fix the caller \u2014 this is almost always a missing useEffect dep or a render loop.`
78
- );
91
+ if (!isProbe) {
92
+ entry.attempts.push(now);
93
+ prune(entry.attempts, now, HARD_BURST_WINDOW_MS);
94
+ if (entry.attempts.length > HARD_BURST_THRESHOLD) {
95
+ trip(entry, now);
96
+ if (!entry.warned) {
97
+ entry.warned = true;
98
+ console.error(
99
+ `[fetchBreaker] Burst detected on ${key} (${entry.attempts.length} calls / ${HARD_BURST_WINDOW_MS}ms). Blocking for up to ${COOLDOWN_MS / 1e3}s (probing again in ${PROBE_AFTER_MS / 1e3}s). Fix the caller \u2014 this is almost always a missing useEffect dep or a render loop.`
100
+ );
101
+ }
102
+ return synthetic503(key, COOLDOWN_MS);
79
103
  }
80
- return synthetic503(key, COOLDOWN_MS);
81
104
  }
105
+ const onProbeFailure = (ts) => {
106
+ if (!isProbe) return;
107
+ entry.probing = false;
108
+ entry.probeAfter = ts + Math.min(MAX_PROBE_BACKOFF_MS, PROBE_AFTER_MS * 2);
109
+ entry.blockedUntil = Math.max(entry.blockedUntil, ts + PROBE_AFTER_MS);
110
+ };
82
111
  let response;
83
112
  try {
84
113
  response = await original(input, init);
@@ -86,12 +115,13 @@ var installFetchBreaker = () => {
86
115
  const ts = Date.now();
87
116
  entry.failures.push(ts);
88
117
  prune(entry.failures, ts, ROLLING_WINDOW_MS);
89
- if (entry.failures.length >= FAIL_THRESHOLD) {
90
- entry.blockedUntil = ts + COOLDOWN_MS;
118
+ onProbeFailure(ts);
119
+ if (!isProbe && entry.failures.length >= FAIL_THRESHOLD) {
120
+ trip(entry, ts);
91
121
  if (!entry.warned) {
92
122
  entry.warned = true;
93
123
  console.error(
94
- `[fetchBreaker] ${entry.failures.length} network errors on ${key} in ${ROLLING_WINDOW_MS / 1e3}s. Blocking for ${COOLDOWN_MS / 1e3}s.`
124
+ `[fetchBreaker] ${entry.failures.length} network errors on ${key} in ${ROLLING_WINDOW_MS / 1e3}s. Blocking for up to ${COOLDOWN_MS / 1e3}s.`
95
125
  );
96
126
  }
97
127
  }
@@ -101,18 +131,20 @@ var installFetchBreaker = () => {
101
131
  const ts = Date.now();
102
132
  entry.failures.push(ts);
103
133
  prune(entry.failures, ts, ROLLING_WINDOW_MS);
104
- if (entry.failures.length >= FAIL_THRESHOLD) {
105
- entry.blockedUntil = ts + COOLDOWN_MS;
134
+ onProbeFailure(ts);
135
+ if (!isProbe && entry.failures.length >= FAIL_THRESHOLD) {
136
+ trip(entry, ts);
106
137
  if (!entry.warned) {
107
138
  entry.warned = true;
108
139
  console.error(
109
- `[fetchBreaker] ${entry.failures.length} ${response.status}s on ${key} in ${ROLLING_WINDOW_MS / 1e3}s. Blocking for ${COOLDOWN_MS / 1e3}s.`
140
+ `[fetchBreaker] ${entry.failures.length} ${response.status}s on ${key} in ${ROLLING_WINDOW_MS / 1e3}s. Blocking for up to ${COOLDOWN_MS / 1e3}s.`
110
141
  );
111
142
  }
112
143
  }
113
144
  } else if (response.status < 400) {
114
- entry.failures.length = 0;
115
- entry.warned = false;
145
+ reset(entry);
146
+ } else {
147
+ if (isProbe) reset(entry);
116
148
  }
117
149
  return response;
118
150
  });
@@ -134,7 +166,7 @@ var getEnvVar = (key) => {
134
166
  var isDevEnvironment = () => {
135
167
  if (getEnvVar("VITE_SHUFFLE_API_URL")) return false;
136
168
  const hostname = typeof window !== "undefined" ? window.location.hostname : "";
137
- return hostname.includes("lovableproject.com") || hostname.includes("id-preview--");
169
+ return hostname.includes("lovableproject.com") || hostname.includes("id-preview--") || hostname.endsWith(".lovable.app") || hostname.endsWith(".lovable.dev");
138
170
  };
139
171
  var isCloudDomain = () => {
140
172
  const hostname = typeof window !== "undefined" ? window.location.hostname : "";
@@ -154,9 +186,54 @@ var getDefaultBaseUrl = () => {
154
186
  }
155
187
  return PROD_BACKEND;
156
188
  };
157
- var _regionUrl = null;
158
- var _trackedOrgId = null;
189
+ var REGION_STORAGE_KEY = "shuffle_region_url";
190
+ var readCachedRegion = () => {
191
+ if (typeof window === "undefined") return { url: null, orgId: null };
192
+ try {
193
+ const raw = localStorage.getItem(REGION_STORAGE_KEY);
194
+ if (!raw) return { url: null, orgId: null };
195
+ const parsed = JSON.parse(raw);
196
+ return { url: parsed?.url || null, orgId: parsed?.orgId || null };
197
+ } catch {
198
+ return { url: null, orgId: null };
199
+ }
200
+ };
201
+ var cached = readCachedRegion();
202
+ var _regionUrl = cached.url;
203
+ var _trackedOrgId = cached.orgId;
159
204
  var _hostBaseUrl = null;
205
+ var REGION_EVENT = "shuffle:region-url";
206
+ var _lastBroadcastUrl = cached.url;
207
+ var persistRegion = (url, orgId) => {
208
+ if (typeof window === "undefined") return;
209
+ const changed = url !== _lastBroadcastUrl;
210
+ _lastBroadcastUrl = url;
211
+ try {
212
+ if (url) localStorage.setItem(REGION_STORAGE_KEY, JSON.stringify({ url, orgId }));
213
+ else localStorage.removeItem(REGION_STORAGE_KEY);
214
+ } catch {
215
+ }
216
+ if (!changed) return;
217
+ try {
218
+ window.dispatchEvent(new CustomEvent(REGION_EVENT, { detail: { url, orgId } }));
219
+ } catch {
220
+ }
221
+ };
222
+ if (typeof window !== "undefined") {
223
+ const sync = () => {
224
+ const next = readCachedRegion();
225
+ if (next.url !== _regionUrl) {
226
+ _regionUrl = next.url;
227
+ _lastBroadcastUrl = next.url;
228
+ console.log(`[API] Region URL synced to: ${_regionUrl || "default"}`);
229
+ }
230
+ _trackedOrgId = next.orgId;
231
+ };
232
+ window.addEventListener(REGION_EVENT, sync);
233
+ window.addEventListener("storage", (e) => {
234
+ if (e.key === REGION_STORAGE_KEY) sync();
235
+ });
236
+ }
160
237
  var isShufflerSubdomain = (url) => {
161
238
  try {
162
239
  const parsed = new URL(url);
@@ -166,26 +243,32 @@ var isShufflerSubdomain = (url) => {
166
243
  }
167
244
  };
168
245
  var setRegionUrl = (regionUrl, orgId) => {
169
- if (isDevEnvironment()) {
170
- _trackedOrgId = orgId || null;
171
- return;
172
- }
173
246
  _trackedOrgId = orgId || null;
174
247
  if (regionUrl && isShufflerSubdomain(regionUrl)) {
175
248
  const normalized = regionUrl.replace(/\/+$/, "");
176
249
  if (normalized !== PROD_BACKEND) {
177
250
  _regionUrl = normalized;
251
+ persistRegion(_regionUrl, _trackedOrgId);
178
252
  console.log(`[API] Region URL set to: ${_regionUrl}`);
179
253
  return;
180
254
  }
181
255
  }
182
256
  _regionUrl = null;
257
+ persistRegion(null, _trackedOrgId);
258
+ };
259
+ var applyRegionFromPayload = (payload, orgIdOverride) => {
260
+ if (!payload || typeof payload !== "object") return null;
261
+ const orgId = orgIdOverride ?? payload?.active_org?.id ?? payload?.org_id ?? null;
262
+ const regionUrl = payload?.region_url || payload?.active_org?.region_url || null;
263
+ setRegionUrl(regionUrl, orgId);
264
+ return regionUrl;
183
265
  };
184
266
  var resetRegionUrl = () => {
185
267
  if (_regionUrl) {
186
268
  console.log(`[API] Region URL reset to default (org changed)`);
187
269
  }
188
270
  _regionUrl = null;
271
+ persistRegion(null, null);
189
272
  };
190
273
  var SHUFFLE_HOST_BASE_URL_EVENT = "shuffle:set-host-base-url";
191
274
  var setHostBaseUrl = (url) => {
@@ -219,7 +302,7 @@ var getTrackedOrgId = () => _trackedOrgId;
219
302
  var API_CONFIG = {
220
303
  // Shuffle backend URL — host override beats region URL beats default.
221
304
  get baseUrl() {
222
- const url = _hostBaseUrl || _regionUrl || getDefaultBaseUrl();
305
+ const url = _hostBaseUrl || (isDevEnvironment() || getEnvVar("VITE_SHUFFLE_API_URL") ? getDefaultBaseUrl() : _regionUrl || getDefaultBaseUrl());
223
306
  try {
224
307
  registerProtectedOrigin(url);
225
308
  } catch {
@@ -244,13 +327,6 @@ var API_CONFIG = {
244
327
  var getApiUrl = (endpoint) => {
245
328
  return `${API_CONFIG.baseUrl}${endpoint}`;
246
329
  };
247
- var getShuffleCoreFormUrl = (refUrl) => {
248
- if (!refUrl) return refUrl;
249
- if (/^https?:\/\//i.test(refUrl)) return refUrl;
250
- const path = refUrl.startsWith("/") ? refUrl : `/${refUrl}`;
251
- if (isCloud()) return `https://shuffler.io${path}`;
252
- return `${API_CONFIG.baseUrl}${path}`;
253
- };
254
330
  var shuffleFetch = (url, init) => {
255
331
  const { headers: extraHeaders, ...rest } = init || {};
256
332
  return fetch(url, {
@@ -334,13 +410,13 @@ export {
334
410
  isCloud,
335
411
  isOnprem,
336
412
  setRegionUrl,
413
+ applyRegionFromPayload,
337
414
  resetRegionUrl,
338
415
  setHostBaseUrl,
339
416
  getHostBaseUrl,
340
417
  getTrackedOrgId,
341
418
  API_CONFIG,
342
419
  getApiUrl,
343
- getShuffleCoreFormUrl,
344
420
  shuffleFetch,
345
421
  getAuthHeader,
346
422
  fetchApps,
package/dist/index.d.mts CHANGED
@@ -131,7 +131,7 @@ interface CustomStyles {
131
131
  checkbox?: React.CSSProperties;
132
132
  checkboxChecked?: React.CSSProperties;
133
133
  }
134
- interface AppAuthentication {
134
+ interface AppAuthentication$1 {
135
135
  app: {
136
136
  id: string;
137
137
  name: string;
@@ -212,7 +212,7 @@ interface ShuffleMCPProps extends ShuffleHostProps {
212
212
  /** Base URL for Singul API calls (default: https://singul.io) */
213
213
  singulBaseUrl?: string;
214
214
  /** Manually provided authenticated apps (used when apiKey is not provided) */
215
- authenticatedApps?: AppAuthentication[];
215
+ authenticatedApps?: AppAuthentication$1[];
216
216
  /** Hide the auth status chips (Configured/Not configured, Tested/Not tested) */
217
217
  hideAuthStatus?: boolean;
218
218
  /** Apps to pin at the top of the results (prepended, deduped by name). */
@@ -604,8 +604,9 @@ interface AgentPromptPrefixChipProps {
604
604
  declare const AgentPromptPrefixChip: ({ label, userId, value, onChange, onRemove, defaultPrompt, dialogTitle, readOnly, }: AgentPromptPrefixChipProps) => React$1.JSX.Element;
605
605
 
606
606
  declare const AGENT_PROMPT_PREFIX_CATEGORY = "agent-prompt-prefix";
607
- /** Default seed used until the user saves their own prefix. */
608
- declare const DEFAULT_AGENT_PROMPT_PREFIX = "You are the Shuffle Tools agent. Use the connected Shuffle tools to help me with the request that follows.";
607
+ /** Default seed used until the user saves their own prefix.
608
+ * Empty by default — the backend system prompt handles agent identity. */
609
+ declare const DEFAULT_AGENT_PROMPT_PREFIX = "";
609
610
  interface UseAgentPromptPrefixOptions {
610
611
  /** Storage key — typically the current user id. Falls back to `"default"`. */
611
612
  userId?: string;
@@ -641,7 +642,7 @@ interface AgentRunDrawerProps extends ShuffleHostProps {
641
642
  permissionsDisabledTooltip?: string;
642
643
  /** Forwarded to the embedded AgentUI (apiKey, apiBaseUrl, orgId, etc.). */
643
644
  agentUIProps?: Partial<AgentUIProps>;
644
- /** Drawer width override (default: 480 px on >=sm, full-width on xs). */
645
+ /** Drawer width override (default: 595 px on >=sm, full-width on xs). */
645
646
  width?: number;
646
647
  /** Header title. Default: "Agent". */
647
648
  title?: string;
@@ -675,9 +676,18 @@ declare const isCloud: () => boolean;
675
676
  declare const isOnprem: () => boolean;
676
677
  /**
677
678
  * Set the dynamic region URL from getinfo response.
678
- * Only applies if the URL is a shuffler.io subdomain and different from default.
679
+ * ALWAYS honored for the current org/tenant (including dev/preview) as long as
680
+ * the URL is a valid shuffler.io subdomain different from the default backend.
681
+ * Persisted in localStorage so later page loads do not have to wait on getinfo.
679
682
  */
680
683
  declare const setRegionUrl: (regionUrl: string | undefined | null, orgId: string | undefined | null) => void;
684
+ /**
685
+ * Single entry point for applying a region from ANY backend response that
686
+ * carries one (`/api/v1/getinfo`, `/api/v1/orgs/{id}/change`, ...). Extracts
687
+ * `region_url` (top-level first, then `active_org`) and routes it through
688
+ * `setRegionUrl`, so setting + broadcasting always happens in one place.
689
+ */
690
+ declare const applyRegionFromPayload: (payload: any, orgIdOverride?: string | null) => string | null;
681
691
  /**
682
692
  * Called when org changes. Resets region URL to default until next getinfo.
683
693
  */
@@ -807,6 +817,18 @@ declare const scheduleAgentRun: ({ cron, input, apps, onStep, apiKey, apiBaseUrl
807
817
  cron: string;
808
818
  }>;
809
819
 
820
+ /**
821
+ * A usecase-backed agent "type" surfaced in the run filter dropdown.
822
+ * Hosts supply only the usecases that are actually enabled for the tenant.
823
+ */
824
+ interface AgentUsecaseFilter {
825
+ /** Unique id (used as the menu value). */
826
+ id: string;
827
+ /** Menu label, e.g. "Incident Response Agent". */
828
+ label: string;
829
+ /** Case-insensitive substrings matched against run source/workflow metadata. */
830
+ matchTokens: string[];
831
+ }
810
832
  interface AgentActivityListProps extends ShuffleHostProps {
811
833
  /** Optional Shuffle API key. Falls back to the shared API_CONFIG. */
812
834
  apiKey?: string;
@@ -844,6 +866,8 @@ interface AgentActivityListProps extends ShuffleHostProps {
844
866
  toolbarSx?: SxProps<Theme>;
845
867
  /** Style overrides for each individual run row. */
846
868
  rowSx?: SxProps<Theme>;
869
+ /** Usecase-backed agent types shown in the run filter dropdown. */
870
+ usecaseFilters?: AgentUsecaseFilter[];
847
871
  }
848
872
 
849
873
  interface AgentExecutionDrawerProps extends ShuffleHostProps {
@@ -914,6 +938,8 @@ interface AgentsViewProps extends ShuffleHostProps {
914
938
  disableAppsPersistence?: boolean;
915
939
  /** Storage key for internal chip-row persistence. Defaults to `shuffle-agents-selected-apps`. */
916
940
  appsStorageKey?: string;
941
+ /** Usecase-backed agent types shown in the activity list filter dropdown. */
942
+ usecaseFilters?: AgentUsecaseFilter[];
917
943
  }
918
944
 
919
945
  interface AgentLocalModel {
@@ -932,6 +958,10 @@ interface LocalLLMConfigProps extends ShuffleHostProps {
932
958
  hasOpenAIAuth?: boolean;
933
959
  onSave?: (model: AgentLocalModel) => void;
934
960
  onTestResult?: (result: LocalLLMTestResult) => void;
961
+ /** When the panel is rendered inside a drawer, pass the drawer open state
962
+ * so the provider selector can reset to the currently active provider each
963
+ * time the drawer opens. */
964
+ open?: boolean;
935
965
  }
936
966
 
937
967
  /**
@@ -964,6 +994,30 @@ interface AppAuthState {
964
994
  executionId?: string;
965
995
  errorCode?: number;
966
996
  }
997
+ interface AuthParameter {
998
+ description: string;
999
+ example: string;
1000
+ id: string;
1001
+ name: string;
1002
+ required: boolean;
1003
+ schema: {
1004
+ type: string;
1005
+ };
1006
+ }
1007
+ interface AppAuthentication {
1008
+ type: string;
1009
+ description?: string;
1010
+ redirect_uri?: string;
1011
+ token_uri?: string;
1012
+ refresh_uri?: string;
1013
+ authorization_url?: string;
1014
+ auth_uri?: string;
1015
+ authorize_url?: string;
1016
+ scope?: string[];
1017
+ client_id?: string;
1018
+ client_secret?: string;
1019
+ parameters?: AuthParameter[];
1020
+ }
967
1021
  interface ApiAuthEntry {
968
1022
  id?: string;
969
1023
  label?: string;
@@ -1023,6 +1077,12 @@ interface AppAuthCardProps extends ShuffleHostProps {
1023
1077
  * credentials form (with the small "Test Authentication" CTA) is always
1024
1078
  * visible so users can edit & retest in one place. */
1025
1079
  compactAuthForm?: boolean;
1080
+ /** Always render the "Select authentication" dropdown, even when there are no
1081
+ * saved entries yet, so the UI does not switch between two different shapes. */
1082
+ alwaysShowAuthSelector?: boolean;
1083
+ /** Suppress the "Authentication saved" success toast (embedded flows that
1084
+ * already give their own feedback, e.g. the LLM provider config). */
1085
+ suppressSaveToast?: boolean;
1026
1086
  /** Render additional fields inside the expanded body, above the credential
1027
1087
  * inputs. The slot receives the live `localCredentials` and a `setField`
1028
1088
  * helper so its values are persisted as part of the auth on Save. */
@@ -1030,8 +1090,11 @@ interface AppAuthCardProps extends ShuffleHostProps {
1030
1090
  credentials: Record<string, string>;
1031
1091
  setField: (key: string, value: string) => void;
1032
1092
  }) => React.ReactNode;
1093
+ /** Known-ahead-of-time auth schema. When provided the fields render
1094
+ * instantly and no app-config request is made (no "Loading configuration"). */
1095
+ initialAuthConfig?: AppAuthentication;
1033
1096
  }
1034
- declare const AppAuthCard: ({ app, authState, isExpanded, onToggle, onAuthChange, onTestConnection, onSaveAuth, apiAuthEntries, onSelectAuth, onRefreshAuth, disableUrlPrefill, hideHeader, hideStatusChips, hideDocsLink, hideUrlFields, borderless, compactAuthForm, extraFieldsSlot, globalUrl, userdata, isLoaded, isLoggedIn, serverside, }: AppAuthCardProps) => React$1.JSX.Element;
1097
+ declare const AppAuthCard: ({ app, authState, isExpanded, onToggle, onAuthChange, onTestConnection, onSaveAuth, apiAuthEntries, onSelectAuth, onRefreshAuth, disableUrlPrefill, hideHeader, hideStatusChips, hideDocsLink, hideUrlFields, borderless, compactAuthForm, alwaysShowAuthSelector, suppressSaveToast, extraFieldsSlot, initialAuthConfig, globalUrl, userdata, isLoaded, isLoggedIn, serverside, }: AppAuthCardProps) => React$1.JSX.Element;
1035
1098
  declare const AppAuthConfig: ({ apps, authStates, authenticatedApps, onAuthChange, onTestConnection, onSaveAuth, onSelectAuth, onRefreshAuth, globalUrl, userdata, isLoaded, isLoggedIn, serverside, }: AppAuthConfigProps) => React$1.JSX.Element;
1036
1099
 
1037
1100
  /**
@@ -1221,7 +1284,7 @@ declare function useAppAuth(): {
1221
1284
  loading: boolean;
1222
1285
  handleAuthChange: (systemId: string, credentials: Record<string, string>) => void;
1223
1286
  handleTestConnection: (systemId: string, authenticationId?: string) => Promise<void>;
1224
- handleSaveAuth: (appId: string, credentials: Record<string, string>, appName?: string) => Promise<boolean>;
1287
+ handleSaveAuth: (appId: string, credentials: Record<string, string>, appName?: string, label?: string) => Promise<boolean>;
1225
1288
  refreshAuth: () => Promise<void>;
1226
1289
  };
1227
1290
 
@@ -1248,6 +1311,10 @@ declare const useSyncHostBaseUrl: (globalUrl: string | undefined | null) => void
1248
1311
  * scoped to a Shuffle backend origin) fails repeatedly inside a short window,
1249
1312
  * subsequent calls fail-fast with a synthetic 503 for a cooldown period.
1250
1313
  *
1314
+ * The breaker is "half-open": shortly after tripping it lets a single probe
1315
+ * request through. If that probe succeeds the endpoint is restored immediately
1316
+ * instead of staying blocked for the full cooldown.
1317
+ *
1251
1318
  * This is a safety net — components and hooks should still throttle / cache
1252
1319
  * their own requests. The breaker only kicks in when something has gone wrong
1253
1320
  * (a useEffect missing deps, a render loop, an unreachable backend).
@@ -1400,6 +1467,13 @@ declare const getDatastoreItem: (key: string, category: string, overrideOrgId?:
1400
1467
  declare const getDatastoreItemPublic: (key: string, orgId: string, authorization: string) => Promise<DatastoreResponse & {
1401
1468
  item?: DatastoreItem;
1402
1469
  }>;
1470
+ /**
1471
+ /**
1472
+ * Page size used for a category. Exported so callers that follow cursors can
1473
+ * tell a full page (more data may exist) from a short page (definitively the
1474
+ * last one) — the backend returns a cursor even on the final page.
1475
+ */
1476
+ declare const getDatastorePageSize: (category: string, limit?: number) => number;
1403
1477
  /**
1404
1478
  * Get all items in a category with optional cursor-based pagination
1405
1479
  */
@@ -1552,6 +1626,67 @@ interface UsageBarProps {
1552
1626
  }
1553
1627
  declare const UsageBar: React__default.FC<UsageBarProps>;
1554
1628
 
1629
+ /**
1630
+ * ShuffleMarkdown — the ONE markdown renderer for the platform.
1631
+ *
1632
+ * Every place that renders user/AI/remote markdown should use this component
1633
+ * (or `InlineMarkdown` for single-line strings) instead of importing
1634
+ * `react-markdown` directly, so plugins, link safety and typography stay
1635
+ * identical everywhere.
1636
+ *
1637
+ * Defaults:
1638
+ * - remark-gfm (tables, strikethrough, task lists, autolinks)
1639
+ * - remark-breaks (single newline = <br>, matches how LLM/agent output reads)
1640
+ * - rehype-sanitize (defense in depth; raw HTML is never enabled)
1641
+ * - external links open in a new tab with noopener/noreferrer
1642
+ * - shared code / table / blockquote styling based on HSL design tokens
1643
+ */
1644
+
1645
+ /** Standardised JSON tree used inside markdown (same viewer as the rest of the platform). */
1646
+ declare const MarkdownJsonBlock: React__default.FC<{
1647
+ src: object;
1648
+ }>;
1649
+ /**
1650
+ * Deliberately loose (not react-markdown's own `Components` type): that type is a mapped
1651
+ * type over `keyof JSX.IntrinsicElements`, which tsup's declaration bundler (rollup-plugin-dts)
1652
+ * cannot inline into this package's published `.d.ts` without erroring (TS2709).
1653
+ */
1654
+ type MarkdownComponentOverrides = Record<string, React__default.ElementType>;
1655
+ interface ShuffleMarkdownProps {
1656
+ /** The markdown source. */
1657
+ children?: string | null;
1658
+ /** Component overrides merged on top of the shared defaults. */
1659
+ components?: MarkdownComponentOverrides;
1660
+ /** Extra remark plugins appended to the defaults. */
1661
+ remarkPlugins?: any[];
1662
+ /** Disable remark-breaks (for prose docs where blank lines separate paragraphs). */
1663
+ disableBreaks?: boolean;
1664
+ /** Styling applied to the wrapping Box. */
1665
+ sx?: SxProps<Theme>;
1666
+ className?: string;
1667
+ }
1668
+ declare const ShuffleMarkdown: React__default.FC<ShuffleMarkdownProps>;
1669
+
1670
+ /**
1671
+ * VideoEmbed — shared inline video player for markdown content.
1672
+ *
1673
+ * Supports YouTube, Loom and direct video files (mp4/webm/ogg).
1674
+ * Rendered as a block-level span so it is valid inside <p> elements.
1675
+ */
1676
+
1677
+ type VideoKind = 'youtube' | 'loom' | 'file';
1678
+ interface ResolvedVideo {
1679
+ kind: VideoKind;
1680
+ /** Embed URL for iframes, or the direct file URL for <video>. */
1681
+ src: string;
1682
+ }
1683
+ /** Returns embed info when the URL points at a supported video, otherwise null. */
1684
+ declare function resolveVideoUrl(raw?: string | null): ResolvedVideo | null;
1685
+ declare const VideoEmbed: React__default.FC<{
1686
+ video: ResolvedVideo;
1687
+ title?: string;
1688
+ }>;
1689
+
1555
1690
  /**
1556
1691
  * Local Singul Library — fully self-contained.
1557
1692
  * No host-app `@/` imports remain inside this folder (assets aside).
@@ -1598,4 +1733,4 @@ declare const LocalLLMConfig: React__default.ComponentType<any>;
1598
1733
 
1599
1734
  declare const AddAppModal: React__default.ComponentType<any>;
1600
1735
 
1601
- export { AGENT_PRESETS, AGENT_PROMPT_PREFIX_CATEGORY, API_CONFIG, AddAppModal, type AddAppModalProps, AgentActivityList, type AgentActivityListProps, type AgentActivityParams, type AgentActivityResponse, type AgentDecision, AgentExecutionDrawer, type AgentExecutionDrawerProps, AgentIcon, type AgentLocalModel, type AgentPreset, AgentPresets, type AgentPresetsProps, AgentPromptPrefixChip, type AgentPromptPrefixChipProps, type AgentRun, AgentRunDiagnosisBanner, AgentRunDrawer, type AgentRunDrawerProps, type AgentRunDrawerTab, type AgentRunResult, AgentUI, type AgentUIApp, type AgentUIProps, AgentsView, type AgentsViewProps, AiAgentPromptsEditor, type AiAgentPromptsEditorProps, type AlgoliaSearchApp, type ApiAuthEntry, AppAuthCard, type AppAuthCardProps, AppAuthConfig, AppAuthSection, type AppAuthSectionProps, type AppAuthState, type AppAuthentication, AppDetailDrawer, AppDetailProvider, type AppLookupResult, AppSearchDrawer, type AppSelectedEvent, AppTitleHeader, type AppTitleHeaderProps, type AuthStatus, CASES_PATTERNS, COMMUNICATION_PATTERNS_NAMES, type CategoryAutomation, type CategoryConfig, type CustomStyles, DATASTORE_CATEGORIES, DEFAULT_AGENT_PROMPT_PREFIX, type DatastoreDiagnostics, type DatastoreItem, type DatastoreResponse, type DiagnosableRun, type DiagnosisEvidence, EDR_PATTERNS, EMAIL_APP_PATTERNS, FORWARD_TICKETS_WORKFLOW_NAME, type FetchAppsOptions, INGEST_TICKETS_WORKFLOW_NAME, type IngestionCategory, IntegrationStatus, LocalLLMConfig, type LocalLLMConfigProps, type LocalLLMTestResult, type OutputDiagnosis, type ResolvedApp, SIEM_PATTERNS, type ShuffleHostProps, ShuffleMCP, type ShuffleMCPHandle, type ShuffleMCPProps, type ShuffleMcpColorMode, ShuffleMcpThemeProvider, type ShuffleMcpThemeProviderProps, ShufflePipelinesBanner, type ShuffleTheme, SingulActionsPreview, THREAT_INTEL_PATTERNS, TryMcpSection, type TryMcpSectionProps, UsageBar, type UsageBarProps, type UseAgentPromptPrefixOptions, VULN_SCANNER_PATTERNS, type ValidatedIngestionApp, ShuffleMCP as default, deleteDatastoreItem, deleteDatastoreItems, diagnoseOutputWarning, extractActionAppNames, extractValidatedIngestionApps, extractWorkflowActionAppNames, extractWorkflowAppNames, fetchApps, fetchAppsViaApiConfig, findForwardTicketsWorkflow, findIngestTicketsWorkflow, getApiUrl, getAuthHeader, getDatastoreByCategory, getDatastoreItem, getDatastoreItemPublic, getFailureInfo, getHostBaseUrl, getIngestionCategory, hasOutputWarning, installFetchBreaker, invalidateAppsCache, invalidateResolvedApps, isCloud, isCloudDomain, isEmailApp, isIngestionApp, isOnprem, isThreatIntelApp, isVulnScannerApp, isWorkflowScheduleStopped, normalizeAppName, parseRunResult, refreshAllIntegrationStatus, registerProtectedOrigin, resetRegionUrl, resolveApp, resolveApps, scheduleAgentRun, searchAgentActivity, seedResolvedApp, setDatastoreItem, setDatastoreItems, setHostBaseUrl, setRegionUrl, setRuntimeOrgId, setToastImpl, shuffleFetch, toast, useAgentPromptPrefix, useAppAuth, useAppAuthFlow, useAppDetail, useAppDetailOptional, useAppLookup, useSyncHostBaseUrl };
1736
+ export { AGENT_PRESETS, AGENT_PROMPT_PREFIX_CATEGORY, API_CONFIG, AddAppModal, type AddAppModalProps, AgentActivityList, type AgentActivityListProps, type AgentActivityParams, type AgentActivityResponse, type AgentDecision, AgentExecutionDrawer, type AgentExecutionDrawerProps, AgentIcon, type AgentLocalModel, type AgentPreset, AgentPresets, type AgentPresetsProps, AgentPromptPrefixChip, type AgentPromptPrefixChipProps, type AgentRun, AgentRunDiagnosisBanner, AgentRunDrawer, type AgentRunDrawerProps, type AgentRunDrawerTab, type AgentRunResult, AgentUI, type AgentUIApp, type AgentUIProps, AgentsView, type AgentsViewProps, AiAgentPromptsEditor, type AiAgentPromptsEditorProps, type AlgoliaSearchApp, type ApiAuthEntry, AppAuthCard, type AppAuthCardProps, AppAuthConfig, AppAuthSection, type AppAuthSectionProps, type AppAuthState, type AppAuthentication$1 as AppAuthentication, AppDetailDrawer, AppDetailProvider, type AppLookupResult, AppSearchDrawer, type AppSelectedEvent, AppTitleHeader, type AppTitleHeaderProps, type AuthStatus, CASES_PATTERNS, COMMUNICATION_PATTERNS_NAMES, type CategoryAutomation, type CategoryConfig, type CustomStyles, DATASTORE_CATEGORIES, DEFAULT_AGENT_PROMPT_PREFIX, type DatastoreDiagnostics, type DatastoreItem, type DatastoreResponse, type DiagnosableRun, type DiagnosisEvidence, EDR_PATTERNS, EMAIL_APP_PATTERNS, FORWARD_TICKETS_WORKFLOW_NAME, type FetchAppsOptions, INGEST_TICKETS_WORKFLOW_NAME, type IngestionCategory, IntegrationStatus, LocalLLMConfig, type LocalLLMConfigProps, type LocalLLMTestResult, ShuffleMarkdown as Markdown, MarkdownJsonBlock, type OutputDiagnosis, type ResolvedApp, SIEM_PATTERNS, type ShuffleHostProps, ShuffleMCP, type ShuffleMCPHandle, type ShuffleMCPProps, ShuffleMarkdown, type ShuffleMcpColorMode, ShuffleMcpThemeProvider, type ShuffleMcpThemeProviderProps, ShufflePipelinesBanner, type ShuffleTheme, SingulActionsPreview, THREAT_INTEL_PATTERNS, TryMcpSection, type TryMcpSectionProps, UsageBar, type UsageBarProps, type UseAgentPromptPrefixOptions, VULN_SCANNER_PATTERNS, type ValidatedIngestionApp, VideoEmbed, applyRegionFromPayload, ShuffleMCP as default, deleteDatastoreItem, deleteDatastoreItems, diagnoseOutputWarning, extractActionAppNames, extractValidatedIngestionApps, extractWorkflowActionAppNames, extractWorkflowAppNames, fetchApps, fetchAppsViaApiConfig, findForwardTicketsWorkflow, findIngestTicketsWorkflow, getApiUrl, getAuthHeader, getDatastoreByCategory, getDatastoreItem, getDatastoreItemPublic, getDatastorePageSize, getFailureInfo, getHostBaseUrl, getIngestionCategory, hasOutputWarning, installFetchBreaker, invalidateAppsCache, invalidateResolvedApps, isCloud, isCloudDomain, isEmailApp, isIngestionApp, isOnprem, isThreatIntelApp, isVulnScannerApp, isWorkflowScheduleStopped, normalizeAppName, parseRunResult, refreshAllIntegrationStatus, registerProtectedOrigin, resetRegionUrl, resolveApp, resolveApps, resolveVideoUrl, scheduleAgentRun, searchAgentActivity, seedResolvedApp, setDatastoreItem, setDatastoreItems, setHostBaseUrl, setRegionUrl, setRuntimeOrgId, setToastImpl, shuffleFetch, toast, useAgentPromptPrefix, useAppAuth, useAppAuthFlow, useAppDetail, useAppDetailOptional, useAppLookup, useSyncHostBaseUrl };