62 lines
2.7 KiB
TypeScript
62 lines
2.7 KiB
TypeScript
/*
|
|
* SPEC: PJ2026-010103 HWPOD 服务。
|
|
* 实现引用: draft-2026-07-20-hwpod-temporal-split。
|
|
* 责任: 独立 HWPOD API、worker 和 Web 共用的稳定输入输出合同。
|
|
*/
|
|
|
|
export type HwpodOperationInput = {
|
|
operationId: string;
|
|
plan: Record<string, unknown>;
|
|
runtimeApiUrl: string;
|
|
authorization?: string;
|
|
};
|
|
|
|
export type HwpodOperationResult = {
|
|
ok: boolean;
|
|
status: string;
|
|
operationId: string;
|
|
workflowId: string;
|
|
workflowRunId: string | null;
|
|
result?: Record<string, unknown> | null;
|
|
error?: { code: string; message: string } | null;
|
|
};
|
|
|
|
export const HWPOD_WEB_OPERATION_INTENTS = new Set([
|
|
"workspace.ls",
|
|
"workspace.cat",
|
|
"debug.build",
|
|
"debug.download",
|
|
"debug.reset",
|
|
"io.uart.open",
|
|
"io.uart.close",
|
|
"io.uart.read",
|
|
"io.uart.write",
|
|
]);
|
|
|
|
export function validateHwpodOperationInput(value: unknown): HwpodOperationInput {
|
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw codedError("hwpod_operation_input_invalid", "HWPOD operation input must be an object");
|
|
const input = value as Record<string, unknown>;
|
|
const operationId = text(input.operationId);
|
|
const runtimeApiUrl = text(input.runtimeApiUrl);
|
|
const plan = input.plan;
|
|
if (!operationId) throw codedError("hwpod_operation_id_required", "operationId is required");
|
|
if (!runtimeApiUrl) throw codedError("hwpod_runtime_api_url_required", "runtimeApiUrl is required");
|
|
if (!plan || typeof plan !== "object" || Array.isArray(plan)) throw codedError("hwpod_operation_plan_required", "plan must be an object");
|
|
return { operationId, runtimeApiUrl: runtimeApiUrl.replace(/\/+$/u, ""), plan: plan as Record<string, unknown>, authorization: text(input.authorization) || undefined };
|
|
}
|
|
|
|
export function validateHwpodWebOperationRequest(value: unknown) {
|
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw codedError("hwpod_operation_request_invalid", "HWPOD operation request must be an object");
|
|
const input = value as Record<string, unknown>;
|
|
const hwpodId = text(input.hwpodId);
|
|
const intent = text(input.intent);
|
|
if (!hwpodId) throw codedError("hwpod_id_required", "hwpodId is required");
|
|
if (!HWPOD_WEB_OPERATION_INTENTS.has(intent)) throw codedError("hwpod_operation_intent_unsupported", `unsupported HWPOD Web operation intent: ${intent}`);
|
|
const args = input.args === undefined ? {} : input.args;
|
|
if (!args || typeof args !== "object" || Array.isArray(args)) throw codedError("hwpod_operation_args_invalid", "HWPOD operation args must be an object");
|
|
return { hwpodId, intent, args: args as Record<string, unknown> };
|
|
}
|
|
|
|
function text(value: unknown) { return typeof value === "string" ? value.trim() : ""; }
|
|
function codedError(code: string, message: string) { return Object.assign(new Error(message), { code }); }
|