71 lines
2.2 KiB
TypeScript
71 lines
2.2 KiB
TypeScript
import type { BinarySessionPort } from "../application/BinarySession.js";
|
|
import {
|
|
EvidenceIntegrityError,
|
|
EvidenceReferenceError,
|
|
type EvidenceLimitError,
|
|
} from "../domain/errors.js";
|
|
import type { Evidence } from "../domain/evidence.js";
|
|
import { err, ok, type Result } from "../domain/result.js";
|
|
|
|
type EvidenceAuthorityResult = Result<Evidence[], EvidenceIntegrityError>;
|
|
|
|
/** Resolve bounded IDs to authoritative records with exact semantic identity. */
|
|
export const resolveSessionEvidenceIds = (
|
|
session: BinarySessionPort,
|
|
evidenceIds: readonly string[],
|
|
expected: {
|
|
readonly operation: string | readonly string[];
|
|
readonly predicate: string;
|
|
},
|
|
): EvidenceAuthorityResult => {
|
|
const records: Evidence[] = [];
|
|
const expectedOperations = Array.isArray(expected.operation)
|
|
? expected.operation
|
|
: [expected.operation];
|
|
const expectedOperationLabel = expectedOperations.join(" or ");
|
|
for (const evidenceId of evidenceIds) {
|
|
const record = session.evidenceById(evidenceId);
|
|
if (record === undefined)
|
|
return err(
|
|
new EvidenceReferenceError(
|
|
evidenceId,
|
|
"missing",
|
|
expectedOperationLabel,
|
|
null,
|
|
),
|
|
);
|
|
if (!expectedOperations.includes(record.operation))
|
|
return err(
|
|
new EvidenceReferenceError(
|
|
evidenceId,
|
|
"wrong_operation",
|
|
expectedOperationLabel,
|
|
record.operation,
|
|
),
|
|
);
|
|
if (record.predicate_type !== expected.predicate)
|
|
return err(
|
|
new EvidenceReferenceError(
|
|
evidenceId,
|
|
"wrong_predicate",
|
|
expected.predicate,
|
|
record.predicate_type,
|
|
),
|
|
);
|
|
records.push(record);
|
|
}
|
|
return ok(records);
|
|
};
|
|
|
|
/** Record source evidence in order, stopping at the first session rejection. */
|
|
export const recordSessionEvidenceSources = (
|
|
recordEvidence: BinarySessionPort["recordEvidence"] | undefined,
|
|
sources: readonly Evidence[],
|
|
): Result<null, EvidenceIntegrityError | EvidenceLimitError> => {
|
|
for (const source of sources) {
|
|
const recorded = recordEvidence?.(source);
|
|
if (recorded !== undefined && !recorded.ok) return recorded;
|
|
}
|
|
return ok(null);
|
|
};
|