@kya-os/mcp-i
Version:
The TypeScript MCP framework with identity features built-in
175 lines (174 loc) • 6.2 kB
TypeScript
/**
* Proof Batch Queue
*
* Collects proofs in memory and submits them in batches to KTA and AgentShield.
* This prevents blocking tool execution while ensuring proofs are eventually submitted.
*
* Performance:
* - Batch size: 10 proofs (configurable)
* - Flush interval: 5 seconds (configurable)
* - Fire-and-forget submission (doesn't block tool execution)
*
* Retry Strategy:
* - Exponential backoff: 1s, 2s, 4s, 8s, 16s
* - Max retries: 5
* - Failed proofs logged and dropped after max retries
*
* Related: PHASE_1_XMCP_I_SERVER.md Epic 3 (Proof Batching)
*/
import type { DetachedProof } from "@kya-os/mcp/types" with { "resolution-mode": "import" };
/**
* A proof plus the tool-call context KTA's submission API requires
* alongside it. DetachedProof (proof.meta) carries did/kid/ts/nonce/
* audience/etc, but not which tool was called or how it turned out —
* that context only exists at the call site, so it has to be threaded
* through explicitly rather than derived from the proof.
*/
export interface ProofSubmission {
proof: DetachedProof;
toolName: string;
outcome: "success" | "failure" | "denied";
}
/**
* Proof submission destination
*/
export interface ProofDestination {
/** Destination name (for logging) */
name: string;
/** Submit a batch of proof submissions */
submit(submissions: ProofSubmission[]): Promise<void>;
}
/**
* Thrown by a ProofDestination whose submit() made independent per-item
* requests (rather than one atomic request for the whole array) when only
* some of them failed. Callers that retry on failure MUST retry only
* `failed`, not the original full array — retrying everything would
* resubmit proofs the destination already accepted.
*/
export declare class PartialProofSubmissionError extends Error {
readonly failed: ProofSubmission[];
readonly succeededCount: number;
/** The per-item rejection reason for each entry in `failed`, same order. */
readonly causes?: unknown[] | undefined;
constructor(message: string, failed: ProofSubmission[], succeededCount: number,
/** The per-item rejection reason for each entry in `failed`, same order. */
causes?: unknown[] | undefined);
}
/**
* KTA proof submission destination
*
* The live KTA API (POST /api/v1/proofs) accepts exactly one proof per
* request — there is no /batch endpoint — so a "batch" here means firing
* one request per submission, not one request for the whole array. Since
* each request is independent, submit() reports PARTIAL failure via
* PartialProofSubmissionError rather than treating the whole array as
* atomic — a caller that blindly retried everything on any rejection
* would resubmit proofs that already succeeded.
*/
export declare class KTAProofDestination implements ProofDestination {
name: string;
private apiUrl;
private apiKey?;
constructor(apiUrl: string, apiKey?: string);
submit(submissions: ProofSubmission[]): Promise<void>;
private submitOne;
}
/**
* AgentShield proof submission destination
*
* Submits proofs to AgentShield's /api/v1/bouncer/proofs endpoint
* with proper authentication and session grouping.
*/
export declare class AgentShieldProofDestination implements ProofDestination {
name: string;
private apiUrl;
private apiKey;
constructor(apiUrl: string, apiKey: string);
submit(submissions: ProofSubmission[]): Promise<void>;
}
/**
* Proof batch queue configuration
*/
export interface ProofBatchQueueConfig {
/** Destinations to submit proofs to */
destinations: ProofDestination[];
/** Maximum batch size (default: 10) */
maxBatchSize?: number;
/** Flush interval in milliseconds (default: 5000 = 5 seconds) */
flushIntervalMs?: number;
/** Maximum retries per batch (default: 5) */
maxRetries?: number;
/** Enable debug logging */
debug?: boolean;
}
/**
* Proof Batch Queue
*
* Collects proofs and submits them in batches to multiple destinations
*/
export declare class ProofBatchQueue {
private queue;
private pendingBatches;
private config;
private flushTimer?;
private retryTimer?;
private closed;
private stats;
constructor(config: ProofBatchQueueConfig);
/**
* Add a proof submission to the queue.
*
* Accepts a bare DetachedProof for backward compatibility with the
* pre-#650 API: a plain-JS (or un-upgraded TS) consumer built against
* the old `enqueue(proof: DetachedProof)` signature would otherwise have
* `toolName`/`outcome` silently come through as `undefined`.
*/
enqueue(item: ProofSubmission | DetachedProof): void;
/**
* Normalize a bare DetachedProof (the pre-#650 enqueue() shape) into a
* ProofSubmission. Derives toolName/outcome from the proof's own signed
* meta when present, rather than a hardcoded literal -- a destination's
* server-side check compares the submitted toolName/outcome against what
* was actually signed into the JWS payload, so a literal that disagrees
* with the real signed value is guaranteed to fail verification. When the
* proof was never signed with these fields at all (a genuinely pre-#651
* proof), no fallback can make the submission succeed, so this warns
* rather than silently queueing a doomed submission.
*/
private submissionFromBareProof;
/**
* Flush queue immediately (submit all queued proofs)
*/
flush(): Promise<void>;
/**
* Submit batch to destination (with retries)
*/
private submitBatch;
/**
* Start flush timer
*/
private startFlushTimer;
/**
* Start retry timer
*/
private startRetryTimer;
/**
* Close queue and flush remaining proofs
*/
close(): Promise<void>;
/**
* Get queue statistics
*/
getStats(): {
queueSize: number;
pendingBatches: number;
queued: number;
submitted: number;
failed: number;
batchesSubmitted: number;
};
}
/**
* Create proof batch queue from config
*/
export declare function createProofBatchQueue(config: ProofBatchQueueConfig): ProofBatchQueue;