git-paid 0.0.0-stage → 2.1.0

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,485 @@
1
+ /**
2
+ * Postbuild Stateful MCP Middleware (v2.1.0)
3
+ *
4
+ * High-performance stateful middleware for Model Context Protocol (MCP) servers.
5
+ * Provides:
6
+ * 1. Watermark Context Residuals (`compactList` -> `unchanged@vN`, `updated@vN`, `rehydrated@vN`)
7
+ * 2. Sliding-Window Attention Rehydration (`maxConsecutiveDeltas`)
8
+ * 3. In-Memory Superset Query Cache (`queryWithSupersetCache` — 1-2ms subset filtering)
9
+ * 4. Two-Phase Cryptographic Write Guard (`evaluateWriteMutation` — HMAC-SHA256 OCC `ct_...` tokens)
10
+ * 5. Untrusted Content Spotlighting (`<<<UNTRUSTED_CONTENT_DATA_ONLY: ... >>>`)
11
+ */
12
+
13
+ import crypto from "node:crypto";
14
+
15
+ const DEFAULT_SECRET =
16
+ process.env.POSTBUILD_SECRET ||
17
+ "postbuild_mcp_stateful_occ_hmac_secret";
18
+
19
+ export function spotlightUntrustedText(value) {
20
+ if (value === null || value === undefined) return value;
21
+ const raw = String(value).trim();
22
+ if (!raw) return raw;
23
+ if (raw.startsWith("<<<UNTRUSTED_CONTENT_DATA_ONLY:")) return raw;
24
+ return `<<<UNTRUSTED_CONTENT_DATA_ONLY: ${raw} >>>`;
25
+ }
26
+
27
+ /**
28
+ * Creates a generic entity adapter for stateful MCP tracking.
29
+ */
30
+ export function createGenericEntityAdapter(config = {}) {
31
+ const {
32
+ name = "generic-entity",
33
+ idField = "id",
34
+ versionField = "version_etag",
35
+ updatedAtField = "updated_at",
36
+ stubFields = ["id", "name", "status"],
37
+ journalFields = [],
38
+ untrustedTextFields = [],
39
+ isActiveRecord = () => true
40
+ } = config;
41
+
42
+ return {
43
+ name,
44
+ idField,
45
+ versionField,
46
+ updatedAtField,
47
+ stubFields,
48
+ journalFields,
49
+ untrustedTextFields,
50
+ isActiveRecord,
51
+
52
+ getId(record) {
53
+ return String(record?.[idField] ?? record?.id ?? "");
54
+ },
55
+
56
+ getWatermark(record) {
57
+ if (record?.[versionField] !== undefined && record?.[versionField] !== null) {
58
+ return String(record[versionField]);
59
+ }
60
+ if (record?.[updatedAtField]) {
61
+ return `v_${record[updatedAtField]}`;
62
+ }
63
+ const payload = JSON.stringify(record || {});
64
+ return "v1_" + crypto.createHash("sha1").update(payload).digest("hex").slice(0, 6);
65
+ },
66
+
67
+ projectInitial(record) {
68
+ if (!record || typeof record !== "object") return record;
69
+ const out = {};
70
+ for (const [k, v] of Object.entries(record)) {
71
+ if (journalFields.includes(k)) continue;
72
+ if (untrustedTextFields.includes(k) && typeof v === "string") {
73
+ out[k] = spotlightUntrustedText(v);
74
+ } else {
75
+ out[k] = v;
76
+ }
77
+ }
78
+ return out;
79
+ },
80
+
81
+ projectStub(record, watermark) {
82
+ const stub = {};
83
+ stub[idField] = this.getId(record);
84
+ for (const f of stubFields) {
85
+ if (record[f] !== undefined) {
86
+ stub[f] = untrustedTextFields.includes(f)
87
+ ? spotlightUntrustedText(record[f])
88
+ : record[f];
89
+ }
90
+ }
91
+ stub._context_delta = `unchanged@${watermark}`;
92
+ return stub;
93
+ }
94
+ };
95
+ }
96
+
97
+ /**
98
+ * Stateful MCP Middleware instance factory.
99
+ */
100
+ export function withStatefulMcp(options = {}) {
101
+ const {
102
+ adapter = createGenericEntityAdapter(),
103
+ maxConsecutiveDeltas = 8,
104
+ requireCommitTokenOnWrite = true,
105
+ commitTokenTtlMs = 5 * 60 * 1000
106
+ } = options;
107
+
108
+ const sessions = new Map();
109
+ const ticketVault = new Map();
110
+
111
+ const telemetry = {
112
+ totalCalls: 0,
113
+ supersetCacheHits: 0,
114
+ upstreamFetches: 0,
115
+ rawBytesEstimated: 0,
116
+ compactedBytesEmitted: 0,
117
+ deltasEmitted: 0,
118
+ rehydrationsEmitted: 0,
119
+ occDryRuns: 0,
120
+ occCommits: 0,
121
+ occRejections: 0
122
+ };
123
+
124
+ function getSession(sessionId = "global-default", principalId = "default") {
125
+ const key = `${sessionId}::${principalId}`;
126
+ if (!sessions.has(key)) {
127
+ sessions.set(key, {
128
+ entityMap: new Map(),
129
+ supersetCache: new Map(),
130
+ createdAt: Date.now(),
131
+ turns: 0
132
+ });
133
+ }
134
+ return sessions.get(key);
135
+ }
136
+
137
+ function computeDiff(prevSnapshot = {}, nextSnapshot = {}) {
138
+ const changedFields = [];
139
+ const diffValues = {};
140
+ const allKeys = new Set([
141
+ ...Object.keys(prevSnapshot || {}),
142
+ ...Object.keys(nextSnapshot || {})
143
+ ]);
144
+ for (const k of allKeys) {
145
+ if (k.startsWith("_")) continue;
146
+ if (adapter.journalFields.includes(k)) continue;
147
+ const a = JSON.stringify(prevSnapshot?.[k]);
148
+ const b = JSON.stringify(nextSnapshot?.[k]);
149
+ if (a !== b) {
150
+ changedFields.push(k);
151
+ diffValues[k] = adapter.untrustedTextFields.includes(k)
152
+ ? spotlightUntrustedText(nextSnapshot?.[k])
153
+ : nextSnapshot?.[k];
154
+ }
155
+ }
156
+ return { changedFields, diffValues };
157
+ }
158
+
159
+ return {
160
+ adapter,
161
+ telemetry,
162
+
163
+ /**
164
+ * Evaluates a query against a warm in-memory superset cache before hitting upstream.
165
+ */
166
+ async queryWithSupersetCache({
167
+ sessionId = "global-default",
168
+ principalId = "default",
169
+ cacheKey = "default_collection",
170
+ fetchLive,
171
+ filter = () => true,
172
+ limit = 50,
173
+ bypassCache = false,
174
+ ttlMs = 120 * 1000
175
+ }) {
176
+ const sess = getSession(sessionId, principalId);
177
+ const cached = sess.supersetCache.get(cacheKey);
178
+ const now = Date.now();
179
+
180
+ let baseRecords;
181
+ let cacheHit = false;
182
+ const t0 = performance.now();
183
+
184
+ if (!bypassCache && cached && now - cached.ts < ttlMs) {
185
+ baseRecords = cached.records;
186
+ cacheHit = true;
187
+ telemetry.supersetCacheHits += 1;
188
+ } else {
189
+ baseRecords = await fetchLive();
190
+ sess.supersetCache.set(cacheKey, {
191
+ records: Array.isArray(baseRecords) ? baseRecords : [],
192
+ ts: now
193
+ });
194
+ telemetry.upstreamFetches += 1;
195
+ }
196
+
197
+ const filtered = (Array.isArray(baseRecords) ? baseRecords : [])
198
+ .filter(filter)
199
+ .slice(0, limit);
200
+
201
+ const elapsedMs = Number((performance.now() - t0).toFixed(2));
202
+ return Object.assign(filtered, {
203
+ _mcp_cache_hit: cacheHit,
204
+ _mcp_query_ms: elapsedMs,
205
+ _mcp_superset_total: Array.isArray(baseRecords) ? baseRecords.length : 0
206
+ });
207
+ },
208
+
209
+ /**
210
+ * Compacts a list of records using per-entity Watermark Context Residuals (`@vN`)
211
+ * and Sliding-Window Attention Rehydration (`maxConsecutiveDeltas`).
212
+ */
213
+ compactList({
214
+ sessionId = "global-default",
215
+ principalId = "default",
216
+ records = [],
217
+ bypassCache = false
218
+ }) {
219
+ telemetry.totalCalls += 1;
220
+ const sess = getSession(sessionId, principalId);
221
+ sess.turns += 1;
222
+
223
+ const rawJson = JSON.stringify(records);
224
+ const rawBytes = Buffer.byteLength(rawJson, "utf8");
225
+ telemetry.rawBytesEstimated += rawBytes;
226
+
227
+ const compacted = [];
228
+ let unchangedCount = 0;
229
+ let updatedCount = 0;
230
+ let rehydratedCount = 0;
231
+ let initialCount = 0;
232
+
233
+ for (const rec of records) {
234
+ const id = adapter.getId(rec);
235
+ const watermark = adapter.getWatermark(rec);
236
+ const projected = adapter.projectInitial(rec);
237
+ const prev = sess.entityMap.get(id);
238
+
239
+ if (bypassCache || !prev) {
240
+ sess.entityMap.set(id, {
241
+ watermark,
242
+ snapshot: projected,
243
+ consecutiveDeltas: 0
244
+ });
245
+ compacted.push({
246
+ ...projected,
247
+ _context_delta: `initial@${watermark}`
248
+ });
249
+ initialCount += 1;
250
+ continue;
251
+ }
252
+
253
+ if (prev.watermark === watermark) {
254
+ const nextConsecutive = prev.consecutiveDeltas + 1;
255
+ if (nextConsecutive >= maxConsecutiveDeltas) {
256
+ sess.entityMap.set(id, {
257
+ watermark,
258
+ snapshot: projected,
259
+ consecutiveDeltas: 0
260
+ });
261
+ compacted.push({
262
+ ...projected,
263
+ _context_delta: `rehydrated@${watermark}`
264
+ });
265
+ rehydratedCount += 1;
266
+ telemetry.rehydrationsEmitted += 1;
267
+ } else {
268
+ sess.entityMap.set(id, {
269
+ ...prev,
270
+ consecutiveDeltas: nextConsecutive
271
+ });
272
+ compacted.push(adapter.projectStub(rec, watermark));
273
+ unchangedCount += 1;
274
+ telemetry.deltasEmitted += 1;
275
+ }
276
+ } else {
277
+ const { changedFields, diffValues } = computeDiff(prev.snapshot, projected);
278
+ sess.entityMap.set(id, {
279
+ watermark,
280
+ snapshot: projected,
281
+ consecutiveDeltas: 0
282
+ });
283
+ compacted.push({
284
+ [adapter.idField]: id,
285
+ _context_delta: `updated@${watermark}`,
286
+ _changed_fields: changedFields,
287
+ ...diffValues
288
+ });
289
+ updatedCount += 1;
290
+ telemetry.deltasEmitted += 1;
291
+ }
292
+ }
293
+
294
+ const outEnvelope = {
295
+ _mcp: {
296
+ server: "postbuild-mcp@2.1.0",
297
+ adapter: adapter.name,
298
+ session_id: sessionId,
299
+ turn: sess.turns,
300
+ cache_hit: Boolean(records._mcp_cache_hit),
301
+ query_ms: records._mcp_query_ms ?? 1.1,
302
+ counts: {
303
+ total: compacted.length,
304
+ initial: initialCount,
305
+ unchanged_stubs: unchangedCount,
306
+ updated_deltas: updatedCount,
307
+ rehydrated: rehydratedCount
308
+ }
309
+ },
310
+ records: compacted
311
+ };
312
+
313
+ const compactBytes = Buffer.byteLength(JSON.stringify(outEnvelope), "utf8");
314
+ telemetry.compactedBytesEmitted += compactBytes;
315
+ const savingsPct =
316
+ rawBytes > 0 ? Number((((rawBytes - compactBytes) / rawBytes) * 100).toFixed(1)) : 0;
317
+ outEnvelope._mcp.payload_bytes = {
318
+ raw_stateless_bytes: rawBytes,
319
+ compacted_bytes: compactBytes,
320
+ reduction_pct: savingsPct > 0 ? `-${savingsPct}%` : "0%"
321
+ };
322
+
323
+ return outEnvelope;
324
+ },
325
+
326
+ /**
327
+ * Two-Phase Cryptographic Write Guard (Optimistic Concurrency Control).
328
+ */
329
+ evaluateWriteMutation({
330
+ sessionId = "global-default",
331
+ principalId = "default",
332
+ entityId,
333
+ liveRecord,
334
+ expectedWatermark,
335
+ changes = {},
336
+ dryRun = true,
337
+ commitToken
338
+ }) {
339
+ if (!liveRecord) {
340
+ telemetry.occRejections += 1;
341
+ return { allowed: false, reason: `Entity '${entityId}' not found.` };
342
+ }
343
+
344
+ const liveWatermark = adapter.getWatermark(liveRecord);
345
+ if (expectedWatermark && expectedWatermark !== liveWatermark) {
346
+ telemetry.occRejections += 1;
347
+ return {
348
+ allowed: false,
349
+ reason: `OCC Watermark mismatch on '${entityId}': expected '${expectedWatermark}', but live record is at '${liveWatermark}'. Re-read the entity before mutating.`
350
+ };
351
+ }
352
+
353
+ const previewDiff = {};
354
+ for (const [k, newVal] of Object.entries(changes)) {
355
+ previewDiff[k] = {
356
+ before: liveRecord[k] ?? null,
357
+ after: newVal
358
+ };
359
+ }
360
+
361
+ const changeHash = crypto
362
+ .createHash("sha256")
363
+ .update(JSON.stringify({ entityId, liveWatermark, changes }))
364
+ .digest("hex")
365
+ .slice(0, 16);
366
+
367
+ if (dryRun) {
368
+ telemetry.occDryRuns += 1;
369
+ const nonce = crypto.randomBytes(6).toString("hex");
370
+ const rawPayload = `${sessionId}|${principalId}|${entityId}|${liveWatermark}|${changeHash}|${nonce}`;
371
+ const sig = crypto
372
+ .createHmac("sha256", DEFAULT_SECRET)
373
+ .update(rawPayload)
374
+ .digest("hex")
375
+ .slice(0, 20);
376
+ const token = `ct_${nonce}_${sig}`;
377
+
378
+ ticketVault.set(token, {
379
+ sessionId,
380
+ principalId,
381
+ entityId: String(entityId),
382
+ expectedWatermark: liveWatermark,
383
+ changeHash,
384
+ expiresAt: Date.now() + commitTokenTtlMs,
385
+ used: false
386
+ });
387
+
388
+ return {
389
+ allowed: true,
390
+ dryRun: true,
391
+ liveWatermark,
392
+ previewDiff,
393
+ commitToken: token,
394
+ expiresInSeconds: Math.round(commitTokenTtlMs / 1000)
395
+ };
396
+ }
397
+
398
+ if (requireCommitTokenOnWrite) {
399
+ if (!commitToken || !ticketVault.has(commitToken)) {
400
+ telemetry.occRejections += 1;
401
+ return {
402
+ allowed: false,
403
+ reason:
404
+ "Missing or unknown commit_token. Run this tool with dry_run: true first to obtain a cryptographic Two-Phase Commit token."
405
+ };
406
+ }
407
+
408
+ const ticket = ticketVault.get(commitToken);
409
+ if (ticket.used) {
410
+ telemetry.occRejections += 1;
411
+ return {
412
+ allowed: false,
413
+ reason: "Replay rejected: commit_token has already been consumed."
414
+ };
415
+ }
416
+ if (Date.now() > ticket.expiresAt) {
417
+ ticketVault.delete(commitToken);
418
+ telemetry.occRejections += 1;
419
+ return {
420
+ allowed: false,
421
+ reason: "Expired commit_token (TTL > 5 minutes). Re-run with dry_run: true."
422
+ };
423
+ }
424
+ if (ticket.sessionId !== sessionId || ticket.principalId !== principalId) {
425
+ telemetry.occRejections += 1;
426
+ return {
427
+ allowed: false,
428
+ reason: "Principal binding violation: commit_token belongs to a different session or principal."
429
+ };
430
+ }
431
+ if (ticket.entityId !== String(entityId) || ticket.expectedWatermark !== liveWatermark) {
432
+ telemetry.occRejections += 1;
433
+ return {
434
+ allowed: false,
435
+ reason: `Concurrent modification detected: entity '${entityId}' changed since dry_run token was issued.`
436
+ };
437
+ }
438
+ if (ticket.changeHash !== changeHash) {
439
+ telemetry.occRejections += 1;
440
+ return {
441
+ allowed: false,
442
+ reason: "Payload mismatch: mutation parameters differ from the approved dry_run preview."
443
+ };
444
+ }
445
+
446
+ ticket.used = true;
447
+ }
448
+
449
+ telemetry.occCommits += 1;
450
+ return {
451
+ allowed: true,
452
+ dryRun: false,
453
+ committedWatermark: liveWatermark,
454
+ previewDiff
455
+ };
456
+ },
457
+
458
+ invalidateEntityCache(sessionId = "global-default", entityId = null, principalId = "default") {
459
+ const sess = getSession(sessionId, principalId);
460
+ sess.supersetCache.clear();
461
+ if (entityId) {
462
+ sess.entityMap.delete(String(entityId));
463
+ }
464
+ },
465
+
466
+ resetSession(sessionId = "global-default", principalId = "default") {
467
+ sessions.delete(`${sessionId}::${principalId}`);
468
+ },
469
+
470
+ getTelemetrySummary() {
471
+ const savedBytes = Math.max(0, telemetry.rawBytesEstimated - telemetry.compactedBytesEmitted);
472
+ const savedPct =
473
+ telemetry.rawBytesEstimated > 0
474
+ ? Number(((savedBytes / telemetry.rawBytesEstimated) * 100).toFixed(1))
475
+ : 0;
476
+ return {
477
+ server: "postbuild-mcp@2.1.0",
478
+ adapter: adapter.name,
479
+ ...telemetry,
480
+ bytesSaved: savedBytes,
481
+ tokenReductionPct: `-${savedPct}%`
482
+ };
483
+ }
484
+ };
485
+ }