Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[db] wait for token to propagate #10431

Merged
merged 1 commit into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/breezy-dancers-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@astrojs/db": patch
---

Add wait time for the db token to propagate
25 changes: 11 additions & 14 deletions packages/db/src/core/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { homedir } from 'node:os';
import { join } from 'node:path';
import { pathToFileURL } from 'node:url';
import { MISSING_PROJECT_ID_ERROR, MISSING_SESSION_ID_ERROR } from './errors.js';
import { getAstroStudioEnv, getAstroStudioUrl, getRemoteDatabaseUrl, safeFetch } from './utils.js';
import { getAstroStudioEnv, getAstroStudioUrl, safeFetch } from './utils.js';
import ora from 'ora';
import { green } from 'kleur/colors';

export const SESSION_LOGIN_FILE = pathToFileURL(join(homedir(), '.astro', 'session-token'));
export const PROJECT_ID_FILE = pathToFileURL(join(process.cwd(), '.astro', 'link'));
Expand All @@ -26,38 +28,35 @@ class ManagedLocalAppToken implements ManagedAppToken {
class ManagedRemoteAppToken implements ManagedAppToken {
token: string;
session: string;
region: string | undefined;
projectId: string;
ttl: number;
renewTimer: NodeJS.Timeout | undefined;

static async getRegionCode(): Promise<string | undefined> {
const pingResponse = await safeFetch(new URL(`${getRemoteDatabaseUrl()}/ping`));
const pingResult = (await pingResponse.json()) as { success: true; data: { region: string } };
return pingResult.data.region;
}

static async create(sessionToken: string, projectId: string) {
const region = await ManagedRemoteAppToken.getRegionCode();
const spinner = ora('Connecting to remote database...').start();
const response = await safeFetch(
new URL(`${getAstroStudioUrl()}/auth/cli/token-create`),
{
method: 'POST',
headers: new Headers({
Authorization: `Bearer ${sessionToken}`,
}),
body: JSON.stringify({ projectId, region }),
body: JSON.stringify({ projectId }),
},
(res) => {
throw new Error(`Failed to create token: ${res.status} ${res.statusText}`);
}
);
// Wait for 2 seconds! This is the maximum time we would reasonably expect a token
// to be created and propagate to all the necessary DB services. Without this, you
// risk a token being created, used immediately, and failing to authenticate.
await new Promise((resolve) => setTimeout(resolve, 2000));
spinner.succeed(green('Connected to remote database.'));

const { token: shortLivedAppToken, ttl } = await response.json();
return new ManagedRemoteAppToken({
token: shortLivedAppToken,
session: sessionToken,
region,
projectId,
ttl,
});
Expand All @@ -66,13 +65,11 @@ class ManagedRemoteAppToken implements ManagedAppToken {
constructor(options: {
token: string;
session: string;
region: string | undefined;
projectId: string;
ttl: number;
}) {
this.token = options.token;
this.session = options.session;
this.region = options.region;
this.projectId = options.projectId;
this.ttl = options.ttl;
this.renewTimer = setTimeout(() => this.renew(), (1000 * 60 * 5) / 2);
Expand All @@ -87,7 +84,7 @@ class ManagedRemoteAppToken implements ManagedAppToken {
Authorization: `Bearer ${this.session}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ ...body, region: this.region }),
body: JSON.stringify(body),
},
() => {
throw new Error(`Failed to fetch ${url}.`);
Expand Down
Loading