Repository: withastro/astro
File: packages/db/src/runtime/db-client.ts (TypeScript)

Code before:
		!rawUrl.startsWith('file:/')
	) {
		// libSQL accepts relative and absolute file URLs
		// for local DBs. This doesn't match the URL specification.
		// Parsing `file:some.db` and `file:/some.db` should yield
		// the same result, but libSQL interprets the former as
		// a relative path, and the latter as an absolute path.
		// This detects when such a conversion happened during parsing
		// and undoes it so that the URL given to libSQL is the
		// same as given by the user.
		url = 'file:' + remoteDbURL.pathname.substring(1);
	}

	// this function parses the options from a `Record<string, string>`
	// provided from the object conversion of the searchParams and properly
	// verifies that the Config object is providing the correct types.
	// without this, there is runtime errors due to incorrect values
	function parseOpts(config: Record<string, string>): LibSQLConfig {
		return {
			... config,
			syncInterval: config.syncInterval ? parseInt(options.syncInterval) : undefined,
			readYourWrites: config.readYourWrites ? !!config.readYourWrites : undefined,
			offline: config.offline ? !!config.offline : undefined,
			tls: config.tls ? !!config.tls : undefined,
			concurrency: config.concurrency ? parseInt(options.concurrency) : undefined,
			authToken: appToken,
			url,
		}
	}

	const client = createClient(parseOpts(options));
	return drizzleLibsql(client);
}

function createStudioDatabaseClient(appToken: string, remoteDbURL: URL) {
	if (appToken == null) {
		throw new Error(`Cannot create a remote client: missing app token.`);
	}

	const url = new URL('/db/query', remoteDbURL);

	const db = drizzleProxy(
		async (sql, parameters, method) => {
			const requestBody: InStatement = { sql, args: parameters };
			const res = await safeFetch(
				url,
				{
					method: 'POST',
					headers: {
						Authorization: `Bearer ${appToken}`,
						'Content-Type': 'application/json',

Review comment (security):
Passing `?readYourWrites` would result in the flag not being passed since an empty string is a falsy value. For the boolean values I think the following would be better:

```suggestion
			syncInterval: config.syncInterval ? parseInt(options.syncInterval) : undefined,
			readYourWrites: 'readYourWrites' in config ? config.readYourWrites !== 'false' : undefined,
			offline: 'offline' in config ? config.offline !== 'false' : undefined,
			tls: 'tls' in config ? config.tls !== 'false' : undefined,
			concurrency: config.concurrency ? parseInt(options.concurrency) : undefined,
			authToken: appToken,
```

This way not passing a boolean value uses the default value, passing `?readYourWrites` enables the flag explicitly, and passing `?readYourWrites=false` disables the flag explicitly.

Code after:
	}
}

function createRemoteLibSQLClient(appToken: string, remoteDbURL: URL, rawUrl: string) {
	const options: Record<string, string> = Object.fromEntries(remoteDbURL.searchParams.entries());
	remoteDbURL.search = '';

	let url = remoteDbURL.toString();
	if (remoteDbURL.protocol === 'memory:') {
		// libSQL expects a special string in place of a URL
		// for in-memory DBs.
		url = ':memory:';
	} else if (
		remoteDbURL.protocol === 'file:' &&
		remoteDbURL.pathname.startsWith('/') &&
		!rawUrl.startsWith('file:/')
	) {
		// libSQL accepts relative and absolute file URLs
		// for local DBs. This doesn't match the URL specification.
		// Parsing `file:some.db` and `file:/some.db` should yield
		// the same result, but libSQL interprets the former as
		// a relative path, and the latter as an absolute path.
		// This detects when such a conversion happened during parsing
		// and undoes it so that the URL given to libSQL is the
		// same as given by the user.
		url = 'file:' + remoteDbURL.pathname.substring(1);
	}

	const client = createClient({ ...parseOpts(options), url, authToken: appToken, });
	return drizzleLibsql(client);
}

function createStudioDatabaseClient(appToken: string, remoteDbURL: URL) {
	if (appToken == null) {
		throw new Error(`Cannot create a remote client: missing app token.`);
	}

	const url = new URL('/db/query', remoteDbURL);

	const db = drizzleProxy(
		async (sql, parameters, method) => {
			const requestBody: InStatement = { sql, args: parameters };
			const res = await safeFetch(
				url,
				{
					method: 'POST',
					headers: {
						Authorization: `Bearer ${appToken}`,
						'Content-Type': 'application/json',
					},
					body: JSON.stringify(requestBody),