UNPKG

zenstack

Version:

FullStack enhancement for Prisma ORM: seamless integration from database to UI

281 lines 12.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ZenStackAuthenticationProvider = exports.API_URL = exports.AUTH_URL = exports.AUTH_PROVIDER_ID = void 0; const vscode = __importStar(require("vscode")); exports.AUTH_PROVIDER_ID = 'ZenStack'; exports.AUTH_URL = 'https://accounts.zenstack.dev'; exports.API_URL = 'https://api.zenstack.dev'; class ZenStackAuthenticationProvider { constructor(context) { this._onDidChangeSessions = new vscode.EventEmitter(); this.onDidChangeSessions = this._onDidChangeSessions.event; this._sessions = []; this._context = context; this._disposable = vscode.Disposable.from(vscode.authentication.registerAuthenticationProvider(exports.AUTH_PROVIDER_ID, 'ZenStack', this), vscode.window.registerUriHandler({ handleUri: (uri) => __awaiter(this, void 0, void 0, function* () { if (uri.path === '/auth-callback') { yield this.handleAuthCallback(uri); } }), }), // Register logout command vscode.commands.registerCommand('zenstack.logout', () => __awaiter(this, void 0, void 0, function* () { yield this.logoutAllSessions(); }))); } getSessions(_scopes) { return __awaiter(this, void 0, void 0, function* () { // Check if we have stored sessions in VS Code's secret storage const storedSessions = yield this.getStoredSessions(); this._sessions = storedSessions; return this._sessions; }); } createSession(scopes) { return __awaiter(this, void 0, void 0, function* () { // Create a login flow const session = yield this.performLogin(scopes); if (session) { this._sessions.push(session); yield this.storeSession(session); this._onDidChangeSessions.fire({ added: [session], removed: [], changed: [], }); } return session; }); } removeSession(sessionId) { return __awaiter(this, void 0, void 0, function* () { const sessionIndex = this._sessions.findIndex((s) => s.id === sessionId); if (sessionIndex > -1) { const session = this._sessions[sessionIndex]; this._sessions.splice(sessionIndex, 1); yield this.removeStoredSession(sessionId); this._onDidChangeSessions.fire({ added: [], removed: [session], changed: [], }); } }); } /** * Log out all sessions */ logoutAllSessions() { return __awaiter(this, void 0, void 0, function* () { if (this._sessions.length === 0) { return; } (yield this.getSessions()).forEach((s) => __awaiter(this, void 0, void 0, function* () { return yield this.removeSession(s.id); })); vscode.window.showInformationMessage('Successfully logged out of ZenStack.'); }); } performLogin(scopes) { return __awaiter(this, void 0, void 0, function* () { // Create the authentication promise return vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: 'Signing in to ZenStack', cancellable: true, }, (progress, token) => __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { // Handle cancellation token.onCancellationRequested(() => { if (this.pendingAuth) { delete this.pendingAuth; } reject(new Error('User Cancelled')); }); const isCursor = vscode.env.appName == 'Cursor'; let signInUrl = vscode.Uri.parse(new URL('/sign-in', exports.AUTH_URL).toString()); if (isCursor) { signInUrl = signInUrl.with({ query: `redirect_url=${exports.API_URL}/oauth/oauth_callback?vscodeapp=cursor`, }); } console.log('ZenStack sign-in URL:', signInUrl.toString()); // Store the state and resolve function for later use this.pendingAuth = { resolve, reject, scopes }; // Open the ZenStack sign-in page in the user's default browser vscode.env.openExternal(signInUrl).then(() => { console.log('Opened ZenStack sign-in page in browser'); progress.report({ message: 'Waiting for return from browser...' }); }, (error) => { if (this.pendingAuth) { delete this.pendingAuth; } reject(new Error(`Failed to open sign-in page: ${error}`)); }); // 2 minutes timeout setTimeout(() => { if (this.pendingAuth) { delete this.pendingAuth; } reject(new Error('Timeout')); }, 120000); }); })); }); } generateState() { return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); } // Handle authentication callback from ZenStack handleAuthCallback(callbackUri) { return __awaiter(this, void 0, void 0, function* () { const query = new URLSearchParams(callbackUri.query); const accessToken = query.get('access_token'); if (!this.pendingAuth) { console.warn('No pending authentication found'); return; } if (!accessToken) { this.pendingAuth.reject(new Error('No access token received')); delete this.pendingAuth; return; } try { // Create session from the access token const session = yield this.createSessionFromAccessToken(accessToken); this.pendingAuth.resolve(session); delete this.pendingAuth; } catch (error) { if (this.pendingAuth) { this.pendingAuth.reject(error instanceof Error ? error : new Error(String(error))); delete this.pendingAuth; } } }); } createSessionFromAccessToken(accessToken) { return __awaiter(this, void 0, void 0, function* () { try { // Decode JWT to get claims const claims = this.parseJWTClaims(accessToken); return { id: claims.jti || Math.random().toString(36), accessToken: accessToken, account: { id: claims.sub || 'unknown', label: claims.email || 'unknown@zenstack.dev', }, scopes: [], }; } catch (error) { throw new Error(`Failed to create session from access token: ${error}`); } }); } parseJWTClaims(token) { try { // JWT tokens have 3 parts separated by dots: header.payload.signature const parts = token.split('.'); if (parts.length !== 3) { throw new Error('Invalid JWT format'); } // Decode the payload (second part) const payload = parts[1]; // Add padding if needed for base64 decoding const paddedPayload = payload + '='.repeat((4 - (payload.length % 4)) % 4); const decoded = atob(paddedPayload); return JSON.parse(decoded); } catch (error) { throw new Error(`Failed to parse JWT claims: ${error}`); } } getStoredSessions() { return __awaiter(this, void 0, void 0, function* () { try { const stored = yield this._context.secrets.get('zenstack-auth-sessions'); return stored ? JSON.parse(stored) : []; } catch (error) { console.error('Error retrieving stored sessions:', error); return []; } }); } storeSession(session) { return __awaiter(this, void 0, void 0, function* () { try { const sessions = yield this.getStoredSessions(); sessions.push(session); yield this._context.secrets.store('zenstack-auth-sessions', JSON.stringify(sessions)); } catch (error) { console.error('Error storing session:', error); } }); } removeStoredSession(sessionId) { return __awaiter(this, void 0, void 0, function* () { try { const sessions = yield this.getStoredSessions(); const filteredSessions = sessions.filter((s) => s.id !== sessionId); yield this._context.secrets.store('zenstack-auth-sessions', JSON.stringify(filteredSessions)); } catch (error) { console.error('Error removing stored session:', error); } }); } /** * Dispose the registered services */ dispose() { return __awaiter(this, void 0, void 0, function* () { this._disposable.dispose(); }); } } exports.ZenStackAuthenticationProvider = ZenStackAuthenticationProvider; //# sourceMappingURL=zenstack-auth-provider.js.map