@civic/hub-bridge
Version:
Stdio <-> HTTP/SSE MCP bridge with Civic auth handling
205 lines • 9.9 kB
JavaScript
/**
* CLIAuthProviderSingleton.ts
*
* Singleton implementation for CLIAuthProvider to ensure a single shared instance
* across the entire application for consistent authentication state.
*/
import { CLIAuthProvider } from "@civic/auth-mcp/client";
import { ConfigManager } from "../lib/ConfigManager.js";
import { CALLBACK_PORT, CLIENT_ID } from "../config/index.js";
/**
* Singleton class for CLIAuthProvider
*/
export class CLIAuthProviderSingleton {
static instance = null;
/**
* Get the singleton instance of CLIAuthProvider
* Creates it if it doesn't exist
*/
static getInstance() {
if (!CLIAuthProviderSingleton.instance) {
const configManager = ConfigManager.getInstance();
CLIAuthProviderSingleton.instance = new CLIAuthProvider({
clientId: CLIENT_ID,
tokenPersistence: configManager,
callbackPort: CALLBACK_PORT,
scope: "openid email profile offline_access",
successHtml: CLIAuthProviderSingleton.getSuccessHtml(),
errorHtml: CLIAuthProviderSingleton.getErrorHtml(),
});
}
return CLIAuthProviderSingleton.instance;
}
/**
* Get the custom success HTML from the legacy bridge
*/
static getSuccessHtml() {
return `<html lang="en">
<head>
<title>Civic Hub Bridge</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
background-color: #13151f;
color: white;
text-align: center;
padding: 0;
margin: 0;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
}
.container {
position: relative;
z-index: 10;
padding: 2rem;
}
.logo {
margin-bottom: 2rem;
text-align: center;
}
.logo svg {
width: 180px;
height: auto;
}
h1 {
font-size: 1.5rem;
font-weight: normal;
margin-bottom: 1rem;
}
p {
margin: 0.5rem 0;
font-size: 1.2rem;
}
.dots-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: radial-gradient(circle, rgba(128, 90, 213, 0.1) 2px, transparent 2px);
background-size: 25px 25px;
opacity: 0.5;
z-index: 1;
}
</style>
<script>setTimeout(() => window.close(), 5000);</script>
</head>
<body>
<div class="dots-bg"></div>
<div class="container">
<div class="logo">
<svg width="246" height="48" viewBox="0 0 246 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M76.6941 20.535C76.6941 17.8747 74.5376 15.7183 71.8771 15.7183C69.2168 15.7183 67.0601 17.8747 67.0601 20.535C67.0601 22.3965 68.1178 24.0083 69.6635 24.8102L67.8783 32.5297H75.8759L74.0908 24.8102C75.6364 24.0083 76.6941 22.3965 76.6941 20.535Z" fill="white"/>
<path d="M90.7181 30.1948C89.7825 37.4582 83.563 43.0902 76.0486 43.0902H67.7056C59.5472 43.0902 52.9099 36.4532 52.9099 28.2952V19.9528C52.9099 11.7948 59.5472 5.15785 67.7056 5.15785H76.0486C83.563 5.15785 89.7824 10.7899 90.7181 18.0534H95.6608C94.7019 8.07614 86.2734 0.248047 76.0486 0.248047H67.7056C56.8399 0.248047 48 9.08764 48 19.9528V28.2952C48 39.1605 56.8399 48 67.7056 48H76.0486C86.2734 48 94.7019 40.1717 95.6608 30.1948H90.7181Z" fill="white"/>
<path d="M137.674 13.792H132.757V36.7303H137.674V13.792Z" fill="white"/>
<path d="M152.582 31.3592L146.326 13.792H141.046L149.514 36.7303H155.471L163.939 13.792H158.748L152.582 31.3592Z" fill="white"/>
<path d="M172.228 13.792H167.312V36.7303H172.228V13.792Z" fill="white"/>
<path d="M192.801 28.791C192.131 31.3034 190.148 32.7958 187.435 32.7958C183.622 32.7958 181.06 29.7858 181.06 25.3058C181.06 20.7725 183.622 17.7267 187.435 17.7267C190.224 17.7267 192.132 19.1478 192.843 21.7314H197.998C196.946 16.5144 193.147 13.5244 187.524 13.5244C184.121 13.5244 181.23 14.644 179.164 16.7622C177.101 18.8769 176.01 21.8312 176.01 25.3058C176.01 28.8171 177.078 31.7675 179.097 33.8382C181.113 35.9054 183.981 36.9981 187.391 36.9981C193.056 36.9981 196.998 33.9331 198 28.7911H192.801V28.791Z" fill="white"/>
<path d="M123.55 28.791C122.881 31.3034 120.897 32.7958 118.185 32.7958C114.372 32.7958 111.81 29.7858 111.81 25.3058C111.81 20.7725 114.372 17.7267 118.185 17.7267C120.974 17.7267 122.881 19.1478 123.592 21.7314H128.748C127.695 16.5144 123.897 13.5244 118.274 13.5244C114.871 13.5244 111.98 14.644 109.913 16.7622C107.85 18.8769 106.76 21.8312 106.76 25.3058C106.76 28.8171 107.827 31.7675 109.097 33.8382C111.862 35.9054 114.73 36.9981 118.14 36.9981C123.806 36.9981 127.748 33.9331 128.749 28.7911H123.55V28.791Z" fill="white"/>
</svg>
</div>
<h1>Connected.</h1>
<p>You can close this window.</p>
</div>
</body>
</html>`;
}
/**
* Get the custom error HTML from the legacy bridge
*/
static getErrorHtml() {
return `<html lang="en">
<head>
<title>Civic Hub Bridge</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
background-color: #13151f;
color: white;
text-align: center;
padding: 0;
margin: 0;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
}
.container {
position: relative;
z-index: 10;
padding: 2rem;
}
.logo {
margin-bottom: 2rem;
text-align: center;
}
.logo svg {
width: 180px;
height: auto;
}
h1 {
font-size: 1.5rem;
font-weight: normal;
margin-bottom: 1rem;
color: #ff6b6b;
}
p {
margin: 0.5rem 0;
font-size: 1.2rem;
}
.dots-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: radial-gradient(circle, rgba(128, 90, 213, 0.1) 2px, transparent 2px);
background-size: 25px 25px;
opacity: 0.5;
z-index: 1;
}
</style>
<script>setTimeout(() => window.close(), 5000);</script>
</head>
<body>
<div class="dots-bg"></div>
<div class="container">
<div class="logo">
<svg width="246" height="48" viewBox="0 0 246 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M76.6941 20.535C76.6941 17.8747 74.5376 15.7183 71.8771 15.7183C69.2168 15.7183 67.0601 17.8747 67.0601 20.535C67.0601 22.3965 68.1178 24.0083 69.6635 24.8102L67.8783 32.5297H75.8759L74.0908 24.8102C75.6364 24.0083 76.6941 22.3965 76.6941 20.535Z" fill="white"/>
<path d="M90.7181 30.1948C89.7825 37.4582 83.563 43.0902 76.0486 43.0902H67.7056C59.5472 43.0902 52.9099 36.4532 52.9099 28.2952V19.9528C52.9099 11.7948 59.5472 5.15785 67.7056 5.15785H76.0486C83.563 5.15785 89.7824 10.7899 90.7181 18.0534H95.6608C94.7019 8.07614 86.2734 0.248047 76.0486 0.248047H67.7056C56.8399 0.248047 48 9.08764 48 19.9528V28.2952C48 39.1605 56.8399 48 67.7056 48H76.0486C86.2734 48 94.7019 40.1717 95.6608 30.1948H90.7181Z" fill="white"/>
<path d="M137.674 13.792H132.757V36.7303H137.674V13.792Z" fill="white"/>
<path d="M152.582 31.3592L146.326 13.792H141.046L149.514 36.7303H155.471L163.939 13.792H158.748L152.582 31.3592Z" fill="white"/>
<path d="M172.228 13.792H167.312V36.7303H172.228V13.792Z" fill="white"/>
<path d="M192.801 28.791C192.131 31.3034 190.148 32.7958 187.435 32.7958C183.622 32.7958 181.06 29.7858 181.06 25.3058C181.06 20.7725 183.622 17.7267 187.435 17.7267C190.224 17.7267 192.132 19.1478 192.843 21.7314H197.998C196.946 16.5144 193.147 13.5244 187.524 13.5244C184.121 13.5244 181.23 14.644 179.164 16.7622C177.101 18.8769 176.01 21.8312 176.01 25.3058C176.01 28.8171 177.078 31.7675 179.097 33.8382C181.113 35.9054 183.981 36.9981 187.391 36.9981C193.056 36.9981 196.998 33.9331 198 28.7911H192.801V28.791Z" fill="white"/>
<path d="M123.55 28.791C122.881 31.3034 120.897 32.7958 118.185 32.7958C114.372 32.7958 111.81 29.7858 111.81 25.3058C111.81 20.7725 114.372 17.7267 118.185 17.7267C120.974 17.7267 122.881 19.1478 123.592 21.7314H128.748C127.695 16.5144 123.897 13.5244 118.274 13.5244C114.871 13.5244 111.98 14.644 109.913 16.7622C107.85 18.8769 106.76 21.8312 106.76 25.3058C106.76 28.8171 107.827 31.7675 109.097 33.8382C111.862 35.9054 114.73 36.9981 118.14 36.9981C123.806 36.9981 127.748 33.9331 128.749 28.7911H123.55V28.791Z" fill="white"/>
</svg>
</div>
<h1>Connection Failed.</h1>
<p>Please try again or close this window.</p>
</div>
</body>
</html>`;
}
/**
* Reset the singleton instance (useful for testing)
*/
static reset() {
CLIAuthProviderSingleton.instance = null;
}
/**
* Private constructor to prevent direct instantiation
*/
constructor() { }
}
//# sourceMappingURL=cli-auth-provider-singleton.js.map