@devlab.group/agent-commerce 2.4.0 → 2.5.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.
Files changed (108) hide show
  1. package/README.md +115 -15
  2. package/dist/ap2.d.ts +24 -12
  3. package/dist/ap2.js +31 -13
  4. package/dist/ap2.js.map +1 -1
  5. package/dist/{chunk-AITMDXKW.js → chunk-3OTCFFFT.js} +37 -4
  6. package/dist/chunk-3OTCFFFT.js.map +1 -0
  7. package/dist/{chunk-4OEXK3YG.js → chunk-4K7FIBJM.js} +25 -4
  8. package/dist/chunk-4K7FIBJM.js.map +1 -0
  9. package/dist/{chunk-WUIAUAA7.js → chunk-FKQK5XZA.js} +652 -68
  10. package/dist/chunk-FKQK5XZA.js.map +1 -0
  11. package/dist/chunk-GA3O2A7R.js +92 -0
  12. package/dist/chunk-GA3O2A7R.js.map +1 -0
  13. package/dist/{chunk-6WACRJVT.js → chunk-VUCMBGUR.js} +3 -3
  14. package/dist/{chunk-6WACRJVT.js.map → chunk-VUCMBGUR.js.map} +1 -1
  15. package/dist/cli/{ap2-QDHPRSTF.js → ap2-YAPLERSC.js} +34 -15
  16. package/dist/cli/ap2-YAPLERSC.js.map +1 -0
  17. package/dist/cli/{chunk-G2JEY7MB.js → chunk-2J2IQQ4X.js} +8 -7
  18. package/dist/cli/chunk-2J2IQQ4X.js.map +1 -0
  19. package/dist/cli/chunk-2UPPX3FJ.js +311 -0
  20. package/dist/cli/chunk-2UPPX3FJ.js.map +1 -0
  21. package/dist/cli/{chunk-WYOGIANL.js → chunk-4H2QLHQI.js} +4 -4
  22. package/dist/cli/{chunk-WYOGIANL.js.map → chunk-4H2QLHQI.js.map} +1 -1
  23. package/dist/cli/{chunk-OZ4LAWBK.js → chunk-5R7DM5LM.js} +25 -4
  24. package/dist/cli/chunk-5R7DM5LM.js.map +1 -0
  25. package/dist/cli/chunk-663ALDZA.js +92 -0
  26. package/dist/cli/chunk-663ALDZA.js.map +1 -0
  27. package/dist/cli/{chunk-QQ3WY5L3.js → chunk-IDY2735M.js} +36 -104
  28. package/dist/cli/chunk-IDY2735M.js.map +1 -0
  29. package/dist/cli/chunk-JFVRG2HH.js +107 -0
  30. package/dist/cli/chunk-JFVRG2HH.js.map +1 -0
  31. package/dist/cli/chunk-M7NXVRU5.js +8 -0
  32. package/dist/cli/{chunk-UXB65XCS.js.map → chunk-M7NXVRU5.js.map} +1 -1
  33. package/dist/cli/chunk-NIU5EMSB.js +119 -0
  34. package/dist/cli/chunk-NIU5EMSB.js.map +1 -0
  35. package/dist/cli/{chunk-AZDWFVDW.js → chunk-QA2OPHBF.js} +655 -70
  36. package/dist/cli/chunk-QA2OPHBF.js.map +1 -0
  37. package/dist/cli/{chunk-DCMW67JM.js → chunk-QLUCNPRT.js} +404 -161
  38. package/dist/cli/chunk-QLUCNPRT.js.map +1 -0
  39. package/dist/cli/chunk-SYQLJXIU.js +105 -0
  40. package/dist/cli/chunk-SYQLJXIU.js.map +1 -0
  41. package/dist/cli/{chunk-3MGAJ5FX.js → chunk-VJ4EO4LE.js} +3 -3
  42. package/dist/cli/{chunk-3MGAJ5FX.js.map → chunk-VJ4EO4LE.js.map} +1 -1
  43. package/dist/cli/{chunk-PIMFPCNZ.js → chunk-Z34UMZBB.js} +234 -85
  44. package/dist/cli/chunk-Z34UMZBB.js.map +1 -0
  45. package/dist/cli/config-BWFMN2ZB.js +12 -0
  46. package/dist/cli/{config-UI4EDG4L.js.map → config-BWFMN2ZB.js.map} +1 -1
  47. package/dist/cli/index.js +258 -11
  48. package/dist/cli/index.js.map +1 -1
  49. package/dist/cli/{mcp-26LJMN4N.js → mcp-KZEMXLHR.js} +5 -4
  50. package/dist/cli/mcp-KZEMXLHR.js.map +1 -0
  51. package/dist/cli/{near-5AY3HWYF.js → near-U6365VFX.js} +15 -4
  52. package/dist/cli/near-U6365VFX.js.map +1 -0
  53. package/dist/cli/payment-providers-SZL36H3Y.js +6 -0
  54. package/dist/cli/payment-providers-SZL36H3Y.js.map +1 -0
  55. package/dist/cli/{provider-Z4OJNAYI.js → provider-6TKB5ADJ.js} +30 -16
  56. package/dist/cli/provider-6TKB5ADJ.js.map +1 -0
  57. package/dist/cli/receipts-ZGLJWMQG.js +8 -0
  58. package/dist/cli/receipts-ZGLJWMQG.js.map +1 -0
  59. package/dist/cli/reconcile-IC22MJD5.js +4 -0
  60. package/dist/cli/reconcile-IC22MJD5.js.map +1 -0
  61. package/dist/cli/{run-TEPYJUHG.js → run-ZTYPQI4D.js} +151 -115
  62. package/dist/cli/run-ZTYPQI4D.js.map +1 -0
  63. package/dist/cli/svm-KDSPDFJG.js +48 -0
  64. package/dist/cli/svm-KDSPDFJG.js.map +1 -0
  65. package/dist/cli/{x402-BMVONZKA.js → x402-WLYBLODI.js} +10 -9
  66. package/dist/cli/x402-WLYBLODI.js.map +1 -0
  67. package/dist/index.d.ts +112 -12
  68. package/dist/index.js +948 -157
  69. package/dist/index.js.map +1 -1
  70. package/dist/mcp.d.ts +1 -2
  71. package/dist/mcp.js +1 -1
  72. package/dist/mpp.js +24 -11
  73. package/dist/mpp.js.map +1 -1
  74. package/dist/{near-D6C42VPE.js → near-FH7HPZV3.js} +15 -4
  75. package/dist/near-FH7HPZV3.js.map +1 -0
  76. package/dist/{protocol-adapter-C9odYl6l.d.ts → protocol-adapter-DEXpdp8m.d.ts} +102 -48
  77. package/dist/{runtime-Cl_BLVZV.d.ts → runtime-Dz2fSO-P.d.ts} +220 -2
  78. package/dist/svm-KNC3PHMS.js +48 -0
  79. package/dist/svm-KNC3PHMS.js.map +1 -0
  80. package/dist/x402.js +5 -5
  81. package/package.json +1 -1
  82. package/dist/authorization-DjAecwuW.d.ts +0 -115
  83. package/dist/chunk-4OEXK3YG.js.map +0 -1
  84. package/dist/chunk-AITMDXKW.js.map +0 -1
  85. package/dist/chunk-KA2AX5FH.js +0 -44
  86. package/dist/chunk-KA2AX5FH.js.map +0 -1
  87. package/dist/chunk-WUIAUAA7.js.map +0 -1
  88. package/dist/cli/ap2-QDHPRSTF.js.map +0 -1
  89. package/dist/cli/chunk-AZDWFVDW.js.map +0 -1
  90. package/dist/cli/chunk-DCMW67JM.js.map +0 -1
  91. package/dist/cli/chunk-G2JEY7MB.js.map +0 -1
  92. package/dist/cli/chunk-OSTCU6ZK.js +0 -44
  93. package/dist/cli/chunk-OSTCU6ZK.js.map +0 -1
  94. package/dist/cli/chunk-OZ4LAWBK.js.map +0 -1
  95. package/dist/cli/chunk-PIMFPCNZ.js.map +0 -1
  96. package/dist/cli/chunk-QQ3WY5L3.js.map +0 -1
  97. package/dist/cli/chunk-UXB65XCS.js +0 -8
  98. package/dist/cli/config-UI4EDG4L.js +0 -11
  99. package/dist/cli/mcp-26LJMN4N.js.map +0 -1
  100. package/dist/cli/near-5AY3HWYF.js.map +0 -1
  101. package/dist/cli/provider-Z4OJNAYI.js.map +0 -1
  102. package/dist/cli/run-TEPYJUHG.js.map +0 -1
  103. package/dist/cli/svm-3MMYFPC7.js +0 -33
  104. package/dist/cli/svm-3MMYFPC7.js.map +0 -1
  105. package/dist/cli/x402-BMVONZKA.js.map +0 -1
  106. package/dist/near-D6C42VPE.js.map +0 -1
  107. package/dist/svm-QEUAUNPQ.js +0 -33
  108. package/dist/svm-QEUAUNPQ.js.map +0 -1
