@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,185 @@
1
+ import { buildTpayTransactionPayload, } from "./tpayTransactionPayload.js";
2
+ import { tpayTransactionDispatchBoundary } from "./tpayDispatchFailure.js";
3
+ import { readTpayHttpFailure, TpayHttpError } from "./tpayHttpFailure.js";
4
+ export { TpayHttpError } from "./tpayHttpFailure.js";
5
+ const TOKEN_REFRESH_SKEW_MS = 60_000;
6
+ const DEFAULT_TPAY_TIMEOUT_MS = 10_000;
7
+ export function createTpayHttpClient({ baseUrl, clientId, clientSecret, timeoutMs = DEFAULT_TPAY_TIMEOUT_MS, fetchImpl = globalThis.fetch, now = () => Date.now(), }) {
8
+ let token = null;
9
+ const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
10
+ function requestDeadline() {
11
+ return { expiresAtMs: Date.now() + timeoutMs };
12
+ }
13
+ async function bearer(deadline) {
14
+ if (token && token.expiresAtMs - TOKEN_REFRESH_SKEW_MS > now()) {
15
+ return token.accessToken;
16
+ }
17
+ const body = new URLSearchParams({ client_id: clientId, client_secret: clientSecret });
18
+ const response = await fetchWithTimeout(fetchImpl, `${normalizedBaseUrl}/oauth/auth`, {
19
+ method: "POST",
20
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
21
+ body: body.toString(),
22
+ }, remainingTimeoutMs(deadline, "tpay_oauth_timeout"), "tpay_oauth_timeout");
23
+ const json = await readJson(response, "tpay_oauth_failed");
24
+ const accessToken = readString(json, "access_token");
25
+ const expiresIn = readNumber(json, "expires_in");
26
+ token = { accessToken, expiresAtMs: now() + expiresIn * 1000 };
27
+ return accessToken;
28
+ }
29
+ async function request(path, init = {}, deadline = requestDeadline()) {
30
+ const headers = { Authorization: `Bearer ${await bearer(deadline)}` };
31
+ let body;
32
+ if (init.body !== undefined) {
33
+ headers["Content-Type"] = "application/json";
34
+ body = JSON.stringify(init.body);
35
+ }
36
+ const response = await fetchWithTimeout(fetchImpl, `${normalizedBaseUrl}${path}`, {
37
+ method: init.method ?? "GET",
38
+ headers,
39
+ body,
40
+ }, remainingTimeoutMs(deadline, "tpay_request_timeout"), "tpay_request_timeout");
41
+ return readJson(response, "tpay_request_failed");
42
+ }
43
+ return {
44
+ async createTransaction(input) {
45
+ const deadline = requestDeadline();
46
+ return tpayTransactionDispatchBoundary({
47
+ authenticate: () => bearer(deadline),
48
+ prepare: (accessToken) => ({
49
+ headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json" },
50
+ body: JSON.stringify(buildTpayTransactionPayload(input)),
51
+ timeoutMs: remainingTimeoutMs(deadline, "tpay_request_deadline_exhausted"),
52
+ }),
53
+ dispatch: ({ headers, body, timeoutMs }) => fetchWithTimeout(fetchImpl, `${normalizedBaseUrl}/transactions`, { method: "POST", headers, body }, timeoutMs, "tpay_request_timeout"),
54
+ decode: async (response) => {
55
+ const json = await readJson(response, "tpay_request_failed");
56
+ const payments = asRecord(json.payments);
57
+ return {
58
+ transactionId: readString(json, "transactionId"),
59
+ title: readString(json, "title"),
60
+ status: readString(json, "status"),
61
+ transactionPaymentUrl: readNullableString(json, "transactionPaymentUrl"),
62
+ requestId: readNullableString(json, "requestId"),
63
+ payIdEligible: typeof payments.payIdEligible === "boolean" ? payments.payIdEligible : null,
64
+ errors: readPaymentErrors(payments.errors),
65
+ };
66
+ },
67
+ });
68
+ },
69
+ async getTransaction(transactionId) {
70
+ const json = await request(`/transactions/${encodeURIComponent(transactionId)}`, {}, requestDeadline());
71
+ return {
72
+ // Keep provider fields that recovery normalizes later (notably nested
73
+ // dates and paidAmount). Explicit canonical fields below remain the
74
+ // typed client contract.
75
+ ...json,
76
+ transactionId: readString(json, "transactionId"),
77
+ title: readNullableString(json, "title"),
78
+ status: readString(json, "status"),
79
+ transactionPaymentUrl: readNullableString(json, "transactionPaymentUrl"),
80
+ amount: readNullableTransactionAmount(json, "amount"),
81
+ currency: readNullableString(json, "currency"),
82
+ requestId: readNullableString(json, "requestId"),
83
+ payments: asRecord(json.payments),
84
+ };
85
+ },
86
+ async listPaymentChannels() {
87
+ const json = await request("/transactions/channels", {}, requestDeadline());
88
+ const channels = Array.isArray(json.channels)
89
+ ? json.channels
90
+ : [];
91
+ return channels.map(mapChannel);
92
+ },
93
+ };
94
+ }
95
+ function remainingTimeoutMs(deadline, timeoutCode) {
96
+ const remaining = deadline.expiresAtMs - Date.now();
97
+ if (remaining <= 0)
98
+ throw new TpayHttpError(timeoutCode, 504);
99
+ return remaining;
100
+ }
101
+ async function fetchWithTimeout(fetchImpl, url, init, timeoutMs, timeoutCode) {
102
+ const controller = new AbortController();
103
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
104
+ try {
105
+ return await fetchImpl(url, { ...init, signal: controller.signal });
106
+ }
107
+ catch (error) {
108
+ if (controller.signal.aborted) {
109
+ throw new TpayHttpError(timeoutCode, 504);
110
+ }
111
+ throw error;
112
+ }
113
+ finally {
114
+ clearTimeout(timeout);
115
+ }
116
+ }
117
+ function asRecord(value) {
118
+ return value && typeof value === "object" ? value : {};
119
+ }
120
+ function readPaymentErrors(value) {
121
+ if (!Array.isArray(value))
122
+ return [];
123
+ return value.map((entry) => {
124
+ const record = asRecord(entry);
125
+ return {
126
+ errorCode: String(record.errorCode ?? ""),
127
+ errorMessage: String(record.errorMessage ?? ""),
128
+ fieldName: typeof record.fieldName === "string" ? record.fieldName : null,
129
+ };
130
+ });
131
+ }
132
+ async function readJson(response, code) {
133
+ if (!response.ok) {
134
+ const failure = await readTpayHttpFailure(response);
135
+ throw new TpayHttpError(code, response.status, failure.diagnostic, failure.refusedBeforeTransaction);
136
+ }
137
+ const json = await response.json();
138
+ if (!json || typeof json !== "object")
139
+ throw new TpayHttpError("tpay_invalid_response", response.status);
140
+ return json;
141
+ }
142
+ function mapChannel(value) {
143
+ const record = value && typeof value === "object" ? value : {};
144
+ return {
145
+ id: String(record.id ?? ""),
146
+ name: String(record.name ?? ""),
147
+ fullName: String(record.fullName ?? record.name ?? ""),
148
+ available: record.available === true,
149
+ onlinePayment: record.onlinePayment === true,
150
+ instantRedirection: record.instantRedirection === true,
151
+ groups: Array.isArray(record.groups) ? record.groups.map(mapGroup) : [],
152
+ };
153
+ }
154
+ function mapGroup(value) {
155
+ const record = value && typeof value === "object" ? value : {};
156
+ return { id: Number(record.id ?? 0), name: String(record.name ?? "") };
157
+ }
158
+ function readString(value, key) {
159
+ const raw = value[key];
160
+ if (typeof raw !== "string" || raw.length === 0)
161
+ throw new TpayHttpError("tpay_invalid_response", 200);
162
+ return raw;
163
+ }
164
+ function readNullableString(value, key) {
165
+ const raw = value[key];
166
+ return typeof raw === "string" && raw.length > 0 ? raw : null;
167
+ }
168
+ function readNumber(value, key) {
169
+ const raw = value[key];
170
+ if (typeof raw !== "number" || !Number.isFinite(raw))
171
+ throw new TpayHttpError("tpay_invalid_response", 200);
172
+ return raw;
173
+ }
174
+ function readNullableTransactionAmount(value, key) {
175
+ const raw = value[key];
176
+ if (typeof raw === "number")
177
+ return Number.isFinite(raw) ? raw : null;
178
+ if (typeof raw !== "string")
179
+ return null;
180
+ const trimmed = raw.trim();
181
+ if (!/^\d+(?:\.\d+)?$/.test(trimmed))
182
+ return null;
183
+ const parsed = Number(trimmed);
184
+ return Number.isFinite(parsed) ? parsed : null;
185
+ }
@@ -0,0 +1,57 @@
1
+ export interface TpayHttpFailureDiagnostic {
2
+ httpStatus: number;
3
+ requestId: string | null;
4
+ providerErrorCodes: string[];
5
+ fieldNames: string[];
6
+ }
7
+ /**
8
+ * The provider answered, and its answer is read for two independent things: the
9
+ * sanitized diagnostic that may be logged, and whether the refusal PROVES no
10
+ * transaction was created.
11
+ */
12
+ export interface TpayHttpFailure {
13
+ diagnostic: TpayHttpFailureDiagnostic;
14
+ /**
15
+ * Tpay rejected the request document itself, so no transaction row can exist.
16
+ * `false` is the fail-closed answer and the only one any ambiguity produces.
17
+ */
18
+ refusedBeforeTransaction: boolean;
19
+ }
20
+ /**
21
+ * Tpay error codes that describe the REQUEST DOCUMENT — a missing field, a wrong
22
+ * type, an out-of-range or malformed value, an unknown field, an unparseable
23
+ * body, a wrong content type. Every one of them is decided by request validation
24
+ * and therefore cannot be produced once a transaction row exists.
25
+ *
26
+ * Deliberately excluded, and each for a reason: `crc_not_unique` names an
27
+ * ALREADY EXISTING transaction; `transaction_lock`, `transaction_blocked`,
28
+ * `payment_failed` and `ts:transaction:*` describe a transaction's outcome or a
29
+ * partially completed insert; `cannot_create_transaction`,
30
+ * `partner_cannot_create_transaction` and every channel/merchant availability
31
+ * code refuse for reasons whose ordering against creation we cannot prove from
32
+ * here; `general` and `internal_server_error` are opaque. A refusal carrying any
33
+ * of them keeps today's behavior and defers to reconciliation.
34
+ *
35
+ * ⚠️ This list is matched against the RAW body, never against
36
+ * `TpayHttpFailureDiagnostic.providerErrorCodes` — that projection drops any code
37
+ * outside the loggable set, which would turn a mixed body into a uniformly safe
38
+ * one.
39
+ */
40
+ export declare const TPAY_PRE_TRANSACTION_REFUSAL_CODES: ReadonlySet<string>;
41
+ export declare function readTpayHttpFailure(response: {
42
+ status: number;
43
+ text(): Promise<string>;
44
+ }): Promise<TpayHttpFailure>;
45
+ export declare function tpayHttpFailureDiagnostic(error: unknown): TpayHttpFailureDiagnostic | null;
46
+ export declare class TpayHttpError extends Error {
47
+ readonly code: string;
48
+ readonly status: number;
49
+ readonly failureDiagnostic: TpayHttpFailureDiagnostic | null;
50
+ /**
51
+ * Set only from a body this client actually parsed. It never crosses a
52
+ * boundary as a claim on its own — the dispatch boundary turns it into typed
53
+ * evidence, and the control-plane RPC re-proves the attempt independently.
54
+ */
55
+ readonly refusedBeforeTransaction: boolean;
56
+ constructor(code: string, status: number, failureDiagnostic?: TpayHttpFailureDiagnostic | null, refusedBeforeTransaction?: boolean);
57
+ }
@@ -0,0 +1,143 @@
1
+ import { loggableProviderErrorCode, loggableProviderFieldName, loggableProviderRequestId, } from "./providerAttemptFailureDiagnostic.js";
2
+ /**
3
+ * Tpay error codes that describe the REQUEST DOCUMENT — a missing field, a wrong
4
+ * type, an out-of-range or malformed value, an unknown field, an unparseable
5
+ * body, a wrong content type. Every one of them is decided by request validation
6
+ * and therefore cannot be produced once a transaction row exists.
7
+ *
8
+ * Deliberately excluded, and each for a reason: `crc_not_unique` names an
9
+ * ALREADY EXISTING transaction; `transaction_lock`, `transaction_blocked`,
10
+ * `payment_failed` and `ts:transaction:*` describe a transaction's outcome or a
11
+ * partially completed insert; `cannot_create_transaction`,
12
+ * `partner_cannot_create_transaction` and every channel/merchant availability
13
+ * code refuse for reasons whose ordering against creation we cannot prove from
14
+ * here; `general` and `internal_server_error` are opaque. A refusal carrying any
15
+ * of them keeps today's behavior and defers to reconciliation.
16
+ *
17
+ * ⚠️ This list is matched against the RAW body, never against
18
+ * `TpayHttpFailureDiagnostic.providerErrorCodes` — that projection drops any code
19
+ * outside the loggable set, which would turn a mixed body into a uniformly safe
20
+ * one.
21
+ */
22
+ export const TPAY_PRE_TRANSACTION_REFUSAL_CODES = new Set([
23
+ "country_not_valid",
24
+ "field_required",
25
+ "incorrect_content_type",
26
+ "invalid_request_body",
27
+ "is_required",
28
+ "not_array",
29
+ "not_natural_int",
30
+ "not_string",
31
+ "not_valid",
32
+ "too_low",
33
+ "ts:country:not_valid",
34
+ "ts:payer:phone:not_valid",
35
+ "unexpected_field",
36
+ ]);
37
+ /** The one HTTP status on which Tpay reports request validation. */
38
+ const TPAY_REQUEST_VALIDATION_STATUS = 400;
39
+ const MAX_FAILURE_BODY_BYTES = 16_384;
40
+ const MAX_DIAGNOSTIC_ITEMS = 5;
41
+ export async function readTpayHttpFailure(response) {
42
+ const base = emptyDiagnostic(response.status);
43
+ try {
44
+ const body = await response.text();
45
+ if (body.length > MAX_FAILURE_BODY_BYTES)
46
+ return unreadableFailure(base);
47
+ const parsed = JSON.parse(body);
48
+ const root = asRecord(parsed);
49
+ const payment = asRecord(root.payments);
50
+ const errors = [...readArray(root.errors), ...readArray(payment.errors)];
51
+ const rawErrorCodes = errors.map((entry) => asRecord(entry).errorCode);
52
+ return {
53
+ diagnostic: {
54
+ ...base,
55
+ requestId: loggableProviderRequestId(root.requestId) ? root.requestId : null,
56
+ providerErrorCodes: allowedValues(errors.map((entry) => asRecord(entry).errorCode), loggableProviderErrorCode),
57
+ fieldNames: allowedValues(errors.map((entry) => asRecord(entry).fieldName), loggableProviderFieldName),
58
+ },
59
+ refusedBeforeTransaction: refusedBeforeTransaction(response.status, rawErrorCodes),
60
+ };
61
+ }
62
+ catch {
63
+ return unreadableFailure(base);
64
+ }
65
+ }
66
+ /**
67
+ * Whether this answer proves Tpay created nothing.
68
+ *
69
+ * Three conditions, all required. The status must be exactly the validation
70
+ * status: a 409 may name an existing transaction, a 429 or any 5xx may follow
71
+ * one that was created before the response was lost. The body must have yielded
72
+ * at least one error code, so an opaque refusal from an edge proxy — which we
73
+ * cannot attribute to Tpay's validator — releases nothing. And EVERY raw code
74
+ * must be allow-listed, including codes this repository does not otherwise
75
+ * recognize, so one unknown code in a mixed body is enough to refuse.
76
+ */
77
+ function refusedBeforeTransaction(status, rawErrorCodes) {
78
+ return status === TPAY_REQUEST_VALIDATION_STATUS
79
+ && rawErrorCodes.length > 0
80
+ && rawErrorCodes.every((code) => typeof code === "string" && TPAY_PRE_TRANSACTION_REFUSAL_CODES.has(code));
81
+ }
82
+ function unreadableFailure(diagnostic) {
83
+ return { diagnostic, refusedBeforeTransaction: false };
84
+ }
85
+ export function tpayHttpFailureDiagnostic(error) {
86
+ if (!error || typeof error !== "object")
87
+ return null;
88
+ const value = asRecord(error.failureDiagnostic);
89
+ const httpStatus = value.httpStatus;
90
+ const requestId = value.requestId;
91
+ const providerErrorCodes = value.providerErrorCodes;
92
+ const fieldNames = value.fieldNames;
93
+ if (!Number.isInteger(httpStatus) || httpStatus < 100 || httpStatus > 599)
94
+ return null;
95
+ if (requestId !== null && !loggableProviderRequestId(requestId))
96
+ return null;
97
+ if (!validAllowedValues(providerErrorCodes, loggableProviderErrorCode)
98
+ || !validAllowedValues(fieldNames, loggableProviderFieldName))
99
+ return null;
100
+ return {
101
+ httpStatus: httpStatus,
102
+ requestId: requestId,
103
+ providerErrorCodes: [...providerErrorCodes],
104
+ fieldNames: [...fieldNames],
105
+ };
106
+ }
107
+ export class TpayHttpError extends Error {
108
+ code;
109
+ status;
110
+ failureDiagnostic;
111
+ /**
112
+ * Set only from a body this client actually parsed. It never crosses a
113
+ * boundary as a claim on its own — the dispatch boundary turns it into typed
114
+ * evidence, and the control-plane RPC re-proves the attempt independently.
115
+ */
116
+ refusedBeforeTransaction;
117
+ constructor(code, status, failureDiagnostic = null, refusedBeforeTransaction = false) {
118
+ super(code);
119
+ this.name = "TpayHttpError";
120
+ this.code = code;
121
+ this.status = status;
122
+ this.failureDiagnostic = failureDiagnostic;
123
+ this.refusedBeforeTransaction = refusedBeforeTransaction;
124
+ }
125
+ }
126
+ function emptyDiagnostic(httpStatus) {
127
+ return { httpStatus, requestId: null, providerErrorCodes: [], fieldNames: [] };
128
+ }
129
+ function asRecord(value) {
130
+ return value && typeof value === "object" && !Array.isArray(value)
131
+ ? value
132
+ : {};
133
+ }
134
+ function readArray(value) {
135
+ return Array.isArray(value) ? value : [];
136
+ }
137
+ function allowedValues(values, allowed) {
138
+ return [...new Set(values.filter(allowed))].slice(0, MAX_DIAGNOSTIC_ITEMS);
139
+ }
140
+ function validAllowedValues(value, allowed) {
141
+ return Array.isArray(value) && value.length <= MAX_DIAGNOSTIC_ITEMS
142
+ && value.every(allowed);
143
+ }
@@ -0,0 +1,20 @@
1
+ import type { PaymentExecutionPort } from "./donorContracts.js";
2
+ import type { PaymentExecutionInput } from "./donorContracts.js";
3
+ import type { TpayHttpClient, TpayPayerInput } from "./tpayHttpClient.js";
4
+ /** The one place this adapter spells its own provider identity. */
5
+ export declare const PROVIDER_KIND: "tpay";
6
+ export interface TpayPaymentExecutionAdapterOptions {
7
+ client: TpayHttpClient;
8
+ notificationUrl: string;
9
+ successUrl: string;
10
+ errorUrl: string;
11
+ oneClickEnabled?: boolean;
12
+ aliasRegistrationOnCodeEnabled?: boolean;
13
+ /** One public switch for admitting new subscription BLIK Model O mandates. */
14
+ modelOActivationEnabled?: boolean;
15
+ resolvePayer?: (input: PaymentExecutionInput) => TpayPayerInput | null;
16
+ }
17
+ export declare function createTpayPaymentExecutionAdapter({ client, notificationUrl, successUrl, errorUrl, oneClickEnabled, aliasRegistrationOnCodeEnabled, modelOActivationEnabled, resolvePayer, }: TpayPaymentExecutionAdapterOptions): PaymentExecutionPort;
18
+ export declare class TpayExecutionInputError extends Error {
19
+ constructor(message: string);
20
+ }
@@ -0,0 +1,249 @@
1
+ import { failureEvidencePayload } from "./paymentFailureEvidence.js";
2
+ import { tpayFailureEvidence } from "./tpayFailureEvidence.js";
3
+ import { aliasValue, buildCreateTransactionInput, resolveRecurringModel, } from "./tpayCreateTransactionInput.js";
4
+ import { declineCodeReading } from "./declineFailureHints.js";
5
+ import { assertableHints, isMandateRefusal, mandateCapabilityReadable, readAttemptDeclineObservation, declineEvidenceSource, states, } from "./tpayDeclineEvidence.js";
6
+ import { tpayTrustedPreDispatchFailure, tpayTrustedRefusalFailure, } from "./tpayDispatchFailure.js";
7
+ import { ProviderAttemptPreDispatchError } from "./preparedProviderAttempt.js";
8
+ /** The one place this adapter spells its own provider identity. */
9
+ export const PROVIDER_KIND = "tpay";
10
+ export function createTpayPaymentExecutionAdapter({ client, notificationUrl, successUrl, errorUrl, oneClickEnabled = false, aliasRegistrationOnCodeEnabled = false, modelOActivationEnabled = false, resolvePayer = defaultPayer, }) {
11
+ const validateInput = (input) => {
12
+ const transient = requireTpayTransientInput(input, {
13
+ oneClickEnabled,
14
+ modelOActivationEnabled,
15
+ });
16
+ if (input.currency !== "PLN")
17
+ throw new TpayExecutionInputError("tpay_currency_not_supported");
18
+ const payer = resolvePayer(input);
19
+ if (!payer)
20
+ throw new TpayExecutionInputError("tpay_payer_missing");
21
+ return { transient, payer };
22
+ };
23
+ return {
24
+ validateInput(input) {
25
+ validateInput(input);
26
+ },
27
+ async execute(input) {
28
+ const { transient, payer } = validateInput(input);
29
+ const request = buildCreateTransactionInput({
30
+ input,
31
+ transient,
32
+ payer,
33
+ notificationUrl,
34
+ successUrl,
35
+ errorUrl,
36
+ aliasRegistrationOnCodeEnabled,
37
+ modelOActivationEnabled,
38
+ });
39
+ let response;
40
+ try {
41
+ response = await client.createTransaction(request);
42
+ }
43
+ catch (error) {
44
+ // Two independent proofs Tpay holds no transaction: never asked, or it refused the request
45
+ // document. Both release the attempt; everything else stays ambiguous and rethrows.
46
+ const noCharge = tpayTrustedPreDispatchFailure(error) ?? tpayTrustedRefusalFailure(error);
47
+ if (noCharge)
48
+ throw new ProviderAttemptPreDispatchError(noCharge);
49
+ throw error;
50
+ }
51
+ const providerAttemptId = response.title || response.transactionId;
52
+ // This provider reports a synchronous decline ONLY here. `result`, `status`
53
+ // and `payments.status` all still read "success"/"pending" on a rejected
54
+ // transaction, so they cannot be used to detect one.
55
+ const rejections = response.errors ?? [];
56
+ const rejection = rejections[0] ?? null;
57
+ // The provider has carried a hard refusal code since the first minute, but
58
+ // only in the transaction's attempt log — never in the create response,
59
+ // whose codes are generic. So ask for it the moment the provider says no,
60
+ // instead of learning it hours later from the reconciliation poll.
61
+ // Fail-open: `null` means "read nothing", and every branch below then
62
+ // behaves exactly as it did before this read existed.
63
+ const observation = rejection
64
+ ? await readAttemptDeclineObservation(client, response.transactionId)
65
+ : null;
66
+ const attemptCode = observation?.code ?? null;
67
+ // A code the table cannot read decides nothing. Promoting a known-unknown
68
+ // such as `"100"` to a verdict would silence the message fallback for the
69
+ // one code we openly admit we cannot read — a regression, not a fix.
70
+ const attemptReading = attemptCode === null ? null : declineCodeReading(attemptCode);
71
+ const decidingAttemptReading = attemptReading !== null && states(attemptReading)
72
+ ? attemptReading
73
+ : null;
74
+ const mandateUnsupported = decidingAttemptReading
75
+ ? mandateCapabilityReadable(transient.flow)
76
+ && response.payIdEligible !== true
77
+ && (decidingAttemptReading.hints?.includes("mandateUnsupported") ?? false)
78
+ : rejection !== null && rejections.some((error) => isMandateRefusal(transient.flow, response.payIdEligible, error.errorMessage));
79
+ // Read here, where the code vocabulary is owned, so the control plane
80
+ // classifies the refusal without ever seeing a provider-native code. The
81
+ // attempt log wins when it says something, because it is the carrier the
82
+ // provider itself writes the refusal into; the create response's own code
83
+ // is the fallback reading.
84
+ // The advice half is suppressed when this adapter is already asserting a
85
+ // mandate refusal: advice outranks hints by design in the taxonomy, and
86
+ // the identity code is only the FIRST error, so a generic terminal code
87
+ // arriving ahead of the mandate explanation would otherwise mask the one
88
+ // reading that says the stored reference — not the instrument — is dead.
89
+ const reading = decidingAttemptReading ?? declineCodeReading(rejection?.errorCode);
90
+ const declineEvidence = rejection ? declineEvidenceSource({
91
+ attemptCode, decidingAttemptReading, mandateUnsupported, reading, errorCode: rejection.errorCode,
92
+ }) : null;
93
+ // A capability code is read as mandate evidence only while registering a
94
+ // mandate. The same opaque code on one-time or stored-mandate charges must
95
+ // not claim that a mandate is dead. The rule itself lives beside the
96
+ // refusal evidence it qualifies, because the reconciliation rail funnels
97
+ // its hints through the same one — a refusal must not classify by which
98
+ // rail saw it.
99
+ const neutralReasonHints = assertableHints(reading.hints, transient.flow);
100
+ const providerDecline = rejection
101
+ ? {
102
+ code: rejection.errorCode,
103
+ // Preserve the first provider code as the stable decline identity, but
104
+ // inspect every error for the capability signal. The provider may put a
105
+ // generic payment failure first and the mandate explanation later.
106
+ mandateUnsupported,
107
+ ...(reading.adviceCode && !mandateUnsupported ? { adviceCode: reading.adviceCode } : {}),
108
+ ...(neutralReasonHints?.length ? { neutralReasonHints } : {}),
109
+ }
110
+ : null;
111
+ return {
112
+ provider: PROVIDER_KIND,
113
+ providerAttemptId,
114
+ providerSessionId: response.transactionId,
115
+ // Stays non-terminal even on a decline: the control plane owns terminal
116
+ // transitions and reads `providerDecline` below to make one.
117
+ attemptStatus: "processing",
118
+ providerDecline,
119
+ nextActionKind: !providerDecline && transient.flow === "pbl_one_time" && response.transactionPaymentUrl
120
+ ? "redirect"
121
+ : null,
122
+ redirectUrl: providerDecline ? null : response.transactionPaymentUrl,
123
+ // A rejected activation must not publish a payment method reference.
124
+ paymentMethodRef: transient.flow === "blik_recurring_activation" && !providerDecline
125
+ ? aliasValue(input.paymentIntentId)
126
+ : null,
127
+ // A declined transaction produces no webhook at all: Tpay's `tr_status`
128
+ // only ever carries `true` or `chargeback`. Claiming otherwise would
129
+ // strand the attempt waiting for a callback that never arrives.
130
+ webhookExpected: !providerDecline,
131
+ recoveryRequired: false,
132
+ requestPayload: {
133
+ providerIdempotencyKey: input.providerIdempotencyKey,
134
+ providerRequestFingerprint: input.providerRequestFingerprint,
135
+ providerFlow: transient.flow,
136
+ amountMinor: input.amountMinor,
137
+ currency: input.currency,
138
+ orderRef: input.orderRef,
139
+ channelId: transient.flow === "pbl_one_time" ? transient.channelId : undefined,
140
+ // The model actually sent, not the one the client asked for — the single
141
+ // activation switch can make those diverge, and this field is where a
142
+ // diagnosis looks for the truth.
143
+ recurringModel: transient.flow === "blik_recurring_activation"
144
+ ? resolveRecurringModel(transient.recurringModel, modelOActivationEnabled)
145
+ : undefined,
146
+ methodRefPresent: transient.flow === "recurring_charge" || transient.flow === "blik_one_click"
147
+ ? Boolean(input.paymentMethodRef)
148
+ : undefined,
149
+ methodRefAliasType: transient.flow === "recurring_charge" || transient.flow === "blik_one_click"
150
+ ? input.paymentMethodAliasType ?? "PAYID"
151
+ : undefined,
152
+ aliasRegistrationRequested: transient.flow === "blik_one_time"
153
+ ? aliasRegistrationOnCodeEnabled
154
+ : undefined,
155
+ },
156
+ responsePayload: {
157
+ providerStatus: response.status,
158
+ providerAttemptId,
159
+ providerSessionId: response.transactionId,
160
+ requestId: response.requestId,
161
+ redirectUrlPresent: Boolean(response.transactionPaymentUrl),
162
+ payIdEligible: response.payIdEligible,
163
+ // Codes only. `errorMessage` is free-form prose that can carry
164
+ // payer-identifying text, so it never reaches our stored payload.
165
+ providerErrorCodes: (response.errors ?? []).map((error) => error.errorCode),
166
+ ...(declineEvidence ? { declineEvidence } : {}),
167
+ ...failureEvidencePayload(observation ? tpayFailureEvidence({
168
+ source: "execution", providerPaymentId: response.transactionId, refusalVerified: true,
169
+ flow: transient.flow, observation, errorCode: rejection?.errorCode, reading,
170
+ }) : null),
171
+ },
172
+ };
173
+ },
174
+ };
175
+ }
176
+ function requireTpayTransientInput(input, options) {
177
+ if (input.providerFlow === "blik_one_click") {
178
+ if (!options.oneClickEnabled)
179
+ throw new TpayExecutionInputError("tpay_blik_one_click_not_enabled");
180
+ if (input.mode !== "one_time")
181
+ throw new TpayExecutionInputError("tpay_blik_one_click_requires_one_time");
182
+ if (!input.paymentMethodRef)
183
+ throw new TpayExecutionInputError("tpay_blik_one_click_payid_missing");
184
+ if (input.transientProviderInput && input.transientProviderInput.flow !== "blik_one_click") {
185
+ throw new TpayExecutionInputError("tpay_provider_flow_mismatch");
186
+ }
187
+ return { provider: PROVIDER_KIND, flow: "blik_one_click" };
188
+ }
189
+ if (input.providerFlow === "recurring_charge") {
190
+ if (input.mode !== "subscription_cycle")
191
+ throw new TpayExecutionInputError("tpay_recurring_charge_requires_cycle");
192
+ if (!input.paymentMethodRef)
193
+ throw new TpayExecutionInputError("tpay_recurring_charge_payid_missing");
194
+ if (input.paymentMethodAliasType && input.paymentMethodAliasType !== "PAYID") {
195
+ throw new TpayExecutionInputError("tpay_recurring_charge_requires_payid");
196
+ }
197
+ if (input.paymentMethodRecurringModel !== "O") {
198
+ throw new TpayExecutionInputError("tpay_recurring_charge_requires_model_o");
199
+ }
200
+ if (input.transientProviderInput && input.transientProviderInput.flow !== "recurring_charge") {
201
+ throw new TpayExecutionInputError("tpay_provider_flow_mismatch");
202
+ }
203
+ return { provider: PROVIDER_KIND, flow: "recurring_charge" };
204
+ }
205
+ const transient = input.transientProviderInput;
206
+ if (!transient || transient.provider !== PROVIDER_KIND)
207
+ throw new TpayExecutionInputError("tpay_transient_input_missing");
208
+ if (input.providerFlow && input.providerFlow !== transient.flow) {
209
+ throw new TpayExecutionInputError("tpay_provider_flow_mismatch");
210
+ }
211
+ if (transient.flow === "blik_one_time" || transient.flow === "blik_recurring_activation") {
212
+ if (!transient.blikToken)
213
+ throw new TpayExecutionInputError("tpay_blik_token_missing");
214
+ }
215
+ if (transient.flow === "pbl_one_time" && !transient.channelId) {
216
+ throw new TpayExecutionInputError("tpay_channel_id_missing");
217
+ }
218
+ if (transient.flow === "pbl_one_time" && input.mode !== "one_time") {
219
+ throw new TpayExecutionInputError("tpay_pbl_recurring_not_supported");
220
+ }
221
+ if (transient.flow === "blik_recurring_activation") {
222
+ if (!options.modelOActivationEnabled) {
223
+ throw new TpayExecutionInputError("tpay_blik_recurring_activation_not_enabled");
224
+ }
225
+ if (transient.recurringModel !== "O") {
226
+ throw new TpayExecutionInputError("tpay_blik_model_o_required");
227
+ }
228
+ if (input.mode !== "subscription_cycle") {
229
+ throw new TpayExecutionInputError("tpay_blik_recurring_activation_requires_subscription_cycle");
230
+ }
231
+ if (input.saveForFutureUse !== true) {
232
+ throw new TpayExecutionInputError("tpay_blik_recurring_activation_requires_save_for_future_use");
233
+ }
234
+ }
235
+ return transient;
236
+ }
237
+ function defaultPayer(input) {
238
+ if (input.payer)
239
+ return input.payer;
240
+ if (!input.customerRef)
241
+ return null;
242
+ return { email: input.customerRef, name: "Customer" };
243
+ }
244
+ export class TpayExecutionInputError extends Error {
245
+ constructor(message) {
246
+ super(message);
247
+ this.name = "TpayExecutionInputError";
248
+ }
249
+ }
@@ -0,0 +1,5 @@
1
+ import type { ProviderReconciliationStatus } from "./donorContracts.js";
2
+ import type { PaymentProviderRecoveryProvider } from "./donorContracts.js";
3
+ import type { TpayHttpClient } from "./tpayHttpClient.js";
4
+ export declare function createTpayPaymentReconciliationProvider(client: Pick<TpayHttpClient, "getTransaction">): PaymentProviderRecoveryProvider;
5
+ export declare function normalizeTpayTransaction(transaction: Record<string, unknown>): ProviderReconciliationStatus;