@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.
- package/README.md +115 -15
- package/dist/ap2.d.ts +24 -12
- package/dist/ap2.js +31 -13
- package/dist/ap2.js.map +1 -1
- package/dist/{chunk-AITMDXKW.js → chunk-3OTCFFFT.js} +37 -4
- package/dist/chunk-3OTCFFFT.js.map +1 -0
- package/dist/{chunk-4OEXK3YG.js → chunk-4K7FIBJM.js} +25 -4
- package/dist/chunk-4K7FIBJM.js.map +1 -0
- package/dist/{chunk-WUIAUAA7.js → chunk-FKQK5XZA.js} +652 -68
- package/dist/chunk-FKQK5XZA.js.map +1 -0
- package/dist/chunk-GA3O2A7R.js +92 -0
- package/dist/chunk-GA3O2A7R.js.map +1 -0
- package/dist/{chunk-6WACRJVT.js → chunk-VUCMBGUR.js} +3 -3
- package/dist/{chunk-6WACRJVT.js.map → chunk-VUCMBGUR.js.map} +1 -1
- package/dist/cli/{ap2-QDHPRSTF.js → ap2-YAPLERSC.js} +34 -15
- package/dist/cli/ap2-YAPLERSC.js.map +1 -0
- package/dist/cli/{chunk-G2JEY7MB.js → chunk-2J2IQQ4X.js} +8 -7
- package/dist/cli/chunk-2J2IQQ4X.js.map +1 -0
- package/dist/cli/chunk-2UPPX3FJ.js +311 -0
- package/dist/cli/chunk-2UPPX3FJ.js.map +1 -0
- package/dist/cli/{chunk-WYOGIANL.js → chunk-4H2QLHQI.js} +4 -4
- package/dist/cli/{chunk-WYOGIANL.js.map → chunk-4H2QLHQI.js.map} +1 -1
- package/dist/cli/{chunk-OZ4LAWBK.js → chunk-5R7DM5LM.js} +25 -4
- package/dist/cli/chunk-5R7DM5LM.js.map +1 -0
- package/dist/cli/chunk-663ALDZA.js +92 -0
- package/dist/cli/chunk-663ALDZA.js.map +1 -0
- package/dist/cli/{chunk-QQ3WY5L3.js → chunk-IDY2735M.js} +36 -104
- package/dist/cli/chunk-IDY2735M.js.map +1 -0
- package/dist/cli/chunk-JFVRG2HH.js +107 -0
- package/dist/cli/chunk-JFVRG2HH.js.map +1 -0
- package/dist/cli/chunk-M7NXVRU5.js +8 -0
- package/dist/cli/{chunk-UXB65XCS.js.map → chunk-M7NXVRU5.js.map} +1 -1
- package/dist/cli/chunk-NIU5EMSB.js +119 -0
- package/dist/cli/chunk-NIU5EMSB.js.map +1 -0
- package/dist/cli/{chunk-AZDWFVDW.js → chunk-QA2OPHBF.js} +655 -70
- package/dist/cli/chunk-QA2OPHBF.js.map +1 -0
- package/dist/cli/{chunk-DCMW67JM.js → chunk-QLUCNPRT.js} +404 -161
- package/dist/cli/chunk-QLUCNPRT.js.map +1 -0
- package/dist/cli/chunk-SYQLJXIU.js +105 -0
- package/dist/cli/chunk-SYQLJXIU.js.map +1 -0
- package/dist/cli/{chunk-3MGAJ5FX.js → chunk-VJ4EO4LE.js} +3 -3
- package/dist/cli/{chunk-3MGAJ5FX.js.map → chunk-VJ4EO4LE.js.map} +1 -1
- package/dist/cli/{chunk-PIMFPCNZ.js → chunk-Z34UMZBB.js} +234 -85
- package/dist/cli/chunk-Z34UMZBB.js.map +1 -0
- package/dist/cli/config-BWFMN2ZB.js +12 -0
- package/dist/cli/{config-UI4EDG4L.js.map → config-BWFMN2ZB.js.map} +1 -1
- package/dist/cli/index.js +258 -11
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/{mcp-26LJMN4N.js → mcp-KZEMXLHR.js} +5 -4
- package/dist/cli/mcp-KZEMXLHR.js.map +1 -0
- package/dist/cli/{near-5AY3HWYF.js → near-U6365VFX.js} +15 -4
- package/dist/cli/near-U6365VFX.js.map +1 -0
- package/dist/cli/payment-providers-SZL36H3Y.js +6 -0
- package/dist/cli/payment-providers-SZL36H3Y.js.map +1 -0
- package/dist/cli/{provider-Z4OJNAYI.js → provider-6TKB5ADJ.js} +30 -16
- package/dist/cli/provider-6TKB5ADJ.js.map +1 -0
- package/dist/cli/receipts-ZGLJWMQG.js +8 -0
- package/dist/cli/receipts-ZGLJWMQG.js.map +1 -0
- package/dist/cli/reconcile-IC22MJD5.js +4 -0
- package/dist/cli/reconcile-IC22MJD5.js.map +1 -0
- package/dist/cli/{run-TEPYJUHG.js → run-ZTYPQI4D.js} +151 -115
- package/dist/cli/run-ZTYPQI4D.js.map +1 -0
- package/dist/cli/svm-KDSPDFJG.js +48 -0
- package/dist/cli/svm-KDSPDFJG.js.map +1 -0
- package/dist/cli/{x402-BMVONZKA.js → x402-WLYBLODI.js} +10 -9
- package/dist/cli/x402-WLYBLODI.js.map +1 -0
- package/dist/index.d.ts +112 -12
- package/dist/index.js +948 -157
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +1 -2
- package/dist/mcp.js +1 -1
- package/dist/mpp.js +24 -11
- package/dist/mpp.js.map +1 -1
- package/dist/{near-D6C42VPE.js → near-FH7HPZV3.js} +15 -4
- package/dist/near-FH7HPZV3.js.map +1 -0
- package/dist/{protocol-adapter-C9odYl6l.d.ts → protocol-adapter-DEXpdp8m.d.ts} +102 -48
- package/dist/{runtime-Cl_BLVZV.d.ts → runtime-Dz2fSO-P.d.ts} +220 -2
- package/dist/svm-KNC3PHMS.js +48 -0
- package/dist/svm-KNC3PHMS.js.map +1 -0
- package/dist/x402.js +5 -5
- package/package.json +1 -1
- package/dist/authorization-DjAecwuW.d.ts +0 -115
- package/dist/chunk-4OEXK3YG.js.map +0 -1
- package/dist/chunk-AITMDXKW.js.map +0 -1
- package/dist/chunk-KA2AX5FH.js +0 -44
- package/dist/chunk-KA2AX5FH.js.map +0 -1
- package/dist/chunk-WUIAUAA7.js.map +0 -1
- package/dist/cli/ap2-QDHPRSTF.js.map +0 -1
- package/dist/cli/chunk-AZDWFVDW.js.map +0 -1
- package/dist/cli/chunk-DCMW67JM.js.map +0 -1
- package/dist/cli/chunk-G2JEY7MB.js.map +0 -1
- package/dist/cli/chunk-OSTCU6ZK.js +0 -44
- package/dist/cli/chunk-OSTCU6ZK.js.map +0 -1
- package/dist/cli/chunk-OZ4LAWBK.js.map +0 -1
- package/dist/cli/chunk-PIMFPCNZ.js.map +0 -1
- package/dist/cli/chunk-QQ3WY5L3.js.map +0 -1
- package/dist/cli/chunk-UXB65XCS.js +0 -8
- package/dist/cli/config-UI4EDG4L.js +0 -11
- package/dist/cli/mcp-26LJMN4N.js.map +0 -1
- package/dist/cli/near-5AY3HWYF.js.map +0 -1
- package/dist/cli/provider-Z4OJNAYI.js.map +0 -1
- package/dist/cli/run-TEPYJUHG.js.map +0 -1
- package/dist/cli/svm-3MMYFPC7.js +0 -33
- package/dist/cli/svm-3MMYFPC7.js.map +0 -1
- package/dist/cli/x402-BMVONZKA.js.map +0 -1
- package/dist/near-D6C42VPE.js.map +0 -1
- package/dist/svm-QEUAUNPQ.js +0 -33
- 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-
|
|
2
|
-
import { RESERVED_INPUT_FIELDS, NOOP_LOGGER, DEFAULT_BACKEND_TIMEOUT_MS,
|
|
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,
|
|
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
|
-
{
|
|
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
|
|
846
|
-
|
|
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 {
|
|
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
|
|
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
|
-
|
|
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: {
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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:
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
1120
|
-
|
|
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
|
|
1140
|
-
|
|
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
|
|
1167
|
-
|
|
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
|
|
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-
|
|
1353
|
-
//# sourceMappingURL=chunk-
|
|
1501
|
+
//# sourceMappingURL=chunk-Z34UMZBB.js.map
|
|
1502
|
+
//# sourceMappingURL=chunk-Z34UMZBB.js.map
|