Skip to content

Commit

Permalink
db: add login flow for web containers (#10816)
Browse files Browse the repository at this point in the history
* feat: add login flow for web containers

* chore: changeset

* chore: remove unused web()

* feat: detect github codespaces

* fix: add success msg for manual flow

* refactor: use URL constructor for login URL

Co-authored-by:  Matthew Phillips <matthew@skypack.dev>

* fix: add .href for url string

---------

Co-authored-by: Matthew Phillips <matthew@skypack.dev>
  • Loading branch information
bholmesdev and matthewp authored Apr 22, 2024
1 parent 8d5f3e8 commit 8e6eb62
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 25 deletions.
5 changes: 5 additions & 0 deletions .changeset/spotty-dots-beg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@astrojs/db": patch
---

Add `astro login` support from online editors like Stackblitz and GitHub Codespaces
73 changes: 48 additions & 25 deletions packages/db/src/core/cli/commands/login/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,59 @@ import { listen } from 'async-listen';
import { cyan } from 'kleur/colors';
import open from 'open';
import ora from 'ora';
import prompt from 'prompts';
import type { Arguments } from 'yargs-parser';
import { SESSION_LOGIN_FILE } from '../../../tokens.js';
import type { DBConfig } from '../../../types.js';
import { getAstroStudioUrl } from '../../../utils.js';

const isWebContainer =
// Stackblitz heuristic
process.versions?.webcontainer ??
// Github Codespaces heuristic
process.env.CODESPACE_NAME;

export async function cmd({
flags,
}: {
astroConfig: AstroConfig;
dbConfig: DBConfig;
flags: Arguments;
}) {
let session = flags.session;

if (!session && isWebContainer) {
console.log(`Please visit the following URL in your web browser:`);
console.log(cyan(`${getAstroStudioUrl()}/auth/cli/login`));
console.log(`After login in complete, enter the verification code displayed:`);
const response = await prompt({
type: 'text',
name: 'session',
message: 'Verification code:',
});
if (!response.session) {
console.error('Cancelling login.');
process.exit(0);
}
session = response.session;
console.log('Successfully logged in');
} else if (!session) {
const { url, promise } = await createServer();
const loginUrl = new URL('/auth/cli/login', getAstroStudioUrl());
loginUrl.searchParams.set('returnTo', url);
console.log(`Opening the following URL in your browser...`);
console.log(cyan(loginUrl.href));
console.log(`If something goes wrong, copy-and-paste the URL into your browser.`);
open(loginUrl.href);
const spinner = ora('Waiting for confirmation...');
session = await promise;
spinner.succeed('Successfully logged in');
}

await mkdir(new URL('.', SESSION_LOGIN_FILE), { recursive: true });
await writeFile(SESSION_LOGIN_FILE, `${session}`);
}

// NOTE(fks): How the Astro CLI login process works:
// 1. The Astro CLI creates a temporary server to listen for the session token
// 2. The user is directed to studio.astro.build/ to login
Expand Down Expand Up @@ -47,28 +95,3 @@ async function createServer(): Promise<{ url: string; promise: Promise<string> }

return { url: serverUrl, promise: sessionPromise };
}

export async function cmd({
flags,
}: {
astroConfig: AstroConfig;
dbConfig: DBConfig;
flags: Arguments;
}) {
let session = flags.session;

if (!session) {
const { url, promise } = await createServer();
const loginUrl = getAstroStudioUrl() + '/auth/cli/login?returnTo=' + encodeURIComponent(url);
console.log(`Opening the following URL in your browser...`);
console.log(cyan(loginUrl));
console.log(`If something goes wrong, copy-and-paste the URL into your browser.`);
open(loginUrl);
const spinner = ora('Waiting for confirmation...');
session = await promise;
spinner.succeed('Successfully logged in!');
}

await mkdir(new URL('.', SESSION_LOGIN_FILE), { recursive: true });
await writeFile(SESSION_LOGIN_FILE, `${session}`);
}

0 comments on commit 8e6eb62

Please sign in to comment.