@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/fetch/index.cjs
CHANGED
|
@@ -879,6 +879,9 @@ function classifyPaywallState(limits) {
|
|
|
879
879
|
if (limits.activationRequired === true || limits.paywallReason === "activation_required") {
|
|
880
880
|
return { kind: "activation_required" };
|
|
881
881
|
}
|
|
882
|
+
if (limits.paywallReason === "limit_reached") {
|
|
883
|
+
return { kind: "limit_reached" };
|
|
884
|
+
}
|
|
882
885
|
if (limits.paywallReason === "topup_required") {
|
|
883
886
|
return { kind: "topup_required" };
|
|
884
887
|
}
|
|
@@ -942,9 +945,12 @@ function formatCreditsWithMoney(credits, gate) {
|
|
|
942
945
|
}
|
|
943
946
|
return `${amount} credits`;
|
|
944
947
|
}
|
|
948
|
+
function isFreeMeter(name) {
|
|
949
|
+
return typeof name === "string" && name.startsWith("free-");
|
|
950
|
+
}
|
|
945
951
|
function meterLabel(gate) {
|
|
946
952
|
if (!gate.meterName) return "units";
|
|
947
|
-
return gate.meterName.replace(/_/g, " ");
|
|
953
|
+
return gate.meterName.replace(/[_-]/g, " ");
|
|
948
954
|
}
|
|
949
955
|
function namedCheckoutMarkdown(url, label = "Open checkout") {
|
|
950
956
|
return `[${label}](${url})`;
|
|
@@ -980,6 +986,12 @@ function buildGateMessage(state, gate) {
|
|
|
980
986
|
switch (state.kind) {
|
|
981
987
|
case "limit_reached": {
|
|
982
988
|
const included = gate.included;
|
|
989
|
+
if (isFreeMeter(gate.meterName)) {
|
|
990
|
+
const total = included?.total;
|
|
991
|
+
const usedLine2 = total !== void 0 ? `You've used all ${total} ${meterLabel(gate)} for this period.` : `You've used all ${meterLabel(gate)} for this period.`;
|
|
992
|
+
const switchLine2 = ladder ? ` Pick a plan to keep going: ${ladder}. ${callViewer("account").replace(/^c/, "C")} for usage and recovery.` : recoverClause(url, "keep going", "checkout");
|
|
993
|
+
return `${usedLine2}${switchLine2}`;
|
|
994
|
+
}
|
|
983
995
|
const price = gate.unitPriceMinor != null && gate.currency ? formatMinor(gate.unitPriceMinor, gate.currency) : null;
|
|
984
996
|
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.`;
|
|
985
997
|
const nextLine = price ? ` The next call is ${price}.` : "";
|
|
@@ -1282,6 +1294,7 @@ function createRequestDeduplicator(options = {}) {
|
|
|
1282
1294
|
}
|
|
1283
1295
|
|
|
1284
1296
|
// src/paywall.ts
|
|
1297
|
+
var import_core5 = require("@solvapay/core");
|
|
1285
1298
|
var PaywallError = class extends Error {
|
|
1286
1299
|
/**
|
|
1287
1300
|
* Creates a new PaywallError instance.
|
|
@@ -1332,6 +1345,15 @@ var sharedLimitsFetchDeduplicator = createRequestDeduplicator({
|
|
|
1332
1345
|
});
|
|
1333
1346
|
var sharedLimitsFetchClaims = /* @__PURE__ */ new Map();
|
|
1334
1347
|
var EXTRA_FORWARD_KEY = "__solvapayExtra";
|
|
1348
|
+
function trackUsageExtra(metadata, outcome, consequence) {
|
|
1349
|
+
if (metadata.freeLimit) {
|
|
1350
|
+
return { meterName: metadata.freeLimit.meter };
|
|
1351
|
+
}
|
|
1352
|
+
if (outcome === "success") {
|
|
1353
|
+
return { usageClass: consequence === "overage" ? "overage" : "included" };
|
|
1354
|
+
}
|
|
1355
|
+
return void 0;
|
|
1356
|
+
}
|
|
1335
1357
|
var SolvaPayPaywall = class {
|
|
1336
1358
|
constructor(apiClient, options = {}) {
|
|
1337
1359
|
this.apiClient = apiClient;
|
|
@@ -1391,10 +1413,19 @@ var SolvaPayPaywall = class {
|
|
|
1391
1413
|
*/
|
|
1392
1414
|
async decide(args, metadata = {}, getCustomerRef) {
|
|
1393
1415
|
const product = this.resolveProduct(metadata);
|
|
1394
|
-
const usageType = metadata.meterName || metadata.usageType || "requests";
|
|
1416
|
+
const usageType = metadata.freeLimit?.meter || metadata.meterName || metadata.usageType || "requests";
|
|
1395
1417
|
const requestId = this.generateRequestId();
|
|
1396
1418
|
const startTime = Date.now();
|
|
1397
1419
|
const inputCustomerRef = getCustomerRef ? getCustomerRef(args) : args.auth?.customer_ref || "anonymous";
|
|
1420
|
+
if (metadata.freeLimit) {
|
|
1421
|
+
const resolved = typeof inputCustomerRef === "string" ? inputCustomerRef.trim() : "";
|
|
1422
|
+
if (!resolved || resolved === "anonymous") {
|
|
1423
|
+
throw new import_core5.SolvaPayError("identity required", {
|
|
1424
|
+
status: 401,
|
|
1425
|
+
code: "identity_required"
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1398
1429
|
let backendCustomerRef;
|
|
1399
1430
|
if (inputCustomerRef.startsWith("cus_")) {
|
|
1400
1431
|
backendCustomerRef = inputCustomerRef;
|
|
@@ -1445,7 +1476,8 @@ var SolvaPayPaywall = class {
|
|
|
1445
1476
|
// `checkLimitsCore`, which powers the React `useLimits` hook)
|
|
1446
1477
|
// leave this unset and the backend skips the session-creation
|
|
1447
1478
|
// side effect.
|
|
1448
|
-
includeCheckoutSession: true
|
|
1479
|
+
includeCheckoutSession: true,
|
|
1480
|
+
...metadata.freeLimit ? { freeAllowance: metadata.freeLimit } : {}
|
|
1449
1481
|
});
|
|
1450
1482
|
}
|
|
1451
1483
|
);
|
|
@@ -1489,7 +1521,8 @@ var SolvaPayPaywall = class {
|
|
|
1489
1521
|
"paywall",
|
|
1490
1522
|
requestId,
|
|
1491
1523
|
latencyMs,
|
|
1492
|
-
metadata.toolName
|
|
1524
|
+
metadata.toolName,
|
|
1525
|
+
metadata.freeLimit ? { meterName: metadata.freeLimit.meter } : void 0
|
|
1493
1526
|
).catch(() => void 0);
|
|
1494
1527
|
const gate = buildPaywallGate(
|
|
1495
1528
|
product,
|
|
@@ -1536,7 +1569,7 @@ var SolvaPayPaywall = class {
|
|
|
1536
1569
|
*/
|
|
1537
1570
|
async runAllow(decision, handler, metadata, args) {
|
|
1538
1571
|
const product = this.resolveProduct(metadata);
|
|
1539
|
-
const usageType = metadata.meterName || metadata.usageType || "requests";
|
|
1572
|
+
const usageType = metadata.freeLimit?.meter || metadata.meterName || metadata.usageType || "requests";
|
|
1540
1573
|
const requestId = decision.requestId;
|
|
1541
1574
|
const startTime = Date.now();
|
|
1542
1575
|
const forwardedExtra = args[EXTRA_FORWARD_KEY];
|
|
@@ -1555,7 +1588,8 @@ var SolvaPayPaywall = class {
|
|
|
1555
1588
|
"success",
|
|
1556
1589
|
requestId,
|
|
1557
1590
|
latencyMs,
|
|
1558
|
-
metadata.toolName
|
|
1591
|
+
metadata.toolName,
|
|
1592
|
+
trackUsageExtra(metadata, "success", decision.consequence)
|
|
1559
1593
|
).catch(() => void 0);
|
|
1560
1594
|
return result;
|
|
1561
1595
|
} catch (error) {
|
|
@@ -1574,7 +1608,8 @@ var SolvaPayPaywall = class {
|
|
|
1574
1608
|
"fail",
|
|
1575
1609
|
requestId,
|
|
1576
1610
|
latencyMs,
|
|
1577
|
-
metadata.toolName
|
|
1611
|
+
metadata.toolName,
|
|
1612
|
+
trackUsageExtra(metadata, "fail")
|
|
1578
1613
|
).catch(() => void 0);
|
|
1579
1614
|
}
|
|
1580
1615
|
throw error;
|
|
@@ -1765,7 +1800,7 @@ var SolvaPayPaywall = class {
|
|
|
1765
1800
|
}
|
|
1766
1801
|
return backendRef;
|
|
1767
1802
|
}
|
|
1768
|
-
async trackUsage(customerRef, productRef, action, outcome, requestId, actionDuration, toolName) {
|
|
1803
|
+
async trackUsage(customerRef, productRef, action, outcome, requestId, actionDuration, toolName, extra) {
|
|
1769
1804
|
await withRetry(
|
|
1770
1805
|
() => this.apiClient.trackUsage({
|
|
1771
1806
|
customerRef,
|
|
@@ -1778,7 +1813,9 @@ var SolvaPayPaywall = class {
|
|
|
1778
1813
|
metadata: {
|
|
1779
1814
|
action: action || "api_requests",
|
|
1780
1815
|
requestId,
|
|
1781
|
-
...toolName ? { toolName } : {}
|
|
1816
|
+
...toolName ? { toolName } : {},
|
|
1817
|
+
...extra?.meterName ? { meterName: extra.meterName } : {},
|
|
1818
|
+
...extra?.usageClass ? { usageClass: extra.usageClass } : {}
|
|
1782
1819
|
},
|
|
1783
1820
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1784
1821
|
}),
|
|
@@ -2118,7 +2155,7 @@ var McpAdapter = class {
|
|
|
2118
2155
|
};
|
|
2119
2156
|
|
|
2120
2157
|
// src/factory.ts
|
|
2121
|
-
var
|
|
2158
|
+
var import_core6 = require("@solvapay/core");
|
|
2122
2159
|
|
|
2123
2160
|
// src/virtual-tools.ts
|
|
2124
2161
|
var TOOL_GET_USER_INFO = {
|
|
@@ -2359,7 +2396,7 @@ function registerVirtualToolsMcpImpl(server, apiClient, options) {
|
|
|
2359
2396
|
function createSolvaPay(config) {
|
|
2360
2397
|
let resolvedConfig;
|
|
2361
2398
|
if (!config) {
|
|
2362
|
-
const envConfig = (0,
|
|
2399
|
+
const envConfig = (0, import_core6.getSolvaPayConfig)();
|
|
2363
2400
|
resolvedConfig = {
|
|
2364
2401
|
apiKey: envConfig.apiKey,
|
|
2365
2402
|
apiBaseUrl: envConfig.apiBaseUrl
|
|
@@ -2395,25 +2432,25 @@ function createSolvaPay(config) {
|
|
|
2395
2432
|
},
|
|
2396
2433
|
createPaymentIntent(params) {
|
|
2397
2434
|
if (!apiClient.createPaymentIntent) {
|
|
2398
|
-
throw new
|
|
2435
|
+
throw new import_core6.SolvaPayError("createPaymentIntent is not available on this API client");
|
|
2399
2436
|
}
|
|
2400
2437
|
return apiClient.createPaymentIntent(params);
|
|
2401
2438
|
},
|
|
2402
2439
|
createTopupPaymentIntent(params) {
|
|
2403
2440
|
if (!apiClient.createTopupPaymentIntent) {
|
|
2404
|
-
throw new
|
|
2441
|
+
throw new import_core6.SolvaPayError("createTopupPaymentIntent is not available on this API client");
|
|
2405
2442
|
}
|
|
2406
2443
|
return apiClient.createTopupPaymentIntent(params);
|
|
2407
2444
|
},
|
|
2408
2445
|
processPaymentIntent(params) {
|
|
2409
2446
|
if (!apiClient.processPaymentIntent) {
|
|
2410
|
-
throw new
|
|
2447
|
+
throw new import_core6.SolvaPayError("processPaymentIntent is not available on this API client");
|
|
2411
2448
|
}
|
|
2412
2449
|
return apiClient.processPaymentIntent(params);
|
|
2413
2450
|
},
|
|
2414
2451
|
attachBusinessDetails(params) {
|
|
2415
2452
|
if (!apiClient.attachBusinessDetails) {
|
|
2416
|
-
throw new
|
|
2453
|
+
throw new import_core6.SolvaPayError("attachBusinessDetails is not available on this API client");
|
|
2417
2454
|
}
|
|
2418
2455
|
return apiClient.attachBusinessDetails(params);
|
|
2419
2456
|
},
|
|
@@ -2425,13 +2462,13 @@ function createSolvaPay(config) {
|
|
|
2425
2462
|
},
|
|
2426
2463
|
trackUsageBulk(params) {
|
|
2427
2464
|
if (!apiClient.trackUsageBulk) {
|
|
2428
|
-
throw new
|
|
2465
|
+
throw new import_core6.SolvaPayError("trackUsageBulk is not available on this API client");
|
|
2429
2466
|
}
|
|
2430
2467
|
return apiClient.trackUsageBulk(params);
|
|
2431
2468
|
},
|
|
2432
2469
|
createCustomer(params) {
|
|
2433
2470
|
if (!apiClient.createCustomer) {
|
|
2434
|
-
throw new
|
|
2471
|
+
throw new import_core6.SolvaPayError("createCustomer is not available on this API client");
|
|
2435
2472
|
}
|
|
2436
2473
|
return apiClient.createCustomer({ ...params, metadata: params.metadata ?? {} });
|
|
2437
2474
|
},
|
|
@@ -2440,13 +2477,13 @@ function createSolvaPay(config) {
|
|
|
2440
2477
|
},
|
|
2441
2478
|
assignCredits(params) {
|
|
2442
2479
|
if (!apiClient.assignCredits) {
|
|
2443
|
-
throw new
|
|
2480
|
+
throw new import_core6.SolvaPayError("assignCredits is not available on this API client");
|
|
2444
2481
|
}
|
|
2445
2482
|
return apiClient.assignCredits(params);
|
|
2446
2483
|
},
|
|
2447
2484
|
getCustomerBalance(params) {
|
|
2448
2485
|
if (!apiClient.getCustomerBalance) {
|
|
2449
|
-
throw new
|
|
2486
|
+
throw new import_core6.SolvaPayError("getCustomerBalance is not available on this API client");
|
|
2450
2487
|
}
|
|
2451
2488
|
return apiClient.getCustomerBalance(params);
|
|
2452
2489
|
},
|
|
@@ -2464,19 +2501,19 @@ function createSolvaPay(config) {
|
|
|
2464
2501
|
},
|
|
2465
2502
|
activatePlan(params) {
|
|
2466
2503
|
if (!apiClient.activatePlan) {
|
|
2467
|
-
throw new
|
|
2504
|
+
throw new import_core6.SolvaPayError("activatePlan is not available on this API client");
|
|
2468
2505
|
}
|
|
2469
2506
|
return apiClient.activatePlan(params);
|
|
2470
2507
|
},
|
|
2471
2508
|
bootstrapMcpProduct(params) {
|
|
2472
2509
|
if (!apiClient.bootstrapMcpProduct) {
|
|
2473
|
-
throw new
|
|
2510
|
+
throw new import_core6.SolvaPayError("bootstrapMcpProduct is not available on this API client");
|
|
2474
2511
|
}
|
|
2475
2512
|
return apiClient.bootstrapMcpProduct(params);
|
|
2476
2513
|
},
|
|
2477
2514
|
configureMcpPlans(productRef, params) {
|
|
2478
2515
|
if (!apiClient.configureMcpPlans) {
|
|
2479
|
-
throw new
|
|
2516
|
+
throw new import_core6.SolvaPayError("configureMcpPlans is not available on this API client");
|
|
2480
2517
|
}
|
|
2481
2518
|
return apiClient.configureMcpPlans(productRef, params);
|
|
2482
2519
|
},
|
|
@@ -2489,12 +2526,13 @@ function createSolvaPay(config) {
|
|
|
2489
2526
|
// Payable API for framework-specific handlers
|
|
2490
2527
|
payable(options = {}) {
|
|
2491
2528
|
const product = resolveProductRef(options.productRef || options.product);
|
|
2492
|
-
const usageType = options.meterName || options.usageType || "requests";
|
|
2529
|
+
const usageType = options.freeLimit?.meter || options.meterName || options.usageType || "requests";
|
|
2493
2530
|
const metadata = {
|
|
2494
2531
|
product,
|
|
2495
2532
|
meterName: usageType,
|
|
2496
2533
|
usageType,
|
|
2497
|
-
...options.toolName ? { toolName: options.toolName } : {}
|
|
2534
|
+
...options.toolName ? { toolName: options.toolName } : {},
|
|
2535
|
+
...options.freeLimit ? { freeLimit: options.freeLimit } : {}
|
|
2498
2536
|
};
|
|
2499
2537
|
return {
|
|
2500
2538
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -2583,6 +2621,8 @@ function createSolvaPay(config) {
|
|
|
2583
2621
|
const errMeta = opts?.error !== void 0 ? {
|
|
2584
2622
|
error: opts.error instanceof Error ? opts.error.message : String(opts.error)
|
|
2585
2623
|
} : {};
|
|
2624
|
+
const isFree = Boolean(decideMetadata.freeLimit);
|
|
2625
|
+
const usageClass = !isFree && outcome === "success" ? decision.consequence === "overage" ? "overage" : "included" : void 0;
|
|
2586
2626
|
const trackPromise = apiClient.trackUsage({
|
|
2587
2627
|
customerRef,
|
|
2588
2628
|
productRef,
|
|
@@ -2595,6 +2635,8 @@ function createSolvaPay(config) {
|
|
|
2595
2635
|
action: meterName,
|
|
2596
2636
|
requestId,
|
|
2597
2637
|
...decideMetadata.toolName ? { toolName: decideMetadata.toolName } : {},
|
|
2638
|
+
...isFree && decideMetadata.freeLimit ? { meterName: decideMetadata.freeLimit.meter } : {},
|
|
2639
|
+
...usageClass ? { usageClass } : {},
|
|
2598
2640
|
...errMeta,
|
|
2599
2641
|
...opts?.metadata ?? {}
|
|
2600
2642
|
},
|
|
@@ -2667,7 +2709,7 @@ async function getCustomerBalanceCore(request, options = {}) {
|
|
|
2667
2709
|
}
|
|
2668
2710
|
|
|
2669
2711
|
// src/helpers/payment.ts
|
|
2670
|
-
var
|
|
2712
|
+
var import_core7 = require("@solvapay/core");
|
|
2671
2713
|
async function createPaymentIntentCore(request, body, options = {}) {
|
|
2672
2714
|
try {
|
|
2673
2715
|
if (!body.planRef || !body.productRef) {
|
|
@@ -2850,7 +2892,7 @@ async function createCustomerSessionCore(request, options = {}) {
|
|
|
2850
2892
|
}
|
|
2851
2893
|
|
|
2852
2894
|
// src/helpers/renewal.ts
|
|
2853
|
-
var
|
|
2895
|
+
var import_core8 = require("@solvapay/core");
|
|
2854
2896
|
async function cancelPurchaseCore(request, body, options = {}) {
|
|
2855
2897
|
try {
|
|
2856
2898
|
if (!body.purchaseRef) {
|
|
@@ -2896,7 +2938,7 @@ async function cancelPurchaseCore(request, body, options = {}) {
|
|
|
2896
2938
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
2897
2939
|
return cancelledPurchase;
|
|
2898
2940
|
} catch (error) {
|
|
2899
|
-
if (error instanceof
|
|
2941
|
+
if (error instanceof import_core8.SolvaPayError) {
|
|
2900
2942
|
const errorMessage = error.message;
|
|
2901
2943
|
if (errorMessage.includes("not found")) {
|
|
2902
2944
|
return {
|
|
@@ -2964,7 +3006,7 @@ async function reactivatePurchaseCore(request, body, options = {}) {
|
|
|
2964
3006
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
2965
3007
|
return reactivatedPurchase;
|
|
2966
3008
|
} catch (error) {
|
|
2967
|
-
if (error instanceof
|
|
3009
|
+
if (error instanceof import_core8.SolvaPayError) {
|
|
2968
3010
|
const errorMessage = error.message;
|
|
2969
3011
|
if (errorMessage.includes("not found")) {
|
|
2970
3012
|
return {
|
|
@@ -3086,7 +3128,7 @@ async function getHistoryCore(request, input, options = {}) {
|
|
|
3086
3128
|
}
|
|
3087
3129
|
|
|
3088
3130
|
// src/helpers/plans.ts
|
|
3089
|
-
var
|
|
3131
|
+
var import_core9 = require("@solvapay/core");
|
|
3090
3132
|
async function listPlansCore(request, options = {}) {
|
|
3091
3133
|
try {
|
|
3092
3134
|
const url = new URL(request.url);
|
|
@@ -3098,7 +3140,7 @@ async function listPlansCore(request, options = {}) {
|
|
|
3098
3140
|
};
|
|
3099
3141
|
}
|
|
3100
3142
|
const apiClient = options.solvaPay?.apiClient ?? (() => {
|
|
3101
|
-
const config = (0,
|
|
3143
|
+
const config = (0, import_core9.getSolvaPayConfig)();
|
|
3102
3144
|
if (!config.apiKey) return null;
|
|
3103
3145
|
return createSolvaPayClient({
|
|
3104
3146
|
apiKey: config.apiKey,
|
|
@@ -3128,11 +3170,11 @@ async function listPlansCore(request, options = {}) {
|
|
|
3128
3170
|
}
|
|
3129
3171
|
|
|
3130
3172
|
// src/helpers/merchant.ts
|
|
3131
|
-
var
|
|
3173
|
+
var import_core10 = require("@solvapay/core");
|
|
3132
3174
|
async function getMerchantCore(_request, options = {}) {
|
|
3133
3175
|
try {
|
|
3134
3176
|
const apiClient = options.solvaPay?.apiClient ?? (() => {
|
|
3135
|
-
const config = (0,
|
|
3177
|
+
const config = (0, import_core10.getSolvaPayConfig)();
|
|
3136
3178
|
if (!config.apiKey) return null;
|
|
3137
3179
|
return createSolvaPayClient({
|
|
3138
3180
|
apiKey: config.apiKey,
|
|
@@ -3159,7 +3201,7 @@ async function getMerchantCore(_request, options = {}) {
|
|
|
3159
3201
|
}
|
|
3160
3202
|
|
|
3161
3203
|
// src/helpers/product.ts
|
|
3162
|
-
var
|
|
3204
|
+
var import_core11 = require("@solvapay/core");
|
|
3163
3205
|
async function getProductCore(request, options = {}) {
|
|
3164
3206
|
try {
|
|
3165
3207
|
const url = new URL(request.url);
|
|
@@ -3171,7 +3213,7 @@ async function getProductCore(request, options = {}) {
|
|
|
3171
3213
|
};
|
|
3172
3214
|
}
|
|
3173
3215
|
const apiClient = options.solvaPay?.apiClient ?? (() => {
|
|
3174
|
-
const config = (0,
|
|
3216
|
+
const config = (0, import_core11.getSolvaPayConfig)();
|
|
3175
3217
|
if (!config.apiKey) return null;
|
|
3176
3218
|
return createSolvaPayClient({
|
|
3177
3219
|
apiKey: config.apiKey,
|
|
@@ -3254,7 +3296,7 @@ async function checkPurchaseCore(request, options = {}) {
|
|
|
3254
3296
|
}
|
|
3255
3297
|
|
|
3256
3298
|
// src/helpers/usage.ts
|
|
3257
|
-
var
|
|
3299
|
+
var import_core12 = require("@solvapay/core");
|
|
3258
3300
|
async function trackUsageCore(request, body, options = {}) {
|
|
3259
3301
|
try {
|
|
3260
3302
|
const userResult = await getAuthenticatedUserCore(request);
|
|
@@ -3283,7 +3325,7 @@ async function trackUsageCore(request, body, options = {}) {
|
|
|
3283
3325
|
}
|
|
3284
3326
|
|
|
3285
3327
|
// src/edge.ts
|
|
3286
|
-
var
|
|
3328
|
+
var import_core13 = require("@solvapay/core");
|
|
3287
3329
|
function timingSafeEqual(a, b) {
|
|
3288
3330
|
if (a.length !== b.length) return false;
|
|
3289
3331
|
let mismatch = 0;
|
|
@@ -3298,22 +3340,22 @@ async function verifyWebhook({
|
|
|
3298
3340
|
secret
|
|
3299
3341
|
}) {
|
|
3300
3342
|
const toleranceSec = 300;
|
|
3301
|
-
if (!signature) throw new
|
|
3343
|
+
if (!signature) throw new import_core13.SolvaPayError("Missing webhook signature");
|
|
3302
3344
|
const parts = signature.split(",");
|
|
3303
3345
|
const tPart = parts.find((p) => p.startsWith("t="));
|
|
3304
3346
|
const v1Part = parts.find((p) => p.startsWith("v1="));
|
|
3305
3347
|
if (!tPart || !v1Part) {
|
|
3306
|
-
throw new
|
|
3348
|
+
throw new import_core13.SolvaPayError("Malformed webhook signature");
|
|
3307
3349
|
}
|
|
3308
3350
|
const timestamp = parseInt(tPart.slice(2), 10);
|
|
3309
3351
|
const receivedHmac = v1Part.slice(3);
|
|
3310
3352
|
if (Number.isNaN(timestamp) || !receivedHmac) {
|
|
3311
|
-
throw new
|
|
3353
|
+
throw new import_core13.SolvaPayError("Malformed webhook signature");
|
|
3312
3354
|
}
|
|
3313
3355
|
if (toleranceSec > 0) {
|
|
3314
3356
|
const age = Math.abs(Math.floor(Date.now() / 1e3) - timestamp);
|
|
3315
3357
|
if (age > toleranceSec) {
|
|
3316
|
-
throw new
|
|
3358
|
+
throw new import_core13.SolvaPayError("Webhook signature timestamp too old");
|
|
3317
3359
|
}
|
|
3318
3360
|
}
|
|
3319
3361
|
const enc = new TextEncoder();
|
|
@@ -3327,12 +3369,12 @@ async function verifyWebhook({
|
|
|
3327
3369
|
const sigBuf = await crypto.subtle.sign("HMAC", key, enc.encode(`${timestamp}.${body}`));
|
|
3328
3370
|
const expectedHmac = Array.from(new Uint8Array(sigBuf)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
3329
3371
|
if (!timingSafeEqual(expectedHmac, receivedHmac)) {
|
|
3330
|
-
throw new
|
|
3372
|
+
throw new import_core13.SolvaPayError("Invalid webhook signature");
|
|
3331
3373
|
}
|
|
3332
3374
|
try {
|
|
3333
3375
|
return JSON.parse(body);
|
|
3334
3376
|
} catch {
|
|
3335
|
-
throw new
|
|
3377
|
+
throw new import_core13.SolvaPayError("Invalid webhook payload: body is not valid JSON");
|
|
3336
3378
|
}
|
|
3337
3379
|
}
|
|
3338
3380
|
|
package/dist/fetch/index.d.cts
CHANGED
|
@@ -251,6 +251,15 @@ interface components {
|
|
|
251
251
|
};
|
|
252
252
|
CheckLimitRequest: {
|
|
253
253
|
customerRef: string;
|
|
254
|
+
/** @description SDK-only free-tool allowance. Authenticated by the provider secret key, so `cap` is the provider's own declaration, not customer input. */
|
|
255
|
+
freeAllowance?: {
|
|
256
|
+
cap?: number;
|
|
257
|
+
/** @description Free meter name. Must match `/^free-[a-z0-9-]+$/`. */
|
|
258
|
+
meter?: string;
|
|
259
|
+
/** @enum {string} */
|
|
260
|
+
scope?: 'rolling_window' | 'lifetime';
|
|
261
|
+
windowDays?: number;
|
|
262
|
+
};
|
|
254
263
|
includeCheckoutSession?: boolean;
|
|
255
264
|
meterName?: string;
|
|
256
265
|
productRef: string;
|
|
@@ -906,7 +915,7 @@ interface components {
|
|
|
906
915
|
* Authoritative paywall classification shared with Managed MCP. Present on denial responses only.
|
|
907
916
|
* @enum {string}
|
|
908
917
|
*/
|
|
909
|
-
paywallReason?: 'activation_required' | 'topup_required' | 'payment_required';
|
|
918
|
+
paywallReason?: 'activation_required' | 'topup_required' | 'payment_required' | 'limit_reached';
|
|
910
919
|
/** @description Display name of the active or default plan */
|
|
911
920
|
planName?: string;
|
|
912
921
|
/** @description Active plan reference when the customer already holds a purchase */
|
package/dist/fetch/index.d.ts
CHANGED
|
@@ -251,6 +251,15 @@ interface components {
|
|
|
251
251
|
};
|
|
252
252
|
CheckLimitRequest: {
|
|
253
253
|
customerRef: string;
|
|
254
|
+
/** @description SDK-only free-tool allowance. Authenticated by the provider secret key, so `cap` is the provider's own declaration, not customer input. */
|
|
255
|
+
freeAllowance?: {
|
|
256
|
+
cap?: number;
|
|
257
|
+
/** @description Free meter name. Must match `/^free-[a-z0-9-]+$/`. */
|
|
258
|
+
meter?: string;
|
|
259
|
+
/** @enum {string} */
|
|
260
|
+
scope?: 'rolling_window' | 'lifetime';
|
|
261
|
+
windowDays?: number;
|
|
262
|
+
};
|
|
254
263
|
includeCheckoutSession?: boolean;
|
|
255
264
|
meterName?: string;
|
|
256
265
|
productRef: string;
|
|
@@ -906,7 +915,7 @@ interface components {
|
|
|
906
915
|
* Authoritative paywall classification shared with Managed MCP. Present on denial responses only.
|
|
907
916
|
* @enum {string}
|
|
908
917
|
*/
|
|
909
|
-
paywallReason?: 'activation_required' | 'topup_required' | 'payment_required';
|
|
918
|
+
paywallReason?: 'activation_required' | 'topup_required' | 'payment_required' | 'limit_reached';
|
|
910
919
|
/** @description Display name of the active or default plan */
|
|
911
920
|
planName?: string;
|
|
912
921
|
/** @description Active plan reference when the customer already holds a purchase */
|