@solvapay/server 2.3.1 → 2.4.0-preview-11dbbe603cd1b9a44cc41b5eee3686bc4000f97f
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 +50 -17
- package/dist/edge.js +88 -14
- package/dist/fetch/index.cjs +82 -9
- package/dist/fetch/index.js +82 -9
- package/dist/index.cjs +140 -28
- package/dist/index.d.cts +98 -18
- package/dist/index.d.ts +98 -18
- package/dist/index.js +139 -28
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -762,6 +762,8 @@ function createSolvaPayClient(opts) {
|
|
|
762
762
|
}
|
|
763
763
|
|
|
764
764
|
// src/paywall-state.ts
|
|
765
|
+
var CHECKOUT_SESSION_TTL_MINUTES = 15;
|
|
766
|
+
var DOCS_HINT = "See docs://solvapay/overview.md.";
|
|
765
767
|
function classifyPaywallState(limits) {
|
|
766
768
|
if (!limits) return { kind: "upgrade_required" };
|
|
767
769
|
if (limits.activationRequired === true) {
|
|
@@ -782,34 +784,77 @@ function classifyPaywallState(limits) {
|
|
|
782
784
|
return { kind: "topup_required" };
|
|
783
785
|
}
|
|
784
786
|
}
|
|
787
|
+
if (limits.plan.length > 0 && limits.remaining <= 0) {
|
|
788
|
+
return { kind: "limit_reached" };
|
|
789
|
+
}
|
|
785
790
|
return { kind: "upgrade_required" };
|
|
786
791
|
}
|
|
792
|
+
function formatMinor(amountMinor, currency) {
|
|
793
|
+
const major = amountMinor / 100;
|
|
794
|
+
try {
|
|
795
|
+
return new Intl.NumberFormat("en-US", {
|
|
796
|
+
style: "currency",
|
|
797
|
+
currency: currency.toUpperCase(),
|
|
798
|
+
minimumFractionDigits: 2,
|
|
799
|
+
maximumFractionDigits: 2
|
|
800
|
+
}).format(major);
|
|
801
|
+
} catch {
|
|
802
|
+
return `${currency.toUpperCase()} ${major.toFixed(2)}`;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
function meterLabel(gate) {
|
|
806
|
+
if (!gate.meterName) return "units";
|
|
807
|
+
return gate.meterName.replace(/_/g, " ");
|
|
808
|
+
}
|
|
809
|
+
function namedCheckoutMarkdown(url) {
|
|
810
|
+
return `[Open checkout](${url})`;
|
|
811
|
+
}
|
|
812
|
+
var VIEWER_TOOL = "account";
|
|
813
|
+
function callViewer(view) {
|
|
814
|
+
return view ? `call the \`${VIEWER_TOOL}\` tool with view: '${view}'` : `call the \`${VIEWER_TOOL}\` tool`;
|
|
815
|
+
}
|
|
816
|
+
function recoverClause(url, verb, view) {
|
|
817
|
+
if (url) {
|
|
818
|
+
return ` ${namedCheckoutMarkdown(url)} to ${verb} (expires in ${CHECKOUT_SESSION_TTL_MINUTES} minutes), or ${callViewer(view)}.`;
|
|
819
|
+
}
|
|
820
|
+
return ` ${callViewer(view).replace(/^c/, "C")}.`;
|
|
821
|
+
}
|
|
787
822
|
function buildGateMessage(state, gate) {
|
|
788
823
|
const url = gate.checkoutUrl && gate.checkoutUrl.length > 0 ? gate.checkoutUrl : null;
|
|
789
|
-
const openClause = url ? `, or open ${url} in a browser` : "";
|
|
790
824
|
switch (state.kind) {
|
|
825
|
+
case "limit_reached": {
|
|
826
|
+
const included = gate.included;
|
|
827
|
+
const price = gate.unitPriceMinor != null && gate.currency ? formatMinor(gate.unitPriceMinor, gate.currency) : null;
|
|
828
|
+
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.`;
|
|
829
|
+
const nextLine = price ? ` The next call is ${price}.` : "";
|
|
830
|
+
return `${usedLine}${nextLine}${recoverClause(url, "continue", "checkout")} ${DOCS_HINT}`;
|
|
831
|
+
}
|
|
791
832
|
case "activation_required":
|
|
792
|
-
return `Your plan needs activation
|
|
793
|
-
case "topup_required":
|
|
794
|
-
|
|
833
|
+
return `Your plan needs activation.${recoverClause(url, "activate", "checkout")} Or call \`activate_plan\` with a \`planRef\`. ${DOCS_HINT}`;
|
|
834
|
+
case "topup_required": {
|
|
835
|
+
const currency = gate.currency ?? gate.balance?.currency ?? "USD";
|
|
836
|
+
const presets = [1e3, 2500, 5e3, 1e4].map((m) => formatMinor(m, currency)).join(" \xB7 ");
|
|
837
|
+
return `You're out of credits. Top up first (${presets}).${recoverClause(url, "add credits", "topup")} ${DOCS_HINT}`;
|
|
838
|
+
}
|
|
795
839
|
case "upgrade_required":
|
|
796
|
-
return `You don't have an active plan for this tool
|
|
840
|
+
return `You don't have an active plan for this tool.${recoverClause(url, "pick a plan", "checkout")} ${DOCS_HINT}`;
|
|
797
841
|
case "reactivation_required":
|
|
798
|
-
return `Your previous plan is no longer active.
|
|
842
|
+
return `Your previous plan is no longer active. ${callViewer("account").replace(/^c/, "C")} to reactivate it, or ${callViewer("checkout")} to pick a new plan. ${DOCS_HINT}`;
|
|
799
843
|
}
|
|
800
844
|
}
|
|
801
845
|
function buildNudgeMessage(state, limits) {
|
|
802
846
|
const url = limits?.checkoutUrl && limits.checkoutUrl.length > 0 ? limits.checkoutUrl : null;
|
|
803
|
-
const visitClause = url ? `, or
|
|
847
|
+
const visitClause = url ? `, or ${namedCheckoutMarkdown(url)}` : "";
|
|
804
848
|
switch (state.kind) {
|
|
805
849
|
case "topup_required":
|
|
806
|
-
return `Heads up \u2014 running low on credits.
|
|
850
|
+
return `Heads up \u2014 running low on credits. ${callViewer("topup").replace(/^c/, "C")} to add more${visitClause}.`;
|
|
807
851
|
case "upgrade_required":
|
|
808
|
-
|
|
852
|
+
case "limit_reached":
|
|
853
|
+
return `Heads up \u2014 approaching your plan's limit this period. ${callViewer("checkout").replace(/^c/, "C")} for more headroom${visitClause}.`;
|
|
809
854
|
case "activation_required":
|
|
810
|
-
return `Heads up \u2014 this plan still needs activation. Call the \`activate_plan\` tool
|
|
855
|
+
return `Heads up \u2014 this plan still needs activation. Call the \`activate_plan\` tool with a \`planRef\`${visitClause}.`;
|
|
811
856
|
case "reactivation_required":
|
|
812
|
-
return `Heads up \u2014 your plan is no longer active.
|
|
857
|
+
return `Heads up \u2014 your plan is no longer active. ${callViewer("account").replace(/^c/, "C")} to reactivate it${visitClause}.`;
|
|
813
858
|
}
|
|
814
859
|
}
|
|
815
860
|
|
|
@@ -820,26 +865,55 @@ function allPaidPlansArePayg(plans) {
|
|
|
820
865
|
if (paidPlans.length === 0) return false;
|
|
821
866
|
return paidPlans.every((p) => p.type === "usage-based" || p.type === "hybrid");
|
|
822
867
|
}
|
|
868
|
+
function activePlanOf(limits) {
|
|
869
|
+
if (!limits.plan) return void 0;
|
|
870
|
+
return limits.plans?.find((p) => p.reference === limits.plan);
|
|
871
|
+
}
|
|
872
|
+
function includedFromLimits(limits) {
|
|
873
|
+
const total = activePlanOf(limits)?.freeUnits;
|
|
874
|
+
if (total == null || total === 0) return void 0;
|
|
875
|
+
const remaining = limits.remaining;
|
|
876
|
+
return {
|
|
877
|
+
total,
|
|
878
|
+
used: Math.max(0, total - remaining),
|
|
879
|
+
remaining
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
function recoveryFields(limits) {
|
|
883
|
+
const plan = activePlanOf(limits);
|
|
884
|
+
const included = includedFromLimits(limits);
|
|
885
|
+
const creditBalance = limits.balance?.creditBalance ?? limits.creditBalance;
|
|
886
|
+
return {
|
|
887
|
+
...limits.plan ? { planRef: limits.plan } : {},
|
|
888
|
+
...limits.plans !== void 0 ? { plans: limits.plans } : {},
|
|
889
|
+
...limits.meterName !== void 0 ? { meterName: limits.meterName } : {},
|
|
890
|
+
...plan?.perUnitChargeMinor != null ? { unitPriceMinor: plan.perUnitChargeMinor, currency: plan.currency } : limits.currency ? { currency: limits.currency } : {},
|
|
891
|
+
...included ? { included } : {},
|
|
892
|
+
...creditBalance !== void 0 ? { creditBalance } : {}
|
|
893
|
+
};
|
|
894
|
+
}
|
|
823
895
|
function buildPaywallGate(productRef, limits) {
|
|
824
896
|
const checkoutUrl = limits.checkoutUrl;
|
|
825
897
|
const state = classifyPaywallState({ ...limits, plan: limits.plan ?? "" });
|
|
826
898
|
const useActivationForTopup = !limits.activationRequired && state.kind === "topup_required" && allPaidPlansArePayg(limits.plans);
|
|
899
|
+
const recovery = recoveryFields(limits);
|
|
827
900
|
const preMessage = limits.activationRequired || useActivationForTopup ? {
|
|
828
901
|
kind: "activation_required",
|
|
829
902
|
product: productRef,
|
|
830
903
|
message: "",
|
|
831
904
|
checkoutUrl: limits.confirmationUrl || checkoutUrl || "",
|
|
832
905
|
...limits.confirmationUrl !== void 0 ? { confirmationUrl: limits.confirmationUrl } : {},
|
|
833
|
-
...limits.plans !== void 0 ? { plans: limits.plans } : {},
|
|
834
906
|
...limits.balance !== void 0 ? { balance: limits.balance } : {},
|
|
835
|
-
...limits.product !== void 0 ? { productDetails: limits.product } : {}
|
|
907
|
+
...limits.product !== void 0 ? { productDetails: limits.product } : {},
|
|
908
|
+
...recovery
|
|
836
909
|
} : {
|
|
837
910
|
kind: "payment_required",
|
|
838
911
|
product: productRef,
|
|
839
912
|
checkoutUrl: checkoutUrl || "",
|
|
840
913
|
message: "",
|
|
841
914
|
...limits.balance !== void 0 ? { balance: limits.balance } : {},
|
|
842
|
-
...limits.product !== void 0 ? { productDetails: limits.product } : {}
|
|
915
|
+
...limits.product !== void 0 ? { productDetails: limits.product } : {},
|
|
916
|
+
...recovery
|
|
843
917
|
};
|
|
844
918
|
return { ...preMessage, message: buildGateMessage(state, preMessage) };
|
|
845
919
|
}
|
|
@@ -1947,34 +2021,34 @@ function isJsonSchemaObject(value) {
|
|
|
1947
2021
|
return Boolean(value && typeof value === "object");
|
|
1948
2022
|
}
|
|
1949
2023
|
function toZodSchema(property) {
|
|
1950
|
-
const
|
|
2024
|
+
const z2 = getZod();
|
|
1951
2025
|
if (Array.isArray(property.enum) && property.enum.length > 0) {
|
|
1952
2026
|
if (property.enum.every((value) => typeof value === "string")) {
|
|
1953
2027
|
const [first, ...rest] = property.enum;
|
|
1954
|
-
return
|
|
2028
|
+
return z2.enum([first, ...rest]);
|
|
1955
2029
|
}
|
|
1956
2030
|
if (property.enum.length === 1) {
|
|
1957
|
-
return
|
|
2031
|
+
return z2.literal(property.enum[0]);
|
|
1958
2032
|
}
|
|
1959
|
-
return
|
|
2033
|
+
return z2.union(property.enum.map((value) => z2.literal(value)));
|
|
1960
2034
|
}
|
|
1961
2035
|
switch (property.type) {
|
|
1962
2036
|
case "string":
|
|
1963
|
-
return
|
|
2037
|
+
return z2.string();
|
|
1964
2038
|
case "number":
|
|
1965
|
-
return
|
|
2039
|
+
return z2.number();
|
|
1966
2040
|
case "integer":
|
|
1967
|
-
return
|
|
2041
|
+
return z2.number().int();
|
|
1968
2042
|
case "boolean":
|
|
1969
|
-
return
|
|
2043
|
+
return z2.boolean();
|
|
1970
2044
|
case "array":
|
|
1971
|
-
return
|
|
1972
|
-
isJsonSchemaObject(property.items) ? toZodSchema(property.items) :
|
|
2045
|
+
return z2.array(
|
|
2046
|
+
isJsonSchemaObject(property.items) ? toZodSchema(property.items) : z2.any()
|
|
1973
2047
|
);
|
|
1974
2048
|
case "object":
|
|
1975
|
-
return
|
|
2049
|
+
return z2.object(jsonSchemaToZodRawShape(property.properties || {}));
|
|
1976
2050
|
default:
|
|
1977
|
-
return
|
|
2051
|
+
return z2.any();
|
|
1978
2052
|
}
|
|
1979
2053
|
}
|
|
1980
2054
|
function jsonSchemaToZodRawShape(properties, required = []) {
|
|
@@ -2009,12 +2083,12 @@ function registerVirtualToolsMcpImpl(server, apiClient, options) {
|
|
|
2009
2083
|
if (filter && !filter(toolDefinition)) continue;
|
|
2010
2084
|
const mappedDefinition = mapDefinition ? mapDefinition(toolDefinition) : toolDefinition;
|
|
2011
2085
|
const wrappedHandler = wrapHandler ? wrapHandler(mappedDefinition.handler, mappedDefinition) : mappedDefinition.handler;
|
|
2012
|
-
const
|
|
2086
|
+
const z2 = getZod();
|
|
2013
2087
|
server.registerTool(
|
|
2014
2088
|
mappedDefinition.name,
|
|
2015
2089
|
{
|
|
2016
2090
|
description: mappedDefinition.description,
|
|
2017
|
-
inputSchema:
|
|
2091
|
+
inputSchema: z2.object(
|
|
2018
2092
|
jsonSchemaToZodRawShape(
|
|
2019
2093
|
mappedDefinition.inputSchema.properties,
|
|
2020
2094
|
mappedDefinition.inputSchema.required || []
|
|
@@ -2337,6 +2411,42 @@ function isPaywallStructuredContent(value) {
|
|
|
2337
2411
|
return kind === "payment_required" || kind === "activation_required";
|
|
2338
2412
|
}
|
|
2339
2413
|
|
|
2414
|
+
// src/types/paywall-schema.ts
|
|
2415
|
+
import { z } from "zod";
|
|
2416
|
+
var includedSchema = z.object({
|
|
2417
|
+
total: z.number(),
|
|
2418
|
+
used: z.number(),
|
|
2419
|
+
remaining: z.number()
|
|
2420
|
+
});
|
|
2421
|
+
var recoveryFields2 = {
|
|
2422
|
+
planRef: z.string().optional(),
|
|
2423
|
+
plans: z.array(z.record(z.string(), z.unknown())).optional(),
|
|
2424
|
+
meterName: z.string().optional(),
|
|
2425
|
+
unitPriceMinor: z.number().optional(),
|
|
2426
|
+
currency: z.string().optional(),
|
|
2427
|
+
included: includedSchema.optional(),
|
|
2428
|
+
creditBalance: z.number().optional(),
|
|
2429
|
+
balance: z.record(z.string(), z.unknown()).optional(),
|
|
2430
|
+
productDetails: z.record(z.string(), z.unknown()).optional()
|
|
2431
|
+
};
|
|
2432
|
+
var PaywallStructuredContentSchema = z.discriminatedUnion("kind", [
|
|
2433
|
+
z.object({
|
|
2434
|
+
kind: z.literal("payment_required"),
|
|
2435
|
+
product: z.string(),
|
|
2436
|
+
checkoutUrl: z.string(),
|
|
2437
|
+
message: z.string(),
|
|
2438
|
+
...recoveryFields2
|
|
2439
|
+
}),
|
|
2440
|
+
z.object({
|
|
2441
|
+
kind: z.literal("activation_required"),
|
|
2442
|
+
product: z.string(),
|
|
2443
|
+
checkoutUrl: z.string(),
|
|
2444
|
+
message: z.string(),
|
|
2445
|
+
confirmationUrl: z.string().optional(),
|
|
2446
|
+
...recoveryFields2
|
|
2447
|
+
})
|
|
2448
|
+
]);
|
|
2449
|
+
|
|
2340
2450
|
// src/helpers/error.ts
|
|
2341
2451
|
import { SolvaPayError as SolvaPayError5 } from "@solvapay/core";
|
|
2342
2452
|
function isErrorResult(result) {
|
|
@@ -3399,6 +3509,7 @@ function verifyWebhook({
|
|
|
3399
3509
|
export {
|
|
3400
3510
|
BALANCE_RECONCILE_DELAYS_MS,
|
|
3401
3511
|
PaywallError,
|
|
3512
|
+
PaywallStructuredContentSchema,
|
|
3402
3513
|
TOPUP_BALANCE_POLL_DELAYS_MS,
|
|
3403
3514
|
VIRTUAL_TOOL_DEFINITIONS,
|
|
3404
3515
|
activatePlanCore,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solvapay/server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0-preview-11dbbe603cd1b9a44cc41b5eee3686bc4000f97f",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"sideEffects": false,
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@solvapay/core": "1.6.0"
|
|
45
|
+
"@solvapay/core": "1.6.0-preview-11dbbe603cd1b9a44cc41b5eee3686bc4000f97f"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"zod": "^4.2.0",
|