local-model-suitability-mcp 1.1.18 → 1.1.19
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/CHANGELOG.md +3 -0
- package/package.json +1 -1
- package/src/server.js +56 -1
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "local-model-suitability-mcp",
|
|
3
3
|
"mcpName": "io.github.OjasKord/local-model-suitability-mcp",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.19",
|
|
5
5
|
"description": "AI model router for agents. Checks whether a local model can handle the task before calling cloud inference. LOCAL/CLOUD verdict saves cost on every call.",
|
|
6
6
|
"main": "src/server.js",
|
|
7
7
|
"type": "module",
|
package/src/server.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createHmac, timingSafeEqual } from 'crypto';
|
|
|
3
3
|
import { readFileSync, writeFileSync } from 'fs';
|
|
4
4
|
import Anthropic from '@anthropic-ai/sdk';
|
|
5
5
|
|
|
6
|
-
const VERSION = '1.1.
|
|
6
|
+
const VERSION = '1.1.19';
|
|
7
7
|
const PRO_UPGRADE_URL = 'https://buy.stripe.com/cNibJ08wd7zf6NS0h2ebu0p';
|
|
8
8
|
const ENTERPRISE_UPGRADE_URL = 'https://buy.stripe.com/28E9AS27PbPvfkoe7Sebu0q';
|
|
9
9
|
const ALLOWED_PAYMENT_LINK_IDS = ['plink_1TQzCBD6WvRe6sn3H1q5t2LF', 'plink_1TQzDSD6WvRe6sn3UM2G1EgX'];
|
|
@@ -161,6 +161,26 @@ async function redisKeys(pattern) {
|
|
|
161
161
|
} catch(e) { return []; }
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
async function redisDelete(key) {
|
|
165
|
+
try {
|
|
166
|
+
const res = await fetch(
|
|
167
|
+
`${UPSTASH_URL}/del/${encodeURIComponent(key)}`,
|
|
168
|
+
{ method: 'POST', headers: { Authorization: `Bearer ${UPSTASH_TOKEN}` } }
|
|
169
|
+
);
|
|
170
|
+
const data = await res.json();
|
|
171
|
+
if (data.error) console.error('[Redis] redisDelete error:', data.error, 'key:', key);
|
|
172
|
+
} catch(e) { console.error('[Redis] redisDelete failed:', e); }
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function findCheckoutSessionEmail(paymentIntentId) {
|
|
176
|
+
const res = await fetch(
|
|
177
|
+
`https://api.stripe.com/v1/checkout/sessions?payment_intent=${encodeURIComponent(paymentIntentId)}`,
|
|
178
|
+
{ headers: { Authorization: `Bearer ${process.env.STRIPE_SECRET_KEY}` } }
|
|
179
|
+
);
|
|
180
|
+
const data = await res.json();
|
|
181
|
+
return data.data?.[0]?.customer_details?.email || data.data?.[0]?.customer_email || null;
|
|
182
|
+
}
|
|
183
|
+
|
|
164
184
|
async function appendSessionLog(ip, tool) {
|
|
165
185
|
try {
|
|
166
186
|
const ipSafe = ip.replace(/:/g, '_').replace(/\s/g, '');
|
|
@@ -411,6 +431,41 @@ async function handleStripeWebhook(body, sig) {
|
|
|
411
431
|
}
|
|
412
432
|
}
|
|
413
433
|
|
|
434
|
+
if (event.type === 'charge.refunded') {
|
|
435
|
+
if (!process.env.STRIPE_SECRET_KEY) {
|
|
436
|
+
console.error('[lms] STRIPE_SECRET_KEY not set — cannot revoke key on refund');
|
|
437
|
+
return { received: true, ignored: true, status: 200 };
|
|
438
|
+
}
|
|
439
|
+
const paymentIntentId = event.data.object.payment_intent;
|
|
440
|
+
if (!paymentIntentId) {
|
|
441
|
+
console.log('[lms] charge.refunded missing payment_intent — ignoring.');
|
|
442
|
+
return { received: true, ignored: true, status: 200 };
|
|
443
|
+
}
|
|
444
|
+
try {
|
|
445
|
+
const email = await findCheckoutSessionEmail(paymentIntentId);
|
|
446
|
+
if (!email) {
|
|
447
|
+
console.log('[lms] No checkout session/email found for refunded payment_intent ' + paymentIntentId);
|
|
448
|
+
return { received: true, ignored: true, status: 200 };
|
|
449
|
+
}
|
|
450
|
+
let revokedKey = null;
|
|
451
|
+
for (const [key, record] of apiKeys.entries()) {
|
|
452
|
+
if (record.email === email) { revokedKey = key; break; }
|
|
453
|
+
}
|
|
454
|
+
if (!revokedKey) {
|
|
455
|
+
console.log('[lms] No API key found for ' + email + ' — refund received, nothing to revoke');
|
|
456
|
+
return { received: true, ignored: true, status: 200 };
|
|
457
|
+
}
|
|
458
|
+
apiKeys.delete(revokedKey);
|
|
459
|
+
await redisDelete(`${REDIS_PREFIX}:key:${revokedKey}`);
|
|
460
|
+
saveStats();
|
|
461
|
+
console.log('[Webhook] API key revoked for ' + email + ' — refund received');
|
|
462
|
+
return { received: true, revoked: true, status: 200 };
|
|
463
|
+
} catch(e) {
|
|
464
|
+
console.error('[lms] charge.refunded handling error:', e.message);
|
|
465
|
+
return { received: true, ignored: true, status: 200 };
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
414
469
|
return { received: true, status: 200 };
|
|
415
470
|
}
|
|
416
471
|
|