govyn 0.0.1 → 0.2.5
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/LICENSE +21 -0
- package/README.md +263 -1
- package/configs/multi-provider.yaml +68 -0
- package/configs/openai-only.yaml +45 -0
- package/configs/team-setup.yaml +88 -0
- package/dist/action-logger.d.ts +128 -0
- package/dist/action-logger.js +356 -0
- package/dist/action-logger.js.map +1 -0
- package/dist/admin-cli.d.ts +2 -0
- package/dist/admin-cli.js +36 -0
- package/dist/admin-cli.js.map +1 -0
- package/dist/agents.d.ts +23 -0
- package/dist/agents.js +59 -0
- package/dist/agents.js.map +1 -0
- package/dist/alert-api.d.ts +14 -0
- package/dist/alert-api.js +355 -0
- package/dist/alert-api.js.map +1 -0
- package/dist/alert-manager.d.ts +77 -0
- package/dist/alert-manager.js +267 -0
- package/dist/alert-manager.js.map +1 -0
- package/dist/approval-api.d.ts +19 -0
- package/dist/approval-api.js +82 -0
- package/dist/approval-api.js.map +1 -0
- package/dist/approval-timeout.d.ts +29 -0
- package/dist/approval-timeout.js +45 -0
- package/dist/approval-timeout.js.map +1 -0
- package/dist/approval.d.ts +78 -0
- package/dist/approval.js +101 -0
- package/dist/approval.js.map +1 -0
- package/dist/auth.d.ts +47 -0
- package/dist/auth.js +335 -0
- package/dist/auth.js.map +1 -0
- package/dist/budget-api.d.ts +20 -0
- package/dist/budget-api.js +85 -0
- package/dist/budget-api.js.map +1 -0
- package/dist/budget-enforcer.d.ts +102 -0
- package/dist/budget-enforcer.js +294 -0
- package/dist/budget-enforcer.js.map +1 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.js +200 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.js +267 -0
- package/dist/config.js.map +1 -0
- package/dist/cost-aggregator.d.ts +69 -0
- package/dist/cost-aggregator.js +305 -0
- package/dist/cost-aggregator.js.map +1 -0
- package/dist/cost-api.d.ts +29 -0
- package/dist/cost-api.js +128 -0
- package/dist/cost-api.js.map +1 -0
- package/dist/database-url.d.ts +6 -0
- package/dist/database-url.js +47 -0
- package/dist/database-url.js.map +1 -0
- package/dist/db-retention.d.ts +53 -0
- package/dist/db-retention.js +82 -0
- package/dist/db-retention.js.map +1 -0
- package/dist/db-schema.d.ts +17 -0
- package/dist/db-schema.js +167 -0
- package/dist/db-schema.js.map +1 -0
- package/dist/db-writer.d.ts +55 -0
- package/dist/db-writer.js +115 -0
- package/dist/db-writer.js.map +1 -0
- package/dist/db.d.ts +33 -0
- package/dist/db.js +78 -0
- package/dist/db.js.map +1 -0
- package/dist/events.d.ts +77 -0
- package/dist/events.js +12 -0
- package/dist/events.js.map +1 -0
- package/dist/health.d.ts +14 -0
- package/dist/health.js +49 -0
- package/dist/health.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/init-wizard.d.ts +12 -0
- package/dist/init-wizard.js +206 -0
- package/dist/init-wizard.js.map +1 -0
- package/dist/log-api.d.ts +20 -0
- package/dist/log-api.js +371 -0
- package/dist/log-api.js.map +1 -0
- package/dist/log-rotator.d.ts +55 -0
- package/dist/log-rotator.js +157 -0
- package/dist/log-rotator.js.map +1 -0
- package/dist/loop-detector.d.ts +71 -0
- package/dist/loop-detector.js +122 -0
- package/dist/loop-detector.js.map +1 -0
- package/dist/persistence-types.d.ts +165 -0
- package/dist/persistence-types.js +2 -0
- package/dist/persistence-types.js.map +1 -0
- package/dist/persistence.d.ts +185 -0
- package/dist/persistence.js +785 -0
- package/dist/persistence.js.map +1 -0
- package/dist/policy-api.d.ts +25 -0
- package/dist/policy-api.js +347 -0
- package/dist/policy-api.js.map +1 -0
- package/dist/policy-engine.d.ts +76 -0
- package/dist/policy-engine.js +835 -0
- package/dist/policy-engine.js.map +1 -0
- package/dist/policy-file.d.ts +10 -0
- package/dist/policy-file.js +52 -0
- package/dist/policy-file.js.map +1 -0
- package/dist/policy-parser.d.ts +21 -0
- package/dist/policy-parser.js +560 -0
- package/dist/policy-parser.js.map +1 -0
- package/dist/policy-types.d.ts +216 -0
- package/dist/policy-types.js +8 -0
- package/dist/policy-types.js.map +1 -0
- package/dist/policy-watcher.d.ts +54 -0
- package/dist/policy-watcher.js +116 -0
- package/dist/policy-watcher.js.map +1 -0
- package/dist/pricing.d.ts +69 -0
- package/dist/pricing.js +93 -0
- package/dist/pricing.js.map +1 -0
- package/dist/prompt.d.ts +6 -0
- package/dist/prompt.js +47 -0
- package/dist/prompt.js.map +1 -0
- package/dist/providers/anthropic.d.ts +18 -0
- package/dist/providers/anthropic.js +61 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/custom.d.ts +19 -0
- package/dist/providers/custom.js +54 -0
- package/dist/providers/custom.js.map +1 -0
- package/dist/providers/openai.d.ts +17 -0
- package/dist/providers/openai.js +48 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/proxy.d.ts +57 -0
- package/dist/proxy.js +477 -0
- package/dist/proxy.js.map +1 -0
- package/dist/router.d.ts +23 -0
- package/dist/router.js +89 -0
- package/dist/router.js.map +1 -0
- package/dist/runtime.d.ts +1 -0
- package/dist/runtime.js +139 -0
- package/dist/runtime.js.map +1 -0
- package/dist/security.d.ts +64 -0
- package/dist/security.js +422 -0
- package/dist/security.js.map +1 -0
- package/dist/server.d.ts +33 -0
- package/dist/server.js +1147 -0
- package/dist/server.js.map +1 -0
- package/dist/sqlite-schema.d.ts +6 -0
- package/dist/sqlite-schema.js +134 -0
- package/dist/sqlite-schema.js.map +1 -0
- package/dist/streaming.d.ts +24 -0
- package/dist/streaming.js +63 -0
- package/dist/streaming.js.map +1 -0
- package/dist/tokens.d.ts +45 -0
- package/dist/tokens.js +237 -0
- package/dist/tokens.js.map +1 -0
- package/dist/types.d.ts +344 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +66 -2
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async action logger for the Govyn proxy server.
|
|
3
|
+
*
|
|
4
|
+
* Writes structured JSONL log entries for every proxied request.
|
|
5
|
+
* Supports two modes:
|
|
6
|
+
* - metadata: summary fields only (default)
|
|
7
|
+
* - full-payload: stores request/response bodies as separate JSON files
|
|
8
|
+
*
|
|
9
|
+
* Design:
|
|
10
|
+
* - log() is synchronous and non-blocking (zero added latency)
|
|
11
|
+
* - Entries are buffered in memory and flushed to disk on a 1-second interval
|
|
12
|
+
* - storePayload() is fire-and-forget async (errors logged to stderr)
|
|
13
|
+
* - Dual output: stdout AND/OR file, either disableable in config
|
|
14
|
+
*/
|
|
15
|
+
import * as fs from 'node:fs';
|
|
16
|
+
import * as path from 'node:path';
|
|
17
|
+
import * as crypto from 'node:crypto';
|
|
18
|
+
import * as zlib from 'node:zlib';
|
|
19
|
+
import { LogRotator } from './log-rotator.js';
|
|
20
|
+
/**
|
|
21
|
+
* ActionLogger writes structured JSONL log entries for proxied requests.
|
|
22
|
+
*
|
|
23
|
+
* Non-blocking by design: log() pushes to an in-memory buffer that is
|
|
24
|
+
* flushed to disk on a 1-second unref'd interval. storePayload() writes
|
|
25
|
+
* payload files asynchronously without awaiting in the request path.
|
|
26
|
+
*/
|
|
27
|
+
export class ActionLogger {
|
|
28
|
+
/** Exposed config for consumers that need to read settings (e.g., maxBodySize) */
|
|
29
|
+
config;
|
|
30
|
+
/** Internal write buffer — entries waiting to be flushed to disk */
|
|
31
|
+
buffer = [];
|
|
32
|
+
/** Path to the current active JSONL log file */
|
|
33
|
+
currentFilePath;
|
|
34
|
+
/** Path to the payloads subdirectory */
|
|
35
|
+
payloadsDir;
|
|
36
|
+
/** Periodic flush interval handle */
|
|
37
|
+
flushInterval = null;
|
|
38
|
+
/** Log rotator for size/time-based rotation and retention cleanup */
|
|
39
|
+
rotator;
|
|
40
|
+
constructor(config) {
|
|
41
|
+
this.config = config;
|
|
42
|
+
// Create log directory and payloads subdirectory
|
|
43
|
+
const logDir = path.resolve(config.directory);
|
|
44
|
+
this.payloadsDir = path.join(logDir, 'payloads');
|
|
45
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
46
|
+
fs.mkdirSync(this.payloadsDir, { recursive: true });
|
|
47
|
+
// Build initial JSONL file path: govyn-YYYY-MM-DD.jsonl
|
|
48
|
+
const dateStr = new Date().toISOString().slice(0, 10);
|
|
49
|
+
this.currentFilePath = path.join(logDir, `govyn-${dateStr}.jsonl`);
|
|
50
|
+
// Create log rotator for rotation and retention
|
|
51
|
+
this.rotator = new LogRotator(config);
|
|
52
|
+
// Start periodic flush (every 1 second, unref'd so it doesn't keep the process alive)
|
|
53
|
+
if (config.file) {
|
|
54
|
+
this.flushInterval = setInterval(() => this.flush(), 1000);
|
|
55
|
+
this.flushInterval.unref();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Read-only access to the log directory path.
|
|
60
|
+
* Used by the log query API to locate JSONL files.
|
|
61
|
+
*/
|
|
62
|
+
get logDirectory() {
|
|
63
|
+
return this.config.directory;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get the full filesystem path to a payload file.
|
|
67
|
+
*
|
|
68
|
+
* @param payloadId - The payload ID (used as filename stem)
|
|
69
|
+
* @returns Full path to the payload JSON file
|
|
70
|
+
*/
|
|
71
|
+
getPayloadPath(payloadId) {
|
|
72
|
+
return path.join(this.payloadsDir, `${payloadId}.json`);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Log a structured entry. Non-blocking — adds to buffer and optionally writes to stdout.
|
|
76
|
+
* This is the zero-latency guarantee: no file I/O in the hot path.
|
|
77
|
+
* Automatically sets storage_region from config if not already set on the entry.
|
|
78
|
+
*
|
|
79
|
+
* @param entry - The structured log entry to record
|
|
80
|
+
*/
|
|
81
|
+
log(entry) {
|
|
82
|
+
// Ensure storage_region is set from config
|
|
83
|
+
if (!entry.storage_region) {
|
|
84
|
+
entry.storage_region = this.config.storageRegion;
|
|
85
|
+
}
|
|
86
|
+
const line = JSON.stringify(entry);
|
|
87
|
+
if (this.config.stdout) {
|
|
88
|
+
process.stdout.write(line + '\n');
|
|
89
|
+
}
|
|
90
|
+
if (this.config.file) {
|
|
91
|
+
this.buffer.push(line);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Store a full payload (request + response bodies) as a separate JSON file.
|
|
96
|
+
* Fully async — fire and forget. Errors are logged to stderr but never thrown.
|
|
97
|
+
*
|
|
98
|
+
* @param payloadId - Unique ID for this payload (used as filename)
|
|
99
|
+
* @param requestBody - Raw request body buffer (or null)
|
|
100
|
+
* @param responseBody - Raw response body buffer (or null)
|
|
101
|
+
* @param truncated - Whether either body was truncated due to size limits
|
|
102
|
+
*/
|
|
103
|
+
storePayload(payloadId, requestBody, responseBody, truncated) {
|
|
104
|
+
const maxSize = this.config.maxBodySize;
|
|
105
|
+
// Truncate bodies if they exceed maxBodySize
|
|
106
|
+
let reqBody = requestBody;
|
|
107
|
+
let resBody = responseBody;
|
|
108
|
+
let wasTruncated = truncated;
|
|
109
|
+
if (reqBody && reqBody.length > maxSize) {
|
|
110
|
+
reqBody = reqBody.subarray(0, maxSize);
|
|
111
|
+
wasTruncated = true;
|
|
112
|
+
}
|
|
113
|
+
if (resBody && resBody.length > maxSize) {
|
|
114
|
+
resBody = resBody.subarray(0, maxSize);
|
|
115
|
+
wasTruncated = true;
|
|
116
|
+
}
|
|
117
|
+
const payload = {
|
|
118
|
+
request_body: reqBody ? reqBody.toString('base64') : null,
|
|
119
|
+
response_body: resBody ? resBody.toString('base64') : null,
|
|
120
|
+
truncated: wasTruncated,
|
|
121
|
+
stored_at: new Date().toISOString(),
|
|
122
|
+
};
|
|
123
|
+
const filePath = path.join(this.payloadsDir, `${payloadId}.json`);
|
|
124
|
+
// Fire and forget — async write, errors go to stderr
|
|
125
|
+
fs.promises.writeFile(filePath, JSON.stringify(payload), 'utf8').catch((err) => {
|
|
126
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
127
|
+
process.stderr.write(`[govyn] Failed to store payload ${payloadId}: ${message}\n`);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Flush buffered entries to the current JSONL file.
|
|
132
|
+
* Uses synchronous append to ensure atomicity of the batch write.
|
|
133
|
+
*/
|
|
134
|
+
flush() {
|
|
135
|
+
if (this.buffer.length === 0)
|
|
136
|
+
return;
|
|
137
|
+
// Check rotation before writing
|
|
138
|
+
try {
|
|
139
|
+
if (fs.existsSync(this.currentFilePath)) {
|
|
140
|
+
const result = this.rotator.checkRotation(this.currentFilePath);
|
|
141
|
+
if (result.shouldRotate) {
|
|
142
|
+
const freshPath = this.rotator.rotate(this.currentFilePath);
|
|
143
|
+
this.currentFilePath = freshPath;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
149
|
+
process.stderr.write(`[govyn] Rotation check failed: ${message}\n`);
|
|
150
|
+
}
|
|
151
|
+
const lines = this.buffer.join('\n') + '\n';
|
|
152
|
+
this.buffer = [];
|
|
153
|
+
try {
|
|
154
|
+
fs.appendFileSync(this.currentFilePath, lines, 'utf8');
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
158
|
+
process.stderr.write(`[govyn] Failed to flush log entries: ${message}\n`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get the logging mode for a specific agent.
|
|
163
|
+
* Returns the agent-specific override if set, otherwise the default mode.
|
|
164
|
+
*
|
|
165
|
+
* @param agentId - The agent to look up
|
|
166
|
+
* @returns The LoggingMode to use for this agent
|
|
167
|
+
*/
|
|
168
|
+
getMode(agentId) {
|
|
169
|
+
return this.config.agentModes.get(agentId) ?? this.config.defaultMode;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Set the logging mode for a specific agent at runtime.
|
|
173
|
+
* Does NOT persist to YAML — runtime-only toggle.
|
|
174
|
+
*
|
|
175
|
+
* @param agentId - The agent to configure
|
|
176
|
+
* @param mode - The logging mode to set
|
|
177
|
+
*/
|
|
178
|
+
setMode(agentId, mode) {
|
|
179
|
+
this.config.agentModes.set(agentId, mode);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Get the path of the current active JSONL log file.
|
|
183
|
+
* Useful for rotation logic and diagnostics.
|
|
184
|
+
*/
|
|
185
|
+
getCurrentFilePath() {
|
|
186
|
+
return this.currentFilePath;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Purge all log entries and associated payload files older than the given date.
|
|
190
|
+
*
|
|
191
|
+
* - Reads all JSONL files (current + rotated) in the log directory
|
|
192
|
+
* - For each file: filters out entries with timestamps before the date
|
|
193
|
+
* - Deletes payload files for removed entries that have has_payload=true
|
|
194
|
+
* - Handles gzipped rotated files: decompress, filter, recompress or delete
|
|
195
|
+
* - Returns counts of deleted log entries and deleted payload files
|
|
196
|
+
*
|
|
197
|
+
* @param date - Purge entries with timestamps strictly before this date
|
|
198
|
+
* @returns Counts of deleted log entries and payload files
|
|
199
|
+
*/
|
|
200
|
+
purgeBefore(date) {
|
|
201
|
+
// Flush buffer first so all entries are on disk
|
|
202
|
+
this.flush();
|
|
203
|
+
const logDir = path.resolve(this.config.directory);
|
|
204
|
+
const dateIso = date.toISOString();
|
|
205
|
+
let deletedLogs = 0;
|
|
206
|
+
let deletedPayloads = 0;
|
|
207
|
+
if (!fs.existsSync(logDir)) {
|
|
208
|
+
return { deletedLogs, deletedPayloads };
|
|
209
|
+
}
|
|
210
|
+
const files = fs.readdirSync(logDir);
|
|
211
|
+
for (const file of files) {
|
|
212
|
+
const filePath = path.join(logDir, file);
|
|
213
|
+
if (file.endsWith('.jsonl')) {
|
|
214
|
+
// Process uncompressed JSONL files
|
|
215
|
+
const result = this.purgeJsonlFile(filePath, dateIso);
|
|
216
|
+
deletedLogs += result.deletedLogs;
|
|
217
|
+
deletedPayloads += result.deletedPayloads;
|
|
218
|
+
}
|
|
219
|
+
else if (file.endsWith('.jsonl.gz')) {
|
|
220
|
+
// Process gzipped rotated files
|
|
221
|
+
const result = this.purgeGzipFile(filePath, dateIso);
|
|
222
|
+
deletedLogs += result.deletedLogs;
|
|
223
|
+
deletedPayloads += result.deletedPayloads;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return { deletedLogs, deletedPayloads };
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Purge entries from a plain JSONL file.
|
|
230
|
+
* Rewrites the file with only entries newer than the cutoff date.
|
|
231
|
+
*/
|
|
232
|
+
purgeJsonlFile(filePath, dateIso) {
|
|
233
|
+
let deletedLogs = 0;
|
|
234
|
+
let deletedPayloads = 0;
|
|
235
|
+
try {
|
|
236
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
237
|
+
const lines = content.trim().split('\n').filter((l) => l.length > 0);
|
|
238
|
+
const kept = [];
|
|
239
|
+
for (const line of lines) {
|
|
240
|
+
try {
|
|
241
|
+
const entry = JSON.parse(line);
|
|
242
|
+
if (entry.timestamp < dateIso) {
|
|
243
|
+
// Entry is older than cutoff — remove it
|
|
244
|
+
deletedLogs++;
|
|
245
|
+
// Delete associated payload file if present
|
|
246
|
+
if (entry.has_payload && entry.payload_id) {
|
|
247
|
+
const payloadPath = path.join(this.payloadsDir, `${entry.payload_id}.json`);
|
|
248
|
+
try {
|
|
249
|
+
if (fs.existsSync(payloadPath)) {
|
|
250
|
+
fs.unlinkSync(payloadPath);
|
|
251
|
+
deletedPayloads++;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
// Skip payload deletion errors
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
kept.push(line);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
// Keep malformed lines (don't delete data we can't parse)
|
|
265
|
+
kept.push(line);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
// Rewrite file with kept entries
|
|
269
|
+
if (kept.length === 0) {
|
|
270
|
+
fs.writeFileSync(filePath, '', 'utf8');
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
fs.writeFileSync(filePath, kept.join('\n') + '\n', 'utf8');
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
catch (err) {
|
|
277
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
278
|
+
process.stderr.write(`[govyn] Purge error for ${filePath}: ${message}\n`);
|
|
279
|
+
}
|
|
280
|
+
return { deletedLogs, deletedPayloads };
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Purge entries from a gzipped rotated JSONL file.
|
|
284
|
+
* Decompresses, filters, and either recompresses or deletes if empty.
|
|
285
|
+
*/
|
|
286
|
+
purgeGzipFile(filePath, dateIso) {
|
|
287
|
+
let deletedLogs = 0;
|
|
288
|
+
let deletedPayloads = 0;
|
|
289
|
+
try {
|
|
290
|
+
const compressed = fs.readFileSync(filePath);
|
|
291
|
+
const content = zlib.gunzipSync(compressed).toString('utf8');
|
|
292
|
+
const lines = content.trim().split('\n').filter((l) => l.length > 0);
|
|
293
|
+
const kept = [];
|
|
294
|
+
for (const line of lines) {
|
|
295
|
+
try {
|
|
296
|
+
const entry = JSON.parse(line);
|
|
297
|
+
if (entry.timestamp < dateIso) {
|
|
298
|
+
deletedLogs++;
|
|
299
|
+
if (entry.has_payload && entry.payload_id) {
|
|
300
|
+
const payloadPath = path.join(this.payloadsDir, `${entry.payload_id}.json`);
|
|
301
|
+
try {
|
|
302
|
+
if (fs.existsSync(payloadPath)) {
|
|
303
|
+
fs.unlinkSync(payloadPath);
|
|
304
|
+
deletedPayloads++;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
// Skip payload deletion errors
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
kept.push(line);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
kept.push(line);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (kept.length === 0) {
|
|
321
|
+
// All entries removed — delete the gzip file
|
|
322
|
+
fs.unlinkSync(filePath);
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
// Recompress with remaining entries
|
|
326
|
+
const newContent = kept.join('\n') + '\n';
|
|
327
|
+
const recompressed = zlib.gzipSync(Buffer.from(newContent, 'utf8'));
|
|
328
|
+
fs.writeFileSync(filePath, recompressed);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
catch (err) {
|
|
332
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
333
|
+
process.stderr.write(`[govyn] Purge error for gzip ${filePath}: ${message}\n`);
|
|
334
|
+
}
|
|
335
|
+
return { deletedLogs, deletedPayloads };
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Close the logger: flush remaining buffer and stop the flush interval.
|
|
339
|
+
*/
|
|
340
|
+
close() {
|
|
341
|
+
this.flush();
|
|
342
|
+
if (this.flushInterval !== null) {
|
|
343
|
+
clearInterval(this.flushInterval);
|
|
344
|
+
this.flushInterval = null;
|
|
345
|
+
}
|
|
346
|
+
this.rotator.stop();
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Generate a unique ID for log entries and payload files.
|
|
350
|
+
* Uses crypto.randomUUID() for guaranteed uniqueness.
|
|
351
|
+
*/
|
|
352
|
+
static generateId() {
|
|
353
|
+
return crypto.randomUUID();
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
//# sourceMappingURL=action-logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-logger.js","sourceRoot":"","sources":["../src/action-logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { LocalAuthManager, DEFAULT_AUTH_FILE } from './auth.js';
|
|
2
|
+
import { createPrompt } from './prompt.js';
|
|
3
|
+
export async function runAdminSetup(authFile = DEFAULT_AUTH_FILE) {
|
|
4
|
+
const authManager = new LocalAuthManager(authFile);
|
|
5
|
+
const { ask, askHidden, close } = createPrompt();
|
|
6
|
+
try {
|
|
7
|
+
const username = (await ask("Admin username (default: 'admin'): ")) || 'admin';
|
|
8
|
+
const password = await askHidden('Admin password: ');
|
|
9
|
+
const confirmation = await askHidden('Confirm password: ');
|
|
10
|
+
if (password !== confirmation) {
|
|
11
|
+
throw new Error('Passwords did not match');
|
|
12
|
+
}
|
|
13
|
+
const normalizedUsername = authManager.setupAdmin(username, password);
|
|
14
|
+
console.log(`[govyn] Local admin "${normalizedUsername}" created at ${authManager.authFile}`);
|
|
15
|
+
}
|
|
16
|
+
finally {
|
|
17
|
+
close();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export async function runAdminResetPassword(authFile = DEFAULT_AUTH_FILE) {
|
|
21
|
+
const authManager = new LocalAuthManager(authFile);
|
|
22
|
+
const { askHidden, close } = createPrompt();
|
|
23
|
+
try {
|
|
24
|
+
const password = await askHidden('New admin password: ');
|
|
25
|
+
const confirmation = await askHidden('Confirm new password: ');
|
|
26
|
+
if (password !== confirmation) {
|
|
27
|
+
throw new Error('Passwords did not match');
|
|
28
|
+
}
|
|
29
|
+
const username = authManager.resetPassword(password);
|
|
30
|
+
console.log(`[govyn] Password reset for "${username}" using ${authManager.authFile}`);
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
close();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=admin-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-cli.js","sourceRoot":"","sources":["../src/admin-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAQ,GAAG,iBAAiB;IAC9D,MAAM,WAAW,GAAG,IAAI,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACnD,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,YAAY,EAAE,CAAC;IAEjD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,CAAC,MAAM,GAAG,CAAC,qCAAqC,CAAC,CAAC,IAAI,OAAO,CAAC;QAC/E,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,kBAAkB,CAAC,CAAC;QACrD,MAAM,YAAY,GAAG,MAAM,SAAS,CAAC,oBAAoB,CAAC,CAAC;QAE3D,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,kBAAkB,GAAG,WAAW,CAAC,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACtE,OAAO,CAAC,GAAG,CAAC,wBAAwB,kBAAkB,gBAAgB,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC;IAChG,CAAC;YAAS,CAAC;QACT,KAAK,EAAE,CAAC;IACV,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,QAAQ,GAAG,iBAAiB;IACtE,MAAM,WAAW,GAAG,IAAI,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACnD,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,YAAY,EAAE,CAAC;IAE5C,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,sBAAsB,CAAC,CAAC;QACzD,MAAM,YAAY,GAAG,MAAM,SAAS,CAAC,wBAAwB,CAAC,CAAC;QAE/D,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,QAAQ,GAAG,WAAW,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,CAAC,+BAA+B,QAAQ,WAAW,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC;IACxF,CAAC;YAAS,CAAC;QACT,KAAK,EAAE,CAAC;IACV,CAAC;AACH,CAAC"}
|
package/dist/agents.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent identification module for the Govyn proxy server.
|
|
3
|
+
*
|
|
4
|
+
* Resolves the identity of the agent making a request using:
|
|
5
|
+
* 1. X-Govyn-Agent header (self-identified, highest priority)
|
|
6
|
+
* 2. API key scoped to an agent (from Authorization Bearer token)
|
|
7
|
+
* 3. Default 'unknown' agent
|
|
8
|
+
*/
|
|
9
|
+
import type { IncomingMessage } from 'node:http';
|
|
10
|
+
import type { AgentConfig, AgentIdentity } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Resolve the agent identity from an incoming HTTP request.
|
|
13
|
+
*
|
|
14
|
+
* Resolution order (per ADR-014):
|
|
15
|
+
* 1. X-Govyn-Agent header — any string is accepted (agents self-identify; no config lookup)
|
|
16
|
+
* 2. Authorization Bearer token — looked up in the agents map for API key scoping
|
|
17
|
+
* 3. Default — returns { agentId: 'unknown', source: 'default' }
|
|
18
|
+
*
|
|
19
|
+
* @param req - Incoming HTTP request
|
|
20
|
+
* @param agents - Map of agent name to AgentConfig (from ProxyConfig)
|
|
21
|
+
* @returns Resolved AgentIdentity
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveAgentId(req: IncomingMessage, agents: Map<string, AgentConfig>): AgentIdentity;
|
package/dist/agents.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent identification module for the Govyn proxy server.
|
|
3
|
+
*
|
|
4
|
+
* Resolves the identity of the agent making a request using:
|
|
5
|
+
* 1. X-Govyn-Agent header (self-identified, highest priority)
|
|
6
|
+
* 2. API key scoped to an agent (from Authorization Bearer token)
|
|
7
|
+
* 3. Default 'unknown' agent
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Resolve the agent identity from an incoming HTTP request.
|
|
11
|
+
*
|
|
12
|
+
* Resolution order (per ADR-014):
|
|
13
|
+
* 1. X-Govyn-Agent header — any string is accepted (agents self-identify; no config lookup)
|
|
14
|
+
* 2. Authorization Bearer token — looked up in the agents map for API key scoping
|
|
15
|
+
* 3. Default — returns { agentId: 'unknown', source: 'default' }
|
|
16
|
+
*
|
|
17
|
+
* @param req - Incoming HTTP request
|
|
18
|
+
* @param agents - Map of agent name to AgentConfig (from ProxyConfig)
|
|
19
|
+
* @returns Resolved AgentIdentity
|
|
20
|
+
*/
|
|
21
|
+
export function resolveAgentId(req, agents) {
|
|
22
|
+
// Priority 1: Authorization Bearer token matched against agent API keys.
|
|
23
|
+
// Authenticated identity must win over self-declared headers to prevent impersonation.
|
|
24
|
+
const authHeader = req.headers['authorization'];
|
|
25
|
+
if (authHeader) {
|
|
26
|
+
const token = extractBearerToken(authHeader);
|
|
27
|
+
if (token) {
|
|
28
|
+
for (const [agentName, agentConfig] of agents) {
|
|
29
|
+
if (agentConfig.apiKeys && agentConfig.apiKeys.includes(token)) {
|
|
30
|
+
return { agentId: agentName, source: 'api-key' };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Priority 2: X-Govyn-Agent header (case-insensitive — Node.js lowercases all headers)
|
|
36
|
+
const agentHeader = req.headers['x-govyn-agent'];
|
|
37
|
+
if (agentHeader) {
|
|
38
|
+
const agentId = Array.isArray(agentHeader) ? agentHeader[0] : agentHeader;
|
|
39
|
+
if (agentId && agentId.trim().length > 0) {
|
|
40
|
+
return { agentId: agentId.trim(), source: 'header' };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Priority 3: Default unknown agent
|
|
44
|
+
return { agentId: 'unknown', source: 'default' };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Extract Bearer token from an Authorization header value.
|
|
48
|
+
*
|
|
49
|
+
* @param authHeader - Raw Authorization header value (e.g. "Bearer gvn_ra_xxxx")
|
|
50
|
+
* @returns The token string, or null if not a Bearer token
|
|
51
|
+
*/
|
|
52
|
+
function extractBearerToken(authHeader) {
|
|
53
|
+
const header = Array.isArray(authHeader) ? authHeader[0] : authHeader;
|
|
54
|
+
if (!header)
|
|
55
|
+
return null;
|
|
56
|
+
const match = /^Bearer\s+(.+)$/i.exec(header.trim());
|
|
57
|
+
return match ? (match[1] ?? null) : null;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=agents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAoB,EACpB,MAAgC;IAEhC,yEAAyE;IACzE,uFAAuF;IACvF,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAChD,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,KAAK,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;QAC7C,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,MAAM,EAAE,CAAC;gBAC9C,IAAI,WAAW,CAAC,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC/D,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;gBACnD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,uFAAuF;IACvF,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IACjD,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QAC1E,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QACvD,CAAC;IACH,CAAC;IAED,oCAAoC;IACpC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AACnD,CAAC;AAED;;;;;GAKG;AACH,SAAS,kBAAkB,CAAC,UAA6B;IACvD,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IACtE,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACrD,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alert API handler for the Govyn proxy.
|
|
3
|
+
*
|
|
4
|
+
* Handles all /api/alerts/* routes:
|
|
5
|
+
* - GET /api/alerts/rules — list all alert rules
|
|
6
|
+
* - POST /api/alerts/rules — create a new alert rule
|
|
7
|
+
* - PUT /api/alerts/rules/:id — update an existing rule
|
|
8
|
+
* - DELETE /api/alerts/rules/:id — delete a rule
|
|
9
|
+
* - GET /api/alerts/history — list alert history with pagination
|
|
10
|
+
* - POST /api/alerts/test — test webhook delivery
|
|
11
|
+
*/
|
|
12
|
+
import type http from 'node:http';
|
|
13
|
+
import type { AlertManager } from './alert-manager.js';
|
|
14
|
+
export declare function handleAlertApi(req: http.IncomingMessage, res: http.ServerResponse, alertManager: AlertManager): void;
|