@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.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 auth = args?.auth;
1122
- const customerRef = auth?.customer_ref || "anonymous";
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
- return {
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
- customerReference: customerRef,
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
- customerReference: params.customerRef,
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 auth = args?.auth;
5457
- const customerRef = auth?.customer_ref || "anonymous";
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
- return {
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
- customerReference: customerRef,
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
- customerReference: params.customerRef,
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