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.
Files changed (153) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +263 -1
  3. package/configs/multi-provider.yaml +68 -0
  4. package/configs/openai-only.yaml +45 -0
  5. package/configs/team-setup.yaml +88 -0
  6. package/dist/action-logger.d.ts +128 -0
  7. package/dist/action-logger.js +356 -0
  8. package/dist/action-logger.js.map +1 -0
  9. package/dist/admin-cli.d.ts +2 -0
  10. package/dist/admin-cli.js +36 -0
  11. package/dist/admin-cli.js.map +1 -0
  12. package/dist/agents.d.ts +23 -0
  13. package/dist/agents.js +59 -0
  14. package/dist/agents.js.map +1 -0
  15. package/dist/alert-api.d.ts +14 -0
  16. package/dist/alert-api.js +355 -0
  17. package/dist/alert-api.js.map +1 -0
  18. package/dist/alert-manager.d.ts +77 -0
  19. package/dist/alert-manager.js +267 -0
  20. package/dist/alert-manager.js.map +1 -0
  21. package/dist/approval-api.d.ts +19 -0
  22. package/dist/approval-api.js +82 -0
  23. package/dist/approval-api.js.map +1 -0
  24. package/dist/approval-timeout.d.ts +29 -0
  25. package/dist/approval-timeout.js +45 -0
  26. package/dist/approval-timeout.js.map +1 -0
  27. package/dist/approval.d.ts +78 -0
  28. package/dist/approval.js +101 -0
  29. package/dist/approval.js.map +1 -0
  30. package/dist/auth.d.ts +47 -0
  31. package/dist/auth.js +335 -0
  32. package/dist/auth.js.map +1 -0
  33. package/dist/budget-api.d.ts +20 -0
  34. package/dist/budget-api.js +85 -0
  35. package/dist/budget-api.js.map +1 -0
  36. package/dist/budget-enforcer.d.ts +102 -0
  37. package/dist/budget-enforcer.js +294 -0
  38. package/dist/budget-enforcer.js.map +1 -0
  39. package/dist/cli.d.ts +15 -0
  40. package/dist/cli.js +200 -0
  41. package/dist/cli.js.map +1 -0
  42. package/dist/config.d.ts +15 -0
  43. package/dist/config.js +267 -0
  44. package/dist/config.js.map +1 -0
  45. package/dist/cost-aggregator.d.ts +69 -0
  46. package/dist/cost-aggregator.js +305 -0
  47. package/dist/cost-aggregator.js.map +1 -0
  48. package/dist/cost-api.d.ts +29 -0
  49. package/dist/cost-api.js +128 -0
  50. package/dist/cost-api.js.map +1 -0
  51. package/dist/database-url.d.ts +6 -0
  52. package/dist/database-url.js +47 -0
  53. package/dist/database-url.js.map +1 -0
  54. package/dist/db-retention.d.ts +53 -0
  55. package/dist/db-retention.js +82 -0
  56. package/dist/db-retention.js.map +1 -0
  57. package/dist/db-schema.d.ts +17 -0
  58. package/dist/db-schema.js +167 -0
  59. package/dist/db-schema.js.map +1 -0
  60. package/dist/db-writer.d.ts +55 -0
  61. package/dist/db-writer.js +115 -0
  62. package/dist/db-writer.js.map +1 -0
  63. package/dist/db.d.ts +33 -0
  64. package/dist/db.js +78 -0
  65. package/dist/db.js.map +1 -0
  66. package/dist/events.d.ts +77 -0
  67. package/dist/events.js +12 -0
  68. package/dist/events.js.map +1 -0
  69. package/dist/health.d.ts +14 -0
  70. package/dist/health.js +49 -0
  71. package/dist/health.js.map +1 -0
  72. package/dist/index.d.ts +7 -0
  73. package/dist/index.js +14 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/init-wizard.d.ts +12 -0
  76. package/dist/init-wizard.js +206 -0
  77. package/dist/init-wizard.js.map +1 -0
  78. package/dist/log-api.d.ts +20 -0
  79. package/dist/log-api.js +371 -0
  80. package/dist/log-api.js.map +1 -0
  81. package/dist/log-rotator.d.ts +55 -0
  82. package/dist/log-rotator.js +157 -0
  83. package/dist/log-rotator.js.map +1 -0
  84. package/dist/loop-detector.d.ts +71 -0
  85. package/dist/loop-detector.js +122 -0
  86. package/dist/loop-detector.js.map +1 -0
  87. package/dist/persistence-types.d.ts +165 -0
  88. package/dist/persistence-types.js +2 -0
  89. package/dist/persistence-types.js.map +1 -0
  90. package/dist/persistence.d.ts +185 -0
  91. package/dist/persistence.js +785 -0
  92. package/dist/persistence.js.map +1 -0
  93. package/dist/policy-api.d.ts +25 -0
  94. package/dist/policy-api.js +347 -0
  95. package/dist/policy-api.js.map +1 -0
  96. package/dist/policy-engine.d.ts +76 -0
  97. package/dist/policy-engine.js +835 -0
  98. package/dist/policy-engine.js.map +1 -0
  99. package/dist/policy-file.d.ts +10 -0
  100. package/dist/policy-file.js +52 -0
  101. package/dist/policy-file.js.map +1 -0
  102. package/dist/policy-parser.d.ts +21 -0
  103. package/dist/policy-parser.js +560 -0
  104. package/dist/policy-parser.js.map +1 -0
  105. package/dist/policy-types.d.ts +216 -0
  106. package/dist/policy-types.js +8 -0
  107. package/dist/policy-types.js.map +1 -0
  108. package/dist/policy-watcher.d.ts +54 -0
  109. package/dist/policy-watcher.js +116 -0
  110. package/dist/policy-watcher.js.map +1 -0
  111. package/dist/pricing.d.ts +69 -0
  112. package/dist/pricing.js +93 -0
  113. package/dist/pricing.js.map +1 -0
  114. package/dist/prompt.d.ts +6 -0
  115. package/dist/prompt.js +47 -0
  116. package/dist/prompt.js.map +1 -0
  117. package/dist/providers/anthropic.d.ts +18 -0
  118. package/dist/providers/anthropic.js +61 -0
  119. package/dist/providers/anthropic.js.map +1 -0
  120. package/dist/providers/custom.d.ts +19 -0
  121. package/dist/providers/custom.js +54 -0
  122. package/dist/providers/custom.js.map +1 -0
  123. package/dist/providers/openai.d.ts +17 -0
  124. package/dist/providers/openai.js +48 -0
  125. package/dist/providers/openai.js.map +1 -0
  126. package/dist/proxy.d.ts +57 -0
  127. package/dist/proxy.js +477 -0
  128. package/dist/proxy.js.map +1 -0
  129. package/dist/router.d.ts +23 -0
  130. package/dist/router.js +89 -0
  131. package/dist/router.js.map +1 -0
  132. package/dist/runtime.d.ts +1 -0
  133. package/dist/runtime.js +139 -0
  134. package/dist/runtime.js.map +1 -0
  135. package/dist/security.d.ts +64 -0
  136. package/dist/security.js +422 -0
  137. package/dist/security.js.map +1 -0
  138. package/dist/server.d.ts +33 -0
  139. package/dist/server.js +1147 -0
  140. package/dist/server.js.map +1 -0
  141. package/dist/sqlite-schema.d.ts +6 -0
  142. package/dist/sqlite-schema.js +134 -0
  143. package/dist/sqlite-schema.js.map +1 -0
  144. package/dist/streaming.d.ts +24 -0
  145. package/dist/streaming.js +63 -0
  146. package/dist/streaming.js.map +1 -0
  147. package/dist/tokens.d.ts +45 -0
  148. package/dist/tokens.js +237 -0
  149. package/dist/tokens.js.map +1 -0
  150. package/dist/types.d.ts +344 -0
  151. package/dist/types.js +5 -0
  152. package/dist/types.js.map +1 -0
  153. 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,2 @@
1
+ export declare function runAdminSetup(authFile?: string): Promise<void>;
2
+ export declare function runAdminResetPassword(authFile?: string): Promise<void>;
@@ -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"}
@@ -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;