@solvapay/server 1.0.8-preview.9 → 1.0.8
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 +80 -2
- package/dist/edge.d.ts +472 -61
- package/dist/edge.js +576 -187
- package/dist/fetch/index.cjs +3071 -0
- package/dist/fetch/index.d.cts +112 -0
- package/dist/fetch/index.d.ts +112 -0
- package/dist/fetch/index.js +3017 -0
- package/dist/index.cjs +606 -4721
- package/dist/index.d.cts +490 -124
- package/dist/index.d.ts +490 -124
- package/dist/index.js +573 -406
- package/package.json +16 -13
- package/dist/chunk-MLKGABMK.js +0 -9
- package/dist/webapi-K5XBCEO6.js +0 -3775
package/dist/index.d.ts
CHANGED
|
@@ -49,6 +49,58 @@ type WebhookEvent = {
|
|
|
49
49
|
|
|
50
50
|
interface components {
|
|
51
51
|
schemas: {
|
|
52
|
+
SdkMerchantResponseDto: {
|
|
53
|
+
/**
|
|
54
|
+
* Brand name shown in UI
|
|
55
|
+
* @example Acme
|
|
56
|
+
*/
|
|
57
|
+
displayName: string;
|
|
58
|
+
/**
|
|
59
|
+
* Legal entity name used in SCA mandate copy
|
|
60
|
+
* @example Acme Inc.
|
|
61
|
+
*/
|
|
62
|
+
legalName: string;
|
|
63
|
+
/** @example support@acme.com */
|
|
64
|
+
supportEmail?: string;
|
|
65
|
+
/** @example https://acme.com/support */
|
|
66
|
+
supportUrl?: string;
|
|
67
|
+
/** @example https://acme.com/terms */
|
|
68
|
+
termsUrl?: string;
|
|
69
|
+
/** @example https://acme.com/privacy */
|
|
70
|
+
privacyUrl?: string;
|
|
71
|
+
/**
|
|
72
|
+
* ISO-3166 alpha-2 country code of the merchant
|
|
73
|
+
* @example US
|
|
74
|
+
*/
|
|
75
|
+
country?: string;
|
|
76
|
+
/**
|
|
77
|
+
* ISO-4217 default settlement currency
|
|
78
|
+
* @example usd
|
|
79
|
+
*/
|
|
80
|
+
defaultCurrency?: string;
|
|
81
|
+
/**
|
|
82
|
+
* Descriptor appearing on the customer card statement
|
|
83
|
+
* @example ACME INC
|
|
84
|
+
*/
|
|
85
|
+
statementDescriptor?: string;
|
|
86
|
+
/**
|
|
87
|
+
* Absolute URL to the merchant logo
|
|
88
|
+
* @example https://cdn.acme.com/logo.png
|
|
89
|
+
*/
|
|
90
|
+
logoUrl?: string;
|
|
91
|
+
/**
|
|
92
|
+
* Absolute URL to the square app icon / logomark. Consumed by MCP host chromes, mobile avatar slots, and any surface where the landscape `logoUrl` would need letterboxing.
|
|
93
|
+
* @example https://cdn.acme.com/icon.png
|
|
94
|
+
*/
|
|
95
|
+
iconUrl?: string;
|
|
96
|
+
};
|
|
97
|
+
SdkPlatformConfigResponseDto: {
|
|
98
|
+
/**
|
|
99
|
+
* SolvaPay's platform Stripe publishable key for the authenticated provider's environment. Safe to expose browser-side; paired with the connected `accountId` returned from `create-payment-intent` for Stripe Connect direct charges. Omitted when not configured so callers can fall back cleanly to a hosted flow.
|
|
100
|
+
* @example pk_test_...
|
|
101
|
+
*/
|
|
102
|
+
stripePublishableKey?: string;
|
|
103
|
+
};
|
|
52
104
|
CreatePaymentIntentDto: {
|
|
53
105
|
productRef?: string;
|
|
54
106
|
customerRef: string;
|
|
@@ -1047,6 +1099,14 @@ interface components {
|
|
|
1047
1099
|
/** @description Active purchases */
|
|
1048
1100
|
purchases?: components["schemas"]["PurchaseInfo"][];
|
|
1049
1101
|
};
|
|
1102
|
+
UpdateCustomerRequest: {
|
|
1103
|
+
/** Format: email */
|
|
1104
|
+
email?: string;
|
|
1105
|
+
name?: string;
|
|
1106
|
+
telephone?: string;
|
|
1107
|
+
metadata?: unknown;
|
|
1108
|
+
externalRef?: string;
|
|
1109
|
+
};
|
|
1050
1110
|
CreateCustomerSessionResponse: {
|
|
1051
1111
|
/**
|
|
1052
1112
|
* Customer session ID/token
|
|
@@ -1180,6 +1240,53 @@ interface components {
|
|
|
1180
1240
|
pathItems: never;
|
|
1181
1241
|
}
|
|
1182
1242
|
interface operations {
|
|
1243
|
+
getMerchant: {
|
|
1244
|
+
parameters: {
|
|
1245
|
+
query?: never;
|
|
1246
|
+
header?: never;
|
|
1247
|
+
path?: never;
|
|
1248
|
+
cookie?: never;
|
|
1249
|
+
};
|
|
1250
|
+
requestBody?: never;
|
|
1251
|
+
responses: {
|
|
1252
|
+
/** @description Merchant identity */
|
|
1253
|
+
200: {
|
|
1254
|
+
headers: {
|
|
1255
|
+
[name: string]: unknown;
|
|
1256
|
+
};
|
|
1257
|
+
content: {
|
|
1258
|
+
"application/json": components["schemas"]["SdkMerchantResponseDto"];
|
|
1259
|
+
};
|
|
1260
|
+
};
|
|
1261
|
+
/** @description Provider not found */
|
|
1262
|
+
404: {
|
|
1263
|
+
headers: {
|
|
1264
|
+
[name: string]: unknown;
|
|
1265
|
+
};
|
|
1266
|
+
content?: never;
|
|
1267
|
+
};
|
|
1268
|
+
};
|
|
1269
|
+
};
|
|
1270
|
+
getPlatformConfig: {
|
|
1271
|
+
parameters: {
|
|
1272
|
+
query?: never;
|
|
1273
|
+
header?: never;
|
|
1274
|
+
path?: never;
|
|
1275
|
+
cookie?: never;
|
|
1276
|
+
};
|
|
1277
|
+
requestBody?: never;
|
|
1278
|
+
responses: {
|
|
1279
|
+
/** @description Platform config */
|
|
1280
|
+
200: {
|
|
1281
|
+
headers: {
|
|
1282
|
+
[name: string]: unknown;
|
|
1283
|
+
};
|
|
1284
|
+
content: {
|
|
1285
|
+
"application/json": components["schemas"]["SdkPlatformConfigResponseDto"];
|
|
1286
|
+
};
|
|
1287
|
+
};
|
|
1288
|
+
};
|
|
1289
|
+
};
|
|
1183
1290
|
PaymentIntentSdkController_getPaymentIntents: {
|
|
1184
1291
|
parameters: {
|
|
1185
1292
|
query?: {
|
|
@@ -2258,7 +2365,7 @@ interface operations {
|
|
|
2258
2365
|
};
|
|
2259
2366
|
};
|
|
2260
2367
|
};
|
|
2261
|
-
|
|
2368
|
+
CustomerSdkController_getCustomer: {
|
|
2262
2369
|
parameters: {
|
|
2263
2370
|
query?: never;
|
|
2264
2371
|
header?: never;
|
|
@@ -2270,13 +2377,13 @@ interface operations {
|
|
|
2270
2377
|
};
|
|
2271
2378
|
requestBody?: never;
|
|
2272
2379
|
responses: {
|
|
2273
|
-
/** @description Customer
|
|
2380
|
+
/** @description Customer retrieved successfully */
|
|
2274
2381
|
200: {
|
|
2275
2382
|
headers: {
|
|
2276
2383
|
[name: string]: unknown;
|
|
2277
2384
|
};
|
|
2278
2385
|
content: {
|
|
2279
|
-
"application/json":
|
|
2386
|
+
"application/json": components["schemas"]["CustomerResponse"];
|
|
2280
2387
|
};
|
|
2281
2388
|
};
|
|
2282
2389
|
/** @description Customer not found */
|
|
@@ -2290,7 +2397,7 @@ interface operations {
|
|
|
2290
2397
|
};
|
|
2291
2398
|
};
|
|
2292
2399
|
};
|
|
2293
|
-
|
|
2400
|
+
CustomerSdkController_updateCustomer: {
|
|
2294
2401
|
parameters: {
|
|
2295
2402
|
query?: never;
|
|
2296
2403
|
header?: never;
|
|
@@ -2300,9 +2407,14 @@ interface operations {
|
|
|
2300
2407
|
};
|
|
2301
2408
|
cookie?: never;
|
|
2302
2409
|
};
|
|
2303
|
-
|
|
2410
|
+
/** @description Fields to update (all optional) */
|
|
2411
|
+
requestBody: {
|
|
2412
|
+
content: {
|
|
2413
|
+
"application/json": components["schemas"]["UpdateCustomerRequest"];
|
|
2414
|
+
};
|
|
2415
|
+
};
|
|
2304
2416
|
responses: {
|
|
2305
|
-
/** @description Customer
|
|
2417
|
+
/** @description Customer updated successfully */
|
|
2306
2418
|
200: {
|
|
2307
2419
|
headers: {
|
|
2308
2420
|
[name: string]: unknown;
|
|
@@ -2311,6 +2423,43 @@ interface operations {
|
|
|
2311
2423
|
"application/json": components["schemas"]["CustomerResponse"];
|
|
2312
2424
|
};
|
|
2313
2425
|
};
|
|
2426
|
+
/** @description Invalid update payload */
|
|
2427
|
+
400: {
|
|
2428
|
+
headers: {
|
|
2429
|
+
[name: string]: unknown;
|
|
2430
|
+
};
|
|
2431
|
+
content?: never;
|
|
2432
|
+
};
|
|
2433
|
+
/** @description Customer not found */
|
|
2434
|
+
404: {
|
|
2435
|
+
headers: {
|
|
2436
|
+
[name: string]: unknown;
|
|
2437
|
+
};
|
|
2438
|
+
content?: never;
|
|
2439
|
+
};
|
|
2440
|
+
};
|
|
2441
|
+
};
|
|
2442
|
+
CustomerSdkController_getCustomerBalance: {
|
|
2443
|
+
parameters: {
|
|
2444
|
+
query?: never;
|
|
2445
|
+
header?: never;
|
|
2446
|
+
path: {
|
|
2447
|
+
/** @description Customer reference identifier */
|
|
2448
|
+
reference: string;
|
|
2449
|
+
};
|
|
2450
|
+
cookie?: never;
|
|
2451
|
+
};
|
|
2452
|
+
requestBody?: never;
|
|
2453
|
+
responses: {
|
|
2454
|
+
/** @description Customer balance retrieved successfully */
|
|
2455
|
+
200: {
|
|
2456
|
+
headers: {
|
|
2457
|
+
[name: string]: unknown;
|
|
2458
|
+
};
|
|
2459
|
+
content: {
|
|
2460
|
+
"application/json": unknown;
|
|
2461
|
+
};
|
|
2462
|
+
};
|
|
2314
2463
|
/** @description Customer not found */
|
|
2315
2464
|
404: {
|
|
2316
2465
|
headers: {
|
|
@@ -2435,6 +2584,43 @@ interface operations {
|
|
|
2435
2584
|
};
|
|
2436
2585
|
};
|
|
2437
2586
|
};
|
|
2587
|
+
PaymentMethodSdkController_getPaymentMethod: {
|
|
2588
|
+
parameters: {
|
|
2589
|
+
query: {
|
|
2590
|
+
/** @description Customer reference (e.g. `customer_...`). */
|
|
2591
|
+
customerRef: string;
|
|
2592
|
+
};
|
|
2593
|
+
header?: never;
|
|
2594
|
+
path?: never;
|
|
2595
|
+
cookie?: never;
|
|
2596
|
+
};
|
|
2597
|
+
requestBody?: never;
|
|
2598
|
+
responses: {
|
|
2599
|
+
/** @description The customer's default card, or `{ kind: 'none' }` when no card is on file. */
|
|
2600
|
+
200: {
|
|
2601
|
+
headers: {
|
|
2602
|
+
[name: string]: unknown;
|
|
2603
|
+
};
|
|
2604
|
+
content: {
|
|
2605
|
+
"application/json": {
|
|
2606
|
+
/** @enum {string} */
|
|
2607
|
+
kind: "card";
|
|
2608
|
+
/** @example visa */
|
|
2609
|
+
brand: string;
|
|
2610
|
+
/** @example 4242 */
|
|
2611
|
+
last4: string;
|
|
2612
|
+
/** @example 12 */
|
|
2613
|
+
expMonth: number;
|
|
2614
|
+
/** @example 2030 */
|
|
2615
|
+
expYear: number;
|
|
2616
|
+
} | {
|
|
2617
|
+
/** @enum {string} */
|
|
2618
|
+
kind: "none";
|
|
2619
|
+
};
|
|
2620
|
+
};
|
|
2621
|
+
};
|
|
2622
|
+
};
|
|
2623
|
+
};
|
|
2438
2624
|
}
|
|
2439
2625
|
|
|
2440
2626
|
/**
|
|
@@ -2488,24 +2674,29 @@ interface ProcessPaymentResult {
|
|
|
2488
2674
|
status: 'completed';
|
|
2489
2675
|
}
|
|
2490
2676
|
type ActivatePlanResult = components['schemas']['ActivatePlanResponseDto'];
|
|
2677
|
+
/**
|
|
2678
|
+
* SDK-facing payment-method projection returned by
|
|
2679
|
+
* `GET /v1/sdk/payment-method?customerRef=...`.
|
|
2680
|
+
*
|
|
2681
|
+
* Derived from the generated operation response so any backend shape
|
|
2682
|
+
* change propagates through a single `npm run generate:types` run. The
|
|
2683
|
+
* inline `oneOf` schema on the backend controller translates to a clean
|
|
2684
|
+
* `{ kind: 'card', ... } | { kind: 'none' }` discriminated union here.
|
|
2685
|
+
*/
|
|
2686
|
+
type PaymentMethodInfo = operations['PaymentMethodSdkController_getPaymentMethod']['responses']['200']['content']['application/json'];
|
|
2491
2687
|
/**
|
|
2492
2688
|
* SDK-facing merchant identity (source: GET /v1/sdk/merchant).
|
|
2689
|
+
*/
|
|
2690
|
+
type SdkMerchantResponse = components['schemas']['SdkMerchantResponseDto'];
|
|
2691
|
+
/**
|
|
2692
|
+
* SDK-facing platform config (source: GET /v1/sdk/platform-config).
|
|
2493
2693
|
*
|
|
2494
|
-
*
|
|
2495
|
-
*
|
|
2694
|
+
* Environment-aware platform values resolved against the authenticated
|
|
2695
|
+
* provider. Primary consumer today is the MCP checkout app, which uses
|
|
2696
|
+
* `stripePublishableKey` to boot Stripe.js for a CSP probe before a
|
|
2697
|
+
* PaymentIntent exists.
|
|
2496
2698
|
*/
|
|
2497
|
-
type
|
|
2498
|
-
displayName: string;
|
|
2499
|
-
legalName: string;
|
|
2500
|
-
supportEmail?: string;
|
|
2501
|
-
supportUrl?: string;
|
|
2502
|
-
termsUrl?: string;
|
|
2503
|
-
privacyUrl?: string;
|
|
2504
|
-
country?: string;
|
|
2505
|
-
defaultCurrency?: string;
|
|
2506
|
-
statementDescriptor?: string;
|
|
2507
|
-
logoUrl?: string;
|
|
2508
|
-
};
|
|
2699
|
+
type SdkPlatformConfigResponse = components['schemas']['SdkPlatformConfigResponseDto'];
|
|
2509
2700
|
/** SDK-facing product projection. Sourced from the existing OpenAPI spec. */
|
|
2510
2701
|
type SdkProductResponse = components['schemas']['SdkProductResponse'];
|
|
2511
2702
|
type McpBootstrapPlanInput = NonNullable<components['schemas']['McpBootstrapDto']['plans']>[number];
|
|
@@ -2571,6 +2762,21 @@ interface SolvaPayClient {
|
|
|
2571
2762
|
createCustomer?(params: components['schemas']['CreateCustomerRequest']): Promise<{
|
|
2572
2763
|
customerRef: string;
|
|
2573
2764
|
}>;
|
|
2765
|
+
/**
|
|
2766
|
+
* PATCH: /v1/sdk/customers/{customerRef}
|
|
2767
|
+
* Update mutable customer fields. Used by `ensureCustomer` to backfill
|
|
2768
|
+
* `externalRef` on an existing email-matched customer, and exposed
|
|
2769
|
+
* directly for integrators who need it.
|
|
2770
|
+
*/
|
|
2771
|
+
updateCustomer?(customerRef: string, params: {
|
|
2772
|
+
email?: string;
|
|
2773
|
+
name?: string;
|
|
2774
|
+
telephone?: string;
|
|
2775
|
+
metadata?: Record<string, unknown>;
|
|
2776
|
+
externalRef?: string;
|
|
2777
|
+
}): Promise<{
|
|
2778
|
+
customerRef: string;
|
|
2779
|
+
}>;
|
|
2574
2780
|
getCustomer(params: {
|
|
2575
2781
|
customerRef?: string;
|
|
2576
2782
|
externalRef?: string;
|
|
@@ -2582,6 +2788,14 @@ interface SolvaPayClient {
|
|
|
2582
2788
|
* used by `<MandateText>`, `<CheckoutSummary>`, and trust signals.
|
|
2583
2789
|
*/
|
|
2584
2790
|
getMerchant?(): Promise<SdkMerchantResponse>;
|
|
2791
|
+
/**
|
|
2792
|
+
* SDK-facing platform config (GET /v1/sdk/platform-config).
|
|
2793
|
+
* Returns environment-aware browser-safe values (resolved sandbox/live
|
|
2794
|
+
* against the authenticated provider). Primary consumer today is the
|
|
2795
|
+
* MCP checkout app, which uses `stripePublishableKey` to boot Stripe.js
|
|
2796
|
+
* for a CSP probe before a PaymentIntent exists.
|
|
2797
|
+
*/
|
|
2798
|
+
getPlatformConfig?(): Promise<SdkPlatformConfigResponse>;
|
|
2585
2799
|
getProduct?(productRef: string): Promise<SdkProductResponse>;
|
|
2586
2800
|
listProducts?(): Promise<Array<{
|
|
2587
2801
|
reference: string;
|
|
@@ -2661,6 +2875,9 @@ interface SolvaPayClient {
|
|
|
2661
2875
|
createCheckoutSession(params: operations['CheckoutSessionSdkController_createCheckoutSession']['requestBody']['content']['application/json']): Promise<components['schemas']['CreateCheckoutSessionResponse']>;
|
|
2662
2876
|
createCustomerSession(params: components['schemas']['CreateCustomerSessionRequest']): Promise<components['schemas']['CreateCustomerSessionResponse']>;
|
|
2663
2877
|
activatePlan?(params: components['schemas']['ActivatePlanDto']): Promise<ActivatePlanResult>;
|
|
2878
|
+
getPaymentMethod?(params: {
|
|
2879
|
+
customerRef: string;
|
|
2880
|
+
}): Promise<PaymentMethodInfo>;
|
|
2664
2881
|
}
|
|
2665
2882
|
|
|
2666
2883
|
/**
|
|
@@ -2697,6 +2914,15 @@ type PaywallStructuredContent = {
|
|
|
2697
2914
|
product: string;
|
|
2698
2915
|
checkoutUrl: string;
|
|
2699
2916
|
message: string;
|
|
2917
|
+
/**
|
|
2918
|
+
* Quota balance at the moment the paywall tripped. Optional so
|
|
2919
|
+
* older server versions (pre-balance-on-payment_required) stay
|
|
2920
|
+
* compatible; the React `PaywallNotice.Message` prefers this
|
|
2921
|
+
* structured data over the raw `message` when available.
|
|
2922
|
+
*/
|
|
2923
|
+
balance?: LimitActivationBalance;
|
|
2924
|
+
/** Rich product context from checkLimits (name, ref, provider slug/id) */
|
|
2925
|
+
productDetails?: LimitActivationProduct;
|
|
2700
2926
|
} | {
|
|
2701
2927
|
kind: 'activation_required';
|
|
2702
2928
|
/** Product ref from paywall metadata (or env default) */
|
|
@@ -2713,18 +2939,47 @@ type PaywallStructuredContent = {
|
|
|
2713
2939
|
productDetails?: LimitActivationProduct;
|
|
2714
2940
|
};
|
|
2715
2941
|
/**
|
|
2716
|
-
*
|
|
2942
|
+
* Runtime type guard for `PaywallStructuredContent`.
|
|
2943
|
+
*
|
|
2944
|
+
* Used by the MCP registration layer to detect paywall-shaped tool results
|
|
2945
|
+
* coming out of `.mcp()` so it knows whether to attach the `_meta.ui`
|
|
2946
|
+
* envelope that tells MCP hosts which UI resource to open.
|
|
2947
|
+
*
|
|
2948
|
+
* @since 1.0.9
|
|
2717
2949
|
*/
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2950
|
+
declare function isPaywallStructuredContent(value: unknown): value is PaywallStructuredContent;
|
|
2951
|
+
/**
|
|
2952
|
+
* Discriminated union returned from `paywall.decide(args, metadata)` that
|
|
2953
|
+
* surfaces the pre-check outcome as data instead of an exception.
|
|
2954
|
+
*
|
|
2955
|
+
* Replaces the throw-based `PaywallError` control flow adapters previously
|
|
2956
|
+
* relied on: `allow` carries the resolved customer ref + fresh
|
|
2957
|
+
* `LimitResponseWithPlan` so the handler can run, while `gate` carries the
|
|
2958
|
+
* ready-to-serialise `PaywallStructuredContent` so the adapter's
|
|
2959
|
+
* `formatGate` can emit the transport-specific paywall response.
|
|
2960
|
+
*
|
|
2961
|
+
* The `args` field on `allow` is the same shape passed in — threaded
|
|
2962
|
+
* through so callers can hand it directly to the handler without having
|
|
2963
|
+
* to hold onto a reference across the call.
|
|
2964
|
+
*
|
|
2965
|
+
* @since 1.1.0
|
|
2966
|
+
*/
|
|
2967
|
+
type PaywallDecision<T> = {
|
|
2968
|
+
outcome: 'allow';
|
|
2969
|
+
args: T;
|
|
2970
|
+
limits: LimitResponseWithPlan;
|
|
2971
|
+
customerRef: string;
|
|
2972
|
+
} | {
|
|
2973
|
+
outcome: 'gate';
|
|
2974
|
+
gate: PaywallStructuredContent;
|
|
2975
|
+
/**
|
|
2976
|
+
* The `LimitResponseWithPlan` consulted when the gate tripped. May
|
|
2977
|
+
* be `null` on degraded paths that couldn't produce a fresh
|
|
2978
|
+
* response (defensive — normal flow always populates this).
|
|
2979
|
+
*/
|
|
2980
|
+
limits: LimitResponseWithPlan | null;
|
|
2981
|
+
customerRef: string;
|
|
2982
|
+
};
|
|
2728
2983
|
|
|
2729
2984
|
/**
|
|
2730
2985
|
* Configuration Options Type Definitions
|
|
@@ -2765,16 +3020,33 @@ interface RetryOptions {
|
|
|
2765
3020
|
*/
|
|
2766
3021
|
onRetry?: (error: Error, attempt: number) => void;
|
|
2767
3022
|
}
|
|
3023
|
+
/**
|
|
3024
|
+
* Extra context passed into MCP tool handlers — structural copy of
|
|
3025
|
+
* `McpToolExtra` from `@solvapay/mcp` kept here to avoid a build-time
|
|
3026
|
+
* circular dependency between `@solvapay/server` and `@solvapay/mcp`.
|
|
3027
|
+
*
|
|
3028
|
+
* The canonical version lives in `@solvapay/mcp/types.ts`. Keep the two
|
|
3029
|
+
* in lockstep — a `vitest` snapshot in `@solvapay/mcp` guards the
|
|
3030
|
+
* shape.
|
|
3031
|
+
*/
|
|
2768
3032
|
interface McpToolExtra {
|
|
2769
3033
|
authInfo?: {
|
|
2770
|
-
token
|
|
2771
|
-
clientId
|
|
2772
|
-
scopes
|
|
3034
|
+
token?: string;
|
|
3035
|
+
clientId?: string;
|
|
3036
|
+
scopes?: string[];
|
|
2773
3037
|
expiresAt?: number;
|
|
2774
3038
|
extra?: Record<string, unknown>;
|
|
2775
3039
|
};
|
|
2776
3040
|
[key: string]: unknown;
|
|
2777
3041
|
}
|
|
3042
|
+
/**
|
|
3043
|
+
* MCP adapter options — structural copy of `McpAdapterOptions` from
|
|
3044
|
+
* `@solvapay/mcp`.
|
|
3045
|
+
*/
|
|
3046
|
+
interface McpAdapterOptions {
|
|
3047
|
+
getCustomerRef?: (args: any, extra?: McpToolExtra) => string | Promise<string>;
|
|
3048
|
+
transformResponse?: (result: any) => any;
|
|
3049
|
+
}
|
|
2778
3050
|
/**
|
|
2779
3051
|
* Options for configuring payable protection
|
|
2780
3052
|
*/
|
|
@@ -2830,19 +3102,6 @@ interface NextAdapterOptions {
|
|
|
2830
3102
|
*/
|
|
2831
3103
|
transformResponse?: (result: any) => any;
|
|
2832
3104
|
}
|
|
2833
|
-
/**
|
|
2834
|
-
* MCP adapter options for MCP servers
|
|
2835
|
-
*/
|
|
2836
|
-
interface McpAdapterOptions {
|
|
2837
|
-
/**
|
|
2838
|
-
* Extract customer reference from MCP args
|
|
2839
|
-
*/
|
|
2840
|
-
getCustomerRef?: (args: any, extra?: McpToolExtra) => string | Promise<string>;
|
|
2841
|
-
/**
|
|
2842
|
-
* Transform the response before wrapping in MCP format
|
|
2843
|
-
*/
|
|
2844
|
-
transformResponse?: (result: any) => any;
|
|
2845
|
-
}
|
|
2846
3105
|
|
|
2847
3106
|
/**
|
|
2848
3107
|
* Virtual Tools for MCP Server Monetization
|
|
@@ -3602,30 +3861,48 @@ declare function createSolvaPayClient(opts: ServerClientOptions): SolvaPayClient
|
|
|
3602
3861
|
*/
|
|
3603
3862
|
|
|
3604
3863
|
/**
|
|
3605
|
-
* Error
|
|
3864
|
+
* Error representing a paywall gate outcome (purchase required or usage
|
|
3865
|
+
* limit exceeded).
|
|
3606
3866
|
*
|
|
3607
|
-
*
|
|
3608
|
-
*
|
|
3609
|
-
*
|
|
3610
|
-
*
|
|
3867
|
+
* Soft-deprecated since 1.1.0 as the internal control-flow signal —
|
|
3868
|
+
* `paywall.decide()` returns a typed `PaywallDecision<T>` union instead,
|
|
3869
|
+
* and adapters route gate outcomes through `formatGate` without
|
|
3870
|
+
* throwing. `PaywallError` is retained as a compat shim for three paths
|
|
3871
|
+
* that keep working without migration:
|
|
3611
3872
|
*
|
|
3612
|
-
*
|
|
3613
|
-
*
|
|
3873
|
+
* 1. `paywall.protect(handler, ...)` still throws `PaywallError` on
|
|
3874
|
+
* gate outcomes (the legacy throw-based API).
|
|
3875
|
+
* 2. Merchant code that `throw new PaywallError(...)` (or
|
|
3876
|
+
* `ctx.gate(reason)`, which is implemented on top of
|
|
3877
|
+
* `PaywallError`) — caught at the adapter boundary and routed
|
|
3878
|
+
* through `formatGate` so transport responses stay consistent.
|
|
3879
|
+
* 3. Custom third-party adapters that didn't implement `formatGate` —
|
|
3880
|
+
* `AbstractAdapter.formatGate` falls back to wrapping in
|
|
3881
|
+
* `PaywallError` and delegating to `formatError`.
|
|
3614
3882
|
*
|
|
3615
|
-
*
|
|
3883
|
+
* The error includes structured content with checkout URLs and metadata
|
|
3884
|
+
* for building custom paywall UIs.
|
|
3885
|
+
*
|
|
3886
|
+
* @example Preferred (decide()/formatGate)
|
|
3616
3887
|
* ```typescript
|
|
3617
|
-
*
|
|
3888
|
+
* const decision = await solvaPay.paywall.decide(args, { product })
|
|
3889
|
+
* if (decision.outcome === 'gate') {
|
|
3890
|
+
* return res.status(402).json(paywallErrorToClientPayload(
|
|
3891
|
+
* new PaywallError(decision.gate.message, decision.gate),
|
|
3892
|
+
* ))
|
|
3893
|
+
* }
|
|
3894
|
+
* ```
|
|
3618
3895
|
*
|
|
3896
|
+
* @example Compat (try/catch on throw-based legacy path)
|
|
3897
|
+
* ```typescript
|
|
3619
3898
|
* try {
|
|
3620
3899
|
* const result = await payable.http(createTask)(req, res);
|
|
3621
3900
|
* return result;
|
|
3622
3901
|
* } catch (error) {
|
|
3623
3902
|
* if (error instanceof PaywallError) {
|
|
3624
|
-
* // Custom paywall handling
|
|
3625
3903
|
* return res.status(402).json({
|
|
3626
3904
|
* error: error.message,
|
|
3627
3905
|
* checkoutUrl: error.structuredContent.checkoutUrl,
|
|
3628
|
-
* // Additional metadata available in error.structuredContent
|
|
3629
3906
|
* });
|
|
3630
3907
|
* }
|
|
3631
3908
|
* throw error;
|
|
@@ -3633,6 +3910,7 @@ declare function createSolvaPayClient(opts: ServerClientOptions): SolvaPayClient
|
|
|
3633
3910
|
* ```
|
|
3634
3911
|
*
|
|
3635
3912
|
* @see {@link PaywallStructuredContent} for the structured content format
|
|
3913
|
+
* @see {@link PaywallDecision} for the preferred decision-based API
|
|
3636
3914
|
* @since 1.0.0
|
|
3637
3915
|
*/
|
|
3638
3916
|
declare class PaywallError extends Error {
|
|
@@ -3647,76 +3925,114 @@ declare class PaywallError extends Error {
|
|
|
3647
3925
|
}
|
|
3648
3926
|
/** JSON body shape for HTTP adapters and MCP text content (stable fields for clients). */
|
|
3649
3927
|
declare function paywallErrorToClientPayload(error: PaywallError): Record<string, unknown>;
|
|
3650
|
-
|
|
3651
3928
|
/**
|
|
3652
|
-
*
|
|
3929
|
+
* Handler-scoped context passed as the optional second positional
|
|
3930
|
+
* argument to handlers registered via `paywall.protect(...)`.
|
|
3931
|
+
*
|
|
3932
|
+
* Backwards-compatible: existing one-arg handlers `(args) => ...`
|
|
3933
|
+
* ignore the second argument and continue to work.
|
|
3653
3934
|
*
|
|
3654
|
-
*
|
|
3655
|
-
*
|
|
3935
|
+
* Consumed by `@solvapay/mcp`'s `buildPayableHandler` to construct the
|
|
3936
|
+
* `ResponseContext` merchant tools receive as their second argument.
|
|
3656
3937
|
*/
|
|
3657
|
-
|
|
3658
|
-
|
|
3938
|
+
interface ProtectHandlerContext {
|
|
3939
|
+
/** Resolved backend customer ref (`cus_...`). */
|
|
3940
|
+
customerRef: string;
|
|
3941
|
+
/**
|
|
3942
|
+
* The `LimitResponseWithPlan` consulted at pre-check time. Sourced
|
|
3943
|
+
* from either the fresh `checkLimits` call on cache-miss or the
|
|
3944
|
+
* cached entry on cache-hit. `null` only when the paywall is
|
|
3945
|
+
* operating in a degraded mode that couldn't produce a limit
|
|
3946
|
+
* response (defensive; normal flow always populates this).
|
|
3947
|
+
*/
|
|
3948
|
+
limits: LimitResponseWithPlan | null;
|
|
3949
|
+
/**
|
|
3950
|
+
* Transport-level extra passed through adapter chains (e.g. the MCP
|
|
3951
|
+
* adapter's `extra` bag holding `authInfo`). Opaque to `protect()`
|
|
3952
|
+
* itself; forwarded verbatim so adapter-aware handlers can use it.
|
|
3953
|
+
*/
|
|
3954
|
+
extra?: unknown;
|
|
3659
3955
|
}
|
|
3660
|
-
type McpBearerCustomerRefOptions = {
|
|
3661
|
-
claimPriority?: string[];
|
|
3662
|
-
};
|
|
3663
|
-
declare function extractBearerToken(authorization?: string | null): string | null;
|
|
3664
|
-
declare function decodeJwtPayload(token: string): Record<string, unknown>;
|
|
3665
|
-
declare function getCustomerRefFromJwtPayload(payload: Record<string, unknown>, options?: McpBearerCustomerRefOptions): string;
|
|
3666
|
-
declare function getCustomerRefFromBearerAuthHeader(authorization?: string | null, options?: McpBearerCustomerRefOptions): string;
|
|
3667
3956
|
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3957
|
+
/**
|
|
3958
|
+
* Pure state engine that classifies a `LimitResponseWithPlan` into a
|
|
3959
|
+
* recovery-tool-specific `PaywallState`, and produces the human-readable
|
|
3960
|
+
* gate / nudge message templates the MCP transport ships as
|
|
3961
|
+
* `content[0].text` on gate/nudge responses.
|
|
3962
|
+
*
|
|
3963
|
+
* This module has no UI dependencies — it's framework-neutral so
|
|
3964
|
+
* `@solvapay/server`, `@solvapay/mcp-core`, and any HTTP adapter can
|
|
3965
|
+
* reuse the classification + copy. The text-only paywall design puts
|
|
3966
|
+
* the full narration (including a clickable `checkoutUrl` for
|
|
3967
|
+
* terminal-first hosts) on `gate.message`, and names exactly one
|
|
3968
|
+
* primary recovery tool so LLMs chain naturally toward it.
|
|
3969
|
+
*/
|
|
3674
3970
|
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
}
|
|
3687
|
-
|
|
3688
|
-
type Middleware = (req: RequestLike, res: ResponseLike, next: NextLike) => void;
|
|
3689
|
-
interface OAuthAuthorizationServerOptions {
|
|
3690
|
-
apiBaseUrl: string;
|
|
3691
|
-
productRef: string;
|
|
3692
|
-
}
|
|
3693
|
-
interface McpOAuthBridgeOptions {
|
|
3694
|
-
publicBaseUrl: string;
|
|
3695
|
-
apiBaseUrl: string;
|
|
3696
|
-
productRef: string;
|
|
3697
|
-
mcpPath?: string;
|
|
3698
|
-
requireAuth?: boolean;
|
|
3699
|
-
authInfo?: BuildAuthInfoFromBearerOptions;
|
|
3700
|
-
protectedResourcePath?: string;
|
|
3701
|
-
authorizationServerPath?: string;
|
|
3702
|
-
}
|
|
3703
|
-
declare function getOAuthProtectedResourceResponse(publicBaseUrl: string): {
|
|
3704
|
-
resource: string;
|
|
3705
|
-
authorization_servers: string[];
|
|
3706
|
-
scopes_supported: string[];
|
|
3707
|
-
};
|
|
3708
|
-
declare function getOAuthAuthorizationServerResponse({ apiBaseUrl, productRef, }: OAuthAuthorizationServerOptions): {
|
|
3709
|
-
issuer: string;
|
|
3710
|
-
authorization_endpoint: string;
|
|
3711
|
-
token_endpoint: string;
|
|
3712
|
-
registration_endpoint: string;
|
|
3713
|
-
token_endpoint_auth_methods_supported: string[];
|
|
3714
|
-
response_types_supported: string[];
|
|
3715
|
-
grant_types_supported: string[];
|
|
3716
|
-
scopes_supported: string[];
|
|
3717
|
-
code_challenge_methods_supported: string[];
|
|
3971
|
+
/**
|
|
3972
|
+
* Discriminated union describing which recovery path the customer
|
|
3973
|
+
* needs. Every state maps to exactly one primary recovery tool except
|
|
3974
|
+
* `reactivation_required`, which surfaces two alternatives (rare).
|
|
3975
|
+
*/
|
|
3976
|
+
type PaywallState = {
|
|
3977
|
+
kind: 'activation_required';
|
|
3978
|
+
} | {
|
|
3979
|
+
kind: 'topup_required';
|
|
3980
|
+
} | {
|
|
3981
|
+
kind: 'upgrade_required';
|
|
3982
|
+
} | {
|
|
3983
|
+
kind: 'reactivation_required';
|
|
3718
3984
|
};
|
|
3719
|
-
|
|
3985
|
+
/**
|
|
3986
|
+
* Classify a `LimitResponseWithPlan` (or `null` on degraded paths) into
|
|
3987
|
+
* a `PaywallState`. Pure — safe to call multiple times per request.
|
|
3988
|
+
*
|
|
3989
|
+
* Precedence:
|
|
3990
|
+
* 1. `activationRequired === true` — trumps everything else; the
|
|
3991
|
+
* backend explicitly flagged that no plan is live yet.
|
|
3992
|
+
* 2. Usage-based plan out of credits — the customer has a plan but
|
|
3993
|
+
* ran out, so a topup is the right action. "Out of credits" is
|
|
3994
|
+
* determined from (in order): the nested
|
|
3995
|
+
* `balance.creditBalance === 0` block, the top-level
|
|
3996
|
+
* `creditBalance === 0` field, or `remaining === 0` as a
|
|
3997
|
+
* fallback for older backend responses that omit both credit
|
|
3998
|
+
* fields on usage-based plans.
|
|
3999
|
+
* 3. Everything else → `upgrade_required`, including:
|
|
4000
|
+
* - `limits === null` (defensive),
|
|
4001
|
+
* - no active plan on the product,
|
|
4002
|
+
* - recurring plan at period cap (`remaining <= 0`).
|
|
4003
|
+
*
|
|
4004
|
+
* `reactivation_required` is deferred — it needs a distinct backend
|
|
4005
|
+
* signal (future `LimitResponse.inactivePurchaseRef`) which isn't
|
|
4006
|
+
* emitted yet. Kept in the type so downstream code compiles against
|
|
4007
|
+
* the full discriminated union; `classifyPaywallState` will never
|
|
4008
|
+
* return it under current backend behaviour.
|
|
4009
|
+
*/
|
|
4010
|
+
declare function classifyPaywallState(limits: LimitResponseWithPlan | null): PaywallState;
|
|
4011
|
+
/**
|
|
4012
|
+
* Produce the terminal-friendly gate message. Names exactly one
|
|
4013
|
+
* recovery tool (`upgrade` / `topup` / `activate_plan`), except for
|
|
4014
|
+
* the rare `reactivation_required` path which names two alternatives
|
|
4015
|
+
* (`manage_account` / `upgrade`). Inlines `gate.checkoutUrl` when
|
|
4016
|
+
* present so terminal-only MCP hosts (Claude Code, CLI clients) can
|
|
4017
|
+
* open a browser directly.
|
|
4018
|
+
*
|
|
4019
|
+
* Kept as a pure string so the adapter layer can concatenate it with
|
|
4020
|
+
* an optional narrator prefix without parsing structured copy.
|
|
4021
|
+
*/
|
|
4022
|
+
declare function buildGateMessage(state: PaywallState, gate: PaywallStructuredContent): string;
|
|
4023
|
+
/**
|
|
4024
|
+
* Low-balance / approaching-cap nudge copy used as a plain text suffix
|
|
4025
|
+
* on a successful merchant response (no `structuredContent` switch, no
|
|
4026
|
+
* view switch). Mirrors the `buildGateMessage` surface so nudges feel
|
|
4027
|
+
* like a softer version of the same text-only nudge path.
|
|
4028
|
+
*
|
|
4029
|
+
* Receives the `PaywallState` the classifier would have produced if
|
|
4030
|
+
* the customer had tripped the gate. `upgrade_required` and
|
|
4031
|
+
* `topup_required` are the only kinds that currently produce nudge
|
|
4032
|
+
* copy; the others are no-ops (shouldn't happen — nudges only fire
|
|
4033
|
+
* on successful calls).
|
|
4034
|
+
*/
|
|
4035
|
+
declare function buildNudgeMessage(state: PaywallState, limits: LimitResponseWithPlan | null): string;
|
|
3720
4036
|
|
|
3721
4037
|
/**
|
|
3722
4038
|
* Utility functions for the SolvaPay Server SDK
|
|
@@ -3812,8 +4128,16 @@ declare function handleRouteError(error: unknown, operationName: string, default
|
|
|
3812
4128
|
* and name from authenticated requests. Works with any framework that uses
|
|
3813
4129
|
* the standard Web API Request (Express, Fastify, Next.js, Edge Functions, etc.).
|
|
3814
4130
|
*
|
|
3815
|
-
*
|
|
3816
|
-
*
|
|
4131
|
+
* Resolution order:
|
|
4132
|
+
* 1. `x-user-id` header — set by Next.js-style middleware (unchanged).
|
|
4133
|
+
* 2. `Authorization: Bearer <jwt>` — verified via HS256 when a secret is
|
|
4134
|
+
* configured (`SOLVAPAY_JWT_SECRET` or `SUPABASE_JWT_SECRET`), or
|
|
4135
|
+
* unverified-decoded when no secret is configured. The unverified path
|
|
4136
|
+
* covers platforms that verify JWTs at the gateway (e.g. Supabase Edge
|
|
4137
|
+
* with `verify_jwt = true`, which is the default) and asymmetric signing
|
|
4138
|
+
* keys (ES256/RS256) that the SDK does not have keys for.
|
|
4139
|
+
* 3. Set `SOLVAPAY_AUTH_STRICT=true` to require cryptographic verification
|
|
4140
|
+
* inside the handler (the unverified-decode fallback is then disabled).
|
|
3817
4141
|
*
|
|
3818
4142
|
* @param request - Standard Web API Request object
|
|
3819
4143
|
* @param options - Configuration options
|
|
@@ -4133,6 +4457,21 @@ declare function activatePlanCore(request: Request, body: {
|
|
|
4133
4457
|
includeName?: boolean;
|
|
4134
4458
|
}): Promise<ActivatePlanResult | ErrorResult>;
|
|
4135
4459
|
|
|
4460
|
+
/**
|
|
4461
|
+
* Payment-method helpers (core).
|
|
4462
|
+
*
|
|
4463
|
+
* Thin wrapper over `GET /v1/sdk/payment-method`. Extracts the authenticated
|
|
4464
|
+
* user from the request via `syncCustomerCore`, then asks the SolvaPay API
|
|
4465
|
+
* for the customer's default card. Returns `{ kind: 'none' }` gracefully
|
|
4466
|
+
* when no card is on file; any other failure surfaces as an `ErrorResult`.
|
|
4467
|
+
*/
|
|
4468
|
+
|
|
4469
|
+
declare function getPaymentMethodCore(request: Request, options?: {
|
|
4470
|
+
solvaPay?: SolvaPay;
|
|
4471
|
+
includeEmail?: boolean;
|
|
4472
|
+
includeName?: boolean;
|
|
4473
|
+
}): Promise<PaymentMethodInfo | ErrorResult>;
|
|
4474
|
+
|
|
4136
4475
|
/**
|
|
4137
4476
|
* Plans Helper (Core)
|
|
4138
4477
|
*
|
|
@@ -4210,6 +4549,33 @@ declare function checkPurchaseCore(request: Request, options?: {
|
|
|
4210
4549
|
includeName?: boolean;
|
|
4211
4550
|
}): Promise<PurchaseCheckResult | ErrorResult>;
|
|
4212
4551
|
|
|
4552
|
+
/**
|
|
4553
|
+
* Usage snapshot derived from the authenticated customer's active purchase.
|
|
4554
|
+
*
|
|
4555
|
+
* Shape matches the backend's `UserInfoUsageDto` so the React `useUsage`
|
|
4556
|
+
* hook gets a canonical set of fields regardless of transport.
|
|
4557
|
+
*/
|
|
4558
|
+
interface GetUsageResult {
|
|
4559
|
+
meterRef: string | null;
|
|
4560
|
+
total: number | null;
|
|
4561
|
+
used: number;
|
|
4562
|
+
remaining: number | null;
|
|
4563
|
+
/** 0–100, rounded to 2dp. `null` when `total` is unknown. */
|
|
4564
|
+
percentUsed: number | null;
|
|
4565
|
+
periodStart?: string;
|
|
4566
|
+
periodEnd?: string;
|
|
4567
|
+
/** Raw purchase ref the usage belongs to (when a usage-based plan is active). */
|
|
4568
|
+
purchaseRef?: string;
|
|
4569
|
+
}
|
|
4570
|
+
/**
|
|
4571
|
+
* Fetch the authenticated customer's usage snapshot for the active purchase.
|
|
4572
|
+
*
|
|
4573
|
+
* Derives the values from `checkPurchaseCore` — no extra backend call.
|
|
4574
|
+
* Returns `null` values when no usage-based plan is active.
|
|
4575
|
+
*/
|
|
4576
|
+
declare function getUsageCore(request: Request, options?: {
|
|
4577
|
+
solvaPay?: SolvaPay;
|
|
4578
|
+
}): Promise<GetUsageResult | ErrorResult>;
|
|
4213
4579
|
declare function trackUsageCore(request: Request, body: {
|
|
4214
4580
|
actionType?: 'transaction' | 'api_call' | 'hour' | 'email' | 'storage' | 'custom';
|
|
4215
4581
|
units?: number;
|
|
@@ -4277,4 +4643,4 @@ declare function verifyWebhook({ body, signature, secret, }: {
|
|
|
4277
4643
|
secret: string;
|
|
4278
4644
|
}): WebhookEvent;
|
|
4279
4645
|
|
|
4280
|
-
export { type ActivatePlanResult, type AuthenticatedUser, type ConfigureMcpPlansRequest, type ConfigureMcpPlansResponse, type CreateSolvaPayConfig, type CustomerBalanceResult, type CustomerResponseMapped, type CustomerWebhookObject, type ErrorResult, type HttpAdapterOptions, type LimitActivationBalance, type LimitActivationProduct, type LimitPlanSummary, type
|
|
4646
|
+
export { type ActivatePlanResult, type AuthenticatedUser, type ConfigureMcpPlansRequest, type ConfigureMcpPlansResponse, type CreateSolvaPayConfig, type CustomerBalanceResult, type CustomerResponseMapped, type CustomerWebhookObject, type ErrorResult, type GetUsageResult, type HttpAdapterOptions, type LimitActivationBalance, type LimitActivationProduct, type LimitPlanSummary, type LimitResponseWithPlan, type McpBootstrapPlanInput, type McpBootstrapRequest, type McpBootstrapResponse, type McpServerLike, type McpToolPlanMappingInput, type NextAdapterOptions, type OneTimePurchaseInfo, type PayableFunction, type PayableOptions, type PaymentMethodInfo, type PaywallArgs, type PaywallDecision, PaywallError, type PaywallMetadata, type PaywallState, type PaywallStructuredContent, type ProcessPaymentResult, type ProtectHandlerContext, type PurchaseCheckResult, type RegisterVirtualToolsMcpOptions, type RetryOptions, type SdkMerchantResponse, type SdkProductResponse, type ServerClientOptions, type SolvaPay, type SolvaPayClient, type ToolPlanMappingInput, VIRTUAL_TOOL_DEFINITIONS, type VirtualToolDefinition, type VirtualToolsOptions, type WebhookEvent, type WebhookEventForType, type WebhookEventObjectMap, type WebhookEventType, type WebhookProduct, activatePlanCore, buildGateMessage, buildNudgeMessage, cancelPurchaseCore, checkPurchaseCore, classifyPaywallState, type components, createCheckoutSessionCore, createCustomerSessionCore, createPaymentIntentCore, createSolvaPay, createSolvaPayClient, createTopupPaymentIntentCore, createVirtualTools, getAuthenticatedUserCore, getCustomerBalanceCore, getMerchantCore, getPaymentMethodCore, getProductCore, getUsageCore, handleRouteError, isErrorResult, isPaywallStructuredContent, jsonSchemaToZodRawShape, listPlansCore, paywallErrorToClientPayload, processPaymentIntentCore, reactivatePurchaseCore, registerVirtualToolsMcpImpl, syncCustomerCore, trackUsageCore, verifyWebhook, withRetry };
|