@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,290 @@
1
+ import {
2
+ buildTpayTransactionPayload,
3
+ type TpayPaymentError,
4
+ type TpayTransactionCreateInput,
5
+ type TpayTransactionCreated,
6
+ } from "./tpayTransactionPayload.js";
7
+ import { tpayTransactionDispatchBoundary } from "./tpayDispatchFailure.js";
8
+ import { readTpayHttpFailure, TpayHttpError } from "./tpayHttpFailure.js";
9
+
10
+ export { TpayHttpError } from "./tpayHttpFailure.js";
11
+
12
+ export interface TpayFetchLike {
13
+ (url: string, init?: {
14
+ method?: string;
15
+ headers?: Record<string, string>;
16
+ body?: string;
17
+ signal?: AbortSignal;
18
+ }): Promise<{
19
+ ok: boolean;
20
+ status: number;
21
+ json(): Promise<unknown>;
22
+ text(): Promise<string>;
23
+ }>;
24
+ }
25
+
26
+ export interface TpayHttpClientOptions {
27
+ baseUrl: string;
28
+ clientId: string;
29
+ clientSecret: string;
30
+ timeoutMs?: number;
31
+ fetchImpl?: TpayFetchLike;
32
+ now?: () => number;
33
+ }
34
+
35
+ export type {
36
+ TpayAliasInput,
37
+ TpayPayerInput,
38
+ TpayPaymentError,
39
+ TpayTransactionCreateInput,
40
+ TpayTransactionCreated,
41
+ } from "./tpayTransactionPayload.js";
42
+
43
+ export interface TpayPaymentChannel {
44
+ id: string;
45
+ name: string;
46
+ fullName: string;
47
+ available: boolean;
48
+ onlinePayment: boolean;
49
+ instantRedirection: boolean;
50
+ groups: Array<{ id: number; name: string }>;
51
+ }
52
+
53
+ export interface TpayHttpClient {
54
+ createTransaction(input: TpayTransactionCreateInput): Promise<TpayTransactionCreated>;
55
+ getTransaction(transactionId: string): Promise<TpayTransactionReadback>;
56
+ listPaymentChannels(): Promise<TpayPaymentChannel[]>;
57
+ }
58
+
59
+ export interface TpayTransactionReadback extends Record<string, unknown> {
60
+ transactionId: string;
61
+ title: string | null;
62
+ status: string;
63
+ transactionPaymentUrl: string | null;
64
+ amount: number | null;
65
+ currency: string | null;
66
+ requestId: string | null;
67
+ payments: Record<string, unknown>;
68
+ }
69
+
70
+ interface OAuthToken {
71
+ accessToken: string;
72
+ expiresAtMs: number;
73
+ }
74
+
75
+ const TOKEN_REFRESH_SKEW_MS = 60_000;
76
+ const DEFAULT_TPAY_TIMEOUT_MS = 10_000;
77
+
78
+ export function createTpayHttpClient({
79
+ baseUrl,
80
+ clientId,
81
+ clientSecret,
82
+ timeoutMs = DEFAULT_TPAY_TIMEOUT_MS,
83
+ fetchImpl = globalThis.fetch as unknown as TpayFetchLike,
84
+ now = () => Date.now(),
85
+ }: TpayHttpClientOptions): TpayHttpClient {
86
+ let token: OAuthToken | null = null;
87
+ const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
88
+
89
+ function requestDeadline(): { expiresAtMs: number } {
90
+ return { expiresAtMs: Date.now() + timeoutMs };
91
+ }
92
+
93
+ async function bearer(deadline: { expiresAtMs: number }): Promise<string> {
94
+ if (token && token.expiresAtMs - TOKEN_REFRESH_SKEW_MS > now()) {
95
+ return token.accessToken;
96
+ }
97
+ const body = new URLSearchParams({ client_id: clientId, client_secret: clientSecret });
98
+ const response = await fetchWithTimeout(fetchImpl, `${normalizedBaseUrl}/oauth/auth`, {
99
+ method: "POST",
100
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
101
+ body: body.toString(),
102
+ }, remainingTimeoutMs(deadline, "tpay_oauth_timeout"), "tpay_oauth_timeout");
103
+ const json = await readJson(response, "tpay_oauth_failed");
104
+ const accessToken = readString(json, "access_token");
105
+ const expiresIn = readNumber(json, "expires_in");
106
+ token = { accessToken, expiresAtMs: now() + expiresIn * 1000 };
107
+ return accessToken;
108
+ }
109
+
110
+ async function request(
111
+ path: string,
112
+ init: { method?: string; body?: unknown } = {},
113
+ deadline = requestDeadline(),
114
+ ) {
115
+ const headers: Record<string, string> = { Authorization: `Bearer ${await bearer(deadline)}` };
116
+ let body: string | undefined;
117
+ if (init.body !== undefined) {
118
+ headers["Content-Type"] = "application/json";
119
+ body = JSON.stringify(init.body);
120
+ }
121
+ const response = await fetchWithTimeout(fetchImpl, `${normalizedBaseUrl}${path}`, {
122
+ method: init.method ?? "GET",
123
+ headers,
124
+ body,
125
+ }, remainingTimeoutMs(deadline, "tpay_request_timeout"), "tpay_request_timeout");
126
+ return readJson(response, "tpay_request_failed");
127
+ }
128
+
129
+ return {
130
+ async createTransaction(input) {
131
+ const deadline = requestDeadline();
132
+ return tpayTransactionDispatchBoundary({
133
+ authenticate: () => bearer(deadline),
134
+ prepare: (accessToken) => ({
135
+ headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json" },
136
+ body: JSON.stringify(buildTpayTransactionPayload(input)),
137
+ timeoutMs: remainingTimeoutMs(deadline, "tpay_request_deadline_exhausted"),
138
+ }),
139
+ dispatch: ({ headers, body, timeoutMs }) => fetchWithTimeout(
140
+ fetchImpl,
141
+ `${normalizedBaseUrl}/transactions`,
142
+ { method: "POST", headers, body },
143
+ timeoutMs,
144
+ "tpay_request_timeout",
145
+ ),
146
+ decode: async (response) => {
147
+ const json = await readJson(response, "tpay_request_failed");
148
+ const payments = asRecord(json.payments);
149
+ return {
150
+ transactionId: readString(json, "transactionId"),
151
+ title: readString(json, "title"),
152
+ status: readString(json, "status"),
153
+ transactionPaymentUrl: readNullableString(json, "transactionPaymentUrl"),
154
+ requestId: readNullableString(json, "requestId"),
155
+ payIdEligible: typeof payments.payIdEligible === "boolean" ? payments.payIdEligible : null,
156
+ errors: readPaymentErrors(payments.errors),
157
+ };
158
+ },
159
+ });
160
+ },
161
+
162
+ async getTransaction(transactionId) {
163
+ const json = await request(
164
+ `/transactions/${encodeURIComponent(transactionId)}`,
165
+ {},
166
+ requestDeadline(),
167
+ );
168
+ return {
169
+ // Keep provider fields that recovery normalizes later (notably nested
170
+ // dates and paidAmount). Explicit canonical fields below remain the
171
+ // typed client contract.
172
+ ...json,
173
+ transactionId: readString(json, "transactionId"),
174
+ title: readNullableString(json, "title"),
175
+ status: readString(json, "status"),
176
+ transactionPaymentUrl: readNullableString(json, "transactionPaymentUrl"),
177
+ amount: readNullableTransactionAmount(json, "amount"),
178
+ currency: readNullableString(json, "currency"),
179
+ requestId: readNullableString(json, "requestId"),
180
+ payments: asRecord(json.payments),
181
+ };
182
+ },
183
+
184
+ async listPaymentChannels() {
185
+ const json = await request("/transactions/channels", {}, requestDeadline());
186
+ const channels: unknown[] = Array.isArray((json as Record<string, unknown>).channels)
187
+ ? (json as Record<string, unknown>).channels as unknown[]
188
+ : [];
189
+ return channels.map(mapChannel);
190
+ },
191
+ };
192
+ }
193
+
194
+ function remainingTimeoutMs(deadline: { expiresAtMs: number }, timeoutCode: string): number {
195
+ const remaining = deadline.expiresAtMs - Date.now();
196
+ if (remaining <= 0) throw new TpayHttpError(timeoutCode, 504);
197
+ return remaining;
198
+ }
199
+
200
+ async function fetchWithTimeout(
201
+ fetchImpl: TpayFetchLike,
202
+ url: string,
203
+ init: Parameters<TpayFetchLike>[1],
204
+ timeoutMs: number,
205
+ timeoutCode: string,
206
+ ): ReturnType<TpayFetchLike> {
207
+ const controller = new AbortController();
208
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
209
+ try {
210
+ return await fetchImpl(url, { ...init, signal: controller.signal });
211
+ } catch (error) {
212
+ if (controller.signal.aborted) {
213
+ throw new TpayHttpError(timeoutCode, 504);
214
+ }
215
+ throw error;
216
+ } finally {
217
+ clearTimeout(timeout);
218
+ }
219
+ }
220
+
221
+ function asRecord(value: unknown): Record<string, unknown> {
222
+ return value && typeof value === "object" ? value as Record<string, unknown> : {};
223
+ }
224
+
225
+ function readPaymentErrors(value: unknown): TpayPaymentError[] {
226
+ if (!Array.isArray(value)) return [];
227
+ return value.map((entry) => {
228
+ const record = asRecord(entry);
229
+ return {
230
+ errorCode: String(record.errorCode ?? ""),
231
+ errorMessage: String(record.errorMessage ?? ""),
232
+ fieldName: typeof record.fieldName === "string" ? record.fieldName : null,
233
+ };
234
+ });
235
+ }
236
+
237
+ async function readJson(response: Awaited<ReturnType<TpayFetchLike>>, code: string): Promise<Record<string, unknown>> {
238
+ if (!response.ok) {
239
+ const failure = await readTpayHttpFailure(response);
240
+ throw new TpayHttpError(code, response.status, failure.diagnostic, failure.refusedBeforeTransaction);
241
+ }
242
+ const json = await response.json();
243
+ if (!json || typeof json !== "object") throw new TpayHttpError("tpay_invalid_response", response.status);
244
+ return json as Record<string, unknown>;
245
+ }
246
+
247
+ function mapChannel(value: unknown): TpayPaymentChannel {
248
+ const record = value && typeof value === "object" ? value as Record<string, unknown> : {};
249
+ return {
250
+ id: String(record.id ?? ""),
251
+ name: String(record.name ?? ""),
252
+ fullName: String(record.fullName ?? record.name ?? ""),
253
+ available: record.available === true,
254
+ onlinePayment: record.onlinePayment === true,
255
+ instantRedirection: record.instantRedirection === true,
256
+ groups: Array.isArray(record.groups) ? record.groups.map(mapGroup) : [],
257
+ };
258
+ }
259
+
260
+ function mapGroup(value: unknown): { id: number; name: string } {
261
+ const record = value && typeof value === "object" ? value as Record<string, unknown> : {};
262
+ return { id: Number(record.id ?? 0), name: String(record.name ?? "") };
263
+ }
264
+
265
+ function readString(value: Record<string, unknown>, key: string): string {
266
+ const raw = value[key];
267
+ if (typeof raw !== "string" || raw.length === 0) throw new TpayHttpError("tpay_invalid_response", 200);
268
+ return raw;
269
+ }
270
+
271
+ function readNullableString(value: Record<string, unknown>, key: string): string | null {
272
+ const raw = value[key];
273
+ return typeof raw === "string" && raw.length > 0 ? raw : null;
274
+ }
275
+
276
+ function readNumber(value: Record<string, unknown>, key: string): number {
277
+ const raw = value[key];
278
+ if (typeof raw !== "number" || !Number.isFinite(raw)) throw new TpayHttpError("tpay_invalid_response", 200);
279
+ return raw;
280
+ }
281
+
282
+ function readNullableTransactionAmount(value: Record<string, unknown>, key: string): number | null {
283
+ const raw = value[key];
284
+ if (typeof raw === "number") return Number.isFinite(raw) ? raw : null;
285
+ if (typeof raw !== "string") return null;
286
+ const trimmed = raw.trim();
287
+ if (!/^\d+(?:\.\d+)?$/.test(trimmed)) return null;
288
+ const parsed = Number(trimmed);
289
+ return Number.isFinite(parsed) ? parsed : null;
290
+ }
@@ -0,0 +1,186 @@
1
+ import {
2
+ loggableProviderErrorCode,
3
+ loggableProviderFieldName,
4
+ loggableProviderRequestId,
5
+ } from "./providerAttemptFailureDiagnostic.js";
6
+
7
+ export interface TpayHttpFailureDiagnostic {
8
+ httpStatus: number;
9
+ requestId: string | null;
10
+ providerErrorCodes: string[];
11
+ fieldNames: string[];
12
+ }
13
+
14
+ /**
15
+ * The provider answered, and its answer is read for two independent things: the
16
+ * sanitized diagnostic that may be logged, and whether the refusal PROVES no
17
+ * transaction was created.
18
+ */
19
+ export interface TpayHttpFailure {
20
+ diagnostic: TpayHttpFailureDiagnostic;
21
+ /**
22
+ * Tpay rejected the request document itself, so no transaction row can exist.
23
+ * `false` is the fail-closed answer and the only one any ambiguity produces.
24
+ */
25
+ refusedBeforeTransaction: boolean;
26
+ }
27
+
28
+ /**
29
+ * Tpay error codes that describe the REQUEST DOCUMENT — a missing field, a wrong
30
+ * type, an out-of-range or malformed value, an unknown field, an unparseable
31
+ * body, a wrong content type. Every one of them is decided by request validation
32
+ * and therefore cannot be produced once a transaction row exists.
33
+ *
34
+ * Deliberately excluded, and each for a reason: `crc_not_unique` names an
35
+ * ALREADY EXISTING transaction; `transaction_lock`, `transaction_blocked`,
36
+ * `payment_failed` and `ts:transaction:*` describe a transaction's outcome or a
37
+ * partially completed insert; `cannot_create_transaction`,
38
+ * `partner_cannot_create_transaction` and every channel/merchant availability
39
+ * code refuse for reasons whose ordering against creation we cannot prove from
40
+ * here; `general` and `internal_server_error` are opaque. A refusal carrying any
41
+ * of them keeps today's behavior and defers to reconciliation.
42
+ *
43
+ * ⚠️ This list is matched against the RAW body, never against
44
+ * `TpayHttpFailureDiagnostic.providerErrorCodes` — that projection drops any code
45
+ * outside the loggable set, which would turn a mixed body into a uniformly safe
46
+ * one.
47
+ */
48
+ export const TPAY_PRE_TRANSACTION_REFUSAL_CODES: ReadonlySet<string> = new Set([
49
+ "country_not_valid",
50
+ "field_required",
51
+ "incorrect_content_type",
52
+ "invalid_request_body",
53
+ "is_required",
54
+ "not_array",
55
+ "not_natural_int",
56
+ "not_string",
57
+ "not_valid",
58
+ "too_low",
59
+ "ts:country:not_valid",
60
+ "ts:payer:phone:not_valid",
61
+ "unexpected_field",
62
+ ]);
63
+
64
+ /** The one HTTP status on which Tpay reports request validation. */
65
+ const TPAY_REQUEST_VALIDATION_STATUS = 400;
66
+
67
+ const MAX_FAILURE_BODY_BYTES = 16_384;
68
+ const MAX_DIAGNOSTIC_ITEMS = 5;
69
+
70
+ export async function readTpayHttpFailure(response: {
71
+ status: number;
72
+ text(): Promise<string>;
73
+ }): Promise<TpayHttpFailure> {
74
+ const base = emptyDiagnostic(response.status);
75
+ try {
76
+ const body = await response.text();
77
+ if (body.length > MAX_FAILURE_BODY_BYTES) return unreadableFailure(base);
78
+ const parsed = JSON.parse(body) as unknown;
79
+ const root = asRecord(parsed);
80
+ const payment = asRecord(root.payments);
81
+ const errors = [...readArray(root.errors), ...readArray(payment.errors)];
82
+ const rawErrorCodes = errors.map((entry) => asRecord(entry).errorCode);
83
+ return {
84
+ diagnostic: {
85
+ ...base,
86
+ requestId: loggableProviderRequestId(root.requestId) ? root.requestId : null,
87
+ providerErrorCodes: allowedValues(errors.map((entry) => asRecord(entry).errorCode), loggableProviderErrorCode),
88
+ fieldNames: allowedValues(errors.map((entry) => asRecord(entry).fieldName), loggableProviderFieldName),
89
+ },
90
+ refusedBeforeTransaction: refusedBeforeTransaction(response.status, rawErrorCodes),
91
+ };
92
+ } catch {
93
+ return unreadableFailure(base);
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Whether this answer proves Tpay created nothing.
99
+ *
100
+ * Three conditions, all required. The status must be exactly the validation
101
+ * status: a 409 may name an existing transaction, a 429 or any 5xx may follow
102
+ * one that was created before the response was lost. The body must have yielded
103
+ * at least one error code, so an opaque refusal from an edge proxy — which we
104
+ * cannot attribute to Tpay's validator — releases nothing. And EVERY raw code
105
+ * must be allow-listed, including codes this repository does not otherwise
106
+ * recognize, so one unknown code in a mixed body is enough to refuse.
107
+ */
108
+ function refusedBeforeTransaction(status: number, rawErrorCodes: unknown[]): boolean {
109
+ return status === TPAY_REQUEST_VALIDATION_STATUS
110
+ && rawErrorCodes.length > 0
111
+ && rawErrorCodes.every((code) =>
112
+ typeof code === "string" && TPAY_PRE_TRANSACTION_REFUSAL_CODES.has(code)
113
+ );
114
+ }
115
+
116
+ function unreadableFailure(diagnostic: TpayHttpFailureDiagnostic): TpayHttpFailure {
117
+ return { diagnostic, refusedBeforeTransaction: false };
118
+ }
119
+
120
+ export function tpayHttpFailureDiagnostic(error: unknown): TpayHttpFailureDiagnostic | null {
121
+ if (!error || typeof error !== "object") return null;
122
+ const value = asRecord((error as { failureDiagnostic?: unknown }).failureDiagnostic);
123
+ const httpStatus = value.httpStatus;
124
+ const requestId = value.requestId;
125
+ const providerErrorCodes = value.providerErrorCodes;
126
+ const fieldNames = value.fieldNames;
127
+ if (!Number.isInteger(httpStatus) || (httpStatus as number) < 100 || (httpStatus as number) > 599) return null;
128
+ if (requestId !== null && !loggableProviderRequestId(requestId)) return null;
129
+ if (!validAllowedValues(providerErrorCodes, loggableProviderErrorCode)
130
+ || !validAllowedValues(fieldNames, loggableProviderFieldName)) return null;
131
+ return {
132
+ httpStatus: httpStatus as number,
133
+ requestId: requestId as string | null,
134
+ providerErrorCodes: [...providerErrorCodes],
135
+ fieldNames: [...fieldNames],
136
+ };
137
+ }
138
+
139
+ export class TpayHttpError extends Error {
140
+ readonly code: string;
141
+ readonly status: number;
142
+ readonly failureDiagnostic: TpayHttpFailureDiagnostic | null;
143
+ /**
144
+ * Set only from a body this client actually parsed. It never crosses a
145
+ * boundary as a claim on its own — the dispatch boundary turns it into typed
146
+ * evidence, and the control-plane RPC re-proves the attempt independently.
147
+ */
148
+ readonly refusedBeforeTransaction: boolean;
149
+
150
+ constructor(
151
+ code: string,
152
+ status: number,
153
+ failureDiagnostic: TpayHttpFailureDiagnostic | null = null,
154
+ refusedBeforeTransaction = false,
155
+ ) {
156
+ super(code);
157
+ this.name = "TpayHttpError";
158
+ this.code = code;
159
+ this.status = status;
160
+ this.failureDiagnostic = failureDiagnostic;
161
+ this.refusedBeforeTransaction = refusedBeforeTransaction;
162
+ }
163
+ }
164
+
165
+ function emptyDiagnostic(httpStatus: number): TpayHttpFailureDiagnostic {
166
+ return { httpStatus, requestId: null, providerErrorCodes: [], fieldNames: [] };
167
+ }
168
+
169
+ function asRecord(value: unknown): Record<string, unknown> {
170
+ return value && typeof value === "object" && !Array.isArray(value)
171
+ ? value as Record<string, unknown>
172
+ : {};
173
+ }
174
+
175
+ function readArray(value: unknown): unknown[] {
176
+ return Array.isArray(value) ? value : [];
177
+ }
178
+
179
+ function allowedValues(values: unknown[], allowed: (value: unknown) => value is string): string[] {
180
+ return [...new Set(values.filter(allowed))].slice(0, MAX_DIAGNOSTIC_ITEMS);
181
+ }
182
+
183
+ function validAllowedValues(value: unknown, allowed: (item: unknown) => item is string): value is string[] {
184
+ return Array.isArray(value) && value.length <= MAX_DIAGNOSTIC_ITEMS
185
+ && value.every(allowed);
186
+ }