@agent-score/commerce 2.1.0 → 2.2.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/README.md +1 -1
- package/dist/challenge/index.d.mts +2 -2
- package/dist/challenge/index.d.ts +2 -2
- package/dist/challenge/index.js +7 -5
- package/dist/challenge/index.js.map +1 -1
- package/dist/challenge/index.mjs +7 -5
- package/dist/challenge/index.mjs.map +1 -1
- package/dist/{checkout-Bd_4aQ6c.d.mts → checkout-CKQE2QpJ.d.mts} +38 -23
- package/dist/{checkout-BH-I_Ns8.d.ts → checkout-CfgxgPZL.d.ts} +38 -23
- package/dist/core.js +4 -3
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +4 -3
- package/dist/core.mjs.map +1 -1
- package/dist/{default_rails-BxBzcCA1.d.ts → default_rails-C5gKZJMI.d.ts} +11 -1
- package/dist/{default_rails-BWAquZeu.d.mts → default_rails-XFCuRddA.d.mts} +11 -1
- package/dist/discovery/index.d.mts +3 -3
- package/dist/discovery/index.d.ts +3 -3
- package/dist/identity/express.d.mts +4 -3
- package/dist/identity/express.d.ts +4 -3
- package/dist/identity/express.js +4 -3
- package/dist/identity/express.js.map +1 -1
- package/dist/identity/express.mjs +4 -3
- package/dist/identity/express.mjs.map +1 -1
- package/dist/identity/fastify.d.mts +4 -3
- package/dist/identity/fastify.d.ts +4 -3
- package/dist/identity/fastify.js +4 -3
- package/dist/identity/fastify.js.map +1 -1
- package/dist/identity/fastify.mjs +4 -3
- package/dist/identity/fastify.mjs.map +1 -1
- package/dist/identity/hono.d.mts +4 -3
- package/dist/identity/hono.d.ts +4 -3
- package/dist/identity/hono.js +4 -3
- package/dist/identity/hono.js.map +1 -1
- package/dist/identity/hono.mjs +4 -3
- package/dist/identity/hono.mjs.map +1 -1
- package/dist/identity/nextjs.js +4 -3
- package/dist/identity/nextjs.js.map +1 -1
- package/dist/identity/nextjs.mjs +4 -3
- package/dist/identity/nextjs.mjs.map +1 -1
- package/dist/identity/policy.js +22 -23363
- package/dist/identity/policy.js.map +1 -1
- package/dist/identity/policy.mjs +1 -23366
- package/dist/identity/policy.mjs.map +1 -1
- package/dist/identity/web.js +4 -3
- package/dist/identity/web.js.map +1 -1
- package/dist/identity/web.mjs +4 -3
- package/dist/identity/web.mjs.map +1 -1
- package/dist/index.d.mts +73 -6
- package/dist/index.d.ts +73 -6
- package/dist/index.js +392 -148
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +389 -146
- package/dist/index.mjs.map +1 -1
- package/dist/middleware/express.js.map +1 -1
- package/dist/middleware/express.mjs.map +1 -1
- package/dist/middleware/fastify.js.map +1 -1
- package/dist/middleware/fastify.mjs.map +1 -1
- package/dist/middleware/hono.js.map +1 -1
- package/dist/middleware/hono.mjs.map +1 -1
- package/dist/middleware/nextjs.js.map +1 -1
- package/dist/middleware/nextjs.mjs.map +1 -1
- package/dist/middleware/web.js.map +1 -1
- package/dist/middleware/web.mjs.map +1 -1
- package/dist/payment/index.d.mts +13 -17
- package/dist/payment/index.d.ts +13 -17
- package/dist/payment/index.js +80 -4
- package/dist/payment/index.js.map +1 -1
- package/dist/payment/index.mjs +79 -4
- package/dist/payment/index.mjs.map +1 -1
- package/dist/{pricing-4n5Ota0D.d.mts → pricing-dSI3ePmE.d.mts} +4 -2
- package/dist/{pricing-DHfH3ogG.d.ts → pricing-uFGRNoGl.d.ts} +4 -2
- package/dist/stripe-multichain/index.js +55 -5
- package/dist/stripe-multichain/index.js.map +1 -1
- package/dist/stripe-multichain/index.mjs +55 -5
- package/dist/stripe-multichain/index.mjs.map +1 -1
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -20061,11 +20061,12 @@ function toClient(method, options) {
|
|
|
20061
20061
|
};
|
|
20062
20062
|
}
|
|
20063
20063
|
function toServer(method, options) {
|
|
20064
|
-
const { authorize, defaults, html, request, respond, stableBinding, transport, verify: verify3 } = options;
|
|
20064
|
+
const { authorize, defaults, extensions, html, request, respond, stableBinding, transport, verify: verify3 } = options;
|
|
20065
20065
|
return {
|
|
20066
20066
|
...method,
|
|
20067
20067
|
authorize,
|
|
20068
20068
|
defaults,
|
|
20069
|
+
extensions,
|
|
20069
20070
|
html,
|
|
20070
20071
|
request,
|
|
20071
20072
|
respond,
|
|
@@ -20825,6 +20826,7 @@ __export(index_exports, {
|
|
|
20825
20826
|
buildMppxComposeRails: () => buildMppxComposeRails,
|
|
20826
20827
|
buildSignerMismatchBody: () => buildSignerMismatchBody,
|
|
20827
20828
|
buildUCPProfile: () => buildUCPProfile,
|
|
20829
|
+
buildVerificationRequiredBody: () => buildVerificationRequiredBody,
|
|
20828
20830
|
computeFirstCheckout: () => computeFirstCheckout,
|
|
20829
20831
|
createDefaultOnDenied: () => createDefaultOnDenied,
|
|
20830
20832
|
createQuoteCache: () => createQuoteCache,
|
|
@@ -21049,6 +21051,20 @@ var RESERVED_FIELDS = /* @__PURE__ */ new Set([
|
|
|
21049
21051
|
"actual_signer",
|
|
21050
21052
|
"linked_wallets"
|
|
21051
21053
|
]);
|
|
21054
|
+
function buildVerificationRequiredBody(reason, opts = {}) {
|
|
21055
|
+
const body = denialReasonToBody(reason);
|
|
21056
|
+
body.error = {
|
|
21057
|
+
code: "operator_verification_required",
|
|
21058
|
+
message: opts.message ?? "Identity verification is required."
|
|
21059
|
+
};
|
|
21060
|
+
if (opts.agentInstructions !== void 0) {
|
|
21061
|
+
body.agent_instructions = opts.agentInstructions;
|
|
21062
|
+
}
|
|
21063
|
+
if (opts.extra) {
|
|
21064
|
+
for (const [k, v] of Object.entries(opts.extra)) body[k] = v;
|
|
21065
|
+
}
|
|
21066
|
+
return body;
|
|
21067
|
+
}
|
|
21052
21068
|
function denialReasonToBody(reason) {
|
|
21053
21069
|
const message = reason.message ?? DEFAULT_MESSAGES[reason.code];
|
|
21054
21070
|
const body = { error: { code: reason.code, message } };
|
|
@@ -21206,7 +21222,7 @@ function createAgentScoreCore(options) {
|
|
|
21206
21222
|
} = options;
|
|
21207
21223
|
const baseUrl = stripTrailingSlashes(rawBaseUrl);
|
|
21208
21224
|
const agentMemoryHint = buildAgentMemoryHint();
|
|
21209
|
-
const defaultUa = `@agent-score/commerce@${"2.
|
|
21225
|
+
const defaultUa = `@agent-score/commerce@${"2.2.0"}`;
|
|
21210
21226
|
const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
|
|
21211
21227
|
const sdk = new import_sdk.AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
|
|
21212
21228
|
const sessionSdkCache = /* @__PURE__ */ new Map();
|
|
@@ -21343,8 +21359,9 @@ function createAgentScoreCore(options) {
|
|
|
21343
21359
|
...Object.keys(policy).length > 0 ? { policy } : {},
|
|
21344
21360
|
// Pre-extracted payment signer (by the adapter middleware). When present, the API
|
|
21345
21361
|
// composes BOTH signer_match (wallet-binding) and signer_sanctions (OFAC SDN wallet
|
|
21346
|
-
// check) verdicts on the response in one round trip.
|
|
21347
|
-
//
|
|
21362
|
+
// check) verdicts on the response in one round trip. Wallet-OFAC enforcement on the
|
|
21363
|
+
// signer block is unconditional — a signer_sanctions hit flips decision -> deny
|
|
21364
|
+
// regardless of policy.require_sanctions_clear (which gates the separate NAME screen).
|
|
21348
21365
|
...signer && { signer: { address: signer.address, network: signer.network } }
|
|
21349
21366
|
};
|
|
21350
21367
|
const result = identity.address ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken }) : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken });
|
|
@@ -21664,9 +21681,140 @@ var A2A_DEFAULT_TRANSPORT = DEFAULT_TRANSPORT;
|
|
|
21664
21681
|
init_ucp();
|
|
21665
21682
|
init_ucp_jwks();
|
|
21666
21683
|
|
|
21667
|
-
// src/
|
|
21684
|
+
// src/errors.ts
|
|
21685
|
+
var CheckoutValidationError = class extends Error {
|
|
21686
|
+
code;
|
|
21687
|
+
action;
|
|
21688
|
+
status;
|
|
21689
|
+
extra;
|
|
21690
|
+
constructor(opts) {
|
|
21691
|
+
super(opts.message);
|
|
21692
|
+
this.name = "CheckoutValidationError";
|
|
21693
|
+
this.code = opts.code;
|
|
21694
|
+
this.action = opts.action ?? "fix_request";
|
|
21695
|
+
this.status = opts.status ?? 400;
|
|
21696
|
+
this.extra = opts.extra;
|
|
21697
|
+
}
|
|
21698
|
+
};
|
|
21699
|
+
|
|
21700
|
+
// src/identity/policy.ts
|
|
21701
|
+
function buildGateFromPolicy(policy, base) {
|
|
21702
|
+
if (!policy || !policy.enforcement) return null;
|
|
21703
|
+
return {
|
|
21704
|
+
apiKey: base.apiKey,
|
|
21705
|
+
...base.baseUrl !== void 0 && { baseUrl: base.baseUrl },
|
|
21706
|
+
...policy.requireKyc !== void 0 && { requireKyc: policy.requireKyc },
|
|
21707
|
+
...policy.requireSanctionsClear !== void 0 && {
|
|
21708
|
+
requireSanctionsClear: policy.requireSanctionsClear
|
|
21709
|
+
},
|
|
21710
|
+
...policy.minAge !== void 0 && { minAge: policy.minAge },
|
|
21711
|
+
...policy.allowedJurisdictions !== void 0 && {
|
|
21712
|
+
allowedJurisdictions: [...policy.allowedJurisdictions]
|
|
21713
|
+
}
|
|
21714
|
+
};
|
|
21715
|
+
}
|
|
21716
|
+
async function runGateWithEnforcement(enforcement, runGate) {
|
|
21717
|
+
if (!runGate || !enforcement) return { status: "anonymous" };
|
|
21718
|
+
const outcome = await runGate();
|
|
21719
|
+
if (outcome.ok) return { status: "verified" };
|
|
21720
|
+
if (enforcement === "hard") {
|
|
21721
|
+
return {
|
|
21722
|
+
status: "denied",
|
|
21723
|
+
denialStatus: outcome.status,
|
|
21724
|
+
denialBody: outcome.body,
|
|
21725
|
+
...outcome.reason !== void 0 && { denialReason: outcome.reason }
|
|
21726
|
+
};
|
|
21727
|
+
}
|
|
21728
|
+
return {
|
|
21729
|
+
status: "unverified",
|
|
21730
|
+
denialStatus: outcome.status,
|
|
21731
|
+
denialBody: outcome.body,
|
|
21732
|
+
...outcome.reason !== void 0 && { denialReason: outcome.reason }
|
|
21733
|
+
};
|
|
21734
|
+
}
|
|
21735
|
+
function shippingCountryAllowed(country, policy) {
|
|
21736
|
+
if (!policy?.allowedShippingCountries || policy.allowedShippingCountries.length === 0) return true;
|
|
21737
|
+
const allowed = new Set(policy.allowedShippingCountries.map((c) => c.toUpperCase()));
|
|
21738
|
+
return allowed.has(country.toUpperCase());
|
|
21739
|
+
}
|
|
21740
|
+
function shippingStateAllowed(state, country, policy) {
|
|
21741
|
+
if (!policy?.allowedShippingStates || policy.allowedShippingStates.length === 0) return true;
|
|
21742
|
+
if (country.toUpperCase() !== "US") return true;
|
|
21743
|
+
const allowed = new Set(policy.allowedShippingStates.map((s) => s.toUpperCase()));
|
|
21744
|
+
return allowed.has(state.toUpperCase());
|
|
21745
|
+
}
|
|
21746
|
+
function validateShippingAgainstPolicy(opts) {
|
|
21747
|
+
const code = opts.errorCode ?? "unsupported_jurisdiction";
|
|
21748
|
+
const action = opts.errorAction ?? "change_shipping_state";
|
|
21749
|
+
const item = opts.productName ? `'${opts.productName}'` : "this item";
|
|
21750
|
+
if (!shippingCountryAllowed(opts.country, opts.policy)) {
|
|
21751
|
+
throw new CheckoutValidationError({
|
|
21752
|
+
code,
|
|
21753
|
+
message: opts.countryMessage ?? `We can't ship ${item} to ${opts.country.toUpperCase() || "<unset>"}.`,
|
|
21754
|
+
action
|
|
21755
|
+
});
|
|
21756
|
+
}
|
|
21757
|
+
if (!shippingStateAllowed(opts.state, opts.country, opts.policy)) {
|
|
21758
|
+
throw new CheckoutValidationError({
|
|
21759
|
+
code,
|
|
21760
|
+
message: opts.stateMessage ?? `We can't ship ${item} to ${opts.state.toUpperCase() || "<unset>"}.`,
|
|
21761
|
+
action
|
|
21762
|
+
});
|
|
21763
|
+
}
|
|
21764
|
+
}
|
|
21765
|
+
|
|
21766
|
+
// src/identity/tokens.ts
|
|
21668
21767
|
var import_node_crypto = require("crypto");
|
|
21669
21768
|
|
|
21769
|
+
// src/payment/payment_header.ts
|
|
21770
|
+
function toTitleCase(name) {
|
|
21771
|
+
return name.replace(/(^|-)([a-z])/g, (_m, sep, c) => sep + c.toUpperCase());
|
|
21772
|
+
}
|
|
21773
|
+
function readHeader(headers, name) {
|
|
21774
|
+
if (typeof headers.get === "function") {
|
|
21775
|
+
return headers.get(name);
|
|
21776
|
+
}
|
|
21777
|
+
const rec = headers;
|
|
21778
|
+
const v = rec[name] ?? rec[name.toLowerCase()] ?? rec[toTitleCase(name)];
|
|
21779
|
+
if (typeof v === "string") return v;
|
|
21780
|
+
if (Array.isArray(v) && typeof v[0] === "string") return v[0];
|
|
21781
|
+
return null;
|
|
21782
|
+
}
|
|
21783
|
+
function asHeaders(input) {
|
|
21784
|
+
return typeof input.headers === "object" && input instanceof Request ? input.headers : input;
|
|
21785
|
+
}
|
|
21786
|
+
function hasPaymentHeader(input) {
|
|
21787
|
+
const headers = asHeaders(input);
|
|
21788
|
+
return Boolean(
|
|
21789
|
+
readHeader(headers, "payment-signature") || readHeader(headers, "x-payment") || readHeader(headers, "authorization")?.startsWith("Payment ")
|
|
21790
|
+
);
|
|
21791
|
+
}
|
|
21792
|
+
function hasX402Header(input) {
|
|
21793
|
+
const headers = asHeaders(input);
|
|
21794
|
+
return Boolean(readHeader(headers, "payment-signature") || readHeader(headers, "x-payment"));
|
|
21795
|
+
}
|
|
21796
|
+
function hasMppxHeader(input) {
|
|
21797
|
+
const headers = asHeaders(input);
|
|
21798
|
+
return Boolean(readHeader(headers, "authorization")?.startsWith("Payment "));
|
|
21799
|
+
}
|
|
21800
|
+
|
|
21801
|
+
// src/identity/tokens.ts
|
|
21802
|
+
function hashOperatorToken(plaintext) {
|
|
21803
|
+
return (0, import_node_crypto.createHash)("sha256").update(plaintext, "utf8").digest("hex");
|
|
21804
|
+
}
|
|
21805
|
+
function extractOwnerScope(input) {
|
|
21806
|
+
const headers = asHeaders(input);
|
|
21807
|
+
const walletAddress = readHeader(headers, "x-wallet-address");
|
|
21808
|
+
const operatorToken = readHeader(headers, "x-operator-token");
|
|
21809
|
+
return {
|
|
21810
|
+
...walletAddress ? { walletAddress } : {},
|
|
21811
|
+
...operatorToken ? { operatorTokenHash: hashOperatorToken(operatorToken) } : {}
|
|
21812
|
+
};
|
|
21813
|
+
}
|
|
21814
|
+
|
|
21815
|
+
// src/checkout.ts
|
|
21816
|
+
var import_node_crypto2 = require("crypto");
|
|
21817
|
+
|
|
21670
21818
|
// src/_mppx_receipt.ts
|
|
21671
21819
|
function extractMppxReceiptHeaderFromRaw(raw) {
|
|
21672
21820
|
if (!raw || typeof raw !== "object" || !("withReceipt" in raw)) return null;
|
|
@@ -21695,6 +21843,16 @@ async function deriveMppxReceiptMethod(raw) {
|
|
|
21695
21843
|
return extractMppxReceiptMethod(header);
|
|
21696
21844
|
}
|
|
21697
21845
|
|
|
21846
|
+
// src/_warnings.ts
|
|
21847
|
+
var warnedNoApiKey = false;
|
|
21848
|
+
function warnMissingApiKeyOnce(label) {
|
|
21849
|
+
if (warnedNoApiKey) return;
|
|
21850
|
+
warnedNoApiKey = true;
|
|
21851
|
+
console.warn(
|
|
21852
|
+
`[${label}] AGENTSCORE_API_KEY is not set \u2014 wallet OFAC SDN sanctions are NOT being enforced. Set the env var to enable strict-liability protection on settle.`
|
|
21853
|
+
);
|
|
21854
|
+
}
|
|
21855
|
+
|
|
21698
21856
|
// src/payment/rail_spec.ts
|
|
21699
21857
|
init_usdc();
|
|
21700
21858
|
async function resolveRecipient(r) {
|
|
@@ -21926,14 +22084,16 @@ function buildHowToPay({
|
|
|
21926
22084
|
const d = decimals ?? 2;
|
|
21927
22085
|
const defaultMaxSpend = totalNum >= 1 ? (Math.ceil(totalNum) + 1).toFixed(d) : totalNum.toFixed(d);
|
|
21928
22086
|
const maxSpendStr = String(maxSpend ?? defaultMaxSpend);
|
|
22087
|
+
const gateless = opTokenPlaceholder === null;
|
|
21929
22088
|
const opToken = opTokenPlaceholder ?? "<your_opc_token>";
|
|
22089
|
+
const opTokenHeaderFlag = gateless ? "" : `-H 'X-Operator-Token: ${opToken}' `;
|
|
21930
22090
|
const block = {};
|
|
21931
22091
|
if (rails2.tempo) {
|
|
21932
22092
|
const networkName = rails2.tempo.testnet ? "tempo-testnet" : rails2.tempo.network ?? RAIL_SPEC_DEFAULTS.tempo.network;
|
|
21933
22093
|
const chainId = rails2.tempo.chainId ?? RAIL_SPEC_DEFAULTS.tempo.chainId;
|
|
21934
22094
|
const recommend = rails2.tempo.recommend ?? RAIL_SPEC_DEFAULTS.tempo.recommend;
|
|
21935
|
-
const tempoCommand = `tempo request -X POST
|
|
21936
|
-
const payCommand = `agentscore-pay pay POST ${url2} --chain tempo
|
|
22095
|
+
const tempoCommand = `tempo request -X POST ${opTokenHeaderFlag}-H 'Content-Type: application/json' --json '${retryBodyJson}' --max-spend ${maxSpendStr} ${url2}`;
|
|
22096
|
+
const payCommand = `agentscore-pay pay POST ${url2} --chain tempo ${opTokenHeaderFlag}-H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`;
|
|
21937
22097
|
block.tempo = {
|
|
21938
22098
|
setup: TEMPO_SETUP,
|
|
21939
22099
|
prerequisite: `Run \`tempo wallet whoami\` and confirm USDC.e balance on ${networkName} (chain ${chainId}) is at least $${maxSpendStr}. If the tempo CLI is not installed, run the setup commands above first.`,
|
|
@@ -21947,7 +22107,7 @@ function buildHowToPay({
|
|
|
21947
22107
|
block.x402_base = {
|
|
21948
22108
|
setup: PAY_SETUP_BASE,
|
|
21949
22109
|
prerequisite: `Run \`agentscore-pay balance --chain base\` and confirm USDC balance on Base (${network}) is at least $${maxSpendStr}. If the CLI is not installed, run the setup commands above first.`,
|
|
21950
|
-
command: `agentscore-pay pay POST ${url2} --chain base
|
|
22110
|
+
command: `agentscore-pay pay POST ${url2} --chain base ${opTokenHeaderFlag}-H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`,
|
|
21951
22111
|
what_it_does: "Pays via USDC on Base."
|
|
21952
22112
|
};
|
|
21953
22113
|
}
|
|
@@ -21956,7 +22116,7 @@ function buildHowToPay({
|
|
|
21956
22116
|
block.solana_mpp = {
|
|
21957
22117
|
setup: PAY_SETUP_SOLANA,
|
|
21958
22118
|
prerequisite: `Run \`agentscore-pay balance --chain solana\` and confirm USDC balance on Solana (${network}) is at least $${maxSpendStr}. If the CLI is not installed, run the setup commands above first.`,
|
|
21959
|
-
command: `agentscore-pay pay POST ${url2} --chain solana
|
|
22119
|
+
command: `agentscore-pay pay POST ${url2} --chain solana ${opTokenHeaderFlag}-H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`,
|
|
21960
22120
|
what_it_does: "Pays via USDC on Solana."
|
|
21961
22121
|
};
|
|
21962
22122
|
}
|
|
@@ -21978,7 +22138,7 @@ function buildHowToPay({
|
|
|
21978
22138
|
];
|
|
21979
22139
|
stripe.command_link_cli = [
|
|
21980
22140
|
`SPEND_ID=$(link-cli spend-request create --payment-method-id <csmrpd_id_from_payment_methods_list> --credential-type shared_payment_token --network-id ${stripeCfg.profileId} --amount ${amountCents} --context "${sptContext}" --request-approval --output-json | jq -r .id)`,
|
|
21981
|
-
`link-cli mpp pay ${url2} --spend-request-id $SPEND_ID --method POST --data '${retryBodyJson}' --header 'X-Operator-Token: ${opToken}' --output-json`
|
|
22141
|
+
gateless ? `link-cli mpp pay ${url2} --spend-request-id $SPEND_ID --method POST --data '${retryBodyJson}' --output-json` : `link-cli mpp pay ${url2} --spend-request-id $SPEND_ID --method POST --data '${retryBodyJson}' --header 'X-Operator-Token: ${opToken}' --output-json`
|
|
21982
22142
|
];
|
|
21983
22143
|
stripe.what_it_does_link_cli = "Mints a one-time-use SharedPaymentToken scoped to this purchase (user approves in Link wallet), then submits it as the payment credential.";
|
|
21984
22144
|
} else if (linkCliBlocked) {
|
|
@@ -22073,6 +22233,12 @@ function buildValidationError({
|
|
|
22073
22233
|
return body;
|
|
22074
22234
|
}
|
|
22075
22235
|
|
|
22236
|
+
// src/payment/constants.ts
|
|
22237
|
+
var STRIPE_MIN_CHARGE_USD = 0.5;
|
|
22238
|
+
|
|
22239
|
+
// src/payment/mppx_server.ts
|
|
22240
|
+
var import_node_async_hooks = require("async_hooks");
|
|
22241
|
+
|
|
22076
22242
|
// src/stripe-multichain/mppx_stripe.ts
|
|
22077
22243
|
async function createMppxStripe({
|
|
22078
22244
|
profileId,
|
|
@@ -22253,6 +22419,31 @@ function wrapSolanaChargeWithFinalizedBlockhash(baseMethod, rpcUrl) {
|
|
|
22253
22419
|
}
|
|
22254
22420
|
};
|
|
22255
22421
|
}
|
|
22422
|
+
var mppxCapture = new import_node_async_hooks.AsyncLocalStorage();
|
|
22423
|
+
var consoleErrorPatched = false;
|
|
22424
|
+
function ensureConsoleErrorPatch() {
|
|
22425
|
+
if (consoleErrorPatched) return;
|
|
22426
|
+
consoleErrorPatched = true;
|
|
22427
|
+
const original = console.error.bind(console);
|
|
22428
|
+
console.error = function captureMppxInternal(...args) {
|
|
22429
|
+
if (args[0] === "mppx: internal verification error" && args[1] !== void 0) {
|
|
22430
|
+
const ctx = mppxCapture.getStore();
|
|
22431
|
+
if (ctx) {
|
|
22432
|
+
const e = args[1];
|
|
22433
|
+
const reason = typeof e?.shortMessage === "string" ? e.shortMessage : typeof e?.message === "string" ? e.message : String(args[1]);
|
|
22434
|
+
const details = e?.details;
|
|
22435
|
+
ctx.reason = typeof details === "string" && details.length > 0 ? `${reason} (${details})` : reason;
|
|
22436
|
+
}
|
|
22437
|
+
}
|
|
22438
|
+
return original(...args);
|
|
22439
|
+
};
|
|
22440
|
+
}
|
|
22441
|
+
async function runWithMppxFailureCapture(fn) {
|
|
22442
|
+
ensureConsoleErrorPatch();
|
|
22443
|
+
const ctx = { reason: null };
|
|
22444
|
+
const result = await mppxCapture.run(ctx, fn);
|
|
22445
|
+
return { result, failureReason: ctx.reason };
|
|
22446
|
+
}
|
|
22256
22447
|
|
|
22257
22448
|
// src/payment/x402_server.ts
|
|
22258
22449
|
init_networks();
|
|
@@ -22394,40 +22585,28 @@ function lazyMppxServer(opts) {
|
|
|
22394
22585
|
};
|
|
22395
22586
|
}
|
|
22396
22587
|
|
|
22397
|
-
// src/
|
|
22398
|
-
|
|
22399
|
-
|
|
22400
|
-
|
|
22401
|
-
|
|
22402
|
-
|
|
22403
|
-
|
|
22404
|
-
|
|
22405
|
-
|
|
22406
|
-
|
|
22588
|
+
// src/payment/mppx_failures.ts
|
|
22589
|
+
var TEMPO_KEY_NOT_REGISTERED = {
|
|
22590
|
+
code: "tempo_key_not_registered",
|
|
22591
|
+
status: 401,
|
|
22592
|
+
message: "Tempo rejected the transaction: signer wallet is not registered with Tempo's keychain.",
|
|
22593
|
+
nextSteps: {
|
|
22594
|
+
action: "register_tempo_key",
|
|
22595
|
+
user_message: "Your wallet is not enrolled with Tempo. Run `tempo wallet login` to complete the one-time WebAuthn enrollment (or use `tempo request` directly), then retry. To skip enrollment, switch to the Base or Solana rail on this 402."
|
|
22596
|
+
},
|
|
22597
|
+
extra: { upstream_error: "KeyNotFound", chain: "tempo" }
|
|
22598
|
+
};
|
|
22599
|
+
function classifyMppxFailure(reason) {
|
|
22600
|
+
if (!reason) return null;
|
|
22601
|
+
const lower = reason.toLowerCase();
|
|
22602
|
+
if (lower.includes("keychain validation failed") || lower.includes("keynotfound")) {
|
|
22603
|
+
return TEMPO_KEY_NOT_REGISTERED;
|
|
22407
22604
|
}
|
|
22408
|
-
const rec = headers;
|
|
22409
|
-
const v = rec[name] ?? rec[name.toLowerCase()] ?? rec[toTitleCase(name)];
|
|
22410
|
-
if (typeof v === "string") return v;
|
|
22411
|
-
if (Array.isArray(v) && typeof v[0] === "string") return v[0];
|
|
22412
22605
|
return null;
|
|
22413
22606
|
}
|
|
22414
|
-
|
|
22415
|
-
|
|
22416
|
-
|
|
22417
|
-
function hasPaymentHeader(input) {
|
|
22418
|
-
const headers = asHeaders(input);
|
|
22419
|
-
return Boolean(
|
|
22420
|
-
readHeader(headers, "payment-signature") || readHeader(headers, "x-payment") || readHeader(headers, "authorization")?.startsWith("Payment ")
|
|
22421
|
-
);
|
|
22422
|
-
}
|
|
22423
|
-
function hasX402Header(input) {
|
|
22424
|
-
const headers = asHeaders(input);
|
|
22425
|
-
return Boolean(readHeader(headers, "payment-signature") || readHeader(headers, "x-payment"));
|
|
22426
|
-
}
|
|
22427
|
-
function hasMppxHeader(input) {
|
|
22428
|
-
const headers = asHeaders(input);
|
|
22429
|
-
return Boolean(readHeader(headers, "authorization")?.startsWith("Payment "));
|
|
22430
|
-
}
|
|
22607
|
+
|
|
22608
|
+
// src/checkout.ts
|
|
22609
|
+
init_network_kind();
|
|
22431
22610
|
|
|
22432
22611
|
// src/payment/x402_settle.ts
|
|
22433
22612
|
function classifyX402SettleResult(result) {
|
|
@@ -22750,20 +22929,6 @@ function getIdentityStatus(ctx) {
|
|
|
22750
22929
|
if (decision === "allow") return "verified";
|
|
22751
22930
|
return "unverified";
|
|
22752
22931
|
}
|
|
22753
|
-
var CheckoutValidationError = class extends Error {
|
|
22754
|
-
code;
|
|
22755
|
-
action;
|
|
22756
|
-
status;
|
|
22757
|
-
extra;
|
|
22758
|
-
constructor(opts) {
|
|
22759
|
-
super(opts.message);
|
|
22760
|
-
this.name = "CheckoutValidationError";
|
|
22761
|
-
this.code = opts.code;
|
|
22762
|
-
this.action = opts.action ?? "fix_request";
|
|
22763
|
-
this.status = opts.status ?? 400;
|
|
22764
|
-
this.extra = opts.extra;
|
|
22765
|
-
}
|
|
22766
|
-
};
|
|
22767
22932
|
function resolveIdentityMetadata(ctx) {
|
|
22768
22933
|
const h = normalizeHeadersToLowercase(ctx.request.headers);
|
|
22769
22934
|
const wallet = h["x-wallet-address"];
|
|
@@ -22890,6 +23055,23 @@ var Checkout = class {
|
|
|
22890
23055
|
discoveryExtensions;
|
|
22891
23056
|
discoveryProbe;
|
|
22892
23057
|
_x402ServerGetter;
|
|
23058
|
+
/**
|
|
23059
|
+
* True when the merchant has configured an identity-bearing policy flag —
|
|
23060
|
+
* `require_kyc`, `require_sanctions_clear` (name screening on the KYC
|
|
23061
|
+
* identity), `min_age`, or jurisdiction lists. Wallet OFAC SDN enforcement
|
|
23062
|
+
* (the always-on default) does NOT count as an identity gate; agents don't
|
|
23063
|
+
* need an AgentScore credential to satisfy it.
|
|
23064
|
+
*
|
|
23065
|
+
* Used to conditionally emit AgentScore identity boilerplate in 402 bodies
|
|
23066
|
+
* (`agent_memory`, `X-Operator-Token` references in per-rail commands).
|
|
23067
|
+
*/
|
|
23068
|
+
hasIdentityGate() {
|
|
23069
|
+
const g = this.gate;
|
|
23070
|
+
if (!g) return false;
|
|
23071
|
+
return Boolean(
|
|
23072
|
+
g.requireKyc || g.requireSanctionsClear || g.minAge !== void 0 || g.allowedJurisdictions && g.allowedJurisdictions.length > 0 || g.blockedJurisdictions && g.blockedJurisdictions.length > 0
|
|
23073
|
+
);
|
|
23074
|
+
}
|
|
22893
23075
|
constructor(opts) {
|
|
22894
23076
|
const x402Server = opts.x402Server;
|
|
22895
23077
|
let x402ServerGetter;
|
|
@@ -23087,8 +23269,8 @@ var Checkout = class {
|
|
|
23087
23269
|
}
|
|
23088
23270
|
}
|
|
23089
23271
|
const hasPaymentHeader2 = hasX402Header(request.headers) || hasMppxHeader(request.headers);
|
|
23090
|
-
if (
|
|
23091
|
-
const denial = await this.runGate(ctx);
|
|
23272
|
+
if (hasPaymentHeader2) {
|
|
23273
|
+
const denial = this.gate !== void 0 ? await this.runGate(ctx) : await this.runWalletSanctionsOnly(ctx);
|
|
23092
23274
|
if (denial !== null) {
|
|
23093
23275
|
return {
|
|
23094
23276
|
status: denial.status,
|
|
@@ -23100,7 +23282,14 @@ var Checkout = class {
|
|
|
23100
23282
|
}
|
|
23101
23283
|
}
|
|
23102
23284
|
ctx.pricing = await this.computePricing(ctx);
|
|
23103
|
-
|
|
23285
|
+
try {
|
|
23286
|
+
await this.resolveRecipientsForCtx(ctx);
|
|
23287
|
+
} catch (err) {
|
|
23288
|
+
if (err instanceof Error && err.name === "CheckoutValidationError") {
|
|
23289
|
+
return this.validationErrorResult(ctx, err);
|
|
23290
|
+
}
|
|
23291
|
+
throw err;
|
|
23292
|
+
}
|
|
23104
23293
|
const x402ServerOk = this.x402ServerAvailable() && this.x402BaseNetwork !== null;
|
|
23105
23294
|
if (hasX402Header(request.headers) && x402ServerOk) {
|
|
23106
23295
|
const zero = await this.handleZeroSettle(ctx, "x402-base");
|
|
@@ -23153,7 +23342,9 @@ var Checkout = class {
|
|
|
23153
23342
|
}
|
|
23154
23343
|
return result;
|
|
23155
23344
|
}
|
|
23156
|
-
if (gate.apiKey === void 0)
|
|
23345
|
+
if (gate.apiKey === void 0) {
|
|
23346
|
+
return this.runWalletSanctionsOnly(ctx);
|
|
23347
|
+
}
|
|
23157
23348
|
let policyOverride;
|
|
23158
23349
|
if (gate.perRequestPolicy !== void 0) {
|
|
23159
23350
|
policyOverride = await gate.perRequestPolicy(ctx);
|
|
@@ -23171,8 +23362,16 @@ var Checkout = class {
|
|
|
23171
23362
|
...gate.failOpen !== void 0 && { failOpen: gate.failOpen },
|
|
23172
23363
|
...gate.cacheSeconds !== void 0 && { cacheSeconds: gate.cacheSeconds },
|
|
23173
23364
|
...gate.chain !== void 0 && { chain: gate.chain },
|
|
23174
|
-
|
|
23175
|
-
|
|
23365
|
+
// Auto-default `createSessionOnMissing` from gate config when the merchant
|
|
23366
|
+
// didn't supply one. Matches python-commerce's behavior — every gated route
|
|
23367
|
+
// gets the bootstrap session-mint UX out of the box. Merchants who need
|
|
23368
|
+
// custom session context or onBeforeSession side effects (goods merchants
|
|
23369
|
+
// pre-minting an order_id) supply their own config instead.
|
|
23370
|
+
createSessionOnMissing: gate.createSessionOnMissing ?? {
|
|
23371
|
+
apiKey: gate.apiKey,
|
|
23372
|
+
...gate.baseUrl !== void 0 && { baseUrl: gate.baseUrl },
|
|
23373
|
+
...gate.context !== void 0 && { context: gate.context },
|
|
23374
|
+
...gate.merchantName !== void 0 && { productName: gate.merchantName }
|
|
23176
23375
|
},
|
|
23177
23376
|
...policyOverride ?? {}
|
|
23178
23377
|
};
|
|
@@ -23235,6 +23434,58 @@ var Checkout = class {
|
|
|
23235
23434
|
const status = reason.code === "token_expired" || reason.code === "invalid_credential" ? 401 : reason.code === "api_error" ? 503 : 403;
|
|
23236
23435
|
return { status, body };
|
|
23237
23436
|
}
|
|
23437
|
+
/**
|
|
23438
|
+
* Wallet OFAC SDN enforcement.
|
|
23439
|
+
*
|
|
23440
|
+
* Runs on settle (payment header present) when either `this.gate` is
|
|
23441
|
+
* undefined OR a gate is configured but has no `apiKey` to reach
|
|
23442
|
+
* `/v1/assess` for full policy enforcement (fallback to the
|
|
23443
|
+
* strict-liability default).
|
|
23444
|
+
*
|
|
23445
|
+
* Env knobs:
|
|
23446
|
+
* - `AGENTSCORE_API_KEY` — required. No key → one-time warning + skip
|
|
23447
|
+
* (dev/testnet pattern; production should always configure a key).
|
|
23448
|
+
* - `AGENTSCORE_BASE_URL` — optional override for staging/dev API
|
|
23449
|
+
* (e.g. `https://api-dev.agentscore.sh` or `http://localhost:3002`).
|
|
23450
|
+
*
|
|
23451
|
+
* Stripe SPT (no extractable wallet signer) → skip silently; Stripe runs
|
|
23452
|
+
* its own OFAC screen on the buyer's Stripe account at customer creation.
|
|
23453
|
+
*
|
|
23454
|
+
* Calls `/v1/assess` with the signer wallet as both the primary address
|
|
23455
|
+
* and the signer block. The API enforces signer-sanctions unconditionally
|
|
23456
|
+
* when a signer is present (no policy flag needed). Denies on OFAC SDN
|
|
23457
|
+
* hit; fail-closed on unavailable lookup (strict liability — falsely
|
|
23458
|
+
* allowing a sanctioned settle is an OFAC violation, falsely denying a
|
|
23459
|
+
* clean buyer is just bad UX).
|
|
23460
|
+
*/
|
|
23461
|
+
async runWalletSanctionsOnly(ctx) {
|
|
23462
|
+
const apiKey = process.env.AGENTSCORE_API_KEY;
|
|
23463
|
+
if (!apiKey) {
|
|
23464
|
+
warnMissingApiKeyOnce("checkout");
|
|
23465
|
+
return null;
|
|
23466
|
+
}
|
|
23467
|
+
const headers = normalizeHeadersToLowercase(ctx.request.headers);
|
|
23468
|
+
const x402Header = headers["payment-signature"] ?? headers["x-payment"];
|
|
23469
|
+
const signer = await extractPaymentSignerFromAuth(headers["authorization"], x402Header);
|
|
23470
|
+
if (!signer) {
|
|
23471
|
+
return null;
|
|
23472
|
+
}
|
|
23473
|
+
const baseUrl = process.env.AGENTSCORE_BASE_URL;
|
|
23474
|
+
const core = createAgentScoreCore({
|
|
23475
|
+
apiKey,
|
|
23476
|
+
...baseUrl !== void 0 && { baseUrl }
|
|
23477
|
+
});
|
|
23478
|
+
const outcome = await core.evaluate(
|
|
23479
|
+
{ address: signer.address },
|
|
23480
|
+
ctx,
|
|
23481
|
+
signer
|
|
23482
|
+
);
|
|
23483
|
+
if (outcome.kind === "allow") return null;
|
|
23484
|
+
const reason = outcome.reason;
|
|
23485
|
+
const body = denialReasonToBody(reason);
|
|
23486
|
+
const status = reason.code === "token_expired" || reason.code === "invalid_credential" ? 401 : reason.code === "api_error" ? 503 : 403;
|
|
23487
|
+
return { status, body };
|
|
23488
|
+
}
|
|
23238
23489
|
async handleZeroSettle(ctx, rail) {
|
|
23239
23490
|
if (!this.zeroSettleCarveOut || ctx.pricing === null) return null;
|
|
23240
23491
|
const cents = Math.round(ctx.pricing.amountUsd * 100);
|
|
@@ -23269,7 +23520,7 @@ var Checkout = class {
|
|
|
23269
23520
|
return await this.buildSuccess(ctx, outcome);
|
|
23270
23521
|
}
|
|
23271
23522
|
async mintRefId(request) {
|
|
23272
|
-
if (this.mintReferenceId === void 0) return (0,
|
|
23523
|
+
if (this.mintReferenceId === void 0) return (0, import_node_crypto2.randomUUID)();
|
|
23273
23524
|
const seedCtx = { request, referenceId: "", pricing: null, recipients: {}, state: {} };
|
|
23274
23525
|
return await this.mintReferenceId(seedCtx);
|
|
23275
23526
|
}
|
|
@@ -23372,7 +23623,9 @@ var Checkout = class {
|
|
|
23372
23623
|
if (this.composeMppx === void 0) {
|
|
23373
23624
|
throw new Error("Checkout.handleMppx: composeMppx hook not configured");
|
|
23374
23625
|
}
|
|
23375
|
-
const composed = await
|
|
23626
|
+
const { result: composed, failureReason } = await runWithMppxFailureCapture(
|
|
23627
|
+
async () => this.composeMppx(ctx)
|
|
23628
|
+
);
|
|
23376
23629
|
if (composed.status === 200) {
|
|
23377
23630
|
const paymentReceiptHeader = composed.paymentReceiptHeader ?? extractMppxReceiptHeaderFromRaw(composed.raw);
|
|
23378
23631
|
const directMethod = composed.raw?.receipt?.method;
|
|
@@ -23391,6 +23644,22 @@ var Checkout = class {
|
|
|
23391
23644
|
};
|
|
23392
23645
|
return await this.buildSuccess(ctx, outcome);
|
|
23393
23646
|
}
|
|
23647
|
+
const classified = classifyMppxFailure(failureReason);
|
|
23648
|
+
if (classified !== null) {
|
|
23649
|
+
return {
|
|
23650
|
+
status: classified.status,
|
|
23651
|
+
body: buildValidationError({
|
|
23652
|
+
code: classified.code,
|
|
23653
|
+
message: classified.message,
|
|
23654
|
+
nextSteps: classified.nextSteps,
|
|
23655
|
+
...classified.extra && { extra: classified.extra }
|
|
23656
|
+
}),
|
|
23657
|
+
headers: { ...composed.headers ?? {} },
|
|
23658
|
+
referenceId: ctx.referenceId,
|
|
23659
|
+
settled: false,
|
|
23660
|
+
settlePhase: "verify_failed"
|
|
23661
|
+
};
|
|
23662
|
+
}
|
|
23394
23663
|
return {
|
|
23395
23664
|
status: 400,
|
|
23396
23665
|
body: buildValidationError({
|
|
@@ -23409,7 +23678,11 @@ var Checkout = class {
|
|
|
23409
23678
|
throw new Error("Checkout.emit402: pricing not computed");
|
|
23410
23679
|
}
|
|
23411
23680
|
await this.resolveRecipientsForCtx(ctx);
|
|
23412
|
-
|
|
23681
|
+
let emitRails = applyRecipientOverrides(this.rails, ctx.recipients);
|
|
23682
|
+
if (ctx.pricing.amountUsd < STRIPE_MIN_CHARGE_USD && emitRails.stripe !== void 0) {
|
|
23683
|
+
const { stripe: _stripe, ...rest } = emitRails;
|
|
23684
|
+
emitRails = rest;
|
|
23685
|
+
}
|
|
23413
23686
|
const accepted = await buildAcceptedMethods({
|
|
23414
23687
|
tempo: pickRail(emitRails, "tempo"),
|
|
23415
23688
|
x402_base: pickRail(emitRails, "x402_base"),
|
|
@@ -23428,6 +23701,10 @@ var Checkout = class {
|
|
|
23428
23701
|
retryBodyJson: JSON.stringify(ctx.request.body),
|
|
23429
23702
|
totalUsd: ctx.pricing.amountUsd.toFixed(pricingDecimals),
|
|
23430
23703
|
rails: howToPayRails,
|
|
23704
|
+
// Merchants without an identity-bearing policy flag get clean commands
|
|
23705
|
+
// without an X-Operator-Token header — agents don't need one to satisfy
|
|
23706
|
+
// wallet OFAC enforcement (the always-on default).
|
|
23707
|
+
...this.hasIdentityGate() ? {} : { opTokenPlaceholder: null },
|
|
23431
23708
|
...ctx.pricing.decimals !== void 0 && { decimals: ctx.pricing.decimals }
|
|
23432
23709
|
});
|
|
23433
23710
|
const pricingBlock = ctx.pricing.block ?? buildPricingBlock({
|
|
@@ -23464,7 +23741,10 @@ var Checkout = class {
|
|
|
23464
23741
|
pricing: pricingBlock,
|
|
23465
23742
|
amountUsd: ctx.pricing.amountUsd.toFixed(pricingDecimals),
|
|
23466
23743
|
retryBody: ctx.request.body,
|
|
23467
|
-
|
|
23744
|
+
// Merchants without an identity-bearing gate get a clean 402: no
|
|
23745
|
+
// AgentScore-identity bootstrap describing a verification flow they
|
|
23746
|
+
// don't run. Wallet OFAC (the always-on default) doesn't need it.
|
|
23747
|
+
agentMemory: firstEncounterAgentMemory({ firstEncounter: this.hasIdentityGate() }),
|
|
23468
23748
|
...ctx.pricing.product ? { product: ctx.pricing.product } : {},
|
|
23469
23749
|
...ctx.pricing.bodyExtras ? { extra: ctx.pricing.bodyExtras } : {},
|
|
23470
23750
|
...x402Accepts.length > 0 ? {
|
|
@@ -23812,87 +24092,6 @@ Checkout.prototype.mountUcpRoutesFastify = function(app, opts) {
|
|
|
23812
24092
|
app.options(jwksPath, preflight);
|
|
23813
24093
|
};
|
|
23814
24094
|
|
|
23815
|
-
// src/identity/policy.ts
|
|
23816
|
-
function buildGateFromPolicy(policy, base) {
|
|
23817
|
-
if (!policy || !policy.enforcement) return null;
|
|
23818
|
-
return {
|
|
23819
|
-
apiKey: base.apiKey,
|
|
23820
|
-
...base.baseUrl !== void 0 && { baseUrl: base.baseUrl },
|
|
23821
|
-
...policy.requireKyc !== void 0 && { requireKyc: policy.requireKyc },
|
|
23822
|
-
...policy.requireSanctionsClear !== void 0 && {
|
|
23823
|
-
requireSanctionsClear: policy.requireSanctionsClear
|
|
23824
|
-
},
|
|
23825
|
-
...policy.minAge !== void 0 && { minAge: policy.minAge },
|
|
23826
|
-
...policy.allowedJurisdictions !== void 0 && {
|
|
23827
|
-
allowedJurisdictions: [...policy.allowedJurisdictions]
|
|
23828
|
-
}
|
|
23829
|
-
};
|
|
23830
|
-
}
|
|
23831
|
-
async function runGateWithEnforcement(enforcement, runGate) {
|
|
23832
|
-
if (!runGate || !enforcement) return { status: "anonymous" };
|
|
23833
|
-
const outcome = await runGate();
|
|
23834
|
-
if (outcome.ok) return { status: "verified" };
|
|
23835
|
-
if (enforcement === "hard") {
|
|
23836
|
-
return {
|
|
23837
|
-
status: "denied",
|
|
23838
|
-
denialStatus: outcome.status,
|
|
23839
|
-
denialBody: outcome.body,
|
|
23840
|
-
...outcome.reason !== void 0 && { denialReason: outcome.reason }
|
|
23841
|
-
};
|
|
23842
|
-
}
|
|
23843
|
-
return {
|
|
23844
|
-
status: "unverified",
|
|
23845
|
-
denialStatus: outcome.status,
|
|
23846
|
-
denialBody: outcome.body,
|
|
23847
|
-
...outcome.reason !== void 0 && { denialReason: outcome.reason }
|
|
23848
|
-
};
|
|
23849
|
-
}
|
|
23850
|
-
function shippingCountryAllowed(country, policy) {
|
|
23851
|
-
if (!policy?.allowedShippingCountries || policy.allowedShippingCountries.length === 0) return true;
|
|
23852
|
-
const allowed = new Set(policy.allowedShippingCountries.map((c) => c.toUpperCase()));
|
|
23853
|
-
return allowed.has(country.toUpperCase());
|
|
23854
|
-
}
|
|
23855
|
-
function shippingStateAllowed(state, country, policy) {
|
|
23856
|
-
if (!policy?.allowedShippingStates || policy.allowedShippingStates.length === 0) return true;
|
|
23857
|
-
if (country.toUpperCase() !== "US") return true;
|
|
23858
|
-
const allowed = new Set(policy.allowedShippingStates.map((s) => s.toUpperCase()));
|
|
23859
|
-
return allowed.has(state.toUpperCase());
|
|
23860
|
-
}
|
|
23861
|
-
function validateShippingAgainstPolicy(opts) {
|
|
23862
|
-
const code = opts.errorCode ?? "unsupported_jurisdiction";
|
|
23863
|
-
const action = opts.errorAction ?? "change_shipping_state";
|
|
23864
|
-
const item = opts.productName ? `'${opts.productName}'` : "this item";
|
|
23865
|
-
if (!shippingCountryAllowed(opts.country, opts.policy)) {
|
|
23866
|
-
throw new CheckoutValidationError({
|
|
23867
|
-
code,
|
|
23868
|
-
message: opts.countryMessage ?? `We can't ship ${item} to ${opts.country.toUpperCase() || "<unset>"}.`,
|
|
23869
|
-
action
|
|
23870
|
-
});
|
|
23871
|
-
}
|
|
23872
|
-
if (!shippingStateAllowed(opts.state, opts.country, opts.policy)) {
|
|
23873
|
-
throw new CheckoutValidationError({
|
|
23874
|
-
code,
|
|
23875
|
-
message: opts.stateMessage ?? `We can't ship ${item} to ${opts.state.toUpperCase() || "<unset>"}.`,
|
|
23876
|
-
action
|
|
23877
|
-
});
|
|
23878
|
-
}
|
|
23879
|
-
}
|
|
23880
|
-
|
|
23881
|
-
// src/identity/tokens.ts
|
|
23882
|
-
var import_node_crypto2 = require("crypto");
|
|
23883
|
-
function hashOperatorToken(plaintext) {
|
|
23884
|
-
return (0, import_node_crypto2.createHash)("sha256").update(plaintext, "utf8").digest("hex");
|
|
23885
|
-
}
|
|
23886
|
-
function extractOwnerScope(input) {
|
|
23887
|
-
const headers = asHeaders(input);
|
|
23888
|
-
const walletAddress = readHeader(headers, "x-wallet-address");
|
|
23889
|
-
const operatorToken = readHeader(headers, "x-operator-token");
|
|
23890
|
-
return {
|
|
23891
|
-
...walletAddress ? { walletAddress } : {},
|
|
23892
|
-
...operatorToken ? { operatorTokenHash: hashOperatorToken(operatorToken) } : {}
|
|
23893
|
-
};
|
|
23894
|
-
}
|
|
23895
|
-
|
|
23896
24095
|
// src/payment/index.ts
|
|
23897
24096
|
init_directive();
|
|
23898
24097
|
init_networks();
|
|
@@ -23969,6 +24168,7 @@ async function loadSolanaFeePayer(opts) {
|
|
|
23969
24168
|
|
|
23970
24169
|
// src/payment/compose_rails.ts
|
|
23971
24170
|
init_usdc();
|
|
24171
|
+
var warnedStripeBelowMinimum = false;
|
|
23972
24172
|
function buildMppxComposeRails(opts) {
|
|
23973
24173
|
const rails2 = [];
|
|
23974
24174
|
if (opts.tempoRecipient) {
|
|
@@ -23990,7 +24190,17 @@ function buildMppxComposeRails(opts) {
|
|
|
23990
24190
|
}]);
|
|
23991
24191
|
}
|
|
23992
24192
|
if (opts.includeStripe !== false) {
|
|
23993
|
-
|
|
24193
|
+
const amountUsdNumeric = Number(opts.amountUsd);
|
|
24194
|
+
if (Number.isFinite(amountUsdNumeric) && amountUsdNumeric < STRIPE_MIN_CHARGE_USD) {
|
|
24195
|
+
if (!warnedStripeBelowMinimum) {
|
|
24196
|
+
warnedStripeBelowMinimum = true;
|
|
24197
|
+
console.warn(
|
|
24198
|
+
`[buildMppxComposeRails] Dropping stripe/charge rail: amountUsd=${opts.amountUsd} is below Stripe's $${STRIPE_MIN_CHARGE_USD.toFixed(2)} USD minimum. Stripe's fixed ~$0.30 fee makes sub-50-cent charges unprofitable (and many accounts reject PI creation with amount_too_small below this floor). Pass includeStripe: false to suppress this warning.`
|
|
24199
|
+
);
|
|
24200
|
+
}
|
|
24201
|
+
} else {
|
|
24202
|
+
rails2.push(["stripe/charge", { amount: opts.amountUsd, currency: "usd", decimals: 2 }]);
|
|
24203
|
+
}
|
|
23994
24204
|
}
|
|
23995
24205
|
return rails2;
|
|
23996
24206
|
}
|
|
@@ -24181,10 +24391,11 @@ function computeFirstCheckout(opts) {
|
|
|
24181
24391
|
const tempoRecipient = recipients.tempo;
|
|
24182
24392
|
const x402BaseRecipient = recipients.x402_base;
|
|
24183
24393
|
const solanaRecipient = recipients.solana_mpp;
|
|
24394
|
+
const includeStripeInDiscovery = opts.rails.stripe !== void 0 && Number(totalUsd) >= STRIPE_MIN_CHARGE_USD;
|
|
24184
24395
|
const accepted = await buildAcceptedMethods({
|
|
24185
24396
|
...tempoRecipient && opts.rails.tempo && { tempo: { ...opts.rails.tempo, recipient: tempoRecipient } },
|
|
24186
24397
|
...solanaRecipient && opts.rails.solana_mpp && { solana_mpp: { ...opts.rails.solana_mpp, recipient: solanaRecipient } },
|
|
24187
|
-
...
|
|
24398
|
+
...includeStripeInDiscovery && { stripe: opts.rails.stripe }
|
|
24188
24399
|
});
|
|
24189
24400
|
if (x402BaseRecipient && opts.rails.x402_base) {
|
|
24190
24401
|
try {
|
|
@@ -24261,6 +24472,36 @@ function computeFirstCheckout(opts) {
|
|
|
24261
24472
|
);
|
|
24262
24473
|
return new Response(JSON.stringify(body402), { status: 402, headers });
|
|
24263
24474
|
}
|
|
24475
|
+
async function enforceWalletSanctions(req, referenceId) {
|
|
24476
|
+
const apiKey = process.env.AGENTSCORE_API_KEY;
|
|
24477
|
+
if (!apiKey) {
|
|
24478
|
+
warnMissingApiKeyOnce(`${opts.name}.computeFirst`);
|
|
24479
|
+
return null;
|
|
24480
|
+
}
|
|
24481
|
+
const x402Header = readX402PaymentHeader(req);
|
|
24482
|
+
const signer = await extractPaymentSigner(req, x402Header);
|
|
24483
|
+
if (!signer) return null;
|
|
24484
|
+
const baseUrl = process.env.AGENTSCORE_BASE_URL;
|
|
24485
|
+
const core = createAgentScoreCore({
|
|
24486
|
+
apiKey,
|
|
24487
|
+
...baseUrl !== void 0 && { baseUrl }
|
|
24488
|
+
});
|
|
24489
|
+
const outcome = await core.evaluate({ address: signer.address }, void 0, signer);
|
|
24490
|
+
if (outcome.kind === "allow") return null;
|
|
24491
|
+
const reason = outcome.reason;
|
|
24492
|
+
const body = denialReasonToBody(reason);
|
|
24493
|
+
const status = reason.code === "token_expired" || reason.code === "invalid_credential" ? 401 : reason.code === "api_error" ? 503 : 403;
|
|
24494
|
+
return new Response(
|
|
24495
|
+
JSON.stringify({
|
|
24496
|
+
id: referenceId,
|
|
24497
|
+
endpoint: opts.name,
|
|
24498
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24499
|
+
payment_status: "failed",
|
|
24500
|
+
...body
|
|
24501
|
+
}),
|
|
24502
|
+
{ status, headers: { "Content-Type": "application/json" } }
|
|
24503
|
+
);
|
|
24504
|
+
}
|
|
24264
24505
|
async function handleX402Settle(req, referenceId, cachedBody, priceCents, recipients) {
|
|
24265
24506
|
const verified = await verifyX402Request({
|
|
24266
24507
|
request: req,
|
|
@@ -24459,6 +24700,8 @@ function computeFirstCheckout(opts) {
|
|
|
24459
24700
|
{ status: 400, headers: { "Content-Type": "application/json" } }
|
|
24460
24701
|
);
|
|
24461
24702
|
}
|
|
24703
|
+
const ofacDenial = await enforceWalletSanctions(req, referenceId);
|
|
24704
|
+
if (ofacDenial !== null) return ofacDenial;
|
|
24462
24705
|
if (hasX402Header(req.headers)) return handleX402Settle(req, referenceId, quote2.body, quote2.priceCents, quote2.recipients);
|
|
24463
24706
|
return handleMppSettle(req, referenceId, quote2.body, quote2.priceCents, quote2.recipients);
|
|
24464
24707
|
}
|
|
@@ -24608,6 +24851,7 @@ function defaultReadOnlyOnDenied(reason) {
|
|
|
24608
24851
|
buildMppxComposeRails,
|
|
24609
24852
|
buildSignerMismatchBody,
|
|
24610
24853
|
buildUCPProfile,
|
|
24854
|
+
buildVerificationRequiredBody,
|
|
24611
24855
|
computeFirstCheckout,
|
|
24612
24856
|
createDefaultOnDenied,
|
|
24613
24857
|
createQuoteCache,
|