@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,37 @@
1
+ import { type OmnipackFulfilmentEvidence, type OmnipackFulfilmentRequestEvidence, type OmnipackOrderCreatedEvidence, type OmnipackProductCreatedEvidence, type OmnipackStockEvidence, type OmnipackStockMovementEvidence } from "./mappers.js";
2
+ import { type OmnipackProductEvidence, type OmnipackProductPackCreatedEvidence } from "./productSyncMappers.js";
3
+ export { OmnipackProviderError, sanitizeOmnipackProviderError, type SanitizedOmnipackProviderError, } from "./providerError.js";
4
+ export interface OmnipackClientConfig {
5
+ baseUrl: string;
6
+ credentials: () => {
7
+ username: string;
8
+ password: string;
9
+ } | Promise<{
10
+ username: string;
11
+ password: string;
12
+ }>;
13
+ timeoutMs: number;
14
+ safeReadRetries: number;
15
+ productPath: string;
16
+ }
17
+ export interface OmnipackClient {
18
+ createOrder(body: string): Promise<OmnipackOrderCreatedEvidence>;
19
+ createProduct(payload: Record<string, unknown>, sku: string): Promise<OmnipackProductCreatedEvidence>;
20
+ getProduct(sku: string): Promise<OmnipackProductEvidence>;
21
+ createProductPack(sku: string, payload: Record<string, unknown>, ean: string): Promise<OmnipackProductPackCreatedEvidence>;
22
+ getStock(): Promise<OmnipackStockEvidence[]>;
23
+ getStockMovements(params?: OmnipackQueryParams): Promise<OmnipackStockMovementEvidence[]>;
24
+ getFulfilmentsPage(params?: OmnipackQueryParams): Promise<{
25
+ rows: OmnipackFulfilmentEvidence[];
26
+ complete: boolean;
27
+ }>;
28
+ getFulfilments(params?: OmnipackQueryParams): Promise<OmnipackFulfilmentEvidence[]>;
29
+ getFulfilmentRequests(params?: OmnipackQueryParams): Promise<OmnipackFulfilmentRequestEvidence[]>;
30
+ }
31
+ export interface OmnipackQueryParams {
32
+ startLocalDate?: string;
33
+ endLocalDate?: string;
34
+ page?: number;
35
+ size?: number;
36
+ }
37
+ export declare function createOmnipackClient(config: OmnipackClientConfig, fetchImpl: typeof fetch): OmnipackClient;
@@ -0,0 +1,162 @@
1
+ import { mapOmnipackFulfilmentRequestsResponse, mapOmnipackFulfilmentsResponse, mapOmnipackOrderCreatedResponse, mapOmnipackProductCreatedResponse, mapOmnipackStockMovementsResponse, mapOmnipackStockResponse, sanitizeOmnipackPayload, } from "./mappers.js";
2
+ import { mapOmnipackProductPackCreatedResponse, mapOmnipackProductResponse, } from "./productSyncMappers.js";
3
+ import { mayPostHaveSucceeded, OmnipackProviderError } from "./providerError.js";
4
+ export { OmnipackProviderError, sanitizeOmnipackProviderError, } from "./providerError.js";
5
+ const PRODUCT_PACKS_SEGMENT = "packs";
6
+ export function createOmnipackClient(config, fetchImpl) {
7
+ return {
8
+ async createOrder(body) {
9
+ return mapOmnipackOrderCreatedResponse(await requestJson(fetchImpl, config, "createOrder", "/orders", {
10
+ method: "POST",
11
+ body,
12
+ }));
13
+ },
14
+ async createProduct(payload, sku) {
15
+ const body = await requestJson(fetchImpl, config, "createProduct", config.productPath, post(payload));
16
+ return mapOmnipackProductCreatedResponse(body, sku);
17
+ },
18
+ async getProduct(sku) {
19
+ const path = productResourcePath(config.productPath, sku);
20
+ return mapOmnipackProductResponse(await requestJson(fetchImpl, config, "getProduct", path, { method: "GET" }), sku);
21
+ },
22
+ async createProductPack(sku, payload, ean) {
23
+ const path = `${productResourcePath(config.productPath, sku)}/${PRODUCT_PACKS_SEGMENT}`;
24
+ const body = await requestJson(fetchImpl, config, "createProductPack", path, post(payload));
25
+ return mapOmnipackProductPackCreatedResponse(body, sku, ean);
26
+ },
27
+ async getStock() {
28
+ return mapOmnipackStockResponse(await requestJson(fetchImpl, config, "getStock", "/stock", { method: "GET" }));
29
+ },
30
+ async getStockMovements(params) {
31
+ return mapOmnipackStockMovementsResponse(await requestJson(fetchImpl, config, "getStockMovements", withQuery("/stock-movements", params), { method: "GET" }));
32
+ },
33
+ async getFulfilmentsPage(params) {
34
+ const body = await requestJson(fetchImpl, config, "getFulfilments", withQuery("/fulfilments", params), { method: "GET" });
35
+ const rows = mapOmnipackFulfilmentsResponse(body);
36
+ // Only explicit single-page totals establish whole-collection uniqueness.
37
+ const record = body;
38
+ const page = record?.page;
39
+ const complete = page?.number === 0 && page.totalPages === 1 && page.totalElements === rows.length
40
+ && typeof page.size === "number" && Number.isSafeInteger(page.size) && page.size >= rows.length && page.size > 0
41
+ && !record?._links?.next && !record?.incomplete && !record?.partial;
42
+ return { rows, complete };
43
+ },
44
+ async getFulfilments(params) {
45
+ return mapOmnipackFulfilmentsResponse(await requestJson(fetchImpl, config, "getFulfilments", withQuery("/fulfilments", params), { method: "GET" }));
46
+ },
47
+ async getFulfilmentRequests(params) {
48
+ return mapOmnipackFulfilmentRequestsResponse(await requestJson(fetchImpl, config, "getFulfilmentRequests", withQuery("/fulfilment-requests", params), { method: "GET" }));
49
+ },
50
+ };
51
+ }
52
+ async function requestJson(fetchImpl, config, operation, path, init) {
53
+ const method = (init.method ?? "GET").toUpperCase();
54
+ const attempts = method === "GET" ? config.safeReadRetries + 1 : 1;
55
+ let lastError = null;
56
+ for (let attempt = 1; attempt <= attempts; attempt += 1) {
57
+ let submitted = false;
58
+ try {
59
+ const base = new URL(config.baseUrl);
60
+ const url = new URL(path, base);
61
+ if (url.origin !== base.origin || url.username || url.password || url.protocol !== "https:")
62
+ throw new Error("Invalid fulfillment path");
63
+ const response = await fetchWithTimeout(fetchImpl, url, config, init, () => { submitted = true; });
64
+ if (response.ok)
65
+ return await readJsonBody(response);
66
+ const retryable = method === "GET" && isRetryableStatus(response.status);
67
+ // A failed body read cannot erase the rejection status already received.
68
+ const body = await readJsonBody(response).catch(() => null);
69
+ lastError = new OmnipackProviderError({
70
+ operation,
71
+ status: response.status,
72
+ code: readProviderErrorCode(body) ?? `http_${response.status}`,
73
+ retryable,
74
+ mayHaveSucceeded: mayPostHaveSucceeded(method, response.status),
75
+ });
76
+ if (!retryable || attempt === attempts)
77
+ throw lastError;
78
+ }
79
+ catch (error) {
80
+ const retryable = method === "GET" && attempt < attempts;
81
+ lastError = submitted && error instanceof OmnipackProviderError
82
+ ? error
83
+ : new OmnipackProviderError({
84
+ operation,
85
+ status: null,
86
+ code: "network_error",
87
+ retryable,
88
+ mayHaveSucceeded: submitted && mayPostHaveSucceeded(method, null),
89
+ });
90
+ if (!retryable)
91
+ throw lastError;
92
+ }
93
+ }
94
+ throw lastError;
95
+ }
96
+ async function fetchWithTimeout(fetchImpl, url, config, init, onSubmit) {
97
+ const controller = new AbortController();
98
+ const timeout = setTimeout(() => controller.abort(), config.timeoutMs);
99
+ try {
100
+ const credentials = await config.credentials();
101
+ const requestInit = {
102
+ ...init,
103
+ signal: controller.signal,
104
+ redirect: "error",
105
+ headers: {
106
+ Accept: "application/json",
107
+ "Content-Type": "application/json",
108
+ Authorization: `Basic ${Buffer.from(`${credentials.username}:${credentials.password}`).toString("base64")}`,
109
+ ...(init.headers ?? {}),
110
+ },
111
+ };
112
+ new Request(url, requestInit); // Validate construction before crossing the submission boundary.
113
+ controller.signal.throwIfAborted();
114
+ onSubmit();
115
+ return await fetchImpl(url, requestInit);
116
+ }
117
+ finally {
118
+ clearTimeout(timeout);
119
+ }
120
+ }
121
+ async function readJsonBody(response) {
122
+ const text = await response.text();
123
+ if (!text)
124
+ return {};
125
+ try {
126
+ return sanitizeOmnipackPayload(JSON.parse(text));
127
+ }
128
+ catch {
129
+ return {};
130
+ }
131
+ }
132
+ // A non-retried JSON POST init (mutations must not be silently re-sent — requestJson keys retry
133
+ // off the GET method).
134
+ function post(payload) {
135
+ return { method: "POST", body: JSON.stringify(payload) };
136
+ }
137
+ // Per-product resource path (GET /products/{sku}, base for /packs). sku is percent-encoded; the
138
+ // product path is right-trimmed so a trailing-slash path override does not double the slash.
139
+ function productResourcePath(productPath, sku) {
140
+ return `${productPath.replace(/\/+$/, "")}/${encodeURIComponent(sku)}`;
141
+ }
142
+ function withQuery(path, params) {
143
+ const url = new URL(path, "https://example.test");
144
+ if (params?.startLocalDate)
145
+ url.searchParams.set("startLocalDate", params.startLocalDate);
146
+ if (params?.endLocalDate)
147
+ url.searchParams.set("endLocalDate", params.endLocalDate);
148
+ if (typeof params?.page === "number")
149
+ url.searchParams.set("page", String(params.page));
150
+ if (typeof params?.size === "number")
151
+ url.searchParams.set("size", String(params.size));
152
+ return `${url.pathname}${url.search}`;
153
+ }
154
+ function readProviderErrorCode(body) {
155
+ return typeof body === "object" && body !== null && "code" in body && typeof body.code === "string"
156
+ && /^[A-Z][A-Z0-9_]{0,63}$/.test(body.code)
157
+ ? body.code
158
+ : null;
159
+ }
160
+ function isRetryableStatus(status) {
161
+ return status === 408 || status === 429 || status >= 500;
162
+ }
@@ -0,0 +1,52 @@
1
+ import type { FulfillmentCapabilityDescriptor, FulfillmentDispatchPort, FulfillmentDispatchRequest, FulfillmentLabelPort, FulfillmentObservationPort, FulfillmentReadbackPort, FulfillmentStockSyncProvider, FulfillmentProductSyncProvider } from "../contracts/index.js";
2
+ import { type OmnipackWebhookRouteEvent } from "./omnipackWebhookPayload.js";
3
+ export { omnipackFulfillmentCapabilities } from "./capabilities.js";
4
+ /** Node-only, explicit construction. Secrets are supplied per call, never retained as values. */
5
+ export interface OmnipackFulfillmentAdapterConfig {
6
+ http: {
7
+ baseUrl: string;
8
+ credentials: () => {
9
+ username: string;
10
+ password: string;
11
+ } | Promise<{
12
+ username: string;
13
+ password: string;
14
+ }>;
15
+ fetchImpl: typeof fetch;
16
+ timeoutMs: number;
17
+ safeReadRetries: number;
18
+ productPath: string;
19
+ };
20
+ selected?: boolean;
21
+ /** Per-instance retention target; default 10,000. Evicts oldest completed submissions, never in-flight. */
22
+ maxRetainedSubmissions?: number;
23
+ /** Host account evidence, independent of credentials. Omission remains not ready. */
24
+ readiness?: FulfillmentCapabilityDescriptor["readiness"];
25
+ /** Called in prepare and again for new dispatches; return identical metadata for the same request or dispatch refuses. */
26
+ resolveProduct: (line: FulfillmentDispatchRequest["lines"][number]) => Promise<{
27
+ lotNumber?: string;
28
+ expirationDate?: string;
29
+ } | null>;
30
+ notification: {
31
+ token: () => string | undefined | Promise<string | undefined>;
32
+ expectedEvent: OmnipackWebhookRouteEvent;
33
+ };
34
+ clock: () => string;
35
+ mintEvidenceReference: () => `evidence:${string}`;
36
+ mintSyncRunId: () => string;
37
+ approveTrackingUrl: (url: string) => boolean;
38
+ /** Writes occur only through deliberate calls; scheduled composition must remain pull-only. */
39
+ product?: {
40
+ resolvePushMetadata: (sku: string) => Promise<Record<string, unknown> | null>;
41
+ };
42
+ }
43
+ /** No route, schedule, environment reader or default binding is installed. */
44
+ export declare function createOmnipackFulfillmentAdapter(config: OmnipackFulfillmentAdapterConfig): {
45
+ capabilities: FulfillmentCapabilityDescriptor;
46
+ dispatch: FulfillmentDispatchPort;
47
+ label: FulfillmentLabelPort;
48
+ observation: FulfillmentObservationPort;
49
+ readback: FulfillmentReadbackPort;
50
+ stockSync: FulfillmentStockSyncProvider;
51
+ productSync: FulfillmentProductSyncProvider;
52
+ };
@@ -0,0 +1,349 @@
1
+ import { createOmnipackClient, OmnipackProviderError } from "./client.js";
2
+ import { omnipackFulfillmentCapabilities } from "./capabilities.js";
3
+ import { buildOmnipackDispatchCommand, serializeOmnipackDispatchPayload, stableDispatchHash } from "./omnipackDispatchPayload.js";
4
+ import { mapOmnipackWebhookPayload } from "./mappers.js";
5
+ import { verifyOmnipackWebhookToken } from "./omnipackWebhookPayload.js";
6
+ import { localStatusFor, normalizeStatus } from "./omnipackStatusVocabulary.js";
7
+ import { digest, eventKind, observation, reference, refusal, timestamp } from "./observation.js";
8
+ export { omnipackFulfillmentCapabilities } from "./capabilities.js";
9
+ /** No route, schedule, environment reader or default binding is installed. */
10
+ export function createOmnipackFulfillmentAdapter(config) {
11
+ const maxRetainedSubmissions = config.maxRetainedSubmissions === undefined ? 10_000 : config.maxRetainedSubmissions;
12
+ const base = new URL(config.http.baseUrl);
13
+ if (base.protocol !== "https:" || base.username || base.password || base.search || base.hash
14
+ || !Number.isSafeInteger(maxRetainedSubmissions) || maxRetainedSubmissions <= 0
15
+ || typeof config.http.fetchImpl !== "function" || typeof config.http.credentials !== "function"
16
+ || !Number.isSafeInteger(config.http.timeoutMs) || config.http.timeoutMs <= 0
17
+ || !Number.isSafeInteger(config.http.safeReadRetries) || config.http.safeReadRetries < 0
18
+ || !/^\/[A-Za-z0-9_-]+(?:\/[A-Za-z0-9_-]+)*\/?$/u.test(config.http.productPath)
19
+ || !eventKind(config.notification.expectedEvent))
20
+ throw new Error("Invalid fulfillment configuration");
21
+ const client = createOmnipackClient({ ...config.http }, config.http.fetchImpl);
22
+ // Copy the profile so host selection never mutates the exported default-off descriptor.
23
+ const capabilities = structuredClone(omnipackFulfillmentCapabilities);
24
+ capabilities.selected = config.selected === true;
25
+ capabilities.readiness = config.readiness?.ready === true ? { ready: true }
26
+ : { ready: false, refusal: refusal("not_ready", "selection") };
27
+ const submissions = new Map();
28
+ const evictCompleted = () => {
29
+ for (const [fingerprint, submission] of submissions) {
30
+ if (submissions.size <= maxRetainedSubmissions)
31
+ break;
32
+ if (submission.completed)
33
+ submissions.delete(fingerprint);
34
+ }
35
+ };
36
+ const selectionFailure = (request) => {
37
+ if (!request.selection?.providerRef?.trim())
38
+ return refusal("selection_required", "selection");
39
+ if (request.selection.providerRef !== capabilities.providerRef)
40
+ return refusal("provider_mismatch", "selection");
41
+ if (!reference(request.selection.carrierRef) || !reference(request.selection.serviceRef))
42
+ return refusal("carrier_service_required", "selection");
43
+ if (!capabilities.selected)
44
+ return refusal("disabled", "selection");
45
+ if (!capabilities.readiness.ready)
46
+ return refusal("not_ready", "selection");
47
+ return null;
48
+ };
49
+ const requireSync = () => {
50
+ if (!capabilities.selected || !capabilities.readiness.ready)
51
+ throw refusal(capabilities.selected ? "not_ready" : "disabled", "sync");
52
+ };
53
+ const syncIdentity = () => {
54
+ const syncRunId = reference(config.mintSyncRunId());
55
+ const collectedAt = timestamp(config.clock());
56
+ if (!syncRunId || !collectedAt)
57
+ throw refusal("malformed", "sync");
58
+ return { providerRef: capabilities.providerRef, syncRunId, collectedAt, sourceRevision: null, revisionSource: "collection" };
59
+ };
60
+ // Shared computation: host metadata and serialized bytes live only for this call.
61
+ const buildCommand = async (request) => {
62
+ const requestDigest = stableDispatchHash(request);
63
+ if (!Number.isSafeInteger(request.contactRevision.schemaVersion) || request.contactRevision.schemaVersion < 1
64
+ || !reference(request.contactRevision.source) || !Number.isSafeInteger(request.contactRevision.revision)
65
+ || request.contactRevision.revision < 0)
66
+ throw Error();
67
+ const lines = [];
68
+ for (const line of request.lines) {
69
+ const metadata = await config.resolveProduct(line);
70
+ if (!metadata)
71
+ throw Error();
72
+ lines.push({ sku: line.skuRef, quantity: line.quantity, productSnapshot: { lotNumber: metadata.lotNumber, expirationDate: metadata.expirationDate } });
73
+ }
74
+ if (stableDispatchHash(request) !== requestDigest)
75
+ throw Error();
76
+ const command = buildOmnipackDispatchCommand({
77
+ orderId: request.orderRef, orderNumber: request.orderNumber,
78
+ deliveryContact: { revision: request.contactRevision.revision, recipientName: request.recipient.name,
79
+ contactEmail: request.recipient.email, contactPhone: request.recipient.phone, line1: request.recipient.line1,
80
+ city: request.recipient.city, postalCode: request.recipient.postalCode, country: request.recipient.country,
81
+ selectedDelivery: { providerKind: capabilities.providerRef, carrierKind: request.selection.carrierRef,
82
+ serviceCode: request.selection.serviceRef, deliveryKind: request.selection.deliveryKind, pickupPoint: request.selection.pickupPoint } }, lines,
83
+ });
84
+ const evidence = { commandFingerprint: command.requestFingerprint,
85
+ contactRevision: { schemaVersion: request.contactRevision.schemaVersion, source: request.contactRevision.source, revision: request.contactRevision.revision },
86
+ providerRef: capabilities.providerRef, carrierRef: request.selection.carrierRef, serviceRef: request.selection.serviceRef };
87
+ return { body: command.body, evidence };
88
+ };
89
+ return {
90
+ capabilities,
91
+ dispatch: {
92
+ async prepare(request) {
93
+ const failed = selectionFailure(request);
94
+ if (failed)
95
+ return { kind: "refused", refusal: failed };
96
+ try {
97
+ return { kind: "prepared", evidence: (await buildCommand(request)).evidence };
98
+ }
99
+ catch {
100
+ return { kind: "refused", refusal: refusal("not_dispatchable", "prepare") };
101
+ }
102
+ },
103
+ async dispatch(request, evidence) {
104
+ let commandRequest;
105
+ let fingerprint;
106
+ let evidenceKey;
107
+ let requestCommandDigest;
108
+ try {
109
+ // Validate the closed evidence and its request-bound values without consulting preparation state.
110
+ if (Object.keys(evidence).length !== 5 || Object.keys(evidence.contactRevision).length !== 3
111
+ || typeof evidence.commandFingerprint !== "string" || !/^[a-f0-9]{64}$/u.test(evidence.commandFingerprint)
112
+ || !reference(evidence.providerRef)
113
+ || !reference(evidence.carrierRef) || !reference(evidence.serviceRef)
114
+ || !Number.isSafeInteger(evidence.contactRevision.schemaVersion) || evidence.contactRevision.schemaVersion < 1
115
+ || !reference(evidence.contactRevision.source) || !Number.isSafeInteger(evidence.contactRevision.revision)
116
+ || evidence.contactRevision.revision < 0
117
+ || evidence.contactRevision.schemaVersion !== request.contactRevision.schemaVersion
118
+ || evidence.contactRevision.source !== request.contactRevision.source
119
+ || evidence.contactRevision.revision !== request.contactRevision.revision
120
+ || evidence.providerRef !== request.selection.providerRef
121
+ || evidence.carrierRef !== request.selection.carrierRef || evidence.serviceRef !== request.selection.serviceRef)
122
+ throw Error();
123
+ evidenceKey = serializeOmnipackDispatchPayload(evidence).body;
124
+ requestCommandDigest = commandDigest(request);
125
+ const submitted = submissions.get(evidence.commandFingerprint);
126
+ if (submitted) {
127
+ // Replay is bound to this submission's evidence and command, never replaceable preparation.
128
+ if (submitted.evidenceKey !== evidenceKey || submitted.commandDigest !== requestCommandDigest)
129
+ throw Error();
130
+ return structuredClone(await submitted.result);
131
+ }
132
+ if (selectionFailure(request))
133
+ throw Error();
134
+ commandRequest = structuredClone(request);
135
+ fingerprint = evidence.commandFingerprint;
136
+ }
137
+ catch {
138
+ return { kind: "not_dispatched", effectMayHaveSucceeded: false, refusal: refusal("not_dispatchable", "dispatch") };
139
+ }
140
+ // Reserve before host resolution too, so concurrent dispatches join the rebuild.
141
+ const result = Promise.resolve().then(async () => {
142
+ let command;
143
+ try {
144
+ command = await buildCommand(commandRequest);
145
+ if (command.evidence.commandFingerprint !== fingerprint)
146
+ throw Error();
147
+ }
148
+ catch {
149
+ // A stale or unresolved command has never reached credentials or HTTP.
150
+ submissions.delete(fingerprint);
151
+ return { kind: "not_dispatched", effectMayHaveSucceeded: false, refusal: refusal("not_dispatchable", "dispatch") };
152
+ }
153
+ try {
154
+ const result = await client.createOrder(command.body);
155
+ const externalRef = reference(result.providerOrderId);
156
+ if (!externalRef)
157
+ return { kind: "unknown", effectMayHaveSucceeded: true, refusal: refusal("malformed", "acknowledge") };
158
+ // Opaque provider proof; the worker replaces these with authoritative host keys.
159
+ const proof = digest(JSON.stringify([externalRef, command.evidence.commandFingerprint]));
160
+ return { kind: "accepted", externalRef, evidence: structuredClone(command.evidence),
161
+ providerAttemptKey: `attempt:${proof}`, labelKey: `label:${proof}` };
162
+ }
163
+ catch (error) {
164
+ return error instanceof OmnipackProviderError && !error.mayHaveSucceeded
165
+ ? { kind: "not_dispatched", effectMayHaveSucceeded: false, refusal: refusal("io_failure", "dispatch") }
166
+ : { kind: "unknown", effectMayHaveSucceeded: true, refusal: refusal("io_failure", "dispatch") };
167
+ }
168
+ finally {
169
+ command.body = "";
170
+ submissions.get(fingerprint).completed = true;
171
+ evictCompleted();
172
+ }
173
+ });
174
+ submissions.set(fingerprint, { evidenceKey, commandDigest: requestCommandDigest, completed: false, result });
175
+ evictCompleted();
176
+ return structuredClone(await result);
177
+ },
178
+ },
179
+ label: {
180
+ async create() { return { kind: "refused", refusal: refusal("unsupported", "dispatch") }; },
181
+ async read() { return { kind: "refused", refusal: refusal("unsupported", "dispatch") }; },
182
+ async void() { return { providerDeletion: "unconfirmed", labelDeleted: false, canProceed: false, refusal: refusal("unsupported", "dispatch") }; },
183
+ },
184
+ observation: {
185
+ async verifyAndNormalize(input) {
186
+ // Token check precedes every read of rawBody and every parse.
187
+ try {
188
+ if (!verifyOmnipackWebhookToken({ headers: { ...input.headers } }, await config.notification.token()))
189
+ return { kind: "refused", refusal: refusal("untrusted", "verify") };
190
+ }
191
+ catch {
192
+ return { kind: "refused", refusal: refusal("untrusted", "verify") };
193
+ }
194
+ try {
195
+ const rawBody = Buffer.from(input.rawBody);
196
+ const payload = JSON.parse(rawBody.toString("utf8"));
197
+ if (!payload || typeof payload !== "object" || Array.isArray(payload))
198
+ return { kind: "refused", refusal: refusal("malformed", "normalize") };
199
+ if ("event" in payload && (typeof payload.event !== "string" || !eventKind(payload.event)))
200
+ return { kind: "refused", refusal: refusal("unsupported_event", "normalize") };
201
+ const evidence = mapOmnipackWebhookPayload(payload, config.notification.expectedEvent);
202
+ const event = eventKind(evidence.event);
203
+ if (!event || event !== config.notification.expectedEvent)
204
+ return { kind: "refused", refusal: refusal("unsupported_event", "normalize") };
205
+ if (![evidence.providerOrderId, evidence.orderNumber, evidence.fulfilmentNumber].some(value => reference(value)))
206
+ return { kind: "refused", refusal: refusal("missing_correlation", "normalize") };
207
+ return { kind: "verified", observation: observation({ evidence, event, receivedAt: input.receivedAt,
208
+ rawDigest: digest(rawBody), evidenceRef: config.mintEvidenceReference(), source: "provider_webhook", approveTrackingUrl: config.approveTrackingUrl }) };
209
+ }
210
+ catch {
211
+ return { kind: "refused", refusal: refusal("malformed", "normalize") };
212
+ }
213
+ },
214
+ },
215
+ readback: {
216
+ async read(input) {
217
+ if (input.providerRef !== capabilities.providerRef)
218
+ return { kind: "unsupported", refusal: refusal("provider_mismatch", "readback") };
219
+ if (!capabilities.selected || !capabilities.readiness.ready)
220
+ return { kind: "unsupported", refusal: refusal(capabilities.selected ? "not_ready" : "disabled", "readback") };
221
+ if (!reference(input.externalRef))
222
+ return { kind: "unsupported", refusal: refusal("unsupported", "readback") };
223
+ try {
224
+ const collection = await client.getFulfilmentsPage({ page: 0, size: 100 });
225
+ if (!collection.complete)
226
+ return { kind: "unknown", refusal: refusal("local_missing", "readback") };
227
+ const matches = collection.rows.filter(row => input.mode === "parcel"
228
+ ? row.fulfilmentNumber === input.externalRef : row.providerOrderId === input.externalRef);
229
+ if (matches.length !== 1)
230
+ return { kind: "unknown", refusal: refusal("local_missing", "readback") };
231
+ const row = matches[0];
232
+ const normalized = normalizeStatus(row.status);
233
+ if (!normalized)
234
+ return { kind: "unknown", refusal: refusal("unsupported_event", "readback") };
235
+ const status = localStatusFor(normalized);
236
+ const event = { provider_received: "shipment.accepted", picking: "order.processing_started", packed: "order.picked", in_transit: "order.shipped", delivered: "order.delivered", exception: "parcel.exception" }[status];
237
+ const evidence = { provider: "omnipack", event, providerOrderId: row.providerOrderId, orderNumber: row.orderNumber,
238
+ fulfilmentNumber: row.fulfilmentNumber, occurredAt: row.updatedAt, trackingNumbers: row.trackingNumbers,
239
+ trackingReferences: row.trackingReferences, shippingMethods: [] };
240
+ return { kind: "found", externalRef: input.externalRef, createdAt: timestamp(row.createdAt), updatedAt: timestamp(row.updatedAt),
241
+ observation: observation({ evidence, event, status, fulfillmentRef: input.fulfillmentRef, receivedAt: config.clock(),
242
+ rawDigest: digest(JSON.stringify(evidence)), evidenceRef: config.mintEvidenceReference(), source: "provider_reconciliation", approveTrackingUrl: config.approveTrackingUrl }) };
243
+ }
244
+ catch {
245
+ return { kind: "unknown", refusal: refusal("io_failure", "readback") };
246
+ }
247
+ },
248
+ },
249
+ stockSync: {
250
+ async getStock() {
251
+ requireSync();
252
+ try {
253
+ const identity = syncIdentity();
254
+ return (await client.getStock()).map(row => {
255
+ const skuRef = reference(row.sku);
256
+ if (!skuRef)
257
+ throw refusal("malformed", "sync");
258
+ return { ...identity, skuRef, quantityKind: "snapshot", totalQuantity: row.totalQuantity,
259
+ forSaleQuantity: row.forSaleQuantity, reservedOrUnavailableQuantity: row.reservedOrUnavailableQuantity };
260
+ });
261
+ }
262
+ catch {
263
+ throw refusal("io_failure", "sync");
264
+ }
265
+ },
266
+ async getStockMovements(input) {
267
+ requireSync();
268
+ try {
269
+ const identity = syncIdentity();
270
+ return (await client.getStockMovements(input)).map(row => {
271
+ const skuRef = reference(row.sku);
272
+ if (!skuRef)
273
+ throw refusal("malformed", "sync");
274
+ return { ...identity, skuRef, quantityKind: "movement", quantity: row.quantity, occurredAt: timestamp(row.occurredAt),
275
+ operationType: reference(row.operationType), documentRef: reference(row.warehouseDocumentNumber), lotRef: reference(row.lotNumber), expirationDate: /^\d{4}-\d\d-\d\d$/u.test(row.expirationDate ?? "") ? row.expirationDate : null };
276
+ });
277
+ }
278
+ catch {
279
+ throw refusal("io_failure", "sync");
280
+ }
281
+ },
282
+ },
283
+ productSync: {
284
+ async ensureProduct(sku) {
285
+ requireSync();
286
+ try {
287
+ const metadata = await config.product?.resolvePushMetadata(sku);
288
+ if (!metadata)
289
+ return null;
290
+ await client.createProduct(metadata, sku);
291
+ return { replayed: false };
292
+ }
293
+ catch {
294
+ throw refusal("io_failure", "sync");
295
+ }
296
+ },
297
+ async getProductPacks(sku) {
298
+ requireSync();
299
+ try {
300
+ return (await client.getProduct(sku)).packs.filter(pack => /^\d{8,14}$/u.test(pack.ean) && Number.isSafeInteger(pack.quantity) && pack.quantity > 0).map(pack => ({ ean: pack.ean, quantity: pack.quantity }));
301
+ }
302
+ catch {
303
+ throw refusal("io_failure", "sync");
304
+ }
305
+ },
306
+ async addProductPack(sku, pack) {
307
+ requireSync();
308
+ if (!/^\d{8,14}$/u.test(pack.ean) || !Number.isSafeInteger(pack.quantity) || pack.quantity <= 0)
309
+ throw refusal("malformed", "sync");
310
+ try {
311
+ await client.createProductPack(sku, { ean: pack.ean, quantity: pack.quantity }, pack.ean);
312
+ }
313
+ catch {
314
+ throw refusal("io_failure", "sync");
315
+ }
316
+ },
317
+ async listStockedSkus() {
318
+ requireSync();
319
+ try {
320
+ return [...new Set((await client.getStock()).flatMap(row => reference(row.sku) ? [row.sku] : []))];
321
+ }
322
+ catch {
323
+ throw refusal("io_failure", "sync");
324
+ }
325
+ },
326
+ },
327
+ };
328
+ }
329
+ // buildOmnipackDispatchPayloadFromCandidate forwards only name/email/phone and
330
+ // line1/city/postalCode/country to buildOmnipackOutboundOrderPayload; neither
331
+ // codec reads line titles, recipient line2/deliveryInstructions/courierInstructions,
332
+ // or pickup-point provider/name/address (readPickUpPoint reads only its id).
333
+ // Exclude those descriptions; retain host request/order/fulfillment/parcel and
334
+ // product/pack identities as well as all wire/evidence-bearing request values.
335
+ // The submission retains only this SHA-256 hash in memory, never the raw values.
336
+ function commandDigest(request) {
337
+ return stableDispatchHash({
338
+ requestKey: request.requestKey, fulfillmentRef: request.fulfillmentRef,
339
+ orderRef: request.orderRef, orderNumber: request.orderNumber, parcelRef: request.parcelRef,
340
+ contactRevision: { schemaVersion: request.contactRevision.schemaVersion,
341
+ source: request.contactRevision.source, revision: request.contactRevision.revision },
342
+ recipient: { name: request.recipient.name, email: request.recipient.email, phone: request.recipient.phone,
343
+ line1: request.recipient.line1, city: request.recipient.city, postalCode: request.recipient.postalCode, country: request.recipient.country },
344
+ lines: request.lines.map(line => ({ skuRef: line.skuRef, productRef: line.productRef, packRef: line.packRef, quantity: line.quantity })),
345
+ selection: { providerRef: request.selection.providerRef, carrierRef: request.selection.carrierRef,
346
+ serviceRef: request.selection.serviceRef, deliveryKind: request.selection.deliveryKind,
347
+ pickupPointId: request.selection.pickupPoint?.id ?? null },
348
+ });
349
+ }