@solvapay/server 1.0.1-preview.2 → 1.0.1-preview.3
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/dist/edge.d.ts +1373 -9
- package/dist/edge.js +116 -17
- package/dist/index.cjs +289 -17
- package/dist/index.d.cts +1453 -27
- package/dist/index.d.ts +1453 -27
- package/dist/index.js +283 -17
- package/package.json +15 -5
package/dist/edge.js
CHANGED
|
@@ -919,10 +919,10 @@ async function createAdapterHandler(adapter, paywall, metadata, businessLogic) {
|
|
|
919
919
|
const backendRefCache = /* @__PURE__ */ new Map();
|
|
920
920
|
const getCustomerRef = (args) => args.auth?.customer_ref || "anonymous";
|
|
921
921
|
const protectedHandler = await paywall.protect(businessLogic, metadata, getCustomerRef);
|
|
922
|
-
return async (context) => {
|
|
922
|
+
return async (context, extra) => {
|
|
923
923
|
try {
|
|
924
924
|
const args = await adapter.extractArgs(context);
|
|
925
|
-
const customerRef = await adapter.getCustomerRef(context);
|
|
925
|
+
const customerRef = await adapter.getCustomerRef(context, extra);
|
|
926
926
|
let backendRef = backendRefCache.get(customerRef);
|
|
927
927
|
if (!backendRef) {
|
|
928
928
|
backendRef = await paywall.ensureCustomer(customerRef, customerRef);
|
|
@@ -1113,18 +1113,18 @@ var McpAdapter = class {
|
|
|
1113
1113
|
extractArgs(args) {
|
|
1114
1114
|
return args;
|
|
1115
1115
|
}
|
|
1116
|
-
async getCustomerRef(args) {
|
|
1116
|
+
async getCustomerRef(args, extra) {
|
|
1117
1117
|
if (this.options.getCustomerRef) {
|
|
1118
|
-
const ref = await this.options.getCustomerRef(args);
|
|
1118
|
+
const ref = await this.options.getCustomerRef(args, extra);
|
|
1119
1119
|
return AdapterUtils.ensureCustomerRef(ref);
|
|
1120
1120
|
}
|
|
1121
|
-
const
|
|
1122
|
-
const customerRef =
|
|
1121
|
+
const customerRefFromExtra = extra?.authInfo?.extra?.customer_ref;
|
|
1122
|
+
const customerRef = typeof customerRefFromExtra === "string" && customerRefFromExtra.trim() ? customerRefFromExtra.trim() : "anonymous";
|
|
1123
1123
|
return AdapterUtils.ensureCustomerRef(customerRef);
|
|
1124
1124
|
}
|
|
1125
1125
|
formatResponse(result, _context) {
|
|
1126
1126
|
const transformed = this.options.transformResponse ? this.options.transformResponse(result) : result;
|
|
1127
|
-
|
|
1127
|
+
const response = {
|
|
1128
1128
|
content: [
|
|
1129
1129
|
{
|
|
1130
1130
|
type: "text",
|
|
@@ -1132,6 +1132,10 @@ var McpAdapter = class {
|
|
|
1132
1132
|
}
|
|
1133
1133
|
]
|
|
1134
1134
|
};
|
|
1135
|
+
if (transformed && typeof transformed === "object" && !Array.isArray(transformed)) {
|
|
1136
|
+
response.structuredContent = transformed;
|
|
1137
|
+
}
|
|
1138
|
+
return response;
|
|
1135
1139
|
}
|
|
1136
1140
|
formatError(error, _context) {
|
|
1137
1141
|
if (error instanceof PaywallError) {
|
|
@@ -1218,8 +1222,8 @@ function mcpErrorResult(message) {
|
|
|
1218
1222
|
return { content: [{ type: "text", text: JSON.stringify({ error: message }) }], isError: true };
|
|
1219
1223
|
}
|
|
1220
1224
|
function createGetUserInfoHandler(apiClient, productRef, getCustomerRef) {
|
|
1221
|
-
return async (args) => {
|
|
1222
|
-
const customerRef = getCustomerRef(args);
|
|
1225
|
+
return async (args, extra) => {
|
|
1226
|
+
const customerRef = getCustomerRef(args, extra);
|
|
1223
1227
|
try {
|
|
1224
1228
|
if (!apiClient.getUserInfo) {
|
|
1225
1229
|
return mcpErrorResult("getUserInfo is not available on this API client");
|
|
@@ -1234,12 +1238,12 @@ function createGetUserInfoHandler(apiClient, productRef, getCustomerRef) {
|
|
|
1234
1238
|
};
|
|
1235
1239
|
}
|
|
1236
1240
|
function createUpgradeHandler(apiClient, productRef, getCustomerRef) {
|
|
1237
|
-
return async (args) => {
|
|
1238
|
-
const customerRef = getCustomerRef(args);
|
|
1241
|
+
return async (args, extra) => {
|
|
1242
|
+
const customerRef = getCustomerRef(args, extra);
|
|
1239
1243
|
const planRef = typeof args.planRef === "string" ? args.planRef : void 0;
|
|
1240
1244
|
try {
|
|
1241
1245
|
const result = await apiClient.createCheckoutSession({
|
|
1242
|
-
|
|
1246
|
+
customerRef,
|
|
1243
1247
|
productRef,
|
|
1244
1248
|
...planRef && { planRef }
|
|
1245
1249
|
});
|
|
@@ -1266,8 +1270,8 @@ You'll be able to compare options and select the one that's right for you.`;
|
|
|
1266
1270
|
};
|
|
1267
1271
|
}
|
|
1268
1272
|
function createManageAccountHandler(apiClient, productRef, getCustomerRef) {
|
|
1269
|
-
return async (args) => {
|
|
1270
|
-
const customerRef = getCustomerRef(args);
|
|
1273
|
+
return async (args, extra) => {
|
|
1274
|
+
const customerRef = getCustomerRef(args, extra);
|
|
1271
1275
|
try {
|
|
1272
1276
|
const session = await apiClient.createCustomerSession({ customerRef, productRef });
|
|
1273
1277
|
const portalUrl = session.customerUrl;
|
|
@@ -1310,6 +1314,98 @@ function createVirtualTools(apiClient, options) {
|
|
|
1310
1314
|
return allTools.filter((t) => !excludeSet.has(t.name));
|
|
1311
1315
|
}
|
|
1312
1316
|
|
|
1317
|
+
// src/register-virtual-tools-mcp.ts
|
|
1318
|
+
import { createRequire } from "module";
|
|
1319
|
+
function getNodeRequire() {
|
|
1320
|
+
try {
|
|
1321
|
+
return (0, eval)("require");
|
|
1322
|
+
} catch {
|
|
1323
|
+
return createRequire(`${process.cwd()}/package.json`);
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
var nodeRequire = getNodeRequire();
|
|
1327
|
+
function getZod() {
|
|
1328
|
+
try {
|
|
1329
|
+
const zodModule = nodeRequire("zod");
|
|
1330
|
+
return zodModule.z ?? zodModule;
|
|
1331
|
+
} catch {
|
|
1332
|
+
throw new Error(
|
|
1333
|
+
"zod is required to use registerVirtualToolsMcp(). Install it as a dependency in your MCP server project."
|
|
1334
|
+
);
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
function isJsonSchemaObject(value) {
|
|
1338
|
+
return Boolean(value && typeof value === "object");
|
|
1339
|
+
}
|
|
1340
|
+
function toZodSchema(property) {
|
|
1341
|
+
const z = getZod();
|
|
1342
|
+
if (Array.isArray(property.enum) && property.enum.length > 0) {
|
|
1343
|
+
if (property.enum.every((value) => typeof value === "string")) {
|
|
1344
|
+
const [first, ...rest] = property.enum;
|
|
1345
|
+
return z.enum([first, ...rest]);
|
|
1346
|
+
}
|
|
1347
|
+
if (property.enum.length === 1) {
|
|
1348
|
+
return z.literal(property.enum[0]);
|
|
1349
|
+
}
|
|
1350
|
+
return z.union(property.enum.map((value) => z.literal(value)));
|
|
1351
|
+
}
|
|
1352
|
+
switch (property.type) {
|
|
1353
|
+
case "string":
|
|
1354
|
+
return z.string();
|
|
1355
|
+
case "number":
|
|
1356
|
+
return z.number();
|
|
1357
|
+
case "integer":
|
|
1358
|
+
return z.number().int();
|
|
1359
|
+
case "boolean":
|
|
1360
|
+
return z.boolean();
|
|
1361
|
+
case "array":
|
|
1362
|
+
return z.array(
|
|
1363
|
+
isJsonSchemaObject(property.items) ? toZodSchema(property.items) : z.any()
|
|
1364
|
+
);
|
|
1365
|
+
case "object":
|
|
1366
|
+
return z.object(jsonSchemaToZodRawShape(property.properties || {}));
|
|
1367
|
+
default:
|
|
1368
|
+
return z.any();
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
function jsonSchemaToZodRawShape(properties, required = []) {
|
|
1372
|
+
const requiredSet = new Set(required);
|
|
1373
|
+
return Object.fromEntries(
|
|
1374
|
+
Object.entries(properties).map(([name, property]) => {
|
|
1375
|
+
const schema = toZodSchema(property);
|
|
1376
|
+
const finalSchema = requiredSet.has(name) ? schema : schema.optional();
|
|
1377
|
+
return [name, finalSchema];
|
|
1378
|
+
})
|
|
1379
|
+
);
|
|
1380
|
+
}
|
|
1381
|
+
function defaultGetCustomerRef(_args, extra) {
|
|
1382
|
+
const fromExtra = extra?.authInfo?.extra?.customer_ref;
|
|
1383
|
+
return typeof fromExtra === "string" && fromExtra.trim() ? fromExtra.trim() : "anonymous";
|
|
1384
|
+
}
|
|
1385
|
+
function registerVirtualToolsMcpImpl(server, apiClient, options) {
|
|
1386
|
+
const { filter, mapDefinition, wrapHandler, getCustomerRef, ...virtualToolsOptions } = options;
|
|
1387
|
+
const virtualTools = createVirtualTools(apiClient, {
|
|
1388
|
+
...virtualToolsOptions,
|
|
1389
|
+
getCustomerRef: getCustomerRef || defaultGetCustomerRef
|
|
1390
|
+
});
|
|
1391
|
+
for (const toolDefinition of virtualTools) {
|
|
1392
|
+
if (filter && !filter(toolDefinition)) continue;
|
|
1393
|
+
const mappedDefinition = mapDefinition ? mapDefinition(toolDefinition) : toolDefinition;
|
|
1394
|
+
const wrappedHandler = wrapHandler ? wrapHandler(mappedDefinition.handler, mappedDefinition) : mappedDefinition.handler;
|
|
1395
|
+
server.registerTool(
|
|
1396
|
+
mappedDefinition.name,
|
|
1397
|
+
{
|
|
1398
|
+
description: mappedDefinition.description,
|
|
1399
|
+
inputSchema: jsonSchemaToZodRawShape(
|
|
1400
|
+
mappedDefinition.inputSchema.properties,
|
|
1401
|
+
mappedDefinition.inputSchema.required || []
|
|
1402
|
+
)
|
|
1403
|
+
},
|
|
1404
|
+
wrappedHandler
|
|
1405
|
+
);
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1313
1409
|
// src/factory.ts
|
|
1314
1410
|
function createSolvaPay(config) {
|
|
1315
1411
|
let resolvedConfig;
|
|
@@ -1366,7 +1462,7 @@ function createSolvaPay(config) {
|
|
|
1366
1462
|
},
|
|
1367
1463
|
createCheckoutSession(params) {
|
|
1368
1464
|
return apiClient.createCheckoutSession({
|
|
1369
|
-
|
|
1465
|
+
customerRef: params.customerRef,
|
|
1370
1466
|
productRef: params.productRef,
|
|
1371
1467
|
planRef: params.planRef
|
|
1372
1468
|
});
|
|
@@ -1383,6 +1479,9 @@ function createSolvaPay(config) {
|
|
|
1383
1479
|
getVirtualTools(options) {
|
|
1384
1480
|
return createVirtualTools(apiClient, options);
|
|
1385
1481
|
},
|
|
1482
|
+
async registerVirtualToolsMcp(server, options) {
|
|
1483
|
+
await registerVirtualToolsMcpImpl(server, apiClient, options);
|
|
1484
|
+
},
|
|
1386
1485
|
// Payable API for framework-specific handlers
|
|
1387
1486
|
payable(options = {}) {
|
|
1388
1487
|
const product = options.productRef || options.product || process.env.SOLVAPAY_PRODUCT || "default-product";
|
|
@@ -1421,9 +1520,9 @@ function createSolvaPay(config) {
|
|
|
1421
1520
|
getCustomerRef: adapterOptions?.getCustomerRef || options.getCustomerRef
|
|
1422
1521
|
});
|
|
1423
1522
|
const handlerPromise = createAdapterHandler(adapter, paywall, metadata, businessLogic);
|
|
1424
|
-
return async (args) => {
|
|
1523
|
+
return async (args, extra) => {
|
|
1425
1524
|
const handler = await handlerPromise;
|
|
1426
|
-
return handler(args);
|
|
1525
|
+
return handler(args, extra);
|
|
1427
1526
|
};
|
|
1428
1527
|
},
|
|
1429
1528
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
package/dist/index.cjs
CHANGED
|
@@ -4314,9 +4314,11 @@ __export(index_exports, {
|
|
|
4314
4314
|
McpBearerAuthError: () => McpBearerAuthError,
|
|
4315
4315
|
PaywallError: () => PaywallError,
|
|
4316
4316
|
VIRTUAL_TOOL_DEFINITIONS: () => VIRTUAL_TOOL_DEFINITIONS,
|
|
4317
|
+
buildAuthInfoFromBearer: () => buildAuthInfoFromBearer,
|
|
4317
4318
|
cancelPurchaseCore: () => cancelPurchaseCore,
|
|
4318
4319
|
createCheckoutSessionCore: () => createCheckoutSessionCore,
|
|
4319
4320
|
createCustomerSessionCore: () => createCustomerSessionCore,
|
|
4321
|
+
createMcpOAuthBridge: () => createMcpOAuthBridge,
|
|
4320
4322
|
createPaymentIntentCore: () => createPaymentIntentCore,
|
|
4321
4323
|
createSolvaPay: () => createSolvaPay,
|
|
4322
4324
|
createSolvaPayClient: () => createSolvaPayClient,
|
|
@@ -4326,10 +4328,14 @@ __export(index_exports, {
|
|
|
4326
4328
|
getAuthenticatedUserCore: () => getAuthenticatedUserCore,
|
|
4327
4329
|
getCustomerRefFromBearerAuthHeader: () => getCustomerRefFromBearerAuthHeader,
|
|
4328
4330
|
getCustomerRefFromJwtPayload: () => getCustomerRefFromJwtPayload,
|
|
4331
|
+
getOAuthAuthorizationServerResponse: () => getOAuthAuthorizationServerResponse,
|
|
4332
|
+
getOAuthProtectedResourceResponse: () => getOAuthProtectedResourceResponse,
|
|
4329
4333
|
handleRouteError: () => handleRouteError,
|
|
4330
4334
|
isErrorResult: () => isErrorResult,
|
|
4335
|
+
jsonSchemaToZodRawShape: () => jsonSchemaToZodRawShape,
|
|
4331
4336
|
listPlansCore: () => listPlansCore,
|
|
4332
4337
|
processPaymentIntentCore: () => processPaymentIntentCore,
|
|
4338
|
+
registerVirtualToolsMcpImpl: () => registerVirtualToolsMcpImpl,
|
|
4333
4339
|
syncCustomerCore: () => syncCustomerCore,
|
|
4334
4340
|
verifyWebhook: () => verifyWebhook,
|
|
4335
4341
|
withRetry: () => withRetry
|
|
@@ -5254,10 +5260,10 @@ async function createAdapterHandler(adapter, paywall, metadata, businessLogic) {
|
|
|
5254
5260
|
const backendRefCache = /* @__PURE__ */ new Map();
|
|
5255
5261
|
const getCustomerRef = (args) => args.auth?.customer_ref || "anonymous";
|
|
5256
5262
|
const protectedHandler = await paywall.protect(businessLogic, metadata, getCustomerRef);
|
|
5257
|
-
return async (context) => {
|
|
5263
|
+
return async (context, extra) => {
|
|
5258
5264
|
try {
|
|
5259
5265
|
const args = await adapter.extractArgs(context);
|
|
5260
|
-
const customerRef = await adapter.getCustomerRef(context);
|
|
5266
|
+
const customerRef = await adapter.getCustomerRef(context, extra);
|
|
5261
5267
|
let backendRef = backendRefCache.get(customerRef);
|
|
5262
5268
|
if (!backendRef) {
|
|
5263
5269
|
backendRef = await paywall.ensureCustomer(customerRef, customerRef);
|
|
@@ -5448,18 +5454,18 @@ var McpAdapter = class {
|
|
|
5448
5454
|
extractArgs(args) {
|
|
5449
5455
|
return args;
|
|
5450
5456
|
}
|
|
5451
|
-
async getCustomerRef(args) {
|
|
5457
|
+
async getCustomerRef(args, extra) {
|
|
5452
5458
|
if (this.options.getCustomerRef) {
|
|
5453
|
-
const ref = await this.options.getCustomerRef(args);
|
|
5459
|
+
const ref = await this.options.getCustomerRef(args, extra);
|
|
5454
5460
|
return AdapterUtils.ensureCustomerRef(ref);
|
|
5455
5461
|
}
|
|
5456
|
-
const
|
|
5457
|
-
const customerRef =
|
|
5462
|
+
const customerRefFromExtra = extra?.authInfo?.extra?.customer_ref;
|
|
5463
|
+
const customerRef = typeof customerRefFromExtra === "string" && customerRefFromExtra.trim() ? customerRefFromExtra.trim() : "anonymous";
|
|
5458
5464
|
return AdapterUtils.ensureCustomerRef(customerRef);
|
|
5459
5465
|
}
|
|
5460
5466
|
formatResponse(result, _context) {
|
|
5461
5467
|
const transformed = this.options.transformResponse ? this.options.transformResponse(result) : result;
|
|
5462
|
-
|
|
5468
|
+
const response = {
|
|
5463
5469
|
content: [
|
|
5464
5470
|
{
|
|
5465
5471
|
type: "text",
|
|
@@ -5467,6 +5473,10 @@ var McpAdapter = class {
|
|
|
5467
5473
|
}
|
|
5468
5474
|
]
|
|
5469
5475
|
};
|
|
5476
|
+
if (transformed && typeof transformed === "object" && !Array.isArray(transformed)) {
|
|
5477
|
+
response.structuredContent = transformed;
|
|
5478
|
+
}
|
|
5479
|
+
return response;
|
|
5470
5480
|
}
|
|
5471
5481
|
formatError(error, _context) {
|
|
5472
5482
|
if (error instanceof PaywallError) {
|
|
@@ -5554,8 +5564,8 @@ function mcpErrorResult(message2) {
|
|
|
5554
5564
|
return { content: [{ type: "text", text: JSON.stringify({ error: message2 }) }], isError: true };
|
|
5555
5565
|
}
|
|
5556
5566
|
function createGetUserInfoHandler(apiClient, productRef, getCustomerRef) {
|
|
5557
|
-
return async (args) => {
|
|
5558
|
-
const customerRef = getCustomerRef(args);
|
|
5567
|
+
return async (args, extra) => {
|
|
5568
|
+
const customerRef = getCustomerRef(args, extra);
|
|
5559
5569
|
try {
|
|
5560
5570
|
if (!apiClient.getUserInfo) {
|
|
5561
5571
|
return mcpErrorResult("getUserInfo is not available on this API client");
|
|
@@ -5570,12 +5580,12 @@ function createGetUserInfoHandler(apiClient, productRef, getCustomerRef) {
|
|
|
5570
5580
|
};
|
|
5571
5581
|
}
|
|
5572
5582
|
function createUpgradeHandler(apiClient, productRef, getCustomerRef) {
|
|
5573
|
-
return async (args) => {
|
|
5574
|
-
const customerRef = getCustomerRef(args);
|
|
5583
|
+
return async (args, extra) => {
|
|
5584
|
+
const customerRef = getCustomerRef(args, extra);
|
|
5575
5585
|
const planRef = typeof args.planRef === "string" ? args.planRef : void 0;
|
|
5576
5586
|
try {
|
|
5577
5587
|
const result = await apiClient.createCheckoutSession({
|
|
5578
|
-
|
|
5588
|
+
customerRef,
|
|
5579
5589
|
productRef,
|
|
5580
5590
|
...planRef && { planRef }
|
|
5581
5591
|
});
|
|
@@ -5602,8 +5612,8 @@ You'll be able to compare options and select the one that's right for you.`;
|
|
|
5602
5612
|
};
|
|
5603
5613
|
}
|
|
5604
5614
|
function createManageAccountHandler(apiClient, productRef, getCustomerRef) {
|
|
5605
|
-
return async (args) => {
|
|
5606
|
-
const customerRef = getCustomerRef(args);
|
|
5615
|
+
return async (args, extra) => {
|
|
5616
|
+
const customerRef = getCustomerRef(args, extra);
|
|
5607
5617
|
try {
|
|
5608
5618
|
const session = await apiClient.createCustomerSession({ customerRef, productRef });
|
|
5609
5619
|
const portalUrl = session.customerUrl;
|
|
@@ -5646,6 +5656,98 @@ function createVirtualTools(apiClient, options) {
|
|
|
5646
5656
|
return allTools.filter((t) => !excludeSet.has(t.name));
|
|
5647
5657
|
}
|
|
5648
5658
|
|
|
5659
|
+
// src/register-virtual-tools-mcp.ts
|
|
5660
|
+
var import_node_module = require("module");
|
|
5661
|
+
function getNodeRequire() {
|
|
5662
|
+
try {
|
|
5663
|
+
return (0, eval)("require");
|
|
5664
|
+
} catch {
|
|
5665
|
+
return (0, import_node_module.createRequire)(`${process.cwd()}/package.json`);
|
|
5666
|
+
}
|
|
5667
|
+
}
|
|
5668
|
+
var nodeRequire = getNodeRequire();
|
|
5669
|
+
function getZod() {
|
|
5670
|
+
try {
|
|
5671
|
+
const zodModule = nodeRequire("zod");
|
|
5672
|
+
return zodModule.z ?? zodModule;
|
|
5673
|
+
} catch {
|
|
5674
|
+
throw new Error(
|
|
5675
|
+
"zod is required to use registerVirtualToolsMcp(). Install it as a dependency in your MCP server project."
|
|
5676
|
+
);
|
|
5677
|
+
}
|
|
5678
|
+
}
|
|
5679
|
+
function isJsonSchemaObject(value) {
|
|
5680
|
+
return Boolean(value && typeof value === "object");
|
|
5681
|
+
}
|
|
5682
|
+
function toZodSchema(property) {
|
|
5683
|
+
const z = getZod();
|
|
5684
|
+
if (Array.isArray(property.enum) && property.enum.length > 0) {
|
|
5685
|
+
if (property.enum.every((value) => typeof value === "string")) {
|
|
5686
|
+
const [first, ...rest] = property.enum;
|
|
5687
|
+
return z.enum([first, ...rest]);
|
|
5688
|
+
}
|
|
5689
|
+
if (property.enum.length === 1) {
|
|
5690
|
+
return z.literal(property.enum[0]);
|
|
5691
|
+
}
|
|
5692
|
+
return z.union(property.enum.map((value) => z.literal(value)));
|
|
5693
|
+
}
|
|
5694
|
+
switch (property.type) {
|
|
5695
|
+
case "string":
|
|
5696
|
+
return z.string();
|
|
5697
|
+
case "number":
|
|
5698
|
+
return z.number();
|
|
5699
|
+
case "integer":
|
|
5700
|
+
return z.number().int();
|
|
5701
|
+
case "boolean":
|
|
5702
|
+
return z.boolean();
|
|
5703
|
+
case "array":
|
|
5704
|
+
return z.array(
|
|
5705
|
+
isJsonSchemaObject(property.items) ? toZodSchema(property.items) : z.any()
|
|
5706
|
+
);
|
|
5707
|
+
case "object":
|
|
5708
|
+
return z.object(jsonSchemaToZodRawShape(property.properties || {}));
|
|
5709
|
+
default:
|
|
5710
|
+
return z.any();
|
|
5711
|
+
}
|
|
5712
|
+
}
|
|
5713
|
+
function jsonSchemaToZodRawShape(properties, required = []) {
|
|
5714
|
+
const requiredSet = new Set(required);
|
|
5715
|
+
return Object.fromEntries(
|
|
5716
|
+
Object.entries(properties).map(([name, property]) => {
|
|
5717
|
+
const schema = toZodSchema(property);
|
|
5718
|
+
const finalSchema = requiredSet.has(name) ? schema : schema.optional();
|
|
5719
|
+
return [name, finalSchema];
|
|
5720
|
+
})
|
|
5721
|
+
);
|
|
5722
|
+
}
|
|
5723
|
+
function defaultGetCustomerRef(_args, extra) {
|
|
5724
|
+
const fromExtra = extra?.authInfo?.extra?.customer_ref;
|
|
5725
|
+
return typeof fromExtra === "string" && fromExtra.trim() ? fromExtra.trim() : "anonymous";
|
|
5726
|
+
}
|
|
5727
|
+
function registerVirtualToolsMcpImpl(server, apiClient, options) {
|
|
5728
|
+
const { filter, mapDefinition, wrapHandler, getCustomerRef, ...virtualToolsOptions } = options;
|
|
5729
|
+
const virtualTools = createVirtualTools(apiClient, {
|
|
5730
|
+
...virtualToolsOptions,
|
|
5731
|
+
getCustomerRef: getCustomerRef || defaultGetCustomerRef
|
|
5732
|
+
});
|
|
5733
|
+
for (const toolDefinition of virtualTools) {
|
|
5734
|
+
if (filter && !filter(toolDefinition)) continue;
|
|
5735
|
+
const mappedDefinition = mapDefinition ? mapDefinition(toolDefinition) : toolDefinition;
|
|
5736
|
+
const wrappedHandler = wrapHandler ? wrapHandler(mappedDefinition.handler, mappedDefinition) : mappedDefinition.handler;
|
|
5737
|
+
server.registerTool(
|
|
5738
|
+
mappedDefinition.name,
|
|
5739
|
+
{
|
|
5740
|
+
description: mappedDefinition.description,
|
|
5741
|
+
inputSchema: jsonSchemaToZodRawShape(
|
|
5742
|
+
mappedDefinition.inputSchema.properties,
|
|
5743
|
+
mappedDefinition.inputSchema.required || []
|
|
5744
|
+
)
|
|
5745
|
+
},
|
|
5746
|
+
wrappedHandler
|
|
5747
|
+
);
|
|
5748
|
+
}
|
|
5749
|
+
}
|
|
5750
|
+
|
|
5649
5751
|
// src/factory.ts
|
|
5650
5752
|
function createSolvaPay(config) {
|
|
5651
5753
|
let resolvedConfig;
|
|
@@ -5702,7 +5804,7 @@ function createSolvaPay(config) {
|
|
|
5702
5804
|
},
|
|
5703
5805
|
createCheckoutSession(params) {
|
|
5704
5806
|
return apiClient.createCheckoutSession({
|
|
5705
|
-
|
|
5807
|
+
customerRef: params.customerRef,
|
|
5706
5808
|
productRef: params.productRef,
|
|
5707
5809
|
planRef: params.planRef
|
|
5708
5810
|
});
|
|
@@ -5719,6 +5821,9 @@ function createSolvaPay(config) {
|
|
|
5719
5821
|
getVirtualTools(options) {
|
|
5720
5822
|
return createVirtualTools(apiClient, options);
|
|
5721
5823
|
},
|
|
5824
|
+
async registerVirtualToolsMcp(server, options) {
|
|
5825
|
+
await registerVirtualToolsMcpImpl(server, apiClient, options);
|
|
5826
|
+
},
|
|
5722
5827
|
// Payable API for framework-specific handlers
|
|
5723
5828
|
payable(options = {}) {
|
|
5724
5829
|
const product = options.productRef || options.product || process.env.SOLVAPAY_PRODUCT || "default-product";
|
|
@@ -5757,9 +5862,9 @@ function createSolvaPay(config) {
|
|
|
5757
5862
|
getCustomerRef: adapterOptions?.getCustomerRef || options.getCustomerRef
|
|
5758
5863
|
});
|
|
5759
5864
|
const handlerPromise = createAdapterHandler(adapter, paywall, metadata, businessLogic);
|
|
5760
|
-
return async (args) => {
|
|
5865
|
+
return async (args, extra) => {
|
|
5761
5866
|
const handler = await handlerPromise;
|
|
5762
|
-
return handler(args);
|
|
5867
|
+
return handler(args, extra);
|
|
5763
5868
|
};
|
|
5764
5869
|
},
|
|
5765
5870
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -5829,6 +5934,167 @@ function getCustomerRefFromBearerAuthHeader(authorization, options = {}) {
|
|
|
5829
5934
|
return getCustomerRefFromJwtPayload(payload, options);
|
|
5830
5935
|
}
|
|
5831
5936
|
|
|
5937
|
+
// src/mcp/auth-bridge.ts
|
|
5938
|
+
function getClientId(payload, explicitClientId) {
|
|
5939
|
+
if (explicitClientId) return explicitClientId;
|
|
5940
|
+
const payloadClientId = typeof payload.client_id === "string" && payload.client_id || typeof payload.azp === "string" && payload.azp || typeof payload.aud === "string" && payload.aud || null;
|
|
5941
|
+
return payloadClientId || "solvapay-mcp-client";
|
|
5942
|
+
}
|
|
5943
|
+
function getScopes(payload, defaultScopes) {
|
|
5944
|
+
if (Array.isArray(payload.scp)) {
|
|
5945
|
+
return payload.scp.filter((scope) => typeof scope === "string");
|
|
5946
|
+
}
|
|
5947
|
+
if (typeof payload.scope === "string" && payload.scope.trim()) {
|
|
5948
|
+
return payload.scope.split(/\s+/).map((scope) => scope.trim()).filter(Boolean);
|
|
5949
|
+
}
|
|
5950
|
+
return defaultScopes;
|
|
5951
|
+
}
|
|
5952
|
+
function getExpiresAt(payload) {
|
|
5953
|
+
return typeof payload.exp === "number" ? payload.exp : void 0;
|
|
5954
|
+
}
|
|
5955
|
+
function buildAuthInfoFromBearer(authorization, options = {}) {
|
|
5956
|
+
const token = extractBearerToken(authorization);
|
|
5957
|
+
if (!token) return null;
|
|
5958
|
+
const payload = decodeJwtPayload(token);
|
|
5959
|
+
const customerRef = getCustomerRefFromJwtPayload(payload, options);
|
|
5960
|
+
const clientId = getClientId(payload, options.clientId);
|
|
5961
|
+
const scopes = getScopes(payload, options.defaultScopes || []);
|
|
5962
|
+
const expiresAt = getExpiresAt(payload);
|
|
5963
|
+
return {
|
|
5964
|
+
token,
|
|
5965
|
+
clientId,
|
|
5966
|
+
scopes,
|
|
5967
|
+
expiresAt,
|
|
5968
|
+
extra: {
|
|
5969
|
+
customer_ref: customerRef,
|
|
5970
|
+
...options.includePayload ? { payload } : {}
|
|
5971
|
+
}
|
|
5972
|
+
};
|
|
5973
|
+
}
|
|
5974
|
+
|
|
5975
|
+
// src/mcp/oauth-bridge.ts
|
|
5976
|
+
function withoutTrailingSlash(value) {
|
|
5977
|
+
return value.replace(/\/$/, "");
|
|
5978
|
+
}
|
|
5979
|
+
function getRequestAuthHeader(req) {
|
|
5980
|
+
const header = req.headers?.authorization;
|
|
5981
|
+
if (typeof header === "string") return header;
|
|
5982
|
+
if (Array.isArray(header)) return header[0] || null;
|
|
5983
|
+
return null;
|
|
5984
|
+
}
|
|
5985
|
+
function getRequestJsonRpcId(body) {
|
|
5986
|
+
if (body && typeof body === "object" && "id" in body) {
|
|
5987
|
+
const id = body.id;
|
|
5988
|
+
return id ?? null;
|
|
5989
|
+
}
|
|
5990
|
+
return null;
|
|
5991
|
+
}
|
|
5992
|
+
function makeUnauthorizedJsonRpc(id) {
|
|
5993
|
+
return {
|
|
5994
|
+
jsonrpc: "2.0",
|
|
5995
|
+
id,
|
|
5996
|
+
error: {
|
|
5997
|
+
code: -32001,
|
|
5998
|
+
message: "Unauthorized"
|
|
5999
|
+
}
|
|
6000
|
+
};
|
|
6001
|
+
}
|
|
6002
|
+
function setMcpChallengeHeader(res, publicBaseUrl, protectedResourcePath) {
|
|
6003
|
+
res.setHeader(
|
|
6004
|
+
"WWW-Authenticate",
|
|
6005
|
+
`Bearer resource_metadata="${withoutTrailingSlash(publicBaseUrl)}${protectedResourcePath}"`
|
|
6006
|
+
);
|
|
6007
|
+
}
|
|
6008
|
+
function getOAuthProtectedResourceResponse(publicBaseUrl) {
|
|
6009
|
+
const resource = withoutTrailingSlash(publicBaseUrl);
|
|
6010
|
+
return {
|
|
6011
|
+
resource,
|
|
6012
|
+
authorization_servers: [resource],
|
|
6013
|
+
scopes_supported: ["openid", "profile", "email"]
|
|
6014
|
+
};
|
|
6015
|
+
}
|
|
6016
|
+
function getOAuthAuthorizationServerResponse({
|
|
6017
|
+
apiBaseUrl,
|
|
6018
|
+
productRef
|
|
6019
|
+
}) {
|
|
6020
|
+
const normalizedApiBaseUrl = withoutTrailingSlash(apiBaseUrl);
|
|
6021
|
+
const registrationEndpoint = `${normalizedApiBaseUrl}/v1/customer/auth/register?product_ref=${encodeURIComponent(productRef)}`;
|
|
6022
|
+
return {
|
|
6023
|
+
issuer: normalizedApiBaseUrl,
|
|
6024
|
+
authorization_endpoint: `${normalizedApiBaseUrl}/v1/customer/auth/authorize`,
|
|
6025
|
+
token_endpoint: `${normalizedApiBaseUrl}/v1/customer/auth/token`,
|
|
6026
|
+
registration_endpoint: registrationEndpoint,
|
|
6027
|
+
token_endpoint_auth_methods_supported: ["client_secret_basic", "client_secret_post"],
|
|
6028
|
+
response_types_supported: ["code"],
|
|
6029
|
+
grant_types_supported: ["authorization_code", "refresh_token"],
|
|
6030
|
+
scopes_supported: ["openid", "profile", "email"],
|
|
6031
|
+
code_challenge_methods_supported: ["S256"]
|
|
6032
|
+
};
|
|
6033
|
+
}
|
|
6034
|
+
function createMcpOAuthBridge(options) {
|
|
6035
|
+
const {
|
|
6036
|
+
publicBaseUrl,
|
|
6037
|
+
apiBaseUrl,
|
|
6038
|
+
productRef,
|
|
6039
|
+
mcpPath = "/mcp",
|
|
6040
|
+
requireAuth = true,
|
|
6041
|
+
authInfo,
|
|
6042
|
+
protectedResourcePath = "/.well-known/oauth-protected-resource",
|
|
6043
|
+
authorizationServerPath = "/.well-known/oauth-authorization-server"
|
|
6044
|
+
} = options;
|
|
6045
|
+
const protectedResourceMiddleware = (req, res, next) => {
|
|
6046
|
+
if (req.method !== "GET" || req.path !== protectedResourcePath) {
|
|
6047
|
+
next();
|
|
6048
|
+
return;
|
|
6049
|
+
}
|
|
6050
|
+
res.json(getOAuthProtectedResourceResponse(publicBaseUrl));
|
|
6051
|
+
};
|
|
6052
|
+
const authorizationServerMiddleware = (req, res, next) => {
|
|
6053
|
+
if (req.method !== "GET" || req.path !== authorizationServerPath) {
|
|
6054
|
+
next();
|
|
6055
|
+
return;
|
|
6056
|
+
}
|
|
6057
|
+
if (!productRef) {
|
|
6058
|
+
res.status(500).json({ error: "SOLVAPAY_PRODUCT_REF missing" });
|
|
6059
|
+
return;
|
|
6060
|
+
}
|
|
6061
|
+
res.json(
|
|
6062
|
+
getOAuthAuthorizationServerResponse({
|
|
6063
|
+
apiBaseUrl,
|
|
6064
|
+
productRef
|
|
6065
|
+
})
|
|
6066
|
+
);
|
|
6067
|
+
};
|
|
6068
|
+
const mcpAuthMiddleware = (req, res, next) => {
|
|
6069
|
+
if (req.path !== mcpPath) {
|
|
6070
|
+
next();
|
|
6071
|
+
return;
|
|
6072
|
+
}
|
|
6073
|
+
const authHeader = getRequestAuthHeader(req);
|
|
6074
|
+
const id = getRequestJsonRpcId(req.body);
|
|
6075
|
+
if (!authHeader && !requireAuth) {
|
|
6076
|
+
next();
|
|
6077
|
+
return;
|
|
6078
|
+
}
|
|
6079
|
+
try {
|
|
6080
|
+
const auth = buildAuthInfoFromBearer(authHeader, authInfo);
|
|
6081
|
+
if (!auth) {
|
|
6082
|
+
throw new McpBearerAuthError("Missing bearer token");
|
|
6083
|
+
}
|
|
6084
|
+
req.auth = auth;
|
|
6085
|
+
next();
|
|
6086
|
+
} catch {
|
|
6087
|
+
setMcpChallengeHeader(res, publicBaseUrl, protectedResourcePath);
|
|
6088
|
+
if (req.method === "POST") {
|
|
6089
|
+
res.status(401).json(makeUnauthorizedJsonRpc(id));
|
|
6090
|
+
return;
|
|
6091
|
+
}
|
|
6092
|
+
res.status(401).json({ error: "Unauthorized" });
|
|
6093
|
+
}
|
|
6094
|
+
};
|
|
6095
|
+
return [protectedResourceMiddleware, authorizationServerMiddleware, mcpAuthMiddleware];
|
|
6096
|
+
}
|
|
6097
|
+
|
|
5832
6098
|
// src/helpers/error.ts
|
|
5833
6099
|
var import_core3 = require("@solvapay/core");
|
|
5834
6100
|
function isErrorResult(result) {
|
|
@@ -6183,9 +6449,11 @@ function verifyWebhook({
|
|
|
6183
6449
|
McpBearerAuthError,
|
|
6184
6450
|
PaywallError,
|
|
6185
6451
|
VIRTUAL_TOOL_DEFINITIONS,
|
|
6452
|
+
buildAuthInfoFromBearer,
|
|
6186
6453
|
cancelPurchaseCore,
|
|
6187
6454
|
createCheckoutSessionCore,
|
|
6188
6455
|
createCustomerSessionCore,
|
|
6456
|
+
createMcpOAuthBridge,
|
|
6189
6457
|
createPaymentIntentCore,
|
|
6190
6458
|
createSolvaPay,
|
|
6191
6459
|
createSolvaPayClient,
|
|
@@ -6195,10 +6463,14 @@ function verifyWebhook({
|
|
|
6195
6463
|
getAuthenticatedUserCore,
|
|
6196
6464
|
getCustomerRefFromBearerAuthHeader,
|
|
6197
6465
|
getCustomerRefFromJwtPayload,
|
|
6466
|
+
getOAuthAuthorizationServerResponse,
|
|
6467
|
+
getOAuthProtectedResourceResponse,
|
|
6198
6468
|
handleRouteError,
|
|
6199
6469
|
isErrorResult,
|
|
6470
|
+
jsonSchemaToZodRawShape,
|
|
6200
6471
|
listPlansCore,
|
|
6201
6472
|
processPaymentIntentCore,
|
|
6473
|
+
registerVirtualToolsMcpImpl,
|
|
6202
6474
|
syncCustomerCore,
|
|
6203
6475
|
verifyWebhook,
|
|
6204
6476
|
withRetry
|