paygate-mcp 6.9.0 → 7.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.
- package/README.md +72 -0
- package/dist/audit.d.ts +1 -1
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js.map +1 -1
- package/dist/server.d.ts +14 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +346 -0
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -96,6 +96,8 @@ Agent → PayGate (auth + billing) → Your MCP Server (stdio or HTTP)
|
|
|
96
96
|
- **Key Health Score** — `GET /keys/health?key=...` returns composite health score (0–100) with weighted component breakdown: balance health (30%), quota utilization (25%), rate limit pressure (20%), error rate (25%) — status levels (healthy/good/caution/warning/critical), key issue detection (revoked/suspended/expired/expiring/zero credits), alias support
|
|
97
97
|
- **Maintenance Mode** — `POST /maintenance` enables/disables maintenance mode with custom message — `/mcp` returns 503 to clients while admin endpoints stay operational, `GET /maintenance` checks status, `GET /health` reflects maintenance state, full audit trail
|
|
98
98
|
- **Admin Event Stream** — `GET /admin/events` SSE endpoint streams real-time audit events to admin clients — tool calls, denials, key operations, maintenance changes, all with optional `?types=` filter for event type filtering, keepalive pings, multi-client support
|
|
99
|
+
- **Key Notes** — `POST /keys/notes` adds timestamped notes to API keys, `GET /keys/notes?key=...` lists notes, `DELETE /keys/notes?key=...&index=N` removes notes — max 50 per key, 1000 char limit, works on suspended/revoked keys, alias support, audit trail
|
|
100
|
+
- **Scheduled Actions** — `POST /keys/schedule` creates future-dated actions (revoke/suspend/topup) on API keys, `GET /keys/schedule` lists pending schedules with optional `?key=` filter, `DELETE /keys/schedule?id=...` cancels a schedule — max 20 per key, alias support, background execution timer, audit trail
|
|
99
101
|
- **Config Hot Reload** — `POST /config/reload` reloads pricing, rate limits, webhooks, quotas, and behavior flags from config file without server restart
|
|
100
102
|
- **Webhook Events** — POST batched usage events to any URL for external billing/alerting
|
|
101
103
|
- **Config File Mode** — Load all settings from a JSON file (`--config`)
|
|
@@ -1930,6 +1932,76 @@ data: {"id":43,"timestamp":"2025-03-15T14:30:01.000Z","type":"gate.allow","actor
|
|
|
1930
1932
|
|
|
1931
1933
|
Every audit event (tool calls, denials, key operations, maintenance, alerts) is broadcast in real-time. Use `?types=` to filter by comma-separated event types. Supports multiple concurrent admin clients. Keepalive pings every 15s prevent connection timeouts. Connections are cleaned up automatically on disconnect.
|
|
1932
1934
|
|
|
1935
|
+
### Key Notes
|
|
1936
|
+
|
|
1937
|
+
Attach timestamped notes to API keys for operational tracking:
|
|
1938
|
+
|
|
1939
|
+
```bash
|
|
1940
|
+
# Add a note
|
|
1941
|
+
curl -X POST http://localhost:3402/keys/notes \
|
|
1942
|
+
-H "X-Admin-Key: YOUR_ADMIN_KEY" \
|
|
1943
|
+
-d '{"key": "pg_...", "text": "Increased credits per customer request #1234"}'
|
|
1944
|
+
|
|
1945
|
+
# List notes
|
|
1946
|
+
curl "http://localhost:3402/keys/notes?key=pg_..." -H "X-Admin-Key: YOUR_ADMIN_KEY"
|
|
1947
|
+
|
|
1948
|
+
# Delete a note by index
|
|
1949
|
+
curl -X DELETE "http://localhost:3402/keys/notes?key=pg_...&index=0" \
|
|
1950
|
+
-H "X-Admin-Key: YOUR_ADMIN_KEY"
|
|
1951
|
+
```
|
|
1952
|
+
|
|
1953
|
+
**Response (list):**
|
|
1954
|
+
|
|
1955
|
+
```json
|
|
1956
|
+
{
|
|
1957
|
+
"key": "pg_abc1...2345",
|
|
1958
|
+
"notes": [
|
|
1959
|
+
{ "timestamp": "2025-03-15T14:30:00.000Z", "author": "admin", "text": "Increased credits per customer request #1234" },
|
|
1960
|
+
{ "timestamp": "2025-03-16T09:00:00.000Z", "author": "admin", "text": "Upgraded to premium tier" }
|
|
1961
|
+
],
|
|
1962
|
+
"count": 2
|
|
1963
|
+
}
|
|
1964
|
+
```
|
|
1965
|
+
|
|
1966
|
+
Max 50 notes per key, 1000 characters per note. Works on suspended and revoked keys. Supports aliases. All add/delete operations recorded in audit trail (`key.note_added` / `key.note_deleted`).
|
|
1967
|
+
|
|
1968
|
+
### Scheduled Actions
|
|
1969
|
+
|
|
1970
|
+
Schedule future-dated actions on API keys — automatically revoke, suspend, or top up credits at a specified time:
|
|
1971
|
+
|
|
1972
|
+
```bash
|
|
1973
|
+
# Schedule a key revocation in 24 hours
|
|
1974
|
+
curl -X POST http://localhost:3402/keys/schedule \
|
|
1975
|
+
-H "X-Admin-Key: YOUR_ADMIN_KEY" \
|
|
1976
|
+
-d '{"key": "pg_...", "action": "revoke", "executeAt": "2025-04-01T00:00:00Z"}'
|
|
1977
|
+
|
|
1978
|
+
# Schedule a credit top-up
|
|
1979
|
+
curl -X POST http://localhost:3402/keys/schedule \
|
|
1980
|
+
-H "X-Admin-Key: YOUR_ADMIN_KEY" \
|
|
1981
|
+
-d '{"key": "pg_...", "action": "topup", "executeAt": "2025-04-01T00:00:00Z", "params": {"credits": 500}}'
|
|
1982
|
+
|
|
1983
|
+
# List all pending schedules (optional ?key= filter)
|
|
1984
|
+
curl "http://localhost:3402/keys/schedule" -H "X-Admin-Key: YOUR_ADMIN_KEY"
|
|
1985
|
+
|
|
1986
|
+
# Cancel a schedule
|
|
1987
|
+
curl -X DELETE "http://localhost:3402/keys/schedule?id=sched_1" \
|
|
1988
|
+
-H "X-Admin-Key: YOUR_ADMIN_KEY"
|
|
1989
|
+
```
|
|
1990
|
+
|
|
1991
|
+
**Response (create):**
|
|
1992
|
+
|
|
1993
|
+
```json
|
|
1994
|
+
{
|
|
1995
|
+
"id": "sched_1",
|
|
1996
|
+
"key": "pg_abc1...2345",
|
|
1997
|
+
"action": "revoke",
|
|
1998
|
+
"executeAt": "2025-04-01T00:00:00.000Z",
|
|
1999
|
+
"createdAt": "2025-03-15T10:30:00.000Z"
|
|
2000
|
+
}
|
|
2001
|
+
```
|
|
2002
|
+
|
|
2003
|
+
Supported actions: `revoke`, `suspend`, `topup` (requires `params.credits`). Max 20 schedules per key. Supports aliases. Background timer checks every 10 seconds. All create/execute/cancel operations recorded in audit trail (`schedule.created` / `schedule.executed` / `schedule.cancelled`).
|
|
2004
|
+
|
|
1933
2005
|
### IP Allowlisting
|
|
1934
2006
|
|
|
1935
2007
|
Restrict API keys to specific IP addresses or CIDR ranges:
|
package/dist/audit.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* session lifecycle, and admin operations. Ring buffer with configurable
|
|
6
6
|
* max size and age-based retention. Zero external dependencies.
|
|
7
7
|
*/
|
|
8
|
-
export type AuditEventType = 'key.created' | 'key.revoked' | 'key.suspended' | 'key.resumed' | 'key.cloned' | 'key.rotated' | 'key.topup' | 'key.acl_updated' | 'key.expiry_updated' | 'key.quota_updated' | 'key.tags_updated' | 'key.ip_updated' | 'key.limit_updated' | 'gate.allow' | 'gate.deny' | 'session.created' | 'session.destroyed' | 'oauth.client_registered' | 'oauth.token_issued' | 'oauth.token_revoked' | 'team.created' | 'team.updated' | 'team.deleted' | 'team.key_assigned' | 'team.key_removed' | 'admin.auth_failed' | 'admin.alerts_configured' | 'webhook.dead_letter_cleared' | 'webhook.replayed' | 'webhook.test' | 'webhook.pause' | 'webhook.resume' | 'key.alias_set' | 'key.expiry_warning' | 'template.created' | 'template.updated' | 'template.deleted' | 'token.created' | 'token.revoked' | 'billing.refund' | 'key.auto_topup_configured' | 'key.auto_topped_up' | 'admin_key.created' | 'admin_key.revoked' | 'group.created' | 'group.updated' | 'group.deleted' | 'group.key_assigned' | 'group.key_removed' | 'key.credits_transferred' | 'keys.exported' | 'keys.imported' | 'webhook_filter.created' | 'webhook_filter.updated' | 'webhook_filter.deleted' | 'config.reloaded' | 'config.export' | 'maintenance.enabled' | 'maintenance.disabled';
|
|
8
|
+
export type AuditEventType = 'key.created' | 'key.revoked' | 'key.suspended' | 'key.resumed' | 'key.cloned' | 'key.rotated' | 'key.topup' | 'key.acl_updated' | 'key.expiry_updated' | 'key.quota_updated' | 'key.tags_updated' | 'key.ip_updated' | 'key.limit_updated' | 'gate.allow' | 'gate.deny' | 'session.created' | 'session.destroyed' | 'oauth.client_registered' | 'oauth.token_issued' | 'oauth.token_revoked' | 'team.created' | 'team.updated' | 'team.deleted' | 'team.key_assigned' | 'team.key_removed' | 'admin.auth_failed' | 'admin.alerts_configured' | 'webhook.dead_letter_cleared' | 'webhook.replayed' | 'webhook.test' | 'webhook.pause' | 'webhook.resume' | 'key.alias_set' | 'key.expiry_warning' | 'template.created' | 'template.updated' | 'template.deleted' | 'token.created' | 'token.revoked' | 'billing.refund' | 'key.auto_topup_configured' | 'key.auto_topped_up' | 'admin_key.created' | 'admin_key.revoked' | 'group.created' | 'group.updated' | 'group.deleted' | 'group.key_assigned' | 'group.key_removed' | 'key.credits_transferred' | 'keys.exported' | 'keys.imported' | 'webhook_filter.created' | 'webhook_filter.updated' | 'webhook_filter.deleted' | 'config.reloaded' | 'config.export' | 'maintenance.enabled' | 'maintenance.disabled' | 'key.note_added' | 'key.note_deleted' | 'schedule.created' | 'schedule.executed' | 'schedule.cancelled';
|
|
9
9
|
export interface AuditEvent {
|
|
10
10
|
/** Monotonically increasing ID */
|
|
11
11
|
id: number;
|
package/dist/audit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,MAAM,cAAc,GAEtB,aAAa,GACb,aAAa,GACb,eAAe,GACf,aAAa,GACb,YAAY,GACZ,aAAa,GACb,WAAW,GACX,iBAAiB,GACjB,oBAAoB,GACpB,mBAAmB,GACnB,kBAAkB,GAClB,gBAAgB,GAChB,mBAAmB,GAEnB,YAAY,GACZ,WAAW,GAEX,iBAAiB,GACjB,mBAAmB,GAEnB,yBAAyB,GACzB,oBAAoB,GACpB,qBAAqB,GAErB,cAAc,GACd,cAAc,GACd,cAAc,GACd,mBAAmB,GACnB,kBAAkB,GAElB,mBAAmB,GACnB,yBAAyB,GAEzB,6BAA6B,GAC7B,kBAAkB,GAClB,cAAc,GACd,eAAe,GACf,gBAAgB,GAEhB,eAAe,GAEf,oBAAoB,GAEpB,kBAAkB,GAClB,kBAAkB,GAClB,kBAAkB,GAElB,eAAe,GACf,eAAe,GAEf,gBAAgB,GAEhB,2BAA2B,GAC3B,oBAAoB,GAEpB,mBAAmB,GACnB,mBAAmB,GAEnB,eAAe,GACf,eAAe,GACf,eAAe,GACf,oBAAoB,GACpB,mBAAmB,GAEnB,yBAAyB,GAEzB,eAAe,GACf,eAAe,GAEf,wBAAwB,GACxB,wBAAwB,GACxB,wBAAwB,GAExB,iBAAiB,GACjB,eAAe,GAEf,qBAAqB,GACrB,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
|
package/dist/audit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -107,6 +107,12 @@ export declare class PayGateServer {
|
|
|
107
107
|
private adminEventStreams;
|
|
108
108
|
/** Keepalive timer for admin event streams */
|
|
109
109
|
private adminEventKeepAliveTimer;
|
|
110
|
+
/** Scheduled actions queue */
|
|
111
|
+
private scheduledActions;
|
|
112
|
+
/** Timer for checking scheduled actions */
|
|
113
|
+
private scheduleTimer;
|
|
114
|
+
/** Auto-incrementing schedule ID counter */
|
|
115
|
+
private nextScheduleId;
|
|
110
116
|
/** Number of in-flight /mcp requests */
|
|
111
117
|
private inflight;
|
|
112
118
|
/** Config file path for hot reload (null if not using config file) */
|
|
@@ -225,6 +231,14 @@ export declare class PayGateServer {
|
|
|
225
231
|
private handleGetMaintenance;
|
|
226
232
|
private handleSetMaintenance;
|
|
227
233
|
private handleAdminEventStream;
|
|
234
|
+
private handleGetNotes;
|
|
235
|
+
private handleAddNote;
|
|
236
|
+
private handleDeleteNote;
|
|
237
|
+
private handleGetSchedules;
|
|
238
|
+
private handleCreateSchedule;
|
|
239
|
+
private handleCancelSchedule;
|
|
240
|
+
/** Execute any scheduled actions that are due. Called by the schedule timer. */
|
|
241
|
+
private executeScheduledActions;
|
|
228
242
|
private handleConfigReload;
|
|
229
243
|
private handleWebhookStats;
|
|
230
244
|
private handleWebhookLog;
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -225,6 +225,12 @@ class PayGateServer {
|
|
|
225
225
|
adminEventStreams = new Set();
|
|
226
226
|
/** Keepalive timer for admin event streams */
|
|
227
227
|
adminEventKeepAliveTimer = null;
|
|
228
|
+
/** Scheduled actions queue */
|
|
229
|
+
scheduledActions = [];
|
|
230
|
+
/** Timer for checking scheduled actions */
|
|
231
|
+
scheduleTimer = null;
|
|
232
|
+
/** Auto-incrementing schedule ID counter */
|
|
233
|
+
nextScheduleId = 1;
|
|
228
234
|
/** Number of in-flight /mcp requests */
|
|
229
235
|
inflight = 0;
|
|
230
236
|
/** Config file path for hot reload (null if not using config file) */
|
|
@@ -442,6 +448,9 @@ class PayGateServer {
|
|
|
442
448
|
await this.handler.start();
|
|
443
449
|
// Start the key expiry scanner (proactive background scanning)
|
|
444
450
|
this.expiryScanner.start(() => this.gate.store.getAllRecords());
|
|
451
|
+
// Start scheduled actions executor (checks every 10s)
|
|
452
|
+
this.scheduleTimer = setInterval(() => this.executeScheduledActions(), 10_000);
|
|
453
|
+
this.scheduleTimer.unref();
|
|
445
454
|
// Plugin lifecycle: onStart
|
|
446
455
|
if (this.plugins.count > 0) {
|
|
447
456
|
await this.plugins.executeStart();
|
|
@@ -539,6 +548,26 @@ class PayGateServer {
|
|
|
539
548
|
return this.handleCloneKey(req, res);
|
|
540
549
|
case '/keys/alias':
|
|
541
550
|
return this.handleSetAlias(req, res);
|
|
551
|
+
case '/keys/notes':
|
|
552
|
+
if (req.method === 'GET')
|
|
553
|
+
return this.handleGetNotes(req, res);
|
|
554
|
+
if (req.method === 'POST')
|
|
555
|
+
return this.handleAddNote(req, res);
|
|
556
|
+
if (req.method === 'DELETE')
|
|
557
|
+
return this.handleDeleteNote(req, res);
|
|
558
|
+
res.writeHead(405, { 'Content-Type': 'application/json' });
|
|
559
|
+
res.end(JSON.stringify({ error: 'Method not allowed' }));
|
|
560
|
+
return;
|
|
561
|
+
case '/keys/schedule':
|
|
562
|
+
if (req.method === 'GET')
|
|
563
|
+
return this.handleGetSchedules(req, res);
|
|
564
|
+
if (req.method === 'POST')
|
|
565
|
+
return this.handleCreateSchedule(req, res);
|
|
566
|
+
if (req.method === 'DELETE')
|
|
567
|
+
return this.handleCancelSchedule(req, res);
|
|
568
|
+
res.writeHead(405, { 'Content-Type': 'application/json' });
|
|
569
|
+
res.end(JSON.stringify({ error: 'Method not allowed' }));
|
|
570
|
+
return;
|
|
542
571
|
case '/keys/rotate':
|
|
543
572
|
return this.handleRotateKey(req, res);
|
|
544
573
|
case '/keys/acl':
|
|
@@ -1176,6 +1205,8 @@ class PayGateServer {
|
|
|
1176
1205
|
configExport: 'GET /config — Export running config with sensitive values masked (requires X-Admin-Key)',
|
|
1177
1206
|
maintenance: 'GET /maintenance — Check status + POST to enable/disable maintenance mode (requires X-Admin-Key)',
|
|
1178
1207
|
adminEvents: 'GET /admin/events — Real-time SSE stream of server events (requires X-Admin-Key, Accept: text/event-stream)',
|
|
1208
|
+
keyNotes: 'GET /keys/notes?key=... — List notes + POST to add + DELETE to remove (requires X-Admin-Key)',
|
|
1209
|
+
keySchedule: 'GET /keys/schedule?key=... — List schedules + POST to create + DELETE to cancel (requires X-Admin-Key)',
|
|
1179
1210
|
...(this.oauth ? {
|
|
1180
1211
|
oauthMetadata: 'GET /.well-known/oauth-authorization-server — OAuth 2.1 server metadata',
|
|
1181
1212
|
oauthRegister: 'POST /oauth/register — Register OAuth client',
|
|
@@ -3952,6 +3983,316 @@ class PayGateServer {
|
|
|
3952
3983
|
}
|
|
3953
3984
|
});
|
|
3954
3985
|
}
|
|
3986
|
+
// ─── /keys/notes — Timestamped notes on API keys ─────────────────────────
|
|
3987
|
+
handleGetNotes(req, res) {
|
|
3988
|
+
if (!this.checkAdmin(req, res))
|
|
3989
|
+
return;
|
|
3990
|
+
const urlParts = req.url?.split('?') || [];
|
|
3991
|
+
const params = new URLSearchParams(urlParts[1] || '');
|
|
3992
|
+
const keyParam = params.get('key');
|
|
3993
|
+
if (!keyParam) {
|
|
3994
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
3995
|
+
res.end(JSON.stringify({ error: 'Missing required query parameter: key' }));
|
|
3996
|
+
return;
|
|
3997
|
+
}
|
|
3998
|
+
const record = this.gate.store.resolveKeyRaw(keyParam);
|
|
3999
|
+
if (!record) {
|
|
4000
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
4001
|
+
res.end(JSON.stringify({ error: 'Key not found' }));
|
|
4002
|
+
return;
|
|
4003
|
+
}
|
|
4004
|
+
const notes = record.notes || [];
|
|
4005
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
4006
|
+
res.end(JSON.stringify({ key: (0, audit_1.maskKeyForAudit)(record.key), notes, count: notes.length }));
|
|
4007
|
+
}
|
|
4008
|
+
handleAddNote(req, res) {
|
|
4009
|
+
if (!this.checkAdmin(req, res))
|
|
4010
|
+
return;
|
|
4011
|
+
let body = '';
|
|
4012
|
+
req.on('data', (chunk) => { body += chunk; });
|
|
4013
|
+
req.on('end', () => {
|
|
4014
|
+
let params;
|
|
4015
|
+
try {
|
|
4016
|
+
params = JSON.parse(body);
|
|
4017
|
+
}
|
|
4018
|
+
catch {
|
|
4019
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4020
|
+
res.end(JSON.stringify({ error: 'Invalid JSON body' }));
|
|
4021
|
+
return;
|
|
4022
|
+
}
|
|
4023
|
+
if (!params.key || typeof params.key !== 'string') {
|
|
4024
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4025
|
+
res.end(JSON.stringify({ error: 'Missing required field: key' }));
|
|
4026
|
+
return;
|
|
4027
|
+
}
|
|
4028
|
+
if (!params.text || typeof params.text !== 'string' || !params.text.trim()) {
|
|
4029
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4030
|
+
res.end(JSON.stringify({ error: 'Missing required field: text (non-empty string)' }));
|
|
4031
|
+
return;
|
|
4032
|
+
}
|
|
4033
|
+
if (params.text.length > 1000) {
|
|
4034
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4035
|
+
res.end(JSON.stringify({ error: 'Note text must be 1000 characters or less' }));
|
|
4036
|
+
return;
|
|
4037
|
+
}
|
|
4038
|
+
const record = this.gate.store.resolveKeyRaw(params.key);
|
|
4039
|
+
if (!record) {
|
|
4040
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
4041
|
+
res.end(JSON.stringify({ error: 'Key not found' }));
|
|
4042
|
+
return;
|
|
4043
|
+
}
|
|
4044
|
+
if (!record.notes)
|
|
4045
|
+
record.notes = [];
|
|
4046
|
+
// Cap at 50 notes per key
|
|
4047
|
+
if (record.notes.length >= 50) {
|
|
4048
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4049
|
+
res.end(JSON.stringify({ error: 'Maximum 50 notes per key reached. Delete old notes first.' }));
|
|
4050
|
+
return;
|
|
4051
|
+
}
|
|
4052
|
+
const note = {
|
|
4053
|
+
timestamp: new Date().toISOString(),
|
|
4054
|
+
author: 'admin',
|
|
4055
|
+
text: params.text.trim(),
|
|
4056
|
+
};
|
|
4057
|
+
record.notes.push(note);
|
|
4058
|
+
this.gate.store.save();
|
|
4059
|
+
this.audit.log('key.note_added', 'admin', `Note added to key`, {
|
|
4060
|
+
key: (0, audit_1.maskKeyForAudit)(record.key),
|
|
4061
|
+
text: note.text.slice(0, 100),
|
|
4062
|
+
});
|
|
4063
|
+
res.writeHead(201, { 'Content-Type': 'application/json' });
|
|
4064
|
+
res.end(JSON.stringify({ note, count: record.notes.length }));
|
|
4065
|
+
});
|
|
4066
|
+
}
|
|
4067
|
+
handleDeleteNote(req, res) {
|
|
4068
|
+
if (!this.checkAdmin(req, res))
|
|
4069
|
+
return;
|
|
4070
|
+
const urlParts = req.url?.split('?') || [];
|
|
4071
|
+
const params = new URLSearchParams(urlParts[1] || '');
|
|
4072
|
+
const keyParam = params.get('key');
|
|
4073
|
+
const indexParam = params.get('index');
|
|
4074
|
+
if (!keyParam) {
|
|
4075
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4076
|
+
res.end(JSON.stringify({ error: 'Missing required query parameter: key' }));
|
|
4077
|
+
return;
|
|
4078
|
+
}
|
|
4079
|
+
if (indexParam === null || indexParam === undefined) {
|
|
4080
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4081
|
+
res.end(JSON.stringify({ error: 'Missing required query parameter: index' }));
|
|
4082
|
+
return;
|
|
4083
|
+
}
|
|
4084
|
+
const record = this.gate.store.resolveKeyRaw(keyParam);
|
|
4085
|
+
if (!record) {
|
|
4086
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
4087
|
+
res.end(JSON.stringify({ error: 'Key not found' }));
|
|
4088
|
+
return;
|
|
4089
|
+
}
|
|
4090
|
+
const notes = record.notes || [];
|
|
4091
|
+
const index = parseInt(indexParam, 10);
|
|
4092
|
+
if (isNaN(index) || index < 0 || index >= notes.length) {
|
|
4093
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4094
|
+
res.end(JSON.stringify({ error: `Invalid index: ${indexParam}. Must be 0-${notes.length - 1}` }));
|
|
4095
|
+
return;
|
|
4096
|
+
}
|
|
4097
|
+
const deleted = notes.splice(index, 1)[0];
|
|
4098
|
+
record.notes = notes;
|
|
4099
|
+
this.gate.store.save();
|
|
4100
|
+
this.audit.log('key.note_deleted', 'admin', `Note deleted from key`, {
|
|
4101
|
+
key: (0, audit_1.maskKeyForAudit)(record.key),
|
|
4102
|
+
text: deleted.text.slice(0, 100),
|
|
4103
|
+
index,
|
|
4104
|
+
});
|
|
4105
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
4106
|
+
res.end(JSON.stringify({ deleted, remaining: notes.length }));
|
|
4107
|
+
}
|
|
4108
|
+
// ─── /keys/schedule — Scheduled actions on API keys ──────────────────────
|
|
4109
|
+
handleGetSchedules(req, res) {
|
|
4110
|
+
if (!this.checkAdmin(req, res))
|
|
4111
|
+
return;
|
|
4112
|
+
const urlParts = req.url?.split('?') || [];
|
|
4113
|
+
const params = new URLSearchParams(urlParts[1] || '');
|
|
4114
|
+
const keyParam = params.get('key');
|
|
4115
|
+
let schedules = this.scheduledActions;
|
|
4116
|
+
if (keyParam) {
|
|
4117
|
+
// Resolve alias
|
|
4118
|
+
const record = this.gate.store.resolveKeyRaw(keyParam);
|
|
4119
|
+
if (!record) {
|
|
4120
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
4121
|
+
res.end(JSON.stringify({ error: 'Key not found' }));
|
|
4122
|
+
return;
|
|
4123
|
+
}
|
|
4124
|
+
schedules = schedules.filter(s => s.key === record.key);
|
|
4125
|
+
}
|
|
4126
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
4127
|
+
res.end(JSON.stringify({
|
|
4128
|
+
schedules: schedules.map(s => ({
|
|
4129
|
+
...s,
|
|
4130
|
+
key: (0, audit_1.maskKeyForAudit)(s.key),
|
|
4131
|
+
})),
|
|
4132
|
+
count: schedules.length,
|
|
4133
|
+
}));
|
|
4134
|
+
}
|
|
4135
|
+
handleCreateSchedule(req, res) {
|
|
4136
|
+
if (!this.checkAdmin(req, res))
|
|
4137
|
+
return;
|
|
4138
|
+
let body = '';
|
|
4139
|
+
req.on('data', (chunk) => { body += chunk; });
|
|
4140
|
+
req.on('end', () => {
|
|
4141
|
+
let params;
|
|
4142
|
+
try {
|
|
4143
|
+
params = JSON.parse(body);
|
|
4144
|
+
}
|
|
4145
|
+
catch {
|
|
4146
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4147
|
+
res.end(JSON.stringify({ error: 'Invalid JSON body' }));
|
|
4148
|
+
return;
|
|
4149
|
+
}
|
|
4150
|
+
if (!params.key || typeof params.key !== 'string') {
|
|
4151
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4152
|
+
res.end(JSON.stringify({ error: 'Missing required field: key' }));
|
|
4153
|
+
return;
|
|
4154
|
+
}
|
|
4155
|
+
const validActions = ['revoke', 'suspend', 'topup'];
|
|
4156
|
+
if (!params.action || !validActions.includes(params.action)) {
|
|
4157
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4158
|
+
res.end(JSON.stringify({ error: `Missing or invalid action. Must be one of: ${validActions.join(', ')}` }));
|
|
4159
|
+
return;
|
|
4160
|
+
}
|
|
4161
|
+
if (!params.executeAt || typeof params.executeAt !== 'string') {
|
|
4162
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4163
|
+
res.end(JSON.stringify({ error: 'Missing required field: executeAt (ISO 8601 timestamp)' }));
|
|
4164
|
+
return;
|
|
4165
|
+
}
|
|
4166
|
+
const executeTime = new Date(params.executeAt).getTime();
|
|
4167
|
+
if (isNaN(executeTime)) {
|
|
4168
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4169
|
+
res.end(JSON.stringify({ error: 'Invalid executeAt: must be a valid ISO 8601 timestamp' }));
|
|
4170
|
+
return;
|
|
4171
|
+
}
|
|
4172
|
+
if (executeTime <= Date.now()) {
|
|
4173
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4174
|
+
res.end(JSON.stringify({ error: 'executeAt must be in the future' }));
|
|
4175
|
+
return;
|
|
4176
|
+
}
|
|
4177
|
+
// Topup requires credits param
|
|
4178
|
+
if (params.action === 'topup') {
|
|
4179
|
+
const credits = params.params?.credits;
|
|
4180
|
+
if (!credits || typeof credits !== 'number' || credits <= 0) {
|
|
4181
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4182
|
+
res.end(JSON.stringify({ error: 'topup action requires params.credits (positive number)' }));
|
|
4183
|
+
return;
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
const record = this.gate.store.resolveKeyRaw(params.key);
|
|
4187
|
+
if (!record) {
|
|
4188
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
4189
|
+
res.end(JSON.stringify({ error: 'Key not found' }));
|
|
4190
|
+
return;
|
|
4191
|
+
}
|
|
4192
|
+
// Max 20 schedules per key
|
|
4193
|
+
const keySchedules = this.scheduledActions.filter(s => s.key === record.key);
|
|
4194
|
+
if (keySchedules.length >= 20) {
|
|
4195
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4196
|
+
res.end(JSON.stringify({ error: 'Maximum 20 scheduled actions per key' }));
|
|
4197
|
+
return;
|
|
4198
|
+
}
|
|
4199
|
+
const schedule = {
|
|
4200
|
+
id: `sched_${this.nextScheduleId++}`,
|
|
4201
|
+
key: record.key,
|
|
4202
|
+
action: params.action,
|
|
4203
|
+
executeAt: new Date(params.executeAt).toISOString(),
|
|
4204
|
+
createdAt: new Date().toISOString(),
|
|
4205
|
+
params: params.params,
|
|
4206
|
+
};
|
|
4207
|
+
this.scheduledActions.push(schedule);
|
|
4208
|
+
this.audit.log('schedule.created', 'admin', `Scheduled ${params.action} on key`, {
|
|
4209
|
+
scheduleId: schedule.id,
|
|
4210
|
+
key: (0, audit_1.maskKeyForAudit)(record.key),
|
|
4211
|
+
action: params.action,
|
|
4212
|
+
executeAt: schedule.executeAt,
|
|
4213
|
+
});
|
|
4214
|
+
res.writeHead(201, { 'Content-Type': 'application/json' });
|
|
4215
|
+
res.end(JSON.stringify({
|
|
4216
|
+
...schedule,
|
|
4217
|
+
key: (0, audit_1.maskKeyForAudit)(schedule.key),
|
|
4218
|
+
}));
|
|
4219
|
+
});
|
|
4220
|
+
}
|
|
4221
|
+
handleCancelSchedule(req, res) {
|
|
4222
|
+
if (!this.checkAdmin(req, res))
|
|
4223
|
+
return;
|
|
4224
|
+
const urlParts = req.url?.split('?') || [];
|
|
4225
|
+
const params = new URLSearchParams(urlParts[1] || '');
|
|
4226
|
+
const scheduleId = params.get('id');
|
|
4227
|
+
if (!scheduleId) {
|
|
4228
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4229
|
+
res.end(JSON.stringify({ error: 'Missing required query parameter: id' }));
|
|
4230
|
+
return;
|
|
4231
|
+
}
|
|
4232
|
+
const idx = this.scheduledActions.findIndex(s => s.id === scheduleId);
|
|
4233
|
+
if (idx === -1) {
|
|
4234
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
4235
|
+
res.end(JSON.stringify({ error: 'Schedule not found' }));
|
|
4236
|
+
return;
|
|
4237
|
+
}
|
|
4238
|
+
const cancelled = this.scheduledActions.splice(idx, 1)[0];
|
|
4239
|
+
this.audit.log('schedule.cancelled', 'admin', `Cancelled scheduled ${cancelled.action}`, {
|
|
4240
|
+
scheduleId: cancelled.id,
|
|
4241
|
+
key: (0, audit_1.maskKeyForAudit)(cancelled.key),
|
|
4242
|
+
action: cancelled.action,
|
|
4243
|
+
executeAt: cancelled.executeAt,
|
|
4244
|
+
});
|
|
4245
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
4246
|
+
res.end(JSON.stringify({
|
|
4247
|
+
cancelled: { ...cancelled, key: (0, audit_1.maskKeyForAudit)(cancelled.key) },
|
|
4248
|
+
}));
|
|
4249
|
+
}
|
|
4250
|
+
/** Execute any scheduled actions that are due. Called by the schedule timer. */
|
|
4251
|
+
executeScheduledActions() {
|
|
4252
|
+
const now = Date.now();
|
|
4253
|
+
const due = this.scheduledActions.filter(s => new Date(s.executeAt).getTime() <= now);
|
|
4254
|
+
for (const schedule of due) {
|
|
4255
|
+
// Remove from queue
|
|
4256
|
+
const idx = this.scheduledActions.indexOf(schedule);
|
|
4257
|
+
if (idx !== -1)
|
|
4258
|
+
this.scheduledActions.splice(idx, 1);
|
|
4259
|
+
const record = this.gate.store.resolveKeyRaw(schedule.key);
|
|
4260
|
+
if (!record)
|
|
4261
|
+
continue; // Key was deleted
|
|
4262
|
+
try {
|
|
4263
|
+
switch (schedule.action) {
|
|
4264
|
+
case 'revoke':
|
|
4265
|
+
if (record.active) {
|
|
4266
|
+
record.active = false;
|
|
4267
|
+
this.gate.store.save();
|
|
4268
|
+
}
|
|
4269
|
+
break;
|
|
4270
|
+
case 'suspend':
|
|
4271
|
+
if (!record.suspended) {
|
|
4272
|
+
record.suspended = true;
|
|
4273
|
+
this.gate.store.save();
|
|
4274
|
+
}
|
|
4275
|
+
break;
|
|
4276
|
+
case 'topup': {
|
|
4277
|
+
const credits = schedule.params?.credits || 0;
|
|
4278
|
+
if (credits > 0) {
|
|
4279
|
+
record.credits += credits;
|
|
4280
|
+
this.gate.store.save();
|
|
4281
|
+
}
|
|
4282
|
+
break;
|
|
4283
|
+
}
|
|
4284
|
+
}
|
|
4285
|
+
this.audit.log('schedule.executed', 'system', `Executed scheduled ${schedule.action}`, {
|
|
4286
|
+
scheduleId: schedule.id,
|
|
4287
|
+
key: (0, audit_1.maskKeyForAudit)(schedule.key),
|
|
4288
|
+
action: schedule.action,
|
|
4289
|
+
});
|
|
4290
|
+
}
|
|
4291
|
+
catch {
|
|
4292
|
+
// Log error but don't crash
|
|
4293
|
+
}
|
|
4294
|
+
}
|
|
4295
|
+
}
|
|
3955
4296
|
// ─── /config/reload — Hot reload configuration from file ─────────────────
|
|
3956
4297
|
async handleConfigReload(req, res) {
|
|
3957
4298
|
if (req.method !== 'POST') {
|
|
@@ -5443,6 +5784,11 @@ class PayGateServer {
|
|
|
5443
5784
|
});
|
|
5444
5785
|
}
|
|
5445
5786
|
async stop() {
|
|
5787
|
+
// Stop scheduled actions timer
|
|
5788
|
+
if (this.scheduleTimer) {
|
|
5789
|
+
clearInterval(this.scheduleTimer);
|
|
5790
|
+
this.scheduleTimer = null;
|
|
5791
|
+
}
|
|
5446
5792
|
// Close admin event stream connections
|
|
5447
5793
|
if (this.adminEventKeepAliveTimer) {
|
|
5448
5794
|
clearInterval(this.adminEventKeepAliveTimer);
|