@egain/egain-mcp-server 1.0.12 → 1.0.13
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/bin/mcp-server.js +140 -1177
- package/bin/mcp-server.js.map +6 -6
- package/esm/src/hooks/auth-hook.d.ts +4 -0
- package/esm/src/hooks/auth-hook.d.ts.map +1 -1
- package/esm/src/hooks/auth-hook.js +189 -1184
- package/esm/src/hooks/auth-hook.js.map +1 -1
- package/esm/src/lib/config.d.ts +2 -2
- package/esm/src/lib/config.js +2 -2
- package/esm/src/mcp-server/mcp-server.js +1 -1
- package/esm/src/mcp-server/server.js +1 -1
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/src/hooks/auth-hook.ts +185 -1191
- package/src/lib/config.ts +2 -2
- package/src/mcp-server/mcp-server.ts +1 -1
- package/src/mcp-server/server.ts +1 -1
package/bin/mcp-server.js
CHANGED
|
@@ -4046,9 +4046,9 @@ var init_config = __esm(() => {
|
|
|
4046
4046
|
SDK_METADATA = {
|
|
4047
4047
|
language: "typescript",
|
|
4048
4048
|
openapiDocVersion: "1.0.0",
|
|
4049
|
-
sdkVersion: "1.0.
|
|
4049
|
+
sdkVersion: "1.0.13",
|
|
4050
4050
|
genVersion: "2.723.8",
|
|
4051
|
-
userAgent: "speakeasy-sdk/mcp-typescript 1.0.
|
|
4051
|
+
userAgent: "speakeasy-sdk/mcp-typescript 1.0.13 2.723.8 1.0.0 @egain/egain-mcp-server"
|
|
4052
4052
|
};
|
|
4053
4053
|
});
|
|
4054
4054
|
|
|
@@ -40910,9 +40910,6 @@ class AuthenticationHook {
|
|
|
40910
40910
|
return {};
|
|
40911
40911
|
}
|
|
40912
40912
|
getSafariWarningPage() {
|
|
40913
|
-
if (SAFARI_WARNING_HTML) {
|
|
40914
|
-
return SAFARI_WARNING_HTML;
|
|
40915
|
-
}
|
|
40916
40913
|
try {
|
|
40917
40914
|
const projectRoot = getProjectRoot();
|
|
40918
40915
|
const htmlPath = path.join(projectRoot, "src", "hooks", "auth-pages", "safari-warning.html");
|
|
@@ -40923,9 +40920,6 @@ class AuthenticationHook {
|
|
|
40923
40920
|
}
|
|
40924
40921
|
}
|
|
40925
40922
|
getConfigPage() {
|
|
40926
|
-
if (CONFIG_PAGE_HTML) {
|
|
40927
|
-
return CONFIG_PAGE_HTML;
|
|
40928
|
-
}
|
|
40929
40923
|
try {
|
|
40930
40924
|
const projectRoot = getProjectRoot();
|
|
40931
40925
|
const htmlPath = path.join(projectRoot, "src", "hooks", "auth-pages", "config-page.html");
|
|
@@ -40936,9 +40930,6 @@ class AuthenticationHook {
|
|
|
40936
40930
|
}
|
|
40937
40931
|
}
|
|
40938
40932
|
getConfigPageJS() {
|
|
40939
|
-
if (CONFIG_PAGE_JS) {
|
|
40940
|
-
return CONFIG_PAGE_JS;
|
|
40941
|
-
}
|
|
40942
40933
|
try {
|
|
40943
40934
|
const projectRoot = getProjectRoot();
|
|
40944
40935
|
const jsPath = path.join(projectRoot, "src", "hooks", "auth-pages", "config-page.js");
|
|
@@ -40948,6 +40939,16 @@ class AuthenticationHook {
|
|
|
40948
40939
|
return "";
|
|
40949
40940
|
}
|
|
40950
40941
|
}
|
|
40942
|
+
getBrowserErrorPage() {
|
|
40943
|
+
try {
|
|
40944
|
+
const projectRoot = getProjectRoot();
|
|
40945
|
+
const htmlPath = path.join(projectRoot, "src", "hooks", "auth-pages", "browser-error.html");
|
|
40946
|
+
return fs.readFileSync(htmlPath, "utf8");
|
|
40947
|
+
} catch (error) {
|
|
40948
|
+
console.error("⚠️ Could not load browser error page:", error);
|
|
40949
|
+
return "<html><body><h1>Browser Monitoring Issue</h1><p>We cannot read the current page URL from your browser. Please restart your browser and try again.</p></body></html>";
|
|
40950
|
+
}
|
|
40951
|
+
}
|
|
40951
40952
|
buildAuthUrl() {
|
|
40952
40953
|
const { environmentUrl, clientId, redirectUri, authUrl, scopePrefix } = this.authConfig;
|
|
40953
40954
|
console.error("\uD83D\uDD27 Building OAuth URL...");
|
|
@@ -41233,6 +41234,11 @@ class AuthenticationHook {
|
|
|
41233
41234
|
res.end(this.getSafariWarningPage());
|
|
41234
41235
|
return;
|
|
41235
41236
|
}
|
|
41237
|
+
if (url.pathname === "/browser-error") {
|
|
41238
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
41239
|
+
res.end(this.getBrowserErrorPage());
|
|
41240
|
+
return;
|
|
41241
|
+
}
|
|
41236
41242
|
if (url.pathname === "/get-config" && req.method === "GET") {
|
|
41237
41243
|
try {
|
|
41238
41244
|
const hasValidConfig = this.authConfig.environmentUrl && this.authConfig.clientId && this.authConfig.authUrl && this.authConfig.accessUrl && this.authConfig.redirectUri;
|
|
@@ -41261,6 +41267,17 @@ class AuthenticationHook {
|
|
|
41261
41267
|
}
|
|
41262
41268
|
if (url.pathname === "/get-oauth-url" && req.method === "POST") {
|
|
41263
41269
|
try {
|
|
41270
|
+
if (this.detectedBrowser === "Firefox" && process.platform === "darwin") {
|
|
41271
|
+
console.error(`❌ Firefox detected - browser URL monitoring not available`);
|
|
41272
|
+
console.error(`⚠️ Redirecting to error page instead of OAuth URL`);
|
|
41273
|
+
const errorUrl = `http://${CONFIG_SERVER_HOST}:${CONFIG_SERVER_PORT}/browser-error?type=monitoring&browser=${encodeURIComponent(this.detectedBrowser)}`;
|
|
41274
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
41275
|
+
res.end(JSON.stringify({
|
|
41276
|
+
success: true,
|
|
41277
|
+
oauthUrl: errorUrl
|
|
41278
|
+
}));
|
|
41279
|
+
return;
|
|
41280
|
+
}
|
|
41264
41281
|
const oauthUrl = this.buildAuthUrl();
|
|
41265
41282
|
console.error("\uD83D\uDD10 Generated OAuth URL for saved configuration");
|
|
41266
41283
|
console.error("\uD83D\uDD17 OAuth URL:", oauthUrl);
|
|
@@ -41338,6 +41355,18 @@ class AuthenticationHook {
|
|
|
41338
41355
|
} catch (error) {
|
|
41339
41356
|
console.error("⚠️ Failed to save config to file:", error);
|
|
41340
41357
|
}
|
|
41358
|
+
if (this.detectedBrowser === "Firefox" && process.platform === "darwin") {
|
|
41359
|
+
console.error(`❌ Firefox detected - browser URL monitoring not available`);
|
|
41360
|
+
console.error(`⚠️ Redirecting to error page instead of OAuth URL`);
|
|
41361
|
+
const errorUrl = `http://${CONFIG_SERVER_HOST}:${CONFIG_SERVER_PORT}/browser-error?type=monitoring&browser=${encodeURIComponent(this.detectedBrowser)}`;
|
|
41362
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
41363
|
+
res.end(JSON.stringify({
|
|
41364
|
+
success: true,
|
|
41365
|
+
message: "Firefox detected - showing browser compatibility information...",
|
|
41366
|
+
oauthUrl: errorUrl
|
|
41367
|
+
}));
|
|
41368
|
+
return;
|
|
41369
|
+
}
|
|
41341
41370
|
const oauthUrl = this.buildAuthUrl();
|
|
41342
41371
|
console.error("\uD83D\uDD10 Generated OAuth URL for browser redirect");
|
|
41343
41372
|
console.error("\uD83D\uDD17 OAuth URL:", oauthUrl);
|
|
@@ -41488,8 +41517,18 @@ class AuthenticationHook {
|
|
|
41488
41517
|
let oAuthErrorLogged = false;
|
|
41489
41518
|
let lastUrl = "";
|
|
41490
41519
|
let lastErrorUrl = null;
|
|
41520
|
+
let aboutBlankCount = 0;
|
|
41521
|
+
const ABOUT_BLANK_THRESHOLD = 1;
|
|
41522
|
+
let firefoxWarningLogged = false;
|
|
41491
41523
|
if (platform === "darwin") {
|
|
41492
|
-
|
|
41524
|
+
if (this.detectedBrowser === "Firefox") {
|
|
41525
|
+
console.error(`❌ Firefox detected - Firefox is not supported for authentication`);
|
|
41526
|
+
console.error(`⚠️ Firefox cannot detect authorization codes from external redirect URLs`);
|
|
41527
|
+
console.error(`\uD83D\uDCA1 Please use Chrome, Edge, or Brave browser instead`);
|
|
41528
|
+
return;
|
|
41529
|
+
} else {
|
|
41530
|
+
console.error(`\uD83D\uDD0D Monitoring ${this.detectedBrowser} for authorization code...`);
|
|
41531
|
+
}
|
|
41493
41532
|
} else if (platform === "win32") {
|
|
41494
41533
|
console.error(`\uD83D\uDD0D Monitoring ${this.detectedBrowser} for authorization code...`);
|
|
41495
41534
|
}
|
|
@@ -41499,19 +41538,31 @@ class AuthenticationHook {
|
|
|
41499
41538
|
throw new Error("Authentication timeout. Please try again.");
|
|
41500
41539
|
}
|
|
41501
41540
|
let currentUrl = "";
|
|
41541
|
+
let browserMonitoringError = false;
|
|
41502
41542
|
if (platform === "darwin") {
|
|
41503
|
-
|
|
41504
|
-
|
|
41505
|
-
|
|
41506
|
-
|
|
41507
|
-
|
|
41508
|
-
|
|
41509
|
-
|
|
41510
|
-
|
|
41511
|
-
|
|
41512
|
-
|
|
41513
|
-
|
|
41514
|
-
|
|
41543
|
+
try {
|
|
41544
|
+
const browserName = this.detectedBrowser.replace(/"/g, "\\\"");
|
|
41545
|
+
if (this.detectedBrowser === "Firefox") {
|
|
41546
|
+
browserMonitoringError = true;
|
|
41547
|
+
currentUrl = "";
|
|
41548
|
+
} else {
|
|
41549
|
+
const script = `tell application "${browserName}" to get URL of active tab of front window`;
|
|
41550
|
+
const { stdout, stderr } = await execAsync(`osascript -e '${script}'`);
|
|
41551
|
+
currentUrl = stdout.trim();
|
|
41552
|
+
if (stderr && (stderr.includes("syntax error") || stderr.includes("Expected end of line"))) {
|
|
41553
|
+
console.error(`❌ AppleScript syntax error detected for ${this.detectedBrowser}`);
|
|
41554
|
+
browserMonitoringError = true;
|
|
41555
|
+
}
|
|
41556
|
+
}
|
|
41557
|
+
} catch (scriptError) {
|
|
41558
|
+
const errorMessage = scriptError.message || scriptError.stderr || "";
|
|
41559
|
+
if (errorMessage.includes("syntax error") || errorMessage.includes("Expected end of line") || errorMessage.includes("A property can't go after")) {
|
|
41560
|
+
console.error(`❌ Browser automation error for ${this.detectedBrowser}:`, errorMessage);
|
|
41561
|
+
browserMonitoringError = true;
|
|
41562
|
+
} else {
|
|
41563
|
+
currentUrl = "";
|
|
41564
|
+
}
|
|
41565
|
+
}
|
|
41515
41566
|
} else if (platform === "win32") {
|
|
41516
41567
|
const browserProcessName = this.detectedBrowser.replace(".exe", "");
|
|
41517
41568
|
const psScript = `
|
|
@@ -41525,7 +41576,58 @@ class AuthenticationHook {
|
|
|
41525
41576
|
const { stdout } = await execAsync(`powershell -Command "${psScript}"`);
|
|
41526
41577
|
currentUrl = stdout.trim();
|
|
41527
41578
|
}
|
|
41528
|
-
if (currentUrl
|
|
41579
|
+
if (currentUrl === "about:blank" || currentUrl === "about:blank#") {
|
|
41580
|
+
aboutBlankCount++;
|
|
41581
|
+
if (aboutBlankCount === 1) {
|
|
41582
|
+
console.error(`⚠️ Detected "about:blank" - attempting to refresh page to fix Chrome URL reporting...`);
|
|
41583
|
+
try {
|
|
41584
|
+
if (platform === "darwin") {
|
|
41585
|
+
await execAsync(`osascript -e 'tell application "${this.detectedBrowser}" to tell active tab of front window to reload'`);
|
|
41586
|
+
}
|
|
41587
|
+
} catch (refreshError) {
|
|
41588
|
+
console.error("⚠️ Could not refresh page:", refreshError);
|
|
41589
|
+
}
|
|
41590
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
41591
|
+
} else if (aboutBlankCount >= ABOUT_BLANK_THRESHOLD) {
|
|
41592
|
+
console.error(`❌ Detected ${aboutBlankCount} consecutive "about:blank" readings - Chrome may need to be restarted`);
|
|
41593
|
+
if (this.detectedBrowser !== "Firefox") {
|
|
41594
|
+
try {
|
|
41595
|
+
const errorUrl = `http://${CONFIG_SERVER_HOST}:${CONFIG_SERVER_PORT}/browser-error?type=aboutblank&browser=${encodeURIComponent(this.detectedBrowser)}`;
|
|
41596
|
+
if (platform === "darwin") {
|
|
41597
|
+
await execAsync(`osascript -e 'tell application "${this.detectedBrowser}" to set URL of active tab of front window to "${errorUrl}"'`);
|
|
41598
|
+
}
|
|
41599
|
+
} catch (redirectError) {
|
|
41600
|
+
console.error("⚠️ Could not redirect browser to error page:", redirectError);
|
|
41601
|
+
}
|
|
41602
|
+
} else {
|
|
41603
|
+
console.error("⚠️ Firefox detected - cannot redirect. Please manually navigate to the error page if needed.");
|
|
41604
|
+
}
|
|
41605
|
+
}
|
|
41606
|
+
} else {
|
|
41607
|
+
aboutBlankCount = 0;
|
|
41608
|
+
}
|
|
41609
|
+
if (browserMonitoringError) {
|
|
41610
|
+
if (this.detectedBrowser === "Firefox") {
|
|
41611
|
+
if (!firefoxWarningLogged) {
|
|
41612
|
+
firefoxWarningLogged = true;
|
|
41613
|
+
}
|
|
41614
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
41615
|
+
continue;
|
|
41616
|
+
} else {
|
|
41617
|
+
console.error(`❌ Browser monitoring error detected for ${this.detectedBrowser}`);
|
|
41618
|
+
try {
|
|
41619
|
+
const errorUrl = `http://${CONFIG_SERVER_HOST}:${CONFIG_SERVER_PORT}/browser-error?type=monitoring&browser=${encodeURIComponent(this.detectedBrowser)}`;
|
|
41620
|
+
if (platform === "darwin") {
|
|
41621
|
+
await execAsync(`osascript -e 'tell application "${this.detectedBrowser}" to set URL of active tab of front window to "${errorUrl}"'`);
|
|
41622
|
+
}
|
|
41623
|
+
} catch (redirectError) {
|
|
41624
|
+
console.error("⚠️ Could not redirect browser to error page:", redirectError);
|
|
41625
|
+
}
|
|
41626
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
41627
|
+
continue;
|
|
41628
|
+
}
|
|
41629
|
+
}
|
|
41630
|
+
if (currentUrl && currentUrl !== lastUrl && currentUrl !== "about:blank" && currentUrl !== "about:blank#") {
|
|
41529
41631
|
lastUrl = currentUrl;
|
|
41530
41632
|
console.error(`\uD83D\uDD0D Current URL: ${currentUrl}`);
|
|
41531
41633
|
}
|
|
@@ -41661,28 +41763,17 @@ class AuthenticationHook {
|
|
|
41661
41763
|
}
|
|
41662
41764
|
} else if (this.detectedBrowser === "Firefox") {
|
|
41663
41765
|
console.error(` Opening Firefox in private browsing mode...`);
|
|
41664
|
-
const firefoxScript = `
|
|
41665
|
-
tell application "Firefox"
|
|
41666
|
-
activate
|
|
41667
|
-
|
|
41668
|
-
-- Check if Firefox is running
|
|
41669
|
-
set isRunning to true
|
|
41670
|
-
|
|
41671
|
-
-- Open new private window using Firefox's built-in command
|
|
41672
|
-
try
|
|
41673
|
-
-- Use Firefox's internal private browsing command
|
|
41674
|
-
do shell script "open -a Firefox --args --private-window '${configUrl}'"
|
|
41675
|
-
on error
|
|
41676
|
-
-- Fallback: try to open with just the private flag
|
|
41677
|
-
do shell script "open -na Firefox --args -private-window '${configUrl}'"
|
|
41678
|
-
end try
|
|
41679
|
-
end tell
|
|
41680
|
-
`.replace(/\n\s+/g, " ");
|
|
41681
41766
|
try {
|
|
41682
|
-
await execAsync(`
|
|
41767
|
+
await execAsync(`open -a "Firefox" --args --private-window "${configUrl}"`);
|
|
41683
41768
|
} catch (error) {
|
|
41684
|
-
console.error(`
|
|
41685
|
-
|
|
41769
|
+
console.error(` First attempt failed, trying with new instance...`);
|
|
41770
|
+
try {
|
|
41771
|
+
await execAsync(`open -na "Firefox" --args --private-window "${configUrl}"`);
|
|
41772
|
+
} catch (fallbackError) {
|
|
41773
|
+
console.error(` ⚠️ Could not open Firefox in private mode automatically`);
|
|
41774
|
+
console.error(` ⚠️ Please manually open Firefox in Private Browsing mode`);
|
|
41775
|
+
await execAsync(`open -a "Firefox" "${configUrl}"`);
|
|
41776
|
+
}
|
|
41686
41777
|
}
|
|
41687
41778
|
} else {
|
|
41688
41779
|
const args = incognitoFlag ? `--args ${incognitoFlag} --app="${configUrl}" --window-size=${windowWidth},${windowHeight} --window-position=100,100` : `"${configUrl}"`;
|
|
@@ -41865,1135 +41956,7 @@ var __filename2, __dirname2, getProjectRoot = () => {
|
|
|
41865
41956
|
return configDir;
|
|
41866
41957
|
}, getConfigPath = () => {
|
|
41867
41958
|
return path.join(getConfigDir(), "config.json");
|
|
41868
|
-
}, execAsync, CONFIG_SERVER_PORT = 3333, CONFIG_SERVER_HOST = "localhost"
|
|
41869
|
-
<html lang="en">
|
|
41870
|
-
<head>
|
|
41871
|
-
<meta charset="UTF-8">
|
|
41872
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
41873
|
-
<title>eGain MCP - Sign In</title>
|
|
41874
|
-
<style>
|
|
41875
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
41876
|
-
body {
|
|
41877
|
-
font-family: "Open Sans", "Segoe UI", "SegoeUI", "Helvetica Neue", Helvetica, Arial, sans-serif !important;
|
|
41878
|
-
background: #fef1fd;
|
|
41879
|
-
min-height: 100vh;
|
|
41880
|
-
display: flex;
|
|
41881
|
-
justify-content: center;
|
|
41882
|
-
align-items: center;
|
|
41883
|
-
padding: 20px;
|
|
41884
|
-
}
|
|
41885
|
-
.container {
|
|
41886
|
-
background: white;
|
|
41887
|
-
border-radius: 16px;
|
|
41888
|
-
box-shadow: 0px 0px 30px 0px rgba(0, 0, 0, 0.12);
|
|
41889
|
-
max-width: 500px;
|
|
41890
|
-
width: 100%;
|
|
41891
|
-
padding: 32px;
|
|
41892
|
-
}
|
|
41893
|
-
h1 { color: #333; margin-bottom: 8px; font-size: 24px; }
|
|
41894
|
-
.subtitle { color: #666; margin-bottom: 20px; font-size: 13px; }
|
|
41895
|
-
.quick-signin {
|
|
41896
|
-
display: none;
|
|
41897
|
-
text-align: center;
|
|
41898
|
-
position: relative;
|
|
41899
|
-
}
|
|
41900
|
-
.quick-signin .icon { font-size: 64px; }
|
|
41901
|
-
.quick-signin h1 { text-align: center; }
|
|
41902
|
-
.saved-config {
|
|
41903
|
-
background: #f8f9fa;
|
|
41904
|
-
border-radius: 8px;
|
|
41905
|
-
padding: 20px;
|
|
41906
|
-
margin: 30px 0;
|
|
41907
|
-
text-align: left;
|
|
41908
|
-
}
|
|
41909
|
-
.saved-config-title {
|
|
41910
|
-
font-size: 12px;
|
|
41911
|
-
font-weight: 600;
|
|
41912
|
-
color: #666;
|
|
41913
|
-
text-transform: uppercase;
|
|
41914
|
-
margin-bottom: 15px;
|
|
41915
|
-
text-align: center;
|
|
41916
|
-
}
|
|
41917
|
-
.config-item {
|
|
41918
|
-
display: flex;
|
|
41919
|
-
justify-content: space-between;
|
|
41920
|
-
padding: 8px 0;
|
|
41921
|
-
border-bottom: 1px solid #e1e4e8;
|
|
41922
|
-
font-size: 13px;
|
|
41923
|
-
}
|
|
41924
|
-
.config-item:last-child { border-bottom: none; }
|
|
41925
|
-
.config-label { color: #666; font-weight: 500; }
|
|
41926
|
-
.config-value {
|
|
41927
|
-
color: #333;
|
|
41928
|
-
font-family: 'Courier New', monospace;
|
|
41929
|
-
max-width: 300px;
|
|
41930
|
-
overflow: hidden;
|
|
41931
|
-
text-overflow: ellipsis;
|
|
41932
|
-
white-space: nowrap;
|
|
41933
|
-
}
|
|
41934
|
-
.config-value.masked { color: #999; }
|
|
41935
|
-
.form-view { display: none; }
|
|
41936
|
-
.form-group { margin-bottom: 16px; }
|
|
41937
|
-
label {
|
|
41938
|
-
display: flex;
|
|
41939
|
-
align-items: center;
|
|
41940
|
-
gap: 6px;
|
|
41941
|
-
margin-bottom: 6px;
|
|
41942
|
-
color: #333;
|
|
41943
|
-
font-weight: 500;
|
|
41944
|
-
font-size: 14px;
|
|
41945
|
-
}
|
|
41946
|
-
input {
|
|
41947
|
-
width: 100%;
|
|
41948
|
-
padding: 10px 12px;
|
|
41949
|
-
border: 2px solid #e1e4e8;
|
|
41950
|
-
border-radius: 8px;
|
|
41951
|
-
font-size: 13px;
|
|
41952
|
-
font-family: "Helvetica Neue LT Pro", "Open Sans", 'Courier New', monospace !important;
|
|
41953
|
-
transition: border-color 0.2s;
|
|
41954
|
-
}
|
|
41955
|
-
input:focus {
|
|
41956
|
-
outline: none;
|
|
41957
|
-
border-color: #b91d8f;
|
|
41958
|
-
}
|
|
41959
|
-
.optional {
|
|
41960
|
-
color: #999;
|
|
41961
|
-
font-weight: normal;
|
|
41962
|
-
font-size: 12px;
|
|
41963
|
-
}
|
|
41964
|
-
.tooltip {
|
|
41965
|
-
position: relative;
|
|
41966
|
-
display: inline-flex;
|
|
41967
|
-
align-items: center;
|
|
41968
|
-
justify-content: center;
|
|
41969
|
-
width: 16px;
|
|
41970
|
-
height: 16px;
|
|
41971
|
-
background: #b91d8f;
|
|
41972
|
-
color: white;
|
|
41973
|
-
border-radius: 50%;
|
|
41974
|
-
font-size: 11px;
|
|
41975
|
-
font-weight: bold;
|
|
41976
|
-
cursor: pointer;
|
|
41977
|
-
flex-shrink: 0;
|
|
41978
|
-
user-select: none;
|
|
41979
|
-
}
|
|
41980
|
-
.tooltip-content {
|
|
41981
|
-
display: none !important;
|
|
41982
|
-
position: fixed;
|
|
41983
|
-
max-width: 380px;
|
|
41984
|
-
width: max-content;
|
|
41985
|
-
background: white;
|
|
41986
|
-
border-radius: 8px;
|
|
41987
|
-
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
|
|
41988
|
-
z-index: 10000;
|
|
41989
|
-
overflow: hidden;
|
|
41990
|
-
border: 2px solid #b91d8f;
|
|
41991
|
-
pointer-events: auto;
|
|
41992
|
-
}
|
|
41993
|
-
.tooltip-content.active {
|
|
41994
|
-
display: block !important;
|
|
41995
|
-
}
|
|
41996
|
-
.tooltip-arrow {
|
|
41997
|
-
position: absolute;
|
|
41998
|
-
width: 0;
|
|
41999
|
-
height: 0;
|
|
42000
|
-
border: 8px solid transparent;
|
|
42001
|
-
z-index: 1;
|
|
42002
|
-
}
|
|
42003
|
-
.tooltip-arrow.left {
|
|
42004
|
-
left: -16px;
|
|
42005
|
-
top: 50%;
|
|
42006
|
-
transform: translateY(-50%);
|
|
42007
|
-
border-right-color: #b91d8f;
|
|
42008
|
-
}
|
|
42009
|
-
.tooltip-arrow.right {
|
|
42010
|
-
right: -16px;
|
|
42011
|
-
top: 50%;
|
|
42012
|
-
transform: translateY(-50%);
|
|
42013
|
-
border-left-color: #b91d8f;
|
|
42014
|
-
}
|
|
42015
|
-
.tooltip-arrow.top {
|
|
42016
|
-
top: -16px;
|
|
42017
|
-
left: 50%;
|
|
42018
|
-
transform: translateX(-50%);
|
|
42019
|
-
border-bottom-color: #b91d8f;
|
|
42020
|
-
}
|
|
42021
|
-
.tooltip-arrow.bottom {
|
|
42022
|
-
bottom: -16px;
|
|
42023
|
-
left: 50%;
|
|
42024
|
-
transform: translateX(-50%);
|
|
42025
|
-
border-top-color: #b91d8f;
|
|
42026
|
-
}
|
|
42027
|
-
.tooltip-header {
|
|
42028
|
-
background: #b91d8f;
|
|
42029
|
-
color: white;
|
|
42030
|
-
padding: 8px 12px;
|
|
42031
|
-
font-weight: 600;
|
|
42032
|
-
font-size: 13px;
|
|
42033
|
-
}
|
|
42034
|
-
.tooltip-body {
|
|
42035
|
-
padding: 10px 12px;
|
|
42036
|
-
}
|
|
42037
|
-
.tooltip-image {
|
|
42038
|
-
width: 100%;
|
|
42039
|
-
max-height: 200px;
|
|
42040
|
-
object-fit: contain;
|
|
42041
|
-
border-radius: 4px;
|
|
42042
|
-
margin-bottom: 6px;
|
|
42043
|
-
border: 1px solid #e1e4e8;
|
|
42044
|
-
background: #f8f9fa;
|
|
42045
|
-
}
|
|
42046
|
-
.tooltip-text {
|
|
42047
|
-
color: #555;
|
|
42048
|
-
font-size: 12px;
|
|
42049
|
-
line-height: 1.4;
|
|
42050
|
-
font-style: italic;
|
|
42051
|
-
}
|
|
42052
|
-
.button-group {
|
|
42053
|
-
display: flex;
|
|
42054
|
-
gap: 10px;
|
|
42055
|
-
margin-top: 20px;
|
|
42056
|
-
}
|
|
42057
|
-
button {
|
|
42058
|
-
flex: 1;
|
|
42059
|
-
padding: 12px;
|
|
42060
|
-
border: 2px solid transparent;
|
|
42061
|
-
border-radius: 8px;
|
|
42062
|
-
font-size: 15px;
|
|
42063
|
-
font-weight: 600;
|
|
42064
|
-
cursor: pointer;
|
|
42065
|
-
transition: all 0.2s;
|
|
42066
|
-
}
|
|
42067
|
-
.btn-primary {
|
|
42068
|
-
background: linear-gradient(135deg, #b91d8f 0%, #7a1460 100%);
|
|
42069
|
-
color: white;
|
|
42070
|
-
}
|
|
42071
|
-
.btn-primary:hover {
|
|
42072
|
-
transform: translateY(-2px);
|
|
42073
|
-
box-shadow: 0 6px 20px rgba(185, 29, 143, 0.4);
|
|
42074
|
-
}
|
|
42075
|
-
.btn-secondary {
|
|
42076
|
-
background: #f6f8fa;
|
|
42077
|
-
color: #666;
|
|
42078
|
-
}
|
|
42079
|
-
.btn-secondary:hover {
|
|
42080
|
-
background: #e1e4e8;
|
|
42081
|
-
}
|
|
42082
|
-
.btn-danger {
|
|
42083
|
-
background: white;
|
|
42084
|
-
color: #b91d8f;
|
|
42085
|
-
border: 2px solid #b91d8f;
|
|
42086
|
-
}
|
|
42087
|
-
.btn-danger:hover {
|
|
42088
|
-
background: #fef1fd;
|
|
42089
|
-
transform: translateY(-1px);
|
|
42090
|
-
}
|
|
42091
|
-
.btn-link {
|
|
42092
|
-
background: transparent;
|
|
42093
|
-
color: #b91d8f;
|
|
42094
|
-
padding: 8px;
|
|
42095
|
-
font-size: 14px;
|
|
42096
|
-
}
|
|
42097
|
-
.btn-link:hover {
|
|
42098
|
-
background: #f6f8fa;
|
|
42099
|
-
}
|
|
42100
|
-
.status {
|
|
42101
|
-
margin-top: 20px;
|
|
42102
|
-
padding: 12px;
|
|
42103
|
-
border-radius: 8px;
|
|
42104
|
-
font-size: 14px;
|
|
42105
|
-
display: none;
|
|
42106
|
-
}
|
|
42107
|
-
.status.success {
|
|
42108
|
-
background: #d4edda;
|
|
42109
|
-
color: #155724;
|
|
42110
|
-
border: 1px solid #c3e6cb;
|
|
42111
|
-
}
|
|
42112
|
-
.status.error {
|
|
42113
|
-
background: #f8d7da;
|
|
42114
|
-
color: #721c24;
|
|
42115
|
-
border: 1px solid #f5c6cb;
|
|
42116
|
-
}
|
|
42117
|
-
.status.info {
|
|
42118
|
-
background: #d1ecf1;
|
|
42119
|
-
color: #0c5460;
|
|
42120
|
-
border: 1px solid #bee5eb;
|
|
42121
|
-
}
|
|
42122
|
-
/* Loading overlay and spinner */
|
|
42123
|
-
.loading-overlay {
|
|
42124
|
-
display: none;
|
|
42125
|
-
position: absolute;
|
|
42126
|
-
top: -32px;
|
|
42127
|
-
left: -32px;
|
|
42128
|
-
right: -32px;
|
|
42129
|
-
bottom: -32px;
|
|
42130
|
-
background: rgba(255, 255, 255, 0.85);
|
|
42131
|
-
backdrop-filter: blur(2px);
|
|
42132
|
-
border-radius: 16px;
|
|
42133
|
-
z-index: 1000;
|
|
42134
|
-
justify-content: center;
|
|
42135
|
-
align-items: center;
|
|
42136
|
-
flex-direction: column;
|
|
42137
|
-
gap: 16px;
|
|
42138
|
-
}
|
|
42139
|
-
.loading-overlay.active {
|
|
42140
|
-
display: flex;
|
|
42141
|
-
}
|
|
42142
|
-
.spinner {
|
|
42143
|
-
width: 48px;
|
|
42144
|
-
height: 48px;
|
|
42145
|
-
border: 4px solid #e1e4e8;
|
|
42146
|
-
border-top-color: #b91d8f;
|
|
42147
|
-
border-radius: 50%;
|
|
42148
|
-
animation: spin 0.8s linear infinite;
|
|
42149
|
-
}
|
|
42150
|
-
@keyframes spin {
|
|
42151
|
-
to { transform: rotate(360deg); }
|
|
42152
|
-
}
|
|
42153
|
-
.loading-message {
|
|
42154
|
-
color: #666;
|
|
42155
|
-
font-size: 14px;
|
|
42156
|
-
font-weight: 500;
|
|
42157
|
-
text-align: center;
|
|
42158
|
-
max-width: 300px;
|
|
42159
|
-
}
|
|
42160
|
-
.form-view {
|
|
42161
|
-
position: relative;
|
|
42162
|
-
}
|
|
42163
|
-
.modal-overlay {
|
|
42164
|
-
display: none;
|
|
42165
|
-
position: fixed;
|
|
42166
|
-
top: 0;
|
|
42167
|
-
left: 0;
|
|
42168
|
-
right: 0;
|
|
42169
|
-
bottom: 0;
|
|
42170
|
-
background: rgba(0, 0, 0, 0.5);
|
|
42171
|
-
z-index: 10001;
|
|
42172
|
-
justify-content: center;
|
|
42173
|
-
align-items: center;
|
|
42174
|
-
}
|
|
42175
|
-
.modal-overlay.active {
|
|
42176
|
-
display: flex;
|
|
42177
|
-
}
|
|
42178
|
-
.modal-content {
|
|
42179
|
-
background: white;
|
|
42180
|
-
border-radius: 12px;
|
|
42181
|
-
padding: 30px;
|
|
42182
|
-
max-width: 400px;
|
|
42183
|
-
width: 90%;
|
|
42184
|
-
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
|
|
42185
|
-
}
|
|
42186
|
-
.modal-title {
|
|
42187
|
-
font-size: 20px;
|
|
42188
|
-
font-weight: 600;
|
|
42189
|
-
color: #333;
|
|
42190
|
-
margin-bottom: 12px;
|
|
42191
|
-
}
|
|
42192
|
-
.modal-message {
|
|
42193
|
-
font-size: 14px;
|
|
42194
|
-
color: #666;
|
|
42195
|
-
margin-bottom: 24px;
|
|
42196
|
-
line-height: 1.5;
|
|
42197
|
-
}
|
|
42198
|
-
.modal-buttons {
|
|
42199
|
-
display: flex;
|
|
42200
|
-
gap: 10px;
|
|
42201
|
-
justify-content: flex-end;
|
|
42202
|
-
}
|
|
42203
|
-
.modal-buttons button {
|
|
42204
|
-
padding: 10px 20px;
|
|
42205
|
-
font-size: 14px;
|
|
42206
|
-
flex: none;
|
|
42207
|
-
}
|
|
42208
|
-
</style>
|
|
42209
|
-
</head>
|
|
42210
|
-
<body>
|
|
42211
|
-
<div class="container">
|
|
42212
|
-
<div id="quickSigninView" class="quick-signin">
|
|
42213
|
-
<div id="loadingOverlayQuickSignin" class="loading-overlay">
|
|
42214
|
-
<div class="spinner"></div>
|
|
42215
|
-
<div id="loadingMessageQuickSignin" class="loading-message">Redirecting to login...</div>
|
|
42216
|
-
</div>
|
|
42217
|
-
<div class="icon">\uD83D\uDD10</div>
|
|
42218
|
-
<h1>Welcome Back!</h1>
|
|
42219
|
-
<p class="subtitle">Ready to sign in with your saved configuration</p>
|
|
42220
|
-
<div class="saved-config">
|
|
42221
|
-
<div class="saved-config-title">Saved Configuration</div>
|
|
42222
|
-
<div id="savedConfigList"></div>
|
|
42223
|
-
</div>
|
|
42224
|
-
<div class="button-group">
|
|
42225
|
-
<button type="button" class="btn-danger" onclick="clearConfigAndShowForm()">Clear All</button>
|
|
42226
|
-
<button type="button" class="btn-primary" onclick="signInWithSavedConfig()">Sign In</button>
|
|
42227
|
-
</div>
|
|
42228
|
-
<button type="button" class="btn-link" onclick="showForm()" style="width: 100%; margin-top: 10px;">Edit Configuration</button>
|
|
42229
|
-
</div>
|
|
42230
|
-
<div id="formView" class="form-view">
|
|
42231
|
-
<div id="loadingOverlay" class="loading-overlay">
|
|
42232
|
-
<div class="spinner"></div>
|
|
42233
|
-
<div id="loadingMessage" class="loading-message">Saving configuration...</div>
|
|
42234
|
-
</div>
|
|
42235
|
-
<h1>\uD83D\uDD10 eGain MCP Configuration</h1>
|
|
42236
|
-
<p class="subtitle">Enter details from your eGain <strong>Admin Console</strong></p>
|
|
42237
|
-
<form id="configForm">
|
|
42238
|
-
<div class="form-group">
|
|
42239
|
-
<label for="egainUrl">
|
|
42240
|
-
<span>eGain Environment URL</span>
|
|
42241
|
-
<span class="tooltip" onmouseenter="showTooltip(event, 'egainUrl')" onmouseleave="hideTooltip(event, 'egainUrl')">?</span>
|
|
42242
|
-
</label>
|
|
42243
|
-
<input type="text" id="egainUrl" name="egainUrl" placeholder="https://your-environment.egain.cloud" required>
|
|
42244
|
-
</div>
|
|
42245
|
-
<div class="form-group">
|
|
42246
|
-
<label for="authUrl">
|
|
42247
|
-
<span>Authorization URL</span>
|
|
42248
|
-
<span class="tooltip" onmouseenter="showTooltip(event, 'authUrl')" onmouseleave="hideTooltip(event, 'authUrl')">?</span>
|
|
42249
|
-
</label>
|
|
42250
|
-
<input type="text" id="authUrl" name="authUrl" placeholder="https://login.egain.cloud/.../oauth2/authorize" required>
|
|
42251
|
-
</div>
|
|
42252
|
-
<div class="form-group">
|
|
42253
|
-
<label for="accessTokenUrl">
|
|
42254
|
-
<span>Access Token URL</span>
|
|
42255
|
-
<span class="tooltip" onmouseenter="showTooltip(event, 'accessTokenUrl')" onmouseleave="hideTooltip(event, 'accessTokenUrl')">?</span>
|
|
42256
|
-
</label>
|
|
42257
|
-
<input type="text" id="accessTokenUrl" name="accessTokenUrl" placeholder="https://login.egain.cloud/.../oauth2/token" required>
|
|
42258
|
-
</div>
|
|
42259
|
-
<div class="form-group">
|
|
42260
|
-
<label for="clientId">
|
|
42261
|
-
<span>Client ID</span>
|
|
42262
|
-
<span class="tooltip" onmouseenter="showTooltip(event, 'clientId')" onmouseleave="hideTooltip(event, 'clientId')">?</span>
|
|
42263
|
-
</label>
|
|
42264
|
-
<input type="text" id="clientId" name="clientId" placeholder="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" required>
|
|
42265
|
-
</div>
|
|
42266
|
-
<div class="form-group">
|
|
42267
|
-
<label for="redirectUrl">
|
|
42268
|
-
<span>Redirect URL</span>
|
|
42269
|
-
<span class="tooltip" onmouseenter="showTooltip(event, 'redirectUrl')" onmouseleave="hideTooltip(event, 'redirectUrl')">?</span>
|
|
42270
|
-
</label>
|
|
42271
|
-
<input type="text" id="redirectUrl" name="redirectUrl" placeholder="https://your-redirect-url.com/" required>
|
|
42272
|
-
</div>
|
|
42273
|
-
|
|
42274
|
-
<!-- Advanced Settings Toggle -->
|
|
42275
|
-
<div style="margin: 12px 0;">
|
|
42276
|
-
<button type="button" onclick="toggleAdvancedSettings()" style="padding: 6px 0; font-size: 13px; display: flex; align-items: center; gap: 6px; background: none; border: none; color: #b91d8f; cursor: pointer; font-family: inherit;">
|
|
42277
|
-
<span id="advancedToggleIcon">▶</span>
|
|
42278
|
-
<span>Advanced Settings</span>
|
|
42279
|
-
<span style="color: #999; font-size: 11px;">(optional)</span>
|
|
42280
|
-
</button>
|
|
42281
|
-
</div>
|
|
42282
|
-
|
|
42283
|
-
<!-- Advanced Settings Section (hidden by default) -->
|
|
42284
|
-
<div id="advancedSettings" style="display: none;">
|
|
42285
|
-
<div class="form-group">
|
|
42286
|
-
<label for="clientSecret">
|
|
42287
|
-
<span>Client Secret</span>
|
|
42288
|
-
<span class="tooltip" onmouseenter="showTooltip(event, 'clientSecret')" onmouseleave="hideTooltip(event, 'clientSecret')">?</span>
|
|
42289
|
-
<span class="optional">(optional)</span>
|
|
42290
|
-
</label>
|
|
42291
|
-
<input type="password" id="clientSecret" name="clientSecret" placeholder="Required for normal authentication flow/non-PKCE">
|
|
42292
|
-
</div>
|
|
42293
|
-
<div class="form-group">
|
|
42294
|
-
<label for="scopePrefix">
|
|
42295
|
-
<span>Scope Prefix</span>
|
|
42296
|
-
<span class="tooltip" onmouseenter="showTooltip(event, 'scopePrefix')" onmouseleave="hideTooltip(event, 'scopePrefix')">?</span>
|
|
42297
|
-
<span class="optional">(optional)</span>
|
|
42298
|
-
</label>
|
|
42299
|
-
<input type="text" id="scopePrefix" name="scopePrefix" placeholder="https://your.scope-prefix.cloud/auth/">
|
|
42300
|
-
</div>
|
|
42301
|
-
</div>
|
|
42302
|
-
<div style="font-size: 11px; color: #999; margin: 12px 0 0 0; line-height: 1.4;">
|
|
42303
|
-
\uD83D\uDD12 Your configuration will be securely saved to your <code style="background: #f0f0f0; padding: 2px 4px; border-radius: 3px; font-size: 10px;">~/.egain-mcp/config.json</code>.
|
|
42304
|
-
</div>
|
|
42305
|
-
<div class="button-group">
|
|
42306
|
-
<button type="button" class="btn-secondary" onclick="cancelForm()">Cancel</button>
|
|
42307
|
-
<button type="submit" class="btn-primary">Save & Authenticate</button>
|
|
42308
|
-
</div>
|
|
42309
|
-
</form>
|
|
42310
|
-
</div>
|
|
42311
|
-
<div id="status" class="status"></div>
|
|
42312
|
-
</div>
|
|
42313
|
-
|
|
42314
|
-
<!-- Confirmation Modal -->
|
|
42315
|
-
<div id="confirmModal" class="modal-overlay" onclick="if(event.target === this) closeModal(false)">
|
|
42316
|
-
<div class="modal-content">
|
|
42317
|
-
<div class="modal-title" id="modalTitle">Confirm Action</div>
|
|
42318
|
-
<div class="modal-message" id="modalMessage">Are you sure?</div>
|
|
42319
|
-
<div class="modal-buttons">
|
|
42320
|
-
<button type="button" class="btn-secondary" onclick="closeModal(false)">Cancel</button>
|
|
42321
|
-
<button type="button" class="btn-danger" id="modalConfirmBtn" onclick="closeModal(true)">Confirm</button>
|
|
42322
|
-
</div>
|
|
42323
|
-
</div>
|
|
42324
|
-
</div>
|
|
42325
|
-
|
|
42326
|
-
<!-- Tooltip Popups (outside container for proper fixed positioning) -->
|
|
42327
|
-
<div id="tooltip-egainUrl" class="tooltip-content">
|
|
42328
|
-
<div class="tooltip-header">eGain Environment URL</div>
|
|
42329
|
-
<div class="tooltip-body">
|
|
42330
|
-
<img src="/img/env-tooltip.png" class="tooltip-image" alt="eGain Environment URL" onerror="this.style.display='none'">
|
|
42331
|
-
<div class="tooltip-text">Enter the domain URL displayed in your browser when accessing the eGain application.</div>
|
|
42332
|
-
</div>
|
|
42333
|
-
</div>
|
|
42334
|
-
|
|
42335
|
-
<div id="tooltip-authUrl" class="tooltip-content">
|
|
42336
|
-
<div class="tooltip-header">Authorization URL</div>
|
|
42337
|
-
<div class="tooltip-body">
|
|
42338
|
-
<img src="/img/authurl-tooltip.png" class="tooltip-image" alt="Authorization URL" onerror="this.style.display='none'">
|
|
42339
|
-
<div class="tooltip-text">In the Partition space, go to Integration → Client Application → Metadata, and copy the Authorization URL.</div>
|
|
42340
|
-
</div>
|
|
42341
|
-
</div>
|
|
42342
|
-
|
|
42343
|
-
<div id="tooltip-accessTokenUrl" class="tooltip-content">
|
|
42344
|
-
<div class="tooltip-header">Access Token URL</div>
|
|
42345
|
-
<div class="tooltip-body">
|
|
42346
|
-
<img src="/img/accesstoken-tooltip.png" class="tooltip-image" alt="Access Token URL" onerror="this.style.display='none'">
|
|
42347
|
-
<div class="tooltip-text">In the Partition space, go to Integration → Client Application → Metadata, and copy the Access Token URL.</div>
|
|
42348
|
-
</div>
|
|
42349
|
-
</div>
|
|
42350
|
-
|
|
42351
|
-
<div id="tooltip-clientId" class="tooltip-content">
|
|
42352
|
-
<div class="tooltip-header">Client ID</div>
|
|
42353
|
-
<div class="tooltip-body">
|
|
42354
|
-
<img src="/img/clientid-tooltip.png" class="tooltip-image" alt="Client ID" onerror="this.style.display='none'">
|
|
42355
|
-
<div class="tooltip-text">In the Partition space, go to Integration → Client Application, select your client app, and copy the Client ID.</div>
|
|
42356
|
-
</div>
|
|
42357
|
-
</div>
|
|
42358
|
-
|
|
42359
|
-
<div id="tooltip-redirectUrl" class="tooltip-content">
|
|
42360
|
-
<div class="tooltip-header">Redirect URL</div>
|
|
42361
|
-
<div class="tooltip-body">
|
|
42362
|
-
<img src="/img/redirect-tooltip.png" class="tooltip-image" alt="Redirect URL" onerror="this.style.display='none'">
|
|
42363
|
-
<div class="tooltip-text">In the Partition space, go to Integration → Client Application, select your client app, and copy the Redirect URL.</div>
|
|
42364
|
-
</div>
|
|
42365
|
-
</div>
|
|
42366
|
-
|
|
42367
|
-
<div id="tooltip-clientSecret" class="tooltip-content">
|
|
42368
|
-
<div class="tooltip-header">Client Secret</div>
|
|
42369
|
-
<div class="tooltip-body">
|
|
42370
|
-
<img src="/img/clientsecret-tooltip.png" class="tooltip-image" alt="Client Secret" onerror="this.style.display='none'">
|
|
42371
|
-
<div class="tooltip-text">In the Partition space, go to Integration → Client Application, select your client app, and copy the Client Secret under Secrets.</div>
|
|
42372
|
-
</div>
|
|
42373
|
-
</div>
|
|
42374
|
-
|
|
42375
|
-
<div id="tooltip-scopePrefix" class="tooltip-content">
|
|
42376
|
-
<div class="tooltip-header">Scope Prefix</div>
|
|
42377
|
-
<div class="tooltip-body">
|
|
42378
|
-
<img src="/img/scopeprefix-tooltip.png" class="tooltip-image" alt="Scope Prefix" onerror="this.style.display='none'">
|
|
42379
|
-
<div class="tooltip-text">In the Partition space, go to Integration → Client Application → Metadata, and copy the API Permission Prefix.</div>
|
|
42380
|
-
</div>
|
|
42381
|
-
</div>
|
|
42382
|
-
|
|
42383
|
-
<script src="/config-page.js"></script>
|
|
42384
|
-
</body>
|
|
42385
|
-
</html>`, CONFIG_PAGE_JS = `const FIELDS = ['egainUrl', 'authUrl', 'accessTokenUrl', 'clientId', 'redirectUrl', 'clientSecret', 'scopePrefix'];
|
|
42386
|
-
const FIELD_LABELS = {
|
|
42387
|
-
egainUrl: 'eGain URL', authUrl: 'Auth URL', accessTokenUrl: 'Token URL',
|
|
42388
|
-
clientId: 'Client ID', redirectUrl: 'Redirect URL', clientSecret: 'Client Secret',
|
|
42389
|
-
scopePrefix: 'Scope Prefix'
|
|
42390
|
-
};
|
|
42391
|
-
|
|
42392
|
-
let savedConfigData = null; // Store config in memory only
|
|
42393
|
-
let authenticationStarted = false; // Track if user started authentication process
|
|
42394
|
-
let lastSubmittedConfig = null; // Track last submitted config to prevent duplicate submissions
|
|
42395
|
-
let isSubmitting = false; // Track if form submission is in progress
|
|
42396
|
-
|
|
42397
|
-
// Fetch saved config from backend (secure file storage)
|
|
42398
|
-
async function loadSavedConfig() {
|
|
42399
|
-
try {
|
|
42400
|
-
const response = await fetch('/get-config');
|
|
42401
|
-
if (response.ok) {
|
|
42402
|
-
const data = await response.json();
|
|
42403
|
-
if (data.config && data.config.egainUrl && data.config.clientId) {
|
|
42404
|
-
// Only set if we have valid required fields
|
|
42405
|
-
savedConfigData = data.config;
|
|
42406
|
-
return true;
|
|
42407
|
-
}
|
|
42408
|
-
}
|
|
42409
|
-
} catch (error) {
|
|
42410
|
-
console.error('Could not load saved config:', error);
|
|
42411
|
-
}
|
|
42412
|
-
savedConfigData = null;
|
|
42413
|
-
return false;
|
|
42414
|
-
}
|
|
42415
|
-
|
|
42416
|
-
function hasSavedConfig() {
|
|
42417
|
-
return savedConfigData &&
|
|
42418
|
-
savedConfigData.egainUrl &&
|
|
42419
|
-
savedConfigData.clientId &&
|
|
42420
|
-
savedConfigData.authUrl &&
|
|
42421
|
-
savedConfigData.accessTokenUrl;
|
|
42422
|
-
}
|
|
42423
|
-
|
|
42424
|
-
function displaySavedConfig() {
|
|
42425
|
-
const listEl = document.getElementById('savedConfigList');
|
|
42426
|
-
listEl.innerHTML = '';
|
|
42427
|
-
if (!savedConfigData) return;
|
|
42428
|
-
|
|
42429
|
-
FIELDS.forEach(field => {
|
|
42430
|
-
const value = savedConfigData[field];
|
|
42431
|
-
if (value) {
|
|
42432
|
-
const item = document.createElement('div');
|
|
42433
|
-
item.className = 'config-item';
|
|
42434
|
-
const label = document.createElement('span');
|
|
42435
|
-
label.className = 'config-label';
|
|
42436
|
-
label.textContent = FIELD_LABELS[field];
|
|
42437
|
-
const valueSpan = document.createElement('span');
|
|
42438
|
-
valueSpan.className = 'config-value';
|
|
42439
|
-
if (field === 'clientSecret') {
|
|
42440
|
-
valueSpan.classList.add('masked');
|
|
42441
|
-
valueSpan.textContent = '••••••••';
|
|
42442
|
-
} else if (field === 'clientId') {
|
|
42443
|
-
valueSpan.textContent = value.substring(0, 8) + '...';
|
|
42444
|
-
} else {
|
|
42445
|
-
valueSpan.textContent = value.length > 40 ? value.substring(0, 40) + '...' : value;
|
|
42446
|
-
}
|
|
42447
|
-
item.appendChild(label);
|
|
42448
|
-
item.appendChild(valueSpan);
|
|
42449
|
-
listEl.appendChild(item);
|
|
42450
|
-
}
|
|
42451
|
-
});
|
|
42452
|
-
}
|
|
42453
|
-
|
|
42454
|
-
function showQuickSignin() {
|
|
42455
|
-
document.getElementById('quickSigninView').style.display = 'block';
|
|
42456
|
-
document.getElementById('formView').style.display = 'none';
|
|
42457
|
-
displaySavedConfig();
|
|
42458
|
-
}
|
|
42459
|
-
|
|
42460
|
-
function showForm() {
|
|
42461
|
-
document.getElementById('quickSigninView').style.display = 'none';
|
|
42462
|
-
document.getElementById('formView').style.display = 'block';
|
|
42463
|
-
loadFormValues();
|
|
42464
|
-
}
|
|
42465
|
-
|
|
42466
|
-
function loadFormValues() {
|
|
42467
|
-
if (!savedConfigData) return;
|
|
42468
|
-
|
|
42469
|
-
// Load all field values
|
|
42470
|
-
FIELDS.forEach(field => {
|
|
42471
|
-
const value = savedConfigData[field];
|
|
42472
|
-
if (value) document.getElementById(field).value = value;
|
|
42473
|
-
});
|
|
42474
|
-
|
|
42475
|
-
// Show advanced settings if clientSecret or scopePrefix exist
|
|
42476
|
-
if (savedConfigData.clientSecret || savedConfigData.scopePrefix) {
|
|
42477
|
-
toggleAdvancedSettings();
|
|
42478
|
-
}
|
|
42479
|
-
}
|
|
42480
|
-
|
|
42481
|
-
async function clearConfigAndShowForm() {
|
|
42482
|
-
showModal(
|
|
42483
|
-
'Clear All Configuration?',
|
|
42484
|
-
'This will delete all saved OAuth settings from your home directory. You will need to re-enter them next time.',
|
|
42485
|
-
async (confirmed) => {
|
|
42486
|
-
if (confirmed) {
|
|
42487
|
-
try {
|
|
42488
|
-
const response = await fetch('/clear-config', { method: 'POST' });
|
|
42489
|
-
if (response.ok) {
|
|
42490
|
-
savedConfigData = null;
|
|
42491
|
-
FIELDS.forEach(field => {
|
|
42492
|
-
document.getElementById(field).value = '';
|
|
42493
|
-
});
|
|
42494
|
-
showStatus('Configuration cleared successfully', 'success');
|
|
42495
|
-
showForm();
|
|
42496
|
-
} else {
|
|
42497
|
-
showStatus('Failed to clear configuration', 'error');
|
|
42498
|
-
}
|
|
42499
|
-
} catch (error) {
|
|
42500
|
-
showStatus('Error clearing configuration: ' + error.message, 'error');
|
|
42501
|
-
}
|
|
42502
|
-
}
|
|
42503
|
-
},
|
|
42504
|
-
'Clear All'
|
|
42505
|
-
);
|
|
42506
|
-
}
|
|
42507
|
-
|
|
42508
|
-
function cancelForm() {
|
|
42509
|
-
if (hasSavedConfig()) {
|
|
42510
|
-
showQuickSignin();
|
|
42511
|
-
} else {
|
|
42512
|
-
showModal(
|
|
42513
|
-
'Cancel Authentication?',
|
|
42514
|
-
"You haven't saved any configuration yet. This will cancel the authentication process.",
|
|
42515
|
-
async (confirmed) => {
|
|
42516
|
-
if (confirmed) {
|
|
42517
|
-
// Notify server that user cancelled
|
|
42518
|
-
try {
|
|
42519
|
-
await fetch('/cancel', { method: 'POST' });
|
|
42520
|
-
} catch (error) {
|
|
42521
|
-
console.error('Could not notify server of cancellation:', error);
|
|
42522
|
-
}
|
|
42523
|
-
window.close();
|
|
42524
|
-
}
|
|
42525
|
-
},
|
|
42526
|
-
'Cancel'
|
|
42527
|
-
);
|
|
42528
|
-
}
|
|
42529
|
-
}
|
|
42530
|
-
|
|
42531
|
-
async function signInWithSavedConfig() {
|
|
42532
|
-
authenticationStarted = true; // Mark that auth has started
|
|
42533
|
-
|
|
42534
|
-
// Show loading overlay
|
|
42535
|
-
showLoadingOverlay('Redirecting to login...');
|
|
42536
|
-
|
|
42537
|
-
try {
|
|
42538
|
-
const response = await fetch('/get-oauth-url', { method: 'POST' });
|
|
42539
|
-
const result = await response.json();
|
|
42540
|
-
|
|
42541
|
-
if (response.ok && result.oauthUrl) {
|
|
42542
|
-
console.log('\uD83D\uDD17 OAuth URL:', result.oauthUrl);
|
|
42543
|
-
// Redirect after a brief delay to show loading state
|
|
42544
|
-
setTimeout(() => {
|
|
42545
|
-
window.location.href = result.oauthUrl;
|
|
42546
|
-
}, 500);
|
|
42547
|
-
} else {
|
|
42548
|
-
hideLoadingOverlay();
|
|
42549
|
-
showStatus('❌ ' + (result.error || 'Failed to get OAuth URL'), 'error');
|
|
42550
|
-
authenticationStarted = false; // Reset on error
|
|
42551
|
-
}
|
|
42552
|
-
} catch (error) {
|
|
42553
|
-
hideLoadingOverlay();
|
|
42554
|
-
showStatus('❌ Error: ' + error.message, 'error');
|
|
42555
|
-
authenticationStarted = false; // Reset on error
|
|
42556
|
-
}
|
|
42557
|
-
}
|
|
42558
|
-
|
|
42559
|
-
function showStatus(message, type) {
|
|
42560
|
-
const statusEl = document.getElementById('status');
|
|
42561
|
-
statusEl.textContent = message;
|
|
42562
|
-
statusEl.className = 'status ' + type;
|
|
42563
|
-
statusEl.style.display = 'block';
|
|
42564
|
-
// Auto-hide info and success messages after a delay
|
|
42565
|
-
if (type === 'info') {
|
|
42566
|
-
setTimeout(() => {
|
|
42567
|
-
// Only hide if it's still an info message (not changed to success/error)
|
|
42568
|
-
if (statusEl.className === 'status info') {
|
|
42569
|
-
statusEl.style.display = 'none';
|
|
42570
|
-
}
|
|
42571
|
-
}, 3000);
|
|
42572
|
-
} else if (type === 'success') {
|
|
42573
|
-
setTimeout(() => {
|
|
42574
|
-
// Only hide if it's still a success message (not changed to error)
|
|
42575
|
-
if (statusEl.className === 'status success') {
|
|
42576
|
-
statusEl.style.display = 'none';
|
|
42577
|
-
}
|
|
42578
|
-
}, 4000);
|
|
42579
|
-
}
|
|
42580
|
-
}
|
|
42581
|
-
|
|
42582
|
-
function configValuesEqual(config1, config2) {
|
|
42583
|
-
// Compare all fields that matter
|
|
42584
|
-
const fieldsToCompare = ['egainUrl', 'authUrl', 'accessTokenUrl', 'clientId', 'redirectUrl', 'clientSecret', 'scopePrefix'];
|
|
42585
|
-
for (const field of fieldsToCompare) {
|
|
42586
|
-
const val1 = (config1[field] || '').trim();
|
|
42587
|
-
const val2 = (config2[field] || '').trim();
|
|
42588
|
-
if (val1 !== val2) {
|
|
42589
|
-
return false;
|
|
42590
|
-
}
|
|
42591
|
-
}
|
|
42592
|
-
return true;
|
|
42593
|
-
}
|
|
42594
|
-
|
|
42595
|
-
function showLoadingOverlay(message) {
|
|
42596
|
-
// Show overlay for form view
|
|
42597
|
-
const overlay = document.getElementById('loadingOverlay');
|
|
42598
|
-
const loadingMessage = document.getElementById('loadingMessage');
|
|
42599
|
-
if (overlay) {
|
|
42600
|
-
overlay.classList.add('active');
|
|
42601
|
-
if (loadingMessage) {
|
|
42602
|
-
loadingMessage.textContent = message || 'Saving configuration...';
|
|
42603
|
-
}
|
|
42604
|
-
}
|
|
42605
|
-
|
|
42606
|
-
// Show overlay for quick signin view
|
|
42607
|
-
const overlayQuickSignin = document.getElementById('loadingOverlayQuickSignin');
|
|
42608
|
-
const loadingMessageQuickSignin = document.getElementById('loadingMessageQuickSignin');
|
|
42609
|
-
if (overlayQuickSignin) {
|
|
42610
|
-
overlayQuickSignin.classList.add('active');
|
|
42611
|
-
if (loadingMessageQuickSignin) {
|
|
42612
|
-
loadingMessageQuickSignin.textContent = message || 'Redirecting to login...';
|
|
42613
|
-
}
|
|
42614
|
-
}
|
|
42615
|
-
}
|
|
42616
|
-
|
|
42617
|
-
function hideLoadingOverlay() {
|
|
42618
|
-
// Hide overlay for form view
|
|
42619
|
-
const overlay = document.getElementById('loadingOverlay');
|
|
42620
|
-
if (overlay) {
|
|
42621
|
-
overlay.classList.remove('active');
|
|
42622
|
-
}
|
|
42623
|
-
|
|
42624
|
-
// Hide overlay for quick signin view
|
|
42625
|
-
const overlayQuickSignin = document.getElementById('loadingOverlayQuickSignin');
|
|
42626
|
-
if (overlayQuickSignin) {
|
|
42627
|
-
overlayQuickSignin.classList.remove('active');
|
|
42628
|
-
}
|
|
42629
|
-
}
|
|
42630
|
-
|
|
42631
|
-
async function authenticateWithConfig(config) {
|
|
42632
|
-
// Prevent duplicate submissions
|
|
42633
|
-
if (isSubmitting) {
|
|
42634
|
-
return; // Already submitting, ignore
|
|
42635
|
-
}
|
|
42636
|
-
|
|
42637
|
-
// Check if values have changed since last submission
|
|
42638
|
-
if (lastSubmittedConfig && configValuesEqual(config, lastSubmittedConfig)) {
|
|
42639
|
-
showStatus('⚠️ Configuration unchanged. Already saved.', 'info');
|
|
42640
|
-
return; // Values haven't changed, don't submit again
|
|
42641
|
-
}
|
|
42642
|
-
|
|
42643
|
-
try {
|
|
42644
|
-
isSubmitting = true; // Mark as submitting
|
|
42645
|
-
const submitButton = document.querySelector('button[type="submit"]');
|
|
42646
|
-
if (submitButton) {
|
|
42647
|
-
submitButton.disabled = true;
|
|
42648
|
-
submitButton.textContent = 'Saving...';
|
|
42649
|
-
}
|
|
42650
|
-
|
|
42651
|
-
// Show loading overlay with spinner
|
|
42652
|
-
showLoadingOverlay('Saving configuration...');
|
|
42653
|
-
authenticationStarted = true; // Mark that auth has started
|
|
42654
|
-
|
|
42655
|
-
const response = await fetch('/authenticate', {
|
|
42656
|
-
method: 'POST',
|
|
42657
|
-
headers: { 'Content-Type': 'application/json' },
|
|
42658
|
-
body: JSON.stringify(config)
|
|
42659
|
-
});
|
|
42660
|
-
const result = await response.json();
|
|
42661
|
-
|
|
42662
|
-
if (response.ok && result.oauthUrl) {
|
|
42663
|
-
// Config saved! Store this config as last submitted
|
|
42664
|
-
lastSubmittedConfig = { ...config };
|
|
42665
|
-
|
|
42666
|
-
console.log('\uD83D\uDD17 OAuth URL:', result.oauthUrl);
|
|
42667
|
-
|
|
42668
|
-
// Update loading message (overlay already shows the status, no need for status message)
|
|
42669
|
-
showLoadingOverlay('Configuration saved! Redirecting to login...');
|
|
42670
|
-
|
|
42671
|
-
setTimeout(() => {
|
|
42672
|
-
window.location.href = result.oauthUrl;
|
|
42673
|
-
}, 500);
|
|
42674
|
-
} else if (response.ok && result.success) {
|
|
42675
|
-
lastSubmittedConfig = { ...config };
|
|
42676
|
-
hideLoadingOverlay();
|
|
42677
|
-
showStatus('✅ ' + result.message, 'success');
|
|
42678
|
-
setTimeout(() => { window.close(); }, 2000);
|
|
42679
|
-
} else {
|
|
42680
|
-
hideLoadingOverlay();
|
|
42681
|
-
showStatus('❌ ' + (result.error || 'Authentication failed'), 'error');
|
|
42682
|
-
authenticationStarted = false; // Reset on error
|
|
42683
|
-
isSubmitting = false; // Reset submitting flag
|
|
42684
|
-
if (submitButton) {
|
|
42685
|
-
submitButton.disabled = false;
|
|
42686
|
-
submitButton.textContent = 'Save & Authenticate';
|
|
42687
|
-
}
|
|
42688
|
-
}
|
|
42689
|
-
} catch (error) {
|
|
42690
|
-
hideLoadingOverlay();
|
|
42691
|
-
showStatus('❌ Error: ' + error.message, 'error');
|
|
42692
|
-
authenticationStarted = false; // Reset on error
|
|
42693
|
-
isSubmitting = false; // Reset submitting flag
|
|
42694
|
-
const submitButton = document.querySelector('button[type="submit"]');
|
|
42695
|
-
if (submitButton) {
|
|
42696
|
-
submitButton.disabled = false;
|
|
42697
|
-
submitButton.textContent = 'Save & Authenticate';
|
|
42698
|
-
}
|
|
42699
|
-
}
|
|
42700
|
-
}
|
|
42701
|
-
|
|
42702
|
-
document.getElementById('configForm').addEventListener('submit', async (e) => {
|
|
42703
|
-
e.preventDefault();
|
|
42704
|
-
|
|
42705
|
-
// Prevent duplicate submissions
|
|
42706
|
-
if (isSubmitting) {
|
|
42707
|
-
return;
|
|
42708
|
-
}
|
|
42709
|
-
|
|
42710
|
-
const formData = new FormData(e.target);
|
|
42711
|
-
const config = {};
|
|
42712
|
-
for (let [key, value] of formData.entries()) {
|
|
42713
|
-
config[key] = value;
|
|
42714
|
-
}
|
|
42715
|
-
|
|
42716
|
-
// Config is now sent to backend for secure file storage (not cookies)
|
|
42717
|
-
await authenticateWithConfig(config);
|
|
42718
|
-
});
|
|
42719
|
-
|
|
42720
|
-
// Initialize: Load saved config from backend
|
|
42721
|
-
(async () => {
|
|
42722
|
-
const hasConfig = await loadSavedConfig();
|
|
42723
|
-
if (hasConfig) {
|
|
42724
|
-
showQuickSignin();
|
|
42725
|
-
} else {
|
|
42726
|
-
showForm();
|
|
42727
|
-
}
|
|
42728
|
-
})();
|
|
42729
|
-
|
|
42730
|
-
// Custom modal functions
|
|
42731
|
-
let modalCallback = null;
|
|
42732
|
-
|
|
42733
|
-
function showModal(title, message, callback, confirmText = 'Confirm') {
|
|
42734
|
-
document.getElementById('modalTitle').textContent = title;
|
|
42735
|
-
document.getElementById('modalMessage').textContent = message;
|
|
42736
|
-
document.getElementById('modalConfirmBtn').textContent = confirmText;
|
|
42737
|
-
modalCallback = callback;
|
|
42738
|
-
document.getElementById('confirmModal').classList.add('active');
|
|
42739
|
-
}
|
|
42740
|
-
|
|
42741
|
-
function closeModal(confirmed) {
|
|
42742
|
-
document.getElementById('confirmModal').classList.remove('active');
|
|
42743
|
-
if (modalCallback) {
|
|
42744
|
-
modalCallback(confirmed);
|
|
42745
|
-
modalCallback = null;
|
|
42746
|
-
}
|
|
42747
|
-
}
|
|
42748
|
-
|
|
42749
|
-
// Advanced settings toggle
|
|
42750
|
-
function toggleAdvancedSettings() {
|
|
42751
|
-
const advancedSection = document.getElementById('advancedSettings');
|
|
42752
|
-
const toggleIcon = document.getElementById('advancedToggleIcon');
|
|
42753
|
-
|
|
42754
|
-
if (advancedSection.style.display === 'none') {
|
|
42755
|
-
advancedSection.style.display = 'block';
|
|
42756
|
-
toggleIcon.textContent = '▼';
|
|
42757
|
-
} else {
|
|
42758
|
-
advancedSection.style.display = 'none';
|
|
42759
|
-
toggleIcon.textContent = '▶';
|
|
42760
|
-
}
|
|
42761
|
-
}
|
|
42762
|
-
|
|
42763
|
-
// Tooltip functions
|
|
42764
|
-
function showTooltip(event, fieldName) {
|
|
42765
|
-
event.preventDefault(); // Prevent label from focusing input
|
|
42766
|
-
event.stopPropagation(); // Prevent event from bubbling
|
|
42767
|
-
|
|
42768
|
-
const tooltipId = 'tooltip-' + fieldName;
|
|
42769
|
-
let tooltipElement = document.getElementById(tooltipId);
|
|
42770
|
-
const button = event.currentTarget;
|
|
42771
|
-
|
|
42772
|
-
if (tooltipElement) {
|
|
42773
|
-
// Show the tooltip first to get its dimensions
|
|
42774
|
-
tooltipElement.classList.add('active');
|
|
42775
|
-
|
|
42776
|
-
// Get actual dimensions after showing
|
|
42777
|
-
const buttonRect = button.getBoundingClientRect();
|
|
42778
|
-
const tooltipRect = tooltipElement.getBoundingClientRect();
|
|
42779
|
-
const tooltipWidth = tooltipRect.width || 380;
|
|
42780
|
-
const tooltipHeight = tooltipRect.height || 300;
|
|
42781
|
-
|
|
42782
|
-
const spacing = 16; // Space between button and tooltip
|
|
42783
|
-
const viewportPadding = 10; // Padding from viewport edges
|
|
42784
|
-
const horizontalComfortZone = 50; // Extra space needed to avoid cramped horizontal positioning
|
|
42785
|
-
|
|
42786
|
-
// Calculate available space on all sides
|
|
42787
|
-
const spaceOnRight = window.innerWidth - buttonRect.right;
|
|
42788
|
-
const spaceOnLeft = buttonRect.left;
|
|
42789
|
-
const spaceBelow = window.innerHeight - buttonRect.bottom;
|
|
42790
|
-
const spaceAbove = buttonRect.top;
|
|
42791
|
-
|
|
42792
|
-
let left, top;
|
|
42793
|
-
let arrowSide = 'left'; // Default: tooltip on right, arrow on left
|
|
42794
|
-
|
|
42795
|
-
// Check if horizontal positioning would be too cramped (tooltip might cover the icon)
|
|
42796
|
-
const horizontalSpaceTight = (spaceOnRight < tooltipWidth + horizontalComfortZone) &&
|
|
42797
|
-
(spaceOnLeft < tooltipWidth + horizontalComfortZone);
|
|
42798
|
-
|
|
42799
|
-
if (horizontalSpaceTight) {
|
|
42800
|
-
// Use vertical positioning to avoid covering the icon
|
|
42801
|
-
// Determine if we're in the top or bottom half of the viewport
|
|
42802
|
-
const inTopHalf = buttonRect.top < window.innerHeight / 2;
|
|
42803
|
-
|
|
42804
|
-
if (inTopHalf && spaceBelow >= tooltipHeight + spacing + viewportPadding) {
|
|
42805
|
-
// Position below
|
|
42806
|
-
left = buttonRect.left + (buttonRect.width / 2) - (tooltipWidth / 2);
|
|
42807
|
-
top = buttonRect.bottom + spacing;
|
|
42808
|
-
arrowSide = 'top';
|
|
42809
|
-
} else if (!inTopHalf && spaceAbove >= tooltipHeight + spacing + viewportPadding) {
|
|
42810
|
-
// Position above
|
|
42811
|
-
left = buttonRect.left + (buttonRect.width / 2) - (tooltipWidth / 2);
|
|
42812
|
-
top = buttonRect.top - tooltipHeight - spacing;
|
|
42813
|
-
arrowSide = 'bottom';
|
|
42814
|
-
} else if (spaceBelow > spaceAbove) {
|
|
42815
|
-
// Not enough vertical space either, prefer below
|
|
42816
|
-
left = buttonRect.left + (buttonRect.width / 2) - (tooltipWidth / 2);
|
|
42817
|
-
top = buttonRect.bottom + spacing;
|
|
42818
|
-
arrowSide = 'top';
|
|
42819
|
-
} else {
|
|
42820
|
-
// Prefer above
|
|
42821
|
-
left = buttonRect.left + (buttonRect.width / 2) - (tooltipWidth / 2);
|
|
42822
|
-
top = buttonRect.top - tooltipHeight - spacing;
|
|
42823
|
-
arrowSide = 'bottom';
|
|
42824
|
-
}
|
|
42825
|
-
|
|
42826
|
-
// Keep horizontally centered within viewport
|
|
42827
|
-
if (left < viewportPadding) {
|
|
42828
|
-
left = viewportPadding;
|
|
42829
|
-
}
|
|
42830
|
-
if (left + tooltipWidth > window.innerWidth - viewportPadding) {
|
|
42831
|
-
left = window.innerWidth - tooltipWidth - viewportPadding;
|
|
42832
|
-
}
|
|
42833
|
-
|
|
42834
|
-
} else {
|
|
42835
|
-
// Use horizontal positioning (original logic)
|
|
42836
|
-
// Prefer right side if there's enough space
|
|
42837
|
-
if (spaceOnRight >= tooltipWidth + spacing + viewportPadding) {
|
|
42838
|
-
// Position to the right
|
|
42839
|
-
left = buttonRect.right + spacing;
|
|
42840
|
-
arrowSide = 'left';
|
|
42841
|
-
} else if (spaceOnLeft >= tooltipWidth + spacing + viewportPadding) {
|
|
42842
|
-
// Position to the left
|
|
42843
|
-
left = buttonRect.left - tooltipWidth - spacing;
|
|
42844
|
-
arrowSide = 'right';
|
|
42845
|
-
} else {
|
|
42846
|
-
// Not enough space on either side, use the side with more space
|
|
42847
|
-
if (spaceOnRight > spaceOnLeft) {
|
|
42848
|
-
left = buttonRect.right + spacing;
|
|
42849
|
-
arrowSide = 'left';
|
|
42850
|
-
// Allow tooltip to go to edge of screen
|
|
42851
|
-
if (left + tooltipWidth > window.innerWidth - viewportPadding) {
|
|
42852
|
-
left = window.innerWidth - tooltipWidth - viewportPadding;
|
|
42853
|
-
}
|
|
42854
|
-
} else {
|
|
42855
|
-
left = buttonRect.left - tooltipWidth - spacing;
|
|
42856
|
-
arrowSide = 'right';
|
|
42857
|
-
// Allow tooltip to go to edge of screen
|
|
42858
|
-
if (left < viewportPadding) {
|
|
42859
|
-
left = viewportPadding;
|
|
42860
|
-
}
|
|
42861
|
-
}
|
|
42862
|
-
}
|
|
42863
|
-
|
|
42864
|
-
// Center vertically relative to button
|
|
42865
|
-
top = buttonRect.top + (buttonRect.height / 2) - (tooltipHeight / 2);
|
|
42866
|
-
|
|
42867
|
-
// Keep tooltip within viewport vertically
|
|
42868
|
-
if (top < viewportPadding) {
|
|
42869
|
-
top = viewportPadding;
|
|
42870
|
-
}
|
|
42871
|
-
if (top + tooltipHeight > window.innerHeight - viewportPadding) {
|
|
42872
|
-
top = window.innerHeight - tooltipHeight - viewportPadding;
|
|
42873
|
-
}
|
|
42874
|
-
}
|
|
42875
|
-
|
|
42876
|
-
// Apply positioning
|
|
42877
|
-
tooltipElement.style.left = left + 'px';
|
|
42878
|
-
tooltipElement.style.top = top + 'px';
|
|
42879
|
-
|
|
42880
|
-
// Update arrow direction
|
|
42881
|
-
const arrow = tooltipElement.querySelector('.tooltip-arrow');
|
|
42882
|
-
if (arrow) {
|
|
42883
|
-
arrow.className = 'tooltip-arrow ' + arrowSide;
|
|
42884
|
-
}
|
|
42885
|
-
}
|
|
42886
|
-
}
|
|
42887
|
-
|
|
42888
|
-
function hideTooltip(event, fieldName) {
|
|
42889
|
-
const tooltipId = 'tooltip-' + fieldName;
|
|
42890
|
-
let tooltipElement = document.getElementById(tooltipId);
|
|
42891
|
-
|
|
42892
|
-
if (tooltipElement) {
|
|
42893
|
-
tooltipElement.classList.remove('active');
|
|
42894
|
-
}
|
|
42895
|
-
}
|
|
42896
|
-
|
|
42897
|
-
// Close tooltip on ESC key
|
|
42898
|
-
document.addEventListener('keydown', function(e) {
|
|
42899
|
-
if (e.key === 'Escape') {
|
|
42900
|
-
document.querySelectorAll('.tooltip-content').forEach(tip => {
|
|
42901
|
-
tip.classList.remove('active');
|
|
42902
|
-
});
|
|
42903
|
-
}
|
|
42904
|
-
});
|
|
42905
|
-
|
|
42906
|
-
// Notify server if window is closed without starting authentication
|
|
42907
|
-
window.addEventListener('beforeunload', function(e) {
|
|
42908
|
-
// Only send cancel if user never started the authentication process
|
|
42909
|
-
// (If they started auth, they either completed it or clicked cancel explicitly)
|
|
42910
|
-
if (!authenticationStarted) {
|
|
42911
|
-
// Use sendBeacon for reliable delivery even as page unloads
|
|
42912
|
-
navigator.sendBeacon('/cancel', '');
|
|
42913
|
-
}
|
|
42914
|
-
});`, SAFARI_WARNING_HTML = `<!DOCTYPE html>
|
|
42915
|
-
<html lang="en">
|
|
42916
|
-
<head>
|
|
42917
|
-
<meta charset="UTF-8">
|
|
42918
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
42919
|
-
<title>Safari Not Supported - eGain MCP</title>
|
|
42920
|
-
<style>
|
|
42921
|
-
* {
|
|
42922
|
-
margin: 0;
|
|
42923
|
-
padding: 0;
|
|
42924
|
-
box-sizing: border-box;
|
|
42925
|
-
}
|
|
42926
|
-
|
|
42927
|
-
body {
|
|
42928
|
-
font-family: "Open Sans", "Segoe UI", "SegoeUI", "Helvetica Neue", Helvetica, Arial, sans-serif !important;
|
|
42929
|
-
background: #fef1fd;
|
|
42930
|
-
min-height: 100vh;
|
|
42931
|
-
display: flex;
|
|
42932
|
-
justify-content: center;
|
|
42933
|
-
align-items: center;
|
|
42934
|
-
padding: 20px;
|
|
42935
|
-
}
|
|
42936
|
-
|
|
42937
|
-
.container {
|
|
42938
|
-
background: white;
|
|
42939
|
-
border-radius: 16px;
|
|
42940
|
-
box-shadow: 0px 0px 30px 0px rgba(0, 0, 0, 0.12);
|
|
42941
|
-
max-width: 500px;
|
|
42942
|
-
width: 100%;
|
|
42943
|
-
padding: 32px;
|
|
42944
|
-
text-align: center;
|
|
42945
|
-
}
|
|
42946
|
-
|
|
42947
|
-
.warning-icon {
|
|
42948
|
-
font-size: 64px;
|
|
42949
|
-
margin-bottom: 20px;
|
|
42950
|
-
}
|
|
42951
|
-
|
|
42952
|
-
h1 {
|
|
42953
|
-
color: #e74c3c;
|
|
42954
|
-
font-size: 28px;
|
|
42955
|
-
margin-bottom: 30px;
|
|
42956
|
-
font-weight: 600;
|
|
42957
|
-
}
|
|
42958
|
-
|
|
42959
|
-
.reason {
|
|
42960
|
-
background: #fff0f6;
|
|
42961
|
-
border-left: 4px solid #d946a6;
|
|
42962
|
-
padding: 20px;
|
|
42963
|
-
text-align: left;
|
|
42964
|
-
border-radius: 4px;
|
|
42965
|
-
}
|
|
42966
|
-
|
|
42967
|
-
.reason strong {
|
|
42968
|
-
color: #a21361;
|
|
42969
|
-
display: block;
|
|
42970
|
-
margin-bottom: 12px;
|
|
42971
|
-
font-size: 16px;
|
|
42972
|
-
}
|
|
42973
|
-
|
|
42974
|
-
.reason p {
|
|
42975
|
-
color: #a21361;
|
|
42976
|
-
font-size: 14px;
|
|
42977
|
-
line-height: 1.6;
|
|
42978
|
-
}
|
|
42979
|
-
</style>
|
|
42980
|
-
</head>
|
|
42981
|
-
<body>
|
|
42982
|
-
<div class="container">
|
|
42983
|
-
<div class="warning-icon">⚠️</div>
|
|
42984
|
-
<h1>Safari Not Supported</h1>
|
|
42985
|
-
|
|
42986
|
-
<div class="reason">
|
|
42987
|
-
<strong>Why?</strong>
|
|
42988
|
-
<p>
|
|
42989
|
-
Safari doesn't support private browsing mode via command line, which is required
|
|
42990
|
-
to protect your OAuth credentials from being cached or leaked. We prioritize your
|
|
42991
|
-
security over convenience.
|
|
42992
|
-
</p>
|
|
42993
|
-
</div>
|
|
42994
|
-
</div>
|
|
42995
|
-
</body>
|
|
42996
|
-
</html>`;
|
|
41959
|
+
}, execAsync, CONFIG_SERVER_PORT = 3333, CONFIG_SERVER_HOST = "localhost";
|
|
42997
41960
|
var init_auth_hook = __esm(() => {
|
|
42998
41961
|
__filename2 = fileURLToPath(import.meta.url);
|
|
42999
41962
|
__dirname2 = path.dirname(__filename2);
|
|
@@ -47847,7 +46810,7 @@ The Search API is a hybrid search service that combines semantic understanding w
|
|
|
47847
46810
|
function createMCPServer(deps) {
|
|
47848
46811
|
const server = new McpServer({
|
|
47849
46812
|
name: "EgainMcp",
|
|
47850
|
-
version: "1.0.
|
|
46813
|
+
version: "1.0.13"
|
|
47851
46814
|
});
|
|
47852
46815
|
const getClient = deps.getSDK || (() => new EgainMcpCore({
|
|
47853
46816
|
security: deps.security,
|
|
@@ -49094,7 +48057,7 @@ var routes = ln({
|
|
|
49094
48057
|
var app = _e(routes, {
|
|
49095
48058
|
name: "mcp",
|
|
49096
48059
|
versionInfo: {
|
|
49097
|
-
currentVersion: "1.0.
|
|
48060
|
+
currentVersion: "1.0.13"
|
|
49098
48061
|
}
|
|
49099
48062
|
});
|
|
49100
48063
|
Yt(app, process3.argv.slice(2), buildContext(process3));
|
|
@@ -49102,5 +48065,5 @@ export {
|
|
|
49102
48065
|
app
|
|
49103
48066
|
};
|
|
49104
48067
|
|
|
49105
|
-
//# debugId=
|
|
48068
|
+
//# debugId=B092F14BDBBDEC7964756E2164756E21
|
|
49106
48069
|
//# sourceMappingURL=mcp-server.js.map
|