Initial import: live state on api.qbirr.com (server v0.6.3)
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* HMAC-signed POSTs to the plugin's /wp-json/wp-ide/v1/tool-exec
|
||||
* endpoint. The plugin issued the secret when it called POST /v1/runs;
|
||||
* we use it to sign every tool callback so the plugin can verify the
|
||||
* caller is us.
|
||||
*/
|
||||
|
||||
import { createHmac } from 'node:crypto';
|
||||
import { logger } from '../lib/logger.js';
|
||||
|
||||
export interface ToolExecRequest {
|
||||
call_id: string;
|
||||
name: string;
|
||||
arguments: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface ToolExecResponse {
|
||||
ok: boolean;
|
||||
call_id: string;
|
||||
result?: unknown;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export async function runToolOnSite(
|
||||
callbackUrl: string,
|
||||
runId: string,
|
||||
secret: string,
|
||||
payload: ToolExecRequest,
|
||||
timeoutMs = 60_000,
|
||||
): Promise<ToolExecResponse> {
|
||||
const body = JSON.stringify(payload);
|
||||
const signature = createHmac('sha256', secret).update(body).digest('hex');
|
||||
const url = callbackUrl;
|
||||
|
||||
const controller = new AbortController();
|
||||
const t = setTimeout(() => controller.abort(), timeoutMs);
|
||||
const started = Date.now();
|
||||
try {
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
'accept': 'application/json',
|
||||
'accept-encoding': 'identity',
|
||||
'user-agent': 'wpide-server/0.2',
|
||||
'x-wpide-run-id': runId,
|
||||
'x-wpide-signature': signature,
|
||||
},
|
||||
body,
|
||||
signal: controller.signal,
|
||||
});
|
||||
const ms = Date.now() - started;
|
||||
const text = await res.text();
|
||||
let parsed: ToolExecResponse;
|
||||
try {
|
||||
parsed = JSON.parse(text) as ToolExecResponse;
|
||||
} catch {
|
||||
const respHeaders: Record<string, string> = {};
|
||||
for (const [k, v] of res.headers.entries()) respHeaders[k] = v;
|
||||
logger.error({
|
||||
url,
|
||||
status: res.status,
|
||||
ms,
|
||||
bodyLength: text.length,
|
||||
body: text.slice(0, 500),
|
||||
headers: respHeaders,
|
||||
}, 'tool-exec: non-JSON response');
|
||||
return { ok: false, call_id: payload.call_id, error: `tool-exec non-JSON (HTTP ${res.status})` };
|
||||
}
|
||||
if (!res.ok) {
|
||||
logger.warn({ status: res.status, ms, error: parsed.error }, 'tool-exec returned error status');
|
||||
}
|
||||
return parsed;
|
||||
} catch (err) {
|
||||
return { ok: false, call_id: payload.call_id, error: `tool-exec fetch failed: ${(err as Error).message}` };
|
||||
} finally {
|
||||
clearTimeout(t);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user