paygate-mcp 1.9.0 → 2.0.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.
@@ -0,0 +1,280 @@
1
+ "use strict";
2
+ /**
3
+ * RedisSync — Write-through cache adapter for distributed PayGate deployments.
4
+ *
5
+ * Keeps the existing in-memory KeyStore as the fast sync read path, while
6
+ * propagating all writes to Redis for cross-process shared state. On startup,
7
+ * loads existing state from Redis. Periodically refreshes local state from Redis
8
+ * to pick up changes made by other PayGate processes.
9
+ *
10
+ * Architecture:
11
+ * Gate.evaluate() → reads from local KeyStore (sync, fast)
12
+ * KeyStore.save() → writes to memory + triggers Redis write (async, fire-and-forget)
13
+ * RedisPersistence.refresh() → pulls latest state from Redis → updates local KeyStore
14
+ *
15
+ * For credit deduction, uses a Redis Lua script to ensure atomicity across
16
+ * multiple PayGate instances (prevents double-spend race conditions).
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.RedisSync = void 0;
20
+ const KEY_PREFIX = 'pg:key:';
21
+ const KEY_SET = 'pg:keys';
22
+ const META_KEY = 'pg:meta';
23
+ /** Lua: atomic credit deduction — check + deduct + increment in one round trip */
24
+ const DEDUCT_LUA = `
25
+ local key = KEYS[1]
26
+ local amount = tonumber(ARGV[1])
27
+ local now = ARGV[2]
28
+
29
+ local credits = tonumber(redis.call('HGET', key, 'credits') or '0')
30
+ local active = redis.call('HGET', key, 'active')
31
+ if active == '0' then return -1 end
32
+ if credits < amount then return 0 end
33
+
34
+ redis.call('HINCRBY', key, 'credits', -amount)
35
+ redis.call('HINCRBY', key, 'totalSpent', amount)
36
+ redis.call('HINCRBY', key, 'totalCalls', 1)
37
+ redis.call('HSET', key, 'lastUsedAt', now)
38
+ return 1
39
+ `;
40
+ /** Lua: atomic credit addition (top-up) */
41
+ const TOPUP_LUA = `
42
+ local key = KEYS[1]
43
+ local amount = tonumber(ARGV[1])
44
+ local active = redis.call('HGET', key, 'active')
45
+ if active == '0' then return 0 end
46
+ redis.call('HINCRBY', key, 'credits', amount)
47
+ return 1
48
+ `;
49
+ class RedisSync {
50
+ redis;
51
+ store;
52
+ syncInterval = null;
53
+ syncMs;
54
+ constructor(redis, store, syncIntervalMs = 5000) {
55
+ this.redis = redis;
56
+ this.store = store;
57
+ this.syncMs = syncIntervalMs;
58
+ }
59
+ // ─── Lifecycle ─────────────────────────────────────────────────────────────
60
+ /**
61
+ * Initialize: connect to Redis and load existing state into local KeyStore.
62
+ */
63
+ async init() {
64
+ await this.redis.connect();
65
+ await this.redis.ping();
66
+ console.log('[paygate:redis] Connected to Redis');
67
+ await this.loadFromRedis();
68
+ // Start periodic refresh
69
+ this.syncInterval = setInterval(() => {
70
+ this.loadFromRedis().catch(err => {
71
+ console.error('[paygate:redis] Sync error:', err.message);
72
+ });
73
+ }, this.syncMs);
74
+ }
75
+ async destroy() {
76
+ if (this.syncInterval) {
77
+ clearInterval(this.syncInterval);
78
+ this.syncInterval = null;
79
+ }
80
+ await this.redis.disconnect();
81
+ }
82
+ // ─── Write-through operations ──────────────────────────────────────────────
83
+ /**
84
+ * Save a single key record to Redis. Called after local KeyStore mutations.
85
+ * Fire-and-forget (errors logged, not thrown).
86
+ */
87
+ async saveKey(record) {
88
+ try {
89
+ const redisKey = KEY_PREFIX + record.key;
90
+ await this.redis.hset(redisKey, ...this.recordToHash(record));
91
+ await this.redis.command('SADD', KEY_SET, record.key);
92
+ }
93
+ catch (err) {
94
+ console.error(`[paygate:redis] Save key error: ${err.message}`);
95
+ }
96
+ }
97
+ /**
98
+ * Save ALL keys to Redis. Called when local KeyStore.save() fires.
99
+ */
100
+ async saveAll() {
101
+ try {
102
+ const keys = this.store.listKeys();
103
+ // Use the internal key map via a dedicated export method
104
+ const data = this.store.keys;
105
+ if (!data)
106
+ return;
107
+ for (const [key, record] of data) {
108
+ const redisKey = KEY_PREFIX + key;
109
+ await this.redis.hset(redisKey, ...this.recordToHash(record));
110
+ await this.redis.command('SADD', KEY_SET, key);
111
+ }
112
+ }
113
+ catch (err) {
114
+ console.error(`[paygate:redis] SaveAll error: ${err.message}`);
115
+ }
116
+ }
117
+ /**
118
+ * Atomic credit deduction via Redis Lua. Returns true if deduction succeeded.
119
+ * Call this INSTEAD of store.deductCredits() in Redis mode.
120
+ */
121
+ async atomicDeduct(apiKey, amount) {
122
+ try {
123
+ const result = await this.redis.evalLua(DEDUCT_LUA, 1, KEY_PREFIX + apiKey, String(amount), new Date().toISOString());
124
+ if (result === 1) {
125
+ // Update local cache to reflect the deduction
126
+ const record = this.store.keys.get(apiKey);
127
+ if (record) {
128
+ record.credits -= amount;
129
+ record.totalSpent += amount;
130
+ record.totalCalls++;
131
+ record.lastUsedAt = new Date().toISOString();
132
+ }
133
+ return true;
134
+ }
135
+ return false;
136
+ }
137
+ catch (err) {
138
+ console.error(`[paygate:redis] Atomic deduct error: ${err.message}`);
139
+ // Fallback to local deduction if Redis is temporarily unavailable
140
+ return this.store.deductCredits(apiKey, amount);
141
+ }
142
+ }
143
+ /**
144
+ * Atomic credit top-up via Redis.
145
+ */
146
+ async atomicTopup(apiKey, amount) {
147
+ try {
148
+ const result = await this.redis.evalLua(TOPUP_LUA, 1, KEY_PREFIX + apiKey, String(amount));
149
+ if (result === 1) {
150
+ // Update local cache
151
+ const record = this.store.keys.get(apiKey);
152
+ if (record) {
153
+ record.credits += amount;
154
+ }
155
+ return true;
156
+ }
157
+ return false;
158
+ }
159
+ catch (err) {
160
+ console.error(`[paygate:redis] Atomic topup error: ${err.message}`);
161
+ return this.store.addCredits(apiKey, amount);
162
+ }
163
+ }
164
+ /**
165
+ * Revoke a key in both local store and Redis.
166
+ */
167
+ async revokeKey(apiKey) {
168
+ const localResult = this.store.revokeKey(apiKey);
169
+ try {
170
+ await this.redis.hset(KEY_PREFIX + apiKey, 'active', '0');
171
+ }
172
+ catch (err) {
173
+ console.error(`[paygate:redis] Revoke error: ${err.message}`);
174
+ }
175
+ return localResult;
176
+ }
177
+ // ─── Load from Redis ───────────────────────────────────────────────────────
178
+ /**
179
+ * Load all keys from Redis into the local in-memory KeyStore.
180
+ * Merges with any locally-created keys (doesn't overwrite local-only keys).
181
+ */
182
+ async loadFromRedis() {
183
+ try {
184
+ const allKeyIds = await this.redis.command('SMEMBERS', KEY_SET);
185
+ if (!allKeyIds || allKeyIds.length === 0) {
186
+ // No keys in Redis — push local state up if we have any
187
+ await this.pushLocalToRedis();
188
+ return;
189
+ }
190
+ let loaded = 0;
191
+ for (const keyId of allKeyIds) {
192
+ const hash = await this.redis.hgetall(KEY_PREFIX + keyId);
193
+ if (!hash || !hash.key)
194
+ continue;
195
+ const record = this.hashToRecord(hash);
196
+ if (!record)
197
+ continue;
198
+ // Write directly into the local store's map
199
+ const localKeys = this.store.keys;
200
+ localKeys.set(record.key, record);
201
+ loaded++;
202
+ }
203
+ if (loaded > 0) {
204
+ console.log(`[paygate:redis] Synced ${loaded} key(s) from Redis`);
205
+ }
206
+ }
207
+ catch (err) {
208
+ console.error(`[paygate:redis] Load error: ${err.message}`);
209
+ }
210
+ }
211
+ /**
212
+ * Push local KeyStore state to Redis (used when Redis is empty on first connect).
213
+ */
214
+ async pushLocalToRedis() {
215
+ const localKeys = this.store.keys;
216
+ if (localKeys.size === 0)
217
+ return;
218
+ for (const [key, record] of localKeys) {
219
+ const redisKey = KEY_PREFIX + key;
220
+ await this.redis.hset(redisKey, ...this.recordToHash(record));
221
+ await this.redis.command('SADD', KEY_SET, key);
222
+ }
223
+ console.log(`[paygate:redis] Pushed ${localKeys.size} local key(s) to Redis`);
224
+ }
225
+ // ─── Serialization ─────────────────────────────────────────────────────────
226
+ recordToHash(record) {
227
+ const fields = [];
228
+ fields.push('key', record.key);
229
+ fields.push('name', record.name);
230
+ fields.push('credits', String(record.credits));
231
+ fields.push('totalSpent', String(record.totalSpent));
232
+ fields.push('totalCalls', String(record.totalCalls));
233
+ fields.push('createdAt', record.createdAt);
234
+ fields.push('lastUsedAt', record.lastUsedAt || '');
235
+ fields.push('active', record.active ? '1' : '0');
236
+ fields.push('spendingLimit', String(record.spendingLimit));
237
+ fields.push('allowedTools', JSON.stringify(record.allowedTools));
238
+ fields.push('deniedTools', JSON.stringify(record.deniedTools));
239
+ fields.push('expiresAt', record.expiresAt || '');
240
+ fields.push('quota', record.quota ? JSON.stringify(record.quota) : '');
241
+ fields.push('tags', JSON.stringify(record.tags));
242
+ fields.push('ipAllowlist', JSON.stringify(record.ipAllowlist));
243
+ fields.push('quotaDailyCalls', String(record.quotaDailyCalls));
244
+ fields.push('quotaMonthlyCalls', String(record.quotaMonthlyCalls));
245
+ fields.push('quotaDailyCredits', String(record.quotaDailyCredits));
246
+ fields.push('quotaMonthlyCredits', String(record.quotaMonthlyCredits));
247
+ fields.push('quotaLastResetDay', record.quotaLastResetDay);
248
+ fields.push('quotaLastResetMonth', record.quotaLastResetMonth);
249
+ return fields;
250
+ }
251
+ hashToRecord(hash) {
252
+ if (!hash.key)
253
+ return null;
254
+ return {
255
+ key: hash.key,
256
+ name: hash.name || '',
257
+ credits: parseInt(hash.credits, 10) || 0,
258
+ totalSpent: parseInt(hash.totalSpent, 10) || 0,
259
+ totalCalls: parseInt(hash.totalCalls, 10) || 0,
260
+ createdAt: hash.createdAt || new Date().toISOString(),
261
+ lastUsedAt: hash.lastUsedAt || null,
262
+ active: hash.active !== '0',
263
+ spendingLimit: parseInt(hash.spendingLimit, 10) || 0,
264
+ allowedTools: hash.allowedTools ? JSON.parse(hash.allowedTools) : [],
265
+ deniedTools: hash.deniedTools ? JSON.parse(hash.deniedTools) : [],
266
+ expiresAt: hash.expiresAt || null,
267
+ quota: hash.quota ? JSON.parse(hash.quota) : undefined,
268
+ tags: hash.tags ? JSON.parse(hash.tags) : {},
269
+ ipAllowlist: hash.ipAllowlist ? JSON.parse(hash.ipAllowlist) : [],
270
+ quotaDailyCalls: parseInt(hash.quotaDailyCalls, 10) || 0,
271
+ quotaMonthlyCalls: parseInt(hash.quotaMonthlyCalls, 10) || 0,
272
+ quotaDailyCredits: parseInt(hash.quotaDailyCredits, 10) || 0,
273
+ quotaMonthlyCredits: parseInt(hash.quotaMonthlyCredits, 10) || 0,
274
+ quotaLastResetDay: hash.quotaLastResetDay || new Date().toISOString().slice(0, 10),
275
+ quotaLastResetMonth: hash.quotaLastResetMonth || new Date().toISOString().slice(0, 7),
276
+ };
277
+ }
278
+ }
279
+ exports.RedisSync = RedisSync;
280
+ //# sourceMappingURL=redis-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-sync.js","sourceRoot":"","sources":["../src/redis-sync.ts"],"names":[],"mappings":"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"}
package/dist/server.d.ts CHANGED
@@ -24,6 +24,7 @@ import { MetricsCollector } from './metrics';
24
24
  import { AnalyticsEngine } from './analytics';
