@solvapay/server 1.0.0-preview.20 → 1.0.0-preview.21
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 +32 -6
- package/dist/edge.d.ts +1584 -310
- package/dist/edge.js +329 -50
- package/dist/index.cjs +395 -50
- package/dist/index.d.cts +1611 -310
- package/dist/index.d.ts +1611 -310
- package/dist/index.js +388 -50
- package/package.json +7 -6
package/dist/edge.js
CHANGED
|
@@ -38,10 +38,12 @@ function createSolvaPayClient(opts) {
|
|
|
38
38
|
// POST: /v1/sdk/usages
|
|
39
39
|
async trackUsage(params) {
|
|
40
40
|
const url = `${base}/v1/sdk/usages`;
|
|
41
|
+
const { customerRef, ...rest } = params;
|
|
42
|
+
const body = { ...rest, customerId: customerRef };
|
|
41
43
|
const res = await fetch(url, {
|
|
42
44
|
method: "POST",
|
|
43
45
|
headers,
|
|
44
|
-
body: JSON.stringify(
|
|
46
|
+
body: JSON.stringify(body)
|
|
45
47
|
});
|
|
46
48
|
if (!res.ok) {
|
|
47
49
|
const error = await res.text();
|
|
@@ -145,6 +147,21 @@ function createSolvaPayClient(opts) {
|
|
|
145
147
|
const result = await res.json();
|
|
146
148
|
return result;
|
|
147
149
|
},
|
|
150
|
+
// POST: /v1/sdk/products/mcp/bootstrap
|
|
151
|
+
async bootstrapMcpProduct(params) {
|
|
152
|
+
const url = `${base}/v1/sdk/products/mcp/bootstrap`;
|
|
153
|
+
const res = await fetch(url, {
|
|
154
|
+
method: "POST",
|
|
155
|
+
headers,
|
|
156
|
+
body: JSON.stringify(params)
|
|
157
|
+
});
|
|
158
|
+
if (!res.ok) {
|
|
159
|
+
const error = await res.text();
|
|
160
|
+
log(`\u274C API Error: ${res.status} - ${error}`);
|
|
161
|
+
throw new SolvaPayError(`Bootstrap MCP product failed (${res.status}): ${error}`);
|
|
162
|
+
}
|
|
163
|
+
return await res.json();
|
|
164
|
+
},
|
|
148
165
|
// DELETE: /v1/sdk/products/{productRef}
|
|
149
166
|
async deleteProduct(productRef) {
|
|
150
167
|
const url = `${base}/v1/sdk/products/${productRef}`;
|
|
@@ -158,6 +175,21 @@ function createSolvaPayClient(opts) {
|
|
|
158
175
|
throw new SolvaPayError(`Delete product failed (${res.status}): ${error}`);
|
|
159
176
|
}
|
|
160
177
|
},
|
|
178
|
+
// POST: /v1/sdk/products/{productRef}/clone
|
|
179
|
+
async cloneProduct(productRef, overrides) {
|
|
180
|
+
const url = `${base}/v1/sdk/products/${productRef}/clone`;
|
|
181
|
+
const res = await fetch(url, {
|
|
182
|
+
method: "POST",
|
|
183
|
+
headers,
|
|
184
|
+
body: JSON.stringify(overrides || {})
|
|
185
|
+
});
|
|
186
|
+
if (!res.ok) {
|
|
187
|
+
const error = await res.text();
|
|
188
|
+
log(`\u274C API Error: ${res.status} - ${error}`);
|
|
189
|
+
throw new SolvaPayError(`Clone product failed (${res.status}): ${error}`);
|
|
190
|
+
}
|
|
191
|
+
return await res.json();
|
|
192
|
+
},
|
|
161
193
|
// GET: /v1/sdk/products/{productRef}/plans
|
|
162
194
|
async listPlans(productRef) {
|
|
163
195
|
const url = `${base}/v1/sdk/products/${productRef}/plans`;
|
|
@@ -200,6 +232,21 @@ function createSolvaPayClient(opts) {
|
|
|
200
232
|
const result = await res.json();
|
|
201
233
|
return result;
|
|
202
234
|
},
|
|
235
|
+
// PUT: /v1/sdk/products/{productRef}/plans/{planRef}
|
|
236
|
+
async updatePlan(productRef, planRef, params) {
|
|
237
|
+
const url = `${base}/v1/sdk/products/${productRef}/plans/${planRef}`;
|
|
238
|
+
const res = await fetch(url, {
|
|
239
|
+
method: "PUT",
|
|
240
|
+
headers,
|
|
241
|
+
body: JSON.stringify(params)
|
|
242
|
+
});
|
|
243
|
+
if (!res.ok) {
|
|
244
|
+
const error = await res.text();
|
|
245
|
+
log(`\u274C API Error: ${res.status} - ${error}`);
|
|
246
|
+
throw new SolvaPayError(`Update plan failed (${res.status}): ${error}`);
|
|
247
|
+
}
|
|
248
|
+
return await res.json();
|
|
249
|
+
},
|
|
203
250
|
// DELETE: /v1/sdk/products/{productRef}/plans/{planRef}
|
|
204
251
|
async deletePlan(productRef, planRef) {
|
|
205
252
|
const url = `${base}/v1/sdk/products/${productRef}/plans/${planRef}`;
|
|
@@ -312,6 +359,21 @@ function createSolvaPayClient(opts) {
|
|
|
312
359
|
}
|
|
313
360
|
return result;
|
|
314
361
|
},
|
|
362
|
+
// POST: /v1/sdk/user-info
|
|
363
|
+
async getUserInfo(params) {
|
|
364
|
+
const url = `${base}/v1/sdk/user-info`;
|
|
365
|
+
const res = await fetch(url, {
|
|
366
|
+
method: "POST",
|
|
367
|
+
headers,
|
|
368
|
+
body: JSON.stringify(params)
|
|
369
|
+
});
|
|
370
|
+
if (!res.ok) {
|
|
371
|
+
const error = await res.text();
|
|
372
|
+
log(`\u274C API Error: ${res.status} - ${error}`);
|
|
373
|
+
throw new SolvaPayError(`Get user info failed (${res.status}): ${error}`);
|
|
374
|
+
}
|
|
375
|
+
return await res.json();
|
|
376
|
+
},
|
|
315
377
|
// POST: /v1/sdk/checkout-sessions
|
|
316
378
|
async createCheckoutSession(params) {
|
|
317
379
|
const url = `${base}/v1/sdk/checkout-sessions`;
|
|
@@ -510,11 +572,13 @@ var SolvaPayPaywall = class {
|
|
|
510
572
|
constructor(apiClient, options = {}) {
|
|
511
573
|
this.apiClient = apiClient;
|
|
512
574
|
this.debug = options.debug ?? process.env.SOLVAPAY_DEBUG === "true";
|
|
575
|
+
this.limitsCacheTTL = options.limitsCacheTTL ?? 1e4;
|
|
513
576
|
}
|
|
514
577
|
customerCreationAttempts = /* @__PURE__ */ new Set();
|
|
515
578
|
customerRefMapping = /* @__PURE__ */ new Map();
|
|
516
|
-
// input ref -> backend ref
|
|
517
579
|
debug;
|
|
580
|
+
limitsCache = /* @__PURE__ */ new Map();
|
|
581
|
+
limitsCacheTTL;
|
|
518
582
|
log(...args) {
|
|
519
583
|
if (this.debug) {
|
|
520
584
|
console.log(...args);
|
|
@@ -534,7 +598,9 @@ var SolvaPayPaywall = class {
|
|
|
534
598
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
535
599
|
async protect(handler, metadata = {}, getCustomerRef) {
|
|
536
600
|
const product = this.resolveProduct(metadata);
|
|
537
|
-
const
|
|
601
|
+
const configuredPlanRef = metadata.plan?.trim();
|
|
602
|
+
const usagePlanRef = configuredPlanRef || "unspecified";
|
|
603
|
+
const usageType = metadata.usageType || "requests";
|
|
538
604
|
return async (args) => {
|
|
539
605
|
const startTime = Date.now();
|
|
540
606
|
const requestId = this.generateRequestId();
|
|
@@ -545,19 +611,64 @@ var SolvaPayPaywall = class {
|
|
|
545
611
|
} else {
|
|
546
612
|
backendCustomerRef = await this.ensureCustomer(inputCustomerRef, inputCustomerRef);
|
|
547
613
|
}
|
|
614
|
+
let resolvedMeterName;
|
|
548
615
|
try {
|
|
549
|
-
const
|
|
550
|
-
const
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
616
|
+
const limitsCacheKey = `${backendCustomerRef}:${product}:${configuredPlanRef || ""}:${usageType}`;
|
|
617
|
+
const cachedLimits = this.limitsCache.get(limitsCacheKey);
|
|
618
|
+
const now = Date.now();
|
|
619
|
+
let withinLimits;
|
|
620
|
+
let remaining;
|
|
621
|
+
let checkoutUrl;
|
|
622
|
+
const hasFreshCachedLimits = cachedLimits && now - cachedLimits.timestamp < this.limitsCacheTTL;
|
|
623
|
+
if (hasFreshCachedLimits) {
|
|
624
|
+
checkoutUrl = cachedLimits.checkoutUrl;
|
|
625
|
+
resolvedMeterName = cachedLimits.meterName;
|
|
626
|
+
if (cachedLimits.remaining > 0) {
|
|
627
|
+
cachedLimits.remaining--;
|
|
628
|
+
if (cachedLimits.remaining <= 0) {
|
|
629
|
+
this.limitsCache.delete(limitsCacheKey);
|
|
630
|
+
}
|
|
631
|
+
withinLimits = true;
|
|
632
|
+
remaining = cachedLimits.remaining;
|
|
633
|
+
} else {
|
|
634
|
+
withinLimits = false;
|
|
635
|
+
remaining = 0;
|
|
636
|
+
this.limitsCache.delete(limitsCacheKey);
|
|
637
|
+
}
|
|
638
|
+
} else {
|
|
639
|
+
if (cachedLimits) {
|
|
640
|
+
this.limitsCache.delete(limitsCacheKey);
|
|
641
|
+
}
|
|
642
|
+
const limitsCheck = await this.apiClient.checkLimits({
|
|
643
|
+
customerRef: backendCustomerRef,
|
|
644
|
+
productRef: product,
|
|
645
|
+
...configuredPlanRef ? { planRef: configuredPlanRef } : {},
|
|
646
|
+
meterName: usageType
|
|
647
|
+
});
|
|
648
|
+
withinLimits = limitsCheck.withinLimits;
|
|
649
|
+
remaining = limitsCheck.remaining;
|
|
650
|
+
checkoutUrl = limitsCheck.checkoutUrl;
|
|
651
|
+
resolvedMeterName = limitsCheck.meterName;
|
|
652
|
+
const consumedAllowance = withinLimits && remaining > 0;
|
|
653
|
+
if (consumedAllowance) {
|
|
654
|
+
remaining = Math.max(0, remaining - 1);
|
|
655
|
+
}
|
|
656
|
+
if (consumedAllowance) {
|
|
657
|
+
this.limitsCache.set(limitsCacheKey, {
|
|
658
|
+
remaining,
|
|
659
|
+
checkoutUrl,
|
|
660
|
+
meterName: resolvedMeterName,
|
|
661
|
+
timestamp: now
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
if (!withinLimits) {
|
|
555
666
|
const latencyMs2 = Date.now() - startTime;
|
|
556
|
-
|
|
667
|
+
this.trackUsage(
|
|
557
668
|
backendCustomerRef,
|
|
558
669
|
product,
|
|
559
|
-
|
|
560
|
-
|
|
670
|
+
usagePlanRef,
|
|
671
|
+
resolvedMeterName || usageType,
|
|
561
672
|
"paywall",
|
|
562
673
|
requestId,
|
|
563
674
|
latencyMs2
|
|
@@ -565,17 +676,17 @@ var SolvaPayPaywall = class {
|
|
|
565
676
|
throw new PaywallError("Payment required", {
|
|
566
677
|
kind: "payment_required",
|
|
567
678
|
product,
|
|
568
|
-
checkoutUrl:
|
|
569
|
-
message: `
|
|
679
|
+
checkoutUrl: checkoutUrl || "",
|
|
680
|
+
message: `Purchase required. Remaining: ${remaining}`
|
|
570
681
|
});
|
|
571
682
|
}
|
|
572
683
|
const result = await handler(args);
|
|
573
684
|
const latencyMs = Date.now() - startTime;
|
|
574
|
-
|
|
685
|
+
this.trackUsage(
|
|
575
686
|
backendCustomerRef,
|
|
576
687
|
product,
|
|
577
|
-
|
|
578
|
-
|
|
688
|
+
usagePlanRef,
|
|
689
|
+
resolvedMeterName || usageType,
|
|
579
690
|
"success",
|
|
580
691
|
requestId,
|
|
581
692
|
latencyMs
|
|
@@ -588,18 +699,18 @@ var SolvaPayPaywall = class {
|
|
|
588
699
|
} else {
|
|
589
700
|
this.log(`\u274C Error in paywall:`, error);
|
|
590
701
|
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
702
|
+
if (!(error instanceof PaywallError)) {
|
|
703
|
+
const latencyMs = Date.now() - startTime;
|
|
704
|
+
this.trackUsage(
|
|
705
|
+
backendCustomerRef,
|
|
706
|
+
product,
|
|
707
|
+
usagePlanRef,
|
|
708
|
+
resolvedMeterName || usageType,
|
|
709
|
+
"fail",
|
|
710
|
+
requestId,
|
|
711
|
+
latencyMs
|
|
712
|
+
);
|
|
713
|
+
}
|
|
603
714
|
throw error;
|
|
604
715
|
}
|
|
605
716
|
};
|
|
@@ -748,24 +859,23 @@ var SolvaPayPaywall = class {
|
|
|
748
859
|
}
|
|
749
860
|
return backendRef;
|
|
750
861
|
}
|
|
751
|
-
async trackUsage(customerRef,
|
|
862
|
+
async trackUsage(customerRef, _productRef, _planRef, action, outcome, requestId, actionDuration) {
|
|
752
863
|
await withRetry(
|
|
753
864
|
() => this.apiClient.trackUsage({
|
|
754
865
|
customerRef,
|
|
755
|
-
|
|
756
|
-
|
|
866
|
+
actionType: "api_call",
|
|
867
|
+
units: 1,
|
|
757
868
|
outcome,
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
869
|
+
productReference: _productRef,
|
|
870
|
+
duration: actionDuration,
|
|
871
|
+
metadata: { action: action || "api_requests", requestId },
|
|
761
872
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
762
873
|
}),
|
|
763
874
|
{
|
|
764
875
|
maxRetries: 2,
|
|
765
876
|
initialDelay: 500,
|
|
766
877
|
shouldRetry: (error) => error.message.includes("Customer not found"),
|
|
767
|
-
|
|
768
|
-
onRetry: (error, attempt) => {
|
|
878
|
+
onRetry: (_error, attempt) => {
|
|
769
879
|
console.warn(`\u26A0\uFE0F Customer not found (attempt ${attempt + 1}/3), retrying in 500ms...`);
|
|
770
880
|
}
|
|
771
881
|
}
|
|
@@ -806,13 +916,19 @@ var AdapterUtils = class {
|
|
|
806
916
|
}
|
|
807
917
|
};
|
|
808
918
|
async function createAdapterHandler(adapter, paywall, metadata, businessLogic) {
|
|
919
|
+
const backendRefCache = /* @__PURE__ */ new Map();
|
|
920
|
+
const getCustomerRef = (args) => args.auth?.customer_ref || "anonymous";
|
|
921
|
+
const protectedHandler = await paywall.protect(businessLogic, metadata, getCustomerRef);
|
|
809
922
|
return async (context) => {
|
|
810
923
|
try {
|
|
811
924
|
const args = await adapter.extractArgs(context);
|
|
812
925
|
const customerRef = await adapter.getCustomerRef(context);
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
926
|
+
let backendRef = backendRefCache.get(customerRef);
|
|
927
|
+
if (!backendRef) {
|
|
928
|
+
backendRef = await paywall.ensureCustomer(customerRef, customerRef);
|
|
929
|
+
backendRefCache.set(customerRef, backendRef);
|
|
930
|
+
}
|
|
931
|
+
args.auth = { customer_ref: backendRef };
|
|
816
932
|
const result = await protectedHandler(args);
|
|
817
933
|
return adapter.formatResponse(result, context);
|
|
818
934
|
} catch (error) {
|
|
@@ -1061,6 +1177,140 @@ var McpAdapter = class {
|
|
|
1061
1177
|
|
|
1062
1178
|
// src/factory.ts
|
|
1063
1179
|
import { SolvaPayError as SolvaPayError2, getSolvaPayConfig } from "@solvapay/core";
|
|
1180
|
+
|
|
1181
|
+
// src/virtual-tools.ts
|
|
1182
|
+
var TOOL_GET_USER_INFO = {
|
|
1183
|
+
name: "get_user_info",
|
|
1184
|
+
description: "Get information about the current user and their purchase status for this MCP server. Returns user profile (reference, name, email) and active purchase details including product name, type, dates, and usage limit if applicable.",
|
|
1185
|
+
inputSchema: {
|
|
1186
|
+
type: "object",
|
|
1187
|
+
properties: {},
|
|
1188
|
+
required: []
|
|
1189
|
+
}
|
|
1190
|
+
};
|
|
1191
|
+
var TOOL_UPGRADE = {
|
|
1192
|
+
name: "upgrade",
|
|
1193
|
+
description: "Get available pricing options and checkout URLs for upgrading. Returns a list of available pricing options with their details (price, features) and checkout URLs. Users can click on a checkout URL to purchase. If a specific planRef is provided, returns only the checkout URL for that pricing option.",
|
|
1194
|
+
inputSchema: {
|
|
1195
|
+
type: "object",
|
|
1196
|
+
properties: {
|
|
1197
|
+
planRef: {
|
|
1198
|
+
type: "string",
|
|
1199
|
+
description: 'Optional pricing reference (e.g., "pln_abc123") to get a checkout URL for a specific option. If not provided, returns all available pricing options with their checkout URLs.'
|
|
1200
|
+
}
|
|
1201
|
+
},
|
|
1202
|
+
required: []
|
|
1203
|
+
}
|
|
1204
|
+
};
|
|
1205
|
+
var TOOL_MANAGE_ACCOUNT = {
|
|
1206
|
+
name: "manage_account",
|
|
1207
|
+
description: "Get a URL to the customer portal where users can view and manage their account. The portal shows current account status, billing history, and allows subscription changes. Returns a secure, time-limited URL that the user can click to access their account management page.",
|
|
1208
|
+
inputSchema: {
|
|
1209
|
+
type: "object",
|
|
1210
|
+
properties: {},
|
|
1211
|
+
required: []
|
|
1212
|
+
}
|
|
1213
|
+
};
|
|
1214
|
+
function mcpTextResult(text) {
|
|
1215
|
+
return { content: [{ type: "text", text }] };
|
|
1216
|
+
}
|
|
1217
|
+
function mcpErrorResult(message) {
|
|
1218
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: message }) }], isError: true };
|
|
1219
|
+
}
|
|
1220
|
+
function createGetUserInfoHandler(apiClient, productRef, getCustomerRef) {
|
|
1221
|
+
return async (args) => {
|
|
1222
|
+
const customerRef = getCustomerRef(args);
|
|
1223
|
+
try {
|
|
1224
|
+
if (!apiClient.getUserInfo) {
|
|
1225
|
+
return mcpErrorResult("getUserInfo is not available on this API client");
|
|
1226
|
+
}
|
|
1227
|
+
const userInfo = await apiClient.getUserInfo({ customerRef, productRef });
|
|
1228
|
+
return mcpTextResult(JSON.stringify(userInfo, null, 2));
|
|
1229
|
+
} catch (error) {
|
|
1230
|
+
return mcpErrorResult(
|
|
1231
|
+
`Failed to retrieve user information: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1232
|
+
);
|
|
1233
|
+
}
|
|
1234
|
+
};
|
|
1235
|
+
}
|
|
1236
|
+
function createUpgradeHandler(apiClient, productRef, getCustomerRef) {
|
|
1237
|
+
return async (args) => {
|
|
1238
|
+
const customerRef = getCustomerRef(args);
|
|
1239
|
+
const planRef = typeof args.planRef === "string" ? args.planRef : void 0;
|
|
1240
|
+
try {
|
|
1241
|
+
const result = await apiClient.createCheckoutSession({
|
|
1242
|
+
customerReference: customerRef,
|
|
1243
|
+
productRef,
|
|
1244
|
+
...planRef && { planRef }
|
|
1245
|
+
});
|
|
1246
|
+
const checkoutUrl = result.checkoutUrl;
|
|
1247
|
+
if (planRef) {
|
|
1248
|
+
const responseText2 = `## Upgrade
|
|
1249
|
+
|
|
1250
|
+
**[Click here to upgrade \u2192](${checkoutUrl})**
|
|
1251
|
+
|
|
1252
|
+
After completing the checkout, your purchase will be activated immediately.`;
|
|
1253
|
+
return mcpTextResult(responseText2);
|
|
1254
|
+
}
|
|
1255
|
+
const responseText = `## Upgrade Your Subscription
|
|
1256
|
+
|
|
1257
|
+
**[Click here to view pricing options and upgrade \u2192](${checkoutUrl})**
|
|
1258
|
+
|
|
1259
|
+
You'll be able to compare options and select the one that's right for you.`;
|
|
1260
|
+
return mcpTextResult(responseText);
|
|
1261
|
+
} catch (error) {
|
|
1262
|
+
return mcpErrorResult(
|
|
1263
|
+
`Failed to create checkout session: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1264
|
+
);
|
|
1265
|
+
}
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1268
|
+
function createManageAccountHandler(apiClient, productRef, getCustomerRef) {
|
|
1269
|
+
return async (args) => {
|
|
1270
|
+
const customerRef = getCustomerRef(args);
|
|
1271
|
+
try {
|
|
1272
|
+
const session = await apiClient.createCustomerSession({ customerRef, productRef });
|
|
1273
|
+
const portalUrl = session.customerUrl;
|
|
1274
|
+
const responseText = `## Manage Your Account
|
|
1275
|
+
|
|
1276
|
+
Access your account management portal to:
|
|
1277
|
+
- View your current account status
|
|
1278
|
+
- See billing history and invoices
|
|
1279
|
+
- Update payment methods
|
|
1280
|
+
- Cancel or modify your subscription
|
|
1281
|
+
|
|
1282
|
+
**[Open Account Portal \u2192](${portalUrl})**
|
|
1283
|
+
|
|
1284
|
+
This link is secure and will expire after a short period.`;
|
|
1285
|
+
return mcpTextResult(responseText);
|
|
1286
|
+
} catch (error) {
|
|
1287
|
+
return mcpErrorResult(
|
|
1288
|
+
`Failed to create customer portal session: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1289
|
+
);
|
|
1290
|
+
}
|
|
1291
|
+
};
|
|
1292
|
+
}
|
|
1293
|
+
function createVirtualTools(apiClient, options) {
|
|
1294
|
+
const { product, getCustomerRef, exclude = [] } = options;
|
|
1295
|
+
const excludeSet = new Set(exclude);
|
|
1296
|
+
const allTools = [
|
|
1297
|
+
{
|
|
1298
|
+
...TOOL_GET_USER_INFO,
|
|
1299
|
+
handler: createGetUserInfoHandler(apiClient, product, getCustomerRef)
|
|
1300
|
+
},
|
|
1301
|
+
{
|
|
1302
|
+
...TOOL_UPGRADE,
|
|
1303
|
+
handler: createUpgradeHandler(apiClient, product, getCustomerRef)
|
|
1304
|
+
},
|
|
1305
|
+
{
|
|
1306
|
+
...TOOL_MANAGE_ACCOUNT,
|
|
1307
|
+
handler: createManageAccountHandler(apiClient, product, getCustomerRef)
|
|
1308
|
+
}
|
|
1309
|
+
];
|
|
1310
|
+
return allTools.filter((t) => !excludeSet.has(t.name));
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
// src/factory.ts
|
|
1064
1314
|
function createSolvaPay(config) {
|
|
1065
1315
|
let resolvedConfig;
|
|
1066
1316
|
if (!config) {
|
|
@@ -1077,7 +1327,8 @@ function createSolvaPay(config) {
|
|
|
1077
1327
|
apiBaseUrl: resolvedConfig.apiBaseUrl
|
|
1078
1328
|
});
|
|
1079
1329
|
const paywall = new SolvaPayPaywall(apiClient, {
|
|
1080
|
-
debug: process.env.SOLVAPAY_DEBUG !== "false"
|
|
1330
|
+
debug: process.env.SOLVAPAY_DEBUG !== "false",
|
|
1331
|
+
limitsCacheTTL: resolvedConfig.limitsCacheTTL
|
|
1081
1332
|
});
|
|
1082
1333
|
return {
|
|
1083
1334
|
// Direct access to API client for advanced operations
|
|
@@ -1123,39 +1374,67 @@ function createSolvaPay(config) {
|
|
|
1123
1374
|
createCustomerSession(params) {
|
|
1124
1375
|
return apiClient.createCustomerSession(params);
|
|
1125
1376
|
},
|
|
1377
|
+
bootstrapMcpProduct(params) {
|
|
1378
|
+
if (!apiClient.bootstrapMcpProduct) {
|
|
1379
|
+
throw new SolvaPayError2("bootstrapMcpProduct is not available on this API client");
|
|
1380
|
+
}
|
|
1381
|
+
return apiClient.bootstrapMcpProduct(params);
|
|
1382
|
+
},
|
|
1383
|
+
getVirtualTools(options) {
|
|
1384
|
+
return createVirtualTools(apiClient, options);
|
|
1385
|
+
},
|
|
1126
1386
|
// Payable API for framework-specific handlers
|
|
1127
1387
|
payable(options = {}) {
|
|
1128
1388
|
const product = options.productRef || options.product || process.env.SOLVAPAY_PRODUCT || "default-product";
|
|
1129
|
-
const plan = options.planRef || options.plan
|
|
1130
|
-
const
|
|
1389
|
+
const plan = options.planRef || options.plan;
|
|
1390
|
+
const usageType = options.usageType || "requests";
|
|
1391
|
+
const metadata = { product, plan, usageType };
|
|
1131
1392
|
return {
|
|
1132
1393
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1133
1394
|
http(businessLogic, adapterOptions) {
|
|
1134
|
-
const adapter = new HttpAdapter(
|
|
1395
|
+
const adapter = new HttpAdapter({
|
|
1396
|
+
...adapterOptions,
|
|
1397
|
+
getCustomerRef: adapterOptions?.getCustomerRef || options.getCustomerRef
|
|
1398
|
+
});
|
|
1399
|
+
const handlerPromise = createAdapterHandler(adapter, paywall, metadata, businessLogic);
|
|
1135
1400
|
return async (req, reply) => {
|
|
1136
|
-
const handler = await
|
|
1401
|
+
const handler = await handlerPromise;
|
|
1137
1402
|
return handler([req, reply]);
|
|
1138
1403
|
};
|
|
1139
1404
|
},
|
|
1140
1405
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1141
1406
|
next(businessLogic, adapterOptions) {
|
|
1142
|
-
const adapter = new NextAdapter(
|
|
1407
|
+
const adapter = new NextAdapter({
|
|
1408
|
+
...adapterOptions,
|
|
1409
|
+
getCustomerRef: adapterOptions?.getCustomerRef || options.getCustomerRef
|
|
1410
|
+
});
|
|
1411
|
+
const handlerPromise = createAdapterHandler(adapter, paywall, metadata, businessLogic);
|
|
1143
1412
|
return async (request, context) => {
|
|
1144
|
-
const handler = await
|
|
1413
|
+
const handler = await handlerPromise;
|
|
1145
1414
|
return handler([request, context]);
|
|
1146
1415
|
};
|
|
1147
1416
|
},
|
|
1148
1417
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1149
1418
|
mcp(businessLogic, adapterOptions) {
|
|
1150
|
-
const adapter = new McpAdapter(
|
|
1419
|
+
const adapter = new McpAdapter({
|
|
1420
|
+
...adapterOptions,
|
|
1421
|
+
getCustomerRef: adapterOptions?.getCustomerRef || options.getCustomerRef
|
|
1422
|
+
});
|
|
1423
|
+
const handlerPromise = createAdapterHandler(adapter, paywall, metadata, businessLogic);
|
|
1151
1424
|
return async (args) => {
|
|
1152
|
-
const handler = await
|
|
1425
|
+
const handler = await handlerPromise;
|
|
1153
1426
|
return handler(args);
|
|
1154
1427
|
};
|
|
1155
1428
|
},
|
|
1156
1429
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1157
1430
|
async function(businessLogic) {
|
|
1158
|
-
const getCustomerRef = (args) =>
|
|
1431
|
+
const getCustomerRef = (args) => {
|
|
1432
|
+
const configuredRef = options.getCustomerRef?.(args);
|
|
1433
|
+
if (typeof configuredRef === "string") {
|
|
1434
|
+
return configuredRef;
|
|
1435
|
+
}
|
|
1436
|
+
return args.auth?.customer_ref || "anonymous";
|
|
1437
|
+
};
|
|
1159
1438
|
return paywall.protect(businessLogic, metadata, getCustomerRef);
|
|
1160
1439
|
}
|
|
1161
1440
|
};
|