@solvapay/server 1.0.5 → 1.0.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.
- package/README.md +1 -1
- package/dist/edge.d.ts +945 -1746
- package/dist/edge.js +229 -35
- package/dist/index.cjs +352 -35
- package/dist/index.d.cts +980 -1734
- package/dist/index.d.ts +980 -1734
- package/dist/index.js +347 -35
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -4314,6 +4314,7 @@ __export(index_exports, {
|
|
|
4314
4314
|
McpBearerAuthError: () => McpBearerAuthError,
|
|
4315
4315
|
PaywallError: () => PaywallError,
|
|
4316
4316
|
VIRTUAL_TOOL_DEFINITIONS: () => VIRTUAL_TOOL_DEFINITIONS,
|
|
4317
|
+
activatePlanCore: () => activatePlanCore,
|
|
4317
4318
|
buildAuthInfoFromBearer: () => buildAuthInfoFromBearer,
|
|
4318
4319
|
cancelPurchaseCore: () => cancelPurchaseCore,
|
|
4319
4320
|
createCheckoutSessionCore: () => createCheckoutSessionCore,
|
|
@@ -4322,10 +4323,12 @@ __export(index_exports, {
|
|
|
4322
4323
|
createPaymentIntentCore: () => createPaymentIntentCore,
|
|
4323
4324
|
createSolvaPay: () => createSolvaPay,
|
|
4324
4325
|
createSolvaPayClient: () => createSolvaPayClient,
|
|
4326
|
+
createTopupPaymentIntentCore: () => createTopupPaymentIntentCore,
|
|
4325
4327
|
createVirtualTools: () => createVirtualTools,
|
|
4326
4328
|
decodeJwtPayload: () => decodeJwtPayload,
|
|
4327
4329
|
extractBearerToken: () => extractBearerToken,
|
|
4328
4330
|
getAuthenticatedUserCore: () => getAuthenticatedUserCore,
|
|
4331
|
+
getCustomerBalanceCore: () => getCustomerBalanceCore,
|
|
4329
4332
|
getCustomerRefFromBearerAuthHeader: () => getCustomerRefFromBearerAuthHeader,
|
|
4330
4333
|
getCustomerRefFromJwtPayload: () => getCustomerRefFromJwtPayload,
|
|
4331
4334
|
getOAuthAuthorizationServerResponse: () => getOAuthAuthorizationServerResponse,
|
|
@@ -4334,7 +4337,9 @@ __export(index_exports, {
|
|
|
4334
4337
|
isErrorResult: () => isErrorResult,
|
|
4335
4338
|
jsonSchemaToZodRawShape: () => jsonSchemaToZodRawShape,
|
|
4336
4339
|
listPlansCore: () => listPlansCore,
|
|
4340
|
+
paywallErrorToClientPayload: () => paywallErrorToClientPayload,
|
|
4337
4341
|
processPaymentIntentCore: () => processPaymentIntentCore,
|
|
4342
|
+
reactivatePurchaseCore: () => reactivatePurchaseCore,
|
|
4338
4343
|
registerVirtualToolsMcpImpl: () => registerVirtualToolsMcpImpl,
|
|
4339
4344
|
syncCustomerCore: () => syncCustomerCore,
|
|
4340
4345
|
verifyWebhook: () => verifyWebhook,
|
|
@@ -4379,12 +4384,10 @@ function createSolvaPayClient(opts) {
|
|
|
4379
4384
|
// POST: /v1/sdk/usages
|
|
4380
4385
|
async trackUsage(params) {
|
|
4381
4386
|
const url = `${base}/v1/sdk/usages`;
|
|
4382
|
-
const { customerRef, ...rest } = params;
|
|
4383
|
-
const body = { ...rest, customerId: customerRef };
|
|
4384
4387
|
const res = await fetch(url, {
|
|
4385
4388
|
method: "POST",
|
|
4386
4389
|
headers,
|
|
4387
|
-
body: JSON.stringify(
|
|
4390
|
+
body: JSON.stringify(params)
|
|
4388
4391
|
});
|
|
4389
4392
|
if (!res.ok) {
|
|
4390
4393
|
const error = await res.text();
|
|
@@ -4629,7 +4632,7 @@ function createSolvaPayClient(opts) {
|
|
|
4629
4632
|
body: JSON.stringify({
|
|
4630
4633
|
productRef: params.productRef,
|
|
4631
4634
|
planRef: params.planRef,
|
|
4632
|
-
|
|
4635
|
+
customerRef: params.customerRef
|
|
4633
4636
|
})
|
|
4634
4637
|
});
|
|
4635
4638
|
if (!res.ok) {
|
|
@@ -4637,8 +4640,32 @@ function createSolvaPayClient(opts) {
|
|
|
4637
4640
|
log(`\u274C API Error: ${res.status} - ${error}`);
|
|
4638
4641
|
throw new import_core.SolvaPayError(`Create payment intent failed (${res.status}): ${error}`);
|
|
4639
4642
|
}
|
|
4640
|
-
|
|
4641
|
-
|
|
4643
|
+
return await res.json();
|
|
4644
|
+
},
|
|
4645
|
+
// POST: /v1/sdk/payment-intents (purpose: credit_topup)
|
|
4646
|
+
async createTopupPaymentIntent(params) {
|
|
4647
|
+
const idempotencyKey = params.idempotencyKey || `topup-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
4648
|
+
const url = `${base}/v1/sdk/payment-intents`;
|
|
4649
|
+
const res = await fetch(url, {
|
|
4650
|
+
method: "POST",
|
|
4651
|
+
headers: {
|
|
4652
|
+
...headers,
|
|
4653
|
+
"Idempotency-Key": idempotencyKey
|
|
4654
|
+
},
|
|
4655
|
+
body: JSON.stringify({
|
|
4656
|
+
customerRef: params.customerRef,
|
|
4657
|
+
purpose: "credit_topup",
|
|
4658
|
+
amount: params.amount,
|
|
4659
|
+
currency: params.currency,
|
|
4660
|
+
description: params.description
|
|
4661
|
+
})
|
|
4662
|
+
});
|
|
4663
|
+
if (!res.ok) {
|
|
4664
|
+
const error = await res.text();
|
|
4665
|
+
log(`\u274C API Error: ${res.status} - ${error}`);
|
|
4666
|
+
throw new import_core.SolvaPayError(`Create topup payment intent failed (${res.status}): ${error}`);
|
|
4667
|
+
}
|
|
4668
|
+
return await res.json();
|
|
4642
4669
|
},
|
|
4643
4670
|
// POST: /v1/sdk/payment-intents/{paymentIntentId}/process
|
|
4644
4671
|
async processPaymentIntent(params) {
|
|
@@ -4715,6 +4742,54 @@ function createSolvaPayClient(opts) {
|
|
|
4715
4742
|
}
|
|
4716
4743
|
return result;
|
|
4717
4744
|
},
|
|
4745
|
+
// POST: /v1/sdk/purchases/{purchaseRef}/reactivate
|
|
4746
|
+
async reactivatePurchase(params) {
|
|
4747
|
+
const url = `${base}/v1/sdk/purchases/${params.purchaseRef}/reactivate`;
|
|
4748
|
+
const res = await fetch(url, {
|
|
4749
|
+
method: "POST",
|
|
4750
|
+
headers
|
|
4751
|
+
});
|
|
4752
|
+
if (!res.ok) {
|
|
4753
|
+
const error = await res.text();
|
|
4754
|
+
log(`\u274C API Error: ${res.status} - ${error}`);
|
|
4755
|
+
if (res.status === 404) {
|
|
4756
|
+
throw new import_core.SolvaPayError(`Purchase not found: ${error}`);
|
|
4757
|
+
}
|
|
4758
|
+
if (res.status === 400) {
|
|
4759
|
+
throw new import_core.SolvaPayError(
|
|
4760
|
+
`Purchase cannot be reactivated: ${error}`
|
|
4761
|
+
);
|
|
4762
|
+
}
|
|
4763
|
+
throw new import_core.SolvaPayError(`Reactivate purchase failed (${res.status}): ${error}`);
|
|
4764
|
+
}
|
|
4765
|
+
const responseText = await res.text();
|
|
4766
|
+
let responseData;
|
|
4767
|
+
try {
|
|
4768
|
+
responseData = JSON.parse(responseText);
|
|
4769
|
+
} catch (parseError) {
|
|
4770
|
+
log(`\u274C Failed to parse response as JSON: ${parseError}`);
|
|
4771
|
+
throw new import_core.SolvaPayError(
|
|
4772
|
+
`Invalid JSON response from reactivate purchase endpoint: ${responseText.substring(0, 200)}`
|
|
4773
|
+
);
|
|
4774
|
+
}
|
|
4775
|
+
if (!responseData || typeof responseData !== "object") {
|
|
4776
|
+
log(`\u274C Invalid response structure: ${JSON.stringify(responseData)}`);
|
|
4777
|
+
throw new import_core.SolvaPayError(`Invalid response structure from reactivate purchase endpoint`);
|
|
4778
|
+
}
|
|
4779
|
+
let result;
|
|
4780
|
+
if (responseData.purchase && typeof responseData.purchase === "object") {
|
|
4781
|
+
result = responseData.purchase;
|
|
4782
|
+
} else if (responseData.reference) {
|
|
4783
|
+
result = responseData;
|
|
4784
|
+
} else {
|
|
4785
|
+
result = responseData.purchase || responseData;
|
|
4786
|
+
}
|
|
4787
|
+
if (!result || typeof result !== "object") {
|
|
4788
|
+
log(`\u274C Invalid purchase data in response. Full response:`, responseData);
|
|
4789
|
+
throw new import_core.SolvaPayError(`Invalid purchase data in reactivate purchase response`);
|
|
4790
|
+
}
|
|
4791
|
+
return result;
|
|
4792
|
+
},
|
|
4718
4793
|
// POST: /v1/sdk/user-info
|
|
4719
4794
|
async getUserInfo(params) {
|
|
4720
4795
|
const url = `${base}/v1/sdk/user-info`;
|
|
@@ -4730,6 +4805,20 @@ function createSolvaPayClient(opts) {
|
|
|
4730
4805
|
}
|
|
4731
4806
|
return await res.json();
|
|
4732
4807
|
},
|
|
4808
|
+
// GET: /v1/sdk/customers/:customerRef/balance
|
|
4809
|
+
async getCustomerBalance(params) {
|
|
4810
|
+
const url = `${base}/v1/sdk/customers/${params.customerRef}/balance`;
|
|
4811
|
+
const res = await fetch(url, {
|
|
4812
|
+
method: "GET",
|
|
4813
|
+
headers
|
|
4814
|
+
});
|
|
4815
|
+
if (!res.ok) {
|
|
4816
|
+
const error = await res.text();
|
|
4817
|
+
log(`\u274C API Error: ${res.status} - ${error}`);
|
|
4818
|
+
throw new import_core.SolvaPayError(`Get customer balance failed (${res.status}): ${error}`);
|
|
4819
|
+
}
|
|
4820
|
+
return await res.json();
|
|
4821
|
+
},
|
|
4733
4822
|
// POST: /v1/sdk/checkout-sessions
|
|
4734
4823
|
async createCheckoutSession(params) {
|
|
4735
4824
|
const url = `${base}/v1/sdk/checkout-sessions`;
|
|
@@ -4761,6 +4850,21 @@ function createSolvaPayClient(opts) {
|
|
|
4761
4850
|
}
|
|
4762
4851
|
const result = await res.json();
|
|
4763
4852
|
return result;
|
|
4853
|
+
},
|
|
4854
|
+
// POST: /v1/sdk/activate
|
|
4855
|
+
async activatePlan(params) {
|
|
4856
|
+
const url = `${base}/v1/sdk/activate`;
|
|
4857
|
+
const res = await fetch(url, {
|
|
4858
|
+
method: "POST",
|
|
4859
|
+
headers,
|
|
4860
|
+
body: JSON.stringify(params)
|
|
4861
|
+
});
|
|
4862
|
+
if (!res.ok) {
|
|
4863
|
+
const error = await res.text();
|
|
4864
|
+
log(`\u274C API Error: ${res.status} - ${error}`);
|
|
4865
|
+
throw new import_core.SolvaPayError(`Activate plan failed (${res.status}): ${error}`);
|
|
4866
|
+
}
|
|
4867
|
+
return await res.json();
|
|
4764
4868
|
}
|
|
4765
4869
|
};
|
|
4766
4870
|
}
|
|
@@ -4916,6 +5020,24 @@ var PaywallError = class extends Error {
|
|
|
4916
5020
|
this.name = "PaywallError";
|
|
4917
5021
|
}
|
|
4918
5022
|
};
|
|
5023
|
+
function paywallErrorToClientPayload(error) {
|
|
5024
|
+
const sc = error.structuredContent;
|
|
5025
|
+
const base = {
|
|
5026
|
+
success: false,
|
|
5027
|
+
error: sc.kind === "activation_required" ? "Activation required" : "Payment required",
|
|
5028
|
+
product: sc.product,
|
|
5029
|
+
checkoutUrl: sc.checkoutUrl,
|
|
5030
|
+
message: sc.message
|
|
5031
|
+
};
|
|
5032
|
+
if (sc.kind === "activation_required") {
|
|
5033
|
+
base.kind = "activation_required";
|
|
5034
|
+
if (sc.plans !== void 0) base.plans = sc.plans;
|
|
5035
|
+
if (sc.balance !== void 0) base.balance = sc.balance;
|
|
5036
|
+
if (sc.productDetails !== void 0) base.productDetails = sc.productDetails;
|
|
5037
|
+
if (sc.confirmationUrl !== void 0) base.confirmationUrl = sc.confirmationUrl;
|
|
5038
|
+
}
|
|
5039
|
+
return base;
|
|
5040
|
+
}
|
|
4919
5041
|
var sharedCustomerLookupDeduplicator = createRequestDeduplicator({
|
|
4920
5042
|
cacheTTL: 6e4,
|
|
4921
5043
|
// Cache results for 60 seconds (reduces API calls significantly)
|
|
@@ -4954,8 +5076,6 @@ var SolvaPayPaywall = class {
|
|
|
4954
5076
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4955
5077
|
async protect(handler, metadata = {}, getCustomerRef) {
|
|
4956
5078
|
const product = this.resolveProduct(metadata);
|
|
4957
|
-
const configuredPlanRef = metadata.plan?.trim();
|
|
4958
|
-
const usagePlanRef = configuredPlanRef || "unspecified";
|
|
4959
5079
|
const usageType = metadata.usageType || "requests";
|
|
4960
5080
|
return async (args) => {
|
|
4961
5081
|
const startTime = Date.now();
|
|
@@ -4969,12 +5089,13 @@ var SolvaPayPaywall = class {
|
|
|
4969
5089
|
}
|
|
4970
5090
|
let resolvedMeterName;
|
|
4971
5091
|
try {
|
|
4972
|
-
const limitsCacheKey = `${backendCustomerRef}:${product}:${
|
|
5092
|
+
const limitsCacheKey = `${backendCustomerRef}:${product}:${usageType}`;
|
|
4973
5093
|
const cachedLimits = this.limitsCache.get(limitsCacheKey);
|
|
4974
5094
|
const now = Date.now();
|
|
4975
5095
|
let withinLimits;
|
|
4976
5096
|
let remaining;
|
|
4977
5097
|
let checkoutUrl;
|
|
5098
|
+
let lastLimitsCheck;
|
|
4978
5099
|
const hasFreshCachedLimits = cachedLimits && now - cachedLimits.timestamp < this.limitsCacheTTL;
|
|
4979
5100
|
if (hasFreshCachedLimits) {
|
|
4980
5101
|
checkoutUrl = cachedLimits.checkoutUrl;
|
|
@@ -4998,9 +5119,9 @@ var SolvaPayPaywall = class {
|
|
|
4998
5119
|
const limitsCheck = await this.apiClient.checkLimits({
|
|
4999
5120
|
customerRef: backendCustomerRef,
|
|
5000
5121
|
productRef: product,
|
|
5001
|
-
...configuredPlanRef ? { planRef: configuredPlanRef } : {},
|
|
5002
5122
|
meterName: usageType
|
|
5003
5123
|
});
|
|
5124
|
+
lastLimitsCheck = limitsCheck;
|
|
5004
5125
|
withinLimits = limitsCheck.withinLimits;
|
|
5005
5126
|
remaining = limitsCheck.remaining;
|
|
5006
5127
|
checkoutUrl = limitsCheck.checkoutUrl;
|
|
@@ -5023,12 +5144,25 @@ var SolvaPayPaywall = class {
|
|
|
5023
5144
|
this.trackUsage(
|
|
5024
5145
|
backendCustomerRef,
|
|
5025
5146
|
product,
|
|
5026
|
-
usagePlanRef,
|
|
5027
5147
|
resolvedMeterName || usageType,
|
|
5028
5148
|
"paywall",
|
|
5029
5149
|
requestId,
|
|
5030
5150
|
latencyMs2
|
|
5031
5151
|
);
|
|
5152
|
+
if (lastLimitsCheck?.activationRequired) {
|
|
5153
|
+
const confirmationUrl = lastLimitsCheck.confirmationUrl;
|
|
5154
|
+
const payCheckoutUrl = confirmationUrl || lastLimitsCheck.checkoutUrl || checkoutUrl || "";
|
|
5155
|
+
throw new PaywallError("Activation required", {
|
|
5156
|
+
kind: "activation_required",
|
|
5157
|
+
product,
|
|
5158
|
+
message: "Product activation is required before this tool can be used.",
|
|
5159
|
+
checkoutUrl: payCheckoutUrl,
|
|
5160
|
+
confirmationUrl,
|
|
5161
|
+
plans: lastLimitsCheck.plans,
|
|
5162
|
+
balance: lastLimitsCheck.balance,
|
|
5163
|
+
productDetails: lastLimitsCheck.product
|
|
5164
|
+
});
|
|
5165
|
+
}
|
|
5032
5166
|
throw new PaywallError("Payment required", {
|
|
5033
5167
|
kind: "payment_required",
|
|
5034
5168
|
product,
|
|
@@ -5041,7 +5175,6 @@ var SolvaPayPaywall = class {
|
|
|
5041
5175
|
this.trackUsage(
|
|
5042
5176
|
backendCustomerRef,
|
|
5043
5177
|
product,
|
|
5044
|
-
usagePlanRef,
|
|
5045
5178
|
resolvedMeterName || usageType,
|
|
5046
5179
|
"success",
|
|
5047
5180
|
requestId,
|
|
@@ -5060,7 +5193,6 @@ var SolvaPayPaywall = class {
|
|
|
5060
5193
|
this.trackUsage(
|
|
5061
5194
|
backendCustomerRef,
|
|
5062
5195
|
product,
|
|
5063
|
-
usagePlanRef,
|
|
5064
5196
|
resolvedMeterName || usageType,
|
|
5065
5197
|
"fail",
|
|
5066
5198
|
requestId,
|
|
@@ -5131,7 +5263,8 @@ var SolvaPayPaywall = class {
|
|
|
5131
5263
|
this.customerCreationAttempts.add(customerRef);
|
|
5132
5264
|
try {
|
|
5133
5265
|
const createParams = {
|
|
5134
|
-
email: options?.email || `${customerRef}-${Date.now()}@auto-created.local
|
|
5266
|
+
email: options?.email || `${customerRef}-${Date.now()}@auto-created.local`,
|
|
5267
|
+
metadata: {}
|
|
5135
5268
|
};
|
|
5136
5269
|
if (options?.name) {
|
|
5137
5270
|
createParams.name = options.name;
|
|
@@ -5155,7 +5288,10 @@ var SolvaPayPaywall = class {
|
|
|
5155
5288
|
return searchResult.customerRef;
|
|
5156
5289
|
}
|
|
5157
5290
|
} catch (lookupError) {
|
|
5158
|
-
this.log(
|
|
5291
|
+
this.log(
|
|
5292
|
+
`\u26A0\uFE0F Failed to lookup existing customer by externalRef after 409:`,
|
|
5293
|
+
lookupError instanceof Error ? lookupError.message : lookupError
|
|
5294
|
+
);
|
|
5159
5295
|
}
|
|
5160
5296
|
}
|
|
5161
5297
|
const isEmailConflict = errorMessage.includes("email") || errorMessage.includes("identifier email");
|
|
@@ -5178,7 +5314,8 @@ var SolvaPayPaywall = class {
|
|
|
5178
5314
|
try {
|
|
5179
5315
|
const retryParams = {
|
|
5180
5316
|
email: `${customerRef}-${Date.now()}@auto-created.local`,
|
|
5181
|
-
externalRef
|
|
5317
|
+
externalRef,
|
|
5318
|
+
metadata: {}
|
|
5182
5319
|
};
|
|
5183
5320
|
if (options?.name) {
|
|
5184
5321
|
retryParams.name = options.name;
|
|
@@ -5215,14 +5352,14 @@ var SolvaPayPaywall = class {
|
|
|
5215
5352
|
}
|
|
5216
5353
|
return backendRef;
|
|
5217
5354
|
}
|
|
5218
|
-
async trackUsage(customerRef,
|
|
5355
|
+
async trackUsage(customerRef, productRef, action, outcome, requestId, actionDuration) {
|
|
5219
5356
|
await withRetry(
|
|
5220
5357
|
() => this.apiClient.trackUsage({
|
|
5221
5358
|
customerRef,
|
|
5222
5359
|
actionType: "api_call",
|
|
5223
5360
|
units: 1,
|
|
5224
5361
|
outcome,
|
|
5225
|
-
|
|
5362
|
+
productRef,
|
|
5226
5363
|
duration: actionDuration,
|
|
5227
5364
|
metadata: { action: action || "api_requests", requestId },
|
|
5228
5365
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -5474,8 +5611,10 @@ var McpAdapter = class {
|
|
|
5474
5611
|
const ref = await this.options.getCustomerRef(args, extra);
|
|
5475
5612
|
return AdapterUtils.ensureCustomerRef(ref);
|
|
5476
5613
|
}
|
|
5477
|
-
const customerRefFromExtra = extra?.authInfo?.extra?.customer_ref;
|
|
5478
|
-
const
|
|
5614
|
+
const customerRefFromExtra = typeof extra?.authInfo?.extra?.customer_ref === "string" ? String(extra.authInfo.extra.customer_ref) : void 0;
|
|
5615
|
+
const customerRefFromArgs = typeof args.auth === "object" && args.auth !== null && typeof args.auth.customer_ref === "string" ? String(args.auth.customer_ref) : void 0;
|
|
5616
|
+
const directCustomerRef = typeof args.customer_ref === "string" ? args.customer_ref : void 0;
|
|
5617
|
+
const customerRef = (customerRefFromExtra || customerRefFromArgs || directCustomerRef || "anonymous").trim();
|
|
5479
5618
|
return AdapterUtils.ensureCustomerRef(customerRef);
|
|
5480
5619
|
}
|
|
5481
5620
|
formatResponse(result, _context) {
|
|
@@ -5499,17 +5638,7 @@ var McpAdapter = class {
|
|
|
5499
5638
|
content: [
|
|
5500
5639
|
{
|
|
5501
5640
|
type: "text",
|
|
5502
|
-
text: JSON.stringify(
|
|
5503
|
-
{
|
|
5504
|
-
success: false,
|
|
5505
|
-
error: "Payment required",
|
|
5506
|
-
product: error.structuredContent.product,
|
|
5507
|
-
checkoutUrl: error.structuredContent.checkoutUrl,
|
|
5508
|
-
message: error.structuredContent.message
|
|
5509
|
-
},
|
|
5510
|
-
null,
|
|
5511
|
-
2
|
|
5512
|
-
)
|
|
5641
|
+
text: JSON.stringify(paywallErrorToClientPayload(error), null, 2)
|
|
5513
5642
|
}
|
|
5514
5643
|
],
|
|
5515
5644
|
isError: true,
|
|
@@ -5796,6 +5925,12 @@ function createSolvaPay(config) {
|
|
|
5796
5925
|
}
|
|
5797
5926
|
return apiClient.createPaymentIntent(params);
|
|
5798
5927
|
},
|
|
5928
|
+
createTopupPaymentIntent(params) {
|
|
5929
|
+
if (!apiClient.createTopupPaymentIntent) {
|
|
5930
|
+
throw new import_core2.SolvaPayError("createTopupPaymentIntent is not available on this API client");
|
|
5931
|
+
}
|
|
5932
|
+
return apiClient.createTopupPaymentIntent(params);
|
|
5933
|
+
},
|
|
5799
5934
|
processPaymentIntent(params) {
|
|
5800
5935
|
if (!apiClient.processPaymentIntent) {
|
|
5801
5936
|
throw new import_core2.SolvaPayError("processPaymentIntent is not available on this API client");
|
|
@@ -5812,11 +5947,17 @@ function createSolvaPay(config) {
|
|
|
5812
5947
|
if (!apiClient.createCustomer) {
|
|
5813
5948
|
throw new import_core2.SolvaPayError("createCustomer is not available on this API client");
|
|
5814
5949
|
}
|
|
5815
|
-
return apiClient.createCustomer(params);
|
|
5950
|
+
return apiClient.createCustomer({ ...params, metadata: params.metadata ?? {} });
|
|
5816
5951
|
},
|
|
5817
5952
|
getCustomer(params) {
|
|
5818
5953
|
return apiClient.getCustomer(params);
|
|
5819
5954
|
},
|
|
5955
|
+
getCustomerBalance(params) {
|
|
5956
|
+
if (!apiClient.getCustomerBalance) {
|
|
5957
|
+
throw new import_core2.SolvaPayError("getCustomerBalance is not available on this API client");
|
|
5958
|
+
}
|
|
5959
|
+
return apiClient.getCustomerBalance(params);
|
|
5960
|
+
},
|
|
5820
5961
|
createCheckoutSession(params) {
|
|
5821
5962
|
return apiClient.createCheckoutSession({
|
|
5822
5963
|
customerRef: params.customerRef,
|
|
@@ -5827,6 +5968,12 @@ function createSolvaPay(config) {
|
|
|
5827
5968
|
createCustomerSession(params) {
|
|
5828
5969
|
return apiClient.createCustomerSession(params);
|
|
5829
5970
|
},
|
|
5971
|
+
activatePlan(params) {
|
|
5972
|
+
if (!apiClient.activatePlan) {
|
|
5973
|
+
throw new import_core2.SolvaPayError("activatePlan is not available on this API client");
|
|
5974
|
+
}
|
|
5975
|
+
return apiClient.activatePlan(params);
|
|
5976
|
+
},
|
|
5830
5977
|
bootstrapMcpProduct(params) {
|
|
5831
5978
|
if (!apiClient.bootstrapMcpProduct) {
|
|
5832
5979
|
throw new import_core2.SolvaPayError("bootstrapMcpProduct is not available on this API client");
|
|
@@ -5848,9 +5995,8 @@ function createSolvaPay(config) {
|
|
|
5848
5995
|
// Payable API for framework-specific handlers
|
|
5849
5996
|
payable(options = {}) {
|
|
5850
5997
|
const product = options.productRef || options.product || process.env.SOLVAPAY_PRODUCT || "default-product";
|
|
5851
|
-
const plan = options.planRef || options.plan;
|
|
5852
5998
|
const usageType = options.usageType || "requests";
|
|
5853
|
-
const metadata = { product,
|
|
5999
|
+
const metadata = { product, usageType };
|
|
5854
6000
|
return {
|
|
5855
6001
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5856
6002
|
http(businessLogic, adapterOptions) {
|
|
@@ -6188,6 +6334,24 @@ async function syncCustomerCore(request, options = {}) {
|
|
|
6188
6334
|
return handleRouteError(error, "Sync customer", "Failed to sync customer");
|
|
6189
6335
|
}
|
|
6190
6336
|
}
|
|
6337
|
+
async function getCustomerBalanceCore(request, options = {}) {
|
|
6338
|
+
try {
|
|
6339
|
+
const userResult = await getAuthenticatedUserCore(request);
|
|
6340
|
+
if (isErrorResult(userResult)) {
|
|
6341
|
+
return userResult;
|
|
6342
|
+
}
|
|
6343
|
+
const { userId, email, name } = userResult;
|
|
6344
|
+
const solvaPay = options.solvaPay || createSolvaPay();
|
|
6345
|
+
const customerRef = await solvaPay.ensureCustomer(userId, userId, {
|
|
6346
|
+
email: email || void 0,
|
|
6347
|
+
name: name || void 0
|
|
6348
|
+
});
|
|
6349
|
+
const result = await solvaPay.getCustomerBalance({ customerRef });
|
|
6350
|
+
return result;
|
|
6351
|
+
} catch (error) {
|
|
6352
|
+
return handleRouteError(error, "Get customer credits", "Failed to get customer credits");
|
|
6353
|
+
}
|
|
6354
|
+
}
|
|
6191
6355
|
|
|
6192
6356
|
// src/helpers/payment.ts
|
|
6193
6357
|
async function createPaymentIntentCore(request, body, options = {}) {
|
|
@@ -6214,7 +6378,7 @@ async function createPaymentIntentCore(request, body, options = {}) {
|
|
|
6214
6378
|
customerRef
|
|
6215
6379
|
});
|
|
6216
6380
|
return {
|
|
6217
|
-
|
|
6381
|
+
processorPaymentId: paymentIntent.processorPaymentId,
|
|
6218
6382
|
clientSecret: paymentIntent.clientSecret,
|
|
6219
6383
|
publishableKey: paymentIntent.publishableKey,
|
|
6220
6384
|
accountId: paymentIntent.accountId,
|
|
@@ -6224,6 +6388,57 @@ async function createPaymentIntentCore(request, body, options = {}) {
|
|
|
6224
6388
|
return handleRouteError(error, "Create payment intent", "Payment intent creation failed");
|
|
6225
6389
|
}
|
|
6226
6390
|
}
|
|
6391
|
+
async function createTopupPaymentIntentCore(request, body, options = {}) {
|
|
6392
|
+
try {
|
|
6393
|
+
if (!body.amount || body.amount <= 0) {
|
|
6394
|
+
return {
|
|
6395
|
+
error: "Missing or invalid amount: must be a positive number",
|
|
6396
|
+
status: 400
|
|
6397
|
+
};
|
|
6398
|
+
}
|
|
6399
|
+
if (!body.currency) {
|
|
6400
|
+
return {
|
|
6401
|
+
error: "Missing required parameter: currency",
|
|
6402
|
+
status: 400
|
|
6403
|
+
};
|
|
6404
|
+
}
|
|
6405
|
+
if (body.currency !== body.currency.toUpperCase()) {
|
|
6406
|
+
return {
|
|
6407
|
+
error: `Invalid currency "${body.currency}": must be an uppercase ISO 4217 code (e.g. "USD", "EUR")`,
|
|
6408
|
+
status: 400
|
|
6409
|
+
};
|
|
6410
|
+
}
|
|
6411
|
+
const customerResult = await syncCustomerCore(request, {
|
|
6412
|
+
solvaPay: options.solvaPay,
|
|
6413
|
+
includeEmail: options.includeEmail,
|
|
6414
|
+
includeName: options.includeName
|
|
6415
|
+
});
|
|
6416
|
+
if (isErrorResult(customerResult)) {
|
|
6417
|
+
return customerResult;
|
|
6418
|
+
}
|
|
6419
|
+
const customerRef = customerResult;
|
|
6420
|
+
const solvaPay = options.solvaPay || createSolvaPay();
|
|
6421
|
+
const paymentIntent = await solvaPay.createTopupPaymentIntent({
|
|
6422
|
+
customerRef,
|
|
6423
|
+
amount: body.amount,
|
|
6424
|
+
currency: body.currency,
|
|
6425
|
+
description: body.description
|
|
6426
|
+
});
|
|
6427
|
+
return {
|
|
6428
|
+
processorPaymentId: paymentIntent.processorPaymentId,
|
|
6429
|
+
clientSecret: paymentIntent.clientSecret,
|
|
6430
|
+
publishableKey: paymentIntent.publishableKey,
|
|
6431
|
+
accountId: paymentIntent.accountId,
|
|
6432
|
+
customerRef
|
|
6433
|
+
};
|
|
6434
|
+
} catch (error) {
|
|
6435
|
+
return handleRouteError(
|
|
6436
|
+
error,
|
|
6437
|
+
"Create topup payment intent",
|
|
6438
|
+
"Topup payment intent creation failed"
|
|
6439
|
+
);
|
|
6440
|
+
}
|
|
6441
|
+
}
|
|
6227
6442
|
async function processPaymentIntentCore(request, body, options = {}) {
|
|
6228
6443
|
try {
|
|
6229
6444
|
if (!body.paymentIntentId || !body.productRef) {
|
|
@@ -6386,6 +6601,103 @@ async function cancelPurchaseCore(request, body, options = {}) {
|
|
|
6386
6601
|
return handleRouteError(error, "Cancel purchase", "Failed to cancel purchase");
|
|
6387
6602
|
}
|
|
6388
6603
|
}
|
|
6604
|
+
async function reactivatePurchaseCore(request, body, options = {}) {
|
|
6605
|
+
try {
|
|
6606
|
+
if (!body.purchaseRef) {
|
|
6607
|
+
return {
|
|
6608
|
+
error: "Missing required parameter: purchaseRef is required",
|
|
6609
|
+
status: 400
|
|
6610
|
+
};
|
|
6611
|
+
}
|
|
6612
|
+
const solvaPay = options.solvaPay || createSolvaPay();
|
|
6613
|
+
if (!solvaPay.apiClient.reactivatePurchase) {
|
|
6614
|
+
return {
|
|
6615
|
+
error: "Reactivate purchase method not available on SDK client",
|
|
6616
|
+
status: 500
|
|
6617
|
+
};
|
|
6618
|
+
}
|
|
6619
|
+
let reactivatedPurchase = await solvaPay.apiClient.reactivatePurchase({
|
|
6620
|
+
purchaseRef: body.purchaseRef
|
|
6621
|
+
});
|
|
6622
|
+
if (!reactivatedPurchase || typeof reactivatedPurchase !== "object") {
|
|
6623
|
+
return {
|
|
6624
|
+
error: "Invalid response from reactivate purchase endpoint",
|
|
6625
|
+
status: 500
|
|
6626
|
+
};
|
|
6627
|
+
}
|
|
6628
|
+
const responseObj = reactivatedPurchase;
|
|
6629
|
+
if (responseObj.purchase && typeof responseObj.purchase === "object") {
|
|
6630
|
+
reactivatedPurchase = responseObj.purchase;
|
|
6631
|
+
}
|
|
6632
|
+
if (!reactivatedPurchase.reference) {
|
|
6633
|
+
return {
|
|
6634
|
+
error: "Reactivate purchase response missing required fields",
|
|
6635
|
+
status: 500
|
|
6636
|
+
};
|
|
6637
|
+
}
|
|
6638
|
+
if (reactivatedPurchase.cancelledAt) {
|
|
6639
|
+
return {
|
|
6640
|
+
error: `Purchase reactivation failed: cancelledAt is still set`,
|
|
6641
|
+
status: 500
|
|
6642
|
+
};
|
|
6643
|
+
}
|
|
6644
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
6645
|
+
return reactivatedPurchase;
|
|
6646
|
+
} catch (error) {
|
|
6647
|
+
if (error instanceof import_core4.SolvaPayError) {
|
|
6648
|
+
const errorMessage = error.message;
|
|
6649
|
+
if (errorMessage.includes("not found")) {
|
|
6650
|
+
return {
|
|
6651
|
+
error: "Purchase not found",
|
|
6652
|
+
status: 404,
|
|
6653
|
+
details: errorMessage
|
|
6654
|
+
};
|
|
6655
|
+
}
|
|
6656
|
+
if (errorMessage.includes("cannot be reactivated") || errorMessage.includes("not pending cancellation") || errorMessage.includes("already been fully cancelled") || errorMessage.includes("already ended")) {
|
|
6657
|
+
return {
|
|
6658
|
+
error: "Purchase cannot be reactivated",
|
|
6659
|
+
status: 400,
|
|
6660
|
+
details: errorMessage
|
|
6661
|
+
};
|
|
6662
|
+
}
|
|
6663
|
+
return {
|
|
6664
|
+
error: errorMessage,
|
|
6665
|
+
status: 500,
|
|
6666
|
+
details: errorMessage
|
|
6667
|
+
};
|
|
6668
|
+
}
|
|
6669
|
+
return handleRouteError(error, "Reactivate purchase", "Failed to reactivate purchase");
|
|
6670
|
+
}
|
|
6671
|
+
}
|
|
6672
|
+
|
|
6673
|
+
// src/helpers/activation.ts
|
|
6674
|
+
async function activatePlanCore(request, body, options = {}) {
|
|
6675
|
+
try {
|
|
6676
|
+
if (!body.productRef || !body.planRef) {
|
|
6677
|
+
return {
|
|
6678
|
+
error: "Missing required parameters: productRef and planRef are required",
|
|
6679
|
+
status: 400
|
|
6680
|
+
};
|
|
6681
|
+
}
|
|
6682
|
+
const customerResult = await syncCustomerCore(request, {
|
|
6683
|
+
solvaPay: options.solvaPay,
|
|
6684
|
+
includeEmail: options.includeEmail,
|
|
6685
|
+
includeName: options.includeName
|
|
6686
|
+
});
|
|
6687
|
+
if (isErrorResult(customerResult)) {
|
|
6688
|
+
return customerResult;
|
|
6689
|
+
}
|
|
6690
|
+
const customerRef = customerResult;
|
|
6691
|
+
const solvaPay = options.solvaPay || createSolvaPay();
|
|
6692
|
+
return await solvaPay.activatePlan({
|
|
6693
|
+
customerRef,
|
|
6694
|
+
productRef: body.productRef,
|
|
6695
|
+
planRef: body.planRef
|
|
6696
|
+
});
|
|
6697
|
+
} catch (error) {
|
|
6698
|
+
return handleRouteError(error, "Activate plan", "Plan activation failed");
|
|
6699
|
+
}
|
|
6700
|
+
}
|
|
6389
6701
|
|
|
6390
6702
|
// src/helpers/plans.ts
|
|
6391
6703
|
var import_core5 = require("@solvapay/core");
|
|
@@ -6470,6 +6782,7 @@ function verifyWebhook({
|
|
|
6470
6782
|
McpBearerAuthError,
|
|
6471
6783
|
PaywallError,
|
|
6472
6784
|
VIRTUAL_TOOL_DEFINITIONS,
|
|
6785
|
+
activatePlanCore,
|
|
6473
6786
|
buildAuthInfoFromBearer,
|
|
6474
6787
|
cancelPurchaseCore,
|
|
6475
6788
|
createCheckoutSessionCore,
|
|
@@ -6478,10 +6791,12 @@ function verifyWebhook({
|
|
|
6478
6791
|
createPaymentIntentCore,
|
|
6479
6792
|
createSolvaPay,
|
|
6480
6793
|
createSolvaPayClient,
|
|
6794
|
+
createTopupPaymentIntentCore,
|
|
6481
6795
|
createVirtualTools,
|
|
6482
6796
|
decodeJwtPayload,
|
|
6483
6797
|
extractBearerToken,
|
|
6484
6798
|
getAuthenticatedUserCore,
|
|
6799
|
+
getCustomerBalanceCore,
|
|
6485
6800
|
getCustomerRefFromBearerAuthHeader,
|
|
6486
6801
|
getCustomerRefFromJwtPayload,
|
|
6487
6802
|
getOAuthAuthorizationServerResponse,
|
|
@@ -6490,7 +6805,9 @@ function verifyWebhook({
|
|
|
6490
6805
|
isErrorResult,
|
|
6491
6806
|
jsonSchemaToZodRawShape,
|
|
6492
6807
|
listPlansCore,
|
|
6808
|
+
paywallErrorToClientPayload,
|
|
6493
6809
|
processPaymentIntentCore,
|
|
6810
|
+
reactivatePurchaseCore,
|
|
6494
6811
|
registerVirtualToolsMcpImpl,
|
|
6495
6812
|
syncCustomerCore,
|
|
6496
6813
|
verifyWebhook,
|