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

Fix mixed DB token env vars #11894

Merged
merged 5 commits into from
Sep 3, 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/empty-spoons-kiss.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/db': patch
---

Fixes mixed environment variable for app token when using DB commands with libSQL remote.
4 changes: 2 additions & 2 deletions packages/db/src/core/cli/commands/execute/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { existsSync } from 'node:fs';
import { getManagedAppTokenOrExit } from '@astrojs/studio';
import { LibsqlError } from '@libsql/client';
import type { AstroConfig } from 'astro';
import { green } from 'kleur/colors';
Expand All @@ -16,6 +15,7 @@ import {
} from '../../../integration/vite-plugin-db.js';
import { bundleFile, importBundledFile } from '../../../load-file.js';
import type { DBConfig } from '../../../types.js';
import { getManagedRemoteToken } from '../../../utils.js';

export async function cmd({
astroConfig,
Expand All @@ -40,7 +40,7 @@ export async function cmd({

let virtualModContents: string;
if (flags.remote) {
const appToken = await getManagedAppTokenOrExit(flags.token);
const appToken = await getManagedRemoteToken(flags.token);
virtualModContents = getStudioVirtualModContents({
tables: dbConfig.tables ?? {},
appToken: appToken.token,
Expand Down
16 changes: 10 additions & 6 deletions packages/db/src/core/cli/commands/push/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { getManagedAppTokenOrExit } from '@astrojs/studio';
import type { AstroConfig } from 'astro';
import { sql } from 'drizzle-orm';
import prompts from 'prompts';
Expand All @@ -7,7 +6,7 @@ import { createRemoteDatabaseClient } from '../../../../runtime/index.js';
import { safeFetch } from '../../../../runtime/utils.js';
import { MIGRATION_VERSION } from '../../../consts.js';
import type { DBConfig, DBSnapshot } from '../../../types.js';
import { type Result, getRemoteDatabaseInfo } from '../../../utils.js';
import { type RemoteDatabaseInfo, type Result, getManagedRemoteToken, getRemoteDatabaseInfo } from '../../../utils.js';
import {
createCurrentSnapshot,
createEmptySnapshot,
Expand All @@ -26,8 +25,12 @@ export async function cmd({
}) {
const isDryRun = flags.dryRun;
const isForceReset = flags.forceReset;
const appToken = await getManagedAppTokenOrExit(flags.token);
const productionSnapshot = await getProductionCurrentSnapshot({ appToken: appToken.token });
const dbInfo = getRemoteDatabaseInfo();
const appToken = await getManagedRemoteToken(flags.token, dbInfo);
const productionSnapshot = await getProductionCurrentSnapshot({
dbInfo,
appToken: appToken.token,
});
const currentSnapshot = createCurrentSnapshot(dbConfig);
const isFromScratch = !productionSnapshot;
const { queries: migrationQueries, confirmations } = await getMigrationQueries({
Expand Down Expand Up @@ -68,6 +71,7 @@ export async function cmd({
console.log(`Pushing database schema updates...`);
await pushSchema({
statements: migrationQueries,
dbInfo,
appToken: appToken.token,
isDryRun,
currentSnapshot: currentSnapshot,
Expand All @@ -80,11 +84,13 @@ export async function cmd({

async function pushSchema({
statements,
dbInfo,
appToken,
isDryRun,
currentSnapshot,
}: {
statements: string[];
dbInfo: RemoteDatabaseInfo;
appToken: string;
isDryRun: boolean;
currentSnapshot: DBSnapshot;
Expand All @@ -99,8 +105,6 @@ async function pushSchema({
return new Response(null, { status: 200 });
}

const dbInfo = getRemoteDatabaseInfo();

return dbInfo.type === 'studio'
? pushToStudio(requestBody, appToken, dbInfo.url)
: pushToDb(requestBody, appToken, dbInfo.url);
Expand Down
5 changes: 2 additions & 3 deletions packages/db/src/core/cli/commands/shell/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { getManagedAppTokenOrExit } from '@astrojs/studio';
import type { AstroConfig } from 'astro';
import { sql } from 'drizzle-orm';
import type { Arguments } from 'yargs-parser';
Expand All @@ -10,7 +9,7 @@ import { normalizeDatabaseUrl } from '../../../../runtime/index.js';
import { DB_PATH } from '../../../consts.js';
import { SHELL_QUERY_MISSING_ERROR } from '../../../errors.js';
import type { DBConfigInput } from '../../../types.js';
import { getAstroEnv, getRemoteDatabaseInfo } from '../../../utils.js';
import { getAstroEnv, getManagedRemoteToken, getRemoteDatabaseInfo } from '../../../utils.js';

export async function cmd({
flags,
Expand All @@ -27,7 +26,7 @@ export async function cmd({
}
const dbInfo = getRemoteDatabaseInfo();
if (flags.remote) {
const appToken = await getManagedAppTokenOrExit(flags.token);
const appToken = await getManagedRemoteToken(flags.token, dbInfo);
const db = createRemoteDatabaseClient({
dbType: dbInfo.type,
remoteUrl: dbInfo.url,
Expand Down
10 changes: 7 additions & 3 deletions packages/db/src/core/cli/commands/verify/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { getManagedAppTokenOrExit } from '@astrojs/studio';
import type { AstroConfig } from 'astro';
import type { Arguments } from 'yargs-parser';
import type { DBConfig } from '../../../types.js';
Expand All @@ -9,6 +8,7 @@ import {
getMigrationQueries,
getProductionCurrentSnapshot,
} from '../../migration-queries.js';
import { getManagedRemoteToken, getRemoteDatabaseInfo } from '../../../utils.js';

export async function cmd({
dbConfig,
Expand All @@ -19,8 +19,12 @@ export async function cmd({
flags: Arguments;
}) {
const isJson = flags.json;
const appToken = await getManagedAppTokenOrExit(flags.token);
const productionSnapshot = await getProductionCurrentSnapshot({ appToken: appToken.token });
const dbInfo = getRemoteDatabaseInfo();
const appToken = await getManagedRemoteToken(flags.token, dbInfo);
const productionSnapshot = await getProductionCurrentSnapshot({
dbInfo,
appToken: appToken.token,
});
const currentSnapshot = createCurrentSnapshot(dbConfig);
const { queries: migrationQueries, confirmations } = await getMigrationQueries({
oldSnapshot: productionSnapshot || createEmptySnapshot(),
Expand Down
11 changes: 5 additions & 6 deletions packages/db/src/core/cli/migration-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import type {
ResolvedIndexes,
TextColumn,
} from '../types.js';
import { type Result, getRemoteDatabaseInfo } from '../utils.js';
import type { RemoteDatabaseInfo, Result } from '../utils.js';

const sqlite = new SQLiteAsyncDialect();
const genTempTableName = customAlphabet('abcdefghijklmnopqrstuvwxyz', 10);
Expand Down Expand Up @@ -425,13 +425,12 @@ function hasRuntimeDefault(column: DBColumn): column is DBColumnWithDefault {
}

export function getProductionCurrentSnapshot(options: {
dbInfo: RemoteDatabaseInfo;
appToken: string;
}): Promise<DBSnapshot | undefined> {
const dbInfo = getRemoteDatabaseInfo();

return dbInfo.type === 'studio'
? getStudioCurrentSnapshot(options.appToken, dbInfo.url)
: getDbCurrentSnapshot(options.appToken, dbInfo.url);
return options.dbInfo.type === 'studio'
? getStudioCurrentSnapshot(options.appToken, options.dbInfo.url)
: getDbCurrentSnapshot(options.appToken, options.dbInfo.url);
}

async function getDbCurrentSnapshot(
Expand Down
26 changes: 13 additions & 13 deletions packages/db/src/core/integration/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { existsSync } from 'node:fs';
import { mkdir, writeFile } from 'node:fs/promises';
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { type ManagedAppToken, getManagedAppTokenOrExit } from '@astrojs/studio';
import type { ManagedAppToken } from '@astrojs/studio';
import { LibsqlError } from '@libsql/client';
import type { AstroConfig, AstroIntegration } from 'astro';
import { blue, yellow } from 'kleur/colors';
Expand All @@ -20,7 +20,7 @@ import { CONFIG_FILE_NAMES, DB_PATH } from '../consts.js';
import { EXEC_DEFAULT_EXPORT_ERROR, EXEC_ERROR } from '../errors.js';
import { resolveDbConfig } from '../load-file.js';
import { SEED_DEV_FILE_NAME } from '../queries.js';
import { type VitePlugin, getDbDirectoryUrl } from '../utils.js';
import { type VitePlugin, getDbDirectoryUrl, getManagedRemoteToken } from '../utils.js';
import { fileURLIntegration } from './file-url.js';
import { getDtsContent } from './typegen.js';
import {
Expand All @@ -32,7 +32,7 @@ import {
} from './vite-plugin-db.js';

function astroDBIntegration(): AstroIntegration {
let connectToStudio = false;
let connectToRemote = false;
let configFileDependencies: string[] = [];
let root: URL;
let appToken: ManagedAppToken | undefined;
Expand Down Expand Up @@ -72,12 +72,12 @@ function astroDBIntegration(): AstroIntegration {

let dbPlugin: VitePlugin | undefined = undefined;
const args = parseArgs(process.argv.slice(3));
connectToStudio = process.env.ASTRO_INTERNAL_TEST_REMOTE || args['remote'];
connectToRemote = process.env.ASTRO_INTERNAL_TEST_REMOTE || args['remote'];

if (connectToStudio) {
appToken = await getManagedAppTokenOrExit();
if (connectToRemote) {
appToken = await getManagedRemoteToken();
dbPlugin = vitePluginDb({
connectToStudio,
connectToStudio: connectToRemote,
appToken: appToken.token,
tables,
root: config.root,
Expand Down Expand Up @@ -116,7 +116,7 @@ function astroDBIntegration(): AstroIntegration {
configFileDependencies = dependencies;

const localDbUrl = new URL(DB_PATH, config.root);
if (!connectToStudio && !existsSync(localDbUrl)) {
if (!connectToRemote && !existsSync(localDbUrl)) {
await mkdir(dirname(fileURLToPath(localDbUrl)), { recursive: true });
await writeFile(localDbUrl, '');
}
Expand All @@ -143,9 +143,9 @@ function astroDBIntegration(): AstroIntegration {
// Wait for dev server log before showing "connected".
setTimeout(() => {
logger.info(
connectToStudio ? 'Connected to remote database.' : 'New local database created.',
connectToRemote ? 'Connected to remote database.' : 'New local database created.',
);
if (connectToStudio) return;
if (connectToRemote) return;

const localSeedPaths = SEED_DEV_FILE_NAME.map(
(name) => new URL(name, getDbDirectoryUrl(root)),
Expand All @@ -160,7 +160,7 @@ function astroDBIntegration(): AstroIntegration {
},
'astro:build:start': async ({ logger }) => {
if (
!connectToStudio &&
!connectToRemote &&
!databaseFileEnvDefined() &&
(output === 'server' || output === 'hybrid')
) {
Expand All @@ -170,15 +170,15 @@ function astroDBIntegration(): AstroIntegration {
throw new AstroDbError(message, hint);
}

logger.info('database: ' + (connectToStudio ? yellow('remote') : blue('local database.')));
logger.info('database: ' + (connectToRemote ? yellow('remote') : blue('local database.')));
},
'astro:build:setup': async ({ vite }) => {
tempViteServer = await getTempViteServer({ viteConfig: vite });
seedHandler.execute = async (fileUrl) => {
await executeSeedFile({ fileUrl, viteServer: tempViteServer! });
};
},
'astro:build:done': async ({}) => {
'astro:build:done': async ({ }) => {
await appToken?.destroy();
await tempViteServer?.close();
},
Expand Down
18 changes: 17 additions & 1 deletion packages/db/src/core/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getAstroStudioEnv } from '@astrojs/studio';
import { getAstroStudioEnv, getManagedAppTokenOrExit, type ManagedAppToken } from '@astrojs/studio';
import type { AstroConfig, AstroIntegration } from 'astro';
import { loadEnv } from 'vite';
import './types.js';
Expand Down Expand Up @@ -37,6 +37,22 @@ export function getRemoteDatabaseInfo(): RemoteDatabaseInfo {
};
}

export function getManagedRemoteToken(token?: string, dbInfo?: RemoteDatabaseInfo): Promise<ManagedAppToken> {
dbInfo ??= getRemoteDatabaseInfo();

if (dbInfo.type === 'studio') {
return getManagedAppTokenOrExit(token)
}

const astroEnv = getAstroEnv();

return Promise.resolve({
token: token ?? astroEnv.ASTRO_DB_APP_TOKEN,
renew: () => Promise.resolve(),
destroy: () => Promise.resolve(),
});
}

export function getDbDirectoryUrl(root: URL | string) {
return new URL('db/', root);
}
Expand Down
5 changes: 4 additions & 1 deletion packages/db/test/basics.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { after, before, describe, it } from 'node:test';
import { load as cheerioLoad } from 'cheerio';
import testAdapter from '../../astro/test/test-adapter.js';
import { loadFixture } from '../../astro/test/test-utils.js';
import { setupRemoteDbServer } from './test-utils.js';
import { clearEnvironment, setupRemoteDbServer } from './test-utils.js';

describe('astro:db', () => {
let fixture;
Expand All @@ -19,6 +19,7 @@ describe('astro:db', () => {
let devServer;

before(async () => {
clearEnvironment();
devServer = await fixture.startDevServer();
});

Expand Down Expand Up @@ -98,6 +99,7 @@ describe('astro:db', () => {
let remoteDbServer;

before(async () => {
clearEnvironment();
remoteDbServer = await setupRemoteDbServer(fixture.config);
devServer = await fixture.startDevServer();
});
Expand Down Expand Up @@ -178,6 +180,7 @@ describe('astro:db', () => {
let remoteDbServer;

before(async () => {
clearEnvironment();
process.env.ASTRO_STUDIO_APP_TOKEN = 'some token';
remoteDbServer = await setupRemoteDbServer(fixture.config);
await fixture.build();
Expand Down
3 changes: 2 additions & 1 deletion packages/db/test/static-remote.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import assert from 'node:assert/strict';
import { after, before, describe, it } from 'node:test';
import { load as cheerioLoad } from 'cheerio';
import { loadFixture } from '../../astro/test/test-utils.js';
import { setupRemoteDbServer } from './test-utils.js';
import { clearEnvironment, setupRemoteDbServer } from './test-utils.js';

describe('astro:db', () => {
let fixture;
Expand Down Expand Up @@ -44,6 +44,7 @@ describe('astro:db', () => {
let remoteDbServer;

before(async () => {
clearEnvironment();
process.env.ASTRO_DB_REMOTE_URL = `memory:`;
await fixture.build();
});
Expand Down
12 changes: 12 additions & 0 deletions packages/db/test/test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ export async function setupRemoteDbServer(astroConfig) {
};
}

/**
* Clears the environment variables related to Astro DB and Astro Studio.
*/
export function clearEnvironment() {
const keys = Array.from(Object.keys(process.env));
for (const key of keys) {
if (key.startsWith('ASTRO_DB_') || key.startsWith('ASTRO_STUDIO_')) {
delete process.env[key];
}
}
}

function createRemoteDbServer() {
const dbClient = createClient({
url: ':memory:',
Expand Down
Loading
Loading