fix(qbzd): remove token requirement from remote API client

LAN-only mode means no token auth. The empty string token ('') was
failing the truthy check in requireRemote(), causing 'Not in remote
mode' error on every command after connecting.

Now: token header only sent when token is non-empty. requireRemote
only checks type === 'qbzd' and baseUrl presence.

This was THE bug preventing QBZ Desktop from controlling the daemon.

cc
This commit is contained in:
vicrodh committed 2026-04-09 13:11:26 -06:00
1 parent 6cf396aa8a
commit 72254ac44e
1 file changed
+19 -16
+19 -16
View File
@@ -19,22 +19,21 @@ export class RemoteApiError extends Error {
}
}
function requireRemote(): PlaybackTarget & { type: 'qbzd'; baseUrl: string; token: string } {
function requireRemote(): PlaybackTarget & { type: 'qbzd'; baseUrl: string } {
const target = getTarget();
if (target.type !== 'qbzd' || !target.baseUrl || !target.token) {
if (target.type !== 'qbzd' || !target.baseUrl) {
throw new Error('Not in remote mode');
}
return target as PlaybackTarget & { type: 'qbzd'; baseUrl: string; token: string };
return target as PlaybackTarget & { type: 'qbzd'; baseUrl: string };
}
/** Make a GET request to the remote daemon */
export async function remoteGet<T = unknown>(path: string): Promise<T> {
const target = requireRemote();
const response = await fetch(`${target.baseUrl}${path}`, {
headers: {
'X-API-Key': target.token,
},
});
const headers: Record<string, string> = {};
if (target.token) headers['X-API-Key'] = target.token;
const response = await fetch(`${target.baseUrl}${path}`, { headers });
if (!response.ok) {
const body = await response.text().catch(() => '');
throw new RemoteApiError(response.status, 'request_failed', body || response.statusText);
@@ -45,12 +44,12 @@ export async function remoteGet<T = unknown>(path: string): Promise<T> {
/** Make a POST request to the remote daemon */
export async function remotePost<T = unknown>(path: string, body?: unknown): Promise<T> {
const target = requireRemote();
const headers: Record<string, string> = { 'Content-Type': 'application/json' };
if (target.token) headers['X-API-Key'] = target.token;
const response = await fetch(`${target.baseUrl}${path}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': target.token,
},
headers,
body: body ? JSON.stringify(body) : undefined,
});
if (!response.ok) {
@@ -67,10 +66,12 @@ export async function remotePost<T = unknown>(path: string, body?: unknown): Pro
}
/** Check if a remote daemon is reachable */
export async function pingRemote(baseUrl: string, token: string): Promise<boolean> {
export async function pingRemote(baseUrl: string, token?: string): Promise<boolean> {
try {
const headers: Record<string, string> = {};
if (token) headers['X-API-Key'] = token;
const response = await fetch(`${baseUrl}/api/ping`, {
headers: { 'X-API-Key': token },
headers,
signal: AbortSignal.timeout(5000),
});
return response.ok;
@@ -82,10 +83,12 @@ export async function pingRemote(baseUrl: string, token: string): Promise<boolea
/** Get daemon info (name, version, capabilities) */
export async function getRemoteInfo(
baseUrl: string,
token: string,
token?: string,
): Promise<{ name: string; version: string; cache: Record<string, number> }> {
const headers: Record<string, string> = {};
if (token) headers['X-API-Key'] = token;
const response = await fetch(`${baseUrl}/api/info`, {
headers: { 'X-API-Key': token },
headers,
signal: AbortSignal.timeout(5000),
});
if (!response.ok) throw new Error('Failed to get daemon info');