@openlup/platform 0.20.0 → 0.22.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/CHANGELOG.md +272 -278
- package/README.md +195 -6
- package/dist/composition/composeBundle.d.ts +13 -0
- package/dist/composition/composeBundle.js +4 -0
- package/dist/composition/fulfillmentContribution.d.ts +21 -0
- package/dist/composition/fulfillmentContribution.js +19 -0
- package/dist/composition/index.d.ts +1 -0
- package/dist/composition/index.js +2 -0
- package/dist/fulfillment/adapterConformance.d.ts +3 -0
- package/dist/fulfillment/adapterConformance.js +223 -0
- package/dist/fulfillment/bindings.d.ts +3 -0
- package/dist/fulfillment/bindings.js +29 -0
- package/dist/fulfillment/commerceFulfillmentHandlers.d.ts +29 -0
- package/dist/fulfillment/commerceFulfillmentHandlers.js +184 -0
- package/dist/fulfillment/commerceFulfillmentReadModel.d.ts +86 -0
- package/dist/fulfillment/commerceFulfillmentReadModel.js +131 -0
- package/dist/fulfillment/contracts/alignment.d.ts +25 -0
- package/dist/fulfillment/contracts/alignment.js +1 -0
- package/dist/fulfillment/contracts/bindings.d.ts +51 -0
- package/dist/fulfillment/contracts/bindings.js +1 -0
- package/dist/fulfillment/contracts/capabilities.d.ts +29 -0
- package/dist/fulfillment/contracts/capabilities.js +1 -0
- package/dist/fulfillment/contracts/conformance.d.ts +93 -0
- package/dist/fulfillment/contracts/conformance.js +1 -0
- package/dist/fulfillment/contracts/customerAlignment.d.ts +6 -0
- package/dist/fulfillment/contracts/customerAlignment.js +1 -0
- package/dist/fulfillment/contracts/dispatch.d.ts +105 -0
- package/dist/fulfillment/contracts/dispatch.js +1 -0
- package/dist/fulfillment/contracts/index.d.ts +18 -0
- package/dist/fulfillment/contracts/index.js +1 -0
- package/dist/fulfillment/contracts/label.d.ts +35 -0
- package/dist/fulfillment/contracts/label.js +1 -0
- package/dist/fulfillment/contracts/nativeUnsupported.d.ts +6 -0
- package/dist/fulfillment/contracts/nativeUnsupported.js +1 -0
- package/dist/fulfillment/contracts/observation.d.ts +52 -0
- package/dist/fulfillment/contracts/observation.js +1 -0
- package/dist/fulfillment/contracts/operator.d.ts +64 -0
- package/dist/fulfillment/contracts/operator.js +1 -0
- package/dist/fulfillment/contracts/read.d.ts +110 -0
- package/dist/fulfillment/contracts/read.js +1 -0
- package/dist/fulfillment/contracts/readback.d.ts +38 -0
- package/dist/fulfillment/contracts/readback.js +1 -0
- package/dist/fulfillment/contracts/replacement.d.ts +34 -0
- package/dist/fulfillment/contracts/replacement.js +1 -0
- package/dist/fulfillment/contracts/store.d.ts +86 -0
- package/dist/fulfillment/contracts/store.js +1 -0
- package/dist/fulfillment/contracts/sync.d.ts +170 -0
- package/dist/fulfillment/contracts/sync.js +1 -0
- package/dist/fulfillment/currentFulfillmentParcel.d.ts +2 -0
- package/dist/fulfillment/currentFulfillmentParcel.js +1 -0
- package/dist/fulfillment/delayReadModel.d.ts +11 -0
- package/dist/fulfillment/delayReadModel.js +45 -0
- package/dist/fulfillment/deliveryAlignmentReadModel.d.ts +4 -0
- package/dist/fulfillment/deliveryAlignmentReadModel.js +12 -0
- package/dist/fulfillment/dispatchProjection.d.ts +7 -0
- package/dist/fulfillment/dispatchProjection.js +18 -0
- package/dist/fulfillment/fulfillmentObservationEffects.d.ts +66 -0
- package/dist/fulfillment/fulfillmentObservationEffects.js +36 -0
- package/dist/fulfillment/handlerSchemas.d.ts +647 -0
- package/dist/fulfillment/handlerSchemas.js +213 -0
- package/dist/fulfillment/handlerSupport.d.ts +33 -0
- package/dist/fulfillment/handlerSupport.js +25 -0
- package/dist/fulfillment/index.d.ts +37 -0
- package/dist/fulfillment/index.js +37 -0
- package/dist/fulfillment/labelLifecycle.d.ts +24 -0
- package/dist/fulfillment/labelLifecycle.js +9 -0
- package/dist/fulfillment/lowStockEvidenceHandler.d.ts +36 -0
- package/dist/fulfillment/lowStockEvidenceHandler.js +46 -0
- package/dist/fulfillment/migrations.d.ts +27 -0
- package/dist/fulfillment/migrations.js +8 -0
- package/dist/fulfillment/nativeUnsupported.d.ts +10 -0
- package/dist/fulfillment/nativeUnsupported.js +18 -0
- package/dist/fulfillment/normalizedFulfillmentFacts.d.ts +2 -0
- package/dist/fulfillment/normalizedFulfillmentFacts.js +1 -0
- package/dist/fulfillment/observationProjection.d.ts +11 -0
- package/dist/fulfillment/observationProjection.js +37 -0
- package/dist/fulfillment/omnipack/capabilities.d.ts +3 -0
- package/dist/fulfillment/omnipack/capabilities.js +16 -0
- package/dist/fulfillment/omnipack/client.d.ts +37 -0
- package/dist/fulfillment/omnipack/client.js +162 -0
- package/dist/fulfillment/omnipack/index.d.ts +52 -0
- package/dist/fulfillment/omnipack/index.js +349 -0
- package/dist/fulfillment/omnipack/mappers.d.ts +73 -0
- package/dist/fulfillment/omnipack/mappers.js +177 -0
- package/dist/fulfillment/omnipack/observation.d.ts +21 -0
- package/dist/fulfillment/omnipack/observation.js +57 -0
- package/dist/fulfillment/omnipack/omnipackDispatchPayload.d.ts +36 -0
- package/dist/fulfillment/omnipack/omnipackDispatchPayload.js +63 -0
- package/dist/fulfillment/omnipack/omnipackOutboundOrderPayload.d.ts +83 -0
- package/dist/fulfillment/omnipack/omnipackOutboundOrderPayload.js +113 -0
- package/dist/fulfillment/omnipack/omnipackProductPackPayload.d.ts +11 -0
- package/dist/fulfillment/omnipack/omnipackProductPackPayload.js +38 -0
- package/dist/fulfillment/omnipack/omnipackProductPayload.d.ts +18 -0
- package/dist/fulfillment/omnipack/omnipackProductPayload.js +51 -0
- package/dist/fulfillment/omnipack/omnipackReconciliationPayload.d.ts +1 -0
- package/dist/fulfillment/omnipack/omnipackReconciliationPayload.js +3 -0
- package/dist/fulfillment/omnipack/omnipackStatusVocabulary.d.ts +4 -0
- package/dist/fulfillment/omnipack/omnipackStatusVocabulary.js +87 -0
- package/dist/fulfillment/omnipack/omnipackWebhookPayload.d.ts +9 -0
- package/dist/fulfillment/omnipack/omnipackWebhookPayload.js +76 -0
- package/dist/fulfillment/omnipack/productSyncMappers.d.ts +18 -0
- package/dist/fulfillment/omnipack/productSyncMappers.js +43 -0
- package/dist/fulfillment/omnipack/providerError.d.ts +25 -0
- package/dist/fulfillment/omnipack/providerError.js +47 -0
- package/dist/fulfillment/omnipack/trackingReferences.d.ts +16 -0
- package/dist/fulfillment/omnipack/trackingReferences.js +52 -0
- package/dist/fulfillment/paidFulfillmentRecovery.d.ts +67 -0
- package/dist/fulfillment/paidFulfillmentRecovery.js +154 -0
- package/dist/fulfillment/paidHandoff.d.ts +27 -0
- package/dist/fulfillment/paidHandoff.js +86 -0
- package/dist/fulfillment/paidHandoffPorts.d.ts +24 -0
- package/dist/fulfillment/paidHandoffPorts.js +3 -0
- package/dist/fulfillment/postgresDeliveryAlignment.d.ts +4 -0
- package/dist/fulfillment/postgresDeliveryAlignment.js +12 -0
- package/dist/fulfillment/postgresDispatchStore.d.ts +16 -0
- package/dist/fulfillment/postgresDispatchStore.js +44 -0
- package/dist/fulfillment/postgresEvidenceReadPort.d.ts +25 -0
- package/dist/fulfillment/postgresEvidenceReadPort.js +45 -0
- package/dist/fulfillment/postgresPaidFulfillmentRecovery.d.ts +25 -0
- package/dist/fulfillment/postgresPaidFulfillmentRecovery.js +26 -0
- package/dist/fulfillment/postgresPaidHandoffStore.d.ts +4 -0
- package/dist/fulfillment/postgresPaidHandoffStore.js +10 -0
- package/dist/fulfillment/postgresShipmentSpine.d.ts +63 -0
- package/dist/fulfillment/postgresShipmentSpine.js +232 -0
- package/dist/fulfillment/postgresStockSyncPort.d.ts +8 -0
- package/dist/fulfillment/postgresStockSyncPort.js +63 -0
- package/dist/fulfillment/productReconciliationEvidenceHandler.d.ts +36 -0
- package/dist/fulfillment/productReconciliationEvidenceHandler.js +50 -0
- package/dist/fulfillment/providerCapabilities.d.ts +9 -0
- package/dist/fulfillment/providerCapabilities.js +17 -0
- package/dist/fulfillment/providerCommandLedger.d.ts +143 -0
- package/dist/fulfillment/providerCommandLedger.js +14 -0
- package/dist/fulfillment/providerDispatchAcceptance.d.ts +26 -0
- package/dist/fulfillment/providerDispatchAcceptance.js +23 -0
- package/dist/fulfillment/providerDispatchError.d.ts +6 -0
- package/dist/fulfillment/providerDispatchError.js +5 -0
- package/dist/fulfillment/providerDispatchWorker.d.ts +31 -0
- package/dist/fulfillment/providerDispatchWorker.js +172 -0
- package/dist/fulfillment/providerProductSyncWorker.d.ts +28 -0
- package/dist/fulfillment/providerProductSyncWorker.js +122 -0
- package/dist/fulfillment/providerReconciliationError.d.ts +9 -0
- package/dist/fulfillment/providerReconciliationError.js +17 -0
- package/dist/fulfillment/providerReconciliationTerminalSkip.d.ts +2 -0
- package/dist/fulfillment/providerReconciliationTerminalSkip.js +6 -0
- package/dist/fulfillment/providerReconciliationTimestamp.d.ts +1 -0
- package/dist/fulfillment/providerReconciliationTimestamp.js +27 -0
- package/dist/fulfillment/providerReconciliationWorker.d.ts +82 -0
- package/dist/fulfillment/providerReconciliationWorker.js +151 -0
- package/dist/fulfillment/providerStockAvailability.d.ts +13 -0
- package/dist/fulfillment/providerStockAvailability.js +51 -0
- package/dist/fulfillment/providerStockSyncWorker.d.ts +37 -0
- package/dist/fulfillment/providerStockSyncWorker.js +186 -0
- package/dist/fulfillment/providerTrackingReferences.d.ts +15 -0
- package/dist/fulfillment/providerTrackingReferences.js +23 -0
- package/dist/fulfillment/replacementRefusals.d.ts +5 -0
- package/dist/fulfillment/replacementRefusals.js +38 -0
- package/dist/fulfillment/replacementShipmentHandler.d.ts +5 -0
- package/dist/fulfillment/replacementShipmentHandler.js +46 -0
- package/dist/fulfillment/schemaCapabilities.d.ts +13 -0
- package/dist/fulfillment/schemaCapabilities.js +7 -0
- package/dist/fulfillment/shipmentsOverviewHandler.d.ts +16 -0
- package/dist/fulfillment/shipmentsOverviewHandler.js +54 -0
- package/dist/fulfillment/statusMap.d.ts +2 -0
- package/dist/fulfillment/statusMap.js +1 -0
- package/dist/fulfillment/trackingProgress.d.ts +1 -0
- package/dist/fulfillment/trackingProgress.js +1 -0
- package/dist/fulfillment/verifiedIngress.d.ts +52 -0
- package/dist/fulfillment/verifiedIngress.js +66 -0
- package/dist/payments/adapterConformance.d.ts +8 -0
- package/dist/payments/adapterConformance.js +109 -0
- package/dist/payments/bindings.d.ts +3 -0
- package/dist/payments/bindings.js +17 -0
- package/dist/payments/checkoutActivePaymentActionResolver.d.ts +7 -0
- package/dist/payments/checkoutActivePaymentActionResolver.js +77 -0
- package/dist/payments/checkoutRecoveryPaymentResolver.d.ts +8 -0
- package/dist/payments/checkoutRecoveryPaymentResolver.js +87 -0
- package/dist/payments/contracts/adapter.d.ts +113 -0
- package/dist/payments/contracts/adapter.js +1 -0
- package/dist/payments/contracts/conformance.d.ts +155 -0
- package/dist/payments/contracts/conformance.js +1 -0
- package/dist/payments/contracts/evidence.d.ts +157 -0
- package/dist/payments/contracts/evidence.js +1 -0
- package/dist/payments/contracts/index.d.ts +10 -0
- package/dist/payments/contracts/index.js +1 -0
- package/dist/payments/contracts/preparedAttempt.d.ts +69 -0
- package/dist/payments/contracts/preparedAttempt.js +1 -0
- package/dist/payments/contracts/reconciliation.d.ts +303 -0
- package/dist/payments/contracts/reconciliation.js +1 -0
- package/dist/payments/contracts/repair.d.ts +92 -0
- package/dist/payments/contracts/repair.js +1 -0
- package/dist/payments/contracts/truth.d.ts +92 -0
- package/dist/payments/contracts/truth.js +1 -0
- package/dist/payments/eventConformanceRunner.d.ts +12 -0
- package/dist/payments/eventConformanceRunner.js +125 -0
- package/dist/payments/index.d.ts +16 -0
- package/dist/payments/index.js +16 -0
- package/dist/payments/paymentAttemptSilenceWindow.d.ts +10 -0
- package/dist/payments/paymentAttemptSilenceWindow.js +19 -0
- package/dist/payments/paymentMethodLifecycle.d.ts +11 -0
- package/dist/payments/paymentMethodLifecycle.js +37 -0
- package/dist/payments/paymentProviderReconciliationAbsenceReopen.d.ts +7 -0
- package/dist/payments/paymentProviderReconciliationAbsenceReopen.js +100 -0
- package/dist/payments/paymentProviderReconciliationEvidence.d.ts +36 -0
- package/dist/payments/paymentProviderReconciliationEvidence.js +91 -0
- package/dist/payments/paymentProviderReconciliationWorker.d.ts +4 -0
- package/dist/payments/paymentProviderReconciliationWorker.js +245 -0
- package/dist/payments/paymentTruth.d.ts +8 -0
- package/dist/payments/paymentTruth.js +125 -0
- package/dist/payments/paymentVerifyNowHandler.d.ts +27 -0
- package/dist/payments/paymentVerifyNowHandler.js +70 -0
- package/dist/payments/paymentVerifyNowService.d.ts +23 -0
- package/dist/payments/paymentVerifyNowService.js +93 -0
- package/dist/payments/paymentWebhookPostProcessing.d.ts +22 -0
- package/dist/payments/paymentWebhookPostProcessing.js +15 -0
- package/dist/payments/postgresPaymentTruth.d.ts +10 -0
- package/dist/payments/postgresPaymentTruth.js +126 -0
- package/dist/payments/preparedAttempt.d.ts +6 -0
- package/dist/payments/preparedAttempt.js +70 -0
- package/dist/payments/preparedAttemptFinalization.d.ts +5 -0
- package/dist/payments/preparedAttemptFinalization.js +12 -0
- package/dist/payments/schemaCapabilities.d.ts +10 -0
- package/dist/payments/schemaCapabilities.js +10 -0
- package/dist/payments/sql.d.ts +20 -0
- package/dist/payments/sql.js +6 -0
- package/dist/payments/stripe/classifyDecline.d.ts +46 -0
- package/dist/payments/stripe/classifyDecline.js +58 -0
- package/dist/payments/stripe/declineFailureHints.d.ts +46 -0
- package/dist/payments/stripe/declineFailureHints.js +87 -0
- package/dist/payments/stripe/donorContracts.d.ts +120 -0
- package/dist/payments/stripe/donorContracts.js +1 -0
- package/dist/payments/stripe/executionDecline.d.ts +53 -0
- package/dist/payments/stripe/executionDecline.js +107 -0
- package/dist/payments/stripe/index.d.ts +41 -0
- package/dist/payments/stripe/index.js +264 -0
- package/dist/payments/stripe/intentMapper.d.ts +26 -0
- package/dist/payments/stripe/intentMapper.js +51 -0
- package/dist/payments/stripe/methodFacts.d.ts +10 -0
- package/dist/payments/stripe/methodFacts.js +12 -0
- package/dist/payments/stripe/paymentFailureEvidence.d.ts +26 -0
- package/dist/payments/stripe/paymentFailureEvidence.js +33 -0
- package/dist/payments/stripe/stripeFailureEvidence.d.ts +41 -0
- package/dist/payments/stripe/stripeFailureEvidence.js +82 -0
- package/dist/payments/stripe/stripeIntentConfirmationEvidence.d.ts +28 -0
- package/dist/payments/stripe/stripeIntentConfirmationEvidence.js +32 -0
- package/dist/payments/stripe/stripePaymentReconciliationProvider.d.ts +35 -0
- package/dist/payments/stripe/stripePaymentReconciliationProvider.js +222 -0
- package/dist/payments/stripe/stripeRefundEvidence.d.ts +8 -0
- package/dist/payments/stripe/stripeRefundEvidence.js +17 -0
- package/dist/payments/stripe/stripeSandboxPaymentExecutionAdapter.d.ts +45 -0
- package/dist/payments/stripe/stripeSandboxPaymentExecutionAdapter.js +220 -0
- package/dist/payments/stripe/stripeWebhookNormalizer.d.ts +14 -0
- package/dist/payments/stripe/stripeWebhookNormalizer.js +243 -0
- package/dist/payments/stripe/webhookSignature.d.ts +14 -0
- package/dist/payments/stripe/webhookSignature.js +43 -0
- package/dist/payments/tpay/blikRecurringMapper.d.ts +37 -0
- package/dist/payments/tpay/blikRecurringMapper.js +24 -0
- package/dist/payments/tpay/capabilities.d.ts +3 -0
- package/dist/payments/tpay/capabilities.js +18 -0
- package/dist/payments/tpay/classifyDecline.d.ts +46 -0
- package/dist/payments/tpay/classifyDecline.js +58 -0
- package/dist/payments/tpay/declineFailureHints.d.ts +72 -0
- package/dist/payments/tpay/declineFailureHints.js +37 -0
- package/dist/payments/tpay/donorContracts.d.ts +140 -0
- package/dist/payments/tpay/donorContracts.js +1 -0
- package/dist/payments/tpay/index.d.ts +73 -0
- package/dist/payments/tpay/index.js +294 -0
- package/dist/payments/tpay/paymentFailureEvidence.d.ts +26 -0
- package/dist/payments/tpay/paymentFailureEvidence.js +33 -0
- package/dist/payments/tpay/preparedProviderAttempt.d.ts +22 -0
- package/dist/payments/tpay/preparedProviderAttempt.js +24 -0
- package/dist/payments/tpay/providerAttemptFailureDiagnostic.d.ts +3 -0
- package/dist/payments/tpay/providerAttemptFailureDiagnostic.js +95 -0
- package/dist/payments/tpay/tpayCreateTransactionInput.d.ts +25 -0
- package/dist/payments/tpay/tpayCreateTransactionInput.js +128 -0
- package/dist/payments/tpay/tpayDeclineEvidence.d.ts +126 -0
- package/dist/payments/tpay/tpayDeclineEvidence.js +177 -0
- package/dist/payments/tpay/tpayDispatchFailure.d.ts +60 -0
- package/dist/payments/tpay/tpayDispatchFailure.js +121 -0
- package/dist/payments/tpay/tpayFailureEvidence.d.ts +20 -0
- package/dist/payments/tpay/tpayFailureEvidence.js +61 -0
- package/dist/payments/tpay/tpayHttpClient.d.ts +52 -0
- package/dist/payments/tpay/tpayHttpClient.js +185 -0
- package/dist/payments/tpay/tpayHttpFailure.d.ts +57 -0
- package/dist/payments/tpay/tpayHttpFailure.js +143 -0
- package/dist/payments/tpay/tpayPaymentExecutionAdapter.d.ts +20 -0
- package/dist/payments/tpay/tpayPaymentExecutionAdapter.js +249 -0
- package/dist/payments/tpay/tpayPaymentReconciliationProvider.d.ts +5 -0
- package/dist/payments/tpay/tpayPaymentReconciliationProvider.js +244 -0
- package/dist/payments/tpay/tpayTransactionPayload.d.ts +120 -0
- package/dist/payments/tpay/tpayTransactionPayload.js +96 -0
- package/dist/payments/tpay/wallClockTime.d.ts +31 -0
- package/dist/payments/tpay/wallClockTime.js +57 -0
- package/dist/payments/tpay/webhookJwsVerifier.d.ts +17 -0
- package/dist/payments/tpay/webhookJwsVerifier.js +51 -0
- package/dist/payments/tpay/webhookNormalizer.d.ts +54 -0
- package/dist/payments/tpay/webhookNormalizer.js +200 -0
- package/dist/payments/verifiedEvidenceProjection.d.ts +12 -0
- package/dist/payments/verifiedEvidenceProjection.js +166 -0
- package/dist/payments/verifiedIngress.d.ts +119 -0
- package/dist/payments/verifiedIngress.js +220 -0
- package/package.json +37 -2
- package/release-gates.json +105 -3
- package/sql/20260808210000_fulfillment_shipment_rail.sql +810 -0
- package/sql/20260810180000_payment_settlement_rail.sql +574 -0
- package/sql/20260815150000_payment_truth_reconciliation.sql +479 -0
- package/sql/20260819150000_fulfillment_shipment_sequence.sql +98 -0
- package/sql/20260826100000_late_payment_shifts_the_subscription_cycle.sql +215 -0
- package/sql/20261022080000_fulfillment_command_ledger.sql +786 -0
- package/sql/20261022090000_fulfillment_delivery_alignment.sql +1106 -0
- package/src/composition/composeBundle.ts +13 -0
- package/src/composition/fulfillmentContribution.ts +28 -0
- package/src/composition/index.ts +2 -0
- package/src/fulfillment/adapterConformance.ts +195 -0
- package/src/fulfillment/bindings.ts +26 -0
- package/src/fulfillment/commerceFulfillmentHandlers.ts +263 -0
- package/src/fulfillment/commerceFulfillmentReadModel.ts +257 -0
- package/src/fulfillment/contracts/alignment.ts +13 -0
- package/src/fulfillment/contracts/bindings.ts +30 -0
- package/src/fulfillment/contracts/capabilities.ts +15 -0
- package/src/fulfillment/contracts/conformance.ts +61 -0
- package/src/fulfillment/contracts/customerAlignment.ts +4 -0
- package/src/fulfillment/contracts/dispatch.ts +58 -0
- package/src/fulfillment/contracts/index.ts +18 -0
- package/src/fulfillment/contracts/label.ts +9 -0
- package/src/fulfillment/contracts/nativeUnsupported.ts +6 -0
- package/src/fulfillment/contracts/observation.ts +18 -0
- package/src/fulfillment/contracts/operator.ts +31 -0
- package/src/fulfillment/contracts/read.ts +42 -0
- package/src/fulfillment/contracts/readback.ts +11 -0
- package/src/fulfillment/contracts/replacement.ts +15 -0
- package/src/fulfillment/contracts/store.ts +26 -0
- package/src/fulfillment/contracts/sync.ts +61 -0
- package/src/fulfillment/currentFulfillmentParcel.ts +2 -0
- package/src/fulfillment/delayReadModel.ts +60 -0
- package/src/fulfillment/deliveryAlignmentReadModel.ts +15 -0
- package/src/fulfillment/dispatchProjection.ts +20 -0
- package/src/fulfillment/fulfillmentObservationEffects.ts +86 -0
- package/src/fulfillment/handlerSchemas.ts +255 -0
- package/src/fulfillment/handlerSupport.ts +25 -0
- package/src/fulfillment/index.ts +38 -0
- package/src/fulfillment/labelLifecycle.ts +11 -0
- package/src/fulfillment/lowStockEvidenceHandler.ts +60 -0
- package/src/fulfillment/migrations.ts +8 -0
- package/src/fulfillment/nativeUnsupported.ts +23 -0
- package/src/fulfillment/normalizedFulfillmentFacts.ts +2 -0
- package/src/fulfillment/observationProjection.ts +41 -0
- package/src/fulfillment/omnipack/capabilities.ts +18 -0
- package/src/fulfillment/omnipack/client.ts +258 -0
- package/src/fulfillment/omnipack/index.ts +312 -0
- package/src/fulfillment/omnipack/mappers.ts +261 -0
- package/src/fulfillment/omnipack/observation.ts +61 -0
- package/src/fulfillment/omnipack/omnipackDispatchPayload.ts +93 -0
- package/src/fulfillment/omnipack/omnipackOutboundOrderPayload.ts +194 -0
- package/src/fulfillment/omnipack/omnipackProductPackPayload.ts +47 -0
- package/src/fulfillment/omnipack/omnipackProductPayload.ts +67 -0
- package/src/fulfillment/omnipack/omnipackReconciliationPayload.ts +7 -0
- package/src/fulfillment/omnipack/omnipackStatusVocabulary.ts +103 -0
- package/src/fulfillment/omnipack/omnipackWebhookPayload.ts +73 -0
- package/src/fulfillment/omnipack/productSyncMappers.ts +74 -0
- package/src/fulfillment/omnipack/providerError.ts +64 -0
- package/src/fulfillment/omnipack/trackingReferences.ts +77 -0
- package/src/fulfillment/paidFulfillmentRecovery.ts +252 -0
- package/src/fulfillment/paidHandoff.ts +122 -0
- package/src/fulfillment/paidHandoffPorts.ts +21 -0
- package/src/fulfillment/postgresDeliveryAlignment.ts +14 -0
- package/src/fulfillment/postgresDispatchStore.ts +55 -0
- package/src/fulfillment/postgresEvidenceReadPort.ts +59 -0
- package/src/fulfillment/postgresPaidFulfillmentRecovery.ts +29 -0
- package/src/fulfillment/postgresPaidHandoffStore.ts +11 -0
- package/src/fulfillment/postgresShipmentSpine.ts +321 -0
- package/src/fulfillment/postgresStockSyncPort.ts +65 -0
- package/src/fulfillment/productReconciliationEvidenceHandler.ts +64 -0
- package/src/fulfillment/providerCapabilities.ts +18 -0
- package/src/fulfillment/providerCommandLedger.ts +53 -0
- package/src/fulfillment/providerDispatchAcceptance.ts +31 -0
- package/src/fulfillment/providerDispatchError.ts +7 -0
- package/src/fulfillment/providerDispatchWorker.ts +131 -0
- package/src/fulfillment/providerProductSyncWorker.ts +154 -0
- package/src/fulfillment/providerReconciliationError.ts +20 -0
- package/src/fulfillment/providerReconciliationTerminalSkip.ts +8 -0
- package/src/fulfillment/providerReconciliationTimestamp.ts +34 -0
- package/src/fulfillment/providerReconciliationWorker.ts +150 -0
- package/src/fulfillment/providerStockAvailability.ts +60 -0
- package/src/fulfillment/providerStockSyncWorker.ts +222 -0
- package/src/fulfillment/providerTrackingReferences.ts +31 -0
- package/src/fulfillment/replacementRefusals.ts +43 -0
- package/src/fulfillment/replacementShipmentHandler.ts +47 -0
- package/src/fulfillment/schemaCapabilities.ts +7 -0
- package/src/fulfillment/shipmentsOverviewHandler.ts +73 -0
- package/src/fulfillment/statusMap.ts +2 -0
- package/src/fulfillment/trackingProgress.ts +1 -0
- package/src/fulfillment/verifiedIngress.ts +80 -0
- package/src/payments/adapterConformance.ts +118 -0
- package/src/payments/bindings.ts +17 -0
- package/src/payments/checkoutActivePaymentActionResolver.ts +97 -0
- package/src/payments/checkoutRecoveryPaymentResolver.ts +108 -0
- package/src/payments/contracts/adapter.ts +96 -0
- package/src/payments/contracts/conformance.ts +171 -0
- package/src/payments/contracts/evidence.ts +142 -0
- package/src/payments/contracts/index.ts +54 -0
- package/src/payments/contracts/preparedAttempt.ts +86 -0
- package/src/payments/contracts/reconciliation.ts +296 -0
- package/src/payments/contracts/repair.ts +95 -0
- package/src/payments/contracts/truth.ts +108 -0
- package/src/payments/eventConformanceRunner.ts +149 -0
- package/src/payments/index.ts +21 -0
- package/src/payments/paymentAttemptSilenceWindow.ts +26 -0
- package/src/payments/paymentMethodLifecycle.ts +50 -0
- package/src/payments/paymentProviderReconciliationAbsenceReopen.ts +130 -0
- package/src/payments/paymentProviderReconciliationEvidence.ts +117 -0
- package/src/payments/paymentProviderReconciliationWorker.ts +291 -0
- package/src/payments/paymentTruth.ts +131 -0
- package/src/payments/paymentVerifyNowHandler.ts +94 -0
- package/src/payments/paymentVerifyNowService.ts +125 -0
- package/src/payments/paymentWebhookPostProcessing.ts +36 -0
- package/src/payments/postgresPaymentTruth.ts +149 -0
- package/src/payments/preparedAttempt.ts +90 -0
- package/src/payments/preparedAttemptFinalization.ts +13 -0
- package/src/payments/schemaCapabilities.ts +10 -0
- package/src/payments/sql.ts +6 -0
- package/src/payments/stripe/classifyDecline.ts +62 -0
- package/src/payments/stripe/declineFailureHints.ts +89 -0
- package/src/payments/stripe/donorContracts.ts +87 -0
- package/src/payments/stripe/executionDecline.ts +126 -0
- package/src/payments/stripe/index.ts +265 -0
- package/src/payments/stripe/intentMapper.ts +58 -0
- package/src/payments/stripe/methodFacts.ts +21 -0
- package/src/payments/stripe/paymentFailureEvidence.ts +58 -0
- package/src/payments/stripe/stripeFailureEvidence.ts +115 -0
- package/src/payments/stripe/stripeIntentConfirmationEvidence.ts +34 -0
- package/src/payments/stripe/stripePaymentReconciliationProvider.ts +263 -0
- package/src/payments/stripe/stripeRefundEvidence.ts +19 -0
- package/src/payments/stripe/stripeSandboxPaymentExecutionAdapter.ts +283 -0
- package/src/payments/stripe/stripeWebhookNormalizer.ts +277 -0
- package/src/payments/stripe/webhookSignature.ts +55 -0
- package/src/payments/tpay/blikRecurringMapper.ts +42 -0
- package/src/payments/tpay/capabilities.ts +21 -0
- package/src/payments/tpay/classifyDecline.ts +62 -0
- package/src/payments/tpay/declineFailureHints.ts +90 -0
- package/src/payments/tpay/donorContracts.ts +104 -0
- package/src/payments/tpay/index.ts +293 -0
- package/src/payments/tpay/paymentFailureEvidence.ts +58 -0
- package/src/payments/tpay/preparedProviderAttempt.ts +38 -0
- package/src/payments/tpay/providerAttemptFailureDiagnostic.ts +99 -0
- package/src/payments/tpay/tpayCreateTransactionInput.ts +158 -0
- package/src/payments/tpay/tpayDeclineEvidence.ts +233 -0
- package/src/payments/tpay/tpayDispatchFailure.ts +186 -0
- package/src/payments/tpay/tpayFailureEvidence.ts +75 -0
- package/src/payments/tpay/tpayHttpClient.ts +290 -0
- package/src/payments/tpay/tpayHttpFailure.ts +186 -0
- package/src/payments/tpay/tpayPaymentExecutionAdapter.ts +297 -0
- package/src/payments/tpay/tpayPaymentReconciliationProvider.ts +285 -0
- package/src/payments/tpay/tpayTransactionPayload.ts +207 -0
- package/src/payments/tpay/wallClockTime.ts +57 -0
- package/src/payments/tpay/webhookJwsVerifier.ts +82 -0
- package/src/payments/tpay/webhookNormalizer.ts +279 -0
- package/src/payments/verifiedEvidenceProjection.ts +179 -0
- package/src/payments/verifiedIngress.ts +317 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type PaymentRecoveryEvidence } from "@openlup/core/payment";
|
|
2
|
+
import { type FailureObservationSource, type PaymentFailureEvidence } from "./paymentFailureEvidence.js";
|
|
3
|
+
export interface StripeIntentLike {
|
|
4
|
+
id: string;
|
|
5
|
+
status: string;
|
|
6
|
+
amount?: number | null;
|
|
7
|
+
amount_received?: number | null;
|
|
8
|
+
currency?: string | null;
|
|
9
|
+
client_secret?: string | null;
|
|
10
|
+
customer?: string | null;
|
|
11
|
+
payment_method?: string | null;
|
|
12
|
+
latest_charge?: string | null;
|
|
13
|
+
next_action?: {
|
|
14
|
+
type?: string | null;
|
|
15
|
+
} | null;
|
|
16
|
+
last_payment_error?: {
|
|
17
|
+
code?: string | null;
|
|
18
|
+
message?: string | null;
|
|
19
|
+
type?: string | null;
|
|
20
|
+
decline_code?: string | null;
|
|
21
|
+
advice_code?: string | null;
|
|
22
|
+
} | null;
|
|
23
|
+
/** Kept separate: populating legacy fine fields would change renewal classification. */
|
|
24
|
+
diagnosticFailureEvidence?: PaymentFailureEvidence;
|
|
25
|
+
}
|
|
26
|
+
/** Reads only one current PaymentIntent/error, never an arbitrary historical Charge. */
|
|
27
|
+
export declare function stripeFailureEvidence(input: unknown, options: {
|
|
28
|
+
source: FailureObservationSource;
|
|
29
|
+
confirmedFailureEvent?: boolean;
|
|
30
|
+
knownCardOnlyRequest?: boolean;
|
|
31
|
+
}): PaymentFailureEvidence | null;
|
|
32
|
+
/** UI evidence only: does not call or alter the shared failure taxonomy. */
|
|
33
|
+
export declare function normalizeStripeFailureEvidence(input: PaymentFailureEvidence): PaymentRecoveryEvidence;
|
|
34
|
+
/** Preserve the existing webhook projection and append only failure diagnostics. */
|
|
35
|
+
export declare function stripeWebhookPayload(input: {
|
|
36
|
+
eventId: string;
|
|
37
|
+
eventType: string;
|
|
38
|
+
providerPaymentId: string;
|
|
39
|
+
amountMinor: number | null;
|
|
40
|
+
currency: string | null;
|
|
41
|
+
}, object: unknown): Record<string, unknown>;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { isPaymentRetryAdviceCode } from "@openlup/core/payment";
|
|
2
|
+
import { evidenceRecord, evidenceToken, failureEvidencePayload, serializeFailureEvidence } from "./paymentFailureEvidence.js";
|
|
3
|
+
/** Reads only one current PaymentIntent/error, never an arbitrary historical Charge. */
|
|
4
|
+
export function stripeFailureEvidence(input, options) {
|
|
5
|
+
const object = evidenceRecord(input);
|
|
6
|
+
const thrown = object.type === "StripeCardError";
|
|
7
|
+
const intent = thrown ? evidenceRecord(object.payment_intent) : object;
|
|
8
|
+
const error = thrown ? object : evidenceRecord(intent.last_payment_error);
|
|
9
|
+
if (!thrown && !options.confirmedFailureEvent && Object.keys(error).length === 0)
|
|
10
|
+
return null;
|
|
11
|
+
const refusalVerified = thrown || options.confirmedFailureEvent === true
|
|
12
|
+
|| (intent.status === "requires_payment_method" && Object.keys(error).length > 0
|
|
13
|
+
&& (error.type === "card_error" || error.code === "card_declined" || Boolean(intent.latest_charge)));
|
|
14
|
+
const errorMethod = evidenceRecord(error.payment_method);
|
|
15
|
+
const currentMethod = evidenceRecord(intent.payment_method);
|
|
16
|
+
const errorMethodId = typeof error.payment_method === "string" ? error.payment_method : errorMethod.id;
|
|
17
|
+
const currentMethodId = typeof intent.payment_method === "string" ? intent.payment_method : currentMethod.id;
|
|
18
|
+
const conflictingMethod = Boolean(errorMethodId && currentMethodId && errorMethodId !== currentMethodId)
|
|
19
|
+
|| Boolean(errorMethod.type && currentMethod.type && errorMethod.type !== currentMethod.type);
|
|
20
|
+
const actualMethod = errorMethod.type ?? currentMethod.type;
|
|
21
|
+
const cardContract = options.knownCardOnlyRequest === true
|
|
22
|
+
|| (Array.isArray(intent.payment_method_types) && intent.payment_method_types.length === 1
|
|
23
|
+
&& intent.payment_method_types[0] === "card");
|
|
24
|
+
const flow = evidenceRecord(intent.metadata).providerFlow;
|
|
25
|
+
const operation = flow === "off_session_payment" ? "stored_method_payment"
|
|
26
|
+
: intent.setup_future_usage === "off_session" ? "recurring_setup"
|
|
27
|
+
: intent.setup_future_usage === null && flow === "one_time_payment" ? "one_time_payment" : null;
|
|
28
|
+
const methodKind = actualMethod === "card" || actualMethod === "blik" ? actualMethod
|
|
29
|
+
: actualMethod == null && cardContract ? "card" : null;
|
|
30
|
+
const method = methodKind
|
|
31
|
+
? { kind: methodKind, recoveryMethodKey: methodKind, interaction: operation === "stored_method_payment" ? "stored_instrument" : "new_instrument" } : null;
|
|
32
|
+
const latestCharge = typeof intent.latest_charge === "string" ? intent.latest_charge : evidenceRecord(intent.latest_charge).id;
|
|
33
|
+
const errorCharge = typeof error.charge === "string" ? error.charge : evidenceRecord(error.charge).id;
|
|
34
|
+
// A last error tied to another charge cannot explain the currently observed charge.
|
|
35
|
+
const conflictingEvidence = conflictingMethod || Boolean(latestCharge && errorCharge && latestCharge !== errorCharge);
|
|
36
|
+
return serializeFailureEvidence({
|
|
37
|
+
version: 1, source: options.source,
|
|
38
|
+
disposition: conflictingEvidence ? "unreadable" : Object.keys(error).length ? "present" : "absent",
|
|
39
|
+
refusalVerified: refusalVerified && !conflictingEvidence, providerPaymentId: evidenceToken(intent.id),
|
|
40
|
+
providerChargeId: evidenceToken(errorCharge ?? latestCharge),
|
|
41
|
+
code: conflictingEvidence ? null : evidenceToken(error.code),
|
|
42
|
+
declineCode: conflictingEvidence ? null : evidenceToken(error.decline_code),
|
|
43
|
+
adviceCode: conflictingEvidence ? null : evidenceToken(error.advice_code),
|
|
44
|
+
adviceOrigin: "provider", operation: conflictingEvidence ? null : operation, method: conflictingEvidence ? null : method,
|
|
45
|
+
methodSource: actualMethod != null ? "provider" : cardContract ? "execution_contract" : "unknown",
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
const SAFE_CAUSES = {
|
|
49
|
+
insufficient_funds: "insufficient_funds", expired_card: "expired_card",
|
|
50
|
+
incorrect_cvc: "invalid_payment_data", invalid_cvc: "invalid_payment_data",
|
|
51
|
+
incorrect_number: "invalid_payment_data", invalid_number: "invalid_payment_data",
|
|
52
|
+
invalid_expiry_month: "invalid_payment_data", invalid_expiry_year: "invalid_payment_data",
|
|
53
|
+
authentication_required: "authentication_required",
|
|
54
|
+
card_not_supported: "operation_unsupported", currency_not_supported: "operation_unsupported",
|
|
55
|
+
transaction_not_allowed: "operation_unsupported",
|
|
56
|
+
};
|
|
57
|
+
const RESTRICTED = new Set(["fraudulent", "highest_risk_level", "lost_card", "stolen_card", "merchant_blacklist"]);
|
|
58
|
+
/** UI evidence only: does not call or alter the shared failure taxonomy. */
|
|
59
|
+
export function normalizeStripeFailureEvidence(input) {
|
|
60
|
+
const evidence = serializeFailureEvidence(input);
|
|
61
|
+
const code = evidence.declineCode ?? evidence.code;
|
|
62
|
+
const restricted = code !== null && RESTRICTED.has(code);
|
|
63
|
+
const readable = evidence.refusalVerified && evidence.disposition === "present";
|
|
64
|
+
// A refused BLIK registration names its operation, not a setup cause: no code
|
|
65
|
+
// read here distinguishes a refused agreement from a mistyped or expired code.
|
|
66
|
+
const cause = readable && !restricted && code && Object.hasOwn(SAFE_CAUSES, code)
|
|
67
|
+
? SAFE_CAUSES[code] : "generic_decline";
|
|
68
|
+
return {
|
|
69
|
+
refusalVerified: evidence.refusalVerified, cause,
|
|
70
|
+
certainty: cause === "generic_decline" ? "unknown" : "verified",
|
|
71
|
+
disclosure: restricted ? "restricted" : "safe", method: evidence.method, operation: evidence.operation,
|
|
72
|
+
advice: readable && evidence.adviceOrigin === "provider" && evidence.adviceCode !== null && isPaymentRetryAdviceCode(evidence.adviceCode)
|
|
73
|
+
? { code: evidence.adviceCode, scope: evidence.method?.kind === "card" ? "instrument" : "unknown" } : null,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/** Preserve the existing webhook projection and append only failure diagnostics. */
|
|
77
|
+
export function stripeWebhookPayload(input, object) {
|
|
78
|
+
return { provider: "stripe", ...input,
|
|
79
|
+
...(input.eventType === "payment_intent.payment_failed"
|
|
80
|
+
? failureEvidencePayload(stripeFailureEvidence(object, { source: "webhook", confirmedFailureEvent: true })) : {}),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { StripeIntentLike } from "./stripeSandboxPaymentExecutionAdapter.js";
|
|
2
|
+
/**
|
|
3
|
+
* `requires_payment_method` on an intent that was never confirmed: no payment
|
|
4
|
+
* method attached, no charge, no payment error. The provider object exists —
|
|
5
|
+
* the request reached the provider and was accepted — but the payer never
|
|
6
|
+
* submitted an instrument, so no issuer was ever asked to approve anything.
|
|
7
|
+
*
|
|
8
|
+
* Both absences beside the status are load-bearing. A payment method attached
|
|
9
|
+
* but not yet confirmed means a charge may be seconds from moving; a charge or a
|
|
10
|
+
* payment error means an issuer HAS been asked and answered. Either presence
|
|
11
|
+
* makes this claim false, and the claim is used to decide what a durable row
|
|
12
|
+
* says about the payer's money, so it must stay narrow rather than convenient.
|
|
13
|
+
*
|
|
14
|
+
* Shared deliberately. The execution rail asserts it to record what a fresh
|
|
15
|
+
* intent is, and the reconciliation rail asserts it to answer a payer who is
|
|
16
|
+
* still standing in the checkout. Those are two readings of ONE provider state,
|
|
17
|
+
* and two copies of the predicate would let them drift into disagreeing about
|
|
18
|
+
* whether the same intent had been attempted — the kind of drift that is only
|
|
19
|
+
* discovered by a payer being told the wrong thing about their own payment.
|
|
20
|
+
*
|
|
21
|
+
* ⛔ Not to be widened into "the payer has gone" (abandonment). That is a
|
|
22
|
+
* separate verdict, passed on a payer who is no longer present, and it
|
|
23
|
+
* deliberately asserts fewer absences so a real refusal is never mislabelled as
|
|
24
|
+
* abandonment. Merging the two would put one predicate under two opposite
|
|
25
|
+
* pressures: this one must stay narrow so no live charge is called idle, that
|
|
26
|
+
* one must stay broad so no refusal is silently dropped out of dunning.
|
|
27
|
+
*/
|
|
28
|
+
export declare function noIssuerWasAsked(intent: StripeIntentLike): boolean;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `requires_payment_method` on an intent that was never confirmed: no payment
|
|
3
|
+
* method attached, no charge, no payment error. The provider object exists —
|
|
4
|
+
* the request reached the provider and was accepted — but the payer never
|
|
5
|
+
* submitted an instrument, so no issuer was ever asked to approve anything.
|
|
6
|
+
*
|
|
7
|
+
* Both absences beside the status are load-bearing. A payment method attached
|
|
8
|
+
* but not yet confirmed means a charge may be seconds from moving; a charge or a
|
|
9
|
+
* payment error means an issuer HAS been asked and answered. Either presence
|
|
10
|
+
* makes this claim false, and the claim is used to decide what a durable row
|
|
11
|
+
* says about the payer's money, so it must stay narrow rather than convenient.
|
|
12
|
+
*
|
|
13
|
+
* Shared deliberately. The execution rail asserts it to record what a fresh
|
|
14
|
+
* intent is, and the reconciliation rail asserts it to answer a payer who is
|
|
15
|
+
* still standing in the checkout. Those are two readings of ONE provider state,
|
|
16
|
+
* and two copies of the predicate would let them drift into disagreeing about
|
|
17
|
+
* whether the same intent had been attempted — the kind of drift that is only
|
|
18
|
+
* discovered by a payer being told the wrong thing about their own payment.
|
|
19
|
+
*
|
|
20
|
+
* ⛔ Not to be widened into "the payer has gone" (abandonment). That is a
|
|
21
|
+
* separate verdict, passed on a payer who is no longer present, and it
|
|
22
|
+
* deliberately asserts fewer absences so a real refusal is never mislabelled as
|
|
23
|
+
* abandonment. Merging the two would put one predicate under two opposite
|
|
24
|
+
* pressures: this one must stay narrow so no live charge is called idle, that
|
|
25
|
+
* one must stay broad so no refusal is silently dropped out of dunning.
|
|
26
|
+
*/
|
|
27
|
+
export function noIssuerWasAsked(intent) {
|
|
28
|
+
return intent.status === "requires_payment_method"
|
|
29
|
+
&& !intent.payment_method
|
|
30
|
+
&& !intent.latest_charge
|
|
31
|
+
&& !intent.last_payment_error;
|
|
32
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ProviderReconciliationStatus } from "./donorContracts.js";
|
|
2
|
+
import type { PaymentProviderRecoveryProvider } from "./donorContracts.js";
|
|
3
|
+
import type { StripeIntentLike } from "./stripeSandboxPaymentExecutionAdapter.js";
|
|
4
|
+
export interface StripePaymentIntentReader {
|
|
5
|
+
retrievePaymentIntent(paymentIntentId: string): Promise<StripeIntentLike>;
|
|
6
|
+
cancelPaymentIntent?(paymentIntentId: string): Promise<StripeIntentLike>;
|
|
7
|
+
}
|
|
8
|
+
export interface StripePaymentIntentSearcher {
|
|
9
|
+
/**
|
|
10
|
+
* Search Stripe PaymentIntents by a metadata key/value pair (GET
|
|
11
|
+
* /v1/payment_intents/search). Every intent the payment-control adapter
|
|
12
|
+
* creates carries metadata.paymentIntentId = <local intent uuid>
|
|
13
|
+
* (stripeSandboxPaymentExecutionAdapter metadataFor), so this is the
|
|
14
|
+
* intent-correlated absence probe for prepared attempts that never recorded
|
|
15
|
+
* a provider payment id.
|
|
16
|
+
*/
|
|
17
|
+
searchPaymentIntentsByMetadata(input: {
|
|
18
|
+
key: string;
|
|
19
|
+
value: string;
|
|
20
|
+
limit?: number;
|
|
21
|
+
}): Promise<{
|
|
22
|
+
ids: string[];
|
|
23
|
+
}>;
|
|
24
|
+
}
|
|
25
|
+
export declare function createStripePaymentReconciliationProvider(client: StripePaymentIntentReader & Partial<StripePaymentIntentSearcher>): PaymentProviderRecoveryProvider;
|
|
26
|
+
export declare function normalizeStripeIntent(intent: StripeIntentLike): ProviderReconciliationStatus;
|
|
27
|
+
/**
|
|
28
|
+
* The disposition of a failed intent nobody actually refused.
|
|
29
|
+
*
|
|
30
|
+
* Deliberately NOT a taxonomy class. The kernel classifies REFUSALS — it answers
|
|
31
|
+
* "may this instrument be charged again, and by whom" — and an absence of
|
|
32
|
+
* attempt is not a refusal, so an "abandonment" class would be a category error
|
|
33
|
+
* inside a vocabulary whose every other member describes an issuer's verdict.
|
|
34
|
+
*/
|
|
35
|
+
export declare const ABANDONED_BEFORE_CONFIRMATION = "abandoned_before_confirmation";
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { failureEvidencePayload } from "./paymentFailureEvidence.js";
|
|
2
|
+
import { classifyDecline } from "./classifyDecline.js";
|
|
3
|
+
import { declineCodeHints } from "./declineFailureHints.js";
|
|
4
|
+
import { noIssuerWasAsked } from "./stripeIntentConfirmationEvidence.js";
|
|
5
|
+
export function createStripePaymentReconciliationProvider(client) {
|
|
6
|
+
const search = client.searchPaymentIntentsByMetadata?.bind(client);
|
|
7
|
+
const cancel = client.cancelPaymentIntent?.bind(client);
|
|
8
|
+
return {
|
|
9
|
+
resolvePaymentReference(input) {
|
|
10
|
+
return input.providerAttemptId ?? input.intentProviderPaymentId ?? input.providerSessionId;
|
|
11
|
+
},
|
|
12
|
+
async readRecoveryPayment(input) {
|
|
13
|
+
const intent = await client.retrievePaymentIntent(input.providerPaymentId);
|
|
14
|
+
let status = normalizeStripeIntent(intent);
|
|
15
|
+
let clientAction = null;
|
|
16
|
+
if (intent.status === "processing" || intent.status === "requires_capture") {
|
|
17
|
+
clientAction = null;
|
|
18
|
+
}
|
|
19
|
+
else if (input.purpose === "active_checkout" && noIssuerWasAsked(intent)) {
|
|
20
|
+
clientAction = embeddedAction(intent.client_secret);
|
|
21
|
+
// The status is lowered whether or not a form can be handed back. Our
|
|
22
|
+
// inability to reopen the card panel is a fact about US; it is not an
|
|
23
|
+
// issuer's refusal, and it must not be recorded as one.
|
|
24
|
+
status = { ...status, status: "pending" };
|
|
25
|
+
}
|
|
26
|
+
else if (intent.status === "requires_action" || intent.status === "requires_confirmation") {
|
|
27
|
+
clientAction = embeddedAction(intent.client_secret);
|
|
28
|
+
// Global reconciliation treats requires_action as terminal for
|
|
29
|
+
// off-session dunning. Buyer recovery is different: without a current
|
|
30
|
+
// client secret it is uncertain, not permission to open a new intent.
|
|
31
|
+
if (!clientAction || input.purpose === "active_checkout") {
|
|
32
|
+
status = { ...status, status: "pending" };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
status,
|
|
37
|
+
identityMatches: intent.id === input.providerPaymentId,
|
|
38
|
+
configuredMoneyMatches: stripeConfiguredMoneyMatches(intent, input.attempt),
|
|
39
|
+
manualReviewRequired: false,
|
|
40
|
+
clientAction,
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
async readPayment(input) {
|
|
44
|
+
const intent = await client.retrievePaymentIntent(input.providerPaymentId);
|
|
45
|
+
const status = normalizeStripeIntent(intent);
|
|
46
|
+
// Same rule as the recovery read above, on the rail the buyer's own
|
|
47
|
+
// "check it now" travels: an intent no issuer has been asked about is
|
|
48
|
+
// unsettled, not refused. Only `active_checkout` gets this reading, so
|
|
49
|
+
// the reconciliation worker — which names no purpose — goes on
|
|
50
|
+
// terminalizing abandonment exactly as before.
|
|
51
|
+
return input.purpose === "active_checkout" && noIssuerWasAsked(intent)
|
|
52
|
+
? { ...status, status: "pending" }
|
|
53
|
+
: status;
|
|
54
|
+
},
|
|
55
|
+
...(cancel
|
|
56
|
+
? {
|
|
57
|
+
async closePayment(input) {
|
|
58
|
+
return normalizeStripeIntent(await cancel(input.providerPaymentId));
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
: {}),
|
|
62
|
+
...(search
|
|
63
|
+
? {
|
|
64
|
+
async findPaymentByLocalIntent(input) {
|
|
65
|
+
const result = await search({
|
|
66
|
+
key: "paymentIntentId",
|
|
67
|
+
value: input.attempt.paymentIntentId,
|
|
68
|
+
limit: 1,
|
|
69
|
+
});
|
|
70
|
+
return result.ids.length > 0 ? "found" : "absent";
|
|
71
|
+
},
|
|
72
|
+
}
|
|
73
|
+
: {}),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export function normalizeStripeIntent(intent) {
|
|
77
|
+
const status = normalizeStripeStatus(intent.status);
|
|
78
|
+
return {
|
|
79
|
+
status,
|
|
80
|
+
providerStatus: intent.status,
|
|
81
|
+
occurredAt: null,
|
|
82
|
+
failureReason: failureReason(intent),
|
|
83
|
+
amountMinor: readAmountMinor(intent),
|
|
84
|
+
currency: typeof intent.currency === "string" ? intent.currency.toUpperCase() : null,
|
|
85
|
+
rawPayload: {
|
|
86
|
+
provider: "stripe",
|
|
87
|
+
paymentIntentId: intent.id,
|
|
88
|
+
status: intent.status,
|
|
89
|
+
latestChargePresent: Boolean(intent.latest_charge),
|
|
90
|
+
nextActionType: intent.next_action?.type ?? null,
|
|
91
|
+
lastPaymentErrorCode: intent.last_payment_error?.code ?? null,
|
|
92
|
+
lastPaymentErrorType: intent.last_payment_error?.type ?? null,
|
|
93
|
+
...failureCapture(intent),
|
|
94
|
+
...failureEvidencePayload(intent.diagnosticFailureEvidence),
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The disposition of a failed intent nobody actually refused.
|
|
100
|
+
*
|
|
101
|
+
* Deliberately NOT a taxonomy class. The kernel classifies REFUSALS — it answers
|
|
102
|
+
* "may this instrument be charged again, and by whom" — and an absence of
|
|
103
|
+
* attempt is not a refusal, so an "abandonment" class would be a category error
|
|
104
|
+
* inside a vocabulary whose every other member describes an issuer's verdict.
|
|
105
|
+
*/
|
|
106
|
+
export const ABANDONED_BEFORE_CONFIRMATION = "abandoned_before_confirmation";
|
|
107
|
+
/**
|
|
108
|
+
* `requires_payment_method` on an intent that was never confirmed: no
|
|
109
|
+
* `last_payment_error`, no charge. The buyer closed the tab; no issuer was ever
|
|
110
|
+
* asked. Six of the fifteen production failure rows in the historical corpus are
|
|
111
|
+
* this state.
|
|
112
|
+
*
|
|
113
|
+
* Both absences are required before the claim is made. Presence of either is
|
|
114
|
+
* evidence an attempt happened, and mislabelling a real decline as abandonment
|
|
115
|
+
* would silently drop it out of dunning — the more expensive of the two errors.
|
|
116
|
+
*/
|
|
117
|
+
function abandonedBeforeConfirmation(intent) {
|
|
118
|
+
return intent.status === "requires_payment_method"
|
|
119
|
+
&& !intent.last_payment_error
|
|
120
|
+
&& !intent.latest_charge;
|
|
121
|
+
}
|
|
122
|
+
function embeddedAction(clientSecret) {
|
|
123
|
+
return typeof clientSecret === "string" && clientSecret.length > 0
|
|
124
|
+
? { kind: "provider_embedded", provider: "stripe", clientSecret }
|
|
125
|
+
: null;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* The refusal evidence this rail can state, and the class it produces.
|
|
129
|
+
*
|
|
130
|
+
* This rail births most production failure rows, and it used to keep only
|
|
131
|
+
* `last_payment_error.code` — the coarse bucket ("card_declined") — while
|
|
132
|
+
* dropping `decline_code`, the fine code the adapter's hint table is written
|
|
133
|
+
* against, and `advice_code`, the issuer's own retry verdict. With both gone the
|
|
134
|
+
* taxonomy had nothing to read here, so the programme's classification telemetry
|
|
135
|
+
* stayed empty no matter how many refusals arrived.
|
|
136
|
+
*
|
|
137
|
+
* Classification goes through the shared `classifyDecline` seam, the same one
|
|
138
|
+
* the synchronous decline path uses, so there is exactly one place a refusal
|
|
139
|
+
* becomes a class. Only neutral evidence crosses: this provider's own code
|
|
140
|
+
* vocabulary is translated here, by this adapter's table, and travels no further.
|
|
141
|
+
*
|
|
142
|
+
* The class does not stop here. Since wave 3i-b it reaches the attempt and the
|
|
143
|
+
* dunning case through the terminal write's two classification parameters, and
|
|
144
|
+
* from there it becomes the cause sentence the payer is shown. It remains no
|
|
145
|
+
* part of any retry cadence.
|
|
146
|
+
*/
|
|
147
|
+
function failureCapture(intent) {
|
|
148
|
+
if (normalizeStripeStatus(intent.status) !== "failed")
|
|
149
|
+
return {};
|
|
150
|
+
if (abandonedBeforeConfirmation(intent)) {
|
|
151
|
+
return { nonDeclineDisposition: ABANDONED_BEFORE_CONFIRMATION };
|
|
152
|
+
}
|
|
153
|
+
const declineCode = readCode(intent.last_payment_error?.decline_code);
|
|
154
|
+
const adviceCode = readCode(intent.last_payment_error?.advice_code);
|
|
155
|
+
const neutralReasonHints = declineCodeHints(declineCode);
|
|
156
|
+
const classification = classifyDecline({
|
|
157
|
+
// Correlation handle only — the kernel never reads it. The intent's own
|
|
158
|
+
// status is the provider-native fact when the refusal named no code.
|
|
159
|
+
code: readCode(intent.last_payment_error?.code) ?? intent.status,
|
|
160
|
+
// A read of an existing intent says nothing about whether the payer's bank
|
|
161
|
+
// can hold a reusable mandate, so this rail never claims it.
|
|
162
|
+
mandateUnsupported: false,
|
|
163
|
+
...(declineCode ? { declineCode } : {}),
|
|
164
|
+
...(adviceCode ? { adviceCode } : {}),
|
|
165
|
+
...(neutralReasonHints.length > 0 ? { neutralReasonHints } : {}),
|
|
166
|
+
}, { failureReasonKey: failureReason(intent) ?? undefined });
|
|
167
|
+
return {
|
|
168
|
+
declineCode: declineCode ?? null,
|
|
169
|
+
adviceCode: adviceCode ?? null,
|
|
170
|
+
neutralReasonHints,
|
|
171
|
+
failureClass: classification.failureClass,
|
|
172
|
+
failureClassDecidedBy: classification.decidedBy,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function readCode(value) {
|
|
176
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
177
|
+
}
|
|
178
|
+
function stripeConfiguredMoneyMatches(intent, attempt) {
|
|
179
|
+
return typeof intent.amount === "number"
|
|
180
|
+
&& Number.isFinite(intent.amount)
|
|
181
|
+
&& intent.amount === attempt.amountMinor
|
|
182
|
+
&& typeof intent.currency === "string"
|
|
183
|
+
&& intent.currency.toUpperCase() === attempt.currency.toUpperCase();
|
|
184
|
+
}
|
|
185
|
+
function normalizeStripeStatus(status) {
|
|
186
|
+
if (status === "succeeded")
|
|
187
|
+
return "succeeded";
|
|
188
|
+
if (status === "requires_action" ||
|
|
189
|
+
status === "requires_confirmation" ||
|
|
190
|
+
status === "requires_payment_method" ||
|
|
191
|
+
status === "canceled") {
|
|
192
|
+
return "failed";
|
|
193
|
+
}
|
|
194
|
+
if (status === "processing" || status === "requires_capture")
|
|
195
|
+
return "pending";
|
|
196
|
+
return "unknown";
|
|
197
|
+
}
|
|
198
|
+
function failureReason(intent) {
|
|
199
|
+
const status = normalizeStripeStatus(intent.status);
|
|
200
|
+
if (status !== "failed")
|
|
201
|
+
return null;
|
|
202
|
+
return intent.last_payment_error?.code
|
|
203
|
+
? `stripe_${intent.last_payment_error.code}`
|
|
204
|
+
: `stripe_${intent.status}`;
|
|
205
|
+
}
|
|
206
|
+
function readAmountMinor(intent) {
|
|
207
|
+
// amount_received is settlement truth only after success. For an incomplete,
|
|
208
|
+
// requires-payment-method, cancelled, or requires-capture intent Stripe
|
|
209
|
+
// legitimately returns 0 while `amount` still holds the configured amount.
|
|
210
|
+
// Comparing that zero to the local order created a false mismatch and made
|
|
211
|
+
// reconciliation 502-loop on an ordinary failed payment.
|
|
212
|
+
if (intent.status === "succeeded" && typeof intent.amount_received === "number" && Number.isFinite(intent.amount_received)) {
|
|
213
|
+
return intent.amount_received;
|
|
214
|
+
}
|
|
215
|
+
if (typeof intent.amount === "number" && Number.isFinite(intent.amount)) {
|
|
216
|
+
return intent.amount;
|
|
217
|
+
}
|
|
218
|
+
if (typeof intent.amount_received === "number" && Number.isFinite(intent.amount_received)) {
|
|
219
|
+
return intent.amount_received;
|
|
220
|
+
}
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** A Charge observation is cumulative; its amount never replaces payment amount. */
|
|
2
|
+
export declare function stripeRefundEvidence(eventType: string, charge: Record<string, unknown>): {
|
|
3
|
+
refundKind: "full" | "partial" | null;
|
|
4
|
+
snapshot: {
|
|
5
|
+
chargeId: string;
|
|
6
|
+
amountRefundedMinor: number;
|
|
7
|
+
} | null;
|
|
8
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** A Charge observation is cumulative; its amount never replaces payment amount. */
|
|
2
|
+
export function stripeRefundEvidence(eventType, charge) {
|
|
3
|
+
if (eventType !== "charge.refunded")
|
|
4
|
+
return { refundKind: null, snapshot: null };
|
|
5
|
+
const amount = charge.amount;
|
|
6
|
+
const refunded = charge.amount_refunded;
|
|
7
|
+
const chargeId = charge.id;
|
|
8
|
+
if (typeof chargeId !== "string" || !chargeId.trim()
|
|
9
|
+
|| typeof amount !== "number" || !Number.isSafeInteger(amount) || amount <= 0
|
|
10
|
+
|| typeof refunded !== "number" || !Number.isSafeInteger(refunded) || refunded <= 0 || refunded > amount) {
|
|
11
|
+
return { refundKind: null, snapshot: null };
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
refundKind: refunded === amount ? "full" : "partial",
|
|
15
|
+
snapshot: { chargeId, amountRefundedMinor: refunded },
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { PaymentExecutionPort } from "./donorContracts.js";
|
|
2
|
+
import type { CanonicalPaymentEvent, PaymentProviderFlow } from "./donorContracts.js";
|
|
3
|
+
/** The one place this adapter spells its own provider identity. */
|
|
4
|
+
export declare const PROVIDER_KIND: "stripe";
|
|
5
|
+
import type { StripeIntentLike } from "./stripeFailureEvidence.js";
|
|
6
|
+
export type { StripeIntentLike } from "./stripeFailureEvidence.js";
|
|
7
|
+
export interface StripeSandboxClient {
|
|
8
|
+
createPaymentIntent(input: {
|
|
9
|
+
amount: number;
|
|
10
|
+
currency: string;
|
|
11
|
+
customer?: string;
|
|
12
|
+
paymentMethod?: string;
|
|
13
|
+
offSession?: boolean;
|
|
14
|
+
setupFutureUsage?: "off_session";
|
|
15
|
+
metadata: Record<string, string>;
|
|
16
|
+
}, options: {
|
|
17
|
+
idempotencyKey: string;
|
|
18
|
+
}): Promise<StripeIntentLike>;
|
|
19
|
+
createSetupIntent(input: {
|
|
20
|
+
customer?: string;
|
|
21
|
+
paymentMethod?: string;
|
|
22
|
+
usage: "off_session";
|
|
23
|
+
metadata: Record<string, string>;
|
|
24
|
+
}, options: {
|
|
25
|
+
idempotencyKey: string;
|
|
26
|
+
}): Promise<StripeIntentLike>;
|
|
27
|
+
/**
|
|
28
|
+
* Ensure-or-create a provider Customer for the client. Required before a
|
|
29
|
+
* `setup_future_usage='off_session'` PaymentIntent (the provider rejects it
|
|
30
|
+
* without a customer). Idempotent via the idempotency key.
|
|
31
|
+
*/
|
|
32
|
+
ensureCustomer?(input: {
|
|
33
|
+
clientId: string;
|
|
34
|
+
metadata: Record<string, string>;
|
|
35
|
+
}, options: {
|
|
36
|
+
idempotencyKey: string;
|
|
37
|
+
}): Promise<string>;
|
|
38
|
+
retrievePaymentIntent?(paymentIntentId: string): Promise<StripeIntentLike>;
|
|
39
|
+
}
|
|
40
|
+
export interface StripeSandboxAdapterOptions {
|
|
41
|
+
client: StripeSandboxClient;
|
|
42
|
+
defaultFlow?: Extract<PaymentProviderFlow, "one_time_payment" | "setup_reusable_method" | "off_session_payment">;
|
|
43
|
+
}
|
|
44
|
+
export declare function createStripeSandboxPaymentExecutionAdapter({ client, defaultFlow, }: StripeSandboxAdapterOptions): PaymentExecutionPort;
|
|
45
|
+
export declare function parseStripePaymentWebhookEvent(rawPayload: Record<string, unknown>): CanonicalPaymentEvent;
|