mirror of
https://github.com/binaricat/Netcatty.git
synced 2026-10-09 15:58:34 +00:00
67f8108713
* feat(plugins): add privileged terminal data pipeline * fix(plugins): harden terminal interceptor lifecycle * fix(plugins): close terminal interceptor lifecycle gaps * fix(plugins): preserve terminal interceptor state transitions * fix(plugin): close terminal pipeline lifecycle gaps * fix(plugin): harden terminal interceptor startup * fix(plugin): isolate terminal output route attempts * fix(plugin): isolate reused terminal sessions * fix(plugin): harden terminal interceptor boundaries * fix(plugin): harden terminal replay metadata * fix(plugin): preserve terminal replay provenance * fix(plugin): close terminal pipeline lifecycle races * fix(plugin): harden terminal route handoff * fix(plugin): contain terminal handoff failures * fix(plugin): route terminal attachment through RPC * fix(plugin): validate terminal attachment RPC * fix(plugin): close unexpected runtime ports * fix(plugin): canonicalize terminal data frames * fix(plugin): close terminal pipeline lifecycle gaps * fix(plugin): close terminal interceptor review gaps * fix(plugin): harden terminal interceptor protocol handling * fix(plugin): preserve terminal flow compatibility * fix(plugin): preserve terminal protocol accounting * fix(plugin): bound terminal interceptor lifecycle * fix(plugin): close terminal interceptor review gaps --------- Co-authored-by: ryan-wong-coder <wangsiyuan19990317@gmail.com>
113 lines
4.0 KiB
JavaScript
113 lines
4.0 KiB
JavaScript
"use strict";
|
|
|
|
const path = require("node:path");
|
|
|
|
const Ajv2020 = require("ajv/dist/2020").default;
|
|
const addFormats = require("ajv-formats").default;
|
|
const schema = require("./generated/plugin-contract.schema.json");
|
|
const { assertPluginJsonValue } = require("./jsonBoundary.cjs");
|
|
const {
|
|
PLUGIN_RPC_MAX_JSON_BYTES,
|
|
PLUGIN_STREAM_MAX_FRAME_JSON_BYTES,
|
|
} = require("./constants.cjs");
|
|
|
|
function createDefinitionValidator(definitionName) {
|
|
if (!schema.$defs?.[definitionName]) throw new Error(`Unknown plugin contract definition: ${definitionName}`);
|
|
const ajv = new Ajv2020({ allErrors: true, strict: false, validateFormats: true });
|
|
addFormats(ajv);
|
|
ajv.addSchema(schema);
|
|
return ajv.compile({ $ref: `${schema.$id}#/$defs/${definitionName}` });
|
|
}
|
|
|
|
function formatValidationErrors(errors) {
|
|
return (errors ?? [])
|
|
.slice(0, 8)
|
|
.map((error) => `${error.instancePath || "/"} ${error.message ?? "is invalid"}`)
|
|
.join("; ");
|
|
}
|
|
|
|
const rpcMessageValidator = createDefinitionValidator("RpcMessage");
|
|
const initializeResultValidator = createDefinitionValidator("RuntimeInitializeResult");
|
|
const terminalInterceptorAttachmentParamsValidator = createDefinitionValidator("TerminalInterceptorAttachmentParams");
|
|
const terminalInterceptorAttachmentResultValidator = createDefinitionValidator("TerminalInterceptorAttachmentResult");
|
|
const terminalInterceptorFrameValidator = createDefinitionValidator("TerminalInterceptorFrame");
|
|
const providerRequestValidator = createDefinitionValidator("ProviderRequest");
|
|
const providerResultValidator = createDefinitionValidator("ProviderResult");
|
|
const streamFrameValidator = createDefinitionValidator("StreamFrame");
|
|
|
|
function assertContractValue(validator, value, label) {
|
|
if (!validator(value)) {
|
|
throw new TypeError(`${label} violates the plugin contract: ${formatValidationErrors(validator.errors)}`);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
function assertRpcMessage(value) {
|
|
assertPluginJsonValue(value, { maxBytes: PLUGIN_RPC_MAX_JSON_BYTES });
|
|
return assertContractValue(rpcMessageValidator, value, "RPC message");
|
|
}
|
|
|
|
function assertInitializeResult(value) {
|
|
assertPluginJsonValue(value, { maxBytes: PLUGIN_RPC_MAX_JSON_BYTES });
|
|
return assertContractValue(initializeResultValidator, value, "Initialize result");
|
|
}
|
|
|
|
function assertTerminalInterceptorAttachmentParams(value) {
|
|
assertPluginJsonValue(value, { maxBytes: PLUGIN_RPC_MAX_JSON_BYTES });
|
|
return assertContractValue(
|
|
terminalInterceptorAttachmentParamsValidator,
|
|
value,
|
|
"Terminal interceptor attachment params",
|
|
);
|
|
}
|
|
|
|
function assertTerminalInterceptorAttachmentResult(value) {
|
|
assertPluginJsonValue(value, { maxBytes: PLUGIN_RPC_MAX_JSON_BYTES });
|
|
return assertContractValue(
|
|
terminalInterceptorAttachmentResultValidator,
|
|
value,
|
|
"Terminal interceptor attachment result",
|
|
);
|
|
}
|
|
|
|
function assertTerminalInterceptorFrameSchema(value) {
|
|
return assertContractValue(
|
|
terminalInterceptorFrameValidator,
|
|
value,
|
|
"Terminal interceptor frame",
|
|
);
|
|
}
|
|
|
|
function assertProviderRequest(value) {
|
|
assertPluginJsonValue(value, { maxBytes: PLUGIN_RPC_MAX_JSON_BYTES });
|
|
return assertContractValue(providerRequestValidator, value, "Provider request");
|
|
}
|
|
|
|
function assertProviderResult(value) {
|
|
assertPluginJsonValue(value, { maxBytes: PLUGIN_RPC_MAX_JSON_BYTES });
|
|
return assertContractValue(providerResultValidator, value, "Provider result");
|
|
}
|
|
|
|
function assertStreamFrameSchema(value) {
|
|
assertPluginJsonValue(value, { maxBytes: PLUGIN_STREAM_MAX_FRAME_JSON_BYTES });
|
|
return assertContractValue(streamFrameValidator, value, "Stream frame");
|
|
}
|
|
|
|
function resolveContractRuntimePath(...segments) {
|
|
return path.join(__dirname, "..", "..", "node_modules", "@netcatty", "plugin-contract", "dist", ...segments);
|
|
}
|
|
|
|
module.exports = {
|
|
assertInitializeResult,
|
|
assertTerminalInterceptorAttachmentParams,
|
|
assertTerminalInterceptorAttachmentResult,
|
|
assertTerminalInterceptorFrameSchema,
|
|
assertProviderRequest,
|
|
assertProviderResult,
|
|
assertRpcMessage,
|
|
assertStreamFrameSchema,
|
|
createDefinitionValidator,
|
|
formatValidationErrors,
|
|
resolveContractRuntimePath,
|
|
};
|