128 lines
3.6 KiB
JavaScript
128 lines
3.6 KiB
JavaScript
export const ENVIRONMENT_DEV = "dev";
|
|
export const DEV_ENDPOINT = "http://74.48.78.17:6667";
|
|
export const JSON_RPC_VERSION = "2.0";
|
|
|
|
export const SERVICE_IDS = Object.freeze([
|
|
"hwlab-cloud-api",
|
|
"hwlab-cloud-web",
|
|
"hwlab-agent-mgr",
|
|
"hwlab-agent-worker",
|
|
"hwlab-gateway",
|
|
"hwlab-gateway-simu",
|
|
"hwlab-box-simu",
|
|
"hwlab-patch-panel",
|
|
"hwlab-router",
|
|
"hwlab-tunnel-client",
|
|
"hwlab-edge-proxy",
|
|
"hwlab-cli",
|
|
"hwlab-agent-skills"
|
|
]);
|
|
|
|
export const TABLES = Object.freeze([
|
|
"projects",
|
|
"gateway_sessions",
|
|
"box_resources",
|
|
"box_capabilities",
|
|
"wiring_configs",
|
|
"patch_panel_status",
|
|
"hardware_operations",
|
|
"audit_events",
|
|
"agent_sessions",
|
|
"worker_sessions",
|
|
"agent_trace_events",
|
|
"evidence_records"
|
|
]);
|
|
|
|
export const ERROR_CODES = Object.freeze({
|
|
parseError: -32700,
|
|
invalidRequest: -32600,
|
|
methodNotFound: -32601,
|
|
invalidParams: -32602,
|
|
internalError: -32603,
|
|
hwlabUnknown: -32000,
|
|
projectNotFound: -32010,
|
|
sessionNotFound: -32011,
|
|
capabilityUnavailable: -32020,
|
|
resourceLocked: -32021,
|
|
wiringInvalid: -32022,
|
|
operationRejected: -32023,
|
|
evidenceMissing: -32030,
|
|
auditRequired: -32040
|
|
});
|
|
|
|
const methodPattern = /^[a-z][a-z0-9]*(\.[a-z][a-z0-9_]*)+$/;
|
|
|
|
export function isFrozenServiceId(serviceId) {
|
|
return SERVICE_IDS.includes(serviceId);
|
|
}
|
|
|
|
export function validateMeta(meta) {
|
|
if (!meta || typeof meta !== "object" || Array.isArray(meta)) {
|
|
throw new Error("meta must be an object");
|
|
}
|
|
if (!meta.traceId) {
|
|
throw new Error("meta.traceId is required");
|
|
}
|
|
if (!isFrozenServiceId(meta.serviceId)) {
|
|
throw new Error(`unknown serviceId ${JSON.stringify(meta.serviceId)}`);
|
|
}
|
|
if (meta.environment !== ENVIRONMENT_DEV) {
|
|
throw new Error(`unsupported environment ${JSON.stringify(meta.environment)}`);
|
|
}
|
|
}
|
|
|
|
export function validateRequest(envelope) {
|
|
if (!envelope || typeof envelope !== "object" || Array.isArray(envelope)) {
|
|
throw new Error("request must be an object");
|
|
}
|
|
if (envelope.jsonrpc !== JSON_RPC_VERSION) {
|
|
throw new Error(`jsonrpc must be ${JSON_RPC_VERSION}`);
|
|
}
|
|
if (envelope.id === undefined || envelope.id === null) {
|
|
throw new Error("id is required");
|
|
}
|
|
if (!methodPattern.test(envelope.method)) {
|
|
throw new Error(`invalid method ${JSON.stringify(envelope.method)}`);
|
|
}
|
|
if (
|
|
envelope.params !== undefined &&
|
|
(!envelope.params || typeof envelope.params !== "object" || Array.isArray(envelope.params))
|
|
) {
|
|
throw new Error("params must be an object when present");
|
|
}
|
|
validateMeta(envelope.meta);
|
|
}
|
|
|
|
export function validateResponse(envelope) {
|
|
if (!envelope || typeof envelope !== "object" || Array.isArray(envelope)) {
|
|
throw new Error("response must be an object");
|
|
}
|
|
if (envelope.jsonrpc !== JSON_RPC_VERSION) {
|
|
throw new Error(`jsonrpc must be ${JSON_RPC_VERSION}`);
|
|
}
|
|
if (envelope.id === undefined || envelope.id === null) {
|
|
throw new Error("id is required");
|
|
}
|
|
const hasResult = Object.hasOwn(envelope, "result");
|
|
const hasError = Object.hasOwn(envelope, "error");
|
|
if (hasResult === hasError) {
|
|
throw new Error("response must contain exactly one of result or error");
|
|
}
|
|
if (hasError) {
|
|
validateRpcError(envelope.error);
|
|
}
|
|
validateMeta(envelope.meta);
|
|
}
|
|
|
|
export function validateRpcError(error) {
|
|
if (!error || typeof error !== "object" || Array.isArray(error)) {
|
|
throw new Error("error must be an object");
|
|
}
|
|
if (!Number.isInteger(error.code)) {
|
|
throw new Error("error.code must be an integer");
|
|
}
|
|
if (!error.message || typeof error.message !== "string") {
|
|
throw new Error("error.message is required");
|
|
}
|
|
}
|