@kya-os/mcp-i 1.4.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,257 @@
1
+ "use strict";
2
+ /**
3
+ * Proof Batch Queue
4
+ *
5
+ * Collects proofs in memory and submits them in batches to KTA and AgentShield.
6
+ * This prevents blocking tool execution while ensuring proofs are eventually submitted.
7
+ *
8
+ * Performance:
9
+ * - Batch size: 10 proofs (configurable)
10
+ * - Flush interval: 5 seconds (configurable)
11
+ * - Fire-and-forget submission (doesn't block tool execution)
12
+ *
13
+ * Retry Strategy:
14
+ * - Exponential backoff: 1s, 2s, 4s, 8s, 16s
15
+ * - Max retries: 5
16
+ * - Failed proofs logged and dropped after max retries
17
+ *
18
+ * Related: PHASE_1_XMCP_I_SERVER.md Epic 3 (Proof Batching)
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.ProofBatchQueue = exports.AgentShieldProofDestination = exports.KTAProofDestination = void 0;
22
+ exports.createProofBatchQueue = createProofBatchQueue;
23
+ /**
24
+ * KTA proof submission destination
25
+ */
26
+ class KTAProofDestination {
27
+ name = 'KTA';
28
+ apiUrl;
29
+ apiKey;
30
+ constructor(apiUrl, apiKey) {
31
+ this.apiUrl = apiUrl.replace(/\/$/, '');
32
+ this.apiKey = apiKey;
33
+ }
34
+ async submit(proofs) {
35
+ const headers = {
36
+ 'Content-Type': 'application/json',
37
+ };
38
+ if (this.apiKey) {
39
+ headers['X-API-Key'] = this.apiKey;
40
+ }
41
+ const response = await fetch(`${this.apiUrl}/api/v1/proofs/batch`, {
42
+ method: 'POST',
43
+ headers,
44
+ body: JSON.stringify({ proofs }),
45
+ });
46
+ if (!response.ok) {
47
+ throw new Error(`KTA proof submission failed: ${response.status} ${response.statusText}`);
48
+ }
49
+ }
50
+ }
51
+ exports.KTAProofDestination = KTAProofDestination;
52
+ /**
53
+ * AgentShield proof submission destination
54
+ */
55
+ class AgentShieldProofDestination {
56
+ name = 'AgentShield';
57
+ apiUrl;
58
+ apiKey;
59
+ constructor(apiUrl, apiKey) {
60
+ this.apiUrl = apiUrl.replace(/\/$/, '');
61
+ this.apiKey = apiKey;
62
+ }
63
+ async submit(proofs) {
64
+ const response = await fetch(`${this.apiUrl}/api/v1/proofs/batch`, {
65
+ method: 'POST',
66
+ headers: {
67
+ 'Content-Type': 'application/json',
68
+ 'X-API-Key': this.apiKey,
69
+ },
70
+ body: JSON.stringify({ proofs }),
71
+ });
72
+ if (!response.ok) {
73
+ throw new Error(`AgentShield proof submission failed: ${response.status} ${response.statusText}`);
74
+ }
75
+ }
76
+ }
77
+ exports.AgentShieldProofDestination = AgentShieldProofDestination;
78
+ /**
79
+ * Proof Batch Queue
80
+ *
81
+ * Collects proofs and submits them in batches to multiple destinations
82
+ */
83
+ class ProofBatchQueue {
84
+ queue = [];
85
+ pendingBatches = [];
86
+ config;
87
+ flushTimer;
88
+ retryTimer;
89
+ closed = false;
90
+ // Stats
91
+ stats = {
92
+ queued: 0,
93
+ submitted: 0,
94
+ failed: 0,
95
+ batchesSubmitted: 0,
96
+ };
97
+ constructor(config) {
98
+ this.config = {
99
+ destinations: config.destinations,
100
+ maxBatchSize: config.maxBatchSize || 10,
101
+ flushIntervalMs: config.flushIntervalMs || 5000,
102
+ maxRetries: config.maxRetries || 5,
103
+ debug: config.debug || false,
104
+ };
105
+ // Start flush timer
106
+ this.startFlushTimer();
107
+ // Start retry timer (check every second)
108
+ this.startRetryTimer();
109
+ }
110
+ /**
111
+ * Add proof to queue
112
+ */
113
+ enqueue(proof) {
114
+ if (this.closed) {
115
+ console.warn('[ProofBatchQueue] Queue is closed, dropping proof');
116
+ return;
117
+ }
118
+ this.queue.push(proof);
119
+ this.stats.queued++;
120
+ if (this.config.debug) {
121
+ console.log(`[ProofBatchQueue] Enqueued proof (queue size: ${this.queue.length})`);
122
+ }
123
+ // Flush immediately if batch size reached
124
+ if (this.queue.length >= this.config.maxBatchSize) {
125
+ this.flush();
126
+ }
127
+ }
128
+ /**
129
+ * Flush queue immediately (submit all queued proofs)
130
+ */
131
+ async flush() {
132
+ if (this.queue.length === 0) {
133
+ return;
134
+ }
135
+ const proofs = this.queue.splice(0, this.config.maxBatchSize);
136
+ if (this.config.debug) {
137
+ console.log(`[ProofBatchQueue] Flushing ${proofs.length} proofs to ${this.config.destinations.length} destinations`);
138
+ }
139
+ // Submit to each destination (fire-and-forget)
140
+ for (const destination of this.config.destinations) {
141
+ const batch = {
142
+ proofs,
143
+ destination,
144
+ retryCount: 0,
145
+ };
146
+ this.submitBatch(batch); // Fire-and-forget
147
+ }
148
+ }
149
+ /**
150
+ * Submit batch to destination (with retries)
151
+ */
152
+ async submitBatch(batch) {
153
+ try {
154
+ await batch.destination.submit(batch.proofs);
155
+ this.stats.submitted += batch.proofs.length;
156
+ this.stats.batchesSubmitted++;
157
+ if (this.config.debug) {
158
+ console.log(`[ProofBatchQueue] Successfully submitted ${batch.proofs.length} proofs to ${batch.destination.name}`);
159
+ }
160
+ }
161
+ catch (error) {
162
+ console.error(`[ProofBatchQueue] Failed to submit to ${batch.destination.name}:`, error);
163
+ // Retry with exponential backoff
164
+ if (batch.retryCount < this.config.maxRetries) {
165
+ batch.retryCount++;
166
+ const backoffMs = Math.min(1000 * Math.pow(2, batch.retryCount - 1), 16000);
167
+ batch.nextRetryAt = Date.now() + backoffMs;
168
+ this.pendingBatches.push(batch);
169
+ if (this.config.debug) {
170
+ console.log(`[ProofBatchQueue] Scheduling retry ${batch.retryCount}/${this.config.maxRetries} in ${backoffMs}ms`);
171
+ }
172
+ }
173
+ else {
174
+ // Max retries exceeded, drop batch
175
+ this.stats.failed += batch.proofs.length;
176
+ console.error(`[ProofBatchQueue] Max retries exceeded for ${batch.destination.name}, dropping ${batch.proofs.length} proofs`);
177
+ }
178
+ }
179
+ }
180
+ /**
181
+ * Start flush timer
182
+ */
183
+ startFlushTimer() {
184
+ this.flushTimer = setInterval(() => {
185
+ if (this.queue.length > 0) {
186
+ this.flush();
187
+ }
188
+ }, this.config.flushIntervalMs);
189
+ // Prevent timer from keeping process alive
190
+ if (typeof this.flushTimer.unref === 'function') {
191
+ this.flushTimer.unref();
192
+ }
193
+ }
194
+ /**
195
+ * Start retry timer
196
+ */
197
+ startRetryTimer() {
198
+ this.retryTimer = setInterval(() => {
199
+ const now = Date.now();
200
+ // Find batches ready for retry
201
+ const retryBatches = this.pendingBatches.filter((batch) => batch.nextRetryAt && batch.nextRetryAt <= now);
202
+ if (retryBatches.length > 0) {
203
+ // Remove from pending
204
+ this.pendingBatches = this.pendingBatches.filter((batch) => !retryBatches.includes(batch));
205
+ // Retry each batch
206
+ for (const batch of retryBatches) {
207
+ this.submitBatch(batch); // Fire-and-forget
208
+ }
209
+ }
210
+ }, 1000);
211
+ // Prevent timer from keeping process alive
212
+ if (typeof this.retryTimer.unref === 'function') {
213
+ this.retryTimer.unref();
214
+ }
215
+ }
216
+ /**
217
+ * Close queue and flush remaining proofs
218
+ */
219
+ async close() {
220
+ this.closed = true;
221
+ // Clear timers
222
+ if (this.flushTimer) {
223
+ clearInterval(this.flushTimer);
224
+ }
225
+ if (this.retryTimer) {
226
+ clearInterval(this.retryTimer);
227
+ }
228
+ // Flush remaining proofs
229
+ await this.flush();
230
+ // Wait for pending retries (with timeout)
231
+ const maxWaitMs = 30000; // 30 seconds
232
+ const startTime = Date.now();
233
+ while (this.pendingBatches.length > 0 && Date.now() - startTime < maxWaitMs) {
234
+ await new Promise((resolve) => setTimeout(resolve, 100));
235
+ }
236
+ if (this.pendingBatches.length > 0) {
237
+ console.warn(`[ProofBatchQueue] Closing with ${this.pendingBatches.length} pending batches (timed out)`);
238
+ }
239
+ }
240
+ /**
241
+ * Get queue statistics
242
+ */
243
+ getStats() {
244
+ return {
245
+ ...this.stats,
246
+ queueSize: this.queue.length,
247
+ pendingBatches: this.pendingBatches.length,
248
+ };
249
+ }
250
+ }
251
+ exports.ProofBatchQueue = ProofBatchQueue;
252
+ /**
253
+ * Create proof batch queue from config
254
+ */
255
+ function createProofBatchQueue(config) {
256
+ return new ProofBatchQueue(config);
257
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kya-os/mcp-i",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
4
4
  "description": "The TypeScript MCP framework with identity features built-in",
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",