@relayplane/proxy 1.8.10 → 1.8.11
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.
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +21 -4
- package/dist/config.js.map +1 -1
- package/dist/estimate.d.ts +97 -0
- package/dist/estimate.d.ts.map +1 -0
- package/dist/estimate.js +257 -0
- package/dist/estimate.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/osmosis-store.d.ts +33 -0
- package/dist/osmosis-store.d.ts.map +1 -0
- package/dist/osmosis-store.js +181 -0
- package/dist/osmosis-store.js.map +1 -0
- package/dist/recovery-mesh-server.d.ts +49 -0
- package/dist/recovery-mesh-server.d.ts.map +1 -0
- package/dist/recovery-mesh-server.js +333 -0
- package/dist/recovery-mesh-server.js.map +1 -0
- package/dist/recovery-mesh.d.ts +207 -0
- package/dist/recovery-mesh.d.ts.map +1 -0
- package/dist/recovery-mesh.js +426 -0
- package/dist/recovery-mesh.js.map +1 -0
- package/dist/recovery.d.ts +262 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +570 -0
- package/dist/recovery.js.map +1 -0
- package/dist/standalone-proxy.d.ts.map +1 -1
- package/dist/standalone-proxy.js +40 -1
- package/dist/standalone-proxy.js.map +1 -1
- package/dist/telemetry.d.ts +8 -0
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +3 -2
- package/dist/telemetry.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Osmosis Phase 1 — KnowledgeAtom capture
|
|
4
|
+
*
|
|
5
|
+
* Stores per-request atoms in ~/.relayplane/osmosis.db (SQLite via better-sqlite3).
|
|
6
|
+
* Falls back to ~/.relayplane/osmosis.jsonl if SQLite is unavailable.
|
|
7
|
+
*
|
|
8
|
+
* All writes are fire-and-forget; errors are silently swallowed.
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.captureAtom = captureAtom;
|
|
45
|
+
exports._resetStore = _resetStore;
|
|
46
|
+
const fs = __importStar(require("node:fs"));
|
|
47
|
+
const os = __importStar(require("node:os"));
|
|
48
|
+
const path = __importStar(require("node:path"));
|
|
49
|
+
const SCHEMA_SQL = `
|
|
50
|
+
CREATE TABLE IF NOT EXISTS knowledge_atoms (
|
|
51
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
52
|
+
type TEXT NOT NULL,
|
|
53
|
+
model TEXT,
|
|
54
|
+
task_type TEXT,
|
|
55
|
+
latency_ms INTEGER,
|
|
56
|
+
input_tokens INTEGER,
|
|
57
|
+
output_tokens INTEGER,
|
|
58
|
+
error_type TEXT,
|
|
59
|
+
fallback_taken INTEGER,
|
|
60
|
+
timestamp INTEGER NOT NULL
|
|
61
|
+
);
|
|
62
|
+
`;
|
|
63
|
+
/** Lazy-initialised SQLite database handle, or null if unavailable. */
|
|
64
|
+
let _db = undefined;
|
|
65
|
+
let _jsonlPath = null;
|
|
66
|
+
let _insertStmt = null;
|
|
67
|
+
function getRelayplaneDir() {
|
|
68
|
+
// RELAYPLANE_HOME_OVERRIDE is used in tests to avoid writing to ~/.relayplane
|
|
69
|
+
const override = process.env['RELAYPLANE_HOME_OVERRIDE'];
|
|
70
|
+
const base = override ?? os.homedir();
|
|
71
|
+
return path.join(base, '.relayplane');
|
|
72
|
+
}
|
|
73
|
+
function ensureDir(dir) {
|
|
74
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
75
|
+
}
|
|
76
|
+
function initDb() {
|
|
77
|
+
try {
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
79
|
+
const Database = require('better-sqlite3');
|
|
80
|
+
const dir = getRelayplaneDir();
|
|
81
|
+
ensureDir(dir);
|
|
82
|
+
const dbPath = path.join(dir, 'osmosis.db');
|
|
83
|
+
const db = new Database(dbPath);
|
|
84
|
+
db.pragma('journal_mode = WAL');
|
|
85
|
+
db.exec(SCHEMA_SQL);
|
|
86
|
+
return db;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function getDb() {
|
|
93
|
+
if (_db !== undefined)
|
|
94
|
+
return _db;
|
|
95
|
+
_db = initDb();
|
|
96
|
+
if (_db) {
|
|
97
|
+
_insertStmt = _db.prepare(`
|
|
98
|
+
INSERT INTO knowledge_atoms
|
|
99
|
+
(type, model, task_type, latency_ms, input_tokens, output_tokens, error_type, fallback_taken, timestamp)
|
|
100
|
+
VALUES
|
|
101
|
+
(@type, @model, @task_type, @latency_ms, @input_tokens, @output_tokens, @error_type, @fallback_taken, @timestamp)
|
|
102
|
+
`);
|
|
103
|
+
}
|
|
104
|
+
return _db;
|
|
105
|
+
}
|
|
106
|
+
function getJsonlPath() {
|
|
107
|
+
if (_jsonlPath)
|
|
108
|
+
return _jsonlPath;
|
|
109
|
+
const dir = getRelayplaneDir();
|
|
110
|
+
ensureDir(dir);
|
|
111
|
+
_jsonlPath = path.join(dir, 'osmosis.jsonl');
|
|
112
|
+
return _jsonlPath;
|
|
113
|
+
}
|
|
114
|
+
function writeToJsonl(atom) {
|
|
115
|
+
try {
|
|
116
|
+
fs.appendFileSync(getJsonlPath(), JSON.stringify(atom) + '\n', 'utf-8');
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// best-effort
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Capture a KnowledgeAtom (fire-and-forget).
|
|
124
|
+
* Never throws. Writes to SQLite; falls back to JSONL.
|
|
125
|
+
*/
|
|
126
|
+
function captureAtom(atom) {
|
|
127
|
+
try {
|
|
128
|
+
const db = getDb();
|
|
129
|
+
if (db && _insertStmt) {
|
|
130
|
+
if (atom.type === 'success') {
|
|
131
|
+
_insertStmt.run({
|
|
132
|
+
type: atom.type,
|
|
133
|
+
model: atom.model ?? null,
|
|
134
|
+
task_type: atom.taskType ?? null,
|
|
135
|
+
latency_ms: atom.latencyMs,
|
|
136
|
+
input_tokens: atom.inputTokens,
|
|
137
|
+
output_tokens: atom.outputTokens,
|
|
138
|
+
error_type: null,
|
|
139
|
+
fallback_taken: null,
|
|
140
|
+
timestamp: atom.timestamp,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
_insertStmt.run({
|
|
145
|
+
type: atom.type,
|
|
146
|
+
model: atom.model ?? null,
|
|
147
|
+
task_type: null,
|
|
148
|
+
latency_ms: null,
|
|
149
|
+
input_tokens: null,
|
|
150
|
+
output_tokens: null,
|
|
151
|
+
error_type: atom.errorType ?? null,
|
|
152
|
+
fallback_taken: atom.fallbackTaken ? 1 : 0,
|
|
153
|
+
timestamp: atom.timestamp,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
// SQLite unavailable — fall back to JSONL
|
|
159
|
+
writeToJsonl(atom);
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// best-effort fallback
|
|
163
|
+
try {
|
|
164
|
+
writeToJsonl(atom);
|
|
165
|
+
}
|
|
166
|
+
catch { /* ignore */ }
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/** Exposed for testing — reset singleton state. */
|
|
170
|
+
function _resetStore() {
|
|
171
|
+
if (_db) {
|
|
172
|
+
try {
|
|
173
|
+
_db.close();
|
|
174
|
+
}
|
|
175
|
+
catch { /* ignore */ }
|
|
176
|
+
}
|
|
177
|
+
_db = undefined;
|
|
178
|
+
_insertStmt = null;
|
|
179
|
+
_jsonlPath = null;
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=osmosis-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"osmosis-store.js","sourceRoot":"","sources":["../src/osmosis-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mesh server routes for recovery atom sharing.
|
|
3
|
+
*
|
|
4
|
+
* Provides HTTP endpoints for proxy instances to contribute,
|
|
5
|
+
* query, and confirm recovery patterns via the mesh.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
import { type Server } from 'node:http';
|
|
10
|
+
import { MeshRecoveryAtomStore } from './recovery-mesh.js';
|
|
11
|
+
export interface RecoveryMeshServerConfig {
|
|
12
|
+
/** Port to listen on */
|
|
13
|
+
port: number;
|
|
14
|
+
/** API keys that can write (empty = deny all writes unless allowUnauthenticated is true) */
|
|
15
|
+
writeKeys: string[];
|
|
16
|
+
/** API keys that can read (empty = no auth required) */
|
|
17
|
+
readKeys: string[];
|
|
18
|
+
/** Rate limit per key/IP per hour */
|
|
19
|
+
rateLimitPerHour: number;
|
|
20
|
+
/** Pattern expiry in days */
|
|
21
|
+
expiryDays: number;
|
|
22
|
+
/**
|
|
23
|
+
* When true and writeKeys is empty, allow unauthenticated writes.
|
|
24
|
+
* Requires explicit opt-in — empty writeKeys alone no longer grants open write access.
|
|
25
|
+
* /confirm always requires a writeKey regardless of this flag.
|
|
26
|
+
*/
|
|
27
|
+
allowUnauthenticated?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare const DEFAULT_RECOVERY_MESH_CONFIG: RecoveryMeshServerConfig;
|
|
30
|
+
export interface RecoveryMeshServerHandle {
|
|
31
|
+
store: MeshRecoveryAtomStore;
|
|
32
|
+
server: Server;
|
|
33
|
+
stop(): void;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create an HTTP server that handles recovery atom mesh endpoints.
|
|
37
|
+
*
|
|
38
|
+
* Routes:
|
|
39
|
+
* POST /mesh/recovery/contribute — submit recovery atoms
|
|
40
|
+
* GET /mesh/recovery/atoms?since= — get recovery atoms (incremental)
|
|
41
|
+
* POST /mesh/recovery/confirm — report confirmation/denial (always requires writeKey)
|
|
42
|
+
* GET /mesh/recovery/stats — mesh recovery statistics
|
|
43
|
+
*/
|
|
44
|
+
export declare function createRecoveryMeshServer(store: MeshRecoveryAtomStore, config: RecoveryMeshServerConfig): Server;
|
|
45
|
+
/**
|
|
46
|
+
* Start a recovery mesh server with a fresh store.
|
|
47
|
+
*/
|
|
48
|
+
export declare function startRecoveryMeshServer(config?: Partial<RecoveryMeshServerConfig>): RecoveryMeshServerHandle;
|
|
49
|
+
//# sourceMappingURL=recovery-mesh-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-mesh-server.d.ts","sourceRoot":"","sources":["../src/recovery-mesh-server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAA+E,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AACrH,OAAO,EAEL,qBAAqB,EAGtB,MAAM,oBAAoB,CAAC;AAI5B,MAAM,WAAW,wBAAwB;IACvC,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,4FAA4F;IAC5F,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,qCAAqC;IACrC,gBAAgB,EAAE,MAAM,CAAC;IACzB,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,eAAO,MAAM,4BAA4B,EAAE,wBAO1C,CAAC;AAEF,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,qBAAqB,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,IAAI,IAAI,CAAC;CACd;AAiGD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,qBAAqB,EAC5B,MAAM,EAAE,wBAAwB,GAC/B,MAAM,CAiOR;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,CAAC,EAAE,OAAO,CAAC,wBAAwB,CAAC,GACzC,wBAAwB,CAY1B"}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Mesh server routes for recovery atom sharing.
|
|
4
|
+
*
|
|
5
|
+
* Provides HTTP endpoints for proxy instances to contribute,
|
|
6
|
+
* query, and confirm recovery patterns via the mesh.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.DEFAULT_RECOVERY_MESH_CONFIG = void 0;
|
|
12
|
+
exports.createRecoveryMeshServer = createRecoveryMeshServer;
|
|
13
|
+
exports.startRecoveryMeshServer = startRecoveryMeshServer;
|
|
14
|
+
const node_http_1 = require("node:http");
|
|
15
|
+
const recovery_mesh_js_1 = require("./recovery-mesh.js");
|
|
16
|
+
exports.DEFAULT_RECOVERY_MESH_CONFIG = {
|
|
17
|
+
port: 19600,
|
|
18
|
+
writeKeys: [],
|
|
19
|
+
readKeys: [],
|
|
20
|
+
rateLimitPerHour: 100,
|
|
21
|
+
expiryDays: 30,
|
|
22
|
+
allowUnauthenticated: false,
|
|
23
|
+
};
|
|
24
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
25
|
+
/** Maximum request body size (1 MB) */
|
|
26
|
+
const MAX_BODY_BYTES = 1_048_576;
|
|
27
|
+
/** Maximum atoms allowed in a single /contribute request */
|
|
28
|
+
const MAX_ATOMS_PER_REQUEST = 100;
|
|
29
|
+
/** Maximum allowed value for count fields */
|
|
30
|
+
const MAX_COUNT = 10_000;
|
|
31
|
+
/** Valid atom type values */
|
|
32
|
+
const VALID_ATOM_TYPES = new Set([
|
|
33
|
+
'auth-header',
|
|
34
|
+
'model-rename',
|
|
35
|
+
'timeout-tune',
|
|
36
|
+
'provider-fallback',
|
|
37
|
+
]);
|
|
38
|
+
/** Valid authHeader values */
|
|
39
|
+
const VALID_AUTH_HEADERS = new Set(['Authorization', 'x-api-key']);
|
|
40
|
+
/** Known provider names */
|
|
41
|
+
const KNOWN_PROVIDERS = new Set([
|
|
42
|
+
'anthropic',
|
|
43
|
+
'openai',
|
|
44
|
+
'google',
|
|
45
|
+
'azure',
|
|
46
|
+
'openrouter',
|
|
47
|
+
'cohere',
|
|
48
|
+
'mistral',
|
|
49
|
+
'bedrock',
|
|
50
|
+
'vertex',
|
|
51
|
+
'groq',
|
|
52
|
+
'together',
|
|
53
|
+
'fireworks',
|
|
54
|
+
'perplexity',
|
|
55
|
+
'deepseek',
|
|
56
|
+
'xai',
|
|
57
|
+
'meta',
|
|
58
|
+
'ollama',
|
|
59
|
+
]);
|
|
60
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
61
|
+
function json(res, status, data) {
|
|
62
|
+
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
63
|
+
res.end(JSON.stringify(data));
|
|
64
|
+
}
|
|
65
|
+
function extractKey(req, url) {
|
|
66
|
+
const authHeader = req.headers['authorization'];
|
|
67
|
+
if (authHeader?.startsWith('Bearer '))
|
|
68
|
+
return authHeader.slice(7);
|
|
69
|
+
return url.searchParams.get('key');
|
|
70
|
+
}
|
|
71
|
+
function makeRateLimiter() {
|
|
72
|
+
const buckets = new Map();
|
|
73
|
+
return function checkRateLimit(key, limit) {
|
|
74
|
+
const now = Date.now();
|
|
75
|
+
const bucket = buckets.get(key);
|
|
76
|
+
if (!bucket || now > bucket.resetAt) {
|
|
77
|
+
buckets.set(key, { count: 1, resetAt: now + 3600_000 });
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
if (bucket.count >= limit)
|
|
81
|
+
return false;
|
|
82
|
+
bucket.count++;
|
|
83
|
+
return true;
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function readBody(req) {
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
const chunks = [];
|
|
89
|
+
let total = 0;
|
|
90
|
+
let oversized = false;
|
|
91
|
+
req.on('data', (c) => {
|
|
92
|
+
if (oversized)
|
|
93
|
+
return; // discard additional data without buffering
|
|
94
|
+
total += c.length;
|
|
95
|
+
if (total > MAX_BODY_BYTES) {
|
|
96
|
+
oversized = true;
|
|
97
|
+
chunks.length = 0; // free already-buffered chunks
|
|
98
|
+
return reject(new Error('Payload too large'));
|
|
99
|
+
}
|
|
100
|
+
chunks.push(c);
|
|
101
|
+
});
|
|
102
|
+
req.on('end', () => {
|
|
103
|
+
if (!oversized)
|
|
104
|
+
resolve(Buffer.concat(chunks).toString());
|
|
105
|
+
});
|
|
106
|
+
req.on('error', reject);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
// ─── Server ───────────────────────────────────────────────────────────────────
|
|
110
|
+
/**
|
|
111
|
+
* Create an HTTP server that handles recovery atom mesh endpoints.
|
|
112
|
+
*
|
|
113
|
+
* Routes:
|
|
114
|
+
* POST /mesh/recovery/contribute — submit recovery atoms
|
|
115
|
+
* GET /mesh/recovery/atoms?since= — get recovery atoms (incremental)
|
|
116
|
+
* POST /mesh/recovery/confirm — report confirmation/denial (always requires writeKey)
|
|
117
|
+
* GET /mesh/recovery/stats — mesh recovery statistics
|
|
118
|
+
*/
|
|
119
|
+
function createRecoveryMeshServer(store, config) {
|
|
120
|
+
// Per-server rate limiter (not module-level) to avoid cross-test interference
|
|
121
|
+
const checkRateLimit = makeRateLimiter();
|
|
122
|
+
const server = (0, node_http_1.createServer)(async (req, res) => {
|
|
123
|
+
const url = new URL(req.url ?? '/', `http://localhost:${config.port}`);
|
|
124
|
+
const path = url.pathname;
|
|
125
|
+
const method = req.method ?? 'GET';
|
|
126
|
+
try {
|
|
127
|
+
const apiKey = extractKey(req, url);
|
|
128
|
+
// ── Auth: /confirm always requires a valid writeKey (H3)
|
|
129
|
+
// Not exempted by allowUnauthenticated — prevents unauthenticated confidence flooding.
|
|
130
|
+
if (method === 'POST' && path === '/mesh/recovery/confirm') {
|
|
131
|
+
if (!apiKey || config.writeKeys.length === 0 || !config.writeKeys.includes(apiKey)) {
|
|
132
|
+
return json(res, 401, { error: 'Authentication required for confirmations' });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// ── Auth: all other POSTs (/contribute, etc.) (H1)
|
|
136
|
+
// allowUnauthenticated: true → skip key check (even if writeKeys is set)
|
|
137
|
+
else if (method === 'POST') {
|
|
138
|
+
if (config.allowUnauthenticated) {
|
|
139
|
+
// Explicit opt-in: open write access (e.g., private cluster deployments)
|
|
140
|
+
// /confirm is still always authenticated above
|
|
141
|
+
}
|
|
142
|
+
else if (config.writeKeys.length > 0) {
|
|
143
|
+
// writeKeys configured — validate the key
|
|
144
|
+
if (!apiKey || !config.writeKeys.includes(apiKey)) {
|
|
145
|
+
return json(res, 401, { error: 'Invalid or missing API key' });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// No writeKeys and no explicit opt-in → deny-by-default (H1)
|
|
150
|
+
return json(res, 401, { error: 'Write access requires authentication' });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// ── Auth: reads (C2 rate limit applies before this for GETs? No — reads are separate)
|
|
154
|
+
if (method === 'GET' && config.readKeys.length > 0 && path !== '/mesh/recovery/stats') {
|
|
155
|
+
if (!apiKey || !config.readKeys.includes(apiKey)) {
|
|
156
|
+
return json(res, 401, { error: 'Invalid or missing API key' });
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// ── Rate limiting for writes (C2: use IP when no API key)
|
|
160
|
+
if (method === 'POST') {
|
|
161
|
+
const rateLimitKey = apiKey ?? req.socket.remoteAddress ?? 'unknown';
|
|
162
|
+
if (!checkRateLimit(rateLimitKey, config.rateLimitPerHour)) {
|
|
163
|
+
return json(res, 429, { error: 'Rate limit exceeded' });
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// POST /mesh/recovery/contribute — accept recovery atoms
|
|
167
|
+
if (method === 'POST' && path === '/mesh/recovery/contribute') {
|
|
168
|
+
let body;
|
|
169
|
+
try {
|
|
170
|
+
body = JSON.parse(await readBody(req));
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
if (err.message === 'Payload too large') {
|
|
174
|
+
return json(res, 413, { error: 'Payload too large' });
|
|
175
|
+
}
|
|
176
|
+
return json(res, 400, { error: 'Invalid JSON' });
|
|
177
|
+
}
|
|
178
|
+
const rawAtoms = Array.isArray(body) ? body : [body];
|
|
179
|
+
// M3: Limit atoms per request
|
|
180
|
+
if (rawAtoms.length > MAX_ATOMS_PER_REQUEST) {
|
|
181
|
+
return json(res, 400, { error: `Too many atoms: max ${MAX_ATOMS_PER_REQUEST} per request` });
|
|
182
|
+
}
|
|
183
|
+
const results = [];
|
|
184
|
+
for (const atom of rawAtoms) {
|
|
185
|
+
// Validate required fields
|
|
186
|
+
if (!atom.type || !atom.provider || !atom.trigger || !atom.fix) {
|
|
187
|
+
results.push({ id: atom.id ?? 'unknown', status: 'rejected' });
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
// M3: Validate atom type against enum
|
|
191
|
+
if (!VALID_ATOM_TYPES.has(atom.type)) {
|
|
192
|
+
results.push({ id: atom.id ?? 'unknown', status: 'rejected' });
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
// M3: Validate errorCode is a number in valid HTTP range
|
|
196
|
+
const errorCode = atom.trigger?.errorCode;
|
|
197
|
+
if (typeof errorCode !== 'number' || errorCode < 100 || errorCode > 599) {
|
|
198
|
+
results.push({ id: atom.id ?? 'unknown', status: 'rejected' });
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
// M3: Validate authHeader if present
|
|
202
|
+
if (atom.fix?.authHeader && !VALID_AUTH_HEADERS.has(atom.fix.authHeader)) {
|
|
203
|
+
results.push({ id: atom.id ?? 'unknown', status: 'rejected' });
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
// M2: Strip unknown fix.provider
|
|
207
|
+
if (atom.fix?.provider && !KNOWN_PROVIDERS.has(atom.fix.provider)) {
|
|
208
|
+
delete atom.fix.provider;
|
|
209
|
+
}
|
|
210
|
+
// H2: Cap numeric fields
|
|
211
|
+
if (typeof atom.confirmCount === 'number') {
|
|
212
|
+
atom.confirmCount = Math.min(atom.confirmCount, MAX_COUNT);
|
|
213
|
+
}
|
|
214
|
+
if (typeof atom.denyCount === 'number') {
|
|
215
|
+
atom.denyCount = Math.min(atom.denyCount, MAX_COUNT);
|
|
216
|
+
}
|
|
217
|
+
if (typeof atom.reportCount === 'number') {
|
|
218
|
+
atom.reportCount = Math.min(atom.reportCount, MAX_COUNT);
|
|
219
|
+
}
|
|
220
|
+
// H2: Recalculate confidence from counts (don't trust client-provided value)
|
|
221
|
+
const totalAttempts = (atom.confirmCount ?? 0) + (atom.denyCount ?? 0);
|
|
222
|
+
atom.confidence = totalAttempts > 0 ? (atom.confirmCount ?? 0) / totalAttempts : 0;
|
|
223
|
+
// Ensure atom has an ID
|
|
224
|
+
if (!atom.id) {
|
|
225
|
+
atom.id = (0, recovery_mesh_js_1.recoveryAtomId)(atom.type, atom.provider, atom.trigger);
|
|
226
|
+
}
|
|
227
|
+
// Force recovery atom type
|
|
228
|
+
atom.atomType = 'recovery';
|
|
229
|
+
const existing = store.get(atom.id);
|
|
230
|
+
store.upsert(atom);
|
|
231
|
+
results.push({
|
|
232
|
+
id: atom.id,
|
|
233
|
+
status: existing ? 'merged' : 'created',
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
const accepted = results.filter(r => r.status !== 'rejected').length;
|
|
237
|
+
return json(res, 200, { accepted, results });
|
|
238
|
+
}
|
|
239
|
+
// GET /mesh/recovery/atoms?since=<ISO>
|
|
240
|
+
if (method === 'GET' && path === '/mesh/recovery/atoms') {
|
|
241
|
+
const since = url.searchParams.get('since');
|
|
242
|
+
const atoms = since ? store.getSince(since) : store.getAll();
|
|
243
|
+
return json(res, 200, atoms);
|
|
244
|
+
}
|
|
245
|
+
// POST /mesh/recovery/confirm — report confirmation or denial
|
|
246
|
+
if (method === 'POST' && path === '/mesh/recovery/confirm') {
|
|
247
|
+
let body;
|
|
248
|
+
try {
|
|
249
|
+
body = JSON.parse(await readBody(req));
|
|
250
|
+
}
|
|
251
|
+
catch (err) {
|
|
252
|
+
if (err.message === 'Payload too large') {
|
|
253
|
+
return json(res, 413, { error: 'Payload too large' });
|
|
254
|
+
}
|
|
255
|
+
return json(res, 400, { error: 'Invalid JSON' });
|
|
256
|
+
}
|
|
257
|
+
const { patternId, instanceHash, success } = body;
|
|
258
|
+
if (!patternId) {
|
|
259
|
+
return json(res, 400, { error: 'patternId is required' });
|
|
260
|
+
}
|
|
261
|
+
const atom = store.get(patternId);
|
|
262
|
+
if (!atom) {
|
|
263
|
+
return json(res, 404, { error: 'Pattern not found' });
|
|
264
|
+
}
|
|
265
|
+
if (success) {
|
|
266
|
+
store.recordConfirmation(patternId);
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
store.recordDenial(patternId);
|
|
270
|
+
}
|
|
271
|
+
return json(res, 200, {
|
|
272
|
+
id: patternId,
|
|
273
|
+
confidence: store.get(patternId).confidence,
|
|
274
|
+
confirmCount: store.get(patternId).confirmCount,
|
|
275
|
+
denyCount: store.get(patternId).denyCount,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
// GET /mesh/recovery/stats
|
|
279
|
+
if (method === 'GET' && path === '/mesh/recovery/stats') {
|
|
280
|
+
const stats = store.stats();
|
|
281
|
+
const all = store.getAll();
|
|
282
|
+
// Group by type
|
|
283
|
+
const byType = {};
|
|
284
|
+
const byProvider = {};
|
|
285
|
+
for (const atom of all) {
|
|
286
|
+
byType[atom.type] = (byType[atom.type] ?? 0) + 1;
|
|
287
|
+
byProvider[atom.provider] = (byProvider[atom.provider] ?? 0) + 1;
|
|
288
|
+
}
|
|
289
|
+
return json(res, 200, {
|
|
290
|
+
...stats,
|
|
291
|
+
byType,
|
|
292
|
+
byProvider,
|
|
293
|
+
topPatterns: all
|
|
294
|
+
.sort((a, b) => b.reportCount - a.reportCount)
|
|
295
|
+
.slice(0, 10)
|
|
296
|
+
.map(a => ({
|
|
297
|
+
id: a.id,
|
|
298
|
+
type: a.type,
|
|
299
|
+
provider: a.provider,
|
|
300
|
+
confidence: a.confidence,
|
|
301
|
+
reportCount: a.reportCount,
|
|
302
|
+
confirmCount: a.confirmCount,
|
|
303
|
+
})),
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
json(res, 404, { error: 'Not found' });
|
|
307
|
+
}
|
|
308
|
+
catch (err) {
|
|
309
|
+
if (err.message === 'Payload too large') {
|
|
310
|
+
return json(res, 413, { error: 'Payload too large' });
|
|
311
|
+
}
|
|
312
|
+
json(res, 500, { error: err.message ?? 'Internal error' });
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
server.listen(config.port);
|
|
316
|
+
return server;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Start a recovery mesh server with a fresh store.
|
|
320
|
+
*/
|
|
321
|
+
function startRecoveryMeshServer(config) {
|
|
322
|
+
const fullConfig = { ...exports.DEFAULT_RECOVERY_MESH_CONFIG, ...config };
|
|
323
|
+
const store = new recovery_mesh_js_1.MeshRecoveryAtomStore(fullConfig.expiryDays);
|
|
324
|
+
const server = createRecoveryMeshServer(store, fullConfig);
|
|
325
|
+
return {
|
|
326
|
+
store,
|
|
327
|
+
server,
|
|
328
|
+
stop() {
|
|
329
|
+
server.close();
|
|
330
|
+
},
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
//# sourceMappingURL=recovery-mesh-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-mesh-server.js","sourceRoot":"","sources":["../src/recovery-mesh-server.ts"],"names":[],"mappings":"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"}
|