paygate-mcp 3.4.0 → 3.6.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 +93 -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/gate.d.ts +9 -1
- package/dist/gate.d.ts.map +1 -1
- package/dist/gate.js +53 -11
- package/dist/gate.js.map +1 -1
- package/dist/groups.d.ts +140 -0
- package/dist/groups.d.ts.map +1 -0
- package/dist/groups.js +258 -0
- package/dist/groups.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/redis-sync.d.ts +28 -2
- package/dist/redis-sync.d.ts.map +1 -1
- package/dist/redis-sync.js +176 -0
- package/dist/redis-sync.js.map +1 -1
- package/dist/server.d.ts +8 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +266 -0
- package/dist/server.js.map +1 -1
- package/dist/store.d.ts +5 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +17 -0
- package/dist/store.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/groups.js
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Key Groups — Policy templates for API keys.
|
|
4
|
+
*
|
|
5
|
+
* Groups define shared policies (ACL, rate limits, pricing, quotas, IP rules)
|
|
6
|
+
* that are inherited by all member keys. Key-level settings override group defaults.
|
|
7
|
+
*
|
|
8
|
+
* Unlike Teams (which share budgets), Groups share *policies*:
|
|
9
|
+
* - Tool ACL (allowedTools / deniedTools)
|
|
10
|
+
* - Rate limit override (calls per minute)
|
|
11
|
+
* - Per-tool pricing overrides
|
|
12
|
+
* - Quota defaults (daily/monthly limits)
|
|
13
|
+
* - IP allowlist
|
|
14
|
+
* - Metadata tags
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.KeyGroupManager = void 0;
|
|
18
|
+
const crypto_1 = require("crypto");
|
|
19
|
+
// ─── KeyGroupManager ─────────────────────────────────────────────────────────
|
|
20
|
+
class KeyGroupManager {
|
|
21
|
+
groups = new Map();
|
|
22
|
+
/** Reverse index: apiKey → groupId */
|
|
23
|
+
keyToGroup = new Map();
|
|
24
|
+
// ─── CRUD ────────────────────────────────────────────────────────────────
|
|
25
|
+
createGroup(params) {
|
|
26
|
+
const name = String(params.name || '').trim();
|
|
27
|
+
if (!name)
|
|
28
|
+
throw new Error('Group must have a name');
|
|
29
|
+
// Enforce unique names
|
|
30
|
+
for (const g of this.groups.values()) {
|
|
31
|
+
if (g.active && g.name === name) {
|
|
32
|
+
throw new Error(`Group '${name}' already exists`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const id = 'grp_' + (0, crypto_1.randomBytes)(8).toString('hex');
|
|
36
|
+
const record = {
|
|
37
|
+
id,
|
|
38
|
+
name,
|
|
39
|
+
description: String(params.description || ''),
|
|
40
|
+
allowedTools: params.allowedTools || [],
|
|
41
|
+
deniedTools: params.deniedTools || [],
|
|
42
|
+
rateLimitPerMin: Math.max(0, Math.floor(Number(params.rateLimitPerMin) || 0)),
|
|
43
|
+
toolPricing: params.toolPricing || {},
|
|
44
|
+
quota: params.quota,
|
|
45
|
+
ipAllowlist: params.ipAllowlist || [],
|
|
46
|
+
defaultCredits: Math.max(0, Math.floor(Number(params.defaultCredits) || 0)),
|
|
47
|
+
maxSpendingLimit: Math.max(0, Math.floor(Number(params.maxSpendingLimit) || 0)),
|
|
48
|
+
tags: params.tags || {},
|
|
49
|
+
createdAt: new Date().toISOString(),
|
|
50
|
+
active: true,
|
|
51
|
+
};
|
|
52
|
+
this.groups.set(id, record);
|
|
53
|
+
return record;
|
|
54
|
+
}
|
|
55
|
+
getGroup(id) {
|
|
56
|
+
return this.groups.get(id);
|
|
57
|
+
}
|
|
58
|
+
getGroupByName(name) {
|
|
59
|
+
for (const g of this.groups.values()) {
|
|
60
|
+
if (g.active && g.name === name)
|
|
61
|
+
return g;
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
updateGroup(id, updates) {
|
|
66
|
+
const group = this.groups.get(id);
|
|
67
|
+
if (!group || !group.active)
|
|
68
|
+
throw new Error(`Group '${id}' not found`);
|
|
69
|
+
// Check name uniqueness if name is being changed
|
|
70
|
+
if (updates.name !== undefined && updates.name !== group.name) {
|
|
71
|
+
const name = String(updates.name).trim();
|
|
72
|
+
if (!name)
|
|
73
|
+
throw new Error('Group must have a name');
|
|
74
|
+
for (const g of this.groups.values()) {
|
|
75
|
+
if (g.active && g.id !== id && g.name === name) {
|
|
76
|
+
throw new Error(`Group '${name}' already exists`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
group.name = name;
|
|
80
|
+
}
|
|
81
|
+
if (updates.description !== undefined)
|
|
82
|
+
group.description = String(updates.description);
|
|
83
|
+
if (updates.allowedTools !== undefined)
|
|
84
|
+
group.allowedTools = updates.allowedTools;
|
|
85
|
+
if (updates.deniedTools !== undefined)
|
|
86
|
+
group.deniedTools = updates.deniedTools;
|
|
87
|
+
if (updates.rateLimitPerMin !== undefined)
|
|
88
|
+
group.rateLimitPerMin = Math.max(0, Math.floor(Number(updates.rateLimitPerMin) || 0));
|
|
89
|
+
if (updates.toolPricing !== undefined)
|
|
90
|
+
group.toolPricing = updates.toolPricing;
|
|
91
|
+
if (updates.quota === null)
|
|
92
|
+
delete group.quota;
|
|
93
|
+
else if (updates.quota !== undefined)
|
|
94
|
+
group.quota = updates.quota;
|
|
95
|
+
if (updates.ipAllowlist !== undefined)
|
|
96
|
+
group.ipAllowlist = updates.ipAllowlist;
|
|
97
|
+
if (updates.defaultCredits !== undefined)
|
|
98
|
+
group.defaultCredits = Math.max(0, Math.floor(Number(updates.defaultCredits) || 0));
|
|
99
|
+
if (updates.maxSpendingLimit !== undefined)
|
|
100
|
+
group.maxSpendingLimit = Math.max(0, Math.floor(Number(updates.maxSpendingLimit) || 0));
|
|
101
|
+
if (updates.tags !== undefined)
|
|
102
|
+
group.tags = { ...group.tags, ...updates.tags };
|
|
103
|
+
return group;
|
|
104
|
+
}
|
|
105
|
+
deleteGroup(id) {
|
|
106
|
+
const group = this.groups.get(id);
|
|
107
|
+
if (!group || !group.active)
|
|
108
|
+
return false;
|
|
109
|
+
group.active = false;
|
|
110
|
+
// Remove all key assignments for this group
|
|
111
|
+
for (const [key, gid] of this.keyToGroup.entries()) {
|
|
112
|
+
if (gid === id)
|
|
113
|
+
this.keyToGroup.delete(key);
|
|
114
|
+
}
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
listGroups() {
|
|
118
|
+
const result = [];
|
|
119
|
+
for (const g of this.groups.values()) {
|
|
120
|
+
if (!g.active)
|
|
121
|
+
continue;
|
|
122
|
+
const memberCount = this.getGroupMembers(g.id).length;
|
|
123
|
+
result.push({
|
|
124
|
+
id: g.id,
|
|
125
|
+
name: g.name,
|
|
126
|
+
description: g.description,
|
|
127
|
+
memberCount,
|
|
128
|
+
allowedTools: g.allowedTools,
|
|
129
|
+
deniedTools: g.deniedTools,
|
|
130
|
+
rateLimitPerMin: g.rateLimitPerMin,
|
|
131
|
+
quota: g.quota,
|
|
132
|
+
ipAllowlist: g.ipAllowlist,
|
|
133
|
+
defaultCredits: g.defaultCredits,
|
|
134
|
+
maxSpendingLimit: g.maxSpendingLimit,
|
|
135
|
+
tags: g.tags,
|
|
136
|
+
createdAt: g.createdAt,
|
|
137
|
+
active: g.active,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
// ─── Key Membership ──────────────────────────────────────────────────────
|
|
143
|
+
assignKey(apiKey, groupId) {
|
|
144
|
+
const group = this.groups.get(groupId);
|
|
145
|
+
if (!group || !group.active)
|
|
146
|
+
throw new Error(`Group '${groupId}' not found`);
|
|
147
|
+
this.keyToGroup.set(apiKey, groupId);
|
|
148
|
+
}
|
|
149
|
+
removeKey(apiKey) {
|
|
150
|
+
return this.keyToGroup.delete(apiKey);
|
|
151
|
+
}
|
|
152
|
+
getKeyGroup(apiKey) {
|
|
153
|
+
const groupId = this.keyToGroup.get(apiKey);
|
|
154
|
+
if (!groupId)
|
|
155
|
+
return undefined;
|
|
156
|
+
const group = this.groups.get(groupId);
|
|
157
|
+
if (!group || !group.active) {
|
|
158
|
+
this.keyToGroup.delete(apiKey);
|
|
159
|
+
return undefined;
|
|
160
|
+
}
|
|
161
|
+
return group;
|
|
162
|
+
}
|
|
163
|
+
getKeyGroupId(apiKey) {
|
|
164
|
+
const groupId = this.keyToGroup.get(apiKey);
|
|
165
|
+
if (!groupId)
|
|
166
|
+
return undefined;
|
|
167
|
+
const group = this.groups.get(groupId);
|
|
168
|
+
if (!group || !group.active) {
|
|
169
|
+
this.keyToGroup.delete(apiKey);
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
return groupId;
|
|
173
|
+
}
|
|
174
|
+
getGroupMembers(groupId) {
|
|
175
|
+
const members = [];
|
|
176
|
+
for (const [key, gid] of this.keyToGroup.entries()) {
|
|
177
|
+
if (gid === groupId)
|
|
178
|
+
members.push(key);
|
|
179
|
+
}
|
|
180
|
+
return members;
|
|
181
|
+
}
|
|
182
|
+
// ─── Policy Resolution ───────────────────────────────────────────────────
|
|
183
|
+
/**
|
|
184
|
+
* Resolve the effective policy for a key, merging group defaults with key overrides.
|
|
185
|
+
*
|
|
186
|
+
* Resolution rules:
|
|
187
|
+
* - allowedTools: key-level wins if non-empty, else group default
|
|
188
|
+
* - deniedTools: union of group + key (both applied)
|
|
189
|
+
* - rateLimitPerMin: key-level wins if set, else group default
|
|
190
|
+
* - quota: key-level wins if set, else group default
|
|
191
|
+
* - ipAllowlist: union of group + key (both applied)
|
|
192
|
+
* - toolPricing: group pricing is base, key-level (if any) would need external handling
|
|
193
|
+
* - maxSpendingLimit: group's maxSpendingLimit is a cap on the key's spending limit
|
|
194
|
+
*/
|
|
195
|
+
resolvePolicy(apiKey, keyRecord) {
|
|
196
|
+
const group = this.getKeyGroup(apiKey);
|
|
197
|
+
if (!group)
|
|
198
|
+
return null;
|
|
199
|
+
// Allowed tools: key wins if non-empty, else group
|
|
200
|
+
const allowedTools = keyRecord.allowedTools.length > 0
|
|
201
|
+
? keyRecord.allowedTools
|
|
202
|
+
: group.allowedTools;
|
|
203
|
+
// Denied tools: union (both applied)
|
|
204
|
+
const deniedSet = new Set([...group.deniedTools, ...keyRecord.deniedTools]);
|
|
205
|
+
const deniedTools = Array.from(deniedSet);
|
|
206
|
+
// Rate limit: group default (0 = use global)
|
|
207
|
+
const rateLimitPerMin = group.rateLimitPerMin;
|
|
208
|
+
// Quota: key wins if set, else group
|
|
209
|
+
const quota = keyRecord.quota || group.quota;
|
|
210
|
+
// IP allowlist: union
|
|
211
|
+
const ipSet = new Set([...group.ipAllowlist, ...keyRecord.ipAllowlist]);
|
|
212
|
+
const ipAllowlist = Array.from(ipSet);
|
|
213
|
+
// Tool pricing: group overrides
|
|
214
|
+
const toolPricing = group.toolPricing;
|
|
215
|
+
// Spending limit: cap to group's max if group has one set and key's limit is higher (or unlimited)
|
|
216
|
+
let maxSpendingLimit = group.maxSpendingLimit;
|
|
217
|
+
return {
|
|
218
|
+
allowedTools,
|
|
219
|
+
deniedTools,
|
|
220
|
+
rateLimitPerMin,
|
|
221
|
+
quota,
|
|
222
|
+
ipAllowlist,
|
|
223
|
+
toolPricing,
|
|
224
|
+
maxSpendingLimit,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
// ─── Serialization (for state file persistence) ──────────────────────────
|
|
228
|
+
serialize() {
|
|
229
|
+
return {
|
|
230
|
+
groups: Array.from(this.groups.entries()),
|
|
231
|
+
assignments: Array.from(this.keyToGroup.entries()),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
load(data) {
|
|
235
|
+
this.groups.clear();
|
|
236
|
+
this.keyToGroup.clear();
|
|
237
|
+
if (data.groups) {
|
|
238
|
+
for (const [id, record] of data.groups) {
|
|
239
|
+
this.groups.set(id, record);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (data.assignments) {
|
|
243
|
+
for (const [key, groupId] of data.assignments) {
|
|
244
|
+
this.keyToGroup.set(key, groupId);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
get count() {
|
|
249
|
+
let count = 0;
|
|
250
|
+
for (const g of this.groups.values()) {
|
|
251
|
+
if (g.active)
|
|
252
|
+
count++;
|
|
253
|
+
}
|
|
254
|
+
return count;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
exports.KeyGroupManager = KeyGroupManager;
|
|
258
|
+
//# sourceMappingURL=groups.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"groups.js","sourceRoot":"","sources":["../src/groups.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -57,6 +57,8 @@ export { AdminKeyManager, ROLE_HIERARCHY, VALID_ROLES } from './admin-keys';
|
|
|
57
57
|
export type { AdminRole, AdminKeyRecord } from './admin-keys';
|
|
58
58
|
export { PluginManager } from './plugin';
|
|
59
59
|
export type { PayGatePlugin, PluginGateContext, PluginToolContext, PluginGateOverride, PluginInfo } from './plugin';
|
|
60
|
+
export { KeyGroupManager } from './groups';
|
|
61
|
+
export type { KeyGroupRecord, KeyGroupInfo, ResolvedPolicy } from './groups';
|
|
60
62
|
export type { PayGateConfig, JsonRpcRequest, JsonRpcResponse, JsonRpcError, ToolCallParams, ToolInfo, ToolPricing, ServerBackendConfig, ApiKeyRecord, UsageEvent, UsageSummary, GateDecision, QuotaConfig, BatchToolCall, BatchGateResult, } from './types';
|
|
61
63
|
export { DEFAULT_CONFIG } from './types';
|
|
62
64
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* ```
|
|
17
17
|
*/
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.DEFAULT_CONFIG = exports.PluginManager = exports.VALID_ROLES = exports.ROLE_HIERARCHY = exports.AdminKeyManager = exports.TokenRevocationList = exports.ScopedTokenManager = exports.formatDiagnostics = exports.validateConfig = exports.PayGateError = exports.PayGateClient = exports.RedisSync = exports.RedisSubscriber = exports.parseRedisUrl = exports.RedisClient = exports.TeamManager = exports.AlertEngine = exports.AnalyticsEngine = exports.getDashboardHtml = exports.MetricsCollector = exports.ToolRegistry = exports.maskKeyForAudit = exports.AuditLogger = exports.writeSseKeepAlive = exports.writeSseEvent = exports.writeSseHeaders = exports.SessionManager = exports.OAuthProvider = exports.QuotaTracker = exports.WebhookEmitter = exports.StripeWebhookHandler = exports.RateLimiter = exports.UsageMeter = exports.KeyStore = exports.MultiServerRouter = exports.HttpMcpProxy = exports.McpProxy = exports.Gate = exports.PayGateServer = void 0;
|
|
19
|
+
exports.DEFAULT_CONFIG = exports.KeyGroupManager = exports.PluginManager = exports.VALID_ROLES = exports.ROLE_HIERARCHY = exports.AdminKeyManager = exports.TokenRevocationList = exports.ScopedTokenManager = exports.formatDiagnostics = exports.validateConfig = exports.PayGateError = exports.PayGateClient = exports.RedisSync = exports.RedisSubscriber = exports.parseRedisUrl = exports.RedisClient = exports.TeamManager = exports.AlertEngine = exports.AnalyticsEngine = exports.getDashboardHtml = exports.MetricsCollector = exports.ToolRegistry = exports.maskKeyForAudit = exports.AuditLogger = exports.writeSseKeepAlive = exports.writeSseEvent = exports.writeSseHeaders = exports.SessionManager = exports.OAuthProvider = exports.QuotaTracker = exports.WebhookEmitter = exports.StripeWebhookHandler = exports.RateLimiter = exports.UsageMeter = exports.KeyStore = exports.MultiServerRouter = exports.HttpMcpProxy = exports.McpProxy = exports.Gate = exports.PayGateServer = void 0;
|
|
20
20
|
var server_1 = require("./server");
|
|
21
21
|
Object.defineProperty(exports, "PayGateServer", { enumerable: true, get: function () { return server_1.PayGateServer; } });
|
|
22
22
|
var gate_1 = require("./gate");
|
|
@@ -82,6 +82,8 @@ Object.defineProperty(exports, "ROLE_HIERARCHY", { enumerable: true, get: functi
|
|
|
82
82
|
Object.defineProperty(exports, "VALID_ROLES", { enumerable: true, get: function () { return admin_keys_1.VALID_ROLES; } });
|
|
83
83
|
var plugin_1 = require("./plugin");
|
|
84
84
|
Object.defineProperty(exports, "PluginManager", { enumerable: true, get: function () { return plugin_1.PluginManager; } });
|
|
85
|
+
var groups_1 = require("./groups");
|
|
86
|
+
Object.defineProperty(exports, "KeyGroupManager", { enumerable: true, get: function () { return groups_1.KeyGroupManager; } });
|
|
85
87
|
var types_1 = require("./types");
|
|
86
88
|
Object.defineProperty(exports, "DEFAULT_CONFIG", { enumerable: true, get: function () { return types_1.DEFAULT_CONFIG; } });
|
|
87
89
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAEH,mCAAyC;AAAhC,uGAAA,aAAa,OAAA;AACtB,+BAA8B;AAArB,4FAAA,IAAI,OAAA;AACb,iCAAmC;AAA1B,iGAAA,QAAQ,OAAA;AACjB,2CAA4C;AAAnC,0GAAA,YAAY,OAAA;AACrB,mCAA6C;AAApC,2GAAA,iBAAiB,OAAA;AAC1B,iCAAmC;AAA1B,iGAAA,QAAQ,OAAA;AACjB,iCAAqC;AAA5B,mGAAA,UAAU,OAAA;AACnB,+CAA6C;AAApC,2GAAA,WAAW,OAAA;AACpB,mCAAgD;AAAvC,8GAAA,oBAAoB,OAAA;AAC7B,qCAA2C;AAAlC,yGAAA,cAAc,OAAA;AAEvB,iCAAuC;AAA9B,qGAAA,YAAY,OAAA;AACrB,iCAAwC;AAA/B,sGAAA,aAAa,OAAA;AAEtB,qCAA8F;AAArF,yGAAA,cAAc,OAAA;AAAE,0GAAA,eAAe,OAAA;AAAE,wGAAA,aAAa,OAAA;AAAE,4GAAA,iBAAiB,OAAA;AAC1E,iCAAuD;AAA9C,oGAAA,WAAW,OAAA;AAAE,wGAAA,eAAe,OAAA;AAErC,uCAA0C;AAAjC,wGAAA,YAAY,OAAA;AACrB,qCAA6C;AAApC,2GAAA,gBAAgB,OAAA;AAIzB,yCAA+C;AAAtC,6GAAA,gBAAgB,OAAA;AACzB,yCAA8C;AAArC,4GAAA,eAAe,OAAA;AAExB,mCAAuC;AAA9B,qGAAA,WAAW,OAAA;AAEpB,iCAAsC;AAA7B,oGAAA,WAAW,OAAA;AAEpB,+CAA6E;AAApE,2GAAA,WAAW,OAAA;AAAE,6GAAA,aAAa,OAAA;AAAE,+GAAA,eAAe,OAAA;AAEpD,2CAAyC;AAAhC,uGAAA,SAAS,OAAA;AAElB,mCAAuD;AAA9C,uGAAA,aAAa,OAAA;AAAE,sGAAA,YAAY,OAAA;AAEpC,uDAAuE;AAA9D,kHAAA,cAAc,OAAA;AAAE,qHAAA,iBAAiB,OAAA;AAE1C,mCAAmE;AAA1D,4GAAA,kBAAkB,OAAA;AAAE,6GAAA,mBAAmB,OAAA;AAEhD,2CAA4E;AAAnE,6GAAA,eAAe,OAAA;AAAE,4GAAA,cAAc,OAAA;AAAE,yGAAA,WAAW,OAAA;AAErD,mCAAyC;AAAhC,uGAAA,aAAa,OAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAEH,mCAAyC;AAAhC,uGAAA,aAAa,OAAA;AACtB,+BAA8B;AAArB,4FAAA,IAAI,OAAA;AACb,iCAAmC;AAA1B,iGAAA,QAAQ,OAAA;AACjB,2CAA4C;AAAnC,0GAAA,YAAY,OAAA;AACrB,mCAA6C;AAApC,2GAAA,iBAAiB,OAAA;AAC1B,iCAAmC;AAA1B,iGAAA,QAAQ,OAAA;AACjB,iCAAqC;AAA5B,mGAAA,UAAU,OAAA;AACnB,+CAA6C;AAApC,2GAAA,WAAW,OAAA;AACpB,mCAAgD;AAAvC,8GAAA,oBAAoB,OAAA;AAC7B,qCAA2C;AAAlC,yGAAA,cAAc,OAAA;AAEvB,iCAAuC;AAA9B,qGAAA,YAAY,OAAA;AACrB,iCAAwC;AAA/B,sGAAA,aAAa,OAAA;AAEtB,qCAA8F;AAArF,yGAAA,cAAc,OAAA;AAAE,0GAAA,eAAe,OAAA;AAAE,wGAAA,aAAa,OAAA;AAAE,4GAAA,iBAAiB,OAAA;AAC1E,iCAAuD;AAA9C,oGAAA,WAAW,OAAA;AAAE,wGAAA,eAAe,OAAA;AAErC,uCAA0C;AAAjC,wGAAA,YAAY,OAAA;AACrB,qCAA6C;AAApC,2GAAA,gBAAgB,OAAA;AAIzB,yCAA+C;AAAtC,6GAAA,gBAAgB,OAAA;AACzB,yCAA8C;AAArC,4GAAA,eAAe,OAAA;AAExB,mCAAuC;AAA9B,qGAAA,WAAW,OAAA;AAEpB,iCAAsC;AAA7B,oGAAA,WAAW,OAAA;AAEpB,+CAA6E;AAApE,2GAAA,WAAW,OAAA;AAAE,6GAAA,aAAa,OAAA;AAAE,+GAAA,eAAe,OAAA;AAEpD,2CAAyC;AAAhC,uGAAA,SAAS,OAAA;AAElB,mCAAuD;AAA9C,uGAAA,aAAa,OAAA;AAAE,sGAAA,YAAY,OAAA;AAEpC,uDAAuE;AAA9D,kHAAA,cAAc,OAAA;AAAE,qHAAA,iBAAiB,OAAA;AAE1C,mCAAmE;AAA1D,4GAAA,kBAAkB,OAAA;AAAE,6GAAA,mBAAmB,OAAA;AAEhD,2CAA4E;AAAnE,6GAAA,eAAe,OAAA;AAAE,4GAAA,cAAc,OAAA;AAAE,yGAAA,WAAW,OAAA;AAErD,mCAAyC;AAAhC,uGAAA,aAAa,OAAA;AAEtB,mCAA2C;AAAlC,yGAAA,eAAe,OAAA;AAqBxB,iCAAyC;AAAhC,uGAAA,cAAc,OAAA"}
|
package/dist/redis-sync.d.ts
CHANGED
|
@@ -18,10 +18,11 @@ import { RedisClient } from './redis-client';
|
|
|
18
18
|
import type { RedisClientOptions } from './redis-client';
|
|
19
19
|
import { KeyStore } from './store';
|
|
20
20
|
import { ApiKeyRecord, UsageEvent } from './types';
|
|
21
|
+
import { KeyGroupManager, KeyGroupRecord } from './groups';
|
|
21
22
|
export interface PubSubEvent {
|
|
22
23
|
/** Event type */
|
|
23
|
-
type: 'key_updated' | 'key_revoked' | 'credits_changed' | 'key_created' | 'token_revoked';
|
|
24
|
-
/** API key affected */
|
|
24
|
+
type: 'key_updated' | 'key_revoked' | 'credits_changed' | 'key_created' | 'token_revoked' | 'group_updated' | 'group_deleted' | 'group_assignment_changed';
|
|
25
|
+
/** API key or group ID affected */
|
|
25
26
|
key: string;
|
|
26
27
|
/** Originating instance ID (for self-message filtering) */
|
|
27
28
|
instanceId: string;
|
|
@@ -53,6 +54,8 @@ export declare class RedisSync {
|
|
|
53
54
|
onPubSubEvent?: (event: PubSubEvent) => void;
|
|
54
55
|
/** Callback for token revocation events (wired to ScopedTokenManager by server) */
|
|
55
56
|
onTokenRevoked?: (fingerprint: string, expiresAt: string, revokedAt: string, reason?: string) => void;
|
|
57
|
+
/** Optional KeyGroupManager for group sync (wired by server when groups are used) */
|
|
58
|
+
groupManager?: KeyGroupManager;
|
|
56
59
|
constructor(redis: RedisClient, store: KeyStore, syncIntervalMs?: number);
|
|
57
60
|
/**
|
|
58
61
|
* Initialize: connect to Redis, load existing state, and start pub/sub listener.
|
|
@@ -143,5 +146,28 @@ export declare class RedisSync {
|
|
|
143
146
|
private pushLocalToRedis;
|
|
144
147
|
private recordToHash;
|
|
145
148
|
private hashToRecord;
|
|
149
|
+
/**
|
|
150
|
+
* Save a group record to Redis. Fire-and-forget.
|
|
151
|
+
*/
|
|
152
|
+
saveGroup(group: KeyGroupRecord): Promise<void>;
|
|
153
|
+
/**
|
|
154
|
+
* Delete a group from Redis. Fire-and-forget.
|
|
155
|
+
*/
|
|
156
|
+
deleteGroup(groupId: string): Promise<void>;
|
|
157
|
+
/**
|
|
158
|
+
* Save all group assignments to Redis as a single hash (apiKey → groupId).
|
|
159
|
+
* Fire-and-forget.
|
|
160
|
+
*/
|
|
161
|
+
saveGroupAssignments(): Promise<void>;
|
|
162
|
+
/**
|
|
163
|
+
* Load all groups and assignments from Redis into the local KeyGroupManager.
|
|
164
|
+
*/
|
|
165
|
+
loadGroupsFromRedis(): Promise<void>;
|
|
166
|
+
/**
|
|
167
|
+
* Push local groups to Redis (used when Redis is empty on first connect).
|
|
168
|
+
*/
|
|
169
|
+
private pushGroupsToRedis;
|
|
170
|
+
private groupToHash;
|
|
171
|
+
private hashToGroup;
|
|
146
172
|
}
|
|
147
173
|
//# sourceMappingURL=redis-sync.d.ts.map
|
package/dist/redis-sync.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis-sync.d.ts","sourceRoot":"","sources":["../src/redis-sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,WAAW,EAAkC,MAAM,gBAAgB,CAAC;AAC7E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,YAAY,EAAe,UAAU,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"redis-sync.d.ts","sourceRoot":"","sources":["../src/redis-sync.ts"],"names":[],"mappings":"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"}
|
package/dist/redis-sync.js
CHANGED
|
@@ -24,6 +24,9 @@ const KEY_SET = 'pg:keys';
|
|
|
24
24
|
const META_KEY = 'pg:meta';
|
|
25
25
|
const USAGE_LIST = 'pg:usage';
|
|
26
26
|
const RATE_PREFIX = 'pg:rate:';
|
|
27
|
+
const GROUP_PREFIX = 'pg:group:';
|
|
28
|
+
const GROUP_SET = 'pg:groups';
|
|
29
|
+
const GROUP_ASSIGN_KEY = 'pg:group_assignments';
|
|
27
30
|
const PG_CHANNEL = 'pg:events';
|
|
28
31
|
/** Lua: atomic credit deduction — check + deduct + increment in one round trip */
|
|
29
32
|
const DEDUCT_LUA = `
|
|
@@ -93,6 +96,8 @@ class RedisSync {
|
|
|
93
96
|
onPubSubEvent;
|
|
94
97
|
/** Callback for token revocation events (wired to ScopedTokenManager by server) */
|
|
95
98
|
onTokenRevoked;
|
|
99
|
+
/** Optional KeyGroupManager for group sync (wired by server when groups are used) */
|
|
100
|
+
groupManager;
|
|
96
101
|
constructor(redis, store, syncIntervalMs = 5000) {
|
|
97
102
|
this.redis = redis;
|
|
98
103
|
this.store = store;
|
|
@@ -108,11 +113,15 @@ class RedisSync {
|
|
|
108
113
|
await this.redis.ping();
|
|
109
114
|
console.log('[paygate:redis] Connected to Redis');
|
|
110
115
|
await this.loadFromRedis();
|
|
116
|
+
await this.loadGroupsFromRedis();
|
|
111
117
|
// Start periodic refresh (fallback for missed pub/sub messages)
|
|
112
118
|
this.syncInterval = setInterval(() => {
|
|
113
119
|
this.loadFromRedis().catch(err => {
|
|
114
120
|
console.error('[paygate:redis] Sync error:', err.message);
|
|
115
121
|
});
|
|
122
|
+
this.loadGroupsFromRedis().catch(err => {
|
|
123
|
+
console.error('[paygate:redis] Group sync error:', err.message);
|
|
124
|
+
});
|
|
116
125
|
}, this.syncMs);
|
|
117
126
|
// Start pub/sub subscriber if connection options available
|
|
118
127
|
if (subscriberOpts) {
|
|
@@ -215,6 +224,13 @@ class RedisSync {
|
|
|
215
224
|
}
|
|
216
225
|
break;
|
|
217
226
|
}
|
|
227
|
+
case 'group_updated':
|
|
228
|
+
case 'group_deleted':
|
|
229
|
+
case 'group_assignment_changed': {
|
|
230
|
+
// Reload all groups from Redis (groups are small, full reload is fine)
|
|
231
|
+
this.loadGroupsFromRedis().catch(() => { });
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
218
234
|
}
|
|
219
235
|
}
|
|
220
236
|
catch {
|
|
@@ -526,6 +542,7 @@ class RedisSync {
|
|
|
526
542
|
fields.push('autoTopup', record.autoTopup ? JSON.stringify(record.autoTopup) : '');
|
|
527
543
|
fields.push('autoTopupTodayCount', String(record.autoTopupTodayCount));
|
|
528
544
|
fields.push('autoTopupLastResetDay', record.autoTopupLastResetDay);
|
|
545
|
+
fields.push('group', record.group || '');
|
|
529
546
|
return fields;
|
|
530
547
|
}
|
|
531
548
|
hashToRecord(hash) {
|
|
@@ -557,6 +574,165 @@ class RedisSync {
|
|
|
557
574
|
autoTopup: hash.autoTopup ? JSON.parse(hash.autoTopup) : undefined,
|
|
558
575
|
autoTopupTodayCount: parseInt(hash.autoTopupTodayCount, 10) || 0,
|
|
559
576
|
autoTopupLastResetDay: hash.autoTopupLastResetDay || new Date().toISOString().slice(0, 10),
|
|
577
|
+
group: hash.group || undefined,
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
// ─── Group Sync Operations ─────────────────────────────────────────────────
|
|
581
|
+
/**
|
|
582
|
+
* Save a group record to Redis. Fire-and-forget.
|
|
583
|
+
*/
|
|
584
|
+
async saveGroup(group) {
|
|
585
|
+
try {
|
|
586
|
+
const redisKey = GROUP_PREFIX + group.id;
|
|
587
|
+
await this.redis.hset(redisKey, ...this.groupToHash(group));
|
|
588
|
+
await this.redis.command('SADD', GROUP_SET, group.id);
|
|
589
|
+
await this.publishEvent({ type: 'group_updated', key: group.id });
|
|
590
|
+
}
|
|
591
|
+
catch (err) {
|
|
592
|
+
console.error(`[paygate:redis] Save group error: ${err.message}`);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Delete a group from Redis. Fire-and-forget.
|
|
597
|
+
*/
|
|
598
|
+
async deleteGroup(groupId) {
|
|
599
|
+
try {
|
|
600
|
+
await this.redis.command('DEL', GROUP_PREFIX + groupId);
|
|
601
|
+
await this.redis.command('SREM', GROUP_SET, groupId);
|
|
602
|
+
await this.publishEvent({ type: 'group_deleted', key: groupId });
|
|
603
|
+
}
|
|
604
|
+
catch (err) {
|
|
605
|
+
console.error(`[paygate:redis] Delete group error: ${err.message}`);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Save all group assignments to Redis as a single hash (apiKey → groupId).
|
|
610
|
+
* Fire-and-forget.
|
|
611
|
+
*/
|
|
612
|
+
async saveGroupAssignments() {
|
|
613
|
+
if (!this.groupManager)
|
|
614
|
+
return;
|
|
615
|
+
try {
|
|
616
|
+
// Clear existing assignments
|
|
617
|
+
await this.redis.command('DEL', GROUP_ASSIGN_KEY);
|
|
618
|
+
// Rebuild from group manager
|
|
619
|
+
const serialized = this.groupManager.serialize();
|
|
620
|
+
if (serialized.assignments.length > 0) {
|
|
621
|
+
const fields = [];
|
|
622
|
+
for (const [apiKey, groupId] of serialized.assignments) {
|
|
623
|
+
fields.push(apiKey, groupId);
|
|
624
|
+
}
|
|
625
|
+
await this.redis.hset(GROUP_ASSIGN_KEY, ...fields);
|
|
626
|
+
}
|
|
627
|
+
await this.publishEvent({ type: 'group_assignment_changed', key: '' });
|
|
628
|
+
}
|
|
629
|
+
catch (err) {
|
|
630
|
+
console.error(`[paygate:redis] Save assignments error: ${err.message}`);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Load all groups and assignments from Redis into the local KeyGroupManager.
|
|
635
|
+
*/
|
|
636
|
+
async loadGroupsFromRedis() {
|
|
637
|
+
if (!this.groupManager)
|
|
638
|
+
return;
|
|
639
|
+
try {
|
|
640
|
+
const groupIds = await this.redis.command('SMEMBERS', GROUP_SET);
|
|
641
|
+
if (!groupIds || groupIds.length === 0) {
|
|
642
|
+
// No groups in Redis — push local state up if we have any
|
|
643
|
+
if (this.groupManager.count > 0) {
|
|
644
|
+
await this.pushGroupsToRedis();
|
|
645
|
+
}
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
// Load all group records as [id, record] tuples (matches serialize() format)
|
|
649
|
+
const groups = [];
|
|
650
|
+
for (const id of groupIds) {
|
|
651
|
+
const hash = await this.redis.hgetall(GROUP_PREFIX + id);
|
|
652
|
+
if (!hash || !hash.id)
|
|
653
|
+
continue;
|
|
654
|
+
const record = this.hashToGroup(hash);
|
|
655
|
+
if (record)
|
|
656
|
+
groups.push([id, record]);
|
|
657
|
+
}
|
|
658
|
+
// Load assignments
|
|
659
|
+
const assignHash = await this.redis.hgetall(GROUP_ASSIGN_KEY);
|
|
660
|
+
const assignments = [];
|
|
661
|
+
if (assignHash) {
|
|
662
|
+
for (const [apiKey, groupId] of Object.entries(assignHash)) {
|
|
663
|
+
assignments.push([apiKey, groupId]);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
// Load into group manager
|
|
667
|
+
this.groupManager.load({ groups, assignments });
|
|
668
|
+
if (groups.length > 0) {
|
|
669
|
+
console.log(`[paygate:redis] Synced ${groups.length} group(s) from Redis`);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
catch (err) {
|
|
673
|
+
console.error(`[paygate:redis] Load groups error: ${err.message}`);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Push local groups to Redis (used when Redis is empty on first connect).
|
|
678
|
+
*/
|
|
679
|
+
async pushGroupsToRedis() {
|
|
680
|
+
if (!this.groupManager)
|
|
681
|
+
return;
|
|
682
|
+
const serialized = this.groupManager.serialize();
|
|
683
|
+
if (serialized.groups.length === 0)
|
|
684
|
+
return;
|
|
685
|
+
for (const [id, group] of serialized.groups) {
|
|
686
|
+
const redisKey = GROUP_PREFIX + id;
|
|
687
|
+
await this.redis.hset(redisKey, ...this.groupToHash(group));
|
|
688
|
+
await this.redis.command('SADD', GROUP_SET, id);
|
|
689
|
+
}
|
|
690
|
+
if (serialized.assignments.length > 0) {
|
|
691
|
+
const fields = [];
|
|
692
|
+
for (const [apiKey, groupId] of serialized.assignments) {
|
|
693
|
+
fields.push(apiKey, groupId);
|
|
694
|
+
}
|
|
695
|
+
await this.redis.hset(GROUP_ASSIGN_KEY, ...fields);
|
|
696
|
+
}
|
|
697
|
+
console.log(`[paygate:redis] Pushed ${serialized.groups.length} local group(s) to Redis`);
|
|
698
|
+
}
|
|
699
|
+
// ─── Group Serialization ───────────────────────────────────────────────────
|
|
700
|
+
groupToHash(group) {
|
|
701
|
+
return [
|
|
702
|
+
'id', group.id,
|
|
703
|
+
'name', group.name,
|
|
704
|
+
'description', group.description,
|
|
705
|
+
'allowedTools', JSON.stringify(group.allowedTools),
|
|
706
|
+
'deniedTools', JSON.stringify(group.deniedTools),
|
|
707
|
+
'rateLimitPerMin', String(group.rateLimitPerMin),
|
|
708
|
+
'toolPricing', JSON.stringify(group.toolPricing),
|
|
709
|
+
'quota', group.quota ? JSON.stringify(group.quota) : '',
|
|
710
|
+
'ipAllowlist', JSON.stringify(group.ipAllowlist),
|
|
711
|
+
'defaultCredits', String(group.defaultCredits),
|
|
712
|
+
'maxSpendingLimit', String(group.maxSpendingLimit),
|
|
713
|
+
'tags', JSON.stringify(group.tags),
|
|
714
|
+
'createdAt', group.createdAt,
|
|
715
|
+
'active', group.active ? '1' : '0',
|
|
716
|
+
];
|
|
717
|
+
}
|
|
718
|
+
hashToGroup(hash) {
|
|
719
|
+
if (!hash.id)
|
|
720
|
+
return null;
|
|
721
|
+
return {
|
|
722
|
+
id: hash.id,
|
|
723
|
+
name: hash.name || '',
|
|
724
|
+
description: hash.description || '',
|
|
725
|
+
allowedTools: hash.allowedTools ? JSON.parse(hash.allowedTools) : [],
|
|
726
|
+
deniedTools: hash.deniedTools ? JSON.parse(hash.deniedTools) : [],
|
|
727
|
+
rateLimitPerMin: parseInt(hash.rateLimitPerMin, 10) || 0,
|
|
728
|
+
toolPricing: hash.toolPricing ? JSON.parse(hash.toolPricing) : {},
|
|
729
|
+
quota: hash.quota ? JSON.parse(hash.quota) : undefined,
|
|
730
|
+
ipAllowlist: hash.ipAllowlist ? JSON.parse(hash.ipAllowlist) : [],
|
|
731
|
+
defaultCredits: parseInt(hash.defaultCredits, 10) || 0,
|
|
732
|
+
maxSpendingLimit: parseInt(hash.maxSpendingLimit, 10) || 0,
|
|
733
|
+
tags: hash.tags ? JSON.parse(hash.tags) : {},
|
|
734
|
+
createdAt: hash.createdAt || new Date().toISOString(),
|
|
735
|
+
active: hash.active !== '0',
|
|
560
736
|
};
|
|
561
737
|
}
|
|
562
738
|
}
|