@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.
Files changed (458) hide show
  1. package/CHANGELOG.md +272 -278
  2. package/README.md +195 -6
  3. package/dist/composition/composeBundle.d.ts +13 -0
  4. package/dist/composition/composeBundle.js +4 -0
  5. package/dist/composition/fulfillmentContribution.d.ts +21 -0
  6. package/dist/composition/fulfillmentContribution.js +19 -0
  7. package/dist/composition/index.d.ts +1 -0
  8. package/dist/composition/index.js +2 -0
  9. package/dist/fulfillment/adapterConformance.d.ts +3 -0
  10. package/dist/fulfillment/adapterConformance.js +223 -0
  11. package/dist/fulfillment/bindings.d.ts +3 -0
  12. package/dist/fulfillment/bindings.js +29 -0
  13. package/dist/fulfillment/commerceFulfillmentHandlers.d.ts +29 -0
  14. package/dist/fulfillment/commerceFulfillmentHandlers.js +184 -0
  15. package/dist/fulfillment/commerceFulfillmentReadModel.d.ts +86 -0
  16. package/dist/fulfillment/commerceFulfillmentReadModel.js +131 -0
  17. package/dist/fulfillment/contracts/alignment.d.ts +25 -0
  18. package/dist/fulfillment/contracts/alignment.js +1 -0
  19. package/dist/fulfillment/contracts/bindings.d.ts +51 -0
  20. package/dist/fulfillment/contracts/bindings.js +1 -0
  21. package/dist/fulfillment/contracts/capabilities.d.ts +29 -0
  22. package/dist/fulfillment/contracts/capabilities.js +1 -0
  23. package/dist/fulfillment/contracts/conformance.d.ts +93 -0
  24. package/dist/fulfillment/contracts/conformance.js +1 -0
  25. package/dist/fulfillment/contracts/customerAlignment.d.ts +6 -0
  26. package/dist/fulfillment/contracts/customerAlignment.js +1 -0
  27. package/dist/fulfillment/contracts/dispatch.d.ts +105 -0
  28. package/dist/fulfillment/contracts/dispatch.js +1 -0
  29. package/dist/fulfillment/contracts/index.d.ts +18 -0
  30. package/dist/fulfillment/contracts/index.js +1 -0
  31. package/dist/fulfillment/contracts/label.d.ts +35 -0
  32. package/dist/fulfillment/contracts/label.js +1 -0
  33. package/dist/fulfillment/contracts/nativeUnsupported.d.ts +6 -0
  34. package/dist/fulfillment/contracts/nativeUnsupported.js +1 -0
  35. package/dist/fulfillment/contracts/observation.d.ts +52 -0
  36. package/dist/fulfillment/contracts/observation.js +1 -0
  37. package/dist/fulfillment/contracts/operator.d.ts +64 -0
  38. package/dist/fulfillment/contracts/operator.js +1 -0
  39. package/dist/fulfillment/contracts/read.d.ts +110 -0
  40. package/dist/fulfillment/contracts/read.js +1 -0
  41. package/dist/fulfillment/contracts/readback.d.ts +38 -0
  42. package/dist/fulfillment/contracts/readback.js +1 -0
  43. package/dist/fulfillment/contracts/replacement.d.ts +34 -0
  44. package/dist/fulfillment/contracts/replacement.js +1 -0
  45. package/dist/fulfillment/contracts/store.d.ts +86 -0
  46. package/dist/fulfillment/contracts/store.js +1 -0
  47. package/dist/fulfillment/contracts/sync.d.ts +170 -0
  48. package/dist/fulfillment/contracts/sync.js +1 -0
  49. package/dist/fulfillment/currentFulfillmentParcel.d.ts +2 -0
  50. package/dist/fulfillment/currentFulfillmentParcel.js +1 -0
  51. package/dist/fulfillment/delayReadModel.d.ts +11 -0
  52. package/dist/fulfillment/delayReadModel.js +45 -0
  53. package/dist/fulfillment/deliveryAlignmentReadModel.d.ts +4 -0
  54. package/dist/fulfillment/deliveryAlignmentReadModel.js +12 -0
  55. package/dist/fulfillment/dispatchProjection.d.ts +7 -0
  56. package/dist/fulfillment/dispatchProjection.js +18 -0
  57. package/dist/fulfillment/fulfillmentObservationEffects.d.ts +66 -0
  58. package/dist/fulfillment/fulfillmentObservationEffects.js +36 -0
  59. package/dist/fulfillment/handlerSchemas.d.ts +647 -0
  60. package/dist/fulfillment/handlerSchemas.js +213 -0
  61. package/dist/fulfillment/handlerSupport.d.ts +33 -0
  62. package/dist/fulfillment/handlerSupport.js +25 -0
  63. package/dist/fulfillment/index.d.ts +37 -0
  64. package/dist/fulfillment/index.js +37 -0
  65. package/dist/fulfillment/labelLifecycle.d.ts +24 -0
  66. package/dist/fulfillment/labelLifecycle.js +9 -0
  67. package/dist/fulfillment/lowStockEvidenceHandler.d.ts +36 -0
  68. package/dist/fulfillment/lowStockEvidenceHandler.js +46 -0
  69. package/dist/fulfillment/migrations.d.ts +27 -0
  70. package/dist/fulfillment/migrations.js +8 -0
  71. package/dist/fulfillment/nativeUnsupported.d.ts +10 -0
  72. package/dist/fulfillment/nativeUnsupported.js +18 -0
  73. package/dist/fulfillment/normalizedFulfillmentFacts.d.ts +2 -0
  74. package/dist/fulfillment/normalizedFulfillmentFacts.js +1 -0
  75. package/dist/fulfillment/observationProjection.d.ts +11 -0
  76. package/dist/fulfillment/observationProjection.js +37 -0
  77. package/dist/fulfillment/omnipack/capabilities.d.ts +3 -0
  78. package/dist/fulfillment/omnipack/capabilities.js +16 -0
  79. package/dist/fulfillment/omnipack/client.d.ts +37 -0
  80. package/dist/fulfillment/omnipack/client.js +162 -0
  81. package/dist/fulfillment/omnipack/index.d.ts +52 -0
  82. package/dist/fulfillment/omnipack/index.js +349 -0
  83. package/dist/fulfillment/omnipack/mappers.d.ts +73 -0
  84. package/dist/fulfillment/omnipack/mappers.js +177 -0
  85. package/dist/fulfillment/omnipack/observation.d.ts +21 -0
  86. package/dist/fulfillment/omnipack/observation.js +57 -0
  87. package/dist/fulfillment/omnipack/omnipackDispatchPayload.d.ts +36 -0
  88. package/dist/fulfillment/omnipack/omnipackDispatchPayload.js +63 -0
  89. package/dist/fulfillment/omnipack/omnipackOutboundOrderPayload.d.ts +83 -0
  90. package/dist/fulfillment/omnipack/omnipackOutboundOrderPayload.js +113 -0
  91. package/dist/fulfillment/omnipack/omnipackProductPackPayload.d.ts +11 -0
  92. package/dist/fulfillment/omnipack/omnipackProductPackPayload.js +38 -0
  93. package/dist/fulfillment/omnipack/omnipackProductPayload.d.ts +18 -0
  94. package/dist/fulfillment/omnipack/omnipackProductPayload.js +51 -0
  95. package/dist/fulfillment/omnipack/omnipackReconciliationPayload.d.ts +1 -0
  96. package/dist/fulfillment/omnipack/omnipackReconciliationPayload.js +3 -0
  97. package/dist/fulfillment/omnipack/omnipackStatusVocabulary.d.ts +4 -0
  98. package/dist/fulfillment/omnipack/omnipackStatusVocabulary.js +87 -0
  99. package/dist/fulfillment/omnipack/omnipackWebhookPayload.d.ts +9 -0
  100. package/dist/fulfillment/omnipack/omnipackWebhookPayload.js +76 -0
  101. package/dist/fulfillment/omnipack/productSyncMappers.d.ts +18 -0
  102. package/dist/fulfillment/omnipack/productSyncMappers.js +43 -0
  103. package/dist/fulfillment/omnipack/providerError.d.ts +25 -0
  104. package/dist/fulfillment/omnipack/providerError.js +47 -0
  105. package/dist/fulfillment/omnipack/trackingReferences.d.ts +16 -0
  106. package/dist/fulfillment/omnipack/trackingReferences.js +52 -0
  107. package/dist/fulfillment/paidFulfillmentRecovery.d.ts +67 -0
  108. package/dist/fulfillment/paidFulfillmentRecovery.js +154 -0
  109. package/dist/fulfillment/paidHandoff.d.ts +27 -0
  110. package/dist/fulfillment/paidHandoff.js +86 -0
  111. package/dist/fulfillment/paidHandoffPorts.d.ts +24 -0
  112. package/dist/fulfillment/paidHandoffPorts.js +3 -0
  113. package/dist/fulfillment/postgresDeliveryAlignment.d.ts +4 -0
  114. package/dist/fulfillment/postgresDeliveryAlignment.js +12 -0
  115. package/dist/fulfillment/postgresDispatchStore.d.ts +16 -0
  116. package/dist/fulfillment/postgresDispatchStore.js +44 -0
  117. package/dist/fulfillment/postgresEvidenceReadPort.d.ts +25 -0
  118. package/dist/fulfillment/postgresEvidenceReadPort.js +45 -0
  119. package/dist/fulfillment/postgresPaidFulfillmentRecovery.d.ts +25 -0
  120. package/dist/fulfillment/postgresPaidFulfillmentRecovery.js +26 -0
  121. package/dist/fulfillment/postgresPaidHandoffStore.d.ts +4 -0
  122. package/dist/fulfillment/postgresPaidHandoffStore.js +10 -0
  123. package/dist/fulfillment/postgresShipmentSpine.d.ts +63 -0
  124. package/dist/fulfillment/postgresShipmentSpine.js +232 -0
  125. package/dist/fulfillment/postgresStockSyncPort.d.ts +8 -0
  126. package/dist/fulfillment/postgresStockSyncPort.js +63 -0
  127. package/dist/fulfillment/productReconciliationEvidenceHandler.d.ts +36 -0
  128. package/dist/fulfillment/productReconciliationEvidenceHandler.js +50 -0
  129. package/dist/fulfillment/providerCapabilities.d.ts +9 -0
  130. package/dist/fulfillment/providerCapabilities.js +17 -0
  131. package/dist/fulfillment/providerCommandLedger.d.ts +143 -0
  132. package/dist/fulfillment/providerCommandLedger.js +14 -0
  133. package/dist/fulfillment/providerDispatchAcceptance.d.ts +26 -0
  134. package/dist/fulfillment/providerDispatchAcceptance.js +23 -0
  135. package/dist/fulfillment/providerDispatchError.d.ts +6 -0
  136. package/dist/fulfillment/providerDispatchError.js +5 -0
  137. package/dist/fulfillment/providerDispatchWorker.d.ts +31 -0
  138. package/dist/fulfillment/providerDispatchWorker.js +172 -0
  139. package/dist/fulfillment/providerProductSyncWorker.d.ts +28 -0
  140. package/dist/fulfillment/providerProductSyncWorker.js +122 -0
  141. package/dist/fulfillment/providerReconciliationError.d.ts +9 -0
  142. package/dist/fulfillment/providerReconciliationError.js +17 -0
  143. package/dist/fulfillment/providerReconciliationTerminalSkip.d.ts +2 -0
  144. package/dist/fulfillment/providerReconciliationTerminalSkip.js +6 -0
  145. package/dist/fulfillment/providerReconciliationTimestamp.d.ts +1 -0
  146. package/dist/fulfillment/providerReconciliationTimestamp.js +27 -0
  147. package/dist/fulfillment/providerReconciliationWorker.d.ts +82 -0
  148. package/dist/fulfillment/providerReconciliationWorker.js +151 -0
  149. package/dist/fulfillment/providerStockAvailability.d.ts +13 -0
  150. package/dist/fulfillment/providerStockAvailability.js +51 -0
  151. package/dist/fulfillment/providerStockSyncWorker.d.ts +37 -0
  152. package/dist/fulfillment/providerStockSyncWorker.js +186 -0
  153. package/dist/fulfillment/providerTrackingReferences.d.ts +15 -0
  154. package/dist/fulfillment/providerTrackingReferences.js +23 -0
  155. package/dist/fulfillment/replacementRefusals.d.ts +5 -0
  156. package/dist/fulfillment/replacementRefusals.js +38 -0
  157. package/dist/fulfillment/replacementShipmentHandler.d.ts +5 -0
  158. package/dist/fulfillment/replacementShipmentHandler.js +46 -0
  159. package/dist/fulfillment/schemaCapabilities.d.ts +13 -0
  160. package/dist/fulfillment/schemaCapabilities.js +7 -0
  161. package/dist/fulfillment/shipmentsOverviewHandler.d.ts +16 -0
  162. package/dist/fulfillment/shipmentsOverviewHandler.js +54 -0
  163. package/dist/fulfillment/statusMap.d.ts +2 -0
  164. package/dist/fulfillment/statusMap.js +1 -0
  165. package/dist/fulfillment/trackingProgress.d.ts +1 -0
  166. package/dist/fulfillment/trackingProgress.js +1 -0
  167. package/dist/fulfillment/verifiedIngress.d.ts +52 -0
  168. package/dist/fulfillment/verifiedIngress.js +66 -0
  169. package/dist/payments/adapterConformance.d.ts +8 -0
  170. package/dist/payments/adapterConformance.js +109 -0
  171. package/dist/payments/bindings.d.ts +3 -0
  172. package/dist/payments/bindings.js +17 -0
  173. package/dist/payments/checkoutActivePaymentActionResolver.d.ts +7 -0
  174. package/dist/payments/checkoutActivePaymentActionResolver.js +77 -0
  175. package/dist/payments/checkoutRecoveryPaymentResolver.d.ts +8 -0
  176. package/dist/payments/checkoutRecoveryPaymentResolver.js +87 -0
  177. package/dist/payments/contracts/adapter.d.ts +113 -0
  178. package/dist/payments/contracts/adapter.js +1 -0
  179. package/dist/payments/contracts/conformance.d.ts +155 -0
  180. package/dist/payments/contracts/conformance.js +1 -0
  181. package/dist/payments/contracts/evidence.d.ts +157 -0
  182. package/dist/payments/contracts/evidence.js +1 -0
  183. package/dist/payments/contracts/index.d.ts +10 -0
  184. package/dist/payments/contracts/index.js +1 -0
  185. package/dist/payments/contracts/preparedAttempt.d.ts +69 -0
  186. package/dist/payments/contracts/preparedAttempt.js +1 -0
  187. package/dist/payments/contracts/reconciliation.d.ts +303 -0
  188. package/dist/payments/contracts/reconciliation.js +1 -0
  189. package/dist/payments/contracts/repair.d.ts +92 -0
  190. package/dist/payments/contracts/repair.js +1 -0
  191. package/dist/payments/contracts/truth.d.ts +92 -0
  192. package/dist/payments/contracts/truth.js +1 -0
  193. package/dist/payments/eventConformanceRunner.d.ts +12 -0
  194. package/dist/payments/eventConformanceRunner.js +125 -0
  195. package/dist/payments/index.d.ts +16 -0
  196. package/dist/payments/index.js +16 -0
  197. package/dist/payments/paymentAttemptSilenceWindow.d.ts +10 -0
  198. package/dist/payments/paymentAttemptSilenceWindow.js +19 -0
  199. package/dist/payments/paymentMethodLifecycle.d.ts +11 -0
  200. package/dist/payments/paymentMethodLifecycle.js +37 -0
  201. package/dist/payments/paymentProviderReconciliationAbsenceReopen.d.ts +7 -0
  202. package/dist/payments/paymentProviderReconciliationAbsenceReopen.js +100 -0
  203. package/dist/payments/paymentProviderReconciliationEvidence.d.ts +36 -0
  204. package/dist/payments/paymentProviderReconciliationEvidence.js +91 -0
  205. package/dist/payments/paymentProviderReconciliationWorker.d.ts +4 -0
  206. package/dist/payments/paymentProviderReconciliationWorker.js +245 -0
  207. package/dist/payments/paymentTruth.d.ts +8 -0
  208. package/dist/payments/paymentTruth.js +125 -0
  209. package/dist/payments/paymentVerifyNowHandler.d.ts +27 -0
  210. package/dist/payments/paymentVerifyNowHandler.js +70 -0
  211. package/dist/payments/paymentVerifyNowService.d.ts +23 -0
  212. package/dist/payments/paymentVerifyNowService.js +93 -0
  213. package/dist/payments/paymentWebhookPostProcessing.d.ts +22 -0
  214. package/dist/payments/paymentWebhookPostProcessing.js +15 -0
  215. package/dist/payments/postgresPaymentTruth.d.ts +10 -0
  216. package/dist/payments/postgresPaymentTruth.js +126 -0
  217. package/dist/payments/preparedAttempt.d.ts +6 -0
  218. package/dist/payments/preparedAttempt.js +70 -0
  219. package/dist/payments/preparedAttemptFinalization.d.ts +5 -0
  220. package/dist/payments/preparedAttemptFinalization.js +12 -0
  221. package/dist/payments/schemaCapabilities.d.ts +10 -0
  222. package/dist/payments/schemaCapabilities.js +10 -0
  223. package/dist/payments/sql.d.ts +20 -0
  224. package/dist/payments/sql.js +6 -0
  225. package/dist/payments/stripe/classifyDecline.d.ts +46 -0
  226. package/dist/payments/stripe/classifyDecline.js +58 -0
  227. package/dist/payments/stripe/declineFailureHints.d.ts +46 -0
  228. package/dist/payments/stripe/declineFailureHints.js +87 -0
  229. package/dist/payments/stripe/donorContracts.d.ts +120 -0
  230. package/dist/payments/stripe/donorContracts.js +1 -0
  231. package/dist/payments/stripe/executionDecline.d.ts +53 -0
  232. package/dist/payments/stripe/executionDecline.js +107 -0
  233. package/dist/payments/stripe/index.d.ts +41 -0
  234. package/dist/payments/stripe/index.js +264 -0
  235. package/dist/payments/stripe/intentMapper.d.ts +26 -0
  236. package/dist/payments/stripe/intentMapper.js +51 -0
  237. package/dist/payments/stripe/methodFacts.d.ts +10 -0
  238. package/dist/payments/stripe/methodFacts.js +12 -0
  239. package/dist/payments/stripe/paymentFailureEvidence.d.ts +26 -0
  240. package/dist/payments/stripe/paymentFailureEvidence.js +33 -0
  241. package/dist/payments/stripe/stripeFailureEvidence.d.ts +41 -0
  242. package/dist/payments/stripe/stripeFailureEvidence.js +82 -0
  243. package/dist/payments/stripe/stripeIntentConfirmationEvidence.d.ts +28 -0
  244. package/dist/payments/stripe/stripeIntentConfirmationEvidence.js +32 -0
  245. package/dist/payments/stripe/stripePaymentReconciliationProvider.d.ts +35 -0
  246. package/dist/payments/stripe/stripePaymentReconciliationProvider.js +222 -0
  247. package/dist/payments/stripe/stripeRefundEvidence.d.ts +8 -0
  248. package/dist/payments/stripe/stripeRefundEvidence.js +17 -0
  249. package/dist/payments/stripe/stripeSandboxPaymentExecutionAdapter.d.ts +45 -0
  250. package/dist/payments/stripe/stripeSandboxPaymentExecutionAdapter.js +220 -0
  251. package/dist/payments/stripe/stripeWebhookNormalizer.d.ts +14 -0
  252. package/dist/payments/stripe/stripeWebhookNormalizer.js +243 -0
  253. package/dist/payments/stripe/webhookSignature.d.ts +14 -0
  254. package/dist/payments/stripe/webhookSignature.js +43 -0
  255. package/dist/payments/tpay/blikRecurringMapper.d.ts +37 -0
  256. package/dist/payments/tpay/blikRecurringMapper.js +24 -0
  257. package/dist/payments/tpay/capabilities.d.ts +3 -0
  258. package/dist/payments/tpay/capabilities.js +18 -0
  259. package/dist/payments/tpay/classifyDecline.d.ts +46 -0
  260. package/dist/payments/tpay/classifyDecline.js +58 -0
  261. package/dist/payments/tpay/declineFailureHints.d.ts +72 -0
  262. package/dist/payments/tpay/declineFailureHints.js +37 -0
  263. package/dist/payments/tpay/donorContracts.d.ts +140 -0
  264. package/dist/payments/tpay/donorContracts.js +1 -0
  265. package/dist/payments/tpay/index.d.ts +73 -0
  266. package/dist/payments/tpay/index.js +294 -0
  267. package/dist/payments/tpay/paymentFailureEvidence.d.ts +26 -0
  268. package/dist/payments/tpay/paymentFailureEvidence.js +33 -0
  269. package/dist/payments/tpay/preparedProviderAttempt.d.ts +22 -0
  270. package/dist/payments/tpay/preparedProviderAttempt.js +24 -0
  271. package/dist/payments/tpay/providerAttemptFailureDiagnostic.d.ts +3 -0
  272. package/dist/payments/tpay/providerAttemptFailureDiagnostic.js +95 -0
  273. package/dist/payments/tpay/tpayCreateTransactionInput.d.ts +25 -0
  274. package/dist/payments/tpay/tpayCreateTransactionInput.js +128 -0
  275. package/dist/payments/tpay/tpayDeclineEvidence.d.ts +126 -0
  276. package/dist/payments/tpay/tpayDeclineEvidence.js +177 -0
  277. package/dist/payments/tpay/tpayDispatchFailure.d.ts +60 -0
  278. package/dist/payments/tpay/tpayDispatchFailure.js +121 -0
  279. package/dist/payments/tpay/tpayFailureEvidence.d.ts +20 -0
  280. package/dist/payments/tpay/tpayFailureEvidence.js +61 -0
  281. package/dist/payments/tpay/tpayHttpClient.d.ts +52 -0
  282. package/dist/payments/tpay/tpayHttpClient.js +185 -0
  283. package/dist/payments/tpay/tpayHttpFailure.d.ts +57 -0
  284. package/dist/payments/tpay/tpayHttpFailure.js +143 -0
  285. package/dist/payments/tpay/tpayPaymentExecutionAdapter.d.ts +20 -0
  286. package/dist/payments/tpay/tpayPaymentExecutionAdapter.js +249 -0
  287. package/dist/payments/tpay/tpayPaymentReconciliationProvider.d.ts +5 -0
  288. package/dist/payments/tpay/tpayPaymentReconciliationProvider.js +244 -0
  289. package/dist/payments/tpay/tpayTransactionPayload.d.ts +120 -0
  290. package/dist/payments/tpay/tpayTransactionPayload.js +96 -0
  291. package/dist/payments/tpay/wallClockTime.d.ts +31 -0
  292. package/dist/payments/tpay/wallClockTime.js +57 -0
  293. package/dist/payments/tpay/webhookJwsVerifier.d.ts +17 -0
  294. package/dist/payments/tpay/webhookJwsVerifier.js +51 -0
  295. package/dist/payments/tpay/webhookNormalizer.d.ts +54 -0
  296. package/dist/payments/tpay/webhookNormalizer.js +200 -0
  297. package/dist/payments/verifiedEvidenceProjection.d.ts +12 -0
  298. package/dist/payments/verifiedEvidenceProjection.js +166 -0
  299. package/dist/payments/verifiedIngress.d.ts +119 -0
  300. package/dist/payments/verifiedIngress.js +220 -0
  301. package/package.json +37 -2
  302. package/release-gates.json +105 -3
  303. package/sql/20260808210000_fulfillment_shipment_rail.sql +810 -0
  304. package/sql/20260810180000_payment_settlement_rail.sql +574 -0
  305. package/sql/20260815150000_payment_truth_reconciliation.sql +479 -0
  306. package/sql/20260819150000_fulfillment_shipment_sequence.sql +98 -0
  307. package/sql/20260826100000_late_payment_shifts_the_subscription_cycle.sql +215 -0
  308. package/sql/20261022080000_fulfillment_command_ledger.sql +786 -0
  309. package/sql/20261022090000_fulfillment_delivery_alignment.sql +1106 -0
  310. package/src/composition/composeBundle.ts +13 -0
  311. package/src/composition/fulfillmentContribution.ts +28 -0
  312. package/src/composition/index.ts +2 -0
  313. package/src/fulfillment/adapterConformance.ts +195 -0
  314. package/src/fulfillment/bindings.ts +26 -0
  315. package/src/fulfillment/commerceFulfillmentHandlers.ts +263 -0
  316. package/src/fulfillment/commerceFulfillmentReadModel.ts +257 -0
  317. package/src/fulfillment/contracts/alignment.ts +13 -0
  318. package/src/fulfillment/contracts/bindings.ts +30 -0
  319. package/src/fulfillment/contracts/capabilities.ts +15 -0
  320. package/src/fulfillment/contracts/conformance.ts +61 -0
  321. package/src/fulfillment/contracts/customerAlignment.ts +4 -0
  322. package/src/fulfillment/contracts/dispatch.ts +58 -0
  323. package/src/fulfillment/contracts/index.ts +18 -0
  324. package/src/fulfillment/contracts/label.ts +9 -0
  325. package/src/fulfillment/contracts/nativeUnsupported.ts +6 -0
  326. package/src/fulfillment/contracts/observation.ts +18 -0
  327. package/src/fulfillment/contracts/operator.ts +31 -0
  328. package/src/fulfillment/contracts/read.ts +42 -0
  329. package/src/fulfillment/contracts/readback.ts +11 -0
  330. package/src/fulfillment/contracts/replacement.ts +15 -0
  331. package/src/fulfillment/contracts/store.ts +26 -0
  332. package/src/fulfillment/contracts/sync.ts +61 -0
  333. package/src/fulfillment/currentFulfillmentParcel.ts +2 -0
  334. package/src/fulfillment/delayReadModel.ts +60 -0
  335. package/src/fulfillment/deliveryAlignmentReadModel.ts +15 -0
  336. package/src/fulfillment/dispatchProjection.ts +20 -0
  337. package/src/fulfillment/fulfillmentObservationEffects.ts +86 -0
  338. package/src/fulfillment/handlerSchemas.ts +255 -0
  339. package/src/fulfillment/handlerSupport.ts +25 -0
  340. package/src/fulfillment/index.ts +38 -0
  341. package/src/fulfillment/labelLifecycle.ts +11 -0
  342. package/src/fulfillment/lowStockEvidenceHandler.ts +60 -0
  343. package/src/fulfillment/migrations.ts +8 -0
  344. package/src/fulfillment/nativeUnsupported.ts +23 -0
  345. package/src/fulfillment/normalizedFulfillmentFacts.ts +2 -0
  346. package/src/fulfillment/observationProjection.ts +41 -0
  347. package/src/fulfillment/omnipack/capabilities.ts +18 -0
  348. package/src/fulfillment/omnipack/client.ts +258 -0
  349. package/src/fulfillment/omnipack/index.ts +312 -0
  350. package/src/fulfillment/omnipack/mappers.ts +261 -0
  351. package/src/fulfillment/omnipack/observation.ts +61 -0
  352. package/src/fulfillment/omnipack/omnipackDispatchPayload.ts +93 -0
  353. package/src/fulfillment/omnipack/omnipackOutboundOrderPayload.ts +194 -0
  354. package/src/fulfillment/omnipack/omnipackProductPackPayload.ts +47 -0
  355. package/src/fulfillment/omnipack/omnipackProductPayload.ts +67 -0
  356. package/src/fulfillment/omnipack/omnipackReconciliationPayload.ts +7 -0
  357. package/src/fulfillment/omnipack/omnipackStatusVocabulary.ts +103 -0
  358. package/src/fulfillment/omnipack/omnipackWebhookPayload.ts +73 -0
  359. package/src/fulfillment/omnipack/productSyncMappers.ts +74 -0
  360. package/src/fulfillment/omnipack/providerError.ts +64 -0
  361. package/src/fulfillment/omnipack/trackingReferences.ts +77 -0
  362. package/src/fulfillment/paidFulfillmentRecovery.ts +252 -0
  363. package/src/fulfillment/paidHandoff.ts +122 -0
  364. package/src/fulfillment/paidHandoffPorts.ts +21 -0
  365. package/src/fulfillment/postgresDeliveryAlignment.ts +14 -0
  366. package/src/fulfillment/postgresDispatchStore.ts +55 -0
  367. package/src/fulfillment/postgresEvidenceReadPort.ts +59 -0
  368. package/src/fulfillment/postgresPaidFulfillmentRecovery.ts +29 -0
  369. package/src/fulfillment/postgresPaidHandoffStore.ts +11 -0
  370. package/src/fulfillment/postgresShipmentSpine.ts +321 -0
  371. package/src/fulfillment/postgresStockSyncPort.ts +65 -0
  372. package/src/fulfillment/productReconciliationEvidenceHandler.ts +64 -0
  373. package/src/fulfillment/providerCapabilities.ts +18 -0
  374. package/src/fulfillment/providerCommandLedger.ts +53 -0
  375. package/src/fulfillment/providerDispatchAcceptance.ts +31 -0
  376. package/src/fulfillment/providerDispatchError.ts +7 -0
  377. package/src/fulfillment/providerDispatchWorker.ts +131 -0
  378. package/src/fulfillment/providerProductSyncWorker.ts +154 -0
  379. package/src/fulfillment/providerReconciliationError.ts +20 -0
  380. package/src/fulfillment/providerReconciliationTerminalSkip.ts +8 -0
  381. package/src/fulfillment/providerReconciliationTimestamp.ts +34 -0
  382. package/src/fulfillment/providerReconciliationWorker.ts +150 -0
  383. package/src/fulfillment/providerStockAvailability.ts +60 -0
  384. package/src/fulfillment/providerStockSyncWorker.ts +222 -0
  385. package/src/fulfillment/providerTrackingReferences.ts +31 -0
  386. package/src/fulfillment/replacementRefusals.ts +43 -0
  387. package/src/fulfillment/replacementShipmentHandler.ts +47 -0
  388. package/src/fulfillment/schemaCapabilities.ts +7 -0
  389. package/src/fulfillment/shipmentsOverviewHandler.ts +73 -0
  390. package/src/fulfillment/statusMap.ts +2 -0
  391. package/src/fulfillment/trackingProgress.ts +1 -0
  392. package/src/fulfillment/verifiedIngress.ts +80 -0
  393. package/src/payments/adapterConformance.ts +118 -0
  394. package/src/payments/bindings.ts +17 -0
  395. package/src/payments/checkoutActivePaymentActionResolver.ts +97 -0
  396. package/src/payments/checkoutRecoveryPaymentResolver.ts +108 -0
  397. package/src/payments/contracts/adapter.ts +96 -0
  398. package/src/payments/contracts/conformance.ts +171 -0
  399. package/src/payments/contracts/evidence.ts +142 -0
  400. package/src/payments/contracts/index.ts +54 -0
  401. package/src/payments/contracts/preparedAttempt.ts +86 -0
  402. package/src/payments/contracts/reconciliation.ts +296 -0
  403. package/src/payments/contracts/repair.ts +95 -0
  404. package/src/payments/contracts/truth.ts +108 -0
  405. package/src/payments/eventConformanceRunner.ts +149 -0
  406. package/src/payments/index.ts +21 -0
  407. package/src/payments/paymentAttemptSilenceWindow.ts +26 -0
  408. package/src/payments/paymentMethodLifecycle.ts +50 -0
  409. package/src/payments/paymentProviderReconciliationAbsenceReopen.ts +130 -0
  410. package/src/payments/paymentProviderReconciliationEvidence.ts +117 -0
  411. package/src/payments/paymentProviderReconciliationWorker.ts +291 -0
  412. package/src/payments/paymentTruth.ts +131 -0
  413. package/src/payments/paymentVerifyNowHandler.ts +94 -0
  414. package/src/payments/paymentVerifyNowService.ts +125 -0
  415. package/src/payments/paymentWebhookPostProcessing.ts +36 -0
  416. package/src/payments/postgresPaymentTruth.ts +149 -0
  417. package/src/payments/preparedAttempt.ts +90 -0
  418. package/src/payments/preparedAttemptFinalization.ts +13 -0
  419. package/src/payments/schemaCapabilities.ts +10 -0
  420. package/src/payments/sql.ts +6 -0
  421. package/src/payments/stripe/classifyDecline.ts +62 -0
  422. package/src/payments/stripe/declineFailureHints.ts +89 -0
  423. package/src/payments/stripe/donorContracts.ts +87 -0
  424. package/src/payments/stripe/executionDecline.ts +126 -0
  425. package/src/payments/stripe/index.ts +265 -0
  426. package/src/payments/stripe/intentMapper.ts +58 -0
  427. package/src/payments/stripe/methodFacts.ts +21 -0
  428. package/src/payments/stripe/paymentFailureEvidence.ts +58 -0
  429. package/src/payments/stripe/stripeFailureEvidence.ts +115 -0
  430. package/src/payments/stripe/stripeIntentConfirmationEvidence.ts +34 -0
  431. package/src/payments/stripe/stripePaymentReconciliationProvider.ts +263 -0
  432. package/src/payments/stripe/stripeRefundEvidence.ts +19 -0
  433. package/src/payments/stripe/stripeSandboxPaymentExecutionAdapter.ts +283 -0
  434. package/src/payments/stripe/stripeWebhookNormalizer.ts +277 -0
  435. package/src/payments/stripe/webhookSignature.ts +55 -0
  436. package/src/payments/tpay/blikRecurringMapper.ts +42 -0
  437. package/src/payments/tpay/capabilities.ts +21 -0
  438. package/src/payments/tpay/classifyDecline.ts +62 -0
  439. package/src/payments/tpay/declineFailureHints.ts +90 -0
  440. package/src/payments/tpay/donorContracts.ts +104 -0
  441. package/src/payments/tpay/index.ts +293 -0
  442. package/src/payments/tpay/paymentFailureEvidence.ts +58 -0
  443. package/src/payments/tpay/preparedProviderAttempt.ts +38 -0
  444. package/src/payments/tpay/providerAttemptFailureDiagnostic.ts +99 -0
  445. package/src/payments/tpay/tpayCreateTransactionInput.ts +158 -0
  446. package/src/payments/tpay/tpayDeclineEvidence.ts +233 -0
  447. package/src/payments/tpay/tpayDispatchFailure.ts +186 -0
  448. package/src/payments/tpay/tpayFailureEvidence.ts +75 -0
  449. package/src/payments/tpay/tpayHttpClient.ts +290 -0
  450. package/src/payments/tpay/tpayHttpFailure.ts +186 -0
  451. package/src/payments/tpay/tpayPaymentExecutionAdapter.ts +297 -0
  452. package/src/payments/tpay/tpayPaymentReconciliationProvider.ts +285 -0
  453. package/src/payments/tpay/tpayTransactionPayload.ts +207 -0
  454. package/src/payments/tpay/wallClockTime.ts +57 -0
  455. package/src/payments/tpay/webhookJwsVerifier.ts +82 -0
  456. package/src/payments/tpay/webhookNormalizer.ts +279 -0
  457. package/src/payments/verifiedEvidenceProjection.ts +179 -0
  458. package/src/payments/verifiedIngress.ts +317 -0
