Retain unresolved process identity and launch evidence through retryable cleanup. Share capture path normalization and preserve failed filesystem observations. Bound child output and drain Windows pipes without one-chunk throttling. Reviewed fixes include #1628, #2632, #2644, #2784, #2928, #2931, #2965, #2992, and #3011. Validation: 92 focused source tests passed; four platform-specific skips. Real Windows and Hopper lifecycle coverage was not rerun.
57 lines
2.0 KiB
TypeScript
57 lines
2.0 KiB
TypeScript
import { HopperProtocolError } from "../domain/hopperErrors.js";
|
|
import type { JsonValue } from "../domain/jsonValue.js";
|
|
import { err, ok, type Result } from "../domain/result.js";
|
|
|
|
/** Bound cleanup handshakes and the bridge's idle reconnection wait. */
|
|
export const HOPPER_SHUTDOWN_TIMEOUT_MS = 30_000;
|
|
|
|
/** Authenticated identity returned by the Hopper bridge health handshake. */
|
|
export interface HopperServerInfo {
|
|
readonly name: string;
|
|
readonly version: string;
|
|
readonly processId: number;
|
|
}
|
|
|
|
/** Validate the bridge identity and exact per-launch run identifier. */
|
|
export const parseHopperServerInfo = (
|
|
value: JsonValue,
|
|
expectedRunId: string,
|
|
): Result<HopperServerInfo, HopperProtocolError> => {
|
|
if (
|
|
typeof value === "object" &&
|
|
value !== null &&
|
|
!Array.isArray(value) &&
|
|
value.name === "REA Hopper bridge" &&
|
|
typeof value.version === "string" &&
|
|
typeof value.process_id === "number" &&
|
|
Number.isSafeInteger(value.process_id) &&
|
|
value.process_id > 0 &&
|
|
value.run_id === expectedRunId
|
|
)
|
|
return ok({
|
|
name: value.name,
|
|
version: value.version,
|
|
processId: value.process_id,
|
|
});
|
|
return err(new HopperProtocolError("Hopper bridge health result is invalid"));
|
|
};
|
|
|
|
/** Require confirmation that the REA bridge detached or its document closed. */
|
|
export const isHopperShutdownAcknowledgement = (value: JsonValue): boolean => {
|
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
return false;
|
|
if (value.shutdown !== true) return false;
|
|
return (
|
|
(value.analysis_stopped === true && value.document_closed === true) ||
|
|
(value.document_closed === false && value.document_retained === true)
|
|
);
|
|
};
|
|
|
|
/** Detect the verified Linux bridge response that requires group cleanup. */
|
|
export const isHopperCleanupRequired = (value: JsonValue): boolean =>
|
|
typeof value === "object" &&
|
|
value !== null &&
|
|
!Array.isArray(value) &&
|
|
value.shutdown === true &&
|
|
value.cleanup_required === true;
|