0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-16 21:46:22 -05:00

Require that ASTRO_STUDIO_REMOTE_DB_URL is defined at runtime (#10533)

* Require that ASTRO_STUDIO_REMOTE_DB_URL is defined at runtime

* Add changeset

* Fix build
This commit is contained in:
Matthew Phillips 2024-03-22 11:52:38 -04:00 committed by GitHub
parent 8306ce1ff7
commit 6576f5d458
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 160 additions and 4 deletions

View file

@ -0,0 +1,5 @@
---
"@astrojs/db": patch
---
Ensure ASTRO_STUDIO_APP_TOKEN is found at runtime

View file

@ -44,6 +44,7 @@ export async function cmd({
virtualModContents = getStudioVirtualModContents({
tables: dbConfig.tables ?? {},
appToken: appToken.token,
isBuild: false,
});
} else {
virtualModContents = getLocalVirtualModContents({

View file

@ -37,9 +37,13 @@ type VitePluginDBParams =
export function vitePluginDb(params: VitePluginDBParams): VitePlugin {
const srcDirPath = normalizePath(fileURLToPath(params.srcDir));
let command: 'build' | 'serve' = 'build';
return {
name: 'astro:db',
enforce: 'pre',
configResolved(resolvedConfig) {
command = resolvedConfig.command;
},
async resolveId(id, rawImporter) {
if (id !== VIRTUAL_MODULE_ID) return;
if (params.connectToStudio) return resolved.virtual;
@ -61,6 +65,7 @@ export function vitePluginDb(params: VitePluginDBParams): VitePlugin {
return getStudioVirtualModContents({
appToken: params.appToken,
tables: params.tables.get(),
isBuild: command === 'build',
});
}
return getLocalVirtualModContents({
@ -135,17 +140,31 @@ ${getStringifiedCollectionExports(tables)}`;
export function getStudioVirtualModContents({
tables,
appToken,
isBuild,
}: {
tables: DBTables;
appToken: string;
isBuild: boolean;
}) {
function appTokenArg() {
if(isBuild) {
// In production build, always read the runtime environment variable.
return 'process.env.ASTRO_STUDIO_APP_TOKEN';
} else {
return JSON.stringify(appToken);
}
}
function dbUrlArg() {
const dbStr = JSON.stringify(getRemoteDatabaseUrl());
// Allow overriding, mostly for testing
return `import.meta.env.ASTRO_STUDIO_REMOTE_DB_URL ?? ${dbStr}`;
}
return `
import {asDrizzleTable, createRemoteDatabaseClient} from ${RUNTIME_IMPORT};
export const db = await createRemoteDatabaseClient(process.env.ASTRO_STUDIO_APP_TOKEN ?? ${JSON.stringify(
appToken
// Respect runtime env for user overrides in SSR
)}, import.meta.env.ASTRO_STUDIO_REMOTE_DB_URL ?? ${JSON.stringify(getRemoteDatabaseUrl())});
export const db = await createRemoteDatabaseClient(${appTokenArg()}, ${dbUrlArg()});
export * from ${RUNTIME_CONFIG_IMPORT};

View file

@ -36,6 +36,10 @@ const remoteResultSchema = z.object({
});
export function createRemoteDatabaseClient(appToken: string, remoteDbURL: string) {
if(appToken == null) {
throw new Error(`Cannot create a remote client: missing app token.`)
}
const url = new URL('/db/query', remoteDbURL);
const db = drizzleProxy(

View file

@ -138,4 +138,29 @@ describe('astro:db', () => {
expect($('.username').text()).to.equal('Mario');
});
});
describe('build --remote', () => {
let remoteDbServer;
before(async () => {
process.env.ASTRO_STUDIO_APP_TOKEN = 'some token';
remoteDbServer = await setupRemoteDbServer(fixture.config);
await fixture.build();
});
after(async () => {
await remoteDbServer?.stop();
});
it('Can render page', async () => {
const app = await fixture.loadTestAdapterApp();
const request = new Request('http://example.com/');
const response = await app.render(request);
const html = await response.text();
const $ = cheerioLoad(html);
const ul = $('.authors-list');
expect(ul.children()).to.have.a.lengthOf(5);
});
});
});

View file

@ -0,0 +1,10 @@
import db from '@astrojs/db';
import { defineConfig } from 'astro/config';
// https://astro.build/config
export default defineConfig({
integrations: [db()],
devToolbar: {
enabled: false,
},
});

View file

@ -0,0 +1,14 @@
import { column, defineDb, defineTable } from 'astro:db';
const User = defineTable({
columns: {
id: column.text({ primaryKey: true, optional: false }),
username: column.text({ optional: false, unique: true }),
password: column.text({ optional: false }),
},
});
export default defineDb({
tables: { User },
});

View file

@ -0,0 +1,4 @@
export default function() {
}

View file

@ -0,0 +1,14 @@
{
"name": "@test/db-no-apptoken",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview"
},
"dependencies": {
"@astrojs/db": "workspace:*",
"astro": "workspace:*"
}
}

View file

@ -0,0 +1,15 @@
---
/// <reference path="../../.astro/db-types.d.ts" />
import { db, User } from 'astro:db';
// Just for the side-effect of running all the code
await db.select().from(User);
---
<html>
<head>
<title>Testing</title>
</head>
<body>
<h1>Testing</h1>
</body>
</html>

View file

@ -0,0 +1,36 @@
import { expect } from 'chai';
import testAdapter from '../../astro/test/test-adapter.js';
import { loadFixture } from '../../astro/test/test-utils.js';
import { setupRemoteDbServer } from './test-utils.js';
describe('missing app token', () => {
let fixture;
let remoteDbServer;
before(async () => {
fixture = await loadFixture({
root: new URL('./fixtures/no-apptoken/', import.meta.url),
output: 'server',
adapter: testAdapter(),
});
remoteDbServer = await setupRemoteDbServer(fixture.config);
await fixture.build();
// Ensure there's no token at runtime
delete process.env.ASTRO_STUDIO_APP_TOKEN;
});
after(async () => {
await remoteDbServer?.stop();
});
it('Errors as runtime', async () => {
const app = await fixture.loadTestAdapterApp();
const request = new Request('http://example.com/');
try {
const response = await app.render(request);
await response.text();
} catch {
expect(response.status).to.equal(501);
}
});
});

View file

@ -3948,6 +3948,15 @@ importers:
specifier: workspace:*
version: link:../../../../astro
packages/db/test/fixtures/no-apptoken:
dependencies:
'@astrojs/db':
specifier: workspace:*
version: link:../../..
astro:
specifier: workspace:*
version: link:../../../../astro
packages/db/test/fixtures/no-seed:
dependencies:
'@astrojs/db':