@t2000/sdk 9.2.0 → 9.3.1

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/browser.cjs CHANGED
@@ -447,6 +447,13 @@ var ZkLoginSigner = class {
447
447
  // src/wallet/pay.ts
448
448
  init_errors();
449
449
 
450
+ // src/mpp-cost.ts
451
+ function parseChallengeAmount(challenge) {
452
+ const raw = challenge?.request?.amount;
453
+ const n = typeof raw === "string" ? Number(raw) : typeof raw === "number" ? raw : Number.NaN;
454
+ return Number.isFinite(n) ? n : void 0;
455
+ }
456
+
450
457
  // src/wallet/executeTx.ts
451
458
  async function executeTx(client, signer, buildTx, options = {}) {
452
459
  const tx = await buildTx();
@@ -459,7 +466,11 @@ async function executeTx(client, signer, buildTx, options = {}) {
459
466
  include: { effects: true }
460
467
  });
461
468
  const txn = result.$kind === "Transaction" ? result.Transaction : result.FailedTransaction;
462
- await client.core.waitForTransaction({ digest: txn.digest });
469
+ try {
470
+ await client.core.waitForTransaction({ digest: txn.digest });
471
+ } catch (err) {
472
+ if (!txn.effects) throw err;
473
+ }
463
474
  const effects = txn.effects ?? void 0;
464
475
  const gasUsed = effects?.gasUsed;
465
476
  let gasCostSui = 0;
@@ -520,11 +531,18 @@ function preflightPay(input) {
520
531
  return PREFLIGHT_OK;
521
532
  }
522
533
  async function payWithMpp(args) {
523
- const { signer, client, options } = args;
534
+ const { signer, client } = args;
535
+ let options = args.options;
524
536
  const pf = preflightPay({ url: options.url, maxPrice: options.maxPrice });
525
537
  if (!pf.valid) throw new exports.T2000Error(pf.code, pf.error);
526
538
  const method = (options.method ?? "GET").toUpperCase();
527
539
  const canHaveBody = method !== "GET" && method !== "HEAD";
540
+ if (canHaveBody && typeof options.body === "string" && isJsonText(options.body) && !hasContentType(options.headers)) {
541
+ options = {
542
+ ...options,
543
+ headers: { ...options.headers ?? {}, "content-type": "application/json" }
544
+ };
545
+ }
528
546
  const reqInit = {
529
547
  method,
530
548
  headers: options.headers,
@@ -535,13 +553,35 @@ async function payWithMpp(args) {
535
553
  return finalize(probe, { paid: false });
536
554
  }
537
555
  const requirements = await pickSuiExactRequirements(probe, client.network);
538
- if (!requirements) {
539
- throw new exports.T2000Error(
540
- "FACILITATOR_REJECTION",
541
- `Endpoint returned 402 without an x402 'exact' / sui:${client.network} payment requirement. This SDK only speaks the x402 dialect.`
542
- );
556
+ if (requirements) {
557
+ return payViaX402({ signer, client, options, reqInit, requirements });
558
+ }
559
+ const headerChallenge = await parseMppSuiChallenge(probe);
560
+ if (headerChallenge) {
561
+ return payViaMppHeader({ signer, client, options });
562
+ }
563
+ throw new exports.T2000Error(
564
+ "FACILITATOR_REJECTION",
565
+ `Endpoint returned 402 without an x402 'exact' / sui:${client.network} requirement in the body or an MPP 'sui' challenge in WWW-Authenticate. Nothing this SDK can pay.`
566
+ );
567
+ }
568
+ async function parseMppSuiChallenge(response) {
569
+ try {
570
+ const { Challenge } = await import('mppx');
571
+ const challenges = Challenge.fromResponseList(response);
572
+ const suiChallenge = challenges.find((c) => c.method === "sui" && c.intent === "charge");
573
+ if (!suiChallenge) return void 0;
574
+ const req = suiChallenge.request;
575
+ if (typeof req?.amount !== "string" || typeof req?.recipient !== "string") return void 0;
576
+ return {
577
+ amount: req.amount,
578
+ currency: typeof req.currency === "string" ? req.currency : "",
579
+ recipient: req.recipient,
580
+ description: suiChallenge.description
581
+ };
582
+ } catch {
583
+ return void 0;
543
584
  }
544
- return payViaX402({ signer, client, options, reqInit, requirements });
545
585
  }
546
586
  async function pickSuiExactRequirements(response, network) {
547
587
  try {
@@ -556,6 +596,7 @@ async function payViaX402(args) {
556
596
  const { signer, client, options, reqInit, requirements } = args;
557
597
  const { buildX402SignedPayment, X402_PAYMENT_HEADER, X402_PAYMENT_RESPONSE_HEADER } = await import('@suimpp/mpp/x402');
558
598
  const amountRaw = BigInt(requirements.maxAmountRequired);
599
+ assertWithinMaxPrice(atomicToHuman(amountRaw, await assetDecimals(requirements.asset)), options.maxPrice);
559
600
  const migrationGasSui = await ensureAddressBalanceCovers({
560
601
  signer,
561
602
  client,
@@ -591,6 +632,70 @@ async function payViaX402(args) {
591
632
  receipt: digest ? { reference: digest, timestamp: (/* @__PURE__ */ new Date()).toISOString() } : result.receipt
592
633
  };
593
634
  }
635
+ async function payViaMppHeader(args) {
636
+ const { signer, client, options } = args;
637
+ const { Mppx } = await import('mppx/client');
638
+ const { sui, USDC, USDC_TESTNET } = await import('@suimpp/mpp/client');
639
+ const signerAddress = signer.getAddress();
640
+ const network = client.network === "testnet" ? "testnet" : "mainnet";
641
+ const grpcClient = await makeGrpcBuildClient(client);
642
+ let paymentDigest;
643
+ let gasCostSui = 0;
644
+ let chargedAmount;
645
+ const mppx = Mppx.create({
646
+ polyfill: false,
647
+ onChallenge: async (challenge) => {
648
+ const parsed = parseChallengeAmount(challenge);
649
+ if (parsed !== void 0) {
650
+ chargedAmount = parsed;
651
+ assertWithinMaxPrice(parsed, options.maxPrice);
652
+ }
653
+ return void 0;
654
+ },
655
+ methods: [
656
+ sui({
657
+ client,
658
+ currency: network === "testnet" ? USDC_TESTNET : USDC,
659
+ signer: {
660
+ toSuiAddress: () => signerAddress,
661
+ signPersonalMessage: (bytes) => signer.signPersonalMessage(bytes)
662
+ },
663
+ execute: async (tx) => {
664
+ const result2 = await executeTx(client, signer, () => tx, { buildClient: grpcClient });
665
+ paymentDigest = result2.digest;
666
+ gasCostSui = result2.gasCostSui;
667
+ return { digest: result2.digest };
668
+ }
669
+ })
670
+ ]
671
+ });
672
+ const method = (options.method ?? "GET").toUpperCase();
673
+ const canHaveBody = method !== "GET" && method !== "HEAD";
674
+ const response = await mppx.fetch(options.url, {
675
+ method,
676
+ headers: options.headers,
677
+ body: canHaveBody ? options.body : void 0
678
+ });
679
+ const paid = !!paymentDigest;
680
+ const result = await finalize(response, { paid });
681
+ if (!paid) return { ...result, dialect: "legacy" };
682
+ return {
683
+ ...result,
684
+ dialect: "legacy",
685
+ cost: chargedAmount ?? options.maxPrice ?? void 0,
686
+ gasCostSui,
687
+ receipt: paymentDigest ? { reference: paymentDigest, timestamp: (/* @__PURE__ */ new Date()).toISOString() } : void 0
688
+ };
689
+ }
690
+ function assertWithinMaxPrice(price, maxPrice) {
691
+ if (maxPrice !== void 0 && price > maxPrice) {
692
+ throw new exports.T2000Error(
693
+ "PRICE_EXCEEDS_LIMIT",
694
+ `Service price $${price} exceeds maxPrice ceiling $${maxPrice}`,
695
+ { price, maxPrice }
696
+ );
697
+ }
698
+ }
594
699
  async function ensureAddressBalanceCovers(args) {
595
700
  const { signer, client, asset, amountRaw } = args;
596
701
  const owner = signer.getAddress();
@@ -624,6 +729,18 @@ async function ensureAddressBalanceCovers(args) {
624
729
  const migration = await executeTx(client, signer, () => tx, { buildClient: grpcClient });
625
730
  return migration.gasCostSui;
626
731
  }
732
+ function isJsonText(text) {
733
+ try {
734
+ JSON.parse(text);
735
+ return true;
736
+ } catch {
737
+ return false;
738
+ }
739
+ }
740
+ function hasContentType(headers) {
741
+ if (!headers) return false;
742
+ return Object.keys(headers).some((k) => k.toLowerCase() === "content-type");
743
+ }
627
744
  async function finalize(response, opts) {
628
745
  const contentType = response.headers.get("content-type") ?? "";
629
746
  let body;
@@ -1211,6 +1328,7 @@ exports.getDecimalsForCoinType = getDecimalsForCoinType;
1211
1328
  exports.mapMoveAbortCode = mapMoveAbortCode;
1212
1329
  exports.mapWalletError = mapWalletError;
1213
1330
  exports.mistToSui = mistToSui;
1331
+ exports.parseMppSuiChallenge = parseMppSuiChallenge;
1214
1332
  exports.parseSuiRpcTx = parseSuiRpcTx;
1215
1333
  exports.payWithMpp = payWithMpp;
1216
1334
  exports.preflightFail = preflightFail;