25
25
  import { AlertEngine } from './alerts';
26
26
  import { TeamManager } from './teams';
27
+ import { RedisSync } from './redis-sync';
27
28
  /** Union type for both proxy backends */
28
29
  type ProxyBackend = McpProxy | HttpMcpProxy;
29
30
  export declare class PayGateServer {
@@ -52,11 +53,13 @@ export declare class PayGateServer {
52
53
  readonly alerts: AlertEngine;
53
54
  /** Team/organization manager */
54
55
  readonly teams: TeamManager;
56
+ /** Redis sync adapter for distributed state (null if not using Redis) */
57
+ readonly redisSync: RedisSync | null;
55
58
  /** The active request handler — either proxy or router */
56
59
  private get handler();
57
60
  constructor(config: Partial<PayGateConfig> & {
58
61
  serverCommand: string;
59
- }, adminKey?: string, statePath?: string, remoteUrl?: string, stripeWebhookSecret?: string, servers?: ServerBackendConfig[]);
62
+ }, adminKey?: string, statePath?: string, remoteUrl?: string, stripeWebhookSecret?: string, servers?: ServerBackendConfig[], redisUrl?: string);
60
63
  start(): Promise<{
61
64
  port: number;
62
65
  adminKey: string;
@@ -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
@@ -42,6 +42,8 @@ const dashboard_1 = require("./dashboard");
42
42
  const analytics_1 = require("./analytics");
43
43
  const alerts_1 = require("./alerts");
44
44
  const teams_1 = require("./teams");
45
+ const redis_client_1 = require("./redis-client");
46
+ const redis_sync_1 = require("./redis-sync");
45
47
  /** Max request body size: 1MB */
46
48
  const MAX_BODY_SIZE = 1_048_576;
47
49
  class PayGateServer {
@@ -70,11 +72,13 @@ class PayGateServer {
70
72
  alerts;
71
73
  /** Team/organization manager */
72
74
  teams;
75
+ /** Redis sync adapter for distributed state (null if not using Redis) */
76
+ redisSync = null;
73
77
  /** The active request handler — either proxy or router */
74
78
  get handler() {
75
79
  return (this.router || this.proxy);
76
80
  }
77
- constructor(config, adminKey, statePath, remoteUrl, stripeWebhookSecret, servers) {
81
+ constructor(config, adminKey, statePath, remoteUrl, stripeWebhookSecret, servers, redisUrl) {
78
82
  this.config = { ...types_1.DEFAULT_CONFIG, ...config };
79
83
  this.adminKey = adminKey || `admin_${require('crypto').randomBytes(16).toString('hex')}`;
80
84
  this.gate = new gate_1.Gate(this.config, statePath);
@@ -147,8 +151,19 @@ class PayGateServer {
147
151
  this.gate.teamRecorder = (apiKey, credits) => {
148
152
  this.teams.recordUsage(apiKey, credits);
149
153
  };
154
+ // Redis distributed state (if configured)
155
+ if (redisUrl) {
156
+ const redisOpts = (0, redis_client_1.parseRedisUrl)(redisUrl);
157
+ const redisClient = new redis_client_1.RedisClient(redisOpts);
158
+ this.redisSync = new redis_sync_1.RedisSync(redisClient, this.gate.store);
159
+ }
150
160
  }
151
161
  async start() {
162
+ // Initialize Redis sync before starting (loads state from Redis)
163
+ if (this.redisSync) {
164
+ await this.redisSync.init();
165
+ console.log('[paygate] Redis distributed state enabled');
166
+ }
152
167
  await this.handler.start();
153
168
  return new Promise((resolve, reject) => {
154
169
  this.server = (0, http_1.createServer)(async (req, res) => {
@@ -567,6 +582,7 @@ class PayGateServer {
567
582
  },
568
583
  shadowMode: this.config.shadowMode,
569
584
  oauth: !!this.oauth,
585
+ redis: !!this.redisSync,
570
586
  }));
571
587
  }
572
588
  // ─── /status — Dashboard ────────────────────────────────────────────────────
@@ -1937,6 +1953,9 @@ class PayGateServer {
1937
1953
  this.oauth?.destroy();
1938
1954
  this.sessions.destroy();
1939
1955
  this.audit.destroy();
1956
+ if (this.redisSync) {
1957
+ await this.redisSync.destroy();
1958
+ }
1940
1959
  if (this.server) {
1941
1960
  return new Promise((resolve) => {
1942
1961
  this.server.close(() => resolve());