@shuffleio/shuffle-mcps 0.0.40 → 0.0.46
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/{appsCache-EFH5WV4I.mjs → appsCache-ITT5ZZQS.mjs} +1 -1
- package/dist/{chunk-5LZ5IZ2O.mjs → chunk-45B7UK6Q.mjs} +431 -37
- package/dist/index.d.mts +335 -155
- package/dist/index.d.ts +335 -155
- package/dist/index.js +8637 -4373
- package/dist/index.mjs +7747 -3874
- package/dist/{shuffle-mcp-S6QOJJG4.css → shuffle-mcp-SHQXQS3F.css} +2 -2
- package/package.json +6 -3
|
@@ -1,4 +1,40 @@
|
|
|
1
1
|
// fetchBreaker.ts
|
|
2
|
+
var rewriteShufflerApiToShuffleSecurity = (input) => {
|
|
3
|
+
if (typeof window === "undefined") return input;
|
|
4
|
+
const currentHost = window.location.hostname.toLowerCase();
|
|
5
|
+
const isOnShuffleSecurity = currentHost === "shuffle.security" || currentHost.endsWith(".shuffle.security") || currentHost === "localhost" || currentHost === "127.0.0.1" || currentHost.includes("lovable");
|
|
6
|
+
if (!isOnShuffleSecurity) return input;
|
|
7
|
+
let urlStr = null;
|
|
8
|
+
if (typeof input === "string") urlStr = input;
|
|
9
|
+
else if (input instanceof URL) urlStr = input.toString();
|
|
10
|
+
else if (input && typeof input.url === "string") urlStr = input.url;
|
|
11
|
+
if (!urlStr) return input;
|
|
12
|
+
if (!urlStr.includes("/api/") || urlStr.includes("/api/v1/auth/exchange")) {
|
|
13
|
+
return input;
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const u = new URL(urlStr, window.location.href);
|
|
17
|
+
const host = u.hostname.toLowerCase();
|
|
18
|
+
if (host === "shuffler.io" || host === "www.shuffler.io") {
|
|
19
|
+
u.protocol = "https:";
|
|
20
|
+
u.hostname = "uk.shuffle.security";
|
|
21
|
+
const rewritten = u.toString();
|
|
22
|
+
if (typeof input === "string") return rewritten;
|
|
23
|
+
if (input instanceof URL) return new URL(rewritten);
|
|
24
|
+
if (typeof Request !== "undefined" && input instanceof Request) return new Request(rewritten, input);
|
|
25
|
+
} else if (host.endsWith(".shuffler.io")) {
|
|
26
|
+
const subdomain = host.slice(0, -".shuffler.io".length);
|
|
27
|
+
u.protocol = "https:";
|
|
28
|
+
u.hostname = `${subdomain}.shuffle.security`;
|
|
29
|
+
const rewritten = u.toString();
|
|
30
|
+
if (typeof input === "string") return rewritten;
|
|
31
|
+
if (input instanceof URL) return new URL(rewritten);
|
|
32
|
+
if (typeof Request !== "undefined" && input instanceof Request) return new Request(rewritten, input);
|
|
33
|
+
}
|
|
34
|
+
} catch {
|
|
35
|
+
}
|
|
36
|
+
return input;
|
|
37
|
+
};
|
|
2
38
|
var FAIL_THRESHOLD = 12;
|
|
3
39
|
var ROLLING_WINDOW_MS = 5e3;
|
|
4
40
|
var COOLDOWN_MS = 1e4;
|
|
@@ -64,12 +100,24 @@ var withStoredAuth = (input, init) => {
|
|
|
64
100
|
if (url.pathname === "/api/v1/login" || url.pathname === "/api/v1/users/register") return init;
|
|
65
101
|
const sessionToken = window.localStorage.getItem("session_token");
|
|
66
102
|
const token = sessionToken && sessionToken.trim().length > 0 ? sessionToken.trim() : null;
|
|
103
|
+
const authMode = window.localStorage.getItem("shuffle_auth_mode");
|
|
104
|
+
const isCapacitor = Boolean(
|
|
105
|
+
window.Capacitor?.isNativePlatform?.() || window._isCapacitorNative
|
|
106
|
+
);
|
|
67
107
|
const requestHeaders = typeof Request !== "undefined" && input instanceof Request ? input.headers : void 0;
|
|
68
108
|
const headers = new Headers(requestHeaders);
|
|
69
109
|
if (init?.headers) {
|
|
70
110
|
new Headers(init.headers).forEach((value, name) => headers.set(name, value));
|
|
71
111
|
}
|
|
72
|
-
|
|
112
|
+
const rootDomain = (host) => {
|
|
113
|
+
const parts = host.split(".");
|
|
114
|
+
return parts.length <= 2 ? host : parts.slice(-2).join(".");
|
|
115
|
+
};
|
|
116
|
+
const backendHost = url.hostname.toLowerCase();
|
|
117
|
+
const frontendHost = window.location.hostname.toLowerCase();
|
|
118
|
+
const isLocalPair = ["localhost", "127.0.0.1"].includes(backendHost) && ["localhost", "127.0.0.1"].includes(frontendHost);
|
|
119
|
+
const isCrossDomain = backendHost !== frontendHost && !isLocalPair && rootDomain(backendHost) !== rootDomain(frontendHost);
|
|
120
|
+
if (token && (authMode === "bearer" || isCapacitor || isCrossDomain) && !headers.has("Authorization")) {
|
|
73
121
|
headers.set("Authorization", `Bearer ${token}`);
|
|
74
122
|
}
|
|
75
123
|
if (!headers.has("Org-Id")) {
|
|
@@ -117,9 +165,10 @@ var installFetchBreaker = () => {
|
|
|
117
165
|
installed = true;
|
|
118
166
|
const original = window.fetch.bind(window);
|
|
119
167
|
window.fetch = (async (input, init) => {
|
|
120
|
-
const
|
|
121
|
-
const
|
|
122
|
-
|
|
168
|
+
const finalInput = rewriteShufflerApiToShuffleSecurity(input);
|
|
169
|
+
const authenticatedInit = withStoredAuth(finalInput, init);
|
|
170
|
+
const key = keyFor(finalInput, authenticatedInit);
|
|
171
|
+
if (!key) return original(finalInput, authenticatedInit);
|
|
123
172
|
const entry = getEntry(key);
|
|
124
173
|
const now = Date.now();
|
|
125
174
|
let isProbe = false;
|
|
@@ -153,7 +202,7 @@ var installFetchBreaker = () => {
|
|
|
153
202
|
};
|
|
154
203
|
let response;
|
|
155
204
|
try {
|
|
156
|
-
response = await original(
|
|
205
|
+
response = await original(finalInput, authenticatedInit);
|
|
157
206
|
} catch (err) {
|
|
158
207
|
const ts = Date.now();
|
|
159
208
|
entry.failures.push(ts);
|
|
@@ -240,23 +289,26 @@ var getShuffleCoreBaseUrl = () => {
|
|
|
240
289
|
if (savedCore && savedCore.trim().length > 0) {
|
|
241
290
|
return savedCore.trim().replace(/\/+$/, "");
|
|
242
291
|
}
|
|
292
|
+
} catch {
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
if (typeof window !== "undefined" && isManagedDomain()) {
|
|
296
|
+
return "https://shuffler.io";
|
|
297
|
+
}
|
|
298
|
+
if (typeof window !== "undefined") {
|
|
299
|
+
try {
|
|
243
300
|
const customHost = localStorage.getItem("shuffle_custom_host_url");
|
|
244
301
|
if (customHost && customHost.trim().length > 0) {
|
|
245
302
|
const cleaned = customHost.trim().replace(/\/+$/, "");
|
|
246
303
|
if (cleaned.includes(":5001")) {
|
|
247
304
|
return cleaned.replace(":5001", ":3001");
|
|
248
305
|
}
|
|
249
|
-
return cleaned;
|
|
250
306
|
}
|
|
251
307
|
} catch {
|
|
252
308
|
}
|
|
253
309
|
}
|
|
254
310
|
if (typeof window !== "undefined") {
|
|
255
311
|
const hostname = window.location.hostname;
|
|
256
|
-
const isManaged = isManagedDomain();
|
|
257
|
-
if (isManaged) {
|
|
258
|
-
return "https://shuffler.io";
|
|
259
|
-
}
|
|
260
312
|
if (window.location.port === "3001") {
|
|
261
313
|
return window.location.origin;
|
|
262
314
|
}
|
|
@@ -270,6 +322,212 @@ var getShuffleCoreUrl = (path) => {
|
|
|
270
322
|
const cleanPath = path.startsWith("/") ? path : `/${path}`;
|
|
271
323
|
return `${base}${cleanPath}`;
|
|
272
324
|
};
|
|
325
|
+
var getShuffleSecurityBaseUrl = () => {
|
|
326
|
+
const envUrl = readEnv("VITE_SHUFFLE_SECURITY_URL") || readEnv("SHUFFLE_SECURITY_URL");
|
|
327
|
+
if (envUrl) {
|
|
328
|
+
return envUrl.replace(/\/+$/, "");
|
|
329
|
+
}
|
|
330
|
+
if (typeof window !== "undefined") {
|
|
331
|
+
if (window.location.port !== "3001" && !window.location.hostname.includes("shuffler.io")) {
|
|
332
|
+
return window.location.origin;
|
|
333
|
+
}
|
|
334
|
+
if (window.location.port === "3001") {
|
|
335
|
+
return `${window.location.protocol}//${window.location.hostname}:3002`;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return "https://shuffle.security";
|
|
339
|
+
};
|
|
340
|
+
var getShuffleSecurityUrl = (path) => {
|
|
341
|
+
const base = getShuffleSecurityBaseUrl();
|
|
342
|
+
if (!path) return base;
|
|
343
|
+
const cleanPath = path.startsWith("/") ? path : `/${path}`;
|
|
344
|
+
return `${base}${cleanPath}`;
|
|
345
|
+
};
|
|
346
|
+
var getCurrentShuffleProduct = (override) => {
|
|
347
|
+
if (override) {
|
|
348
|
+
const o = override.trim().toLowerCase();
|
|
349
|
+
if (o === "core" || o === "automation") return "core";
|
|
350
|
+
if (o === "security") return "security";
|
|
351
|
+
}
|
|
352
|
+
if (typeof window !== "undefined") {
|
|
353
|
+
try {
|
|
354
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
355
|
+
const param = urlParams.get("product") || urlParams.get("shuffle_product");
|
|
356
|
+
if (param) {
|
|
357
|
+
const p = param.trim().toLowerCase();
|
|
358
|
+
if (p === "core" || p === "automation") return "core";
|
|
359
|
+
if (p === "security") return "security";
|
|
360
|
+
}
|
|
361
|
+
} catch {
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
const envProduct = readEnv("VITE_SHUFFLE_PRODUCT") || readEnv("SHUFFLE_PRODUCT");
|
|
365
|
+
if (envProduct) {
|
|
366
|
+
const p = envProduct.trim().toLowerCase();
|
|
367
|
+
if (p === "core" || p === "automation") return "core";
|
|
368
|
+
if (p === "security") return "security";
|
|
369
|
+
}
|
|
370
|
+
if (typeof window !== "undefined") {
|
|
371
|
+
const win = window;
|
|
372
|
+
if (win.__SHUFFLE_PRODUCT__) {
|
|
373
|
+
const p = String(win.__SHUFFLE_PRODUCT__).trim().toLowerCase();
|
|
374
|
+
if (p === "core" || p === "automation") return "core";
|
|
375
|
+
if (p === "security") return "security";
|
|
376
|
+
}
|
|
377
|
+
const hostname = window.location.hostname.toLowerCase();
|
|
378
|
+
const port = window.location.port;
|
|
379
|
+
if (port === "3001") return "core";
|
|
380
|
+
if (port === "3002") return "security";
|
|
381
|
+
if (hostname.includes("shuffler.io")) {
|
|
382
|
+
if (hostname.startsWith("security.") || hostname.includes(".security.")) {
|
|
383
|
+
return "security";
|
|
384
|
+
}
|
|
385
|
+
return "core";
|
|
386
|
+
}
|
|
387
|
+
if (hostname.includes("shuffle.security")) {
|
|
388
|
+
return "security";
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return "security";
|
|
392
|
+
};
|
|
393
|
+
var CORE_EXCLUSIVE_PATH_PREFIXES = [
|
|
394
|
+
"/workflows",
|
|
395
|
+
"/new-dashboard",
|
|
396
|
+
"/apps/new"
|
|
397
|
+
];
|
|
398
|
+
var CORE_ADMIN_TABS = ["datastore", "files", "locations", "runtime_locations"];
|
|
399
|
+
var SECURITY_EXCLUSIVE_PATH_PREFIXES = [
|
|
400
|
+
"/incidents",
|
|
401
|
+
"/incidents-simple",
|
|
402
|
+
"/alerts",
|
|
403
|
+
"/cases",
|
|
404
|
+
"/monitors",
|
|
405
|
+
"/vulnerabilities",
|
|
406
|
+
"/detection",
|
|
407
|
+
"/assets",
|
|
408
|
+
"/tickets"
|
|
409
|
+
];
|
|
410
|
+
var isCoreExclusivePath = (path) => {
|
|
411
|
+
if (!path) return false;
|
|
412
|
+
const clean = path.startsWith("/") ? path : `/${path}`;
|
|
413
|
+
const [pathname, search] = clean.split("?");
|
|
414
|
+
if (CORE_EXCLUSIVE_PATH_PREFIXES.some((prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`))) {
|
|
415
|
+
return true;
|
|
416
|
+
}
|
|
417
|
+
if (pathname === "/admin" && search) {
|
|
418
|
+
const params = new URLSearchParams(search);
|
|
419
|
+
const tab = params.get("tab");
|
|
420
|
+
if (tab && CORE_ADMIN_TABS.includes(tab.toLowerCase())) {
|
|
421
|
+
return true;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return false;
|
|
425
|
+
};
|
|
426
|
+
var isSecurityExclusivePath = (path) => {
|
|
427
|
+
if (!path) return false;
|
|
428
|
+
const clean = path.startsWith("/") ? path : `/${path}`;
|
|
429
|
+
const [pathname] = clean.split("?");
|
|
430
|
+
return SECURITY_EXCLUSIVE_PATH_PREFIXES.some((prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`));
|
|
431
|
+
};
|
|
432
|
+
var resolveProductLink = (href, currentProductOverride) => {
|
|
433
|
+
const currentProduct = getCurrentShuffleProduct(currentProductOverride);
|
|
434
|
+
const trimmed = (href || "").trim();
|
|
435
|
+
if (!trimmed) {
|
|
436
|
+
return { url: "", isInternal: false, targetProduct: "external", isCrossDomainToCore: false };
|
|
437
|
+
}
|
|
438
|
+
if (trimmed.startsWith("#")) {
|
|
439
|
+
return { url: trimmed, isInternal: true, targetProduct: "doc", isCrossDomainToCore: false };
|
|
440
|
+
}
|
|
441
|
+
let pathname = "";
|
|
442
|
+
let searchAndHash = "";
|
|
443
|
+
let isAbsolute = false;
|
|
444
|
+
let isShufflerIoDomain = false;
|
|
445
|
+
let isShuffleSecurityDomain = false;
|
|
446
|
+
try {
|
|
447
|
+
if (/^[a-z][a-z\d+.-]*:/i.test(trimmed)) {
|
|
448
|
+
isAbsolute = true;
|
|
449
|
+
const parsed = new URL(trimmed);
|
|
450
|
+
pathname = parsed.pathname;
|
|
451
|
+
searchAndHash = `${parsed.search}${parsed.hash}`;
|
|
452
|
+
const host = parsed.hostname.toLowerCase();
|
|
453
|
+
if (host === "shuffler.io" || host.endsWith(".shuffler.io") && !host.includes("security.")) {
|
|
454
|
+
isShufflerIoDomain = true;
|
|
455
|
+
} else if (host.includes("shuffle.security") || host.includes("security.shuffler.io")) {
|
|
456
|
+
isShuffleSecurityDomain = true;
|
|
457
|
+
}
|
|
458
|
+
} else {
|
|
459
|
+
const splitIdx = trimmed.search(/[?#]/);
|
|
460
|
+
if (splitIdx !== -1) {
|
|
461
|
+
pathname = trimmed.slice(0, splitIdx);
|
|
462
|
+
searchAndHash = trimmed.slice(splitIdx);
|
|
463
|
+
} else {
|
|
464
|
+
pathname = trimmed;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
} catch {
|
|
468
|
+
pathname = trimmed;
|
|
469
|
+
}
|
|
470
|
+
const fullRelativePath = `${pathname}${searchAndHash}`;
|
|
471
|
+
const isDocPath = /^\/docs(?:\/|$)/i.test(pathname) || /(?:^|\/)\.?\.?\/?[^/#?]+\.md(?:$|[?#])/i.test(trimmed);
|
|
472
|
+
if (isDocPath) {
|
|
473
|
+
return {
|
|
474
|
+
url: fullRelativePath,
|
|
475
|
+
isInternal: true,
|
|
476
|
+
targetProduct: "doc",
|
|
477
|
+
isCrossDomainToCore: false
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
const targetsCore = isCoreExclusivePath(fullRelativePath) || isShufflerIoDomain;
|
|
481
|
+
const targetsSecurity = isSecurityExclusivePath(fullRelativePath) || isShuffleSecurityDomain;
|
|
482
|
+
if (targetsCore) {
|
|
483
|
+
if (currentProduct === "core") {
|
|
484
|
+
return {
|
|
485
|
+
url: fullRelativePath,
|
|
486
|
+
isInternal: true,
|
|
487
|
+
targetProduct: "core",
|
|
488
|
+
isCrossDomainToCore: false
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
const targetUrl = getShuffleCoreUrl(fullRelativePath);
|
|
492
|
+
return {
|
|
493
|
+
url: targetUrl,
|
|
494
|
+
isInternal: false,
|
|
495
|
+
targetProduct: "core",
|
|
496
|
+
isCrossDomainToCore: true
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
if (targetsSecurity) {
|
|
500
|
+
if (currentProduct === "security") {
|
|
501
|
+
return {
|
|
502
|
+
url: fullRelativePath,
|
|
503
|
+
isInternal: true,
|
|
504
|
+
targetProduct: "security",
|
|
505
|
+
isCrossDomainToCore: false
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
const targetUrl = getShuffleSecurityUrl(fullRelativePath);
|
|
509
|
+
return {
|
|
510
|
+
url: targetUrl,
|
|
511
|
+
isInternal: false,
|
|
512
|
+
targetProduct: "security",
|
|
513
|
+
isCrossDomainToCore: false
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
if (trimmed.startsWith("/")) {
|
|
517
|
+
return {
|
|
518
|
+
url: trimmed,
|
|
519
|
+
isInternal: true,
|
|
520
|
+
targetProduct: currentProduct,
|
|
521
|
+
isCrossDomainToCore: false
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
return {
|
|
525
|
+
url: trimmed,
|
|
526
|
+
isInternal: false,
|
|
527
|
+
targetProduct: "external",
|
|
528
|
+
isCrossDomainToCore: false
|
|
529
|
+
};
|
|
530
|
+
};
|
|
273
531
|
|
|
274
532
|
// ../lib/platform.ts
|
|
275
533
|
var getPlatform = () => {
|
|
@@ -328,9 +586,57 @@ if (typeof window !== "undefined") {
|
|
|
328
586
|
// api.ts
|
|
329
587
|
installFetchBreaker();
|
|
330
588
|
var DEV_BACKEND = "https://tunnel.schemaless.org";
|
|
331
|
-
var PROD_BACKEND = "https://uk.
|
|
589
|
+
var PROD_BACKEND = "https://uk.shuffle.security";
|
|
332
590
|
var SHUFFLE_AUTOMATION_URL = getShuffleCoreUrl("/new-dashboard");
|
|
333
|
-
var CLOUD_DOMAINS = [
|
|
591
|
+
var CLOUD_DOMAINS = [
|
|
592
|
+
"shuffle.security",
|
|
593
|
+
"www.shuffle.security",
|
|
594
|
+
"uk.shuffle.security",
|
|
595
|
+
"security.shuffler.io",
|
|
596
|
+
"shuffler.io",
|
|
597
|
+
"shutdown.no",
|
|
598
|
+
"www.shutdown.no"
|
|
599
|
+
];
|
|
600
|
+
var isShuffleCloudDomain = (url) => {
|
|
601
|
+
if (!url || typeof url !== "string") return false;
|
|
602
|
+
try {
|
|
603
|
+
const raw = url.trim();
|
|
604
|
+
const parsed = new URL(raw.includes("://") ? raw : `https://${raw}`);
|
|
605
|
+
const host = parsed.hostname.toLowerCase();
|
|
606
|
+
return host === "shuffler.io" || host.endsWith(".shuffler.io") || host === "shuffle.security" || host.endsWith(".shuffle.security");
|
|
607
|
+
} catch {
|
|
608
|
+
return false;
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
var mapCloudRegionUrl = (url) => {
|
|
612
|
+
if (!url || typeof url !== "string") return "";
|
|
613
|
+
const trimmed = url.trim();
|
|
614
|
+
if (!trimmed) return "";
|
|
615
|
+
const hasScheme = /^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(trimmed);
|
|
616
|
+
const toParse = hasScheme ? trimmed : `https://${trimmed}`;
|
|
617
|
+
try {
|
|
618
|
+
const parsed = new URL(toParse);
|
|
619
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
620
|
+
if (hostname === "shuffler.io" || hostname === "www.shuffler.io" || hostname === "shuffle.security" || hostname === "www.shuffle.security") {
|
|
621
|
+
parsed.protocol = "https:";
|
|
622
|
+
parsed.hostname = "uk.shuffle.security";
|
|
623
|
+
return parsed.toString().replace(/\/+$/, "");
|
|
624
|
+
}
|
|
625
|
+
if (hostname.endsWith(".shuffler.io")) {
|
|
626
|
+
const subdomain = hostname.slice(0, -".shuffler.io".length);
|
|
627
|
+
parsed.protocol = "https:";
|
|
628
|
+
parsed.hostname = `${subdomain}.shuffle.security`;
|
|
629
|
+
return parsed.toString().replace(/\/+$/, "");
|
|
630
|
+
}
|
|
631
|
+
if (hostname.endsWith(".shuffle.security")) {
|
|
632
|
+
parsed.protocol = "https:";
|
|
633
|
+
return parsed.toString().replace(/\/+$/, "");
|
|
634
|
+
}
|
|
635
|
+
return trimmed.replace(/\/+$/, "");
|
|
636
|
+
} catch {
|
|
637
|
+
return trimmed.replace(/\/+$/, "");
|
|
638
|
+
}
|
|
639
|
+
};
|
|
334
640
|
var getEnvVar = (key) => {
|
|
335
641
|
try {
|
|
336
642
|
const meta = new Function("try { return import.meta } catch { return undefined }")();
|
|
@@ -345,9 +651,12 @@ var isDevEnvironment = () => {
|
|
|
345
651
|
return hostname.includes("lovableproject.com") || hostname.includes("id-preview--") || hostname.endsWith(".lovable.app") || hostname.endsWith(".lovable.dev");
|
|
346
652
|
};
|
|
347
653
|
var isCloudDomain = () => {
|
|
348
|
-
if (isCapacitorNative())
|
|
654
|
+
if (isCapacitorNative()) {
|
|
655
|
+
if (getHostBaseUrl()) return false;
|
|
656
|
+
return true;
|
|
657
|
+
}
|
|
349
658
|
const hostname = typeof window !== "undefined" ? window.location.hostname : "";
|
|
350
|
-
return CLOUD_DOMAINS.includes(hostname);
|
|
659
|
+
return CLOUD_DOMAINS.includes(hostname) || hostname.endsWith(".shuffle.security") || hostname.endsWith(".shuffler.io");
|
|
351
660
|
};
|
|
352
661
|
var isCloud = () => isCloudDomain();
|
|
353
662
|
var isOnprem = () => !isDevEnvironment() && !isCloudDomain();
|
|
@@ -357,7 +666,11 @@ var getDefaultBaseUrl = () => {
|
|
|
357
666
|
return envUrl;
|
|
358
667
|
}
|
|
359
668
|
if (isDevEnvironment()) return DEV_BACKEND;
|
|
360
|
-
if (isCapacitorNative())
|
|
669
|
+
if (isCapacitorNative()) {
|
|
670
|
+
const customHost = getHostBaseUrl();
|
|
671
|
+
if (customHost) return customHost;
|
|
672
|
+
return PROD_BACKEND;
|
|
673
|
+
}
|
|
361
674
|
if (isCloudDomain()) return PROD_BACKEND;
|
|
362
675
|
if (typeof window !== "undefined") {
|
|
363
676
|
return window.location.origin;
|
|
@@ -371,11 +684,13 @@ var readCachedRegion = () => {
|
|
|
371
684
|
const raw = localStorage.getItem(REGION_STORAGE_KEY);
|
|
372
685
|
if (!raw) return { url: null, orgId: null };
|
|
373
686
|
const parsed = JSON.parse(raw);
|
|
374
|
-
const
|
|
375
|
-
if (url
|
|
687
|
+
const rawUrl = parsed?.url ? parsed.url.replace(/\/+$/, "") : null;
|
|
688
|
+
if (!rawUrl) return { url: null, orgId: parsed?.orgId || null };
|
|
689
|
+
const mapped = mapCloudRegionUrl(rawUrl);
|
|
690
|
+
if (mapped === "https://shuffler.io" || mapped === "https://uk.shuffler.io" || mapped === "https://shuffle.security" || mapped === "https://uk.shuffle.security" || mapped === PROD_BACKEND) {
|
|
376
691
|
return { url: null, orgId: parsed?.orgId || null };
|
|
377
692
|
}
|
|
378
|
-
return { url, orgId: parsed?.orgId || null };
|
|
693
|
+
return { url: mapped, orgId: parsed?.orgId || null };
|
|
379
694
|
} catch {
|
|
380
695
|
return { url: null, orgId: null };
|
|
381
696
|
}
|
|
@@ -389,7 +704,23 @@ var readCachedCustomHost = () => {
|
|
|
389
704
|
if (mode && mode !== "self-hosted") return null;
|
|
390
705
|
const raw = localStorage.getItem("shuffle_custom_host_url");
|
|
391
706
|
const cleaned = raw ? raw.trim().replace(/\/+$/, "") : null;
|
|
392
|
-
if (!cleaned)
|
|
707
|
+
if (!cleaned) {
|
|
708
|
+
const host = window.location.hostname.toLowerCase();
|
|
709
|
+
if ((host === "localhost" || host === "127.0.0.1" || host === "[::1]" || host.endsWith(".localhost")) && mode !== "cloud") {
|
|
710
|
+
return "http://localhost:5001";
|
|
711
|
+
}
|
|
712
|
+
return null;
|
|
713
|
+
}
|
|
714
|
+
if (isShuffleCloudDomain(cleaned)) {
|
|
715
|
+
try {
|
|
716
|
+
localStorage.removeItem("shuffle_custom_host_url");
|
|
717
|
+
if (mode === "self-hosted") {
|
|
718
|
+
localStorage.setItem("shuffle_selected_server_mode", "cloud");
|
|
719
|
+
}
|
|
720
|
+
} catch {
|
|
721
|
+
}
|
|
722
|
+
return null;
|
|
723
|
+
}
|
|
393
724
|
if (cleaned === DEV_BACKEND && !isDevEnvironment() && mode !== "self-hosted") {
|
|
394
725
|
try {
|
|
395
726
|
localStorage.removeItem("shuffle_custom_host_url");
|
|
@@ -437,23 +768,28 @@ if (typeof window !== "undefined") {
|
|
|
437
768
|
if (e.key === REGION_STORAGE_KEY) sync();
|
|
438
769
|
});
|
|
439
770
|
}
|
|
440
|
-
var isShufflerSubdomain = (url) => {
|
|
441
|
-
try {
|
|
442
|
-
const parsed = new URL(url);
|
|
443
|
-
return parsed.hostname.endsWith(".shuffler.io") || parsed.hostname === "shuffler.io";
|
|
444
|
-
} catch {
|
|
445
|
-
return false;
|
|
446
|
-
}
|
|
447
|
-
};
|
|
448
771
|
var setRegionUrl = (regionUrl, orgId) => {
|
|
449
772
|
_trackedOrgId = orgId || null;
|
|
450
|
-
if (regionUrl
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
773
|
+
if (regionUrl) {
|
|
774
|
+
const isSelfHosted = !isCloudDomain() || Boolean(_hostBaseUrl);
|
|
775
|
+
if (isShuffleCloudDomain(regionUrl)) {
|
|
776
|
+
if (isSelfHosted) {
|
|
777
|
+
_regionUrl = null;
|
|
778
|
+
persistRegion(null, _trackedOrgId);
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
const mapped = mapCloudRegionUrl(regionUrl);
|
|
782
|
+
const normalized = mapped.replace(/\/+$/, "");
|
|
783
|
+
const isDefaultCloud = normalized === PROD_BACKEND || normalized === "https://shuffler.io" || normalized === "https://uk.shuffler.io" || normalized === "https://shuffle.security" || normalized === "https://uk.shuffle.security";
|
|
784
|
+
if (!isDefaultCloud) {
|
|
785
|
+
_regionUrl = normalized;
|
|
786
|
+
persistRegion(_regionUrl, _trackedOrgId);
|
|
787
|
+
console.log(`[API] Region URL set to: ${_regionUrl}`);
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
} else {
|
|
791
|
+
_regionUrl = regionUrl.replace(/\/+$/, "");
|
|
455
792
|
persistRegion(_regionUrl, _trackedOrgId);
|
|
456
|
-
console.log(`[API] Region URL set to: ${_regionUrl}`);
|
|
457
793
|
return;
|
|
458
794
|
}
|
|
459
795
|
}
|
|
@@ -463,7 +799,8 @@ var setRegionUrl = (regionUrl, orgId) => {
|
|
|
463
799
|
var applyRegionFromPayload = (payload, orgIdOverride) => {
|
|
464
800
|
if (!payload || typeof payload !== "object") return null;
|
|
465
801
|
const orgId = orgIdOverride ?? payload?.active_org?.id ?? payload?.org_id ?? null;
|
|
466
|
-
const
|
|
802
|
+
const rawRegionUrl = payload?.region_url || payload?.active_org?.region_url || null;
|
|
803
|
+
const regionUrl = rawRegionUrl ? mapCloudRegionUrl(rawRegionUrl) : null;
|
|
467
804
|
setRegionUrl(regionUrl, orgId);
|
|
468
805
|
return regionUrl;
|
|
469
806
|
};
|
|
@@ -518,9 +855,12 @@ var getSessionToken = () => {
|
|
|
518
855
|
localStorage.removeItem(LEGACY_API_KEY_STORAGE_KEY);
|
|
519
856
|
}
|
|
520
857
|
const stored = localStorage.getItem("session_token");
|
|
521
|
-
if (stored && stored.trim().length > 0 && stored !== "null" && stored !== "undefined") {
|
|
858
|
+
if (stored && stored.trim().length > 0 && stored !== "null" && stored !== "undefined" && stored !== "authenticated" && stored !== "session" && stored !== "cookie-session") {
|
|
522
859
|
return stored.trim();
|
|
523
860
|
}
|
|
861
|
+
if (stored === "authenticated" || stored === "session" || stored === "cookie-session") {
|
|
862
|
+
localStorage.removeItem("session_token");
|
|
863
|
+
}
|
|
524
864
|
return null;
|
|
525
865
|
} catch {
|
|
526
866
|
return null;
|
|
@@ -528,13 +868,62 @@ var getSessionToken = () => {
|
|
|
528
868
|
};
|
|
529
869
|
var setSessionToken = (token) => {
|
|
530
870
|
clearAuthTokens();
|
|
531
|
-
if (token && token.trim().length > 0) {
|
|
871
|
+
if (token && token.trim().length > 0 && token !== "authenticated" && token !== "session" && token !== "cookie-session" && token !== "null" && token !== "undefined") {
|
|
532
872
|
try {
|
|
533
873
|
localStorage.setItem("session_token", token.trim());
|
|
534
874
|
} catch {
|
|
535
875
|
}
|
|
536
876
|
}
|
|
537
877
|
};
|
|
878
|
+
var isShuffleSecurityBackend = (backendUrl) => {
|
|
879
|
+
try {
|
|
880
|
+
const backend = backendUrl || API_CONFIG.baseUrl || "";
|
|
881
|
+
if (backend) {
|
|
882
|
+
const parsed = new URL(backend.includes("://") ? backend : `https://${backend}`);
|
|
883
|
+
const host = parsed.hostname.toLowerCase();
|
|
884
|
+
if (host === "shuffle.security" || host.endsWith(".shuffle.security") || host === "shuffler.io" || host.endsWith(".shuffler.io")) {
|
|
885
|
+
return true;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
} catch {
|
|
889
|
+
}
|
|
890
|
+
if (typeof window !== "undefined") {
|
|
891
|
+
try {
|
|
892
|
+
const windowHost = window.location.hostname.toLowerCase();
|
|
893
|
+
if (windowHost === "shuffle.security" || windowHost.endsWith(".shuffle.security") || windowHost === "shuffler.io" || windowHost.endsWith(".shuffler.io")) {
|
|
894
|
+
return true;
|
|
895
|
+
}
|
|
896
|
+
} catch {
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
return false;
|
|
900
|
+
};
|
|
901
|
+
var isCrossDomainBackend = (targetUrl) => {
|
|
902
|
+
if (typeof window === "undefined") return false;
|
|
903
|
+
try {
|
|
904
|
+
const backendUrl = targetUrl || API_CONFIG.baseUrl;
|
|
905
|
+
if (!backendUrl) return false;
|
|
906
|
+
const backendHost = new URL(backendUrl, window.location.origin).hostname.toLowerCase();
|
|
907
|
+
const frontendHost = window.location.hostname.toLowerCase();
|
|
908
|
+
if (backendHost === frontendHost) return false;
|
|
909
|
+
const isLocalFrontend = frontendHost === "localhost" || frontendHost === "127.0.0.1";
|
|
910
|
+
const isLocalBackend = backendHost === "localhost" || backendHost === "127.0.0.1";
|
|
911
|
+
if (isLocalFrontend && isLocalBackend) return false;
|
|
912
|
+
const getRootDomain = (host) => {
|
|
913
|
+
const parts = host.split(".");
|
|
914
|
+
if (parts.length <= 2) return host;
|
|
915
|
+
return parts.slice(-2).join(".");
|
|
916
|
+
};
|
|
917
|
+
const frontendRoot = getRootDomain(frontendHost);
|
|
918
|
+
const backendRoot = getRootDomain(backendHost);
|
|
919
|
+
if (frontendRoot && backendRoot && frontendRoot === backendRoot) {
|
|
920
|
+
return false;
|
|
921
|
+
}
|
|
922
|
+
return true;
|
|
923
|
+
} catch {
|
|
924
|
+
return false;
|
|
925
|
+
}
|
|
926
|
+
};
|
|
538
927
|
var API_CONFIG = {
|
|
539
928
|
// Shuffle backend URL — host override beats region URL beats default.
|
|
540
929
|
get baseUrl() {
|
|
@@ -575,8 +964,9 @@ var shuffleFetch = (url, init) => {
|
|
|
575
964
|
};
|
|
576
965
|
var getAuthHeader = (overrideOrgId) => {
|
|
577
966
|
const headers = {};
|
|
967
|
+
const authMode = typeof localStorage !== "undefined" ? localStorage.getItem("shuffle_auth_mode") : null;
|
|
578
968
|
const token = getSessionToken();
|
|
579
|
-
if (token) {
|
|
969
|
+
if (token && (authMode === "bearer" || isCapacitorNative() || isCrossDomainBackend())) {
|
|
580
970
|
headers["Authorization"] = `Bearer ${token}`;
|
|
581
971
|
}
|
|
582
972
|
let orgId = overrideOrgId ?? _trackedOrgId;
|
|
@@ -661,9 +1051,12 @@ var fetchAppsViaApiConfig = () => {
|
|
|
661
1051
|
};
|
|
662
1052
|
|
|
663
1053
|
export {
|
|
1054
|
+
resolveProductLink,
|
|
664
1055
|
registerProtectedOrigin,
|
|
665
1056
|
installFetchBreaker,
|
|
666
1057
|
isCapacitorNative,
|
|
1058
|
+
isShuffleCloudDomain,
|
|
1059
|
+
mapCloudRegionUrl,
|
|
667
1060
|
isCloudDomain,
|
|
668
1061
|
isCloud,
|
|
669
1062
|
isOnprem,
|
|
@@ -673,6 +1066,7 @@ export {
|
|
|
673
1066
|
setHostBaseUrl,
|
|
674
1067
|
getHostBaseUrl,
|
|
675
1068
|
getTrackedOrgId,
|
|
1069
|
+
isShuffleSecurityBackend,
|
|
676
1070
|
API_CONFIG,
|
|
677
1071
|
getApiUrl,
|
|
678
1072
|
shuffleFetch,
|