@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,66 @@
1
+ import { applyFulfillmentObservationEffects } from "./fulfillmentObservationEffects.js";
2
+ import { observationStatusPolicy, projectObservation } from "./observationProjection.js";
3
+ import { uniqueTrackingReferences } from "./providerTrackingReferences.js";
4
+ /** Adapter verification owns auth-before-parse; the host owns durable replay. */
5
+ export async function verifyAndNormalizeFulfillmentObservation(input) {
6
+ if (!input.enabled)
7
+ return { kind: "refused", refusal: { reason: "disabled", phase: "verify", retryable: false } };
8
+ const verified = await input.provider.verifyAndNormalize(input.verification);
9
+ if (verified.kind === "refused")
10
+ return verified;
11
+ const observation = projectObservation(verified.observation);
12
+ const inbound = await input.localPersistence.recordObservation(observation);
13
+ const ref = await input.lifecycle.findDispatchRef(observation);
14
+ if (!ref) {
15
+ await input.localPersistence.markProcessed(observation.eventKey, { status: "ignored", refusal: { reason: "local_missing", phase: "apply", retryable: false } });
16
+ return { kind: "ignored", observation, replayed: inbound.replayed, trackingRefs: 0, trackingReadBacks: 0 };
17
+ }
18
+ const externalRef = observation.correlation.externalRef?.trim() || ref.externalRef?.trim();
19
+ if (!externalRef)
20
+ throw new TypeError("fulfillment_dispatch_acceptance_external_ref_missing");
21
+ await input.lifecycle.acknowledgeDispatchAcceptance(ref, observation);
22
+ const statusEvidence = await input.lifecycle.recordStatusEvidence(ref, observation);
23
+ let trackingRefs = 0;
24
+ let trackingReadBacks = 0;
25
+ const effectPort = {
26
+ ...input.lifecycle.effects,
27
+ async markProviderStockConsumed(request) {
28
+ try {
29
+ return await input.lifecycle.effects.markProviderStockConsumed(request);
30
+ }
31
+ catch (error) {
32
+ if (input.lifecycle.classifyFailure(error) === "stock_contention") {
33
+ try {
34
+ await input.lifecycle.annotateStockContention?.(observation.eventKey, ref.fulfillmentRef);
35
+ }
36
+ catch { /* Annotation is best-effort; preserve the original stock failure. */ }
37
+ }
38
+ throw error;
39
+ }
40
+ },
41
+ };
42
+ const localStatus = observation.fact.canonicalStatus;
43
+ const effects = {
44
+ port: effectPort, localStatus, ids: { orderId: ref.orderRef, fulfillmentOrderId: ref.fulfillmentRef }, observation,
45
+ trackingRefs: uniqueTrackingReferences(observation.trackingRefs).map(tracking => ({ trackingNumber: tracking.trackingNumber, trackingUrl: tracking.publicUrl, carrierKind: tracking.carrierRef, service: tracking.serviceRef })),
46
+ stockIdempotencyKey: input.lifecycle.keys.stock(ref.fulfillmentRef), handoffIdempotencyKey: input.lifecycle.keys.handoff(ref.fulfillmentRef),
47
+ trackingIdempotencyKey: number => input.lifecycle.keys.tracking(observation.eventKey, number),
48
+ issueAccountingInvoice: input.lifecycle.issueAccountingInvoice ? () => input.lifecycle.issueAccountingInvoice(ref.fulfillmentRef) : undefined,
49
+ onTrackingRecorded: result => { trackingRefs += result.replayed ? 0 : 1; trackingReadBacks += result.readBack ? 1 : 0; },
50
+ };
51
+ if (!observationStatusPolicy.handsOver(localStatus))
52
+ await applyFulfillmentObservationEffects({ ...effects, trackingRefs: [] }, observationStatusPolicy);
53
+ else {
54
+ try {
55
+ await applyFulfillmentObservationEffects(effects, observationStatusPolicy);
56
+ }
57
+ catch (error) {
58
+ if (input.lifecycle.classifyFailure(error) !== "state_conflict")
59
+ throw error;
60
+ await input.localPersistence.markProcessed(observation.eventKey, { status: "processed" });
61
+ return { kind: "superseded", observation, replayed: inbound.replayed || statusEvidence.replayed, trackingRefs, trackingReadBacks };
62
+ }
63
+ }
64
+ await input.localPersistence.markProcessed(observation.eventKey, { status: "processed" });
65
+ return { kind: "processed", observation, replayed: inbound.replayed || statusEvidence.replayed, trackingRefs, trackingReadBacks };
66
+ }
@@ -0,0 +1,8 @@
1
+ import type { PaymentAdapterConformanceEvidence, PaymentAdapterConformanceSubject, PaymentVerifyNormalizePort } from "./contracts/index.js";
2
+ /** Runner-independent adapter proof. Verification fixtures are owned by each adapter. */
3
+ export declare function runPaymentAdapterConformance(subjects: readonly (PaymentAdapterConformanceSubject & {
4
+ verification: readonly {
5
+ input: Parameters<PaymentVerifyNormalizePort["verifyAndNormalize"]>[0];
6
+ expected: Awaited<ReturnType<PaymentVerifyNormalizePort["verifyAndNormalize"]>>;
7
+ }[];
8
+ })[]): Promise<PaymentAdapterConformanceEvidence>;
@@ -0,0 +1,109 @@
1
+ import { projectVerifiedEvidence } from "./verifiedEvidenceProjection.js";
2
+ import { validatePaymentExecutionContractResult } from "@openlup/core/testing";
3
+ /** Runner-independent adapter proof. Verification fixtures are owned by each adapter. */
4
+ export async function runPaymentAdapterConformance(subjects) {
5
+ const observations = [];
6
+ const cases = [];
7
+ for (const subject of subjects) {
8
+ const { adapter, executionInput, readbackInput } = subject;
9
+ const provider = adapter.capabilities.providerKind;
10
+ requireFact(executionInput.money.currency.length > 0, "configured currency");
11
+ adapter.attemptPort.validateInput(executionInput);
12
+ const result = await adapter.attemptPort.execute(executionInput);
13
+ const { handoff, ...execution } = result;
14
+ const sensitiveValues = [executionInput.payer?.email, executionInput.payer?.name, executionInput.customerAuthorization,
15
+ handoff?.kind === "client-confirmed" ? handoff.payload : handoff?.url].filter((v) => v !== undefined && v.length > 0);
16
+ const sensitiveForms = sensitiveValues.flatMap(value => [value, JSON.stringify(value).slice(1, -1)]);
17
+ const payerForms = [executionInput.payer?.email, executionInput.payer?.name]
18
+ .filter((value) => Boolean(value?.length))
19
+ .flatMap(value => [value, JSON.stringify(value).slice(1, -1)]);
20
+ const input = {
21
+ idempotencyKey: executionInput.attemptRef, providerIdempotencyKey: executionInput.providerIdempotencyKey,
22
+ providerRequestFingerprint: executionInput.fingerprint, paymentIntentId: executionInput.intentRef,
23
+ amountMinor: executionInput.money.amountMinor, currency: executionInput.money.currency, mode: "one_time",
24
+ };
25
+ const validation = validatePaymentExecutionContractResult({ input, expectedProvider: provider, sensitiveValues: sensitiveForms,
26
+ result: { provider, providerAttemptId: result.dispatch.kind === "dispatched" ? result.dispatch.providerPaymentRef : null,
27
+ providerSessionId: null, attemptStatus: result.outcome.kind === "attempt" ? result.outcome.status : "processing",
28
+ nextActionKind: null, requestPayload: { providerIdempotencyKey: input.providerIdempotencyKey,
29
+ providerRequestFingerprint: input.providerRequestFingerprint }, responsePayload: result.diagnostics },
30
+ });
31
+ requireFact(validation.ok, "execution diagnostics and taxonomy");
32
+ requireFact(!payerForms.some(value => JSON.stringify(result).includes(value)), "execution payer redaction");
33
+ if (adapter.capabilities.payerContext.requiresPayerBlock && !executionInput.payer) {
34
+ requireFact(result.dispatch.kind === "notDispatched" && result.dispatch.evidence.exact
35
+ && result.dispatch.evidence.phase === "before-dispatch", "missing required input exact notDispatched");
36
+ }
37
+ const returned = await adapter.readbackPort.readPayment(readbackInput);
38
+ const { handoff: readbackHandoff, ...readback } = "handoff" in returned ? returned : { ...returned, handoff: undefined };
39
+ requireFact(!sensitiveForms.some(value => JSON.stringify(readback).includes(value)), "readback secret redaction");
40
+ requireFact(sameIdentity(readback.identity, readbackInput.identity) && sameMoney(readback.expectedMoney, readbackInput.expectedMoney), "readback exact identity and money");
41
+ requireFact(adapter.capabilities.readback === "supported" ? returned.kind !== "unsupported" : returned.kind === "unsupported", "readback capability");
42
+ if ("observedMoney" in returned)
43
+ requireFact(sameMoney(returned.observedMoney, readbackInput.expectedMoney), "observed money");
44
+ if (adapter.capabilities.close === "supported") {
45
+ requireFact(typeof adapter.readbackPort.close === "function", "close method present");
46
+ const closed = await adapter.readbackPort.close(readbackInput);
47
+ requireFact(closed.kind !== "unsupported" && sameIdentity(closed.identity, readbackInput.identity)
48
+ && sameMoney(closed.expectedMoney, readbackInput.expectedMoney), "close exact identity and money");
49
+ }
50
+ else if (adapter.readbackPort.close) {
51
+ requireFact((await adapter.readbackPort.close(readbackInput)).kind === "unsupported", "close refuses");
52
+ }
53
+ let absence;
54
+ if (adapter.capabilities.exactAbsence === "supported")
55
+ requireFact(adapter.absencePort !== undefined, "absence port present");
56
+ if (adapter.absencePort) {
57
+ requireFact(subject.absenceInput !== undefined, "absence input present");
58
+ absence = await adapter.absencePort.proveAbsence(subject.absenceInput);
59
+ requireFact(sameIdentity(absence.identity, subject.absenceInput.identity)
60
+ && sameMoney(absence.expectedMoney, subject.absenceInput.expectedMoney), "absence exact identity and money");
61
+ requireFact(adapter.capabilities.exactAbsence === "supported" ? absence.kind !== "unsupported" : absence.kind === "unsupported", "absence capability");
62
+ if (absence.kind === "absent")
63
+ requireFact(absence.evidence.exact && absence.evidence.complete
64
+ && absence.evidence.lookupReference.trim().length > 0, "complete absence evidence");
65
+ }
66
+ const fingerprints = new Map();
67
+ const moneyEvents = [];
68
+ for (const fixture of subject.verification) {
69
+ const verified = await adapter.verifyPort.verifyAndNormalize(fixture.input);
70
+ requireFact(JSON.stringify(verified) === JSON.stringify(fixture.expected), "verified fixture");
71
+ if (verified.kind !== "refusal") {
72
+ requireFact(verified.kind !== "money" || (verified.money !== null
73
+ && Number.isSafeInteger(verified.money.amountMinor) && verified.money.amountMinor > 0
74
+ && verified.money.currency.trim().length > 0)
75
+ || (verified.outcome !== "succeeded" && verified.outcome !== "refunded" && verified.outcome !== "disputed"), "settling outcome requires positive money");
76
+ requireFact(!sensitiveForms.some(value => JSON.stringify({ payload: projectVerifiedEvidence(verified, fixture.input, "require-evidence").rawPayload, diagnostics: result.diagnostics }).includes(value)), "audit payload secret redaction");
77
+ const outcome = verified.kind + ":" + verified.outcome;
78
+ const previous = fingerprints.get(verified.providerEventId);
79
+ if (previous)
80
+ requireFact(previous.outcome === outcome && previous.fingerprint === verified.fingerprint, "replay identity fingerprint");
81
+ if (verified.kind === "money") {
82
+ for (const event of moneyEvents) {
83
+ if (event.reference === verified.providerPaymentRef && event.outcome !== outcome) {
84
+ requireFact(event.eventId !== verified.providerEventId && event.fingerprint !== verified.fingerprint, "changing outcome identity");
85
+ }
86
+ }
87
+ moneyEvents.push({ reference: verified.providerPaymentRef, outcome, eventId: verified.providerEventId, fingerprint: verified.fingerprint });
88
+ }
89
+ fingerprints.set(verified.providerEventId, { fingerprint: verified.fingerprint, outcome });
90
+ }
91
+ }
92
+ // Transient handoffs are deliberately excluded from the returned evidence.
93
+ void readbackHandoff;
94
+ observations.push({ subjectId: subject.subjectId, execution, readback, ...(absence ? { absence } : {}) });
95
+ cases.push({ subjectIds: [subject.subjectId], name: "execution, verification, capability and exact readback", passed: true });
96
+ }
97
+ return { subjects: observations, cases };
98
+ }
99
+ function requireFact(value, label) {
100
+ if (!value)
101
+ throw new Error(`payment_adapter_conformance:${label}`);
102
+ }
103
+ function sameMoney(left, right) {
104
+ return left.amountMinor === right.amountMinor && left.currency === right.currency;
105
+ }
106
+ function sameIdentity(left, right) {
107
+ return left.provider === right.provider && left.providerPaymentRef === right.providerPaymentRef
108
+ && left.intentRef === right.intentRef && left.attemptRef === right.attemptRef;
109
+ }
@@ -0,0 +1,3 @@
1
+ import type { PaymentServices, PaymentServicesOptions } from "./contracts/repair.js";
2
+ /** One host-owned scope per runtime unit; no driver or environment discovery. */
3
+ export declare function createPaymentServices(options: PaymentServicesOptions): PaymentServices | null;
@@ -0,0 +1,17 @@
1
+ /** One host-owned scope per runtime unit; no driver or environment discovery. */
2
+ export function createPaymentServices(options) {
3
+ if (options.schema?.truth !== "supported" || !options.openTruth)
4
+ return null;
5
+ const openTruth = options.openTruth;
6
+ return {
7
+ async run(work) {
8
+ const scope = await openTruth();
9
+ try {
10
+ return await work(scope.port);
11
+ }
12
+ finally {
13
+ await scope.close();
14
+ }
15
+ },
16
+ };
17
+ }
@@ -0,0 +1,7 @@
1
+ import type { CheckoutActivePaymentActionResolver, CheckoutActionReadProvider } from "./contracts/repair.js";
2
+ import type { PaymentVerifyReadPort } from "./contracts/reconciliation.js";
3
+ export declare function createCheckoutActivePaymentActionResolver(deps: {
4
+ readPort: PaymentVerifyReadPort;
5
+ providers: Partial<Record<string, CheckoutActionReadProvider>>;
6
+ railHandoffKinds(rail: string): readonly ("redirect" | "client-confirmed")[];
7
+ }): CheckoutActivePaymentActionResolver;
@@ -0,0 +1,77 @@
1
+ import { toClaimedAttemptShape } from "./paymentVerifyNowService.js";
2
+ const LIVE_INTENT_STATUSES = new Set(["requires_action", "processing"]);
3
+ const LIVE_ATTEMPT_STATUSES = new Set(["sent_to_provider", "requires_action", "processing"]);
4
+ export function createCheckoutActivePaymentActionResolver(deps) {
5
+ return {
6
+ async readActiveAction(authority) {
7
+ try {
8
+ const initial = await deps.readPort.readVerifiableAttempt({
9
+ orderId: authority.orderId,
10
+ paymentIntentId: authority.paymentIntentId,
11
+ });
12
+ if (!matchesAuthority(initial, authority) || !isLive(initial))
13
+ return null;
14
+ const provider = deps.providers[authority.executionRail];
15
+ const providerPaymentId = provider?.resolvePaymentReference(initial) ?? null;
16
+ if (!provider || !providerPaymentId)
17
+ return null;
18
+ const attempt = toClaimedAttemptShape(initial, providerPaymentId);
19
+ const reading = await provider.readRecoveryPayment({
20
+ providerPaymentId,
21
+ attempt,
22
+ purpose: "active_checkout",
23
+ });
24
+ if (!reading.clientAction
25
+ || !actionMatchesRail(reading.clientAction, authority.executionRail, deps.railHandoffKinds)
26
+ || reading.manualReviewRequired
27
+ || !reading.identityMatches
28
+ || !reading.configuredMoneyMatches
29
+ || reading.status.status !== "pending")
30
+ return null;
31
+ const current = await deps.readPort.readVerifiableAttempt({
32
+ orderId: authority.orderId,
33
+ paymentIntentId: authority.paymentIntentId,
34
+ });
35
+ if (!sameCanonicalAttempt(initial, current) || !isLive(current))
36
+ return null;
37
+ return reading.clientAction;
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ },
43
+ };
44
+ }
45
+ function matchesAuthority(snapshot, authority) {
46
+ return Boolean(snapshot)
47
+ && snapshot?.orderId === authority.orderId
48
+ && snapshot.orderClientId === authority.clientId
49
+ && snapshot.paymentIntentId === authority.paymentIntentId
50
+ && snapshot.paymentAttemptId === authority.paymentAttemptId
51
+ && snapshot.provider === authority.executionRail;
52
+ }
53
+ function isLive(snapshot) {
54
+ return Boolean(snapshot)
55
+ && LIVE_INTENT_STATUSES.has(snapshot?.intentStatus ?? "")
56
+ && LIVE_ATTEMPT_STATUSES.has(snapshot?.attemptStatus ?? "");
57
+ }
58
+ function actionMatchesRail(action, rail, railHandoffKinds) {
59
+ return action.provider === rail && railHandoffKinds(rail).includes(action.kind);
60
+ }
61
+ function sameCanonicalAttempt(before, after) {
62
+ return Boolean(after)
63
+ && after?.orderId === before.orderId
64
+ && after.orderClientId === before.orderClientId
65
+ && after.paymentIntentId === before.paymentIntentId
66
+ && after.paymentAttemptId === before.paymentAttemptId
67
+ && after.paymentId === before.paymentId
68
+ && after.provider === before.provider
69
+ && after.providerAttemptId === before.providerAttemptId
70
+ && after.providerSessionId === before.providerSessionId
71
+ && after.intentProviderPaymentId === before.intentProviderPaymentId
72
+ && after.intentStatus === before.intentStatus
73
+ && after.attemptStatus === before.attemptStatus
74
+ && after.amountMinor === before.amountMinor
75
+ && after.currency.toUpperCase() === before.currency.toUpperCase()
76
+ && after.localUpdatedAt === before.localUpdatedAt;
77
+ }
@@ -0,0 +1,8 @@
1
+ import type { CheckoutRecoveryPaymentResolver, PaymentProviderRecoveryProvider } from "./contracts/repair.js";
2
+ import type { PaymentVerifyReadPort, PaymentProviderReconciliationPort } from "./contracts/reconciliation.js";
3
+ export declare function createCheckoutRecoveryPaymentResolver(deps: {
4
+ readPort: PaymentVerifyReadPort;
5
+ applyPort: Pick<PaymentProviderReconciliationPort, "applyTerminalResult">;
6
+ providers: Partial<Record<string, PaymentProviderRecoveryProvider>>;
7
+ now?: () => Date;
8
+ }): CheckoutRecoveryPaymentResolver;
@@ -0,0 +1,87 @@
1
+ import { terminalAmountMismatch } from "./paymentProviderReconciliationEvidence.js";
2
+ import { toClaimedAttemptShape, verifyPaymentAttemptNow } from "./paymentVerifyNowService.js";
3
+ const LIVE_ATTEMPT_STATUSES = new Set(["sent_to_provider", "requires_action", "processing", "created"]);
4
+ export function createCheckoutRecoveryPaymentResolver(deps) {
5
+ const now = deps.now ?? (() => new Date());
6
+ return {
7
+ async resolve(input) {
8
+ if (!input.paymentIntentId)
9
+ return { kind: "retry_new" };
10
+ const snapshot = await deps.readPort.readVerifiableAttempt({
11
+ orderId: input.orderId,
12
+ paymentIntentId: input.paymentIntentId,
13
+ });
14
+ if (!snapshot) {
15
+ return input.intentStatus === "created" || input.intentStatus === "failed"
16
+ ? { kind: "retry_new" }
17
+ : { kind: "awaiting_provider" };
18
+ }
19
+ return resolveSnapshot(snapshot, deps, now);
20
+ },
21
+ };
22
+ }
23
+ async function resolveSnapshot(snapshot, deps, now) {
24
+ if (snapshot.attemptStatus === "succeeded" || snapshot.intentStatus === "succeeded") {
25
+ return { kind: "paid" };
26
+ }
27
+ if (snapshot.attemptStatus === "failed" || snapshot.intentStatus === "failed") {
28
+ return { kind: "retry_new" };
29
+ }
30
+ if (!LIVE_ATTEMPT_STATUSES.has(snapshot.attemptStatus)) {
31
+ return { kind: "awaiting_provider" };
32
+ }
33
+ const provider = deps.providers[snapshot.provider];
34
+ const providerPaymentId = provider?.resolvePaymentReference(snapshot) ?? null;
35
+ if (!provider || !providerPaymentId)
36
+ return { kind: "awaiting_provider" };
37
+ const attempt = toClaimedAttemptShape(snapshot, providerPaymentId);
38
+ try {
39
+ // Every caller of this resolver is a buyer holding a recovery link open, so
40
+ // an intent still waiting for its first payment method is one they can be
41
+ // handed back — not one to close under them and replace.
42
+ const recovery = await provider.readRecoveryPayment({
43
+ providerPaymentId,
44
+ attempt,
45
+ purpose: "active_checkout",
46
+ });
47
+ if (recovery.manualReviewRequired
48
+ || !recovery.identityMatches
49
+ || !recovery.configuredMoneyMatches) {
50
+ return { kind: "manual_review" };
51
+ }
52
+ if (recovery.clientAction) {
53
+ return { kind: "resume_existing", clientAction: recovery.clientAction };
54
+ }
55
+ if (recovery.status.status === "pending" || recovery.status.status === "unknown") {
56
+ return { kind: "awaiting_provider" };
57
+ }
58
+ if (terminalAmountMismatch(attempt, recovery.status)) {
59
+ return { kind: "manual_review" };
60
+ }
61
+ const verified = await verifyPaymentAttemptNow({
62
+ snapshot,
63
+ applyPort: deps.applyPort,
64
+ providers: deps.providers,
65
+ providerPaymentId,
66
+ providerStatus: recovery.status,
67
+ now,
68
+ });
69
+ if (verified.status !== "succeeded" && verified.status !== "failed") {
70
+ return { kind: "awaiting_provider" };
71
+ }
72
+ const current = await deps.readPort.readVerifiableAttempt({
73
+ orderId: snapshot.orderId,
74
+ paymentIntentId: snapshot.paymentIntentId,
75
+ });
76
+ if (current?.attemptStatus === "succeeded" || current?.intentStatus === "succeeded") {
77
+ return { kind: "paid" };
78
+ }
79
+ if (current?.attemptStatus === "failed" || current?.intentStatus === "failed") {
80
+ return { kind: "retry_new" };
81
+ }
82
+ return verified.status === "succeeded" ? { kind: "paid" } : { kind: "retry_new" };
83
+ }
84
+ catch {
85
+ return { kind: "awaiting_provider" };
86
+ }
87
+ }
@@ -0,0 +1,113 @@
1
+ import type { PaymentExecutionAttemptStatus, PaymentFailureClass, PaymentFailureHint, PaymentProviderCapabilityDescriptor, PaymentRetryAdviceCode, StoredMandateSnapshot } from "@openlup/core/payment";
2
+ import type { PaymentAbsencePort, PaymentReadbackPort, PaymentVerifyNormalizePort } from "./evidence.js";
3
+ declare const transientSecret: unique symbol;
4
+ /**
5
+ * One-time customer authorization or opaque client handoff, held only in memory.
6
+ * Never persist, log, fingerprint, or include in request/response diagnostics.
7
+ * The host brands a value only at the transient client/server input boundary.
8
+ */
9
+ export type TransientSecret = string & {
10
+ readonly [transientSecret]: true;
11
+ };
12
+ /** Hosted navigation or client confirmation; opaque payloads are transient only. */
13
+ export type PaymentMethodHandoff = {
14
+ kind: "redirect";
15
+ url: string;
16
+ } | {
17
+ kind: "client-confirmed";
18
+ payload: TransientSecret;
19
+ };
20
+ /** Only core neutral taxonomy crosses the adapter boundary; no provider prose. */
21
+ export interface PaymentRefusalEnvelope {
22
+ code: PaymentFailureClass;
23
+ hints: readonly PaymentFailureHint[];
24
+ adviceCode?: PaymentRetryAdviceCode;
25
+ }
26
+ /**
27
+ * A non-terminal attempt or synchronous decline; terminal money is evidence-owned.
28
+ * Diagnostics must exclude transient secrets, handoff payloads, raw bodies and
29
+ * provider prose. Persist only explicitly redacted request/response diagnostics.
30
+ */
31
+ export interface PaymentExecutionEnvelope {
32
+ outcome: {
33
+ kind: "attempt";
34
+ status: PaymentExecutionAttemptStatus;
35
+ } | {
36
+ kind: "decline";
37
+ refusal: PaymentRefusalEnvelope;
38
+ };
39
+ dispatch: {
40
+ kind: "dispatched";
41
+ providerPaymentRef: string;
42
+ } | {
43
+ kind: "notDispatched";
44
+ evidence: {
45
+ exact: true;
46
+ phase: "before-dispatch";
47
+ reason: PaymentRefusalEnvelope;
48
+ };
49
+ } | {
50
+ kind: "unknown";
51
+ };
52
+ handoff?: PaymentMethodHandoff;
53
+ diagnostics: Readonly<Record<string, string | number | boolean | null>>;
54
+ }
55
+ /** Host identity/key/fingerprint and configured integer-minor money pass verbatim.
56
+ * Missing adapter-required input must refuse before dispatch with exact
57
+ * notDispatched evidence (phase before-dispatch), never unknown or dispatched.
58
+ */
59
+ export interface PaymentAttemptPort {
60
+ validateInput(input: {
61
+ attemptRef: string;
62
+ intentRef: string;
63
+ fingerprint: string;
64
+ providerIdempotencyKey: string;
65
+ money: {
66
+ amountMinor: number;
67
+ currency: string;
68
+ };
69
+ mode: "live" | "test";
70
+ purpose: "initial" | "renewal-unattended" | "recovery";
71
+ methodSelection?: {
72
+ family: "card" | "wallet" | "bank-redirect" | "one-time-code";
73
+ channelRef?: string;
74
+ };
75
+ /** Transient dispatch input only; never persist, audit, log or diagnose. */
76
+ payer?: {
77
+ email: string;
78
+ name?: string;
79
+ };
80
+ storedMethod?: {
81
+ reference: string;
82
+ mandate: StoredMandateSnapshot;
83
+ };
84
+ /** Client-entered, server-submitted authorization; never persisted or echoed. */
85
+ customerAuthorization?: TransientSecret;
86
+ }): void;
87
+ execute(input: Parameters<PaymentAttemptPort["validateInput"]>[0]): Promise<PaymentExecutionEnvelope>;
88
+ }
89
+ /** Platform overlay; the shared core descriptor remains unchanged. */
90
+ export interface PaymentAdapterCapabilities extends Omit<PaymentProviderCapabilityDescriptor, "captureFlows"> {
91
+ captureFlows: readonly {
92
+ kind: string;
93
+ handoff: PaymentMethodHandoff["kind"] | "customer-authorization";
94
+ methodFamilies: readonly ("card" | "wallet" | "bank-redirect" | "one-time-code")[];
95
+ }[];
96
+ supportedCurrencies: readonly string[];
97
+ unattended: "supported" | "unsupported";
98
+ readback: "supported" | "unsupported";
99
+ close: "supported" | "unsupported";
100
+ exactAbsence: "supported" | "unsupported";
101
+ refundObservation: "supported" | "unsupported";
102
+ refundCreate: "unsupported";
103
+ authorizationCaptureSplit: "unsupported";
104
+ }
105
+ /** The neutral bundle an adapter factory returns; optional ports match declared capabilities. */
106
+ export interface PaymentAdapter {
107
+ capabilities: PaymentAdapterCapabilities;
108
+ attemptPort: PaymentAttemptPort;
109
+ verifyPort: PaymentVerifyNormalizePort;
110
+ readbackPort: PaymentReadbackPort;
111
+ absencePort?: PaymentAbsencePort;
112
+ }
113
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,155 @@
1
+ import type { PaymentAdapter, PaymentAttemptPort, PaymentExecutionEnvelope } from "./adapter.js";
2
+ import type { PaymentAbsenceEnvelope, PaymentAbsencePort, PaymentReadbackEnvelope, PaymentReadbackPort } from "./evidence.js";
3
+ /** A fixture binds its own identity, adapter ports and inputs; scenarios accept multiple subjects. */
4
+ export interface PaymentAdapterConformanceSubject {
5
+ subjectId: string;
6
+ adapter: PaymentAdapter;
7
+ executionInput: Parameters<PaymentAttemptPort["execute"]>[0];
8
+ readbackInput: Parameters<PaymentReadbackPort["readPayment"]>[0];
9
+ /** Required when the adapter supplies an absence port. */
10
+ absenceInput?: Parameters<PaymentAbsencePort["proveAbsence"]>[0];
11
+ }
12
+ /** Runner-independent observations; never include transient input or raw diagnostics. */
13
+ export interface PaymentAdapterConformanceEvidence {
14
+ subjects: readonly {
15
+ subjectId: string;
16
+ execution: Omit<PaymentExecutionEnvelope, "handoff">;
17
+ readback: PaymentReadbackEnvelope & {
18
+ handoff?: never;
19
+ };
20
+ absence?: PaymentAbsenceEnvelope;
21
+ }[];
22
+ cases: readonly {
23
+ subjectIds: readonly string[];
24
+ name: string;
25
+ passed: boolean;
26
+ }[];
27
+ }
28
+ import type { PaymentExecutionBaseInput, PaymentExecutionContractResult } from "@openlup/core/testing";
29
+ export type ExecutionCapability = {
30
+ readonly name: string;
31
+ readonly durabilityClaim: false;
32
+ };
33
+ export type SimulatorResult = PaymentExecutionContractResult & {
34
+ providerDecline?: {
35
+ code?: string;
36
+ mandateUnsupported?: boolean;
37
+ } | null;
38
+ };
39
+ export type ExecutionSubject<TInput extends PaymentExecutionBaseInput, TResult extends SimulatorResult> = {
40
+ readonly execute: (request: TInput) => Promise<TResult>;
41
+ };
42
+ /**
43
+ * The expected provider identity is a property of the adapter under proof, not of
44
+ * this contract. The collector that constructs the subject owns that literal, so a
45
+ * second runtime bundle proves the same behaviour under its own provider identity
46
+ * and this contract names no provider at all.
47
+ */
48
+ export type ExecutionProviderIdentity = {
49
+ readonly expectedProvider: string;
50
+ };
51
+ export type ExecutionEvidence = {
52
+ readonly capability: ExecutionCapability;
53
+ readonly executions: number;
54
+ readonly providerCalls: number;
55
+ readonly capturedEffects: number;
56
+ readonly permanentRefusals: number;
57
+ };
58
+ export type AggregateKey = "outOfOrder" | "lateSuccess";
59
+ export type ResultStatus = "succeeded" | "failed";
60
+ export type DurableEventCounts = {
61
+ clients: number;
62
+ orders: number;
63
+ payments: number;
64
+ intents: number;
65
+ attempts: number;
66
+ events: number;
67
+ transitions: number;
68
+ idempotencyKeys: number;
69
+ outboxEvents: number;
70
+ };
71
+ export type DurableEventAggregate = {
72
+ orderId: string;
73
+ paymentId: string;
74
+ paymentIntentId: string;
75
+ paymentAttemptId: string;
76
+ orderStatus: string;
77
+ paymentStatus: string;
78
+ intentStatus: string;
79
+ attemptStatus: string;
80
+ };
81
+ /** Fixture cardinality that stays constant for the whole run. */
82
+ export type DurableEventFixtureCardinality = Pick<DurableEventCounts, "clients" | "orders" | "payments" | "intents" | "attempts">;
83
+ /** Durable writes the adapter emits per step. */
84
+ export type DurableEventWriteCardinality = Pick<DurableEventCounts, "events" | "transitions" | "idempotencyKeys" | "outboxEvents">;
85
+ /**
86
+ * Exact write cardinality is adapter-owned, not part of the portable contract:
87
+ * how many transitions, idempotency keys, and outbox rows one payment event
88
+ * produces is a property of the writer and outbox fan-out under proof, and a
89
+ * second runtime bundle emits its own. The behavioural assertions below (no
90
+ * second canonical event, no regression after a stale failure, convergence on
91
+ * late success) are the portable part; the collector that owns the adapter
92
+ * injects its own numbers so they are still asserted at the exact same step.
93
+ */
94
+ export type DurableEventCardinalityExpectations = {
95
+ readonly fixture: DurableEventFixtureCardinality;
96
+ readonly baseline: DurableEventWriteCardinality;
97
+ readonly afterOutOfOrderSuccess: DurableEventWriteCardinality;
98
+ readonly afterOutOfOrderFailure: DurableEventWriteCardinality;
99
+ readonly afterDuplicate: DurableEventWriteCardinality;
100
+ readonly afterLateFailure: DurableEventWriteCardinality;
101
+ readonly final: DurableEventWriteCardinality;
102
+ };
103
+ export type DurableEventSnapshot = {
104
+ counts: DurableEventCounts;
105
+ aggregates: Record<AggregateKey, DurableEventAggregate>;
106
+ events: Array<{
107
+ id: string;
108
+ eventKey: string;
109
+ paymentIntentId: string;
110
+ paymentAttemptId: string;
111
+ processingStatus: string;
112
+ }>;
113
+ };
114
+ export type EventReceipt = {
115
+ paymentEventId: string;
116
+ replayed: boolean;
117
+ };
118
+ export type DurableEventCapability = {
119
+ readonly name: string;
120
+ readonly durabilityClaim: true;
121
+ assertSafe(): void;
122
+ reset(): Promise<{
123
+ residualRows: number;
124
+ }>;
125
+ seed(): Promise<void>;
126
+ snapshot(): Promise<DurableEventSnapshot>;
127
+ ingest(input: {
128
+ aggregate: AggregateKey;
129
+ eventKey: string;
130
+ resultStatus: ResultStatus;
131
+ occurredAt: string;
132
+ }): Promise<EventReceipt>;
133
+ apply(input: {
134
+ aggregate: AggregateKey;
135
+ paymentEventId: string;
136
+ eventKey: string;
137
+ resultStatus: ResultStatus;
138
+ occurredAt: string;
139
+ }): Promise<{
140
+ replayed: boolean;
141
+ }>;
142
+ };
143
+ export type DurableEventEvidence = {
144
+ capability: {
145
+ name: string;
146
+ durabilityClaim: true;
147
+ };
148
+ baseline: DurableEventSnapshot;
149
+ afterOutOfOrderSuccess: DurableEventSnapshot;
150
+ afterOutOfOrderFailure: DurableEventSnapshot;
151
+ afterDuplicate: DurableEventSnapshot;
152
+ afterLateFailure: DurableEventSnapshot;
153
+ final: DurableEventSnapshot;
154
+ cleanupResidualRows: 0;
155
+ };