@@ -1,6 +1,8 @@
1
- import { SETTLE_AFTER_BACKEND_METADATA_KEY, REUSE_REJECTED_AUTHORIZATION_METADATA_KEY } from './chunk-OZ4LAWBK.js';
2
- import { RESERVED_INPUT_FIELDS, NOOP_LOGGER, DEFAULT_BACKEND_TIMEOUT_MS, CommerceError, isCommerceError, describeError, toCommerceError } from './chunk-QQ3WY5L3.js';
1
+ import { SETTLE_AFTER_BACKEND_METADATA_KEY, REUSE_REJECTED_AUTHORIZATION_METADATA_KEY, canonicalJson } from './chunk-5R7DM5LM.js';
2
+ import { RESERVED_INPUT_FIELDS, NOOP_LOGGER, DEFAULT_BACKEND_TIMEOUT_MS, RECONCILIATION_METADATA_KEY } from './chunk-IDY2735M.js';
3
+ import { CommerceError, isCommerceError, describeError, toCommerceError } from './chunk-SYQLJXIU.js';
3
4
  import { isRecord } from './chunk-3M6U7ILB.js';
5
+ import { createHash } from 'crypto';
4
6
  import { isDeepStrictEqual } from 'util';
5
7
 
6
8
  // src/config/filename.ts
