paygate-mcp 10.0.0 → 10.2.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 +9 -3
- package/dist/approval-workflows.d.ts +112 -0
- package/dist/approval-workflows.d.ts.map +1 -0
- package/dist/approval-workflows.js +302 -0
- package/dist/approval-workflows.js.map +1 -0
- package/dist/config-profiles.d.ts +126 -0
- package/dist/config-profiles.d.ts.map +1 -0
- package/dist/config-profiles.js +366 -0
- package/dist/config-profiles.js.map +1 -0
- package/dist/gateway-hooks.d.ts +115 -0
- package/dist/gateway-hooks.d.ts.map +1 -0
- package/dist/gateway-hooks.js +268 -0
- package/dist/gateway-hooks.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/quota-manager.d.ts +135 -0
- package/dist/quota-manager.d.ts.map +1 -0
- package/dist/quota-manager.js +349 -0
- package/dist/quota-manager.js.map +1 -0
- package/dist/scheduled-reports.d.ts +137 -0
- package/dist/scheduled-reports.d.ts.map +1 -0
- package/dist/scheduled-reports.js +328 -0
- package/dist/scheduled-reports.js.map +1 -0
- package/dist/server.d.ts +18 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +728 -0
- package/dist/server.js.map +1 -1
- package/dist/webhook-replay.d.ts +123 -0
- package/dist/webhook-replay.d.ts.map +1 -0
- package/dist/webhook-replay.js +305 -0
- package/dist/webhook-replay.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Monetize any MCP server with one command. Add API key auth, per-tool pricing, ra
|
|
|
11
11
|
- [Quick Start](#quick-start)
|
|
12
12
|
- [What It Does](#what-it-does)
|
|
13
13
|
- [Usage](#usage) — Local stdio, remote HTTP, multi-server, client SDK
|
|
14
|
-
- [API Reference](#api-reference) — All
|
|
14
|
+
- [API Reference](#api-reference) — All 199+ endpoints
|
|
15
15
|
- [CLI Options](#cli-options)
|
|
16
16
|
- [Deployment](#deployment) — Docker, docker-compose, systemd, PM2
|
|
17
17
|
- [Load Testing](#load-testing) — k6 benchmarking for production
|
|
@@ -66,7 +66,7 @@ Agent → PayGate (auth + billing) → Your MCP Server (stdio or HTTP)
|
|
|
66
66
|
- **SSE Streaming** — Full MCP Streamable HTTP transport (POST SSE, GET notifications, DELETE sessions)
|
|
67
67
|
- **Audit Log** — Structured audit trail with retention policies, query API, CSV/JSON export
|
|
68
68
|
- **Registry/Discovery** — Agent-discoverable pricing via `/.well-known/mcp-payment`, `/pricing`, and `/.well-known/mcp.json` identity card
|
|
69
|
-
- **OpenAPI 3.1 + Interactive Docs** — Auto-generated spec at `/openapi.json`, Swagger UI at `/docs` — all
|
|
69
|
+
- **OpenAPI 3.1 + Interactive Docs** — Auto-generated spec at `/openapi.json`, Swagger UI at `/docs` — all 199+ endpoints documented
|
|
70
70
|
- **Public Endpoint Rate Limiting** — Configurable per-IP rate limit (default 300/min) on `/health`, `/info`, `/pricing`, `/docs`, `/openapi.json`, `/.well-known/*`, `/robots.txt`, `/` — 429 with Retry-After header
|
|
71
71
|
- **Robots.txt + HEAD Support** — Standard `/robots.txt` (allow public, disallow admin/keys), HEAD method on all public endpoints for uptime monitoring
|
|
72
72
|
- **Prometheus Metrics** — `/metrics` endpoint with counters, gauges, and uptime in standard text format
|
|
@@ -177,6 +177,12 @@ Agent → PayGate (auth + billing) → Your MCP Server (stdio or HTTP)
|
|
|
177
177
|
- **Request Tracing** — End-to-end structured tracing with span recording at gate, backend, and transform stages — trace/request ID lookup, timing breakdown (gateMs/backendMs/transformMs), configurable sample rate, retention limits, P95 latency tracking, JSON export, manage via `GET/POST/DELETE /admin/tracing`
|
|
178
178
|
- **Budget Policy Engine** — Burn rate monitoring with progressive throttling — daily/monthly budget enforcement, credits/minute burn rate tracking over configurable windows, three actions (alert/throttle/deny), per-namespace and per-key targeting, budget remaining forecast, automatic daily/monthly reset, manage via `GET/POST/DELETE /admin/budget-policies`
|
|
179
179
|
- **Tool Dependency Graph** — DAG-based workflow validation — register tool dependencies, enforce execution order, failure propagation (upstream failure blocks downstream), topological sort, cycle detection, per-workflow execution tracking, hard vs soft dependencies, group scoping, manage via `GET/POST/DELETE /admin/tool-deps`
|
|
180
|
+
- **Quota Management** — Granular daily/weekly/monthly hard caps per API key — per-tool or global quotas, calls or credits metric, burst allowance (temporary over-limit percentage), three overage actions (deny/warn/throttle), UTC-based period boundaries (daily midnight, weekly Monday, monthly 1st), automatic period rollover, manage via `GET/POST/DELETE /admin/quota-rules`
|
|
181
|
+
- **Webhook Replay (DLQ)** — Dead letter queue management for failed webhook deliveries — record failures with full request context (URL, headers, body, HMAC signature), replay individual or bulk failed deliveries, status tracking (pending → retrying → succeeded/exhausted), configurable max retries with timeout, purge by ID or status, age-based expiry, manage via `GET/POST/DELETE /admin/webhook-replay`
|
|
182
|
+
- **Config Profiles** — Named configuration presets with save/activate/rollback — profile inheritance chains (base → child merging), SHA-256 checksums, flat-key diffing for comparison (onlyInA/onlyInB/changed/unchanged), import/export as JSON with merge or replace mode, activation history, circular inheritance detection, manage via `GET/POST/DELETE /admin/config-profiles`
|
|
183
|
+
- **Scheduled Reports** — Automated periodic usage, billing, compliance, and security reports delivered via webhook — daily/weekly/monthly frequency with UTC period bounds, HMAC-SHA256 signed payloads, namespace/group/tool/key filters, report generation with delivery tracking, configurable timeouts, manage via `POST /admin/scheduled-reports`
|
|
184
|
+
- **Approval Workflows** — Pre-execution approval gates for high-cost or sensitive tool calls — three conditions (cost_threshold, tool_match with glob, key_match with prefix), pending requests with configurable TTL (default 1h), approve/deny/expire lifecycle, trigger counting, manage via `POST /admin/approval-workflows`
|
|
185
|
+
- **Gateway Hooks** — Pre/post request lifecycle hooks for custom logic — three stages (pre_gate, pre_backend, post_backend), four types (log, header_inject, metadata_tag, reject), priority-based execution pipeline, tool/key glob filtering, reject short-circuits processing, execution counting, manage via `POST /admin/gateway-hooks`
|
|
180
186
|
- **Anomaly Detection** — `GET /admin/anomalies` identifies unusual patterns: keys with high denial rates, rapid credit depletion, low remaining credits, with severity ratings and detailed descriptions
|
|
181
187
|
- **Usage Forecasting** — `GET /admin/forecast` predicts future credit consumption with per-key depletion estimates, calls remaining, at-risk key identification, system-wide consumption aggregates, and per-tool cost breakdown
|
|
182
188
|
- **Compliance Report** — `GET /admin/compliance` generates compliance-ready report with key governance (expiry coverage), access control (ACL/IP/spending limit coverage), audit trail completeness, weighted overall score, and actionable recommendations
|
|
@@ -490,7 +496,7 @@ A real-time admin UI for managing keys, viewing usage, and monitoring tool calls
|
|
|
490
496
|
| `/.well-known/mcp-payment` | GET | None | Server payment metadata (SEP-2007) |
|
|
491
497
|
| `/.well-known/mcp.json` | GET | None | MCP Server Identity card (discovery) |
|
|
492
498
|
| `/pricing` | GET | None | Full per-tool pricing breakdown |
|
|
493
|
-
| `/openapi.json` | GET | None | OpenAPI 3.1 spec (all
|
|
499
|
+
| `/openapi.json` | GET | None | OpenAPI 3.1 spec (all 199+ endpoints) |
|
|
494
500
|
| `/docs` | GET | None | Interactive API docs (Swagger UI) |
|
|
495
501
|
| `/robots.txt` | GET | None | Crawler directives (allow public, disallow admin/keys) |
|
|
496
502
|
| `/portal` | GET | None | Self-service API key portal (browser UI, auth via X-API-Key prompt) |
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Approval Workflows — Pre-execution approval gates for tool calls.
|
|
3
|
+
*
|
|
4
|
+
* Define rules that require explicit admin approval before high-cost
|
|
5
|
+
* or sensitive tool calls are executed. Pending requests are held
|
|
6
|
+
* until approved or denied (or they expire).
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const approvals = new ApprovalWorkflowManager();
|
|
11
|
+
* approvals.configure({ enabled: true });
|
|
12
|
+
*
|
|
13
|
+
* // Require approval for tool calls costing more than 100 credits
|
|
14
|
+
* approvals.createRule({
|
|
15
|
+
* name: 'high-cost-gate',
|
|
16
|
+
* condition: 'cost_threshold',
|
|
17
|
+
* threshold: 100,
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export type ApprovalCondition = 'cost_threshold' | 'tool_match' | 'key_match';
|
|
22
|
+
export type ApprovalStatus = 'pending' | 'approved' | 'denied' | 'expired';
|
|
23
|
+
export interface ApprovalRule {
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
condition: ApprovalCondition;
|
|
27
|
+
/** For cost_threshold: minimum credits to trigger */
|
|
28
|
+
threshold?: number;
|
|
29
|
+
/** For tool_match: tool name pattern (exact or glob with *) */
|
|
30
|
+
toolPattern?: string;
|
|
31
|
+
/** For key_match: specific API key prefix */
|
|
32
|
+
keyPrefix?: string;
|
|
33
|
+
enabled: boolean;
|
|
34
|
+
createdAt: string;
|
|
35
|
+
updatedAt: string;
|
|
36
|
+
triggerCount: number;
|
|
37
|
+
}
|
|
38
|
+
export interface ApprovalRuleCreateParams {
|
|
39
|
+
name: string;
|
|
40
|
+
condition: ApprovalCondition;
|
|
41
|
+
threshold?: number;
|
|
42
|
+
toolPattern?: string;
|
|
43
|
+
keyPrefix?: string;
|
|
44
|
+
enabled?: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface ApprovalRequest {
|
|
47
|
+
id: string;
|
|
48
|
+
ruleId: string;
|
|
49
|
+
ruleName: string;
|
|
50
|
+
apiKey: string;
|
|
51
|
+
tool: string;
|
|
52
|
+
creditCost: number;
|
|
53
|
+
status: ApprovalStatus;
|
|
54
|
+
reason?: string;
|
|
55
|
+
decidedBy?: string;
|
|
56
|
+
createdAt: string;
|
|
57
|
+
updatedAt: string;
|
|
58
|
+
expiresAt: string;
|
|
59
|
+
}
|
|
60
|
+
export interface ApprovalCheckResult {
|
|
61
|
+
requiresApproval: boolean;
|
|
62
|
+
matchedRules: string[];
|
|
63
|
+
requestId?: string;
|
|
64
|
+
}
|
|
65
|
+
export interface ApprovalDecision {
|
|
66
|
+
requestId: string;
|
|
67
|
+
status: 'approved' | 'denied';
|
|
68
|
+
reason?: string;
|
|
69
|
+
decidedBy?: string;
|
|
70
|
+
}
|
|
71
|
+
export interface ApprovalWorkflowStats {
|
|
72
|
+
totalRules: number;
|
|
73
|
+
enabledRules: number;
|
|
74
|
+
totalRequests: number;
|
|
75
|
+
pendingRequests: number;
|
|
76
|
+
approvedRequests: number;
|
|
77
|
+
deniedRequests: number;
|
|
78
|
+
expiredRequests: number;
|
|
79
|
+
byCondition: Record<ApprovalCondition, number>;
|
|
80
|
+
}
|
|
81
|
+
export interface ApprovalWorkflowConfig {
|
|
82
|
+
enabled: boolean;
|
|
83
|
+
maxRules: number;
|
|
84
|
+
maxPendingRequests: number;
|
|
85
|
+
defaultExpiryMs: number;
|
|
86
|
+
}
|
|
87
|
+
export declare class ApprovalWorkflowManager {
|
|
88
|
+
private rules;
|
|
89
|
+
private requests;
|
|
90
|
+
private config;
|
|
91
|
+
createRule(params: ApprovalRuleCreateParams): ApprovalRule;
|
|
92
|
+
getRule(id: string): ApprovalRule | undefined;
|
|
93
|
+
listRules(filter?: {
|
|
94
|
+
condition?: ApprovalCondition;
|
|
95
|
+
enabled?: boolean;
|
|
96
|
+
}): ApprovalRule[];
|
|
97
|
+
updateRule(id: string, updates: Partial<Pick<ApprovalRule, 'name' | 'threshold' | 'toolPattern' | 'keyPrefix' | 'enabled'>>): ApprovalRule;
|
|
98
|
+
deleteRule(id: string): boolean;
|
|
99
|
+
check(apiKey: string, tool: string, creditCost: number): ApprovalCheckResult;
|
|
100
|
+
decide(decision: ApprovalDecision): ApprovalRequest;
|
|
101
|
+
getRequest(id: string): ApprovalRequest | undefined;
|
|
102
|
+
listRequests(filter?: {
|
|
103
|
+
status?: ApprovalStatus;
|
|
104
|
+
apiKey?: string;
|
|
105
|
+
tool?: string;
|
|
106
|
+
}): ApprovalRequest[];
|
|
107
|
+
expirePending(): number;
|
|
108
|
+
configure(updates: Partial<ApprovalWorkflowConfig>): ApprovalWorkflowConfig;
|
|
109
|
+
stats(): ApprovalWorkflowStats;
|
|
110
|
+
clear(): void;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=approval-workflows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval-workflows.d.ts","sourceRoot":"","sources":["../src/approval-workflows.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Approval Workflows — Pre-execution approval gates for tool calls.
|
|
4
|
+
*
|
|
5
|
+
* Define rules that require explicit admin approval before high-cost
|
|
6
|
+
* or sensitive tool calls are executed. Pending requests are held
|
|
7
|
+
* until approved or denied (or they expire).
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const approvals = new ApprovalWorkflowManager();
|
|
12
|
+
* approvals.configure({ enabled: true });
|
|
13
|
+
*
|
|
14
|
+
* // Require approval for tool calls costing more than 100 credits
|
|
15
|
+
* approvals.createRule({
|
|
16
|
+
* name: 'high-cost-gate',
|
|
17
|
+
* condition: 'cost_threshold',
|
|
18
|
+
* threshold: 100,
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
23
|
+
if (k2 === undefined) k2 = k;
|
|
24
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
25
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
26
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
27
|
+
}
|
|
28
|
+
Object.defineProperty(o, k2, desc);
|
|
29
|
+
}) : (function(o, m, k, k2) {
|
|
30
|
+
if (k2 === undefined) k2 = k;
|
|
31
|
+
o[k2] = m[k];
|
|
32
|
+
}));
|
|
33
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
34
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
35
|
+
}) : function(o, v) {
|
|
36
|
+
o["default"] = v;
|
|
37
|
+
});
|
|
38
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
39
|
+
var ownKeys = function(o) {
|
|
40
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
41
|
+
var ar = [];
|
|
42
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
43
|
+
return ar;
|
|
44
|
+
};
|
|
45
|
+
return ownKeys(o);
|
|
46
|
+
};
|
|
47
|
+
return function (mod) {
|
|
48
|
+
if (mod && mod.__esModule) return mod;
|
|
49
|
+
var result = {};
|
|
50
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
51
|
+
__setModuleDefault(result, mod);
|
|
52
|
+
return result;
|
|
53
|
+
};
|
|
54
|
+
})();
|
|
55
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
56
|
+
exports.ApprovalWorkflowManager = void 0;
|
|
57
|
+
const crypto = __importStar(require("crypto"));
|
|
58
|
+
/* ------------------------------------------------------------------ */
|
|
59
|
+
/* Helpers */
|
|
60
|
+
/* ------------------------------------------------------------------ */
|
|
61
|
+
function makeRuleId() {
|
|
62
|
+
return 'ar_' + crypto.randomBytes(8).toString('hex');
|
|
63
|
+
}
|
|
64
|
+
function makeRequestId() {
|
|
65
|
+
return 'areq_' + crypto.randomBytes(8).toString('hex');
|
|
66
|
+
}
|
|
67
|
+
function matchesGlob(pattern, value) {
|
|
68
|
+
if (pattern === '*')
|
|
69
|
+
return true;
|
|
70
|
+
if (!pattern.includes('*'))
|
|
71
|
+
return pattern === value;
|
|
72
|
+
const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
|
|
73
|
+
return regex.test(value);
|
|
74
|
+
}
|
|
75
|
+
/* ------------------------------------------------------------------ */
|
|
76
|
+
/* Manager */
|
|
77
|
+
/* ------------------------------------------------------------------ */
|
|
78
|
+
class ApprovalWorkflowManager {
|
|
79
|
+
rules = new Map();
|
|
80
|
+
requests = new Map();
|
|
81
|
+
config = {
|
|
82
|
+
enabled: false,
|
|
83
|
+
maxRules: 100,
|
|
84
|
+
maxPendingRequests: 5000,
|
|
85
|
+
defaultExpiryMs: 3600_000, // 1 hour
|
|
86
|
+
};
|
|
87
|
+
/* ── Rule CRUD ─────────────────────────────────────────────────── */
|
|
88
|
+
createRule(params) {
|
|
89
|
+
if (!this.config.enabled)
|
|
90
|
+
throw new Error('Approval workflows are disabled');
|
|
91
|
+
if (this.rules.size >= this.config.maxRules) {
|
|
92
|
+
throw new Error(`Maximum rules reached (${this.config.maxRules})`);
|
|
93
|
+
}
|
|
94
|
+
if (!params.name || !params.condition) {
|
|
95
|
+
throw new Error('name and condition are required');
|
|
96
|
+
}
|
|
97
|
+
const VALID_CONDITIONS = ['cost_threshold', 'tool_match', 'key_match'];
|
|
98
|
+
if (!VALID_CONDITIONS.includes(params.condition)) {
|
|
99
|
+
throw new Error(`Invalid condition: ${params.condition}`);
|
|
100
|
+
}
|
|
101
|
+
if (params.condition === 'cost_threshold' && (params.threshold === undefined || params.threshold <= 0)) {
|
|
102
|
+
throw new Error('threshold must be > 0 for cost_threshold condition');
|
|
103
|
+
}
|
|
104
|
+
if (params.condition === 'tool_match' && !params.toolPattern) {
|
|
105
|
+
throw new Error('toolPattern is required for tool_match condition');
|
|
106
|
+
}
|
|
107
|
+
if (params.condition === 'key_match' && !params.keyPrefix) {
|
|
108
|
+
throw new Error('keyPrefix is required for key_match condition');
|
|
109
|
+
}
|
|
110
|
+
// Check duplicate name
|
|
111
|
+
for (const r of this.rules.values()) {
|
|
112
|
+
if (r.name === params.name)
|
|
113
|
+
throw new Error(`Rule name '${params.name}' already exists`);
|
|
114
|
+
}
|
|
115
|
+
const now = new Date().toISOString();
|
|
116
|
+
const rule = {
|
|
117
|
+
id: makeRuleId(),
|
|
118
|
+
name: params.name,
|
|
119
|
+
condition: params.condition,
|
|
120
|
+
threshold: params.threshold,
|
|
121
|
+
toolPattern: params.toolPattern,
|
|
122
|
+
keyPrefix: params.keyPrefix,
|
|
123
|
+
enabled: params.enabled !== false,
|
|
124
|
+
createdAt: now,
|
|
125
|
+
updatedAt: now,
|
|
126
|
+
triggerCount: 0,
|
|
127
|
+
};
|
|
128
|
+
this.rules.set(rule.id, rule);
|
|
129
|
+
return rule;
|
|
130
|
+
}
|
|
131
|
+
getRule(id) {
|
|
132
|
+
return this.rules.get(id);
|
|
133
|
+
}
|
|
134
|
+
listRules(filter) {
|
|
135
|
+
let result = Array.from(this.rules.values());
|
|
136
|
+
if (filter?.condition)
|
|
137
|
+
result = result.filter(r => r.condition === filter.condition);
|
|
138
|
+
if (filter?.enabled !== undefined)
|
|
139
|
+
result = result.filter(r => r.enabled === filter.enabled);
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
updateRule(id, updates) {
|
|
143
|
+
const rule = this.rules.get(id);
|
|
144
|
+
if (!rule)
|
|
145
|
+
throw new Error(`Rule not found: ${id}`);
|
|
146
|
+
if (updates.name !== undefined) {
|
|
147
|
+
for (const r of this.rules.values()) {
|
|
148
|
+
if (r.id !== id && r.name === updates.name) {
|
|
149
|
+
throw new Error(`Rule name '${updates.name}' already exists`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
rule.name = updates.name;
|
|
153
|
+
}
|
|
154
|
+
if (updates.threshold !== undefined)
|
|
155
|
+
rule.threshold = updates.threshold;
|
|
156
|
+
if (updates.toolPattern !== undefined)
|
|
157
|
+
rule.toolPattern = updates.toolPattern;
|
|
158
|
+
if (updates.keyPrefix !== undefined)
|
|
159
|
+
rule.keyPrefix = updates.keyPrefix;
|
|
160
|
+
if (updates.enabled !== undefined)
|
|
161
|
+
rule.enabled = updates.enabled;
|
|
162
|
+
rule.updatedAt = new Date().toISOString();
|
|
163
|
+
return rule;
|
|
164
|
+
}
|
|
165
|
+
deleteRule(id) {
|
|
166
|
+
return this.rules.delete(id);
|
|
167
|
+
}
|
|
168
|
+
/* ── Check & Request ───────────────────────────────────────────── */
|
|
169
|
+
check(apiKey, tool, creditCost) {
|
|
170
|
+
if (!this.config.enabled)
|
|
171
|
+
return { requiresApproval: false, matchedRules: [] };
|
|
172
|
+
const matched = [];
|
|
173
|
+
for (const rule of this.rules.values()) {
|
|
174
|
+
if (!rule.enabled)
|
|
175
|
+
continue;
|
|
176
|
+
let matches = false;
|
|
177
|
+
switch (rule.condition) {
|
|
178
|
+
case 'cost_threshold':
|
|
179
|
+
matches = creditCost >= (rule.threshold ?? Infinity);
|
|
180
|
+
break;
|
|
181
|
+
case 'tool_match':
|
|
182
|
+
matches = rule.toolPattern ? matchesGlob(rule.toolPattern, tool) : false;
|
|
183
|
+
break;
|
|
184
|
+
case 'key_match':
|
|
185
|
+
matches = rule.keyPrefix ? apiKey.startsWith(rule.keyPrefix) : false;
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
if (matches) {
|
|
189
|
+
matched.push(rule.id);
|
|
190
|
+
rule.triggerCount++;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (matched.length === 0)
|
|
194
|
+
return { requiresApproval: false, matchedRules: [] };
|
|
195
|
+
// Create a pending request
|
|
196
|
+
const pendingCount = Array.from(this.requests.values()).filter(r => r.status === 'pending').length;
|
|
197
|
+
if (pendingCount >= this.config.maxPendingRequests) {
|
|
198
|
+
throw new Error('Maximum pending approval requests reached');
|
|
199
|
+
}
|
|
200
|
+
const firstRule = this.rules.get(matched[0]);
|
|
201
|
+
const now = new Date();
|
|
202
|
+
const request = {
|
|
203
|
+
id: makeRequestId(),
|
|
204
|
+
ruleId: firstRule.id,
|
|
205
|
+
ruleName: firstRule.name,
|
|
206
|
+
apiKey,
|
|
207
|
+
tool,
|
|
208
|
+
creditCost,
|
|
209
|
+
status: 'pending',
|
|
210
|
+
createdAt: now.toISOString(),
|
|
211
|
+
updatedAt: now.toISOString(),
|
|
212
|
+
expiresAt: new Date(now.getTime() + this.config.defaultExpiryMs).toISOString(),
|
|
213
|
+
};
|
|
214
|
+
this.requests.set(request.id, request);
|
|
215
|
+
return {
|
|
216
|
+
requiresApproval: true,
|
|
217
|
+
matchedRules: matched,
|
|
218
|
+
requestId: request.id,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/* ── Decision ──────────────────────────────────────────────────── */
|
|
222
|
+
decide(decision) {
|
|
223
|
+
const request = this.requests.get(decision.requestId);
|
|
224
|
+
if (!request)
|
|
225
|
+
throw new Error(`Request not found: ${decision.requestId}`);
|
|
226
|
+
if (request.status !== 'pending') {
|
|
227
|
+
throw new Error(`Request is not pending (current: ${request.status})`);
|
|
228
|
+
}
|
|
229
|
+
// Check expiry
|
|
230
|
+
if (new Date(request.expiresAt) < new Date()) {
|
|
231
|
+
request.status = 'expired';
|
|
232
|
+
request.updatedAt = new Date().toISOString();
|
|
233
|
+
throw new Error('Request has expired');
|
|
234
|
+
}
|
|
235
|
+
request.status = decision.status;
|
|
236
|
+
request.reason = decision.reason;
|
|
237
|
+
request.decidedBy = decision.decidedBy;
|
|
238
|
+
request.updatedAt = new Date().toISOString();
|
|
239
|
+
return request;
|
|
240
|
+
}
|
|
241
|
+
/* ── Request Queries ───────────────────────────────────────────── */
|
|
242
|
+
getRequest(id) {
|
|
243
|
+
return this.requests.get(id);
|
|
244
|
+
}
|
|
245
|
+
listRequests(filter) {
|
|
246
|
+
let result = Array.from(this.requests.values());
|
|
247
|
+
if (filter?.status)
|
|
248
|
+
result = result.filter(r => r.status === filter.status);
|
|
249
|
+
if (filter?.apiKey)
|
|
250
|
+
result = result.filter(r => r.apiKey === filter.apiKey);
|
|
251
|
+
if (filter?.tool)
|
|
252
|
+
result = result.filter(r => r.tool === filter.tool);
|
|
253
|
+
return result.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
254
|
+
}
|
|
255
|
+
expirePending() {
|
|
256
|
+
const now = new Date();
|
|
257
|
+
let count = 0;
|
|
258
|
+
for (const req of this.requests.values()) {
|
|
259
|
+
if (req.status === 'pending' && new Date(req.expiresAt) < now) {
|
|
260
|
+
req.status = 'expired';
|
|
261
|
+
req.updatedAt = now.toISOString();
|
|
262
|
+
count++;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return count;
|
|
266
|
+
}
|
|
267
|
+
/* ── Config & Stats ────────────────────────────────────────────── */
|
|
268
|
+
configure(updates) {
|
|
269
|
+
if (updates.enabled !== undefined)
|
|
270
|
+
this.config.enabled = updates.enabled;
|
|
271
|
+
if (updates.maxRules !== undefined && updates.maxRules > 0)
|
|
272
|
+
this.config.maxRules = updates.maxRules;
|
|
273
|
+
if (updates.maxPendingRequests !== undefined && updates.maxPendingRequests > 0)
|
|
274
|
+
this.config.maxPendingRequests = updates.maxPendingRequests;
|
|
275
|
+
if (updates.defaultExpiryMs !== undefined && updates.defaultExpiryMs > 0)
|
|
276
|
+
this.config.defaultExpiryMs = updates.defaultExpiryMs;
|
|
277
|
+
return { ...this.config };
|
|
278
|
+
}
|
|
279
|
+
stats() {
|
|
280
|
+
const rules = Array.from(this.rules.values());
|
|
281
|
+
const requests = Array.from(this.requests.values());
|
|
282
|
+
const byCondition = { cost_threshold: 0, tool_match: 0, key_match: 0 };
|
|
283
|
+
for (const r of rules)
|
|
284
|
+
byCondition[r.condition]++;
|
|
285
|
+
return {
|
|
286
|
+
totalRules: rules.length,
|
|
287
|
+
enabledRules: rules.filter(r => r.enabled).length,
|
|
288
|
+
totalRequests: requests.length,
|
|
289
|
+
pendingRequests: requests.filter(r => r.status === 'pending').length,
|
|
290
|
+
approvedRequests: requests.filter(r => r.status === 'approved').length,
|
|
291
|
+
deniedRequests: requests.filter(r => r.status === 'denied').length,
|
|
292
|
+
expiredRequests: requests.filter(r => r.status === 'expired').length,
|
|
293
|
+
byCondition,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
clear() {
|
|
297
|
+
this.rules.clear();
|
|
298
|
+
this.requests.clear();
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
exports.ApprovalWorkflowManager = ApprovalWorkflowManager;
|
|
302
|
+
//# sourceMappingURL=approval-workflows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval-workflows.js","sourceRoot":"","sources":["../src/approval-workflows.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfigProfileManager — Named configuration presets.
|
|
3
|
+
*
|
|
4
|
+
* Store and switch between named configuration profiles for different
|
|
5
|
+
* environments (dev, staging, production) or use cases:
|
|
6
|
+
* - Save current config as a named profile
|
|
7
|
+
* - Switch between profiles at runtime
|
|
8
|
+
* - Compare profiles to see differences
|
|
9
|
+
* - Import/export profiles as JSON
|
|
10
|
+
* - Profile inheritance (extend a base profile)
|
|
11
|
+
* - Rollback to previous profile
|
|
12
|
+
*
|
|
13
|
+
* Zero external dependencies.
|
|
14
|
+
*/
|
|
15
|
+
export interface ConfigProfile {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
/** Optional description of what this profile is for. */
|
|
19
|
+
description?: string;
|
|
20
|
+
/** The configuration snapshot. */
|
|
21
|
+
config: Record<string, unknown>;
|
|
22
|
+
/** Profile this extends (inherits values from). */
|
|
23
|
+
extendsProfile?: string;
|
|
24
|
+
/** SHA-256 checksum of the config JSON. */
|
|
25
|
+
checksum: string;
|
|
26
|
+
/** Whether this is the currently active profile. */
|
|
27
|
+
active: boolean;
|
|
28
|
+
createdAt: number;
|
|
29
|
+
updatedAt: number;
|
|
30
|
+
}
|
|
31
|
+
export interface ProfileDiff {
|
|
32
|
+
/** Keys only in profile A. */
|
|
33
|
+
onlyInA: string[];
|
|
34
|
+
/** Keys only in profile B. */
|
|
35
|
+
onlyInB: string[];
|
|
36
|
+
/** Keys present in both but with different values. */
|
|
37
|
+
changed: Array<{
|
|
38
|
+
key: string;
|
|
39
|
+
valueA: unknown;
|
|
40
|
+
valueB: unknown;
|
|
41
|
+
}>;
|
|
42
|
+
/** Keys with identical values in both. */
|
|
43
|
+
unchanged: string[];
|
|
44
|
+
}
|
|
45
|
+
export interface ProfileStats {
|
|
46
|
+
totalProfiles: number;
|
|
47
|
+
activeProfile: string | null;
|
|
48
|
+
switchCount: number;
|
|
49
|
+
lastSwitchAt: number | null;
|
|
50
|
+
rollbackAvailable: boolean;
|
|
51
|
+
}
|
|
52
|
+
export interface ConfigProfileManagerConfig {
|
|
53
|
+
enabled: boolean;
|
|
54
|
+
maxProfiles: number;
|
|
55
|
+
/** Max config size in bytes. Default 1MB. */
|
|
56
|
+
maxConfigSize: number;
|
|
57
|
+
}
|
|
58
|
+
export declare class ConfigProfileManager {
|
|
59
|
+
private config;
|
|
60
|
+
private profiles;
|
|
61
|
+
private activeProfileId;
|
|
62
|
+
private previousProfileId;
|
|
63
|
+
private _switchCount;
|
|
64
|
+
private _lastSwitchAt;
|
|
65
|
+
private counter;
|
|
66
|
+
constructor(config?: Partial<ConfigProfileManagerConfig>);
|
|
67
|
+
/**
|
|
68
|
+
* Save a configuration as a named profile.
|
|
69
|
+
*/
|
|
70
|
+
saveProfile(params: {
|
|
71
|
+
name: string;
|
|
72
|
+
config: Record<string, unknown>;
|
|
73
|
+
description?: string;
|
|
74
|
+
extendsProfile?: string;
|
|
75
|
+
activate?: boolean;
|
|
76
|
+
}): ConfigProfile;
|
|
77
|
+
/**
|
|
78
|
+
* Get a profile by ID.
|
|
79
|
+
*/
|
|
80
|
+
getProfile(id: string): ConfigProfile | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* Get a profile by name.
|
|
83
|
+
*/
|
|
84
|
+
getProfileByName(name: string): ConfigProfile | undefined;
|
|
85
|
+
/**
|
|
86
|
+
* List all profiles.
|
|
87
|
+
*/
|
|
88
|
+
listProfiles(): ConfigProfile[];
|
|
89
|
+
/**
|
|
90
|
+
* Delete a profile.
|
|
91
|
+
*/
|
|
92
|
+
deleteProfile(id: string): boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Activate a profile (makes it the current active profile).
|
|
95
|
+
* Returns the resolved configuration (with inheritance applied).
|
|
96
|
+
*/
|
|
97
|
+
activateProfile(id: string): Record<string, unknown>;
|
|
98
|
+
/**
|
|
99
|
+
* Rollback to the previously active profile.
|
|
100
|
+
*/
|
|
101
|
+
rollback(): Record<string, unknown> | null;
|
|
102
|
+
/**
|
|
103
|
+
* Get the currently active profile.
|
|
104
|
+
*/
|
|
105
|
+
getActive(): ConfigProfile | null;
|
|
106
|
+
/**
|
|
107
|
+
* Resolve configuration for a profile, applying inheritance.
|
|
108
|
+
*/
|
|
109
|
+
resolveConfig(id: string): Record<string, unknown>;
|
|
110
|
+
/**
|
|
111
|
+
* Compare two profiles and return the differences.
|
|
112
|
+
*/
|
|
113
|
+
compare(idA: string, idB: string): ProfileDiff;
|
|
114
|
+
/**
|
|
115
|
+
* Export all profiles as JSON.
|
|
116
|
+
*/
|
|
117
|
+
exportProfiles(): string;
|
|
118
|
+
/**
|
|
119
|
+
* Import profiles from JSON. Returns count imported.
|
|
120
|
+
*/
|
|
121
|
+
importProfiles(json: string, mode?: 'merge' | 'replace'): number;
|
|
122
|
+
configure(updates: Partial<ConfigProfileManagerConfig>): ConfigProfileManagerConfig;
|
|
123
|
+
stats(): ProfileStats;
|
|
124
|
+
clear(): void;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=config-profiles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-profiles.d.ts","sourceRoot":"","sources":["../src/config-profiles.ts"],"names":[],"mappings":"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"}
|