trypear / pearai-app

An Open Sourced AI-Powered Text Editor. A fork of VSCode and Continue.
https://trypear.ai
Other
528 stars 86 forks source link

Backend functionalilty after Sign in for users on app #121

Closed nang-dev closed 1 week ago

nang-dev commented 4 weeks ago

Users need to sign in and use their info in the requests to the server

the code for this should live in pearai-submodule

my convo with chatgpt:

I am building a vscode extenison, how can i have a login on the extension, and then pass the username in each request in the extension code

In a TypeScript file within your VSCode extension, context usually refers to the vscode.ExtensionContext object that is passed to the activate function of your extension. To access context in other parts of your extension, you can either pass it as an argument to the functions that need it or store it in a module-level variable when your extension activates.

Here’s how you can manage it:

Step 1: Store context in a Module-Level Variable

Create a module to store the context. This allows other parts of your extension to access it easily.

// context.ts
import * as vscode from 'vscode';

let extensionContext: vscode.ExtensionContext;

export function setContext(context: vscode.ExtensionContext) {
    extensionContext = context;
}

export function getContext(): vscode.ExtensionContext {
    return extensionContext;
}

Step 2: Set context When Activating the Extension

Update your activate function to set the context using the setContext function.

// extension.ts
import * as vscode from 'vscode';
import { setContext } from './context';

export function activate(context: vscode.ExtensionContext) {
    setContext(context);

    context.subscriptions.push(
        vscode.commands.registerCommand('extension.login', () => {
            const panel = vscode.window.createWebviewPanel(
                'login',
                'Login',
                vscode.ViewColumn.One,
                {}
            );

            panel.webview.html = getWebviewContent();

            panel.webview.onDidReceiveMessage(
                message => {
                    switch (message.command) {
                        case 'login':
                            handleLogin(message.username, message.password, context);
                            return;
                    }
                },
                undefined,
                context.subscriptions
            );
        })
    );

    context.subscriptions.push(
        vscode.commands.registerCommand('extension.makeRequest', () => {
            makeRequest();
        })
    );
}

function getWebviewContent() {
    return `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
    <form id="login-form">
        <label for="username">Username:</label>
        <input type="text" id="username" name="username">
        <label for="password">Password:</label>
        <input type="password" id="password" name="password">
        <button type="submit">Login</button>
    </form>
    <script>
        const vscode = acquireVsCodeApi();
        document.getElementById('login-form').addEventListener('submit', (event) => {
            event.preventDefault();
            const username = document.getElementById('username').value;
            const password = document.getElementById('password').value;
            vscode.postMessage({
                command: 'login',
                username: username,
                password: password
            });
        });
    </script>
</body>
</html>`;
}

async function handleLogin(username: string, password: string, context: vscode.ExtensionContext) {
    // Perform authentication (this example assumes an API call)
    const response = await fetch('https://your-auth-api.com/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ username, password })
    });

    if (response.ok) {
        // Store the username in the global state
        context.globalState.update('username', username);
        vscode.window.showInformationMessage('Login successful');
    } else {
        vscode.window.showErrorMessage('Login failed');
    }
}

Step 3: Access context in Your Request Function

Now, you can access the context in your request function using the getContext function.

// request.ts
import * as vscode from 'vscode';
import { getContext } from './context';

export async function makeRequest() {
    const context = getContext();
    const username = context.globalState.get('username');

    if (!username) {
        vscode.window.showErrorMessage('User is not logged in');
        return;
    }

    const response = await fetch('https://your-api.com/data', {
        method: 'GET',
        headers: {
            'Content-Type': 'application/json',
            'Username': username as string
        }
    });

    if (response.ok) {
        const data = await response.json();
        // Handle the data
    } else {
        vscode.window.showErrorMessage('Request failed');
    }
}

This approach ensures that you have access to the context in any part of your extension, and it keeps your code modular and organized.

ItWasEnder commented 1 week ago

So this is going in the correct direction however I would say we have an authentication page we display in the system native browser on a temporary webserver, this way we can handle the callback logic and also leverage the users browser password manager for login or single-sign-on though apps like Google or Github.

We can either use a temporary webserver or we can create our own callback page and host it with vercel.

Using a webview from electron sucks from a UX perspective because if the user is using any 2FA on their sso account it will cause a lot of friction trying to authenticate or reauthenticate now/future

nang-dev commented 1 week ago

yes