@@ -352,6 +354,56 @@ function safeStringify(value) {
352
354
  function isAbortError(error) {
353
355
  return error instanceof Error && (error.name === "TimeoutError" || error.name === "AbortError");
354
356
  }
357
+ function createFlow(request, transactionId) {
358
+ return { request, transactionId, persistenceFailures: [], journaled: false };
359
+ }
360
+ function failuresOf(flow) {
361
+ return flow.persistenceFailures.length > 0 ? { persistenceFailures: [...flow.persistenceFailures] } : {};
362
+ }
363
+ function sha256(text) {
364
+ return `sha256:${createHash("sha256").update(text, "utf8").digest("hex")}`;
365
+ }
366
+ function inputDigest(input) {
367
+ const json = canonicalJson(input);
368
+ return json !== void 0 ? sha256(json) : void 0;
369
+ }
370
+ function configDigest(resource, requirement) {
371
+ const terms = {
372
+ resourceId: resource.id,
373
+ pricing: resource.pricing,
374
+ paymentMethods: resource.paymentMethods,
375
+ authorization: resource.authorization?.required ?? [],
376
+ requirement: {
377
+ provider: requirement.provider,
378
+ amount: requirement.amount,
379
+ currency: requirement.currency,
380
+ destination: requirement.destination ?? null,
381
+ network: requirement.network ?? null,
382
+ asset: requirement.asset ?? null,
383
+ settleAfterBackend: requirement.metadata?.[SETTLE_AFTER_BACKEND_METADATA_KEY] === true
384
+ }
385
+ };
386
+ return sha256(canonicalJson(terms) ?? JSON.stringify(terms));
387
+ }
388
+ function newTransaction(flow, resource, requirement, verification, validInput, authorization) {
389
+ const raw = verification.metadata?.[RECONCILIATION_METADATA_KEY];
390
+ const locator = isRecord(raw) ? raw : void 0;
391
+ const expiresAt = typeof locator?.["expiresAt"] === "string" ? locator["expiresAt"] : void 0;
392
+ const network = verification.network ?? requirement.network;
393
+ const asset = verification.asset ?? requirement.asset;
394
+ const digest = inputDigest(validInput);
395
+ return {
396
+ id: flow.transactionId,
397
+ protocol: flow.request.protocol,
398
+ ...network !== void 0 ? { network } : {},
399
+ ...asset !== void 0 ? { asset } : {},
400
+ ...locator !== void 0 ? { locator } : {},
401
+ ...expiresAt !== void 0 ? { expiresAt } : {},
402
+ ...authorization !== void 0 ? { authorization } : {},
403
+ ...digest !== void 0 ? { inputDigest: digest } : {},
404
+ configDigest: configDigest(resource, requirement)
405
+ };
406
+ }
355
407
  var SUPPORTED_TYPES = /* @__PURE__ */ new Set([
356
408
  "object",
357
409
  "string",
@@ -494,16 +546,15 @@ function resolveAuthorizationProviders(providers, resource, requestId) {
494
546
  }
495
547
  function createAuthorizeAndReserve(ctx) {
496
548
  const { options, safeEmit, buildEvent } = ctx;
497
- async function authorizeAndReserve(request, resource, providers, requirement, input) {
549
+ async function authorizeAndReserve(flow, request, resource, providers, requirement, input) {
498
550
  if (providers.length === 0) return void 0;
499
551
  const submission = request.authorization;
500
552
  const provider = providers.find((candidate) => candidate.name === submission?.method);
501
553
  const unmet = providers.filter((candidate) => candidate !== provider).map((c) => c.name);
502
554
  if (submission === void 0 || provider === void 0 || unmet.length > 0) {
503
555
  await safeEmit(
504
- buildEvent({
556
+ buildEvent(flow, {
505
557
  type: "authorization.rejected",
506
- requestId: request.requestId,
507
558
  resourceId: resource.id,
508
559
  adapter: request.protocol,
509
560
  status: "error",
@@ -540,9 +591,8 @@ function createAuthorizeAndReserve(ctx) {
540
591
  }
541
592
  );
542
593
  await safeEmit(
543
- buildEvent({
594
+ buildEvent(flow, {
544
595
  type: "authorization.rejected",
545
- requestId: request.requestId,
546
596
  resourceId: resource.id,
547
597
  adapter: request.protocol,
548
598
  status: "error",
@@ -552,9 +602,8 @@ function createAuthorizeAndReserve(ctx) {
552
602
  throw mapped;
553
603
  }
554
604
  await safeEmit(
555
- buildEvent({
605
+ buildEvent(flow, {
556
606
  type: "authorization.verified",
557
- requestId: request.requestId,
558
607
  resourceId: resource.id,
559
608
  adapter: request.protocol,
560
609
  status: "ok",
@@ -568,14 +617,17 @@ function createAuthorizeAndReserve(ctx) {
568
617
  reference: verification.reference,
569
618
  ...verification.metadata !== void 0 ? { metadata: verification.metadata } : {}
570
619
  },
620
+ reservationId: verification.reservationId,
571
621
  async finalize(action) {
572
622
  try {
573
623
  await provider[action](verification.reservationId, context);
624
+ return true;
574
625
  } catch (error) {
575
626
  options.logger.error(
576
627
  { err: describeError(error), requestId: request.requestId, action },
577
628
  "Authorization finalization failed; the reservation stays reserved"
578
629
  );
630
+ return false;
579
631
  }
580
632
  }
581
633
  };
@@ -616,7 +668,7 @@ function replayError(error, requirement) {
616
668
  // src/core/execution/pipeline/admission.ts
617
669
  function createPaymentAdmission(ctx, authorizeAndReserve) {
618
670
  const { options, safeEmit, buildEvent } = ctx;
619
- return async function admitPayment(request, resource, pricing, validInput) {
671
+ return async function admitPayment(flow, request, resource, pricing, validInput) {
620
672
  const provider = pickProvider(options.paymentProviders, resource.paymentMethods);
621
673
  if (!provider) {
622
674
  throw new CommerceError(
@@ -655,9 +707,8 @@ function createPaymentAdmission(ctx, authorizeAndReserve) {
655
707
  }
656
708
  if (!request.payment) {
657
709
  await safeEmit(
658
- buildEvent({
710
+ buildEvent(flow, {
659
711
  type: "payment.required",
660
- requestId: request.requestId,
661
712
  resourceId: resource.id,
662
713
  adapter: request.protocol,
663
714
  paymentProvider: provider.name
@@ -666,6 +717,7 @@ function createPaymentAdmission(ctx, authorizeAndReserve) {
666
717
  return {
667
718
  kind: "payment-required",
668
719
  requestId: request.requestId,
720
+ transactionId: flow.transactionId,
669
721
  resourceId: resource.id,
670
722
  requirement,
671
723
  ...authProviders.length > 0 ? { authorization: authProviders.map((p) => p.requirement) } : {}
@@ -696,9 +748,8 @@ function createPaymentAdmission(ctx, authorizeAndReserve) {
696
748
  ...retryChallenge(requirement)
697
749
  });
698
750
  await safeEmit(
699
- buildEvent({
751
+ buildEvent(flow, {
700
752
  type: "payment.rejected",
701
- requestId: request.requestId,
702
753
  resourceId: resource.id,
703
754
  adapter: request.protocol,
704
755
  paymentProvider: provider.name,
@@ -710,9 +761,8 @@ function createPaymentAdmission(ctx, authorizeAndReserve) {
710
761
  }
711
762
  if (verification.status !== "verified") {
712
763
  await safeEmit(
713
- buildEvent({
764
+ buildEvent(flow, {
714
765
  type: "payment.rejected",
715
- requestId: request.requestId,
716
766
  resourceId: resource.id,
717
767
  adapter: request.protocol,
718
768
  paymentProvider: provider.name,
@@ -732,9 +782,8 @@ function createPaymentAdmission(ctx, authorizeAndReserve) {
732
782
  }
733
783
  if (!verification.replayKey) {
734
784
  await safeEmit(
735
- buildEvent({
785
+ buildEvent(flow, {
736
786
  type: "payment.rejected",
737
- requestId: request.requestId,
738
787
  resourceId: resource.id,
739
788
  adapter: request.protocol,
740
789
  paymentProvider: provider.name,
@@ -749,6 +798,7 @@ function createPaymentAdmission(ctx, authorizeAndReserve) {
749
798
  }
750
799
  const replayKey = verification.replayKey;
751
800
  const hold = await authorizeAndReserve(
801
+ flow,
752
802
  request,
753
803
  resource,
754
804
  authProviders,
@@ -756,7 +806,7 @@ function createPaymentAdmission(ctx, authorizeAndReserve) {
756
806
  validInput
757
807
  );
758
808
  try {
759
- await options.store.reservePaymentAttempt({
809
+ const attempt = await options.store.reservePaymentAttempt({
760
810
  requestId: request.requestId,
761
811
  resourceId: resource.id,
762
812
  provider: provider.name,
@@ -765,8 +815,17 @@ function createPaymentAdmission(ctx, authorizeAndReserve) {
765
815
  currency: verification.currency,
766
816
  ...verification.payer !== void 0 ? { payer: verification.payer } : {},
767
817
  ...verification.payee !== void 0 ? { payee: verification.payee } : {},
768
- ...requirement.metadata?.[REUSE_REJECTED_AUTHORIZATION_METADATA_KEY] === true ? { reclaimRejected: true } : {}
818
+ ...requirement.metadata?.[REUSE_REJECTED_AUTHORIZATION_METADATA_KEY] === true ? { reclaimRejected: true } : {},
819
+ transaction: newTransaction(
820
+ flow,
821
+ resource,
822
+ requirement,
823
+ verification,
824
+ validInput,
825
+ hold !== void 0 ? { ...hold.record, reservationId: hold.reservationId } : void 0
826
+ )
769
827
  });
828
+ flow.journaled = attempt.transactionId === flow.transactionId && options.store.recordTransactionStep !== void 0;
770
829
  } catch (error) {
771
830
  const mapped = toCommerceError(
772
831
  error,
@@ -775,9 +834,8 @@ function createPaymentAdmission(ctx, authorizeAndReserve) {
775
834
  );
776
835
  await hold?.finalize("release");
777
836
  await safeEmit(
778
- buildEvent({
837
+ buildEvent(flow, {
779
838
  type: "payment.rejected",
780
- requestId: request.requestId,
781
839
  resourceId: resource.id,
782
840
  adapter: request.protocol,
783
841
  paymentProvider: provider.name,
@@ -788,9 +846,8 @@ function createPaymentAdmission(ctx, authorizeAndReserve) {
788
846
  throw replayError(mapped, requirement);
789
847
  }
790
848
  await safeEmit(
791
- buildEvent({
849
+ buildEvent(flow, {
792
850
  type: "payment.verified",
793
- requestId: request.requestId,
794
851
  resourceId: resource.id,
795
852
  adapter: request.protocol,
796
853
  paymentProvider: provider.name,
@@ -800,6 +857,7 @@ function createPaymentAdmission(ctx, authorizeAndReserve) {
800
857
  return {
801
858
  kind: "admitted",
802
859
  settleArgs: {
860
+ flow,
803
861
  request,
804
862
  resource,
805
863
  provider,
@@ -821,6 +879,11 @@ function pickProvider(providers, methods) {
821
879
  }
822
880
 
823
881
  // src/core/execution/pipeline/context.ts
882
+ var HOLD_STATES = {
883
+ consume: "consumed",
884
+ release: "released",
885
+ markUncertain: "uncertain"
886
+ };
824
887
  function createPipelineContext(options) {
825
888
  async function safeEmit(event) {
826
889
  try {
@@ -832,27 +895,73 @@ function createPipelineContext(options) {
832
895
  );
833
896
  }
834
897
  }
835
- async function safePersist(op, label, requestId) {
898
+ async function safePersist(flow, op, label, failure) {
836
899
  try {
837
900
  await op();
901
+ return true;
838
902
  } catch (error) {
839
903
  options.logger.error(
840
- { err: describeError(error), requestId },
904
+ {
905
+ err: describeError(error),
906
+ requestId: flow.request.requestId,
907
+ transactionId: flow.transactionId
908
+ },
841
909
  `Persistence failed: ${label}`
842
910
  );
911
+ if (failure !== void 0 && !flow.persistenceFailures.includes(failure)) {
912
+ flow.persistenceFailures.push(failure);
913
+ }
914
+ return false;
843
915
  }
844
916
  }
845
- function buildEvent(partial) {
846
- return { id: options.ids.next("evt"), at: options.clock.nowIso(), ...partial };
917
+ async function recordStep(flow, step) {
918
+ const record = options.store.recordTransactionStep;
919
+ if (!flow.journaled || record === void 0) return;
920
+ const full = {
921
+ ...step,
922
+ transactionId: flow.transactionId,
923
+ at: options.clock.nowIso()
924
+ };
925
+ await safePersist(
926
+ flow,
927
+ () => record.call(options.store, full),
928
+ `recordTransactionStep(${step.kind})`,
929
+ "journal"
930
+ );
931
+ }
932
+ async function finalizeHold(flow, hold, action) {
933
+ if (hold !== void 0 && await hold.finalize(action)) {
934
+ await recordStep(flow, { kind: "hold", hold: HOLD_STATES[action] });
935
+ }
936
+ }
937
+ function buildEvent(flow, partial) {
938
+ return {
939
+ id: options.ids.next("evt"),
940
+ at: options.clock.nowIso(),
941
+ requestId: flow.request.requestId,
942
+ transactionId: flow.transactionId,
943
+ ...partial
944
+ };
847
945
  }
848
- return { options, safeEmit, safePersist, buildEvent };
946
+ return { options, safeEmit, safePersist, recordStep, finalizeHold, buildEvent };
849
947
  }
850
948
 
851
949
  // src/core/execution/pipeline/settlement.ts
852
950
  function createSettlement(ctx) {
853
- const { options, safeEmit, safePersist, buildEvent } = ctx;
951
+ const { options, safeEmit, safePersist, recordStep, finalizeHold, buildEvent } = ctx;
854
952
  async function settle(args) {
855
- const { request, resource, provider, requirement, payment, verification, replayKey, hold } = args;
953
+ const {
954
+ flow,
955
+ request,
956
+ resource,
957
+ provider,
958
+ requirement,
959
+ payment,
960
+ verification,
961
+ replayKey,
962
+ hold
963
+ } = args;
964
+ await recordStep(flow, { kind: "settling" });
856
965
  let settlement;
857
966
  try {
858
967
  settlement = await provider.settle({
@@ -865,25 +974,29 @@ function createSettlement(ctx) {
865
974
  } catch (error) {
866
975
  const notSubmitted = notSubmittedReason(error);
867
976
  if (notSubmitted !== void 0) {
868
- await hold?.finalize("release");
977
+ await finalizeHold(flow, hold, "release");
869
978
  await safePersist(
979
+ flow,
870
980
  () => options.store.updatePaymentAttempt({
871
981
  replayKey,
872
982
  status: "rejected",
873
983
  rejectionReason: notSubmitted
874
984
  }),
875
985
  "updatePaymentAttempt(not-submitted)",
876
- request.requestId
986
+ "payment-attempt"
877
987
  );
878
988
  await safeEmit(
879
- buildEvent({
989
+ buildEvent(flow, {
880
990
  type: "payment.rejected",
881
- requestId: request.requestId,
882
991
  resourceId: resource.id,
883
992
  adapter: request.protocol,
884
993
  paymentProvider: provider.name,
885
994
  status: "error",
886
- data: { reason: "settlement-not-submitted", providerReason: notSubmitted }
995
+ data: {
996
+ reason: "settlement-not-submitted",
997
+ providerReason: notSubmitted,
998
+ ...failuresOf(flow)
999
+ }
887
1000
  })
888
1001
  );
889
1002
  throw new CommerceError(
@@ -893,8 +1006,9 @@ function createSettlement(ctx) {
893
1006
  );
894
1007
  }
895
1008
  const txHash = settlementTxHash(error);
896
- await hold?.finalize("markUncertain");
1009
+ await finalizeHold(flow, hold, "markUncertain");
897
1010
  await safePersist(
1011
+ flow,
898
1012
  () => options.store.updatePaymentAttempt({
899
1013
  replayKey,
900
1014
  status: "settlement-uncertain",
@@ -902,19 +1016,19 @@ function createSettlement(ctx) {
902
1016
  ...error instanceof Error ? { rejectionReason: error.message } : {}
903
1017
  }),
904
1018
  "updatePaymentAttempt(settlement-uncertain)",
905
- request.requestId
1019
+ "payment-attempt"
906
1020
  );
907
1021
  await safeEmit(
908
- buildEvent({
1022
+ buildEvent(flow, {
909
1023
  type: "payment.rejected",
910
- requestId: request.requestId,
911
1024
  resourceId: resource.id,
912
1025
  adapter: request.protocol,
913
1026
  paymentProvider: provider.name,
914
1027
  status: "error",
915
1028
  data: {
916
1029
  reason: "settlement-uncertain",
917
- ...txHash !== void 0 ? { transactionHash: txHash } : {}
1030
+ ...txHash !== void 0 ? { transactionHash: txHash } : {},
1031
+ ...failuresOf(flow)
918
1032
  }
919
1033
  })
920
1034
  );
@@ -930,8 +1044,9 @@ function createSettlement(ctx) {
930
1044
  });
931
1045
  }
932
1046
  if (settlement.status !== "settled") {
933
- await hold?.finalize("release");
1047
+ await finalizeHold(flow, hold, "release");
934
1048
  await safePersist(
1049
+ flow,
935
1050
  () => options.store.updatePaymentAttempt({
936
1051
  replayKey,
937
1052
  status: "rejected",
@@ -939,17 +1054,19 @@ function createSettlement(ctx) {
939
1054
  ...settlement.externalReference !== void 0 ? { externalReference: settlement.externalReference } : {}
940
1055
  }),
941
1056
  "updatePaymentAttempt(rejected)",
942
- request.requestId
1057
+ "payment-attempt"
943
1058
  );
944
1059
  await safeEmit(
945
- buildEvent({
1060
+ buildEvent(flow, {
946
1061
  type: "payment.rejected",
947
- requestId: request.requestId,
948
1062
  resourceId: resource.id,
949
1063
  adapter: request.protocol,
950
1064
  paymentProvider: provider.name,
951
1065
  status: "error",
952
- data: settlement.rejectionReason ? { reason: settlement.rejectionReason } : {}
1066
+ data: {
1067
+ ...settlement.rejectionReason ? { reason: settlement.rejectionReason } : {},
1068
+ ...failuresOf(flow)
1069
+ }
953
1070
  })
954
1071
  );
955
1072
  const rejectionDetails = retryChallenge(requirement, settlement.rejectionReason).details;
@@ -967,20 +1084,20 @@ function createSettlement(ctx) {
967
1084
  }
968
1085
  );
969
1086
  }
970
- await hold?.finalize("consume");
1087
+ await finalizeHold(flow, hold, "consume");
971
1088
  await safePersist(
1089
+ flow,
972
1090
  () => options.store.updatePaymentAttempt({
973
1091
  replayKey,
974
1092
  status: "settled",
975
1093
  ...settlement.externalReference !== void 0 ? { externalReference: settlement.externalReference } : {}
976
1094
  }),
977
1095
  "updatePaymentAttempt(settled)",
978
- request.requestId
1096
+ "payment-attempt"
979
1097
  );
980
1098
  await safeEmit(
981
- buildEvent({
1099
+ buildEvent(flow, {
982
1100
  type: "payment.settled",
983
- requestId: request.requestId,
984
1101
  resourceId: resource.id,
985
1102
  adapter: request.protocol,
986
1103
  paymentProvider: provider.name,
@@ -990,26 +1107,26 @@ function createSettlement(ctx) {
990
1107
  return settlement;
991
1108
  }
992
1109
  async function abandonSettlement(args, backendErrorCode) {
993
- const { request, resource, provider, replayKey, hold } = args;
994
- await hold?.finalize("release");
1110
+ const { flow, request, resource, provider, replayKey, hold } = args;
1111
+ await finalizeHold(flow, hold, "release");
995
1112
  await safePersist(
1113
+ flow,
996
1114
  () => options.store.updatePaymentAttempt({
997
1115
  replayKey,
998
1116
  status: "rejected",
999
1117
  rejectionReason: "backend_failed"
1000
1118
  }),
1001
1119
  "updatePaymentAttempt(backend-failed)",
1002
- request.requestId
1120
+ "payment-attempt"
1003
1121
  );
1004
1122
  await safeEmit(
1005
- buildEvent({
1123
+ buildEvent(flow, {
1006
1124
  type: "payment.rejected",
1007
- requestId: request.requestId,
1008
1125
  resourceId: resource.id,
1009
1126
  adapter: request.protocol,
1010
1127
  paymentProvider: provider.name,
1011
1128
  status: "error",
1012
- data: { reason: "backend-failed", backendErrorCode }
1129
+ data: { reason: "backend-failed", backendErrorCode, ...failuresOf(flow) }
1013
1130
  })
1014
1131
  );
1015
1132
  }
@@ -1046,7 +1163,7 @@ function createExecutionPipeline(options) {
1046
1163
  return compiled;
1047
1164
  }
1048
1165
  const ctx = createPipelineContext(options);
1049
- const { safeEmit, safePersist, buildEvent } = ctx;
1166
+ const { safeEmit, safePersist, recordStep, buildEvent } = ctx;
1050
1167
  const { settle, abandonSettlement } = createSettlement(ctx);
1051
1168
  const admitPayment = createPaymentAdmission(ctx, createAuthorizeAndReserve(ctx));
1052
1169
  async function execute(request) {
@@ -1062,10 +1179,10 @@ function createExecutionPipeline(options) {
1062
1179
  }
1063
1180
  );
1064
1181
  }
1182
+ const flow = createFlow(request, options.ids.next("txn"));
1065
1183
  await safeEmit(
1066
- buildEvent({
1184
+ buildEvent(flow, {
1067
1185
  type: "resource.requested",
1068
- requestId: request.requestId,
1069
1186
  resourceId: resource.id,
1070
1187
  adapter: request.protocol
1071
1188
  })
@@ -1110,20 +1227,34 @@ function createExecutionPipeline(options) {
1110
1227
  }
1111
1228
  );
1112
1229
  }
1113
- let paymentResult;
1114
- let authorization;
1115
- let deferredSettlement;
1230
+ let settleArgs;
1116
1231
  if (resource.pricing.type === "fixed") {
1117
- const admission = await admitPayment(request, resource, resource.pricing, validInput);
1232
+ const admission = await admitPayment(flow, request, resource, resource.pricing, validInput);
1118
1233
  if (admission.kind === "payment-required") return admission;
1119
- const { settleArgs } = admission;
1120
- authorization = settleArgs.hold?.record;
1234
+ settleArgs = admission.settleArgs;
1235
+ }
1236
+ try {
1237
+ return await settleAndDeliver(flow, resource, validInput, settleArgs, pipelineStart);
1238
+ } finally {
1239
+ await recordStep(flow, { kind: "completed", ...failuresOf(flow) });
1240
+ }
1241
+ }
1242
+ async function settleAndDeliver(flow, resource, validInput, settleArgs, pipelineStart) {
1243
+ const { request } = flow;
1244
+ const authorization = settleArgs?.hold?.record;
1245
+ let paymentResult;
1246
+ let deferredSettlement;
1247
+ if (settleArgs !== void 0) {
1121
1248
  if (settleArgs.requirement.metadata?.[SETTLE_AFTER_BACKEND_METADATA_KEY] === true) {
1122
1249
  deferredSettlement = settleArgs;
1123
1250
  } else {
1124
1251
  paymentResult = await settle(settleArgs);
1125
1252
  }
1126
1253
  }
1254
+ await recordStep(flow, {
1255
+ kind: "backend-dispatched",
1256
+ deadlineAt: backendDeadline(options.clock.now(), resource)
1257
+ });
1127
1258
  const backendStart = options.clock.monotonicMs();
1128
1259
  let backendResponse;
1129
1260
  try {
@@ -1136,18 +1267,23 @@ function createExecutionPipeline(options) {
1136
1267
  });
1137
1268
  } catch (error) {
1138
1269
  const commerceError = toCommerceError(error, "BACKEND_ERROR", "Backend call failed");
1139
- await safeEmit(
1140
- buildEvent({
1270
+ await recordStep(flow, {
1271
+ kind: "backend-result",
1272
+ status: backendErrorStatus(commerceError),
1273
+ errorCode: commerceError.code
1274
+ });
1275
+ const backendFailed = (data = {}) => safeEmit(
1276
+ buildEvent(flow, {
1141
1277
  type: "backend.failed",
1142
- requestId: request.requestId,
1143
1278
  resourceId: resource.id,
1144
1279
  adapter: request.protocol,
1145
1280
  status: "error",
1146
1281
  durationMs: Math.round(options.clock.monotonicMs() - backendStart),
1147
- data: { code: commerceError.code }
1282
+ data: { code: commerceError.code, ...data }
1148
1283
  })
1149
1284
  );
1150
1285
  if (deferredSettlement !== void 0) {
1286
+ await backendFailed();
1151
1287
  await abandonSettlement(deferredSettlement, commerceError.code);
1152
1288
  throw commerceError;
1153
1289
  }
@@ -1161,13 +1297,11 @@ function createExecutionPipeline(options) {
1161
1297
  protocol: request.protocol,
1162
1298
  payment: paymentResult,
1163
1299
  ...authorization !== void 0 ? { authorization } : {},
1164
- metadata: { delivered: false, backendErrorCode: commerceError.code }
1300
+ metadata: { delivered: false, backendErrorCode: commerceError.code },
1301
+ transactionId: flow.transactionId
1165
1302
  };
1166
- await safePersist(
1167
- () => options.store.saveReceipt(failedReceipt),
1168
- "saveReceipt(backend-failed-after-settlement)",
1169
- request.requestId
1170
- );
1303
+ await saveReceipt(flow, failedReceipt, "saveReceipt(backend-failed-after-settlement)");
1304
+ await backendFailed(failuresOf(flow));
1171
1305
  throw new CommerceError(
1172
1306
  "BACKEND_ERROR",
1173
1307
  "Payment settled but the backend call failed; the payment was not refunded automatically",
@@ -1191,12 +1325,13 @@ function createExecutionPipeline(options) {
1191
1325
  }
1192
1326
  );
1193
1327
  }
1328
+ await backendFailed();
1194
1329
  throw commerceError;
1195
1330
  }
1331
+ await recordStep(flow, { kind: "backend-result", status: backendResponse.status });
1196
1332
  await safeEmit(
1197
- buildEvent({
1333
+ buildEvent(flow, {
1198
1334
  type: "backend.called",
1199
- requestId: request.requestId,
1200
1335
  resourceId: resource.id,
1201
1336
  adapter: request.protocol,
1202
1337
  status: "ok",
@@ -1216,34 +1351,48 @@ function createExecutionPipeline(options) {
1216
1351
  durationMs: backendResponse.durationMs,
1217
1352
  protocol: request.protocol,
1218
1353
  ...paymentResult !== void 0 ? { payment: paymentResult } : {},
1219
- ...authorization !== void 0 ? { authorization } : {}
1354
+ ...authorization !== void 0 ? { authorization } : {},
1355
+ transactionId: flow.transactionId
1220
1356
  };
1221
- await safePersist(() => options.store.saveReceipt(receipt), "saveReceipt", request.requestId);
1357
+ await saveReceipt(flow, receipt, "saveReceipt");
1222
1358
  const totalDurationMs = Math.round(options.clock.monotonicMs() - pipelineStart);
1359
+ const failures = failuresOf(flow);
1223
1360
  await safeEmit(
1224
- buildEvent({
1361
+ buildEvent(flow, {
1225
1362
  type: "resource.delivered",
1226
- requestId: request.requestId,
1227
1363
  resourceId: resource.id,
1228
1364
  adapter: request.protocol,
1229
1365
  status: "ok",
1230
- durationMs: totalDurationMs
1366
+ durationMs: totalDurationMs,
1367
+ ...failures.persistenceFailures !== void 0 ? { data: failures } : {}
1231
1368
  })
1232
1369
  );
1233
1370
  return {
1234
1371
  kind: "delivered",
1235
1372
  requestId: request.requestId,
1373
+ transactionId: flow.transactionId,
1236
1374
  resourceId: resource.id,
1237
1375
  backendStatus: backendResponse.status,
1238
1376
  body: backendResponse.body,
1239
1377
  headers: backendResponse.headers,
1240
1378
  ...paymentResult !== void 0 ? { payment: paymentResult } : {},
1241
1379
  receipt,
1242
- durationMs: totalDurationMs
1380
+ durationMs: totalDurationMs,
1381
+ ...failures
1243
1382
  };
1244
1383
  }
1384
+ async function saveReceipt(flow, receipt, label) {
1385
+ if (await safePersist(flow, () => options.store.saveReceipt(receipt), label, "receipt")) {
1386
+ await recordStep(flow, { kind: "receipt", receiptId: receipt.id });
1387
+ }
1388
+ }
1245
1389
  return { execute };
1246
1390
  }
1391
+ var BACKEND_DEADLINE_MARGIN_MS = 5e3;
1392
+ function backendDeadline(dispatchedAt, resource) {
1393
+ const timeoutMs = resource.handler.timeoutMs ?? DEFAULT_BACKEND_TIMEOUT_MS;
1394
+ return new Date(dispatchedAt.getTime() + timeoutMs + BACKEND_DEADLINE_MARGIN_MS).toISOString();
1395
+ }
1247
1396
  function backendErrorStatus(error) {
1248
1397
  const status = error.details?.["status"];
1249
1398
  return typeof status === "number" ? status : 0;
@@ -1349,5 +1498,5 @@ var ACP_MERCHANT_RETRY_AFTER_DEFAULT_SECONDS = 5;
1349
1498
  var ACP_MERCHANT_RETRY_AFTER_MAX_SECONDS = 300;
1350
1499
 
1351
1500
  export { ACP_API_VERSION, ACP_API_VERSION_HEADER, ACP_CHECKOUT_OPERATIONS, ACP_FORWARDED_HEADERS, ACP_IDEMPOTENCY_KEY_HEADER, ACP_IDEMPOTENT_REPLAYED_HEADER, ACP_IN_FLIGHT_RETRY_AFTER_SECONDS, ACP_JSON_MEDIA_TYPE, ACP_MAX_FORWARDED_HEADER_LENGTH, ACP_MAX_REQUEST_ID_LENGTH, ACP_MERCHANT_RETRY_AFTER_DEFAULT_SECONDS, ACP_MERCHANT_RETRY_AFTER_MAX_SECONDS, ACP_OPERATION_INPUT_KEYS, ACP_OPERATION_OPTIONAL_INPUT_KEYS, ACP_REQUEST_ID_HEADER, ACP_SESSION_ID_INPUT_KEY, ACP_SPEC_VERSION, ACP_WELL_KNOWN_PATH, BackendErrorResponse, DEFAULT_CONFIG_FILENAME, HttpBackendExecutor, createExecutionPipeline, createResourceRegistry, createStoreEventSink, extractPathParameterNames, findUnparsedBraceToken, isObjectSchemaNode };
1352
- //# sourceMappingURL=chunk-PIMFPCNZ.js.map
1353
- //# sourceMappingURL=chunk-PIMFPCNZ.js.map
1501
+ //# sourceMappingURL=chunk-Z34UMZBB.js.map
1502
+ //# sourceMappingURL=chunk-Z34UMZBB.js.map