@solvapay/server 1.0.8-preview.5 → 1.0.8-preview.7

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.
Files changed (139) hide show
  1. package/dist/chunk-R5U7XKVJ.js +16 -0
  2. package/dist/dist-EPVKJAIP.js +94 -0
  3. package/dist/dist-JBJ4HMP7.js +94 -0
  4. package/dist/esm-5GYCIXIY.js +3475 -0
  5. package/dist/esm-UW7WCMEK.js +3475 -0
  6. package/dist/index.cjs +293 -12
  7. package/dist/index.d.cts +35 -3
  8. package/dist/index.d.ts +35 -3
  9. package/dist/index.js +289 -12
  10. package/dist/src/adapters/base.d.ts +57 -0
  11. package/dist/src/adapters/base.d.ts.map +1 -0
  12. package/dist/src/adapters/base.js +73 -0
  13. package/dist/src/adapters/base.js.map +1 -0
  14. package/dist/src/adapters/http.d.ts +25 -0
  15. package/dist/src/adapters/http.d.ts.map +1 -0
  16. package/dist/src/adapters/http.js +99 -0
  17. package/dist/src/adapters/http.js.map +1 -0
  18. package/dist/src/adapters/index.d.ts +11 -0
  19. package/dist/src/adapters/index.d.ts.map +1 -0
  20. package/dist/src/adapters/index.js +10 -0
  21. package/dist/src/adapters/index.js.map +1 -0
  22. package/dist/src/adapters/mcp.d.ts +24 -0
  23. package/dist/src/adapters/mcp.d.ts.map +1 -0
  24. package/dist/src/adapters/mcp.js +75 -0
  25. package/dist/src/adapters/mcp.js.map +1 -0
  26. package/dist/src/adapters/next.d.ts +24 -0
  27. package/dist/src/adapters/next.d.ts.map +1 -0
  28. package/dist/src/adapters/next.js +109 -0
  29. package/dist/src/adapters/next.js.map +1 -0
  30. package/dist/src/client.d.ts +58 -0
  31. package/dist/src/client.d.ts.map +1 -0
  32. package/dist/src/client.js +495 -0
  33. package/dist/src/client.js.map +1 -0
  34. package/dist/src/edge.d.ts +22 -0
  35. package/dist/src/edge.d.ts.map +1 -0
  36. package/dist/src/edge.js +91 -0
  37. package/dist/src/edge.js.map +1 -0
  38. package/dist/src/factory.d.ts +605 -0
  39. package/dist/src/factory.d.ts.map +1 -0
  40. package/dist/src/factory.js +215 -0
  41. package/dist/src/factory.js.map +1 -0
  42. package/dist/src/helpers/auth.d.ts +47 -0
  43. package/dist/src/helpers/auth.d.ts.map +1 -0
  44. package/dist/src/helpers/auth.js +73 -0
  45. package/dist/src/helpers/auth.js.map +1 -0
  46. package/dist/src/helpers/checkout.d.ts +45 -0
  47. package/dist/src/helpers/checkout.d.ts.map +1 -0
  48. package/dist/src/helpers/checkout.js +89 -0
  49. package/dist/src/helpers/checkout.js.map +1 -0
  50. package/dist/src/helpers/customer.d.ts +51 -0
  51. package/dist/src/helpers/customer.d.ts.map +1 -0
  52. package/dist/src/helpers/customer.js +77 -0
  53. package/dist/src/helpers/customer.js.map +1 -0
  54. package/dist/src/helpers/error.d.ts +15 -0
  55. package/dist/src/helpers/error.d.ts.map +1 -0
  56. package/dist/src/helpers/error.js +35 -0
  57. package/dist/src/helpers/error.js.map +1 -0
  58. package/dist/src/helpers/index.d.ts +17 -0
  59. package/dist/src/helpers/index.d.ts.map +1 -0
  60. package/dist/src/helpers/index.js +23 -0
  61. package/dist/src/helpers/index.js.map +1 -0
  62. package/dist/src/helpers/payment.d.ts +107 -0
  63. package/dist/src/helpers/payment.d.ts.map +1 -0
  64. package/dist/src/helpers/payment.js +150 -0
  65. package/dist/src/helpers/payment.js.map +1 -0
  66. package/dist/src/helpers/plans.d.ts +19 -0
  67. package/dist/src/helpers/plans.d.ts.map +1 -0
  68. package/dist/src/helpers/plans.js +53 -0
  69. package/dist/src/helpers/plans.js.map +1 -0
  70. package/dist/src/helpers/renewal.d.ts +23 -0
  71. package/dist/src/helpers/renewal.d.ts.map +1 -0
  72. package/dist/src/helpers/renewal.js +90 -0
  73. package/dist/src/helpers/renewal.js.map +1 -0
  74. package/dist/src/helpers/subscription.d.ts +23 -0
  75. package/dist/src/helpers/subscription.d.ts.map +1 -0
  76. package/dist/src/helpers/subscription.js +101 -0
  77. package/dist/src/helpers/subscription.js.map +1 -0
  78. package/dist/src/helpers/types.d.ts +22 -0
  79. package/dist/src/helpers/types.d.ts.map +1 -0
  80. package/dist/src/helpers/types.js +7 -0
  81. package/dist/src/helpers/types.js.map +1 -0
  82. package/dist/src/index.d.ts +73 -0
  83. package/dist/src/index.d.ts.map +1 -0
  84. package/dist/src/index.js +106 -0
  85. package/dist/src/index.js.map +1 -0
  86. package/dist/src/mcp/auth-bridge.d.ts +9 -0
  87. package/dist/src/mcp/auth-bridge.d.ts.map +1 -0
  88. package/dist/src/mcp/auth-bridge.js +46 -0
  89. package/dist/src/mcp/auth-bridge.js.map +1 -0
  90. package/dist/src/mcp/oauth-bridge.d.ts +48 -0
  91. package/dist/src/mcp/oauth-bridge.d.ts.map +1 -0
  92. package/dist/src/mcp/oauth-bridge.js +110 -0
  93. package/dist/src/mcp/oauth-bridge.js.map +1 -0
  94. package/dist/src/mcp-auth.d.ts +17 -0
  95. package/dist/src/mcp-auth.d.ts.map +1 -0
  96. package/dist/src/mcp-auth.js +57 -0
  97. package/dist/src/mcp-auth.js.map +1 -0
  98. package/dist/src/paywall.d.ts +119 -0
  99. package/dist/src/paywall.d.ts.map +1 -0
  100. package/dist/src/paywall.js +700 -0
  101. package/dist/src/paywall.js.map +1 -0
  102. package/dist/src/register-virtual-tools-mcp.d.ts +23 -0
  103. package/dist/src/register-virtual-tools-mcp.d.ts.map +1 -0
  104. package/dist/src/register-virtual-tools-mcp.js +86 -0
  105. package/dist/src/register-virtual-tools-mcp.js.map +1 -0
  106. package/dist/src/types/client.d.ts +216 -0
  107. package/dist/src/types/client.d.ts.map +1 -0
  108. package/dist/src/types/client.js +7 -0
  109. package/dist/src/types/client.js.map +1 -0
  110. package/dist/src/types/generated.d.ts +2834 -0
  111. package/dist/src/types/generated.d.ts.map +1 -0
  112. package/dist/src/types/generated.js +6 -0
  113. package/dist/src/types/generated.js.map +1 -0
  114. package/dist/src/types/index.d.ts +13 -0
  115. package/dist/src/types/index.d.ts.map +1 -0
  116. package/dist/src/types/index.js +8 -0
  117. package/dist/src/types/index.js.map +1 -0
  118. package/dist/src/types/options.d.ts +126 -0
  119. package/dist/src/types/options.d.ts.map +1 -0
  120. package/dist/src/types/options.js +8 -0
  121. package/dist/src/types/options.js.map +1 -0
  122. package/dist/src/types/paywall.d.ts +64 -0
  123. package/dist/src/types/paywall.d.ts.map +1 -0
  124. package/dist/src/types/paywall.js +7 -0
  125. package/dist/src/types/paywall.js.map +1 -0
  126. package/dist/src/types/webhook.d.ts +50 -0
  127. package/dist/src/types/webhook.d.ts.map +1 -0
  128. package/dist/src/types/webhook.js +2 -0
  129. package/dist/src/types/webhook.js.map +1 -0
  130. package/dist/src/utils.d.ts +110 -0
  131. package/dist/src/utils.d.ts.map +1 -0
  132. package/dist/src/utils.js +217 -0
  133. package/dist/src/utils.js.map +1 -0
  134. package/dist/src/virtual-tools.d.ts +44 -0
  135. package/dist/src/virtual-tools.d.ts.map +1 -0
  136. package/dist/src/virtual-tools.js +140 -0
  137. package/dist/src/virtual-tools.js.map +1 -0
  138. package/dist/tsconfig.tsbuildinfo +1 -0
  139. package/package.json +7 -7
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Subscription Helpers (Core)
3
+ *
4
+ * Generic helpers for subscription operations.
5
+ * Works with standard Web API Request (works everywhere).
6
+ */
7
+ import { createSolvaPay } from '../factory';
8
+ import { SolvaPayError } from '@solvapay/core';
9
+ import { handleRouteError } from './error';
10
+ /**
11
+ * Cancel subscription - core implementation
12
+ *
13
+ * @param request - Standard Web API Request
14
+ * @param body - Cancellation parameters
15
+ * @param options - Configuration options
16
+ * @returns Cancelled subscription response or error result
17
+ */
18
+ export async function cancelSubscriptionCore(request, body, options = {}) {
19
+ try {
20
+ // Validate required parameters
21
+ if (!body.subscriptionRef) {
22
+ return {
23
+ error: 'Missing required parameter: subscriptionRef is required',
24
+ status: 400,
25
+ };
26
+ }
27
+ // Use provided SolvaPay instance or create new one
28
+ const solvaPay = options.solvaPay || createSolvaPay();
29
+ // Use the SDK client to cancel the subscription
30
+ if (!solvaPay.apiClient.cancelSubscription) {
31
+ return {
32
+ error: 'Cancel subscription method not available on SDK client',
33
+ status: 500,
34
+ };
35
+ }
36
+ let cancelledSubscription = await solvaPay.apiClient.cancelSubscription({
37
+ subscriptionRef: body.subscriptionRef,
38
+ reason: body.reason,
39
+ });
40
+ // Validate response (client should already extract subscription from nested response)
41
+ if (!cancelledSubscription || typeof cancelledSubscription !== 'object') {
42
+ return {
43
+ error: 'Invalid response from cancel subscription endpoint',
44
+ status: 500,
45
+ };
46
+ }
47
+ // Fallback: Extract subscription from nested response if client didn't already do it
48
+ const responseAny = cancelledSubscription;
49
+ if (responseAny.subscription && typeof responseAny.subscription === 'object') {
50
+ cancelledSubscription = responseAny.subscription;
51
+ }
52
+ // Validate required fields
53
+ if (!cancelledSubscription.reference) {
54
+ return {
55
+ error: 'Cancel subscription response missing required fields',
56
+ status: 500,
57
+ };
58
+ }
59
+ // Check if subscription was actually cancelled
60
+ const isCancelled = cancelledSubscription.status === 'cancelled' || cancelledSubscription.cancelledAt;
61
+ if (!isCancelled) {
62
+ return {
63
+ error: `Subscription cancellation failed: backend returned status '${cancelledSubscription.status}' without cancelledAt timestamp`,
64
+ status: 500,
65
+ };
66
+ }
67
+ // Add a small delay to allow backend to fully process the cancellation
68
+ await new Promise(resolve => setTimeout(resolve, 500));
69
+ return cancelledSubscription;
70
+ }
71
+ catch (error) {
72
+ // Handle SolvaPay errors and map to appropriate HTTP status codes
73
+ if (error instanceof SolvaPayError) {
74
+ const errorMessage = error.message;
75
+ // Map specific error messages to HTTP status codes
76
+ if (errorMessage.includes('Subscription not found')) {
77
+ return {
78
+ error: 'Subscription not found',
79
+ status: 404,
80
+ details: errorMessage,
81
+ };
82
+ }
83
+ if (errorMessage.includes('cannot be cancelled') ||
84
+ errorMessage.includes('does not belong to provider')) {
85
+ return {
86
+ error: 'Subscription cannot be cancelled or does not belong to provider',
87
+ status: 400,
88
+ details: errorMessage,
89
+ };
90
+ }
91
+ // For other SolvaPay errors, return 500
92
+ return {
93
+ error: errorMessage,
94
+ status: 500,
95
+ details: errorMessage,
96
+ };
97
+ }
98
+ return handleRouteError(error, 'Cancel subscription', 'Failed to cancel subscription');
99
+ }
100
+ }
101
+ //# sourceMappingURL=subscription.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription.js","sourceRoot":"","sources":["../../../src/helpers/subscription.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE1C;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,OAAgB,EAChB,IAGC,EACD,UAEI,EAAE;IAEN,IAAI,CAAC;QACH,+BAA+B;QAC/B,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;YAC1B,OAAO;gBACL,KAAK,EAAE,yDAAyD;gBAChE,MAAM,EAAE,GAAG;aACZ,CAAA;QACH,CAAC;QAED,mDAAmD;QACnD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,cAAc,EAAE,CAAA;QAErD,gDAAgD;QAChD,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,kBAAkB,EAAE,CAAC;YAC3C,OAAO;gBACL,KAAK,EAAE,wDAAwD;gBAC/D,MAAM,EAAE,GAAG;aACZ,CAAA;QACH,CAAC;QAED,IAAI,qBAAqB,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,kBAAkB,CAAC;YACtE,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAA;QAEF,sFAAsF;QACtF,IAAI,CAAC,qBAAqB,IAAI,OAAO,qBAAqB,KAAK,QAAQ,EAAE,CAAC;YACxE,OAAO;gBACL,KAAK,EAAE,oDAAoD;gBAC3D,MAAM,EAAE,GAAG;aACZ,CAAA;QACH,CAAC;QAED,qFAAqF;QACrF,MAAM,WAAW,GAAG,qBAA4B,CAAA;QAChD,IAAI,WAAW,CAAC,YAAY,IAAI,OAAO,WAAW,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;YAC7E,qBAAqB,GAAG,WAAW,CAAC,YAAY,CAAA;QAClD,CAAC;QAED,2BAA2B;QAC3B,IAAI,CAAC,qBAAqB,CAAC,SAAS,EAAE,CAAC;YACrC,OAAO;gBACL,KAAK,EAAE,sDAAsD;gBAC7D,MAAM,EAAE,GAAG;aACZ,CAAA;QACH,CAAC;QAED,+CAA+C;QAC/C,MAAM,WAAW,GACf,qBAAqB,CAAC,MAAM,KAAK,WAAW,IAAI,qBAAqB,CAAC,WAAW,CAAA;QAEnF,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO;gBACL,KAAK,EAAE,8DAA8D,qBAAqB,CAAC,MAAM,iCAAiC;gBAClI,MAAM,EAAE,GAAG;aACZ,CAAA;QACH,CAAC;QAED,uEAAuE;QACvE,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAA;QAEtD,OAAO,qBAAqB,CAAA;IAC9B,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,kEAAkE;QAClE,IAAI,KAAK,YAAY,aAAa,EAAE,CAAC;YACnC,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAA;YAElC,mDAAmD;YACnD,IAAI,YAAY,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAAE,CAAC;gBACpD,OAAO;oBACL,KAAK,EAAE,wBAAwB;oBAC/B,MAAM,EAAE,GAAG;oBACX,OAAO,EAAE,YAAY;iBACtB,CAAA;YACH,CAAC;YAED,IACE,YAAY,CAAC,QAAQ,CAAC,qBAAqB,CAAC;gBAC5C,YAAY,CAAC,QAAQ,CAAC,6BAA6B,CAAC,EACpD,CAAC;gBACD,OAAO;oBACL,KAAK,EAAE,iEAAiE;oBACxE,MAAM,EAAE,GAAG;oBACX,OAAO,EAAE,YAAY;iBACtB,CAAA;YACH,CAAC;YAED,wCAAwC;YACxC,OAAO;gBACL,KAAK,EAAE,YAAY;gBACnB,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE,YAAY;aACtB,CAAA;QACH,CAAC;QAED,OAAO,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,EAAE,+BAA+B,CAAC,CAAA;IACxF,CAAC;AACH,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Helper Types
3
+ *
4
+ * Shared types for route helpers
5
+ */
6
+ /**
7
+ * Error result returned by core helpers
8
+ */
9
+ export interface ErrorResult {
10
+ error: string;
11
+ status: number;
12
+ details?: string;
13
+ }
14
+ /**
15
+ * Authenticated user information
16
+ */
17
+ export interface AuthenticatedUser {
18
+ userId: string;
19
+ email?: string | null;
20
+ name?: string | null;
21
+ }
22
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/helpers/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Helper Types
3
+ *
4
+ * Shared types for route helpers
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/helpers/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * SolvaPay Server SDK
3
+ *
4
+ * Main entry point for the SolvaPay server-side SDK.
5
+ * Provides unified payable API with explicit adapters for all frameworks.
6
+ */
7
+ import type { WebhookEvent } from './types/webhook';
8
+ export { createSolvaPay } from './factory';
9
+ export type { CreateSolvaPayConfig, SolvaPay, PayableFunction } from './factory';
10
+ export { createSolvaPayClient } from './client';
11
+ export type { ServerClientOptions } from './client';
12
+ /**
13
+ * Verify webhook signature from SolvaPay backend.
14
+ *
15
+ * The backend sends an `SV-Signature` header in the format `t={timestamp},v1={hmac}`.
16
+ * The HMAC is SHA-256 over `"{timestamp}.{rawBody}"` keyed by the full webhook secret
17
+ * (including the `whsec_` prefix). Signatures older than 5 minutes are rejected to
18
+ * prevent replay attacks.
19
+ *
20
+ * @param params - Webhook verification parameters
21
+ * @param params.body - Raw request body as string (must be exactly as received)
22
+ * @param params.signature - Value of the `SV-Signature` header
23
+ * @param params.secret - Webhook signing secret from SolvaPay dashboard (`whsec_…`)
24
+ * @returns Parsed and typed {@link WebhookEvent} object
25
+ * @throws {SolvaPayError} If signature is missing, malformed, expired, or invalid
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * import { verifyWebhook } from '@solvapay/server';
30
+ *
31
+ * // Express.js — use express.raw() so the body is not parsed
32
+ * app.post('/webhooks/solvapay', express.raw({ type: 'application/json' }), (req, res) => {
33
+ * try {
34
+ * const event = verifyWebhook({
35
+ * body: req.body.toString(),
36
+ * signature: req.headers['sv-signature'] as string,
37
+ * secret: process.env.SOLVAPAY_WEBHOOK_SECRET!,
38
+ * });
39
+ *
40
+ * if (event.type === 'purchase.created') {
41
+ * // …
42
+ * }
43
+ *
44
+ * res.json({ received: true });
45
+ * } catch (error) {
46
+ * res.status(401).json({ error: 'Invalid signature' });
47
+ * }
48
+ * });
49
+ * ```
50
+ *
51
+ * @see [Webhook Guide](../../../docs/guides/webhooks.md) for complete webhook handling examples
52
+ * @since 1.0.0
53
+ */
54
+ export declare function verifyWebhook({ body, signature, secret, }: {
55
+ body: string;
56
+ signature: string;
57
+ secret: string;
58
+ }): WebhookEvent;
59
+ export { PaywallError, paywallErrorToClientPayload } from './paywall';
60
+ export { createVirtualTools, VIRTUAL_TOOL_DEFINITIONS } from './virtual-tools';
61
+ export type { VirtualToolsOptions, VirtualToolDefinition } from './virtual-tools';
62
+ export { registerVirtualToolsMcpImpl, jsonSchemaToZodRawShape } from './register-virtual-tools-mcp';
63
+ export type { McpServerLike, RegisterVirtualToolsMcpOptions } from './register-virtual-tools-mcp';
64
+ export { buildAuthInfoFromBearer } from './mcp/auth-bridge';
65
+ export { createMcpOAuthBridge } from './mcp/oauth-bridge';
66
+ export { getOAuthProtectedResourceResponse, getOAuthAuthorizationServerResponse, } from './mcp/oauth-bridge';
67
+ export type { components, LimitActivationBalance, LimitActivationProduct, LimitPlanSummary, SolvaPayClient, PayableOptions, HttpAdapterOptions, NextAdapterOptions, McpAdapterOptions, PaywallArgs, PaywallMetadata, PaywallStructuredContent, PaywallToolResult, RetryOptions, McpToolExtra, WebhookEvent, WebhookEventType, WebhookEventForType, WebhookEventObjectMap, CustomerWebhookObject, WebhookProduct, } from './types';
68
+ export type { OneTimePurchaseInfo, ProcessPaymentResult, CustomerResponseMapped, McpBootstrapRequest, McpBootstrapResponse, McpBootstrapPlanInput, ConfigureMcpPlansRequest, ConfigureMcpPlansResponse, McpToolPlanMappingInput, ToolPlanMappingInput, } from './types/client';
69
+ export { withRetry } from './utils';
70
+ export { McpBearerAuthError, extractBearerToken, decodeJwtPayload, getCustomerRefFromJwtPayload, getCustomerRefFromBearerAuthHeader, } from './mcp-auth';
71
+ export { getAuthenticatedUserCore, syncCustomerCore, createPaymentIntentCore, processPaymentIntentCore, createCheckoutSessionCore, createCustomerSessionCore, cancelPurchaseCore, listPlansCore, isErrorResult, handleRouteError, } from './helpers';
72
+ export type { ErrorResult, AuthenticatedUser } from './helpers';
73
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAGnD,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAC1C,YAAY,EAAE,oBAAoB,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAGhF,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAC/C,YAAY,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,SAAS,EACT,MAAM,GACP,EAAE;IACD,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;CACf,GAAG,YAAY,CAwCf;AAGD,OAAO,EAAE,YAAY,EAAE,2BAA2B,EAAE,MAAM,WAAW,CAAA;AAGrE,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAA;AAC9E,YAAY,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AACjF,OAAO,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AACnG,YAAY,EAAE,aAAa,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAA;AACjG,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EACL,iCAAiC,EACjC,mCAAmC,GACpC,MAAM,oBAAoB,CAAA;AAG3B,YAAY,EACV,UAAU,EACV,sBAAsB,EACtB,sBAAsB,EACtB,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,WAAW,EACX,eAAe,EACf,wBAAwB,EACxB,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,GACf,MAAM,SAAS,CAAA;AAGhB,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,wBAAwB,EACxB,yBAAyB,EACzB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,gBAAgB,CAAA;AAGvB,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACnC,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,4BAA4B,EAC5B,kCAAkC,GACnC,MAAM,YAAY,CAAA;AAGnB,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,uBAAuB,EACvB,wBAAwB,EACxB,yBAAyB,EACzB,yBAAyB,EACzB,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,gBAAgB,GACjB,MAAM,WAAW,CAAA;AAClB,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * SolvaPay Server SDK
3
+ *
4
+ * Main entry point for the SolvaPay server-side SDK.
5
+ * Provides unified payable API with explicit adapters for all frameworks.
6
+ */
7
+ import crypto from 'node:crypto';
8
+ import { SolvaPayError } from '@solvapay/core';
9
+ // Main factory for unified API
10
+ export { createSolvaPay } from './factory';
11
+ // Re-export client creation (for advanced use cases)
12
+ export { createSolvaPayClient } from './client';
13
+ /**
14
+ * Verify webhook signature from SolvaPay backend.
15
+ *
16
+ * The backend sends an `SV-Signature` header in the format `t={timestamp},v1={hmac}`.
17
+ * The HMAC is SHA-256 over `"{timestamp}.{rawBody}"` keyed by the full webhook secret
18
+ * (including the `whsec_` prefix). Signatures older than 5 minutes are rejected to
19
+ * prevent replay attacks.
20
+ *
21
+ * @param params - Webhook verification parameters
22
+ * @param params.body - Raw request body as string (must be exactly as received)
23
+ * @param params.signature - Value of the `SV-Signature` header
24
+ * @param params.secret - Webhook signing secret from SolvaPay dashboard (`whsec_…`)
25
+ * @returns Parsed and typed {@link WebhookEvent} object
26
+ * @throws {SolvaPayError} If signature is missing, malformed, expired, or invalid
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * import { verifyWebhook } from '@solvapay/server';
31
+ *
32
+ * // Express.js — use express.raw() so the body is not parsed
33
+ * app.post('/webhooks/solvapay', express.raw({ type: 'application/json' }), (req, res) => {
34
+ * try {
35
+ * const event = verifyWebhook({
36
+ * body: req.body.toString(),
37
+ * signature: req.headers['sv-signature'] as string,
38
+ * secret: process.env.SOLVAPAY_WEBHOOK_SECRET!,
39
+ * });
40
+ *
41
+ * if (event.type === 'purchase.created') {
42
+ * // …
43
+ * }
44
+ *
45
+ * res.json({ received: true });
46
+ * } catch (error) {
47
+ * res.status(401).json({ error: 'Invalid signature' });
48
+ * }
49
+ * });
50
+ * ```
51
+ *
52
+ * @see [Webhook Guide](../../../docs/guides/webhooks.md) for complete webhook handling examples
53
+ * @since 1.0.0
54
+ */
55
+ export function verifyWebhook({ body, signature, secret, }) {
56
+ const toleranceSec = 300;
57
+ if (!signature)
58
+ throw new SolvaPayError('Missing webhook signature');
59
+ const parts = signature.split(',');
60
+ const tPart = parts.find(p => p.startsWith('t='));
61
+ const v1Part = parts.find(p => p.startsWith('v1='));
62
+ if (!tPart || !v1Part) {
63
+ throw new SolvaPayError('Malformed webhook signature');
64
+ }
65
+ const timestamp = parseInt(tPart.slice(2), 10);
66
+ const receivedHmac = v1Part.slice(3);
67
+ if (Number.isNaN(timestamp) || !receivedHmac) {
68
+ throw new SolvaPayError('Malformed webhook signature');
69
+ }
70
+ if (toleranceSec > 0) {
71
+ const age = Math.abs(Math.floor(Date.now() / 1000) - timestamp);
72
+ if (age > toleranceSec) {
73
+ throw new SolvaPayError('Webhook signature timestamp too old');
74
+ }
75
+ }
76
+ const expectedHmac = crypto
77
+ .createHmac('sha256', secret)
78
+ .update(`${timestamp}.${body}`)
79
+ .digest('hex');
80
+ if (receivedHmac.length !== expectedHmac.length) {
81
+ throw new SolvaPayError('Invalid webhook signature');
82
+ }
83
+ const ok = crypto.timingSafeEqual(Buffer.from(expectedHmac), Buffer.from(receivedHmac));
84
+ if (!ok)
85
+ throw new SolvaPayError('Invalid webhook signature');
86
+ try {
87
+ return JSON.parse(body);
88
+ }
89
+ catch {
90
+ throw new SolvaPayError('Invalid webhook payload: body is not valid JSON');
91
+ }
92
+ }
93
+ // Export PaywallError for error handling
94
+ export { PaywallError, paywallErrorToClientPayload } from './paywall';
95
+ // Export virtual tools for MCP server monetization
96
+ export { createVirtualTools, VIRTUAL_TOOL_DEFINITIONS } from './virtual-tools';
97
+ export { registerVirtualToolsMcpImpl, jsonSchemaToZodRawShape } from './register-virtual-tools-mcp';
98
+ export { buildAuthInfoFromBearer } from './mcp/auth-bridge';
99
+ export { createMcpOAuthBridge } from './mcp/oauth-bridge';
100
+ export { getOAuthProtectedResourceResponse, getOAuthAuthorizationServerResponse, } from './mcp/oauth-bridge';
101
+ // Export utilities for general use
102
+ export { withRetry } from './utils';
103
+ export { McpBearerAuthError, extractBearerToken, decodeJwtPayload, getCustomerRefFromJwtPayload, getCustomerRefFromBearerAuthHeader, } from './mcp-auth';
104
+ // Export route helpers (generic, framework-agnostic)
105
+ export { getAuthenticatedUserCore, syncCustomerCore, createPaymentIntentCore, processPaymentIntentCore, createCheckoutSessionCore, createCustomerSessionCore, cancelPurchaseCore, listPlansCore, isErrorResult, handleRouteError, } from './helpers';
106
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { type McpBearerCustomerRefOptions } from '../mcp-auth';
2
+ import type { McpToolExtra } from '../types';
3
+ export interface BuildAuthInfoFromBearerOptions extends McpBearerCustomerRefOptions {
4
+ clientId?: string;
5
+ defaultScopes?: string[];
6
+ includePayload?: boolean;
7
+ }
8
+ export declare function buildAuthInfoFromBearer(authorization?: string | null, options?: BuildAuthInfoFromBearerOptions): McpToolExtra['authInfo'] | null;
9
+ //# sourceMappingURL=auth-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-bridge.d.ts","sourceRoot":"","sources":["../../../src/mcp/auth-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,2BAA2B,EACjC,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAI5C,MAAM,WAAW,8BAA+B,SAAQ,2BAA2B;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAiCD,wBAAgB,uBAAuB,CACrC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,EAC7B,OAAO,GAAE,8BAAmC,GAC3C,YAAY,CAAC,UAAU,CAAC,GAAG,IAAI,CAoBjC"}
@@ -0,0 +1,46 @@
1
+ import { decodeJwtPayload, extractBearerToken, getCustomerRefFromJwtPayload, } from '../mcp-auth';
2
+ function getClientId(payload, explicitClientId) {
3
+ if (explicitClientId)
4
+ return explicitClientId;
5
+ const payloadClientId = (typeof payload.client_id === 'string' && payload.client_id) ||
6
+ (typeof payload.azp === 'string' && payload.azp) ||
7
+ (typeof payload.aud === 'string' && payload.aud) ||
8
+ null;
9
+ return payloadClientId || 'solvapay-mcp-client';
10
+ }
11
+ function getScopes(payload, defaultScopes) {
12
+ if (Array.isArray(payload.scp)) {
13
+ return payload.scp.filter(scope => typeof scope === 'string');
14
+ }
15
+ if (typeof payload.scope === 'string' && payload.scope.trim()) {
16
+ return payload.scope
17
+ .split(/\s+/)
18
+ .map(scope => scope.trim())
19
+ .filter(Boolean);
20
+ }
21
+ return defaultScopes;
22
+ }
23
+ function getExpiresAt(payload) {
24
+ return typeof payload.exp === 'number' ? payload.exp : undefined;
25
+ }
26
+ export function buildAuthInfoFromBearer(authorization, options = {}) {
27
+ const token = extractBearerToken(authorization);
28
+ if (!token)
29
+ return null;
30
+ const payload = decodeJwtPayload(token);
31
+ const customerRef = getCustomerRefFromJwtPayload(payload, options);
32
+ const clientId = getClientId(payload, options.clientId);
33
+ const scopes = getScopes(payload, options.defaultScopes || []);
34
+ const expiresAt = getExpiresAt(payload);
35
+ return {
36
+ token,
37
+ clientId,
38
+ scopes,
39
+ expiresAt,
40
+ extra: {
41
+ customer_ref: customerRef,
42
+ ...(options.includePayload ? { payload } : {}),
43
+ },
44
+ };
45
+ }
46
+ //# sourceMappingURL=auth-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-bridge.js","sourceRoot":"","sources":["../../../src/mcp/auth-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,4BAA4B,GAE7B,MAAM,aAAa,CAAA;AAWpB,SAAS,WAAW,CAAC,OAAmB,EAAE,gBAAyB;IACjE,IAAI,gBAAgB;QAAE,OAAO,gBAAgB,CAAA;IAE7C,MAAM,eAAe,GACnB,CAAC,OAAO,OAAO,CAAC,SAAS,KAAK,QAAQ,IAAI,OAAO,CAAC,SAAS,CAAC;QAC5D,CAAC,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC;QAChD,CAAC,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC;QAChD,IAAI,CAAA;IAEN,OAAO,eAAe,IAAI,qBAAqB,CAAA;AACjD,CAAC;AAED,SAAS,SAAS,CAAC,OAAmB,EAAE,aAAuB;IAC7D,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAa,CAAA;IAC3E,CAAC;IAED,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAC9D,OAAO,OAAO,CAAC,KAAK;aACjB,KAAK,CAAC,KAAK,CAAC;aACZ,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;aAC1B,MAAM,CAAC,OAAO,CAAC,CAAA;IACpB,CAAC;IAED,OAAO,aAAa,CAAA;AACtB,CAAC;AAED,SAAS,YAAY,CAAC,OAAmB;IACvC,OAAO,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAA;AAClE,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,aAA6B,EAC7B,UAA0C,EAAE;IAE5C,MAAM,KAAK,GAAG,kBAAkB,CAAC,aAAa,CAAC,CAAA;IAC/C,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IAEvB,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAA;IACvC,MAAM,WAAW,GAAG,4BAA4B,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IAClE,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IACvD,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,aAAa,IAAI,EAAE,CAAC,CAAA;IAC9D,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;IAEvC,OAAO;QACL,KAAK;QACL,QAAQ;QACR,MAAM;QACN,SAAS;QACT,KAAK,EAAE;YACL,YAAY,EAAE,WAAW;YACzB,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/C;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,48 @@
1
+ import { type BuildAuthInfoFromBearerOptions } from './auth-bridge';
2
+ type RequestLike = {
3
+ method?: string;
4
+ path?: string;
5
+ headers?: Record<string, string | string[] | undefined>;
6
+ body?: unknown;
7
+ auth?: unknown;
8
+ };
9
+ type ResponseLike = {
10
+ status: (code: number) => ResponseLike;
11
+ json: (payload: unknown) => void;
12
+ setHeader: (name: string, value: string) => void;
13
+ };
14
+ type NextLike = () => void;
15
+ type Middleware = (req: RequestLike, res: ResponseLike, next: NextLike) => void;
16
+ export interface OAuthAuthorizationServerOptions {
17
+ apiBaseUrl: string;
18
+ productRef: string;
19
+ }
20
+ export interface McpOAuthBridgeOptions {
21
+ publicBaseUrl: string;
22
+ apiBaseUrl: string;
23
+ productRef: string;
24
+ mcpPath?: string;
25
+ requireAuth?: boolean;
26
+ authInfo?: BuildAuthInfoFromBearerOptions;
27
+ protectedResourcePath?: string;
28
+ authorizationServerPath?: string;
29
+ }
30
+ export declare function getOAuthProtectedResourceResponse(publicBaseUrl: string): {
31
+ resource: string;
32
+ authorization_servers: string[];
33
+ scopes_supported: string[];
34
+ };
35
+ export declare function getOAuthAuthorizationServerResponse({ apiBaseUrl, productRef, }: OAuthAuthorizationServerOptions): {
36
+ issuer: string;
37
+ authorization_endpoint: string;
38
+ token_endpoint: string;
39
+ registration_endpoint: string;
40
+ token_endpoint_auth_methods_supported: string[];
41
+ response_types_supported: string[];
42
+ grant_types_supported: string[];
43
+ scopes_supported: string[];
44
+ code_challenge_methods_supported: string[];
45
+ };
46
+ export declare function createMcpOAuthBridge(options: McpOAuthBridgeOptions): Middleware[];
47
+ export {};
48
+ //# sourceMappingURL=oauth-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth-bridge.d.ts","sourceRoot":"","sources":["../../../src/mcp/oauth-bridge.ts"],"names":[],"mappings":"AACA,OAAO,EAA2B,KAAK,8BAA8B,EAAE,MAAM,eAAe,CAAA;AAI5F,KAAK,WAAW,GAAG;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAA;IACvD,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,CAAA;AAED,KAAK,YAAY,GAAG;IAClB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,YAAY,CAAA;IACtC,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IAChC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACjD,CAAA;AAED,KAAK,QAAQ,GAAG,MAAM,IAAI,CAAA;AAC1B,KAAK,UAAU,GAAG,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAA;AAE/E,MAAM,WAAW,+BAA+B;IAC9C,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,EAAE,8BAA8B,CAAA;IACzC,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,uBAAuB,CAAC,EAAE,MAAM,CAAA;CACjC;AAuCD,wBAAgB,iCAAiC,CAAC,aAAa,EAAE,MAAM;;;;EAOtE;AAED,wBAAgB,mCAAmC,CAAC,EAClD,UAAU,EACV,UAAU,GACX,EAAE,+BAA+B;;;;;;;;;;EAejC;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,UAAU,EAAE,CA2EjF"}
@@ -0,0 +1,110 @@
1
+ import { McpBearerAuthError } from '../mcp-auth';
2
+ import { buildAuthInfoFromBearer } from './auth-bridge';
3
+ function withoutTrailingSlash(value) {
4
+ return value.replace(/\/$/, '');
5
+ }
6
+ function getRequestAuthHeader(req) {
7
+ const header = req.headers?.authorization;
8
+ if (typeof header === 'string')
9
+ return header;
10
+ if (Array.isArray(header))
11
+ return header[0] || null;
12
+ return null;
13
+ }
14
+ function getRequestJsonRpcId(body) {
15
+ if (body && typeof body === 'object' && 'id' in body) {
16
+ const id = body.id;
17
+ return id ?? null;
18
+ }
19
+ return null;
20
+ }
21
+ function makeUnauthorizedJsonRpc(id) {
22
+ return {
23
+ jsonrpc: '2.0',
24
+ id,
25
+ error: {
26
+ code: -32001,
27
+ message: 'Unauthorized',
28
+ },
29
+ };
30
+ }
31
+ function setMcpChallengeHeader(res, publicBaseUrl, protectedResourcePath) {
32
+ res.setHeader('WWW-Authenticate', `Bearer resource_metadata="${withoutTrailingSlash(publicBaseUrl)}${protectedResourcePath}"`);
33
+ }
34
+ export function getOAuthProtectedResourceResponse(publicBaseUrl) {
35
+ const resource = withoutTrailingSlash(publicBaseUrl);
36
+ return {
37
+ resource,
38
+ authorization_servers: [resource],
39
+ scopes_supported: ['openid', 'profile', 'email'],
40
+ };
41
+ }
42
+ export function getOAuthAuthorizationServerResponse({ apiBaseUrl, productRef, }) {
43
+ const normalizedApiBaseUrl = withoutTrailingSlash(apiBaseUrl);
44
+ const registrationEndpoint = `${normalizedApiBaseUrl}/v1/customer/auth/register?product_ref=${encodeURIComponent(productRef)}`;
45
+ return {
46
+ issuer: normalizedApiBaseUrl,
47
+ authorization_endpoint: `${normalizedApiBaseUrl}/v1/customer/auth/authorize`,
48
+ token_endpoint: `${normalizedApiBaseUrl}/v1/customer/auth/token`,
49
+ registration_endpoint: registrationEndpoint,
50
+ token_endpoint_auth_methods_supported: ['client_secret_basic', 'client_secret_post'],
51
+ response_types_supported: ['code'],
52
+ grant_types_supported: ['authorization_code', 'refresh_token'],
53
+ scopes_supported: ['openid', 'profile', 'email'],
54
+ code_challenge_methods_supported: ['S256'],
55
+ };
56
+ }
57
+ export function createMcpOAuthBridge(options) {
58
+ const { publicBaseUrl, apiBaseUrl, productRef, mcpPath = '/mcp', requireAuth = true, authInfo, protectedResourcePath = '/.well-known/oauth-protected-resource', authorizationServerPath = '/.well-known/oauth-authorization-server', } = options;
59
+ const protectedResourceMiddleware = (req, res, next) => {
60
+ if (req.method !== 'GET' || req.path !== protectedResourcePath) {
61
+ next();
62
+ return;
63
+ }
64
+ res.json(getOAuthProtectedResourceResponse(publicBaseUrl));
65
+ };
66
+ const authorizationServerMiddleware = (req, res, next) => {
67
+ if (req.method !== 'GET' || req.path !== authorizationServerPath) {
68
+ next();
69
+ return;
70
+ }
71
+ if (!productRef) {
72
+ res.status(500).json({ error: 'SOLVAPAY_PRODUCT_REF missing' });
73
+ return;
74
+ }
75
+ res.json(getOAuthAuthorizationServerResponse({
76
+ apiBaseUrl,
77
+ productRef,
78
+ }));
79
+ };
80
+ const mcpAuthMiddleware = (req, res, next) => {
81
+ if (req.path !== mcpPath) {
82
+ next();
83
+ return;
84
+ }
85
+ const authHeader = getRequestAuthHeader(req);
86
+ const id = getRequestJsonRpcId(req.body);
87
+ if (!authHeader && !requireAuth) {
88
+ next();
89
+ return;
90
+ }
91
+ try {
92
+ const auth = buildAuthInfoFromBearer(authHeader, authInfo);
93
+ if (!auth) {
94
+ throw new McpBearerAuthError('Missing bearer token');
95
+ }
96
+ req.auth = auth;
97
+ next();
98
+ }
99
+ catch {
100
+ setMcpChallengeHeader(res, publicBaseUrl, protectedResourcePath);
101
+ if (req.method === 'POST') {
102
+ res.status(401).json(makeUnauthorizedJsonRpc(id));
103
+ return;
104
+ }
105
+ res.status(401).json({ error: 'Unauthorized' });
106
+ }
107
+ };
108
+ return [protectedResourceMiddleware, authorizationServerMiddleware, mcpAuthMiddleware];
109
+ }
110
+ //# sourceMappingURL=oauth-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth-bridge.js","sourceRoot":"","sources":["../../../src/mcp/oauth-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * MCP OAuth helper utilities.
3
+ *
4
+ * These helpers are intentionally lightweight and do not verify JWT signatures.
5
+ * Use them after token validation (for example via /v1/customer/auth/userinfo).
6
+ */
7
+ export declare class McpBearerAuthError extends Error {
8
+ constructor(message: string);
9
+ }
10
+ export type McpBearerCustomerRefOptions = {
11
+ claimPriority?: string[];
12
+ };
13
+ export declare function extractBearerToken(authorization?: string | null): string | null;
14
+ export declare function decodeJwtPayload(token: string): Record<string, unknown>;
15
+ export declare function getCustomerRefFromJwtPayload(payload: Record<string, unknown>, options?: McpBearerCustomerRefOptions): string;
16
+ export declare function getCustomerRefFromBearerAuthHeader(authorization?: string | null, options?: McpBearerCustomerRefOptions): string;
17
+ //# sourceMappingURL=mcp-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-auth.d.ts","sourceRoot":"","sources":["../../src/mcp-auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;CACzB,CAAA;AAQD,wBAAgB,kBAAkB,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAI/E;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAavE;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,GAAE,2BAAgC,GACxC,MAAM,CAaR;AAED,wBAAgB,kCAAkC,CAChD,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,EAC7B,OAAO,GAAE,2BAAgC,GACxC,MAAM,CAOR"}