mirror of
https://github.com/withastro/astro.git
synced 2025-03-24 23:21:57 -05:00
add short-lived db tokens
This commit is contained in:
parent
3850637e19
commit
4712d2be57
11 changed files with 359 additions and 29 deletions
|
@ -59,17 +59,19 @@
|
||||||
"drizzle-orm": "^0.28.6",
|
"drizzle-orm": "^0.28.6",
|
||||||
"kleur": "^4.1.5",
|
"kleur": "^4.1.5",
|
||||||
"nanoid": "^5.0.1",
|
"nanoid": "^5.0.1",
|
||||||
|
"open": "^10.0.3",
|
||||||
|
"ora": "^7.0.1",
|
||||||
"prompts": "^2.4.2",
|
"prompts": "^2.4.2",
|
||||||
"yargs-parser": "^21.1.1",
|
"yargs-parser": "^21.1.1",
|
||||||
"zod": "^3.22.4"
|
"zod": "^3.22.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/chai": "^4.3.6",
|
||||||
"@types/deep-diff": "^1.0.5",
|
"@types/deep-diff": "^1.0.5",
|
||||||
"@types/diff": "^5.0.8",
|
"@types/diff": "^5.0.8",
|
||||||
"@types/yargs-parser": "^21.0.3",
|
|
||||||
"@types/chai": "^4.3.6",
|
|
||||||
"@types/mocha": "^10.0.2",
|
"@types/mocha": "^10.0.2",
|
||||||
"@types/prompts": "^2.4.8",
|
"@types/prompts": "^2.4.8",
|
||||||
|
"@types/yargs-parser": "^21.0.3",
|
||||||
"astro": "workspace:*",
|
"astro": "workspace:*",
|
||||||
"astro-scripts": "workspace:*",
|
"astro-scripts": "workspace:*",
|
||||||
"chai": "^4.3.10",
|
"chai": "^4.3.10",
|
||||||
|
|
61
packages/db/src/core/cli/commands/link/index.ts
Normal file
61
packages/db/src/core/cli/commands/link/index.ts
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import type { AstroConfig } from 'astro';
|
||||||
|
import { mkdir, writeFile } from 'node:fs/promises';
|
||||||
|
import prompts from 'prompts';
|
||||||
|
import type { Arguments } from 'yargs-parser';
|
||||||
|
import { PROJECT_ID_FILE, getSessionIdFromFile } from '../../../tokens.js';
|
||||||
|
import { getAstroStudioUrl } from '../../../utils.js';
|
||||||
|
|
||||||
|
export async function cmd({ flags }: { config: AstroConfig; flags: Arguments }) {
|
||||||
|
const linkUrl = new URL(getAstroStudioUrl() + '/auth/cli/link');
|
||||||
|
const sessionToken = await getSessionIdFromFile();
|
||||||
|
if (!sessionToken) {
|
||||||
|
console.error('You must be logged in to link a project.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const workspaceIdName = await promptWorkspaceName();
|
||||||
|
const projectIdName = await promptProjectName();
|
||||||
|
|
||||||
|
const response = await fetch(linkUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${await getSessionIdFromFile()}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({projectIdName, workspaceIdName})
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
console.error(`Failed to link project: ${response.status} ${response.statusText}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
const { data } = await response.json();
|
||||||
|
await mkdir(new URL('.', PROJECT_ID_FILE), { recursive: true });
|
||||||
|
await writeFile(PROJECT_ID_FILE, `${data.id}`);
|
||||||
|
console.info('Project linked.');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function promptProjectName(defaultName?: string): Promise<string> {
|
||||||
|
const { projectName } = await prompts({
|
||||||
|
type: 'text',
|
||||||
|
name: 'projectName',
|
||||||
|
message: 'Project ID',
|
||||||
|
initial: defaultName,
|
||||||
|
});
|
||||||
|
if (typeof projectName !== 'string') {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
return projectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function promptWorkspaceName(defaultName?: string): Promise<string> {
|
||||||
|
const { workspaceName } = await prompts({
|
||||||
|
type: 'text',
|
||||||
|
name: 'workspaceName',
|
||||||
|
message: 'Workspace ID',
|
||||||
|
initial: defaultName,
|
||||||
|
});
|
||||||
|
if (typeof workspaceName !== 'string') {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
return workspaceName;
|
||||||
|
}
|
52
packages/db/src/core/cli/commands/login/index.ts
Normal file
52
packages/db/src/core/cli/commands/login/index.ts
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import type { AstroConfig } from 'astro';
|
||||||
|
import { cyan } from 'kleur/colors';
|
||||||
|
import { mkdir, writeFile } from 'node:fs/promises';
|
||||||
|
import { createServer } from 'node:http';
|
||||||
|
import ora from 'ora';
|
||||||
|
import type { Arguments } from 'yargs-parser';
|
||||||
|
import { getAstroStudioUrl } from '../../../utils.js';
|
||||||
|
import open from 'open';
|
||||||
|
import { SESSION_LOGIN_FILE } from '../../../tokens.js';
|
||||||
|
|
||||||
|
function serveAndResolveSession(): Promise<string> {
|
||||||
|
let resolve: (value: string | PromiseLike<string>) => void,
|
||||||
|
reject: (value?: string | PromiseLike<string>) => void;
|
||||||
|
const sessionPromise = new Promise<string>((_resolve, _reject) => {
|
||||||
|
resolve = _resolve;
|
||||||
|
reject = _reject;
|
||||||
|
});
|
||||||
|
|
||||||
|
const server = createServer((req, res) => {
|
||||||
|
res.writeHead(200);
|
||||||
|
res.end();
|
||||||
|
const url = new URL(req.url ?? '/', `http://${req.headers.host}`);
|
||||||
|
const session = url.searchParams.get('session');
|
||||||
|
if (!session) {
|
||||||
|
reject();
|
||||||
|
} else {
|
||||||
|
resolve(session);
|
||||||
|
}
|
||||||
|
}).listen(5710, 'localhost');
|
||||||
|
|
||||||
|
return sessionPromise.finally(() => {
|
||||||
|
server.closeAllConnections();
|
||||||
|
server.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function cmd({ flags }: { config: AstroConfig; flags: Arguments }) {
|
||||||
|
let session = flags.session;
|
||||||
|
const loginUrl = getAstroStudioUrl() + '/auth/cli';
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
console.log(`Opening ${cyan(loginUrl)} in your browser...`);
|
||||||
|
console.log(`If something goes wrong, copy-and-paste the URL into your browser.`);
|
||||||
|
open(loginUrl);
|
||||||
|
const spinner = ora('Waiting for confirmation...');
|
||||||
|
session = await serveAndResolveSession();
|
||||||
|
spinner.succeed('Successfully logged in!');
|
||||||
|
}
|
||||||
|
|
||||||
|
await mkdir(new URL('.', SESSION_LOGIN_FILE), { recursive: true });
|
||||||
|
await writeFile(SESSION_LOGIN_FILE, `${session}`);
|
||||||
|
}
|
9
packages/db/src/core/cli/commands/logout/index.ts
Normal file
9
packages/db/src/core/cli/commands/logout/index.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import type { AstroConfig } from 'astro';
|
||||||
|
import { unlink } from 'node:fs/promises';
|
||||||
|
import type { Arguments } from 'yargs-parser';
|
||||||
|
import { SESSION_LOGIN_FILE } from '../../../tokens.js';
|
||||||
|
|
||||||
|
export async function cmd({ }: { config: AstroConfig; flags: Arguments }) {
|
||||||
|
await unlink(SESSION_LOGIN_FILE);
|
||||||
|
console.log('Successfully logged out of Astro Studio.');
|
||||||
|
}
|
|
@ -2,9 +2,15 @@ import { createClient, type InStatement } from '@libsql/client';
|
||||||
import type { AstroConfig } from 'astro';
|
import type { AstroConfig } from 'astro';
|
||||||
import deepDiff from 'deep-diff';
|
import deepDiff from 'deep-diff';
|
||||||
import { drizzle } from 'drizzle-orm/sqlite-proxy';
|
import { drizzle } from 'drizzle-orm/sqlite-proxy';
|
||||||
|
import { red } from 'kleur/colors';
|
||||||
|
import prompts from 'prompts';
|
||||||
import type { Arguments } from 'yargs-parser';
|
import type { Arguments } from 'yargs-parser';
|
||||||
import type { AstroConfigWithDB } from '../../../types.js';
|
|
||||||
import { APP_TOKEN_ERROR } from '../../../errors.js';
|
import { APP_TOKEN_ERROR } from '../../../errors.js';
|
||||||
|
import { setupDbTables } from '../../../queries.js';
|
||||||
|
import { getManagedAppToken } from '../../../tokens.js';
|
||||||
|
import type { AstroConfigWithDB, DBSnapshot } from '../../../types.js';
|
||||||
|
import { getRemoteDatabaseUrl } from '../../../utils.js';
|
||||||
|
import { getMigrationQueries } from '../../migration-queries.js';
|
||||||
import {
|
import {
|
||||||
createCurrentSnapshot,
|
createCurrentSnapshot,
|
||||||
createEmptySnapshot,
|
createEmptySnapshot,
|
||||||
|
@ -13,19 +19,12 @@ import {
|
||||||
loadInitialSnapshot,
|
loadInitialSnapshot,
|
||||||
loadMigration,
|
loadMigration,
|
||||||
} from '../../migrations.js';
|
} from '../../migrations.js';
|
||||||
import type { DBSnapshot } from '../../../types.js';
|
|
||||||
import { getAstroStudioEnv, getRemoteDatabaseUrl } from '../../../utils.js';
|
|
||||||
import { getMigrationQueries } from '../../migration-queries.js';
|
|
||||||
import { setupDbTables } from '../../../queries.js';
|
|
||||||
import prompts from 'prompts';
|
|
||||||
import { red } from 'kleur/colors';
|
|
||||||
|
|
||||||
const { diff } = deepDiff;
|
const { diff } = deepDiff;
|
||||||
|
|
||||||
export async function cmd({ config, flags }: { config: AstroConfig; flags: Arguments }) {
|
export async function cmd({ config, flags }: { config: AstroConfig; flags: Arguments }) {
|
||||||
const isSeedData = flags.seed;
|
const isSeedData = flags.seed;
|
||||||
const isDryRun = flags.dryRun;
|
const isDryRun = flags.dryRun;
|
||||||
const appToken = flags.token ?? getAstroStudioEnv().ASTRO_STUDIO_APP_TOKEN;
|
|
||||||
const currentSnapshot = createCurrentSnapshot(config);
|
const currentSnapshot = createCurrentSnapshot(config);
|
||||||
const allMigrationFiles = await getMigrations();
|
const allMigrationFiles = await getMigrations();
|
||||||
if (allMigrationFiles.length === 0) {
|
if (allMigrationFiles.length === 0) {
|
||||||
|
@ -40,15 +39,18 @@ export async function cmd({ config, flags }: { config: AstroConfig; flags: Argum
|
||||||
console.log(calculatedDiff);
|
console.log(calculatedDiff);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const appToken = await getManagedAppToken(flags.token);
|
||||||
if (!appToken) {
|
if (!appToken) {
|
||||||
console.error(APP_TOKEN_ERROR);
|
console.error(APP_TOKEN_ERROR);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get all migrations from the filesystem
|
// get all migrations from the filesystem
|
||||||
const allLocalMigrations = await getMigrations();
|
const allLocalMigrations = await getMigrations();
|
||||||
const { data: missingMigrations } = await prepareMigrateQuery({
|
const { data: missingMigrations } = await prepareMigrateQuery({
|
||||||
migrations: allLocalMigrations,
|
migrations: allLocalMigrations,
|
||||||
appToken,
|
appToken: appToken.token,
|
||||||
});
|
});
|
||||||
// exit early if there are no migrations to push
|
// exit early if there are no migrations to push
|
||||||
if (missingMigrations.length === 0) {
|
if (missingMigrations.length === 0) {
|
||||||
|
@ -58,13 +60,19 @@ export async function cmd({ config, flags }: { config: AstroConfig; flags: Argum
|
||||||
// push the database schema
|
// push the database schema
|
||||||
if (missingMigrations.length > 0) {
|
if (missingMigrations.length > 0) {
|
||||||
console.log(`Pushing ${missingMigrations.length} migrations...`);
|
console.log(`Pushing ${missingMigrations.length} migrations...`);
|
||||||
await pushSchema({ migrations: missingMigrations, appToken, isDryRun, currentSnapshot });
|
await pushSchema({
|
||||||
|
migrations: missingMigrations,
|
||||||
|
appToken: appToken.token,
|
||||||
|
isDryRun,
|
||||||
|
currentSnapshot,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
// push the database seed data
|
// push the database seed data
|
||||||
if (isSeedData) {
|
if (isSeedData) {
|
||||||
console.info('Pushing data...');
|
console.info('Pushing data...');
|
||||||
await pushData({ config, appToken, isDryRun });
|
await pushData({ config, appToken: appToken.token, isDryRun });
|
||||||
}
|
}
|
||||||
|
await appToken.destroy();
|
||||||
console.info('Push complete!');
|
console.info('Push complete!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,7 +209,7 @@ async function runMigrateQuery({
|
||||||
return new Response(null, { status: 200 });
|
return new Response(null, { status: 200 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = new URL('/db/migrate/run', getRemoteDatabaseUrl());
|
const url = new URL('/migrations/run', getRemoteDatabaseUrl());
|
||||||
|
|
||||||
return await fetch(url, {
|
return await fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
@ -219,7 +227,7 @@ async function prepareMigrateQuery({
|
||||||
migrations: string[];
|
migrations: string[];
|
||||||
appToken: string;
|
appToken: string;
|
||||||
}) {
|
}) {
|
||||||
const url = new URL('/db/migrate/prepare', getRemoteDatabaseUrl());
|
const url = new URL('/migrations/prepare', getRemoteDatabaseUrl());
|
||||||
const requestBody = {
|
const requestBody = {
|
||||||
migrations,
|
migrations,
|
||||||
experimentalVersion: 1,
|
experimentalVersion: 1,
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
import type { AstroConfig } from 'astro';
|
import type { AstroConfig } from 'astro';
|
||||||
import { sql } from 'drizzle-orm';
|
import { sql } from 'drizzle-orm';
|
||||||
import type { Arguments } from 'yargs-parser';
|
import type { Arguments } from 'yargs-parser';
|
||||||
import { APP_TOKEN_ERROR } from '../../../errors.js';
|
|
||||||
import { getAstroStudioEnv, getRemoteDatabaseUrl } from '../../../utils.js';
|
|
||||||
import { createRemoteDatabaseClient } from '../../../../runtime/db-client.js';
|
import { createRemoteDatabaseClient } from '../../../../runtime/db-client.js';
|
||||||
|
import { APP_TOKEN_ERROR } from '../../../errors.js';
|
||||||
|
import { getManagedAppToken } from '../../../tokens.js';
|
||||||
|
import { getRemoteDatabaseUrl } from '../../../utils.js';
|
||||||
|
|
||||||
export async function cmd({ flags }: { config: AstroConfig; flags: Arguments }) {
|
export async function cmd({ flags }: { config: AstroConfig; flags: Arguments }) {
|
||||||
const query = flags.query;
|
const query = flags.query;
|
||||||
const appToken = flags.token ?? getAstroStudioEnv().ASTRO_STUDIO_APP_TOKEN;
|
const appToken = await getManagedAppToken(flags.token);
|
||||||
if (!appToken) {
|
if (!appToken) {
|
||||||
console.error(APP_TOKEN_ERROR);
|
console.error(APP_TOKEN_ERROR);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
const db = createRemoteDatabaseClient(appToken.token, getRemoteDatabaseUrl());
|
||||||
const db = createRemoteDatabaseClient(appToken, getRemoteDatabaseUrl());
|
|
||||||
// Temporary: create the migration table just in case it doesn't exist
|
// Temporary: create the migration table just in case it doesn't exist
|
||||||
const result = await db.run(sql.raw(query));
|
const result = await db.run(sql.raw(query));
|
||||||
|
await appToken.destroy();
|
||||||
console.log(result);
|
console.log(result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,20 +12,32 @@ export async function cli({ flags, config }: { flags: Arguments; config: AstroCo
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 'shell': {
|
case 'shell': {
|
||||||
const { cmd: shellCommand } = await import('./commands/shell/index.js');
|
const { cmd } = await import('./commands/shell/index.js');
|
||||||
return await shellCommand({ config, flags });
|
return await cmd({ config, flags });
|
||||||
}
|
}
|
||||||
case 'sync': {
|
case 'sync': {
|
||||||
const { cmd: syncCommand } = await import('./commands/sync/index.js');
|
const { cmd } = await import('./commands/sync/index.js');
|
||||||
return await syncCommand({ config, flags });
|
return await cmd({ config, flags });
|
||||||
}
|
}
|
||||||
case 'push': {
|
case 'push': {
|
||||||
const { cmd: pushCommand } = await import('./commands/push/index.js');
|
const { cmd } = await import('./commands/push/index.js');
|
||||||
return await pushCommand({ config, flags });
|
return await cmd({ config, flags });
|
||||||
}
|
}
|
||||||
case 'verify': {
|
case 'verify': {
|
||||||
const { cmd: verifyCommand } = await import('./commands/verify/index.js');
|
const { cmd } = await import('./commands/verify/index.js');
|
||||||
return await verifyCommand({ config, flags });
|
return await cmd({ config, flags });
|
||||||
|
}
|
||||||
|
case 'login': {
|
||||||
|
const { cmd } = await import('./commands/login/index.js');
|
||||||
|
return await cmd({ config, flags });
|
||||||
|
}
|
||||||
|
case 'logout': {
|
||||||
|
const { cmd } = await import('./commands/logout/index.js');
|
||||||
|
return await cmd({ config, flags });
|
||||||
|
}
|
||||||
|
case 'link': {
|
||||||
|
const { cmd } = await import('./commands/link/index.js');
|
||||||
|
return await cmd({ config, flags });
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
if (command == null) {
|
if (command == null) {
|
||||||
|
|
134
packages/db/src/core/tokens.ts
Normal file
134
packages/db/src/core/tokens.ts
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
import { readFile } from 'node:fs/promises';
|
||||||
|
import { homedir } from 'node:os';
|
||||||
|
import { join } from 'node:path';
|
||||||
|
import { pathToFileURL } from 'node:url';
|
||||||
|
import { getAstroStudioEnv, getAstroStudioUrl } from './utils.js';
|
||||||
|
|
||||||
|
export const SESSION_LOGIN_FILE = pathToFileURL(join(homedir(), '.astro', 'session-token'));
|
||||||
|
export const PROJECT_ID_FILE = pathToFileURL(join(process.cwd(), '.astro', 'link'));
|
||||||
|
|
||||||
|
export interface ManagedAppToken {
|
||||||
|
token: string;
|
||||||
|
renew(): Promise<void>;
|
||||||
|
destroy(): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ManagedLocalAppToken implements ManagedAppToken {
|
||||||
|
token: string;
|
||||||
|
constructor(token: string) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
async renew() {}
|
||||||
|
async destroy() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ManagedRemoteAppToken implements ManagedAppToken {
|
||||||
|
token: string;
|
||||||
|
session: string;
|
||||||
|
projectId: string;
|
||||||
|
ttl: number;
|
||||||
|
renewTimer: NodeJS.Timeout | undefined;
|
||||||
|
|
||||||
|
static async create(sessionToken: string, projectId: string) {
|
||||||
|
const response = await fetch(new URL(`${getAstroStudioUrl()}/auth/cli/token-create`), {
|
||||||
|
method: 'POST',
|
||||||
|
headers: new Headers({
|
||||||
|
Authorization: `Bearer ${sessionToken}`,
|
||||||
|
}),
|
||||||
|
body: JSON.stringify({ projectId }),
|
||||||
|
});
|
||||||
|
const { token: shortLivedAppToken, ttl } = (await response.json());
|
||||||
|
return new ManagedRemoteAppToken({
|
||||||
|
token: shortLivedAppToken,
|
||||||
|
session: sessionToken,
|
||||||
|
projectId,
|
||||||
|
ttl,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(options: { token: string; session: string; projectId: string; ttl: number }) {
|
||||||
|
this.token = options.token;
|
||||||
|
this.session = options.session;
|
||||||
|
this.projectId = options.projectId;
|
||||||
|
this.ttl = options.ttl;
|
||||||
|
this.renewTimer = setTimeout(() => this.renew(), (1000 * 60 * 5) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async fetch(url: string, body: unknown) {
|
||||||
|
return fetch(`${getAstroStudioUrl()}${url}`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${this.session}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async renew() {
|
||||||
|
clearTimeout(this.renewTimer);
|
||||||
|
delete this.renewTimer;
|
||||||
|
try {
|
||||||
|
const response = await this.fetch('/auth/cli/token-renew', {
|
||||||
|
token: this.token,
|
||||||
|
projectId: this.projectId,
|
||||||
|
});
|
||||||
|
if (response.status === 200) {
|
||||||
|
this.renewTimer = setTimeout(() => this.renew(), (1000 * 60 * this.ttl) / 2);
|
||||||
|
} else {
|
||||||
|
throw new Error(`Unexpected response: ${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
const retryIn = (60 * this.ttl) / 10;
|
||||||
|
console.error(`Failed to renew token. Retrying in ${retryIn} seconds.`, error?.message);
|
||||||
|
this.renewTimer = setTimeout(() => this.renew(), retryIn * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async destroy() {
|
||||||
|
try {
|
||||||
|
const response = await this.fetch('/auth/cli/token-delete', {
|
||||||
|
token: this.token,
|
||||||
|
projectId: this.projectId,
|
||||||
|
});
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Unexpected response: ${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('Failed to delete token.', error?.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function getProjectIdFromFile() {
|
||||||
|
try {
|
||||||
|
return await readFile(PROJECT_ID_FILE, 'utf-8');
|
||||||
|
} catch (error) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSessionIdFromFile() {
|
||||||
|
try {
|
||||||
|
return await readFile(SESSION_LOGIN_FILE, 'utf-8');
|
||||||
|
} catch (error) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getManagedAppToken(token?: string): Promise<ManagedAppToken | undefined> {
|
||||||
|
if (token) {
|
||||||
|
return new ManagedLocalAppToken(token);
|
||||||
|
}
|
||||||
|
const { ASTRO_STUDIO_APP_TOKEN } = getAstroStudioEnv();
|
||||||
|
if (ASTRO_STUDIO_APP_TOKEN) {
|
||||||
|
return new ManagedLocalAppToken(ASTRO_STUDIO_APP_TOKEN);
|
||||||
|
}
|
||||||
|
const sessionToken = await getSessionIdFromFile();
|
||||||
|
const projectId = await getProjectIdFromFile();
|
||||||
|
if (!sessionToken || !projectId) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return ManagedRemoteAppToken.create(sessionToken, projectId);
|
||||||
|
}
|
|
@ -12,3 +12,8 @@ export function getRemoteDatabaseUrl(): string {
|
||||||
const env = getAstroStudioEnv();
|
const env = getAstroStudioEnv();
|
||||||
return env.ASTRO_STUDIO_REMOTE_DB_URL;
|
return env.ASTRO_STUDIO_REMOTE_DB_URL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getAstroStudioUrl(): string {
|
||||||
|
const env = getAstroStudioEnv();
|
||||||
|
return env.ASTRO_STUDIO_URL;
|
||||||
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ function checkIfModificationIsAllowed(collections: DBCollections, Table: SQLiteT
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createRemoteDatabaseClient(appToken: string, remoteDbURL: string) {
|
export function createRemoteDatabaseClient(appToken: string, remoteDbURL: string) {
|
||||||
const url = new URL('./db/query/', remoteDbURL);
|
const url = new URL('/db/query', remoteDbURL);
|
||||||
|
|
||||||
const db = drizzleProxy(async (sql, parameters, method) => {
|
const db = drizzleProxy(async (sql, parameters, method) => {
|
||||||
const requestBody: InStatement = { sql, args: parameters };
|
const requestBody: InStatement = { sql, args: parameters };
|
||||||
|
|
46
pnpm-lock.yaml
generated
46
pnpm-lock.yaml
generated
|
@ -3805,6 +3805,12 @@ importers:
|
||||||
nanoid:
|
nanoid:
|
||||||
specifier: ^5.0.1
|
specifier: ^5.0.1
|
||||||
version: 5.0.1
|
version: 5.0.1
|
||||||
|
open:
|
||||||
|
specifier: ^10.0.3
|
||||||
|
version: 10.0.3
|
||||||
|
ora:
|
||||||
|
specifier: ^7.0.1
|
||||||
|
version: 7.0.1
|
||||||
prompts:
|
prompts:
|
||||||
specifier: ^2.4.2
|
specifier: ^2.4.2
|
||||||
version: 2.4.2
|
version: 2.4.2
|
||||||
|
@ -9108,6 +9114,13 @@ packages:
|
||||||
ieee754: 1.2.1
|
ieee754: 1.2.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/bundle-name@4.1.0:
|
||||||
|
resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
dependencies:
|
||||||
|
run-applescript: 7.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/bytes@3.1.2:
|
/bytes@3.1.2:
|
||||||
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
@ -9799,6 +9812,19 @@ packages:
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/default-browser-id@5.0.0:
|
||||||
|
resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/default-browser@5.2.1:
|
||||||
|
resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
dependencies:
|
||||||
|
bundle-name: 4.1.0
|
||||||
|
default-browser-id: 5.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/defaults@1.0.4:
|
/defaults@1.0.4:
|
||||||
resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
|
resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -9814,6 +9840,11 @@ packages:
|
||||||
has-property-descriptors: 1.0.1
|
has-property-descriptors: 1.0.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/define-lazy-prop@3.0.0:
|
||||||
|
resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/define-properties@1.2.1:
|
/define-properties@1.2.1:
|
||||||
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
|
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -13401,6 +13432,16 @@ packages:
|
||||||
resolution: {integrity: sha512-6mp/gpLQz/ZwrGLz+i7tSJ3eWNLE1KxLXHO+b6xxRyZ1Alp4TgTcvHiQ89rC2IkvsU3/IRhpIJuxl7rRCwUzLA==}
|
resolution: {integrity: sha512-6mp/gpLQz/ZwrGLz+i7tSJ3eWNLE1KxLXHO+b6xxRyZ1Alp4TgTcvHiQ89rC2IkvsU3/IRhpIJuxl7rRCwUzLA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/open@10.0.3:
|
||||||
|
resolution: {integrity: sha512-dtbI5oW7987hwC9qjJTyABldTaa19SuyJse1QboWv3b0qCcrrLNVDqBx1XgELAjh9QTVQaP/C5b1nhQebd1H2A==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
dependencies:
|
||||||
|
default-browser: 5.2.1
|
||||||
|
define-lazy-prop: 3.0.0
|
||||||
|
is-inside-container: 1.0.0
|
||||||
|
is-wsl: 3.1.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/optionator@0.9.3:
|
/optionator@0.9.3:
|
||||||
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
|
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
@ -14815,6 +14856,11 @@ packages:
|
||||||
resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
|
resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/run-applescript@7.0.0:
|
||||||
|
resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/run-parallel@1.2.0:
|
/run-parallel@1.2.0:
|
||||||
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
Loading…
Add table
Reference in a new issue