@@ -0,0 +1,245 @@
1
+ import { tryReopenPreparedAbsence } from "./paymentProviderReconciliationAbsenceReopen.js";
2
+ import { applyResultKey, bucket, clamp, classificationOf, evidencePayload, observedEvidenceKey, preparedAttemptEvidenceKey, safeMessage, terminalAmountMismatch, } from "./paymentProviderReconciliationEvidence.js";
3
+ import { silenceIsOverdue } from "./paymentAttemptSilenceWindow.js";
4
+ const MAX_ATTEMPTS_PER_RUN = 4;
5
+ const DEFAULT_BATCH_SIZE = MAX_ATTEMPTS_PER_RUN;
6
+ export const DEFAULT_STALE_AFTER_SECONDS = 15 * 60;
7
+ export async function runPaymentProviderReconciliationWorker(input) {
8
+ const now = input.now ?? new Date().toISOString();
9
+ const staleAfterSeconds = clamp(input.staleAfterSeconds ?? DEFAULT_STALE_AFTER_SECONDS, 60, 86_400);
10
+ // Provider reads and optional prepared-absence probes are sequential and may
11
+ // be slow. Preserve the per-run ceiling even for an oversized requested batch.
12
+ const batchSize = clamp(input.batchSize ?? DEFAULT_BATCH_SIZE, 1, MAX_ATTEMPTS_PER_RUN);
13
+ const claimKey = input.claimKey ?? `payment-provider-reconciliation:${bucket(now)}`;
14
+ const result = {
15
+ ok: true,
16
+ checked: 0,
17
+ corrected: 0,
18
+ succeeded: 0,
19
+ failed: 0,
20
+ pending: 0,
21
+ unknown: 0,
22
+ ignored: 0,
23
+ dunningOpened: 0,
24
+ replayed: 0,
25
+ providerCalls: 0,
26
+ preparedWithoutProviderAck: 0,
27
+ preparedAttemptsReopened: 0,
28
+ manualReview: 0,
29
+ silenceOverdue: 0,
30
+ amountCurrencyMismatches: 0,
31
+ failures: 0,
32
+ skipped: false,
33
+ };
34
+ // Prepared attempts can remain operator-manual indefinitely. Bound their
35
+ // share so they can never consume a whole worker batch and starve provider
36
+ // readback for finalized attempts. A batch of one intentionally prioritizes
37
+ // provider readback; normal scheduled runs use the larger default batch.
38
+ const preparedLimit = Math.floor(batchSize / 2);
39
+ const preparedAttempts = preparedLimit > 0
40
+ ? await input.port.claimPreparedAttempts({
41
+ now,
42
+ staleAfterSeconds,
43
+ limit: preparedLimit,
44
+ claimKey: `${claimKey}:prepared`,
45
+ })
46
+ : [];
47
+ for (const attempt of preparedAttempts) {
48
+ const providerStatus = {
49
+ status: "unknown",
50
+ providerStatus: "prepared_without_provider_ack",
51
+ occurredAt: null,
52
+ failureReason: "prepared_without_provider_ack",
53
+ amountMinor: null,
54
+ currency: null,
55
+ rawPayload: {
56
+ source: "payment-provider-reconciliation.prepared-watchdog.v0",
57
+ provider: attempt.provider,
58
+ providerCallPlanned: true,
59
+ providerAcknowledged: false,
60
+ },
61
+ };
62
+ const evidence = await input.port.recordEvidence({
63
+ idempotencyKey: preparedAttemptEvidenceKey(attempt, now),
64
+ provider: attempt.provider,
65
+ providerPaymentId: null,
66
+ paymentIntentId: attempt.paymentIntentId,
67
+ paymentAttemptId: attempt.paymentAttemptId,
68
+ localStatus: attempt.attemptStatus,
69
+ providerStatus: providerStatus.providerStatus,
70
+ correctionStatus: "failed",
71
+ checkedAt: now,
72
+ payload: evidencePayload(attempt, providerStatus, {
73
+ applied: false,
74
+ operatorReviewRequired: true,
75
+ }),
76
+ });
77
+ if (evidence.replayed)
78
+ result.replayed += 1;
79
+ result.preparedWithoutProviderAck += 1;
80
+ result.failures += 1;
81
+ result.ok = false;
82
+ result.reason = result.reason ?? "prepared_without_provider_ack";
83
+ // Auto-reopen after a GENUINE provider-side absence proof. A purely local
84
+ // "no ack recorded" signal cannot rule out the crash window between
85
+ // executionPort.execute() (provider charged) and finalizeProviderAttempt
86
+ // (refs persisted) — reopening in that window would mint a fresh PSP
87
+ // idempotency key and double-charge. Providers without an absence probe
88
+ if (input.autoReopenPreparedAbsence) {
89
+ const reopened = await tryReopenPreparedAbsence(input, attempt, now);
90
+ if (reopened)
91
+ result.preparedAttemptsReopened += 1;
92
+ }
93
+ }
94
+ const remainingLimit = batchSize - preparedAttempts.length;
95
+ const attempts = remainingLimit > 0
96
+ ? await input.port.claimStaleAttempts({
97
+ now,
98
+ staleAfterSeconds,
99
+ limit: remainingLimit,
100
+ claimKey,
101
+ })
102
+ : [];
103
+ result.checked = preparedAttempts.length + attempts.length;
104
+ for (const attempt of attempts) {
105
+ const provider = input.providers[attempt.provider];
106
+ if (!provider) {
107
+ await recordNonTerminalEvidence(input.port, attempt, now, {
108
+ status: "unknown",
109
+ providerStatus: "provider_not_configured",
110
+ occurredAt: null,
111
+ failureReason: "provider_not_configured",
112
+ amountMinor: null,
113
+ currency: null,
114
+ rawPayload: { provider: attempt.provider, source: "payment-provider-reconciliation.v0" },
115
+ }, "failed");
116
+ result.unknown += 1;
117
+ result.failures += 1;
118
+ result.ok = false;
119
+ result.reason = result.reason ?? `${attempt.provider}_provider_not_configured`;
120
+ continue;
121
+ }
122
+ let providerStatus;
123
+ try {
124
+ if (!attempt.providerPaymentId) {
125
+ throw new Error("provider_payment_id_missing");
126
+ }
127
+ result.providerCalls += 1;
128
+ providerStatus = await provider.readPayment({
129
+ providerPaymentId: attempt.providerPaymentId,
130
+ attempt,
131
+ });
132
+ }
133
+ catch (error) {
134
+ providerStatus = {
135
+ status: "unknown",
136
+ providerStatus: "provider_read_failed",
137
+ occurredAt: null,
138
+ failureReason: safeMessage(error),
139
+ amountMinor: null,
140
+ currency: null,
141
+ rawPayload: {
142
+ provider: attempt.provider,
143
+ providerPaymentId: attempt.providerPaymentId,
144
+ readError: safeMessage(error),
145
+ },
146
+ };
147
+ await recordNonTerminalEvidence(input.port, attempt, now, providerStatus, "failed");
148
+ result.unknown += 1;
149
+ result.failures += 1;
150
+ result.ok = false;
151
+ result.reason = result.reason ?? safeMessage(error);
152
+ continue;
153
+ }
154
+ if (providerStatus.status === "pending" || providerStatus.status === "unknown") {
155
+ // Polling cannot separate "still running" from "stuck" - both answer
156
+ // non-terminally forever - so ask the rail how long its own silence stays
157
+ // normal and surface the attempt past that. NOT a terminal decision:
158
+ // elapsed time says nothing about whether money moved.
159
+ const overdue = silenceIsOverdue(input.capabilities, attempt, now);
160
+ await recordNonTerminalEvidence(input.port, attempt, now, providerStatus, "observed", overdue);
161
+ if (providerStatus.status === "pending")
162
+ result.pending += 1;
163
+ else
164
+ result.unknown += 1;
165
+ if (overdue) {
166
+ result.silenceOverdue += 1;
167
+ result.manualReview += 1;
168
+ }
169
+ continue;
170
+ }
171
+ const mismatch = terminalAmountMismatch(attempt, providerStatus);
172
+ if (mismatch) {
173
+ await recordNonTerminalEvidence(input.port, attempt, now, {
174
+ ...providerStatus,
175
+ failureReason: mismatch,
176
+ rawPayload: { ...providerStatus.rawPayload, reconciliationMismatch: mismatch },
177
+ }, "failed");
178
+ result.manualReview += 1;
179
+ result.amountCurrencyMismatches += 1;
180
+ continue;
181
+ }
182
+ const occurredAt = providerStatus.occurredAt ?? now;
183
+ const resultStatus = providerStatus.status;
184
+ try {
185
+ const applied = await input.port.applyTerminalResult({
186
+ idempotencyKey: applyResultKey(attempt, resultStatus),
187
+ expectedOrderId: attempt.orderId,
188
+ expectedPaymentIntentId: attempt.paymentIntentId,
189
+ expectedPaymentAttemptId: attempt.paymentAttemptId,
190
+ expectedPaymentId: attempt.paymentId,
191
+ provider: attempt.provider,
192
+ providerPaymentId: attempt.providerPaymentId,
193
+ localStatus: attempt.attemptStatus,
194
+ providerStatus: providerStatus.providerStatus,
195
+ resultStatus,
196
+ occurredAt,
197
+ failureReason: resultStatus === "failed"
198
+ ? providerStatus.failureReason ?? `provider_reconciliation_${providerStatus.providerStatus}`
199
+ : null,
200
+ ...classificationOf(resultStatus, providerStatus),
201
+ checkedAt: now,
202
+ payload: evidencePayload(attempt, providerStatus, { applied: true, resultStatus }),
203
+ });
204
+ if (applied.replayed)
205
+ result.replayed += 1;
206
+ if (applied.correctionStatus === "ignored") {
207
+ result.ignored += 1;
208
+ continue;
209
+ }
210
+ result.corrected += applied.replayed ? 0 : 1;
211
+ if (resultStatus === "succeeded")
212
+ result.succeeded += 1;
213
+ else
214
+ result.failed += 1;
215
+ if (applied.subscriptionWebhookDunning?.opened && !applied.subscriptionWebhookDunning.replayed) {
216
+ result.dunningOpened += 1;
217
+ }
218
+ }
219
+ catch (error) {
220
+ await recordNonTerminalEvidence(input.port, attempt, now, {
221
+ ...providerStatus,
222
+ failureReason: safeMessage(error),
223
+ rawPayload: { ...providerStatus.rawPayload, applyResultError: safeMessage(error) },
224
+ }, "failed");
225
+ result.failures += 1;
226
+ result.ok = false;
227
+ result.reason = result.reason ?? safeMessage(error);
228
+ }
229
+ }
230
+ return result;
231
+ }
232
+ function recordNonTerminalEvidence(port, attempt, checkedAt, providerStatus, correctionStatus, silenceOverdue = false) {
233
+ return port.recordEvidence({
234
+ idempotencyKey: observedEvidenceKey(attempt, providerStatus.status, correctionStatus, checkedAt),
235
+ provider: attempt.provider,
236
+ providerPaymentId: attempt.providerPaymentId,
237
+ paymentIntentId: attempt.paymentIntentId,
238
+ paymentAttemptId: attempt.paymentAttemptId,
239
+ localStatus: attempt.attemptStatus,
240
+ providerStatus: providerStatus.providerStatus,
241
+ correctionStatus,
242
+ checkedAt,
243
+ payload: evidencePayload(attempt, providerStatus, { applied: false, silenceOverdue }),
244
+ });
245
+ }
@@ -0,0 +1,8 @@
1
+ import type { PaymentTruthEvent, PaymentReconciliationResult, CanonicalPaymentSource } from "./contracts/truth.js";
2
+ export declare function paymentReconciliationFingerprint(input: PaymentReconciliationResult): string;
3
+ /** Fingerprint accepted at a provider boundary before local ownership is known. */
4
+ export declare function paymentSourceFingerprint(input: CanonicalPaymentSource): string;
5
+ export declare function paymentPayloadFingerprint(payload: unknown): string;
6
+ /** Canonical identity for one normalized event; idempotency is deliberately not part of it. */
7
+ export declare function paymentTruthFingerprint(input: PaymentTruthEvent): string;
8
+ export declare function assertPaymentTruthEvent(input: PaymentTruthEvent): void;
@@ -0,0 +1,125 @@
1
+ import { createHash } from "node:crypto";
2
+ const PAYMENT_TRUTH_REFUSAL_CLASSES = [
3
+ "authorization_refused",
4
+ "insufficient_funds",
5
+ "method_unavailable",
6
+ "risk_refused",
7
+ "unknown_refusal",
8
+ ];
9
+ export function paymentReconciliationFingerprint(input) {
10
+ if (!input.eventId.trim() || input.idempotencyKey.trim().length < 8 || !isInstant(input.occurredAt)) {
11
+ throw new Error("payment_reconciliation_input_invalid");
12
+ }
13
+ if (input.evidenceStatus === "failed" && input.outcome !== "indeterminate") {
14
+ throw new Error("payment_reconciliation_failure_cannot_terminalize");
15
+ }
16
+ if (input.outcome === "refused" && !input.failure) {
17
+ throw new Error("payment_truth_refusal_classification_required");
18
+ }
19
+ if (input.outcome !== "refused" && input.failure) {
20
+ throw new Error("payment_truth_failure_only_for_refusal");
21
+ }
22
+ assertPaymentFailure(input.failure);
23
+ assertPaymentSourceEvidence(input.evidence);
24
+ return digest({
25
+ eventId: input.eventId,
26
+ evidenceStatus: input.evidenceStatus,
27
+ outcome: input.outcome,
28
+ occurredAt: input.occurredAt,
29
+ failure: input.failure,
30
+ evidence: input.evidence,
31
+ });
32
+ }
33
+ /** Fingerprint accepted at a provider boundary before local ownership is known. */
34
+ export function paymentSourceFingerprint(input) {
35
+ if (!input.sourceEventId.trim() || !input.eventKind.trim()
36
+ || (input.occurredAt !== null && !isInstant(input.occurredAt))) {
37
+ throw new Error("payment_source_fingerprint_input_invalid");
38
+ }
39
+ if (!/^[0-9a-f]{64}$/.test(input.payloadFingerprint)) {
40
+ throw new Error("payment_truth_payload_fingerprint_invalid");
41
+ }
42
+ return digest(input);
43
+ }
44
+ export function paymentPayloadFingerprint(payload) {
45
+ return digest(payload);
46
+ }
47
+ /** Canonical identity for one normalized event; idempotency is deliberately not part of it. */
48
+ export function paymentTruthFingerprint(input) {
49
+ assertPaymentTruthEvent(input);
50
+ return digest({
51
+ sourceEventId: input.sourceEventId,
52
+ settlementIntentId: input.settlementIntentId,
53
+ outcome: input.outcome,
54
+ amountMinor: input.amountMinor,
55
+ currency: input.currency,
56
+ occurredAt: input.occurredAt,
57
+ failure: input.failure,
58
+ evidence: input.evidence,
59
+ });
60
+ }
61
+ export function assertPaymentTruthEvent(input) {
62
+ if (!input.sourceEventId.trim())
63
+ throw new Error("payment_truth_source_event_id_required");
64
+ if (input.idempotencyKey.trim().length < 8)
65
+ throw new Error("payment_truth_idempotency_key_invalid");
66
+ if (!input.settlementIntentId.trim())
67
+ throw new Error("payment_truth_settlement_intent_required");
68
+ if (!Number.isSafeInteger(input.amountMinor) || input.amountMinor <= 0) {
69
+ throw new Error("payment_truth_amount_invalid");
70
+ }
71
+ if (!/^[A-Z]{3}$/.test(input.currency))
72
+ throw new Error("payment_truth_currency_invalid");
73
+ if (!isInstant(input.occurredAt) || !isInstant(input.evidence.observedAt)) {
74
+ throw new Error("payment_truth_time_invalid");
75
+ }
76
+ if (!input.evidence.sourceReference.trim() || !input.evidence.observedStatus.trim()) {
77
+ throw new Error("payment_truth_source_evidence_invalid");
78
+ }
79
+ if (!/^[0-9a-f]{64}$/.test(input.evidence.payloadFingerprint)) {
80
+ throw new Error("payment_truth_payload_fingerprint_invalid");
81
+ }
82
+ if (input.outcome === "refused" && !input.failure) {
83
+ throw new Error("payment_truth_refusal_classification_required");
84
+ }
85
+ if (input.outcome !== "refused" && input.failure) {
86
+ throw new Error("payment_truth_failure_only_for_refusal");
87
+ }
88
+ assertPaymentFailure(input.failure);
89
+ assertPaymentSourceEvidence(input.evidence);
90
+ }
91
+ function isInstant(value) {
92
+ return value.trim().length > 0 && Number.isFinite(Date.parse(value));
93
+ }
94
+ function stableJson(value) {
95
+ if (Array.isArray(value))
96
+ return `[${value.map(stableJson).join(",")}]`;
97
+ if (value && typeof value === "object") {
98
+ return `{${Object.entries(value)
99
+ .sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)
100
+ .map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`)
101
+ .join(",")}}`;
102
+ }
103
+ return JSON.stringify(value);
104
+ }
105
+ function assertPaymentFailure(failure) {
106
+ if (failure && !PAYMENT_TRUTH_REFUSAL_CLASSES.includes(failure.classification)) {
107
+ throw new Error("payment_truth_failure_class_invalid");
108
+ }
109
+ }
110
+ function assertPaymentSourceEvidence(evidence) {
111
+ if (evidence.sourceKind !== "accepted_event" && evidence.sourceKind !== "reconciliation_read") {
112
+ throw new Error("payment_truth_source_kind_invalid");
113
+ }
114
+ if (!evidence.sourceReference.trim() || !evidence.observedStatus.trim()) {
115
+ throw new Error("payment_truth_source_evidence_invalid");
116
+ }
117
+ if (!isInstant(evidence.observedAt))
118
+ throw new Error("payment_truth_time_invalid");
119
+ if (!/^[0-9a-f]{64}$/.test(evidence.payloadFingerprint)) {
120
+ throw new Error("payment_truth_payload_fingerprint_invalid");
121
+ }
122
+ }
123
+ function digest(value) {
124
+ return createHash("sha256").update(stableJson(value)).digest("hex");
125
+ }
@@ -0,0 +1,27 @@
1
+ import { z } from "zod";
2
+ import type { HttpRequest, HttpResponse } from "../http/index.js";
3
+ import type { BffResponder } from "../bff/index.js";
4
+ import type { PaymentProviderReconciliationProvider, PaymentProviderReconciliationPort } from "./contracts/reconciliation.js";
5
+ import type { PaymentVerifyReadPort } from "./contracts/reconciliation.js";
6
+ /**
7
+ * Buyer-triggered "verify now": after a CLIENT-side confirm failure the FE has
8
+ * the only copy of the outcome (a pre-charge provider rejection emits no
9
+ * webhook), so it asks the server to read the provider immediately instead of
10
+ * waiting for the next adopter-configured reconciliation pass. The client can never assert a result — truth is the live
11
+ * provider readback, and the only write path is the reconciliation apply RPC
12
+ * with the cron's own idempotency key, so both paths converge replay-safely.
13
+ */
14
+ export declare const paymentVerifyRequestSchema: z.ZodObject<{
15
+ orderId: z.ZodGUID;
16
+ paymentIntentId: z.ZodGUID;
17
+ clientId: z.ZodGUID;
18
+ }, z.core.$strip>;
19
+ export type PaymentVerifyRequest = z.infer<typeof paymentVerifyRequestSchema>;
20
+ export declare function createCommercePaymentVerifyHandler(deps: {
21
+ readPort: PaymentVerifyReadPort;
22
+ applyPort: Pick<PaymentProviderReconciliationPort, "applyTerminalResult">;
23
+ providers: Partial<Record<string, PaymentProviderReconciliationProvider>>;
24
+ mutationsEnabled: () => boolean;
25
+ now?: () => Date;
26
+ responder: BffResponder;
27
+ }): (req: HttpRequest, res: HttpResponse) => Promise<void>;
@@ -0,0 +1,70 @@
1
+ import { z } from "zod";
2
+ import { verifyPaymentAttemptNow } from "./paymentVerifyNowService.js";
3
+ /**
4
+ * Buyer-triggered "verify now": after a CLIENT-side confirm failure the FE has
5
+ * the only copy of the outcome (a pre-charge provider rejection emits no
6
+ * webhook), so it asks the server to read the provider immediately instead of
7
+ * waiting for the next adopter-configured reconciliation pass. The client can never assert a result — truth is the live
8
+ * provider readback, and the only write path is the reconciliation apply RPC
9
+ * with the cron's own idempotency key, so both paths converge replay-safely.
10
+ */
11
+ export const paymentVerifyRequestSchema = z.object({
12
+ orderId: z.guid(),
13
+ paymentIntentId: z.guid(),
14
+ clientId: z.guid(),
15
+ });
16
+ export function createCommercePaymentVerifyHandler(deps) {
17
+ const now = deps.now ?? (() => new Date());
18
+ const { sendBffError, sendBffSuccess, sendMethodNotAllowed } = deps.responder;
19
+ return async (req, res) => {
20
+ if (req.method !== "POST") {
21
+ sendMethodNotAllowed(res, ["POST"]);
22
+ return;
23
+ }
24
+ if (!deps.mutationsEnabled()) {
25
+ sendBffError(res, "UPSTREAM_UNAVAILABLE", "Provider payment verify is disabled", {
26
+ details: {
27
+ feature: "payment-verify",
28
+ featureFlag: "COMMERCE_PROVIDER_PAYMENTS_ENABLED",
29
+ reason: "feature_flag_disabled",
30
+ },
31
+ });
32
+ return;
33
+ }
34
+ const parsed = paymentVerifyRequestSchema.safeParse(req.body);
35
+ if (!parsed.success) {
36
+ sendBffError(res, "BAD_REQUEST", "Invalid payment verify request", {
37
+ details: parsed.error.flatten(),
38
+ });
39
+ return;
40
+ }
41
+ const snapshot = await deps.readPort.readVerifiableAttempt(parsed.data);
42
+ if (!snapshot) {
43
+ sendBffError(res, "NOT_FOUND", "Payment not found");
44
+ return;
45
+ }
46
+ // Same non-leaking ownership shape as payment-status: a non-owning triple
47
+ // reads as absent rather than confirming the payment exists.
48
+ if (snapshot.orderClientId !== parsed.data.clientId) {
49
+ sendBffError(res, "NOT_FOUND", "Payment not found");
50
+ return;
51
+ }
52
+ const result = await verifyPaymentAttemptNow({
53
+ snapshot,
54
+ applyPort: deps.applyPort,
55
+ providers: deps.providers,
56
+ now,
57
+ // This route has exactly one kind of caller: a browser sitting in a live
58
+ // checkout, asking about the attempt it is currently waiting on. The
59
+ // reconciliation worker never comes through here — it holds the provider
60
+ // and calls `readPayment` itself — so the purpose is a property of the
61
+ // seam, not something a request may choose.
62
+ purpose: "active_checkout",
63
+ });
64
+ sendBffSuccess(res, {
65
+ status: result.status,
66
+ verified: result.verified,
67
+ applied: result.applied,
68
+ });
69
+ };
70
+ }
@@ -0,0 +1,23 @@
1
+ import type { ProviderReadPurpose } from "./contracts/evidence.js";
2
+ import type { VerifiableAttemptSnapshot, PaymentVerifyNowResult } from "./contracts/reconciliation.js";
3
+ import type { ClaimedPaymentAttempt, PaymentProviderReconciliationPort, PaymentProviderReconciliationProvider, ProviderReconciliationStatus } from "./contracts/reconciliation.js";
4
+ /**
5
+ * Shared buyer/cron-compatible live PSP read. It never accepts a browser
6
+ * outcome and terminal writes still pass through the canonical reconciliation
7
+ * RPC, so recovery cannot create a second payment truth path.
8
+ */
9
+ export declare function verifyPaymentAttemptNow(input: {
10
+ snapshot: VerifiableAttemptSnapshot;
11
+ applyPort: Pick<PaymentProviderReconciliationPort, "applyTerminalResult">;
12
+ providers: Partial<Record<string, PaymentProviderReconciliationProvider>>;
13
+ now: () => Date;
14
+ providerPaymentId?: string;
15
+ providerStatus?: ProviderReconciliationStatus;
16
+ /**
17
+ * Passed straight to the provider read. A caller that omits it gets the
18
+ * reconciliation reading, in which an intent still waiting for its first
19
+ * payment method is a finished, abandoned attempt.
20
+ */
21
+ purpose?: ProviderReadPurpose;
22
+ }): Promise<PaymentVerifyNowResult>;
23
+ export declare function toClaimedAttemptShape(snapshot: VerifiableAttemptSnapshot, providerPaymentId: string): ClaimedPaymentAttempt;
@@ -0,0 +1,93 @@
1
+ import { applyResultKey, evidencePayload, terminalAmountMismatch } from "./paymentProviderReconciliationEvidence.js";
2
+ const LIVE_ATTEMPT_STATUSES = new Set(["sent_to_provider", "requires_action", "processing", "created"]);
3
+ /**
4
+ * Shared buyer/cron-compatible live PSP read. It never accepts a browser
5
+ * outcome and terminal writes still pass through the canonical reconciliation
6
+ * RPC, so recovery cannot create a second payment truth path.
7
+ */
8
+ export async function verifyPaymentAttemptNow(input) {
9
+ const { snapshot } = input;
10
+ if (!LIVE_ATTEMPT_STATUSES.has(snapshot.attemptStatus)) {
11
+ return { status: snapshot.attemptStatus, verified: false, applied: false, providerPaymentId: null, attempt: null };
12
+ }
13
+ const provider = input.providers[snapshot.provider];
14
+ const providerPaymentId = input.providerPaymentId
15
+ ?? snapshot.providerAttemptId
16
+ ?? snapshot.intentProviderPaymentId
17
+ ?? snapshot.providerSessionId;
18
+ if (!provider || !providerPaymentId) {
19
+ return { status: "unavailable", verified: false, applied: false, providerPaymentId, attempt: null };
20
+ }
21
+ const attempt = toClaimedAttemptShape(snapshot, providerPaymentId);
22
+ const providerStatus = input.providerStatus
23
+ ?? await provider.readPayment({
24
+ providerPaymentId,
25
+ attempt,
26
+ ...(input.purpose ? { purpose: input.purpose } : {}),
27
+ });
28
+ if (providerStatus.status !== "succeeded" && providerStatus.status !== "failed") {
29
+ return {
30
+ // Preserve the established payment-verify contract: an unknown provider
31
+ // vocabulary is still non-terminal and therefore reported as pending.
32
+ status: "pending",
33
+ verified: true,
34
+ applied: false,
35
+ providerPaymentId,
36
+ attempt,
37
+ };
38
+ }
39
+ if (terminalAmountMismatch(attempt, providerStatus)) {
40
+ return { status: "manual_review", verified: true, applied: false, providerPaymentId, attempt };
41
+ }
42
+ const checkedAt = input.now().toISOString();
43
+ const applied = await input.applyPort.applyTerminalResult({
44
+ idempotencyKey: applyResultKey(attempt, providerStatus.status),
45
+ expectedOrderId: snapshot.orderId,
46
+ expectedPaymentIntentId: snapshot.paymentIntentId,
47
+ expectedPaymentAttemptId: snapshot.paymentAttemptId,
48
+ expectedPaymentId: snapshot.paymentId,
49
+ provider: attempt.provider,
50
+ providerPaymentId,
51
+ localStatus: snapshot.attemptStatus,
52
+ providerStatus: providerStatus.providerStatus,
53
+ resultStatus: providerStatus.status,
54
+ occurredAt: providerStatus.occurredAt ?? checkedAt,
55
+ failureReason: providerStatus.status === "failed"
56
+ ? providerStatus.failureReason ?? `provider_verify_${providerStatus.providerStatus}`
57
+ : null,
58
+ checkedAt,
59
+ payload: evidencePayload(attempt, providerStatus, {
60
+ source: "commerce-payment-verify.v0",
61
+ trigger: "buyer_confirm_settled",
62
+ }),
63
+ });
64
+ return {
65
+ status: providerStatus.status,
66
+ verified: true,
67
+ applied: applied.correctionStatus === "corrected" && !applied.replayed,
68
+ providerPaymentId,
69
+ attempt,
70
+ };
71
+ }
72
+ export function toClaimedAttemptShape(snapshot, providerPaymentId) {
73
+ return {
74
+ paymentAttemptId: snapshot.paymentAttemptId,
75
+ paymentIntentId: snapshot.paymentIntentId,
76
+ paymentId: snapshot.paymentId,
77
+ orderId: snapshot.orderId,
78
+ subscriptionId: null,
79
+ subscriptionCycleId: null,
80
+ provider: snapshot.provider,
81
+ providerPaymentId,
82
+ providerAttemptId: snapshot.providerAttemptId,
83
+ providerSessionId: snapshot.providerSessionId,
84
+ attemptStatus: snapshot.attemptStatus,
85
+ intentStatus: snapshot.intentStatus,
86
+ amountMinor: snapshot.amountMinor,
87
+ currency: snapshot.currency,
88
+ orderMode: snapshot.orderMode,
89
+ cycleRetryAttempt: 0,
90
+ cycleNextRetryAt: null,
91
+ localUpdatedAt: snapshot.localUpdatedAt,
92
+ };
93
+ }
@@ -0,0 +1,22 @@
1
+ export type PaymentRefusalHandoff = {
2
+ outcome: "refused" | "not_refused";
3
+ idempotencyKey: string;
4
+ paymentIntentId: string | null;
5
+ sourceEventId: string;
6
+ failureReason: string | null;
7
+ occurredAt: string;
8
+ };
9
+ export interface PaymentFailureDunningPort {
10
+ openFromExplicitRefusal(input: {
11
+ idempotencyKey: string;
12
+ paymentIntentId: string;
13
+ sourceEventId: string;
14
+ failureReason: string | null;
15
+ occurredAt: string;
16
+ }): Promise<void>;
17
+ }
18
+ /**
19
+ * Neutral terminal handoff. Only explicit refusal evidence may enter dunning;
20
+ * silence, timeout and every other non-terminal answer are deliberate no-ops.
21
+ */
22
+ export declare function handoffExplicitPaymentRefusal(input: PaymentRefusalHandoff, port: PaymentFailureDunningPort): Promise<void>;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Neutral terminal handoff. Only explicit refusal evidence may enter dunning;
3
+ * silence, timeout and every other non-terminal answer are deliberate no-ops.
4
+ */
5
+ export async function handoffExplicitPaymentRefusal(input, port) {
6
+ if (input.outcome !== "refused" || !input.paymentIntentId)
7
+ return;
8
+ await port.openFromExplicitRefusal({
9
+ idempotencyKey: input.idempotencyKey,
10
+ paymentIntentId: input.paymentIntentId,
11
+ sourceEventId: input.sourceEventId,
12
+ failureReason: input.failureReason,
13
+ occurredAt: input.occurredAt,
14
+ });
15
+ }
@@ -0,0 +1,10 @@
1
+ import type { PaymentTruthPort } from "./contracts/truth.js";
2
+ import type { PostgresPaymentTruthOptions } from "./contracts/truth.js";
3
+ interface PgQueryExecutor {
4
+ query(text: string, values?: unknown[]): Promise<{
5
+ rows: Record<string, unknown>[];
6
+ }>;
7
+ }
8
+ /** Direct-PG caller for the provider-neutral payment truth public forward. */
9
+ export declare function createPostgresPaymentTruthPort(executor: PgQueryExecutor, options: PostgresPaymentTruthOptions): PaymentTruthPort;
10
+ export {};