@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.mjs
CHANGED
|
@@ -20059,11 +20059,12 @@ function toClient(method, options) {
|
|
|
20059
20059
|
};
|
|
20060
20060
|
}
|
|
20061
20061
|
function toServer(method, options) {
|
|
20062
|
-
const { authorize, defaults, html, request, respond, stableBinding, transport, verify: verify3 } = options;
|
|
20062
|
+
const { authorize, defaults, extensions, html, request, respond, stableBinding, transport, verify: verify3 } = options;
|
|
20063
20063
|
return {
|
|
20064
20064
|
...method,
|
|
20065
20065
|
authorize,
|
|
20066
20066
|
defaults,
|
|
20067
|
+
extensions,
|
|
20067
20068
|
html,
|
|
20068
20069
|
request,
|
|
20069
20070
|
respond,
|
|
@@ -20990,6 +20991,20 @@ var RESERVED_FIELDS = /* @__PURE__ */ new Set([
|
|
|
20990
20991
|
"actual_signer",
|
|
20991
20992
|
"linked_wallets"
|
|
20992
20993
|
]);
|
|
20994
|
+
function buildVerificationRequiredBody(reason, opts = {}) {
|
|
20995
|
+
const body = denialReasonToBody(reason);
|
|
20996
|
+
body.error = {
|
|
20997
|
+
code: "operator_verification_required",
|
|
20998
|
+
message: opts.message ?? "Identity verification is required."
|
|
20999
|
+
};
|
|
21000
|
+
if (opts.agentInstructions !== void 0) {
|
|
21001
|
+
body.agent_instructions = opts.agentInstructions;
|
|
21002
|
+
}
|
|
21003
|
+
if (opts.extra) {
|
|
21004
|
+
for (const [k, v] of Object.entries(opts.extra)) body[k] = v;
|
|
21005
|
+
}
|
|
21006
|
+
return body;
|
|
21007
|
+
}
|
|
20993
21008
|
function denialReasonToBody(reason) {
|
|
20994
21009
|
const message = reason.message ?? DEFAULT_MESSAGES[reason.code];
|
|
20995
21010
|
const body = { error: { code: reason.code, message } };
|
|
@@ -21147,7 +21162,7 @@ function createAgentScoreCore(options) {
|
|
|
21147
21162
|
} = options;
|
|
21148
21163
|
const baseUrl = stripTrailingSlashes(rawBaseUrl);
|
|
21149
21164
|
const agentMemoryHint = buildAgentMemoryHint();
|
|
21150
|
-
const defaultUa = `@agent-score/commerce@${"2.
|
|
21165
|
+
const defaultUa = `@agent-score/commerce@${"2.2.0"}`;
|
|
21151
21166
|
const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
|
|
21152
21167
|
const sdk = new AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
|
|
21153
21168
|
const sessionSdkCache = /* @__PURE__ */ new Map();
|
|
@@ -21284,8 +21299,9 @@ function createAgentScoreCore(options) {
|
|
|
21284
21299
|
...Object.keys(policy).length > 0 ? { policy } : {},
|
|
21285
21300
|
// Pre-extracted payment signer (by the adapter middleware). When present, the API
|
|
21286
21301
|
// composes BOTH signer_match (wallet-binding) and signer_sanctions (OFAC SDN wallet
|
|
21287
|
-
// check) verdicts on the response in one round trip.
|
|
21288
|
-
//
|
|
21302
|
+
// check) verdicts on the response in one round trip. Wallet-OFAC enforcement on the
|
|
21303
|
+
// signer block is unconditional — a signer_sanctions hit flips decision -> deny
|
|
21304
|
+
// regardless of policy.require_sanctions_clear (which gates the separate NAME screen).
|
|
21289
21305
|
...signer && { signer: { address: signer.address, network: signer.network } }
|
|
21290
21306
|
};
|
|
21291
21307
|
const result = identity.address ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken }) : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken });
|
|
@@ -21605,6 +21621,137 @@ var A2A_DEFAULT_TRANSPORT = DEFAULT_TRANSPORT;
|
|
|
21605
21621
|
init_ucp();
|
|
21606
21622
|
init_ucp_jwks();
|
|
21607
21623
|
|
|
21624
|
+
// src/errors.ts
|
|
21625
|
+
var CheckoutValidationError = class extends Error {
|
|
21626
|
+
code;
|
|
21627
|
+
action;
|
|
21628
|
+
status;
|
|
21629
|
+
extra;
|
|
21630
|
+
constructor(opts) {
|
|
21631
|
+
super(opts.message);
|
|
21632
|
+
this.name = "CheckoutValidationError";
|
|
21633
|
+
this.code = opts.code;
|
|
21634
|
+
this.action = opts.action ?? "fix_request";
|
|
21635
|
+
this.status = opts.status ?? 400;
|
|
21636
|
+
this.extra = opts.extra;
|
|
21637
|
+
}
|
|
21638
|
+
};
|
|
21639
|
+
|
|
21640
|
+
// src/identity/policy.ts
|
|
21641
|
+
function buildGateFromPolicy(policy, base) {
|
|
21642
|
+
if (!policy || !policy.enforcement) return null;
|
|
21643
|
+
return {
|
|
21644
|
+
apiKey: base.apiKey,
|
|
21645
|
+
...base.baseUrl !== void 0 && { baseUrl: base.baseUrl },
|
|
21646
|
+
...policy.requireKyc !== void 0 && { requireKyc: policy.requireKyc },
|
|
21647
|
+
...policy.requireSanctionsClear !== void 0 && {
|
|
21648
|
+
requireSanctionsClear: policy.requireSanctionsClear
|
|
21649
|
+
},
|
|
21650
|
+
...policy.minAge !== void 0 && { minAge: policy.minAge },
|
|
21651
|
+
...policy.allowedJurisdictions !== void 0 && {
|
|
21652
|
+
allowedJurisdictions: [...policy.allowedJurisdictions]
|
|
21653
|
+
}
|
|
21654
|
+
};
|
|
21655
|
+
}
|
|
21656
|
+
async function runGateWithEnforcement(enforcement, runGate) {
|
|
21657
|
+
if (!runGate || !enforcement) return { status: "anonymous" };
|
|
21658
|
+
const outcome = await runGate();
|
|
21659
|
+
if (outcome.ok) return { status: "verified" };
|
|
21660
|
+
if (enforcement === "hard") {
|
|
21661
|
+
return {
|
|
21662
|
+
status: "denied",
|
|
21663
|
+
denialStatus: outcome.status,
|
|
21664
|
+
denialBody: outcome.body,
|
|
21665
|
+
...outcome.reason !== void 0 && { denialReason: outcome.reason }
|
|
21666
|
+
};
|
|
21667
|
+
}
|
|
21668
|
+
return {
|
|
21669
|
+
status: "unverified",
|
|
21670
|
+
denialStatus: outcome.status,
|
|
21671
|
+
denialBody: outcome.body,
|
|
21672
|
+
...outcome.reason !== void 0 && { denialReason: outcome.reason }
|
|
21673
|
+
};
|
|
21674
|
+
}
|
|
21675
|
+
function shippingCountryAllowed(country, policy) {
|
|
21676
|
+
if (!policy?.allowedShippingCountries || policy.allowedShippingCountries.length === 0) return true;
|
|
21677
|
+
const allowed = new Set(policy.allowedShippingCountries.map((c) => c.toUpperCase()));
|
|
21678
|
+
return allowed.has(country.toUpperCase());
|
|
21679
|
+
}
|
|
21680
|
+
function shippingStateAllowed(state, country, policy) {
|
|
21681
|
+
if (!policy?.allowedShippingStates || policy.allowedShippingStates.length === 0) return true;
|
|
21682
|
+
if (country.toUpperCase() !== "US") return true;
|
|
21683
|
+
const allowed = new Set(policy.allowedShippingStates.map((s) => s.toUpperCase()));
|
|
21684
|
+
return allowed.has(state.toUpperCase());
|
|
21685
|
+
}
|
|
21686
|
+
function validateShippingAgainstPolicy(opts) {
|
|
21687
|
+
const code = opts.errorCode ?? "unsupported_jurisdiction";
|
|
21688
|
+
const action = opts.errorAction ?? "change_shipping_state";
|
|
21689
|
+
const item = opts.productName ? `'${opts.productName}'` : "this item";
|
|
21690
|
+
if (!shippingCountryAllowed(opts.country, opts.policy)) {
|
|
21691
|
+
throw new CheckoutValidationError({
|
|
21692
|
+
code,
|
|
21693
|
+
message: opts.countryMessage ?? `We can't ship ${item} to ${opts.country.toUpperCase() || "<unset>"}.`,
|
|
21694
|
+
action
|
|
21695
|
+
});
|
|
21696
|
+
}
|
|
21697
|
+
if (!shippingStateAllowed(opts.state, opts.country, opts.policy)) {
|
|
21698
|
+
throw new CheckoutValidationError({
|
|
21699
|
+
code,
|
|
21700
|
+
message: opts.stateMessage ?? `We can't ship ${item} to ${opts.state.toUpperCase() || "<unset>"}.`,
|
|
21701
|
+
action
|
|
21702
|
+
});
|
|
21703
|
+
}
|
|
21704
|
+
}
|
|
21705
|
+
|
|
21706
|
+
// src/identity/tokens.ts
|
|
21707
|
+
import { createHash } from "crypto";
|
|
21708
|
+
|
|
21709
|
+
// src/payment/payment_header.ts
|
|
21710
|
+
function toTitleCase(name) {
|
|
21711
|
+
return name.replace(/(^|-)([a-z])/g, (_m, sep, c) => sep + c.toUpperCase());
|
|
21712
|
+
}
|
|
21713
|
+
function readHeader(headers, name) {
|
|
21714
|
+
if (typeof headers.get === "function") {
|
|
21715
|
+
return headers.get(name);
|
|
21716
|
+
}
|
|
21717
|
+
const rec = headers;
|
|
21718
|
+
const v = rec[name] ?? rec[name.toLowerCase()] ?? rec[toTitleCase(name)];
|
|
21719
|
+
if (typeof v === "string") return v;
|
|
21720
|
+
if (Array.isArray(v) && typeof v[0] === "string") return v[0];
|
|
21721
|
+
return null;
|
|
21722
|
+
}
|
|
21723
|
+
function asHeaders(input) {
|
|
21724
|
+
return typeof input.headers === "object" && input instanceof Request ? input.headers : input;
|
|
21725
|
+
}
|
|
21726
|
+
function hasPaymentHeader(input) {
|
|
21727
|
+
const headers = asHeaders(input);
|
|
21728
|
+
return Boolean(
|
|
21729
|
+
readHeader(headers, "payment-signature") || readHeader(headers, "x-payment") || readHeader(headers, "authorization")?.startsWith("Payment ")
|
|
21730
|
+
);
|
|
21731
|
+
}
|
|
21732
|
+
function hasX402Header(input) {
|
|
21733
|
+
const headers = asHeaders(input);
|
|
21734
|
+
return Boolean(readHeader(headers, "payment-signature") || readHeader(headers, "x-payment"));
|
|
21735
|
+
}
|
|
21736
|
+
function hasMppxHeader(input) {
|
|
21737
|
+
const headers = asHeaders(input);
|
|
21738
|
+
return Boolean(readHeader(headers, "authorization")?.startsWith("Payment "));
|
|
21739
|
+
}
|
|
21740
|
+
|
|
21741
|
+
// src/identity/tokens.ts
|
|
21742
|
+
function hashOperatorToken(plaintext) {
|
|
21743
|
+
return createHash("sha256").update(plaintext, "utf8").digest("hex");
|
|
21744
|
+
}
|
|
21745
|
+
function extractOwnerScope(input) {
|
|
21746
|
+
const headers = asHeaders(input);
|
|
21747
|
+
const walletAddress = readHeader(headers, "x-wallet-address");
|
|
21748
|
+
const operatorToken = readHeader(headers, "x-operator-token");
|
|
21749
|
+
return {
|
|
21750
|
+
...walletAddress ? { walletAddress } : {},
|
|
21751
|
+
...operatorToken ? { operatorTokenHash: hashOperatorToken(operatorToken) } : {}
|
|
21752
|
+
};
|
|
21753
|
+
}
|
|
21754
|
+
|
|
21608
21755
|
// src/checkout.ts
|
|
21609
21756
|
import { randomUUID } from "crypto";
|
|
21610
21757
|
|
|
@@ -21636,6 +21783,16 @@ async function deriveMppxReceiptMethod(raw) {
|
|
|
21636
21783
|
return extractMppxReceiptMethod(header);
|
|
21637
21784
|
}
|
|
21638
21785
|
|
|
21786
|
+
// src/_warnings.ts
|
|
21787
|
+
var warnedNoApiKey = false;
|
|
21788
|
+
function warnMissingApiKeyOnce(label) {
|
|
21789
|
+
if (warnedNoApiKey) return;
|
|
21790
|
+
warnedNoApiKey = true;
|
|
21791
|
+
console.warn(
|
|
21792
|
+
`[${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.`
|
|
21793
|
+
);
|
|
21794
|
+
}
|
|
21795
|
+
|
|
21639
21796
|
// src/payment/rail_spec.ts
|
|
21640
21797
|
init_usdc();
|
|
21641
21798
|
async function resolveRecipient(r) {
|
|
@@ -21867,14 +22024,16 @@ function buildHowToPay({
|
|
|
21867
22024
|
const d = decimals ?? 2;
|
|
21868
22025
|
const defaultMaxSpend = totalNum >= 1 ? (Math.ceil(totalNum) + 1).toFixed(d) : totalNum.toFixed(d);
|
|
21869
22026
|
const maxSpendStr = String(maxSpend ?? defaultMaxSpend);
|
|
22027
|
+
const gateless = opTokenPlaceholder === null;
|
|
21870
22028
|
const opToken = opTokenPlaceholder ?? "<your_opc_token>";
|
|
22029
|
+
const opTokenHeaderFlag = gateless ? "" : `-H 'X-Operator-Token: ${opToken}' `;
|
|
21871
22030
|
const block = {};
|
|
21872
22031
|
if (rails2.tempo) {
|
|
21873
22032
|
const networkName = rails2.tempo.testnet ? "tempo-testnet" : rails2.tempo.network ?? RAIL_SPEC_DEFAULTS.tempo.network;
|
|
21874
22033
|
const chainId = rails2.tempo.chainId ?? RAIL_SPEC_DEFAULTS.tempo.chainId;
|
|
21875
22034
|
const recommend = rails2.tempo.recommend ?? RAIL_SPEC_DEFAULTS.tempo.recommend;
|
|
21876
|
-
const tempoCommand = `tempo request -X POST
|
|
21877
|
-
const payCommand = `agentscore-pay pay POST ${url2} --chain tempo
|
|
22035
|
+
const tempoCommand = `tempo request -X POST ${opTokenHeaderFlag}-H 'Content-Type: application/json' --json '${retryBodyJson}' --max-spend ${maxSpendStr} ${url2}`;
|
|
22036
|
+
const payCommand = `agentscore-pay pay POST ${url2} --chain tempo ${opTokenHeaderFlag}-H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`;
|
|
21878
22037
|
block.tempo = {
|
|
21879
22038
|
setup: TEMPO_SETUP,
|
|
21880
22039
|
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.`,
|
|
@@ -21888,7 +22047,7 @@ function buildHowToPay({
|
|
|
21888
22047
|
block.x402_base = {
|
|
21889
22048
|
setup: PAY_SETUP_BASE,
|
|
21890
22049
|
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.`,
|
|
21891
|
-
command: `agentscore-pay pay POST ${url2} --chain base
|
|
22050
|
+
command: `agentscore-pay pay POST ${url2} --chain base ${opTokenHeaderFlag}-H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`,
|
|
21892
22051
|
what_it_does: "Pays via USDC on Base."
|
|
21893
22052
|
};
|
|
21894
22053
|
}
|
|
@@ -21897,7 +22056,7 @@ function buildHowToPay({
|
|
|
21897
22056
|
block.solana_mpp = {
|
|
21898
22057
|
setup: PAY_SETUP_SOLANA,
|
|
21899
22058
|
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.`,
|
|
21900
|
-
command: `agentscore-pay pay POST ${url2} --chain solana
|
|
22059
|
+
command: `agentscore-pay pay POST ${url2} --chain solana ${opTokenHeaderFlag}-H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`,
|
|
21901
22060
|
what_it_does: "Pays via USDC on Solana."
|
|
21902
22061
|
};
|
|
21903
22062
|
}
|
|
@@ -21919,7 +22078,7 @@ function buildHowToPay({
|
|
|
21919
22078
|
];
|
|
21920
22079
|
stripe.command_link_cli = [
|
|
21921
22080
|
`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)`,
|
|
21922
|
-
`link-cli mpp pay ${url2} --spend-request-id $SPEND_ID --method POST --data '${retryBodyJson}' --header 'X-Operator-Token: ${opToken}' --output-json`
|
|
22081
|
+
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`
|
|
21923
22082
|
];
|
|
21924
22083
|
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.";
|
|
21925
22084
|
} else if (linkCliBlocked) {
|
|
@@ -22014,6 +22173,12 @@ function buildValidationError({
|
|
|
22014
22173
|
return body;
|
|
22015
22174
|
}
|
|
22016
22175
|
|
|
22176
|
+
// src/payment/constants.ts
|
|
22177
|
+
var STRIPE_MIN_CHARGE_USD = 0.5;
|
|
22178
|
+
|
|
22179
|
+
// src/payment/mppx_server.ts
|
|
22180
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
22181
|
+
|
|
22017
22182
|
// src/stripe-multichain/mppx_stripe.ts
|
|
22018
22183
|
async function createMppxStripe({
|
|
22019
22184
|
profileId,
|
|
@@ -22194,6 +22359,31 @@ function wrapSolanaChargeWithFinalizedBlockhash(baseMethod, rpcUrl) {
|
|
|
22194
22359
|
}
|
|
22195
22360
|
};
|
|
22196
22361
|
}
|
|
22362
|
+
var mppxCapture = new AsyncLocalStorage();
|
|
22363
|
+
var consoleErrorPatched = false;
|
|
22364
|
+
function ensureConsoleErrorPatch() {
|
|
22365
|
+
if (consoleErrorPatched) return;
|
|
22366
|
+
consoleErrorPatched = true;
|
|
22367
|
+
const original = console.error.bind(console);
|
|
22368
|
+
console.error = function captureMppxInternal(...args) {
|
|
22369
|
+
if (args[0] === "mppx: internal verification error" && args[1] !== void 0) {
|
|
22370
|
+
const ctx = mppxCapture.getStore();
|
|
22371
|
+
if (ctx) {
|
|
22372
|
+
const e = args[1];
|
|
22373
|
+
const reason = typeof e?.shortMessage === "string" ? e.shortMessage : typeof e?.message === "string" ? e.message : String(args[1]);
|
|
22374
|
+
const details = e?.details;
|
|
22375
|
+
ctx.reason = typeof details === "string" && details.length > 0 ? `${reason} (${details})` : reason;
|
|
22376
|
+
}
|
|
22377
|
+
}
|
|
22378
|
+
return original(...args);
|
|
22379
|
+
};
|
|
22380
|
+
}
|
|
22381
|
+
async function runWithMppxFailureCapture(fn) {
|
|
22382
|
+
ensureConsoleErrorPatch();
|
|
22383
|
+
const ctx = { reason: null };
|
|
22384
|
+
const result = await mppxCapture.run(ctx, fn);
|
|
22385
|
+
return { result, failureReason: ctx.reason };
|
|
22386
|
+
}
|
|
22197
22387
|
|
|
22198
22388
|
// src/payment/x402_server.ts
|
|
22199
22389
|
init_networks();
|
|
@@ -22335,40 +22525,28 @@ function lazyMppxServer(opts) {
|
|
|
22335
22525
|
};
|
|
22336
22526
|
}
|
|
22337
22527
|
|
|
22338
|
-
// src/
|
|
22339
|
-
|
|
22340
|
-
|
|
22341
|
-
|
|
22342
|
-
|
|
22343
|
-
|
|
22344
|
-
|
|
22345
|
-
|
|
22346
|
-
|
|
22347
|
-
|
|
22528
|
+
// src/payment/mppx_failures.ts
|
|
22529
|
+
var TEMPO_KEY_NOT_REGISTERED = {
|
|
22530
|
+
code: "tempo_key_not_registered",
|
|
22531
|
+
status: 401,
|
|
22532
|
+
message: "Tempo rejected the transaction: signer wallet is not registered with Tempo's keychain.",
|
|
22533
|
+
nextSteps: {
|
|
22534
|
+
action: "register_tempo_key",
|
|
22535
|
+
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."
|
|
22536
|
+
},
|
|
22537
|
+
extra: { upstream_error: "KeyNotFound", chain: "tempo" }
|
|
22538
|
+
};
|
|
22539
|
+
function classifyMppxFailure(reason) {
|
|
22540
|
+
if (!reason) return null;
|
|
22541
|
+
const lower = reason.toLowerCase();
|
|
22542
|
+
if (lower.includes("keychain validation failed") || lower.includes("keynotfound")) {
|
|
22543
|
+
return TEMPO_KEY_NOT_REGISTERED;
|
|
22348
22544
|
}
|
|
22349
|
-
const rec = headers;
|
|
22350
|
-
const v = rec[name] ?? rec[name.toLowerCase()] ?? rec[toTitleCase(name)];
|
|
22351
|
-
if (typeof v === "string") return v;
|
|
22352
|
-
if (Array.isArray(v) && typeof v[0] === "string") return v[0];
|
|
22353
22545
|
return null;
|
|
22354
22546
|
}
|
|
22355
|
-
|
|
22356
|
-
|
|
22357
|
-
|
|
22358
|
-
function hasPaymentHeader(input) {
|
|
22359
|
-
const headers = asHeaders(input);
|
|
22360
|
-
return Boolean(
|
|
22361
|
-
readHeader(headers, "payment-signature") || readHeader(headers, "x-payment") || readHeader(headers, "authorization")?.startsWith("Payment ")
|
|
22362
|
-
);
|
|
22363
|
-
}
|
|
22364
|
-
function hasX402Header(input) {
|
|
22365
|
-
const headers = asHeaders(input);
|
|
22366
|
-
return Boolean(readHeader(headers, "payment-signature") || readHeader(headers, "x-payment"));
|
|
22367
|
-
}
|
|
22368
|
-
function hasMppxHeader(input) {
|
|
22369
|
-
const headers = asHeaders(input);
|
|
22370
|
-
return Boolean(readHeader(headers, "authorization")?.startsWith("Payment "));
|
|
22371
|
-
}
|
|
22547
|
+
|
|
22548
|
+
// src/checkout.ts
|
|
22549
|
+
init_network_kind();
|
|
22372
22550
|
|
|
22373
22551
|
// src/payment/x402_settle.ts
|
|
22374
22552
|
function classifyX402SettleResult(result) {
|
|
@@ -22691,20 +22869,6 @@ function getIdentityStatus(ctx) {
|
|
|
22691
22869
|
if (decision === "allow") return "verified";
|
|
22692
22870
|
return "unverified";
|
|
22693
22871
|
}
|
|
22694
|
-
var CheckoutValidationError = class extends Error {
|
|
22695
|
-
code;
|
|
22696
|
-
action;
|
|
22697
|
-
status;
|
|
22698
|
-
extra;
|
|
22699
|
-
constructor(opts) {
|
|
22700
|
-
super(opts.message);
|
|
22701
|
-
this.name = "CheckoutValidationError";
|
|
22702
|
-
this.code = opts.code;
|
|
22703
|
-
this.action = opts.action ?? "fix_request";
|
|
22704
|
-
this.status = opts.status ?? 400;
|
|
22705
|
-
this.extra = opts.extra;
|
|
22706
|
-
}
|
|
22707
|
-
};
|
|
22708
22872
|
function resolveIdentityMetadata(ctx) {
|
|
22709
22873
|
const h = normalizeHeadersToLowercase(ctx.request.headers);
|
|
22710
22874
|
const wallet = h["x-wallet-address"];
|
|
@@ -22831,6 +22995,23 @@ var Checkout = class {
|
|
|
22831
22995
|
discoveryExtensions;
|
|
22832
22996
|
discoveryProbe;
|
|
22833
22997
|
_x402ServerGetter;
|
|
22998
|
+
/**
|
|
22999
|
+
* True when the merchant has configured an identity-bearing policy flag —
|
|
23000
|
+
* `require_kyc`, `require_sanctions_clear` (name screening on the KYC
|
|
23001
|
+
* identity), `min_age`, or jurisdiction lists. Wallet OFAC SDN enforcement
|
|
23002
|
+
* (the always-on default) does NOT count as an identity gate; agents don't
|
|
23003
|
+
* need an AgentScore credential to satisfy it.
|
|
23004
|
+
*
|
|
23005
|
+
* Used to conditionally emit AgentScore identity boilerplate in 402 bodies
|
|
23006
|
+
* (`agent_memory`, `X-Operator-Token` references in per-rail commands).
|
|
23007
|
+
*/
|
|
23008
|
+
hasIdentityGate() {
|
|
23009
|
+
const g = this.gate;
|
|
23010
|
+
if (!g) return false;
|
|
23011
|
+
return Boolean(
|
|
23012
|
+
g.requireKyc || g.requireSanctionsClear || g.minAge !== void 0 || g.allowedJurisdictions && g.allowedJurisdictions.length > 0 || g.blockedJurisdictions && g.blockedJurisdictions.length > 0
|
|
23013
|
+
);
|
|
23014
|
+
}
|
|
22834
23015
|
constructor(opts) {
|
|
22835
23016
|
const x402Server = opts.x402Server;
|
|
22836
23017
|
let x402ServerGetter;
|
|
@@ -23028,8 +23209,8 @@ var Checkout = class {
|
|
|
23028
23209
|
}
|
|
23029
23210
|
}
|
|
23030
23211
|
const hasPaymentHeader2 = hasX402Header(request.headers) || hasMppxHeader(request.headers);
|
|
23031
|
-
if (
|
|
23032
|
-
const denial = await this.runGate(ctx);
|
|
23212
|
+
if (hasPaymentHeader2) {
|
|
23213
|
+
const denial = this.gate !== void 0 ? await this.runGate(ctx) : await this.runWalletSanctionsOnly(ctx);
|
|
23033
23214
|
if (denial !== null) {
|
|
23034
23215
|
return {
|
|
23035
23216
|
status: denial.status,
|
|
@@ -23041,7 +23222,14 @@ var Checkout = class {
|
|
|
23041
23222
|
}
|
|
23042
23223
|
}
|
|
23043
23224
|
ctx.pricing = await this.computePricing(ctx);
|
|
23044
|
-
|
|
23225
|
+
try {
|
|
23226
|
+
await this.resolveRecipientsForCtx(ctx);
|
|
23227
|
+
} catch (err) {
|
|
23228
|
+
if (err instanceof Error && err.name === "CheckoutValidationError") {
|
|
23229
|
+
return this.validationErrorResult(ctx, err);
|
|
23230
|
+
}
|
|
23231
|
+
throw err;
|
|
23232
|
+
}
|
|
23045
23233
|
const x402ServerOk = this.x402ServerAvailable() && this.x402BaseNetwork !== null;
|
|
23046
23234
|
if (hasX402Header(request.headers) && x402ServerOk) {
|
|
23047
23235
|
const zero = await this.handleZeroSettle(ctx, "x402-base");
|
|
@@ -23094,7 +23282,9 @@ var Checkout = class {
|
|
|
23094
23282
|
}
|
|
23095
23283
|
return result;
|
|
23096
23284
|
}
|
|
23097
|
-
if (gate.apiKey === void 0)
|
|
23285
|
+
if (gate.apiKey === void 0) {
|
|
23286
|
+
return this.runWalletSanctionsOnly(ctx);
|
|
23287
|
+
}
|
|
23098
23288
|
let policyOverride;
|
|
23099
23289
|
if (gate.perRequestPolicy !== void 0) {
|
|
23100
23290
|
policyOverride = await gate.perRequestPolicy(ctx);
|
|
@@ -23112,8 +23302,16 @@ var Checkout = class {
|
|
|
23112
23302
|
...gate.failOpen !== void 0 && { failOpen: gate.failOpen },
|
|
23113
23303
|
...gate.cacheSeconds !== void 0 && { cacheSeconds: gate.cacheSeconds },
|
|
23114
23304
|
...gate.chain !== void 0 && { chain: gate.chain },
|
|
23115
|
-
|
|
23116
|
-
|
|
23305
|
+
// Auto-default `createSessionOnMissing` from gate config when the merchant
|
|
23306
|
+
// didn't supply one. Matches python-commerce's behavior — every gated route
|
|
23307
|
+
// gets the bootstrap session-mint UX out of the box. Merchants who need
|
|
23308
|
+
// custom session context or onBeforeSession side effects (goods merchants
|
|
23309
|
+
// pre-minting an order_id) supply their own config instead.
|
|
23310
|
+
createSessionOnMissing: gate.createSessionOnMissing ?? {
|
|
23311
|
+
apiKey: gate.apiKey,
|
|
23312
|
+
...gate.baseUrl !== void 0 && { baseUrl: gate.baseUrl },
|
|
23313
|
+
...gate.context !== void 0 && { context: gate.context },
|
|
23314
|
+
...gate.merchantName !== void 0 && { productName: gate.merchantName }
|
|
23117
23315
|
},
|
|
23118
23316
|
...policyOverride ?? {}
|
|
23119
23317
|
};
|
|
@@ -23176,6 +23374,58 @@ var Checkout = class {
|
|
|
23176
23374
|
const status = reason.code === "token_expired" || reason.code === "invalid_credential" ? 401 : reason.code === "api_error" ? 503 : 403;
|
|
23177
23375
|
return { status, body };
|
|
23178
23376
|
}
|
|
23377
|
+
/**
|
|
23378
|
+
* Wallet OFAC SDN enforcement.
|
|
23379
|
+
*
|
|
23380
|
+
* Runs on settle (payment header present) when either `this.gate` is
|
|
23381
|
+
* undefined OR a gate is configured but has no `apiKey` to reach
|
|
23382
|
+
* `/v1/assess` for full policy enforcement (fallback to the
|
|
23383
|
+
* strict-liability default).
|
|
23384
|
+
*
|
|
23385
|
+
* Env knobs:
|
|
23386
|
+
* - `AGENTSCORE_API_KEY` — required. No key → one-time warning + skip
|
|
23387
|
+
* (dev/testnet pattern; production should always configure a key).
|
|
23388
|
+
* - `AGENTSCORE_BASE_URL` — optional override for staging/dev API
|
|
23389
|
+
* (e.g. `https://api-dev.agentscore.sh` or `http://localhost:3002`).
|
|
23390
|
+
*
|
|
23391
|
+
* Stripe SPT (no extractable wallet signer) → skip silently; Stripe runs
|
|
23392
|
+
* its own OFAC screen on the buyer's Stripe account at customer creation.
|
|
23393
|
+
*
|
|
23394
|
+
* Calls `/v1/assess` with the signer wallet as both the primary address
|
|
23395
|
+
* and the signer block. The API enforces signer-sanctions unconditionally
|
|
23396
|
+
* when a signer is present (no policy flag needed). Denies on OFAC SDN
|
|
23397
|
+
* hit; fail-closed on unavailable lookup (strict liability — falsely
|
|
23398
|
+
* allowing a sanctioned settle is an OFAC violation, falsely denying a
|
|
23399
|
+
* clean buyer is just bad UX).
|
|
23400
|
+
*/
|
|
23401
|
+
async runWalletSanctionsOnly(ctx) {
|
|
23402
|
+
const apiKey = process.env.AGENTSCORE_API_KEY;
|
|
23403
|
+
if (!apiKey) {
|
|
23404
|
+
warnMissingApiKeyOnce("checkout");
|
|
23405
|
+
return null;
|
|
23406
|
+
}
|
|
23407
|
+
const headers = normalizeHeadersToLowercase(ctx.request.headers);
|
|
23408
|
+
const x402Header = headers["payment-signature"] ?? headers["x-payment"];
|
|
23409
|
+
const signer = await extractPaymentSignerFromAuth(headers["authorization"], x402Header);
|
|
23410
|
+
if (!signer) {
|
|
23411
|
+
return null;
|
|
23412
|
+
}
|
|
23413
|
+
const baseUrl = process.env.AGENTSCORE_BASE_URL;
|
|
23414
|
+
const core = createAgentScoreCore({
|
|
23415
|
+
apiKey,
|
|
23416
|
+
...baseUrl !== void 0 && { baseUrl }
|
|
23417
|
+
});
|
|
23418
|
+
const outcome = await core.evaluate(
|
|
23419
|
+
{ address: signer.address },
|
|
23420
|
+
ctx,
|
|
23421
|
+
signer
|
|
23422
|
+
);
|
|
23423
|
+
if (outcome.kind === "allow") return null;
|
|
23424
|
+
const reason = outcome.reason;
|
|
23425
|
+
const body = denialReasonToBody(reason);
|
|
23426
|
+
const status = reason.code === "token_expired" || reason.code === "invalid_credential" ? 401 : reason.code === "api_error" ? 503 : 403;
|
|
23427
|
+
return { status, body };
|
|
23428
|
+
}
|
|
23179
23429
|
async handleZeroSettle(ctx, rail) {
|
|
23180
23430
|
if (!this.zeroSettleCarveOut || ctx.pricing === null) return null;
|
|
23181
23431
|
const cents = Math.round(ctx.pricing.amountUsd * 100);
|
|
@@ -23313,7 +23563,9 @@ var Checkout = class {
|
|
|
23313
23563
|
if (this.composeMppx === void 0) {
|
|
23314
23564
|
throw new Error("Checkout.handleMppx: composeMppx hook not configured");
|
|
23315
23565
|
}
|
|
23316
|
-
const composed = await
|
|
23566
|
+
const { result: composed, failureReason } = await runWithMppxFailureCapture(
|
|
23567
|
+
async () => this.composeMppx(ctx)
|
|
23568
|
+
);
|
|
23317
23569
|
if (composed.status === 200) {
|
|
23318
23570
|
const paymentReceiptHeader = composed.paymentReceiptHeader ?? extractMppxReceiptHeaderFromRaw(composed.raw);
|
|
23319
23571
|
const directMethod = composed.raw?.receipt?.method;
|
|
@@ -23332,6 +23584,22 @@ var Checkout = class {
|
|
|
23332
23584
|
};
|
|
23333
23585
|
return await this.buildSuccess(ctx, outcome);
|
|
23334
23586
|
}
|
|
23587
|
+
const classified = classifyMppxFailure(failureReason);
|
|
23588
|
+
if (classified !== null) {
|
|
23589
|
+
return {
|
|
23590
|
+
status: classified.status,
|
|
23591
|
+
body: buildValidationError({
|
|
23592
|
+
code: classified.code,
|
|
23593
|
+
message: classified.message,
|
|
23594
|
+
nextSteps: classified.nextSteps,
|
|
23595
|
+
...classified.extra && { extra: classified.extra }
|
|
23596
|
+
}),
|
|
23597
|
+
headers: { ...composed.headers ?? {} },
|
|
23598
|
+
referenceId: ctx.referenceId,
|
|
23599
|
+
settled: false,
|
|
23600
|
+
settlePhase: "verify_failed"
|
|
23601
|
+
};
|
|
23602
|
+
}
|
|
23335
23603
|
return {
|
|
23336
23604
|
status: 400,
|
|
23337
23605
|
body: buildValidationError({
|
|
@@ -23350,7 +23618,11 @@ var Checkout = class {
|
|
|
23350
23618
|
throw new Error("Checkout.emit402: pricing not computed");
|
|
23351
23619
|
}
|
|
23352
23620
|
await this.resolveRecipientsForCtx(ctx);
|
|
23353
|
-
|
|
23621
|
+
let emitRails = applyRecipientOverrides(this.rails, ctx.recipients);
|
|
23622
|
+
if (ctx.pricing.amountUsd < STRIPE_MIN_CHARGE_USD && emitRails.stripe !== void 0) {
|
|
23623
|
+
const { stripe: _stripe, ...rest } = emitRails;
|
|
23624
|
+
emitRails = rest;
|
|
23625
|
+
}
|
|
23354
23626
|
const accepted = await buildAcceptedMethods({
|
|
23355
23627
|
tempo: pickRail(emitRails, "tempo"),
|
|
23356
23628
|
x402_base: pickRail(emitRails, "x402_base"),
|
|
@@ -23369,6 +23641,10 @@ var Checkout = class {
|
|
|
23369
23641
|
retryBodyJson: JSON.stringify(ctx.request.body),
|
|
23370
23642
|
totalUsd: ctx.pricing.amountUsd.toFixed(pricingDecimals),
|
|
23371
23643
|
rails: howToPayRails,
|
|
23644
|
+
// Merchants without an identity-bearing policy flag get clean commands
|
|
23645
|
+
// without an X-Operator-Token header — agents don't need one to satisfy
|
|
23646
|
+
// wallet OFAC enforcement (the always-on default).
|
|
23647
|
+
...this.hasIdentityGate() ? {} : { opTokenPlaceholder: null },
|
|
23372
23648
|
...ctx.pricing.decimals !== void 0 && { decimals: ctx.pricing.decimals }
|
|
23373
23649
|
});
|
|
23374
23650
|
const pricingBlock = ctx.pricing.block ?? buildPricingBlock({
|
|
@@ -23405,7 +23681,10 @@ var Checkout = class {
|
|
|
23405
23681
|
pricing: pricingBlock,
|
|
23406
23682
|
amountUsd: ctx.pricing.amountUsd.toFixed(pricingDecimals),
|
|
23407
23683
|
retryBody: ctx.request.body,
|
|
23408
|
-
|
|
23684
|
+
// Merchants without an identity-bearing gate get a clean 402: no
|
|
23685
|
+
// AgentScore-identity bootstrap describing a verification flow they
|
|
23686
|
+
// don't run. Wallet OFAC (the always-on default) doesn't need it.
|
|
23687
|
+
agentMemory: firstEncounterAgentMemory({ firstEncounter: this.hasIdentityGate() }),
|
|
23409
23688
|
...ctx.pricing.product ? { product: ctx.pricing.product } : {},
|
|
23410
23689
|
...ctx.pricing.bodyExtras ? { extra: ctx.pricing.bodyExtras } : {},
|
|
23411
23690
|
...x402Accepts.length > 0 ? {
|
|
@@ -23753,87 +24032,6 @@ Checkout.prototype.mountUcpRoutesFastify = function(app, opts) {
|
|
|
23753
24032
|
app.options(jwksPath, preflight);
|
|
23754
24033
|
};
|
|
23755
24034
|
|
|
23756
|
-
// src/identity/policy.ts
|
|
23757
|
-
function buildGateFromPolicy(policy, base) {
|
|
23758
|
-
if (!policy || !policy.enforcement) return null;
|
|
23759
|
-
return {
|
|
23760
|
-
apiKey: base.apiKey,
|
|
23761
|
-
...base.baseUrl !== void 0 && { baseUrl: base.baseUrl },
|
|
23762
|
-
...policy.requireKyc !== void 0 && { requireKyc: policy.requireKyc },
|
|
23763
|
-
...policy.requireSanctionsClear !== void 0 && {
|
|
23764
|
-
requireSanctionsClear: policy.requireSanctionsClear
|
|
23765
|
-
},
|
|
23766
|
-
...policy.minAge !== void 0 && { minAge: policy.minAge },
|
|
23767
|
-
...policy.allowedJurisdictions !== void 0 && {
|
|
23768
|
-
allowedJurisdictions: [...policy.allowedJurisdictions]
|
|
23769
|
-
}
|
|
23770
|
-
};
|
|
23771
|
-
}
|
|
23772
|
-
async function runGateWithEnforcement(enforcement, runGate) {
|
|
23773
|
-
if (!runGate || !enforcement) return { status: "anonymous" };
|
|
23774
|
-
const outcome = await runGate();
|
|
23775
|
-
if (outcome.ok) return { status: "verified" };
|
|
23776
|
-
if (enforcement === "hard") {
|
|
23777
|
-
return {
|
|
23778
|
-
status: "denied",
|
|
23779
|
-
denialStatus: outcome.status,
|
|
23780
|
-
denialBody: outcome.body,
|
|
23781
|
-
...outcome.reason !== void 0 && { denialReason: outcome.reason }
|
|
23782
|
-
};
|
|
23783
|
-
}
|
|
23784
|
-
return {
|
|
23785
|
-
status: "unverified",
|
|
23786
|
-
denialStatus: outcome.status,
|
|
23787
|
-
denialBody: outcome.body,
|
|
23788
|
-
...outcome.reason !== void 0 && { denialReason: outcome.reason }
|
|
23789
|
-
};
|
|
23790
|
-
}
|
|
23791
|
-
function shippingCountryAllowed(country, policy) {
|
|
23792
|
-
if (!policy?.allowedShippingCountries || policy.allowedShippingCountries.length === 0) return true;
|
|
23793
|
-
const allowed = new Set(policy.allowedShippingCountries.map((c) => c.toUpperCase()));
|
|
23794
|
-
return allowed.has(country.toUpperCase());
|
|
23795
|
-
}
|
|
23796
|
-
function shippingStateAllowed(state, country, policy) {
|
|
23797
|
-
if (!policy?.allowedShippingStates || policy.allowedShippingStates.length === 0) return true;
|
|
23798
|
-
if (country.toUpperCase() !== "US") return true;
|
|
23799
|
-
const allowed = new Set(policy.allowedShippingStates.map((s) => s.toUpperCase()));
|
|
23800
|
-
return allowed.has(state.toUpperCase());
|
|
23801
|
-
}
|
|
23802
|
-
function validateShippingAgainstPolicy(opts) {
|
|
23803
|
-
const code = opts.errorCode ?? "unsupported_jurisdiction";
|
|
23804
|
-
const action = opts.errorAction ?? "change_shipping_state";
|
|
23805
|
-
const item = opts.productName ? `'${opts.productName}'` : "this item";
|
|
23806
|
-
if (!shippingCountryAllowed(opts.country, opts.policy)) {
|
|
23807
|
-
throw new CheckoutValidationError({
|
|
23808
|
-
code,
|
|
23809
|
-
message: opts.countryMessage ?? `We can't ship ${item} to ${opts.country.toUpperCase() || "<unset>"}.`,
|
|
23810
|
-
action
|
|
23811
|
-
});
|
|
23812
|
-
}
|
|
23813
|
-
if (!shippingStateAllowed(opts.state, opts.country, opts.policy)) {
|
|
23814
|
-
throw new CheckoutValidationError({
|
|
23815
|
-
code,
|
|
23816
|
-
message: opts.stateMessage ?? `We can't ship ${item} to ${opts.state.toUpperCase() || "<unset>"}.`,
|
|
23817
|
-
action
|
|
23818
|
-
});
|
|
23819
|
-
}
|
|
23820
|
-
}
|
|
23821
|
-
|
|
23822
|
-
// src/identity/tokens.ts
|
|
23823
|
-
import { createHash } from "crypto";
|
|
23824
|
-
function hashOperatorToken(plaintext) {
|
|
23825
|
-
return createHash("sha256").update(plaintext, "utf8").digest("hex");
|
|
23826
|
-
}
|
|
23827
|
-
function extractOwnerScope(input) {
|
|
23828
|
-
const headers = asHeaders(input);
|
|
23829
|
-
const walletAddress = readHeader(headers, "x-wallet-address");
|
|
23830
|
-
const operatorToken = readHeader(headers, "x-operator-token");
|
|
23831
|
-
return {
|
|
23832
|
-
...walletAddress ? { walletAddress } : {},
|
|
23833
|
-
...operatorToken ? { operatorTokenHash: hashOperatorToken(operatorToken) } : {}
|
|
23834
|
-
};
|
|
23835
|
-
}
|
|
23836
|
-
|
|
23837
24035
|
// src/payment/index.ts
|
|
23838
24036
|
init_directive();
|
|
23839
24037
|
init_networks();
|
|
@@ -23910,6 +24108,7 @@ async function loadSolanaFeePayer(opts) {
|
|
|
23910
24108
|
|
|
23911
24109
|
// src/payment/compose_rails.ts
|
|
23912
24110
|
init_usdc();
|
|
24111
|
+
var warnedStripeBelowMinimum = false;
|
|
23913
24112
|
function buildMppxComposeRails(opts) {
|
|
23914
24113
|
const rails2 = [];
|
|
23915
24114
|
if (opts.tempoRecipient) {
|
|
@@ -23931,7 +24130,17 @@ function buildMppxComposeRails(opts) {
|
|
|
23931
24130
|
}]);
|
|
23932
24131
|
}
|
|
23933
24132
|
if (opts.includeStripe !== false) {
|
|
23934
|
-
|
|
24133
|
+
const amountUsdNumeric = Number(opts.amountUsd);
|
|
24134
|
+
if (Number.isFinite(amountUsdNumeric) && amountUsdNumeric < STRIPE_MIN_CHARGE_USD) {
|
|
24135
|
+
if (!warnedStripeBelowMinimum) {
|
|
24136
|
+
warnedStripeBelowMinimum = true;
|
|
24137
|
+
console.warn(
|
|
24138
|
+
`[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.`
|
|
24139
|
+
);
|
|
24140
|
+
}
|
|
24141
|
+
} else {
|
|
24142
|
+
rails2.push(["stripe/charge", { amount: opts.amountUsd, currency: "usd", decimals: 2 }]);
|
|
24143
|
+
}
|
|
23935
24144
|
}
|
|
23936
24145
|
return rails2;
|
|
23937
24146
|
}
|
|
@@ -24122,10 +24331,11 @@ function computeFirstCheckout(opts) {
|
|
|
24122
24331
|
const tempoRecipient = recipients.tempo;
|
|
24123
24332
|
const x402BaseRecipient = recipients.x402_base;
|
|
24124
24333
|
const solanaRecipient = recipients.solana_mpp;
|
|
24334
|
+
const includeStripeInDiscovery = opts.rails.stripe !== void 0 && Number(totalUsd) >= STRIPE_MIN_CHARGE_USD;
|
|
24125
24335
|
const accepted = await buildAcceptedMethods({
|
|
24126
24336
|
...tempoRecipient && opts.rails.tempo && { tempo: { ...opts.rails.tempo, recipient: tempoRecipient } },
|
|
24127
24337
|
...solanaRecipient && opts.rails.solana_mpp && { solana_mpp: { ...opts.rails.solana_mpp, recipient: solanaRecipient } },
|
|
24128
|
-
...
|
|
24338
|
+
...includeStripeInDiscovery && { stripe: opts.rails.stripe }
|
|
24129
24339
|
});
|
|
24130
24340
|
if (x402BaseRecipient && opts.rails.x402_base) {
|
|
24131
24341
|
try {
|
|
@@ -24202,6 +24412,36 @@ function computeFirstCheckout(opts) {
|
|
|
24202
24412
|
);
|
|
24203
24413
|
return new Response(JSON.stringify(body402), { status: 402, headers });
|
|
24204
24414
|
}
|
|
24415
|
+
async function enforceWalletSanctions(req, referenceId) {
|
|
24416
|
+
const apiKey = process.env.AGENTSCORE_API_KEY;
|
|
24417
|
+
if (!apiKey) {
|
|
24418
|
+
warnMissingApiKeyOnce(`${opts.name}.computeFirst`);
|
|
24419
|
+
return null;
|
|
24420
|
+
}
|
|
24421
|
+
const x402Header = readX402PaymentHeader(req);
|
|
24422
|
+
const signer = await extractPaymentSigner(req, x402Header);
|
|
24423
|
+
if (!signer) return null;
|
|
24424
|
+
const baseUrl = process.env.AGENTSCORE_BASE_URL;
|
|
24425
|
+
const core = createAgentScoreCore({
|
|
24426
|
+
apiKey,
|
|
24427
|
+
...baseUrl !== void 0 && { baseUrl }
|
|
24428
|
+
});
|
|
24429
|
+
const outcome = await core.evaluate({ address: signer.address }, void 0, signer);
|
|
24430
|
+
if (outcome.kind === "allow") return null;
|
|
24431
|
+
const reason = outcome.reason;
|
|
24432
|
+
const body = denialReasonToBody(reason);
|
|
24433
|
+
const status = reason.code === "token_expired" || reason.code === "invalid_credential" ? 401 : reason.code === "api_error" ? 503 : 403;
|
|
24434
|
+
return new Response(
|
|
24435
|
+
JSON.stringify({
|
|
24436
|
+
id: referenceId,
|
|
24437
|
+
endpoint: opts.name,
|
|
24438
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24439
|
+
payment_status: "failed",
|
|
24440
|
+
...body
|
|
24441
|
+
}),
|
|
24442
|
+
{ status, headers: { "Content-Type": "application/json" } }
|
|
24443
|
+
);
|
|
24444
|
+
}
|
|
24205
24445
|
async function handleX402Settle(req, referenceId, cachedBody, priceCents, recipients) {
|
|
24206
24446
|
const verified = await verifyX402Request({
|
|
24207
24447
|
request: req,
|
|
@@ -24400,6 +24640,8 @@ function computeFirstCheckout(opts) {
|
|
|
24400
24640
|
{ status: 400, headers: { "Content-Type": "application/json" } }
|
|
24401
24641
|
);
|
|
24402
24642
|
}
|
|
24643
|
+
const ofacDenial = await enforceWalletSanctions(req, referenceId);
|
|
24644
|
+
if (ofacDenial !== null) return ofacDenial;
|
|
24403
24645
|
if (hasX402Header(req.headers)) return handleX402Settle(req, referenceId, quote2.body, quote2.priceCents, quote2.recipients);
|
|
24404
24646
|
return handleMppSettle(req, referenceId, quote2.body, quote2.priceCents, quote2.recipients);
|
|
24405
24647
|
}
|
|
@@ -24548,6 +24790,7 @@ export {
|
|
|
24548
24790
|
buildMppxComposeRails,
|
|
24549
24791
|
buildSignerMismatchBody,
|
|
24550
24792
|
buildUCPProfile,
|
|
24793
|
+
buildVerificationRequiredBody,
|
|
24551
24794
|
computeFirstCheckout,
|
|
24552
24795
|
createDefaultOnDenied,
|
|
24553
24796
|
createQuoteCache,
|