@solvapay/server 2.7.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/edge.d.ts +40 -15
- package/dist/edge.js +77 -35
- package/dist/fetch/index.cjs +84 -42
- package/dist/fetch/index.d.cts +10 -1
- package/dist/fetch/index.d.ts +10 -1
- package/dist/fetch/index.js +75 -33
- package/dist/index.cjs +93 -51
- package/dist/index.d.cts +41 -16
- package/dist/index.d.ts +41 -16
- package/dist/index.js +81 -39
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -85,7 +85,7 @@ __export(index_exports, {
|
|
|
85
85
|
});
|
|
86
86
|
module.exports = __toCommonJS(index_exports);
|
|
87
87
|
var import_node_crypto = __toESM(require("crypto"), 1);
|
|
88
|
-
var
|
|
88
|
+
var import_core14 = require("@solvapay/core");
|
|
89
89
|
|
|
90
90
|
// src/client.ts
|
|
91
91
|
var import_core = require("@solvapay/core");
|
|
@@ -760,6 +760,9 @@ function classifyPaywallState(limits) {
|
|
|
760
760
|
if (limits.activationRequired === true || limits.paywallReason === "activation_required") {
|
|
761
761
|
return { kind: "activation_required" };
|
|
762
762
|
}
|
|
763
|
+
if (limits.paywallReason === "limit_reached") {
|
|
764
|
+
return { kind: "limit_reached" };
|
|
765
|
+
}
|
|
763
766
|
if (limits.paywallReason === "topup_required") {
|
|
764
767
|
return { kind: "topup_required" };
|
|
765
768
|
}
|
|
@@ -823,9 +826,12 @@ function formatCreditsWithMoney(credits, gate) {
|
|
|
823
826
|
}
|
|
824
827
|
return `${amount} credits`;
|
|
825
828
|
}
|
|
829
|
+
function isFreeMeter(name) {
|
|
830
|
+
return typeof name === "string" && name.startsWith("free-");
|
|
831
|
+
}
|
|
826
832
|
function meterLabel(gate) {
|
|
827
833
|
if (!gate.meterName) return "units";
|
|
828
|
-
return gate.meterName.replace(/_/g, " ");
|
|
834
|
+
return gate.meterName.replace(/[_-]/g, " ");
|
|
829
835
|
}
|
|
830
836
|
function namedCheckoutMarkdown(url, label = "Open checkout") {
|
|
831
837
|
return `[${label}](${url})`;
|
|
@@ -861,6 +867,12 @@ function buildGateMessage(state, gate) {
|
|
|
861
867
|
switch (state.kind) {
|
|
862
868
|
case "limit_reached": {
|
|
863
869
|
const included = gate.included;
|
|
870
|
+
if (isFreeMeter(gate.meterName)) {
|
|
871
|
+
const total = included?.total;
|
|
872
|
+
const usedLine2 = total !== void 0 ? `You've used all ${total} ${meterLabel(gate)} for this period.` : `You've used all ${meterLabel(gate)} for this period.`;
|
|
873
|
+
const switchLine2 = ladder ? ` Pick a plan to keep going: ${ladder}. ${callViewer("account").replace(/^c/, "C")} for usage and recovery.` : recoverClause(url, "keep going", "checkout");
|
|
874
|
+
return `${usedLine2}${switchLine2}`;
|
|
875
|
+
}
|
|
864
876
|
const price = gate.unitPriceMinor != null && gate.currency ? formatMinor(gate.unitPriceMinor, gate.currency) : null;
|
|
865
877
|
const usedLine = included ? `You've used ${included.used} of ${included.total} included ${meterLabel(gate)} this period.` : `You've reached the included usage for this period.`;
|
|
866
878
|
const nextLine = price ? ` The next call is ${price}.` : "";
|
|
@@ -1187,6 +1199,7 @@ function createRequestDeduplicator(options = {}) {
|
|
|
1187
1199
|
}
|
|
1188
1200
|
|
|
1189
1201
|
// src/paywall.ts
|
|
1202
|
+
var import_core4 = require("@solvapay/core");
|
|
1190
1203
|
var PaywallError = class extends Error {
|
|
1191
1204
|
/**
|
|
1192
1205
|
* Creates a new PaywallError instance.
|
|
@@ -1237,6 +1250,15 @@ var sharedLimitsFetchDeduplicator = createRequestDeduplicator({
|
|
|
1237
1250
|
});
|
|
1238
1251
|
var sharedLimitsFetchClaims = /* @__PURE__ */ new Map();
|
|
1239
1252
|
var EXTRA_FORWARD_KEY = "__solvapayExtra";
|
|
1253
|
+
function trackUsageExtra(metadata, outcome, consequence) {
|
|
1254
|
+
if (metadata.freeLimit) {
|
|
1255
|
+
return { meterName: metadata.freeLimit.meter };
|
|
1256
|
+
}
|
|
1257
|
+
if (outcome === "success") {
|
|
1258
|
+
return { usageClass: consequence === "overage" ? "overage" : "included" };
|
|
1259
|
+
}
|
|
1260
|
+
return void 0;
|
|
1261
|
+
}
|
|
1240
1262
|
var SolvaPayPaywall = class {
|
|
1241
1263
|
constructor(apiClient, options = {}) {
|
|
1242
1264
|
this.apiClient = apiClient;
|
|
@@ -1296,10 +1318,19 @@ var SolvaPayPaywall = class {
|
|
|
1296
1318
|
*/
|
|
1297
1319
|
async decide(args, metadata = {}, getCustomerRef) {
|
|
1298
1320
|
const product = this.resolveProduct(metadata);
|
|
1299
|
-
const usageType = metadata.meterName || metadata.usageType || "requests";
|
|
1321
|
+
const usageType = metadata.freeLimit?.meter || metadata.meterName || metadata.usageType || "requests";
|
|
1300
1322
|
const requestId = this.generateRequestId();
|
|
1301
1323
|
const startTime = Date.now();
|
|
1302
1324
|
const inputCustomerRef = getCustomerRef ? getCustomerRef(args) : args.auth?.customer_ref || "anonymous";
|
|
1325
|
+
if (metadata.freeLimit) {
|
|
1326
|
+
const resolved = typeof inputCustomerRef === "string" ? inputCustomerRef.trim() : "";
|
|
1327
|
+
if (!resolved || resolved === "anonymous") {
|
|
1328
|
+
throw new import_core4.SolvaPayError("identity required", {
|
|
1329
|
+
status: 401,
|
|
1330
|
+
code: "identity_required"
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1303
1334
|
let backendCustomerRef;
|
|
1304
1335
|
if (inputCustomerRef.startsWith("cus_")) {
|
|
1305
1336
|
backendCustomerRef = inputCustomerRef;
|
|
@@ -1350,7 +1381,8 @@ var SolvaPayPaywall = class {
|
|
|
1350
1381
|
// `checkLimitsCore`, which powers the React `useLimits` hook)
|
|
1351
1382
|
// leave this unset and the backend skips the session-creation
|
|
1352
1383
|
// side effect.
|
|
1353
|
-
includeCheckoutSession: true
|
|
1384
|
+
includeCheckoutSession: true,
|
|
1385
|
+
...metadata.freeLimit ? { freeAllowance: metadata.freeLimit } : {}
|
|
1354
1386
|
});
|
|
1355
1387
|
}
|
|
1356
1388
|
);
|
|
@@ -1394,7 +1426,8 @@ var SolvaPayPaywall = class {
|
|
|
1394
1426
|
"paywall",
|
|
1395
1427
|
requestId,
|
|
1396
1428
|
latencyMs,
|
|
1397
|
-
metadata.toolName
|
|
1429
|
+
metadata.toolName,
|
|
1430
|
+
metadata.freeLimit ? { meterName: metadata.freeLimit.meter } : void 0
|
|
1398
1431
|
).catch(() => void 0);
|
|
1399
1432
|
const gate = buildPaywallGate(
|
|
1400
1433
|
product,
|
|
@@ -1441,7 +1474,7 @@ var SolvaPayPaywall = class {
|
|
|
1441
1474
|
*/
|
|
1442
1475
|
async runAllow(decision, handler, metadata, args) {
|
|
1443
1476
|
const product = this.resolveProduct(metadata);
|
|
1444
|
-
const usageType = metadata.meterName || metadata.usageType || "requests";
|
|
1477
|
+
const usageType = metadata.freeLimit?.meter || metadata.meterName || metadata.usageType || "requests";
|
|
1445
1478
|
const requestId = decision.requestId;
|
|
1446
1479
|
const startTime = Date.now();
|
|
1447
1480
|
const forwardedExtra = args[EXTRA_FORWARD_KEY];
|
|
@@ -1460,7 +1493,8 @@ var SolvaPayPaywall = class {
|
|
|
1460
1493
|
"success",
|
|
1461
1494
|
requestId,
|
|
1462
1495
|
latencyMs,
|
|
1463
|
-
metadata.toolName
|
|
1496
|
+
metadata.toolName,
|
|
1497
|
+
trackUsageExtra(metadata, "success", decision.consequence)
|
|
1464
1498
|
).catch(() => void 0);
|
|
1465
1499
|
return result;
|
|
1466
1500
|
} catch (error) {
|
|
@@ -1479,7 +1513,8 @@ var SolvaPayPaywall = class {
|
|
|
1479
1513
|
"fail",
|
|
1480
1514
|
requestId,
|
|
1481
1515
|
latencyMs,
|
|
1482
|
-
metadata.toolName
|
|
1516
|
+
metadata.toolName,
|
|
1517
|
+
trackUsageExtra(metadata, "fail")
|
|
1483
1518
|
).catch(() => void 0);
|
|
1484
1519
|
}
|
|
1485
1520
|
throw error;
|
|
@@ -1670,7 +1705,7 @@ var SolvaPayPaywall = class {
|
|
|
1670
1705
|
}
|
|
1671
1706
|
return backendRef;
|
|
1672
1707
|
}
|
|
1673
|
-
async trackUsage(customerRef, productRef, action, outcome, requestId, actionDuration, toolName) {
|
|
1708
|
+
async trackUsage(customerRef, productRef, action, outcome, requestId, actionDuration, toolName, extra) {
|
|
1674
1709
|
await withRetry(
|
|
1675
1710
|
() => this.apiClient.trackUsage({
|
|
1676
1711
|
customerRef,
|
|
@@ -1683,7 +1718,9 @@ var SolvaPayPaywall = class {
|
|
|
1683
1718
|
metadata: {
|
|
1684
1719
|
action: action || "api_requests",
|
|
1685
1720
|
requestId,
|
|
1686
|
-
...toolName ? { toolName } : {}
|
|
1721
|
+
...toolName ? { toolName } : {},
|
|
1722
|
+
...extra?.meterName ? { meterName: extra.meterName } : {},
|
|
1723
|
+
...extra?.usageClass ? { usageClass: extra.usageClass } : {}
|
|
1687
1724
|
},
|
|
1688
1725
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1689
1726
|
}),
|
|
@@ -2023,7 +2060,7 @@ var McpAdapter = class {
|
|
|
2023
2060
|
};
|
|
2024
2061
|
|
|
2025
2062
|
// src/factory.ts
|
|
2026
|
-
var
|
|
2063
|
+
var import_core5 = require("@solvapay/core");
|
|
2027
2064
|
|
|
2028
2065
|
// src/virtual-tools.ts
|
|
2029
2066
|
var TOOL_GET_USER_INFO = {
|
|
@@ -2265,7 +2302,7 @@ function registerVirtualToolsMcpImpl(server, apiClient, options) {
|
|
|
2265
2302
|
function createSolvaPay(config) {
|
|
2266
2303
|
let resolvedConfig;
|
|
2267
2304
|
if (!config) {
|
|
2268
|
-
const envConfig = (0,
|
|
2305
|
+
const envConfig = (0, import_core5.getSolvaPayConfig)();
|
|
2269
2306
|
resolvedConfig = {
|
|
2270
2307
|
apiKey: envConfig.apiKey,
|
|
2271
2308
|
apiBaseUrl: envConfig.apiBaseUrl
|
|
@@ -2301,25 +2338,25 @@ function createSolvaPay(config) {
|
|
|
2301
2338
|
},
|
|
2302
2339
|
createPaymentIntent(params) {
|
|
2303
2340
|
if (!apiClient.createPaymentIntent) {
|
|
2304
|
-
throw new
|
|
2341
|
+
throw new import_core5.SolvaPayError("createPaymentIntent is not available on this API client");
|
|
2305
2342
|
}
|
|
2306
2343
|
return apiClient.createPaymentIntent(params);
|
|
2307
2344
|
},
|
|
2308
2345
|
createTopupPaymentIntent(params) {
|
|
2309
2346
|
if (!apiClient.createTopupPaymentIntent) {
|
|
2310
|
-
throw new
|
|
2347
|
+
throw new import_core5.SolvaPayError("createTopupPaymentIntent is not available on this API client");
|
|
2311
2348
|
}
|
|
2312
2349
|
return apiClient.createTopupPaymentIntent(params);
|
|
2313
2350
|
},
|
|
2314
2351
|
processPaymentIntent(params) {
|
|
2315
2352
|
if (!apiClient.processPaymentIntent) {
|
|
2316
|
-
throw new
|
|
2353
|
+
throw new import_core5.SolvaPayError("processPaymentIntent is not available on this API client");
|
|
2317
2354
|
}
|
|
2318
2355
|
return apiClient.processPaymentIntent(params);
|
|
2319
2356
|
},
|
|
2320
2357
|
attachBusinessDetails(params) {
|
|
2321
2358
|
if (!apiClient.attachBusinessDetails) {
|
|
2322
|
-
throw new
|
|
2359
|
+
throw new import_core5.SolvaPayError("attachBusinessDetails is not available on this API client");
|
|
2323
2360
|
}
|
|
2324
2361
|
return apiClient.attachBusinessDetails(params);
|
|
2325
2362
|
},
|
|
@@ -2331,13 +2368,13 @@ function createSolvaPay(config) {
|
|
|
2331
2368
|
},
|
|
2332
2369
|
trackUsageBulk(params) {
|
|
2333
2370
|
if (!apiClient.trackUsageBulk) {
|
|
2334
|
-
throw new
|
|
2371
|
+
throw new import_core5.SolvaPayError("trackUsageBulk is not available on this API client");
|
|
2335
2372
|
}
|
|
2336
2373
|
return apiClient.trackUsageBulk(params);
|
|
2337
2374
|
},
|
|
2338
2375
|
createCustomer(params) {
|
|
2339
2376
|
if (!apiClient.createCustomer) {
|
|
2340
|
-
throw new
|
|
2377
|
+
throw new import_core5.SolvaPayError("createCustomer is not available on this API client");
|
|
2341
2378
|
}
|
|
2342
2379
|
return apiClient.createCustomer({ ...params, metadata: params.metadata ?? {} });
|
|
2343
2380
|
},
|
|
@@ -2346,13 +2383,13 @@ function createSolvaPay(config) {
|
|
|
2346
2383
|
},
|
|
2347
2384
|
assignCredits(params) {
|
|
2348
2385
|
if (!apiClient.assignCredits) {
|
|
2349
|
-
throw new
|
|
2386
|
+
throw new import_core5.SolvaPayError("assignCredits is not available on this API client");
|
|
2350
2387
|
}
|
|
2351
2388
|
return apiClient.assignCredits(params);
|
|
2352
2389
|
},
|
|
2353
2390
|
getCustomerBalance(params) {
|
|
2354
2391
|
if (!apiClient.getCustomerBalance) {
|
|
2355
|
-
throw new
|
|
2392
|
+
throw new import_core5.SolvaPayError("getCustomerBalance is not available on this API client");
|
|
2356
2393
|
}
|
|
2357
2394
|
return apiClient.getCustomerBalance(params);
|
|
2358
2395
|
},
|
|
@@ -2370,19 +2407,19 @@ function createSolvaPay(config) {
|
|
|
2370
2407
|
},
|
|
2371
2408
|
activatePlan(params) {
|
|
2372
2409
|
if (!apiClient.activatePlan) {
|
|
2373
|
-
throw new
|
|
2410
|
+
throw new import_core5.SolvaPayError("activatePlan is not available on this API client");
|
|
2374
2411
|
}
|
|
2375
2412
|
return apiClient.activatePlan(params);
|
|
2376
2413
|
},
|
|
2377
2414
|
bootstrapMcpProduct(params) {
|
|
2378
2415
|
if (!apiClient.bootstrapMcpProduct) {
|
|
2379
|
-
throw new
|
|
2416
|
+
throw new import_core5.SolvaPayError("bootstrapMcpProduct is not available on this API client");
|
|
2380
2417
|
}
|
|
2381
2418
|
return apiClient.bootstrapMcpProduct(params);
|
|
2382
2419
|
},
|
|
2383
2420
|
configureMcpPlans(productRef, params) {
|
|
2384
2421
|
if (!apiClient.configureMcpPlans) {
|
|
2385
|
-
throw new
|
|
2422
|
+
throw new import_core5.SolvaPayError("configureMcpPlans is not available on this API client");
|
|
2386
2423
|
}
|
|
2387
2424
|
return apiClient.configureMcpPlans(productRef, params);
|
|
2388
2425
|
},
|
|
@@ -2395,12 +2432,13 @@ function createSolvaPay(config) {
|
|
|
2395
2432
|
// Payable API for framework-specific handlers
|
|
2396
2433
|
payable(options = {}) {
|
|
2397
2434
|
const product = resolveProductRef(options.productRef || options.product);
|
|
2398
|
-
const usageType = options.meterName || options.usageType || "requests";
|
|
2435
|
+
const usageType = options.freeLimit?.meter || options.meterName || options.usageType || "requests";
|
|
2399
2436
|
const metadata = {
|
|
2400
2437
|
product,
|
|
2401
2438
|
meterName: usageType,
|
|
2402
2439
|
usageType,
|
|
2403
|
-
...options.toolName ? { toolName: options.toolName } : {}
|
|
2440
|
+
...options.toolName ? { toolName: options.toolName } : {},
|
|
2441
|
+
...options.freeLimit ? { freeLimit: options.freeLimit } : {}
|
|
2404
2442
|
};
|
|
2405
2443
|
return {
|
|
2406
2444
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -2489,6 +2527,8 @@ function createSolvaPay(config) {
|
|
|
2489
2527
|
const errMeta = opts?.error !== void 0 ? {
|
|
2490
2528
|
error: opts.error instanceof Error ? opts.error.message : String(opts.error)
|
|
2491
2529
|
} : {};
|
|
2530
|
+
const isFree = Boolean(decideMetadata.freeLimit);
|
|
2531
|
+
const usageClass = !isFree && outcome === "success" ? decision.consequence === "overage" ? "overage" : "included" : void 0;
|
|
2492
2532
|
const trackPromise = apiClient.trackUsage({
|
|
2493
2533
|
customerRef,
|
|
2494
2534
|
productRef,
|
|
@@ -2501,6 +2541,8 @@ function createSolvaPay(config) {
|
|
|
2501
2541
|
action: meterName,
|
|
2502
2542
|
requestId,
|
|
2503
2543
|
...decideMetadata.toolName ? { toolName: decideMetadata.toolName } : {},
|
|
2544
|
+
...isFree && decideMetadata.freeLimit ? { meterName: decideMetadata.freeLimit.meter } : {},
|
|
2545
|
+
...usageClass ? { usageClass } : {},
|
|
2504
2546
|
...errMeta,
|
|
2505
2547
|
...opts?.metadata ?? {}
|
|
2506
2548
|
},
|
|
@@ -2533,7 +2575,7 @@ async function resolveCustomerRefFromRequest(req, options) {
|
|
|
2533
2575
|
}
|
|
2534
2576
|
|
|
2535
2577
|
// src/verify-product-configuration.ts
|
|
2536
|
-
var
|
|
2578
|
+
var import_core6 = require("@solvapay/core");
|
|
2537
2579
|
async function verifyProductConfiguration(options) {
|
|
2538
2580
|
const { apiClient, productRef } = options;
|
|
2539
2581
|
const apiBaseUrl = options.apiBaseUrl ?? "(unknown API base URL)";
|
|
@@ -2544,7 +2586,7 @@ async function verifyProductConfiguration(options) {
|
|
|
2544
2586
|
}
|
|
2545
2587
|
try {
|
|
2546
2588
|
const product = await apiClient.getProduct(productRef);
|
|
2547
|
-
const readiness = (0,
|
|
2589
|
+
const readiness = (0, import_core6.evaluateProductReadiness)({
|
|
2548
2590
|
status: product.status,
|
|
2549
2591
|
plans: product.plans
|
|
2550
2592
|
});
|
|
@@ -2557,8 +2599,8 @@ async function verifyProductConfiguration(options) {
|
|
|
2557
2599
|
issues: readiness.issues
|
|
2558
2600
|
};
|
|
2559
2601
|
} catch (error) {
|
|
2560
|
-
const status = error instanceof
|
|
2561
|
-
const code = error instanceof
|
|
2602
|
+
const status = error instanceof import_core6.SolvaPayError ? error.status : void 0;
|
|
2603
|
+
const code = error instanceof import_core6.SolvaPayError ? error.code : void 0;
|
|
2562
2604
|
if (status === 404 && code === "non_json_response") {
|
|
2563
2605
|
throw new Error(
|
|
2564
2606
|
`Could not reach ${apiBaseUrl} while verifying SOLVAPAY_PRODUCT_REF "${productRef}": the server returned a non-JSON response (often an offline ngrok tunnel or proxy error page). Check SOLVAPAY_API_BASE_URL and that the API tunnel is running.`
|
|
@@ -2655,13 +2697,13 @@ var PaywallStructuredContentSchema = import_zod.z.discriminatedUnion("kind", [
|
|
|
2655
2697
|
]);
|
|
2656
2698
|
|
|
2657
2699
|
// src/helpers/error.ts
|
|
2658
|
-
var
|
|
2700
|
+
var import_core7 = require("@solvapay/core");
|
|
2659
2701
|
function isErrorResult(result) {
|
|
2660
2702
|
return typeof result === "object" && result !== null && "error" in result && "status" in result;
|
|
2661
2703
|
}
|
|
2662
2704
|
function handleRouteError(error, operationName, defaultMessage) {
|
|
2663
2705
|
console.error(`[${operationName}] Error:`, error);
|
|
2664
|
-
if (error instanceof
|
|
2706
|
+
if (error instanceof import_core7.SolvaPayError) {
|
|
2665
2707
|
const errorMessage2 = error.message;
|
|
2666
2708
|
return {
|
|
2667
2709
|
error: errorMessage2,
|
|
@@ -2849,7 +2891,7 @@ async function getCustomerBalanceCore(request, options = {}) {
|
|
|
2849
2891
|
}
|
|
2850
2892
|
|
|
2851
2893
|
// src/helpers/payment.ts
|
|
2852
|
-
var
|
|
2894
|
+
var import_core8 = require("@solvapay/core");
|
|
2853
2895
|
|
|
2854
2896
|
// src/helpers/balance-poll.ts
|
|
2855
2897
|
var TOPUP_BALANCE_POLL_DELAYS_MS = [500, 1e3, 2e3, 4e3];
|
|
@@ -2991,7 +3033,7 @@ async function attachBusinessDetailsCore(request, body, options = {}) {
|
|
|
2991
3033
|
status: 400
|
|
2992
3034
|
};
|
|
2993
3035
|
}
|
|
2994
|
-
const validation = (0,
|
|
3036
|
+
const validation = (0, import_core8.validateBusinessDetails)({
|
|
2995
3037
|
isBusiness: body.isBusiness,
|
|
2996
3038
|
businessName: body.businessName,
|
|
2997
3039
|
country: body.country,
|
|
@@ -3158,7 +3200,7 @@ async function createCustomerSessionCore(request, options = {}) {
|
|
|
3158
3200
|
}
|
|
3159
3201
|
|
|
3160
3202
|
// src/helpers/renewal.ts
|
|
3161
|
-
var
|
|
3203
|
+
var import_core9 = require("@solvapay/core");
|
|
3162
3204
|
async function cancelPurchaseCore(request, body, options = {}) {
|
|
3163
3205
|
try {
|
|
3164
3206
|
if (!body.purchaseRef) {
|
|
@@ -3204,7 +3246,7 @@ async function cancelPurchaseCore(request, body, options = {}) {
|
|
|
3204
3246
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
3205
3247
|
return cancelledPurchase;
|
|
3206
3248
|
} catch (error) {
|
|
3207
|
-
if (error instanceof
|
|
3249
|
+
if (error instanceof import_core9.SolvaPayError) {
|
|
3208
3250
|
const errorMessage = error.message;
|
|
3209
3251
|
if (errorMessage.includes("not found")) {
|
|
3210
3252
|
return {
|
|
@@ -3272,7 +3314,7 @@ async function reactivatePurchaseCore(request, body, options = {}) {
|
|
|
3272
3314
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
3273
3315
|
return reactivatedPurchase;
|
|
3274
3316
|
} catch (error) {
|
|
3275
|
-
if (error instanceof
|
|
3317
|
+
if (error instanceof import_core9.SolvaPayError) {
|
|
3276
3318
|
const errorMessage = error.message;
|
|
3277
3319
|
if (errorMessage.includes("not found")) {
|
|
3278
3320
|
return {
|
|
@@ -3442,7 +3484,7 @@ async function getHistoryCore(request, input, options = {}) {
|
|
|
3442
3484
|
}
|
|
3443
3485
|
|
|
3444
3486
|
// src/helpers/plans.ts
|
|
3445
|
-
var
|
|
3487
|
+
var import_core10 = require("@solvapay/core");
|
|
3446
3488
|
async function listPlansCore(request, options = {}) {
|
|
3447
3489
|
try {
|
|
3448
3490
|
const url = new URL(request.url);
|
|
@@ -3454,7 +3496,7 @@ async function listPlansCore(request, options = {}) {
|
|
|
3454
3496
|
};
|
|
3455
3497
|
}
|
|
3456
3498
|
const apiClient = options.solvaPay?.apiClient ?? (() => {
|
|
3457
|
-
const config = (0,
|
|
3499
|
+
const config = (0, import_core10.getSolvaPayConfig)();
|
|
3458
3500
|
if (!config.apiKey) return null;
|
|
3459
3501
|
return createSolvaPayClient({
|
|
3460
3502
|
apiKey: config.apiKey,
|
|
@@ -3517,11 +3559,11 @@ async function checkLimitsCore(request, options = {}) {
|
|
|
3517
3559
|
}
|
|
3518
3560
|
|
|
3519
3561
|
// src/helpers/merchant.ts
|
|
3520
|
-
var
|
|
3562
|
+
var import_core11 = require("@solvapay/core");
|
|
3521
3563
|
async function getMerchantCore(_request, options = {}) {
|
|
3522
3564
|
try {
|
|
3523
3565
|
const apiClient = options.solvaPay?.apiClient ?? (() => {
|
|
3524
|
-
const config = (0,
|
|
3566
|
+
const config = (0, import_core11.getSolvaPayConfig)();
|
|
3525
3567
|
if (!config.apiKey) return null;
|
|
3526
3568
|
return createSolvaPayClient({
|
|
3527
3569
|
apiKey: config.apiKey,
|
|
@@ -3548,7 +3590,7 @@ async function getMerchantCore(_request, options = {}) {
|
|
|
3548
3590
|
}
|
|
3549
3591
|
|
|
3550
3592
|
// src/helpers/product.ts
|
|
3551
|
-
var
|
|
3593
|
+
var import_core12 = require("@solvapay/core");
|
|
3552
3594
|
async function getProductCore(request, options = {}) {
|
|
3553
3595
|
try {
|
|
3554
3596
|
const url = new URL(request.url);
|
|
@@ -3560,7 +3602,7 @@ async function getProductCore(request, options = {}) {
|
|
|
3560
3602
|
};
|
|
3561
3603
|
}
|
|
3562
3604
|
const apiClient = options.solvaPay?.apiClient ?? (() => {
|
|
3563
|
-
const config = (0,
|
|
3605
|
+
const config = (0, import_core12.getSolvaPayConfig)();
|
|
3564
3606
|
if (!config.apiKey) return null;
|
|
3565
3607
|
return createSolvaPayClient({
|
|
3566
3608
|
apiKey: config.apiKey,
|
|
@@ -3643,7 +3685,7 @@ async function checkPurchaseCore(request, options = {}) {
|
|
|
3643
3685
|
}
|
|
3644
3686
|
|
|
3645
3687
|
// src/helpers/usage.ts
|
|
3646
|
-
var
|
|
3688
|
+
var import_core13 = require("@solvapay/core");
|
|
3647
3689
|
function deriveUsageSnapshot(input) {
|
|
3648
3690
|
const period = {
|
|
3649
3691
|
...input.periodStart ? { periodStart: input.periodStart } : {},
|
|
@@ -3693,7 +3735,7 @@ async function getUsageCore(request, options = {}) {
|
|
|
3693
3735
|
if ("limits" in options) {
|
|
3694
3736
|
return deriveUsageSnapshot({ used, ...period, limits: options.limits ?? null });
|
|
3695
3737
|
}
|
|
3696
|
-
const usageCounted = (0,
|
|
3738
|
+
const usageCounted = (0, import_core13.countsUsage)(activePurchase.planSnapshot) || activePurchase.planSnapshot?.isMetered === true;
|
|
3697
3739
|
if (!usageCounted || !activePurchase.productRef) {
|
|
3698
3740
|
return deriveUsageSnapshot({ used, ...period, limits: null });
|
|
3699
3741
|
}
|
|
@@ -3738,34 +3780,34 @@ function verifyWebhook({
|
|
|
3738
3780
|
secret
|
|
3739
3781
|
}) {
|
|
3740
3782
|
const toleranceSec = 300;
|
|
3741
|
-
if (!signature) throw new
|
|
3783
|
+
if (!signature) throw new import_core14.SolvaPayError("Missing webhook signature");
|
|
3742
3784
|
const parts = signature.split(",");
|
|
3743
3785
|
const tPart = parts.find((p) => p.startsWith("t="));
|
|
3744
3786
|
const v1Part = parts.find((p) => p.startsWith("v1="));
|
|
3745
3787
|
if (!tPart || !v1Part) {
|
|
3746
|
-
throw new
|
|
3788
|
+
throw new import_core14.SolvaPayError("Malformed webhook signature");
|
|
3747
3789
|
}
|
|
3748
3790
|
const timestamp = parseInt(tPart.slice(2), 10);
|
|
3749
3791
|
const receivedHmac = v1Part.slice(3);
|
|
3750
3792
|
if (Number.isNaN(timestamp) || !receivedHmac) {
|
|
3751
|
-
throw new
|
|
3793
|
+
throw new import_core14.SolvaPayError("Malformed webhook signature");
|
|
3752
3794
|
}
|
|
3753
3795
|
if (toleranceSec > 0) {
|
|
3754
3796
|
const age = Math.abs(Math.floor(Date.now() / 1e3) - timestamp);
|
|
3755
3797
|
if (age > toleranceSec) {
|
|
3756
|
-
throw new
|
|
3798
|
+
throw new import_core14.SolvaPayError("Webhook signature timestamp too old");
|
|
3757
3799
|
}
|
|
3758
3800
|
}
|
|
3759
3801
|
const expectedHmac = import_node_crypto.default.createHmac("sha256", secret).update(`${timestamp}.${body}`).digest("hex");
|
|
3760
3802
|
if (receivedHmac.length !== expectedHmac.length) {
|
|
3761
|
-
throw new
|
|
3803
|
+
throw new import_core14.SolvaPayError("Invalid webhook signature");
|
|
3762
3804
|
}
|
|
3763
3805
|
const ok = import_node_crypto.default.timingSafeEqual(Buffer.from(expectedHmac), Buffer.from(receivedHmac));
|
|
3764
|
-
if (!ok) throw new
|
|
3806
|
+
if (!ok) throw new import_core14.SolvaPayError("Invalid webhook signature");
|
|
3765
3807
|
try {
|
|
3766
3808
|
return JSON.parse(body);
|
|
3767
3809
|
} catch {
|
|
3768
|
-
throw new
|
|
3810
|
+
throw new import_core14.SolvaPayError("Invalid webhook payload: body is not valid JSON");
|
|
3769
3811
|
}
|
|
3770
3812
|
}
|
|
3771
3813
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/index.d.cts
CHANGED
|
@@ -254,6 +254,15 @@ interface components {
|
|
|
254
254
|
};
|
|
255
255
|
CheckLimitRequest: {
|
|
256
256
|
customerRef: string;
|
|
257
|
+
/** @description SDK-only free-tool allowance. Authenticated by the provider secret key, so `cap` is the provider's own declaration, not customer input. */
|
|
258
|
+
freeAllowance?: {
|
|
259
|
+
cap?: number;
|
|
260
|
+
/** @description Free meter name. Must match `/^free-[a-z0-9-]+$/`. */
|
|
261
|
+
meter?: string;
|
|
262
|
+
/** @enum {string} */
|
|
263
|
+
scope?: 'rolling_window' | 'lifetime';
|
|
264
|
+
windowDays?: number;
|
|
265
|
+
};
|
|
257
266
|
includeCheckoutSession?: boolean;
|
|
258
267
|
meterName?: string;
|
|
259
268
|
productRef: string;
|
|
@@ -909,7 +918,7 @@ interface components {
|
|
|
909
918
|
* Authoritative paywall classification shared with Managed MCP. Present on denial responses only.
|
|
910
919
|
* @enum {string}
|
|
911
920
|
*/
|
|
912
|
-
paywallReason?: 'activation_required' | 'topup_required' | 'payment_required';
|
|
921
|
+
paywallReason?: 'activation_required' | 'topup_required' | 'payment_required' | 'limit_reached';
|
|
913
922
|
/** @description Display name of the active or default plan */
|
|
914
923
|
planName?: string;
|
|
915
924
|
/** @description Active plan reference when the customer already holds a purchase */
|
|
@@ -3919,6 +3928,16 @@ type AttachBusinessDetailsParams = {
|
|
|
3919
3928
|
} & components['schemas']['BusinessDetailsDto'];
|
|
3920
3929
|
type AttachBusinessDetailsResult = components['schemas']['AttachBusinessDetailsResponse'];
|
|
3921
3930
|
type CheckLimitsRequest = components['schemas']['CheckLimitRequest'];
|
|
3931
|
+
/**
|
|
3932
|
+
* Per-customer cap declared in code on a `registerFree` tool. Not a
|
|
3933
|
+
* registered `Meter` — the name must match `/^free-[a-z0-9-]+$/`.
|
|
3934
|
+
*
|
|
3935
|
+
* Derived from `CheckLimitRequest.freeAllowance`. nestjs-zod omits
|
|
3936
|
+
* nested `required`, so OpenAPI marks every property optional; the
|
|
3937
|
+
* object schema only treats `windowDays` as optional.
|
|
3938
|
+
*/
|
|
3939
|
+
type GeneratedFreeAllowance = NonNullable<CheckLimitsRequest['freeAllowance']>;
|
|
3940
|
+
type FreeLimit = Required<Omit<GeneratedFreeAllowance, 'windowDays'>> & Pick<GeneratedFreeAllowance, 'windowDays'>;
|
|
3922
3941
|
/**
|
|
3923
3942
|
* `LimitResponse` plus a deprecated SDK-only `plan` alias.
|
|
3924
3943
|
*
|
|
@@ -4242,6 +4261,11 @@ interface PaywallMetadata {
|
|
|
4242
4261
|
* attributable. Set by `registerPayable` / `buildPayableHandler`.
|
|
4243
4262
|
*/
|
|
4244
4263
|
toolName?: string;
|
|
4264
|
+
/**
|
|
4265
|
+
* SDK-only free-tool allowance. When set, `decide()` sends this as
|
|
4266
|
+
* `freeAllowance` and the free meter wins over `meterName`.
|
|
4267
|
+
*/
|
|
4268
|
+
freeLimit?: FreeLimit;
|
|
4245
4269
|
}
|
|
4246
4270
|
/**
|
|
4247
4271
|
* Structured content for paywall errors (MCP structuredContent and manual handling).
|
|
@@ -4278,9 +4302,9 @@ type PaywallGateRecoveryFields = {
|
|
|
4278
4302
|
creditBalance?: number;
|
|
4279
4303
|
/**
|
|
4280
4304
|
* `PaywallState.kind` — same vocabulary as the classifier, not a third enum.
|
|
4281
|
-
* `upgrade_required` / `
|
|
4282
|
-
*
|
|
4283
|
-
*
|
|
4305
|
+
* `upgrade_required` / `reactivation_required` are SDK-only. The
|
|
4306
|
+
* backend's `paywallReason` covers `activation_required` /
|
|
4307
|
+
* `topup_required` / `payment_required` / `limit_reached`.
|
|
4284
4308
|
*/
|
|
4285
4309
|
reason?: PaywallReason;
|
|
4286
4310
|
/** Single primary recovery the agent should take. */
|
|
@@ -4404,6 +4428,7 @@ type PaywallDecision<T> = {
|
|
|
4404
4428
|
* Types for configuring various aspects of the SDK including retry behavior,
|
|
4405
4429
|
* payable protection, and framework adapters.
|
|
4406
4430
|
*/
|
|
4431
|
+
|
|
4407
4432
|
/**
|
|
4408
4433
|
* Retry configuration options
|
|
4409
4434
|
*/
|
|
@@ -4482,6 +4507,11 @@ interface PayableOptions {
|
|
|
4482
4507
|
* Product reference (alias for product, preferred for consistency with backend API)
|
|
4483
4508
|
*/
|
|
4484
4509
|
productRef?: string;
|
|
4510
|
+
/**
|
|
4511
|
+
* SDK-only free-tool allowance. When set, this meter's name wins over
|
|
4512
|
+
* `meterName` / `usageType`, and `checkLimits` sends a `freeAllowance` block.
|
|
4513
|
+
*/
|
|
4514
|
+
freeLimit?: FreeLimit;
|
|
4485
4515
|
/**
|
|
4486
4516
|
* Meter to charge against (defaults to `requests`).
|
|
4487
4517
|
*/
|
|
@@ -5042,14 +5072,7 @@ interface SolvaPay {
|
|
|
5042
5072
|
* }
|
|
5043
5073
|
* ```
|
|
5044
5074
|
*/
|
|
5045
|
-
checkLimits(params:
|
|
5046
|
-
customerRef: string;
|
|
5047
|
-
productRef: string;
|
|
5048
|
-
planRef?: string;
|
|
5049
|
-
meterName?: string;
|
|
5050
|
-
/** @deprecated Use `meterName`. */
|
|
5051
|
-
usageType?: string;
|
|
5052
|
-
}): Promise<LimitResponseWithPlan>;
|
|
5075
|
+
checkLimits(params: CheckLimitsRequest): Promise<LimitResponseWithPlan>;
|
|
5053
5076
|
/**
|
|
5054
5077
|
* Track usage for a customer action.
|
|
5055
5078
|
*
|
|
@@ -5597,8 +5620,8 @@ declare const PaywallStructuredContentSchema: z.ZodDiscriminatedUnion<[z.ZodObje
|
|
|
5597
5620
|
topup_required: "topup_required";
|
|
5598
5621
|
payment_required: "payment_required";
|
|
5599
5622
|
activation_required: "activation_required";
|
|
5600
|
-
upgrade_required: "upgrade_required";
|
|
5601
5623
|
limit_reached: "limit_reached";
|
|
5624
|
+
upgrade_required: "upgrade_required";
|
|
5602
5625
|
reactivation_required: "reactivation_required";
|
|
5603
5626
|
}>>;
|
|
5604
5627
|
nextAction: z.ZodOptional<z.ZodEnum<{
|
|
@@ -5646,8 +5669,8 @@ declare const PaywallStructuredContentSchema: z.ZodDiscriminatedUnion<[z.ZodObje
|
|
|
5646
5669
|
topup_required: "topup_required";
|
|
5647
5670
|
payment_required: "payment_required";
|
|
5648
5671
|
activation_required: "activation_required";
|
|
5649
|
-
upgrade_required: "upgrade_required";
|
|
5650
5672
|
limit_reached: "limit_reached";
|
|
5673
|
+
upgrade_required: "upgrade_required";
|
|
5651
5674
|
reactivation_required: "reactivation_required";
|
|
5652
5675
|
}>>;
|
|
5653
5676
|
nextAction: z.ZodOptional<z.ZodEnum<{
|
|
@@ -5728,7 +5751,9 @@ declare function nextActionFor(state: PaywallState): PaywallNextAction;
|
|
|
5728
5751
|
*
|
|
5729
5752
|
* Precedence:
|
|
5730
5753
|
* 1. `activationRequired` / `paywallReason === 'activation_required'`.
|
|
5731
|
-
* 2. `paywallReason === '
|
|
5754
|
+
* 2. `paywallReason === 'limit_reached'` — free-allowance exhaustion
|
|
5755
|
+
* (no purchaseRef / planRef) must not fall through to upgrade_required.
|
|
5756
|
+
* 3. `paywallReason === 'topup_required'` — backend stays authoritative
|
|
5732
5757
|
* for credit-based denials (same rule as Managed MCP).
|
|
5733
5758
|
* 3. Authoritative `needsTopUp` / `needsUpgrade` flags from `decideLimit`.
|
|
5734
5759
|
* 4. Credit-field presence + a real shortfall (`balance < cost`).
|
|
@@ -6555,4 +6580,4 @@ declare function verifyWebhook({ body, signature, secret, }: {
|
|
|
6555
6580
|
secret: string;
|
|
6556
6581
|
}): WebhookEvent;
|
|
6557
6582
|
|
|
6558
|
-
export { type ActivatePlanResult, type AssignCreditsRequest, type AssignCreditsResponse, type AttachBusinessDetailsParams, type AttachBusinessDetailsResult, type AuthenticatedUser, type AutoRechargeConfig, type AutoRechargeDisplayBlock, type AutoRechargeInput, type AutoRechargeResponse, BALANCE_RECONCILE_DELAYS_MS, type ConfigureMcpPlansRequest, type ConfigureMcpPlansResponse, type CreateSolvaPayConfig, type CreditActivityEntry, type CreditActivityResult, type CreditActivityType, type CreditDebitResult, type CreditDebitSkipReason, type CreditDisplayBlock, type CreditSignals, type CustomerBalanceResult, type CustomerResponseMapped, type CustomerWebhookObject, type ErrorResult, type GetHistoryResult, type GetUsageResult, type HttpAdapterOptions, type LimitActivationBalance, type LimitActivationProduct, type LimitAutoRechargeDto, type LimitPlanSummary, type LimitResponseWithPlan, type McpBootstrapPlanInput, type McpBootstrapRequest, type McpBootstrapResponse, type McpServerLike, type McpToolPlanMappingInput, type NextAdapterOptions, type OneTimePurchaseInfo, type PayableAllowResult, type PayableFunction, type PayableGateOptions, type PayableGateResult, type PayableOptions, type PayablePaywallResult, type PaymentMethodInfo, type PaywallArgs, type PaywallDecision, PaywallError, type PaywallGateRecoveryFields, type PaywallMetadata, type PaywallNextAction, type PaywallReason, type PaywallState, type PaywallStructuredContent, PaywallStructuredContentSchema, type ProcessPaymentResult, type ProductConfigurationStatus, type ProtectHandlerContext, type PurchaseCheckResult, type PurchaseInfo, type RegisterVirtualToolsMcpOptions, type RetryOptions, type SaveAutoRechargeInput, type SaveAutoRechargeResponse, type SdkMerchantResponse, type SdkProductResponse, type ServerClientOptions, type SolvaPay, type SolvaPayClient, TOPUP_BALANCE_POLL_DELAYS_MS, type ToolPlanMappingInput, type TopupProcessResult, type TrackUsageBulkRequest, type TrackUsageBulkResponse, type TrackUsageRequest, type TrackUsageResponse, type UsageLimitsInput, VIRTUAL_TOOL_DEFINITIONS, type VerifyProductConfigurationOptions, type VirtualToolDefinition, type VirtualToolsOptions, type WebhookEvent, type WebhookEventForType, type WebhookEventObjectMap, type WebhookEventType, type WebhookProduct, activatePlanCore, attachBusinessDetailsCore, buildGateMessage, buildNudgeMessage, buildPaywallGate, cancelPurchaseCore, checkLimitsCore, checkPurchaseCore, classifyPaywallState, type components, createCheckoutSessionCore, createCustomerSessionCore, createPaymentIntentCore, createSolvaPay, createSolvaPayClient, createTopupPaymentIntentCore, createVirtualTools, creditSignals, deriveUsageSnapshot, disableAutoRechargeCore, getAuthenticatedUserCore, getAutoRechargeCore, getCustomerBalanceCore, getHistoryCore, getMerchantCore, getPaymentMethodCore, getProductCore, getUsageCore, handleRouteError, isErrorResult, isPaywallStructuredContent, jsonSchemaToZodRawShape, linkLabel, listPlansCore, nextActionFor, paywallErrorToClientPayload, planLadder, pollBalanceUntilIncreased, processPaymentIntentCore, processTopupPaymentIntentCore, reactivatePurchaseCore, registerVirtualToolsMcpImpl, saveAutoRechargeCore, syncCustomerCore, trackUsageCore, verifyProductConfiguration, verifyWebhook, withRetry };
|
|
6583
|
+
export { type ActivatePlanResult, type AssignCreditsRequest, type AssignCreditsResponse, type AttachBusinessDetailsParams, type AttachBusinessDetailsResult, type AuthenticatedUser, type AutoRechargeConfig, type AutoRechargeDisplayBlock, type AutoRechargeInput, type AutoRechargeResponse, BALANCE_RECONCILE_DELAYS_MS, type ConfigureMcpPlansRequest, type ConfigureMcpPlansResponse, type CreateSolvaPayConfig, type CreditActivityEntry, type CreditActivityResult, type CreditActivityType, type CreditDebitResult, type CreditDebitSkipReason, type CreditDisplayBlock, type CreditSignals, type CustomerBalanceResult, type CustomerResponseMapped, type CustomerWebhookObject, type ErrorResult, type FreeLimit, type GetHistoryResult, type GetUsageResult, type HttpAdapterOptions, type LimitActivationBalance, type LimitActivationProduct, type LimitAutoRechargeDto, type LimitPlanSummary, type LimitResponseWithPlan, type McpBootstrapPlanInput, type McpBootstrapRequest, type McpBootstrapResponse, type McpServerLike, type McpToolPlanMappingInput, type NextAdapterOptions, type OneTimePurchaseInfo, type PayableAllowResult, type PayableFunction, type PayableGateOptions, type PayableGateResult, type PayableOptions, type PayablePaywallResult, type PaymentMethodInfo, type PaywallArgs, type PaywallDecision, PaywallError, type PaywallGateRecoveryFields, type PaywallMetadata, type PaywallNextAction, type PaywallReason, type PaywallState, type PaywallStructuredContent, PaywallStructuredContentSchema, type ProcessPaymentResult, type ProductConfigurationStatus, type ProtectHandlerContext, type PurchaseCheckResult, type PurchaseInfo, type RegisterVirtualToolsMcpOptions, type RetryOptions, type SaveAutoRechargeInput, type SaveAutoRechargeResponse, type SdkMerchantResponse, type SdkProductResponse, type ServerClientOptions, type SolvaPay, type SolvaPayClient, TOPUP_BALANCE_POLL_DELAYS_MS, type ToolPlanMappingInput, type TopupProcessResult, type TrackUsageBulkRequest, type TrackUsageBulkResponse, type TrackUsageRequest, type TrackUsageResponse, type UsageLimitsInput, VIRTUAL_TOOL_DEFINITIONS, type VerifyProductConfigurationOptions, type VirtualToolDefinition, type VirtualToolsOptions, type WebhookEvent, type WebhookEventForType, type WebhookEventObjectMap, type WebhookEventType, type WebhookProduct, activatePlanCore, attachBusinessDetailsCore, buildGateMessage, buildNudgeMessage, buildPaywallGate, cancelPurchaseCore, checkLimitsCore, checkPurchaseCore, classifyPaywallState, type components, createCheckoutSessionCore, createCustomerSessionCore, createPaymentIntentCore, createSolvaPay, createSolvaPayClient, createTopupPaymentIntentCore, createVirtualTools, creditSignals, deriveUsageSnapshot, disableAutoRechargeCore, getAuthenticatedUserCore, getAutoRechargeCore, getCustomerBalanceCore, getHistoryCore, getMerchantCore, getPaymentMethodCore, getProductCore, getUsageCore, handleRouteError, isErrorResult, isPaywallStructuredContent, jsonSchemaToZodRawShape, linkLabel, listPlansCore, nextActionFor, paywallErrorToClientPayload, planLadder, pollBalanceUntilIncreased, processPaymentIntentCore, processTopupPaymentIntentCore, reactivatePurchaseCore, registerVirtualToolsMcpImpl, saveAutoRechargeCore, syncCustomerCore, trackUsageCore, verifyProductConfiguration, verifyWebhook, withRetry };
|