@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
package/README.md CHANGED
@@ -4,18 +4,18 @@ Development preview. This package is part of the publishable set with core and o
4
4
 
5
5
  It holds the runnable server substrate an OpenLup application composes: the Node HTTP runtime, BFF dispatch, scheduling and job leases, blob storage, data gateways, the node-postgres migration runner and bundle composition. Ports and their contracts stay in `@openlup/core/platform-runtime`.
6
6
 
7
- For the prepared `0.20.0` set, read the [adjacent-release migration and known
8
- limitations](CHANGELOG.md#0200) before selecting the opt-in M05 parity seams or
9
- M06 composition bindings. M06 remains incomplete: inventory and shipping entries
7
+ For the prepared `0.22.0` set, read the [adjacent-release migration and known
8
+ limitations](CHANGELOG.md#0220) before selecting the opt-in M05 parity seams or
9
+ M06 composition bindings, the M07 payment selectors, or M08 fulfillment services. Native delivery alignment stays off or shadow until a host composes its automatic-renewal runner with the G23 admission decorator. M07 payment truth is complete for this wave; its selectors are default-off. M06 remains incomplete: inventory and shipping entries
10
10
  are development-preview surfaces, with managed-host proof classes pending in the
11
11
  [M06 parity ledger](../../docs/platform/plans/oss-m06-stock-reservations-delivery.md#parity-pending-rows).
12
- The size gate compares the prepared `0.20.0` set with the published `0.19.0` tarball;
12
+ The size gate compares the prepared `0.22.0` set with the published `0.21.0` tarball;
13
13
  preparation, offline adapter evidence and a passing size cap grant no publication
14
14
  or provider-account certification.
15
15
 
16
16
  ## Package surface
17
17
 
18
- `release-gates.json` declares kind `rail`: this foundation provides runtime infrastructure over core ports, matching the architecture's rail responsibility. Its twenty-five experimental entries each bind a declaration snapshot and package-owned smoke tests. The API checker reads this same inventory.
18
+ `release-gates.json` declares kind `rail`: this foundation provides runtime infrastructure over core ports, matching the architecture's rail responsibility. Its experimental entries each bind a declaration snapshot and package-owned smoke tests. The API checker reads this same inventory.
19
19
 
20
20
  | Export | Contents |
21
21
  | --- | --- |
@@ -32,6 +32,11 @@ or provider-account certification.
32
32
  | `./identity/contracts` | Experimental capability: browser-safe customer auth port, value types and provider parser |
33
33
  | `./communications` | Experimental existing public consent/status, newsletter sync, Auth email hook, transport contracts/capture, observation/polling orchestration, standard webhook verification and delivery receipts; host-selected rendering, egress, protocol mapping and control policy |
34
34
  | `./communications/contracts` | Pure renderer, block builders, copy-injected commerce/subscription factories and email/newsletter/Auth/intake/receipt types; no Zod, Node or provider runtime imports |
35
+ | `./payments/stripe` | Opt-in Node payment example with an injected structural client, verified observations and purpose-sensitive readback; no SDK dependency or default activation. |
36
+ | `./payments/tpay` | Opt-in Node payment example with injected HTTP/certificate I/O, Model O aliases and verified observations; no default activation. |
37
+ | `./fulfillment/omnipack` | Opt-in Node fulfillment example with injected I/O; default-off. |
38
+ | `./payments` | Experimental prepared-attempt ordering with injected persistence, execution and failure policy; contracts at `./payments/contracts`. |
39
+ | `./fulfillment`, `./fulfillment/contracts` | [Experimental fulfillment services, contracts and status canon](../../docs/platform/ARCHITECTURE_AND_EXTENSIONS.md#fulfillment-contracts). |
35
40
  | `./inventory` | Experimental schemas/ports, handlers, native stores, projection, injected forecast and SQL descriptor; `./inventory/contracts` DTOs. |
36
41
  | `./catalog` | Experimental neutral catalog schemas, drafts, reads, media source packs and publication ports |
37
42
  | `./catalog/contracts` | Dependency-free catalog DTOs, media resolver, authority and canonicalization helpers |
@@ -771,7 +776,7 @@ for both-bundle commands, the committed managed grants and installation limits.
771
776
 
772
777
  ## Communications import
773
778
 
774
- For adoption from `0.16.0`, follow the [0.17.0 Migration guidance](CHANGELOG.md#0170)
779
+ For adoption from `0.16.0`, follow the [0.17.0 Migration guidance](CHANGELOG-HISTORY.md#0170) (source repository)
775
780
  for the complete package set, canonical SQL installation and host-owned bindings.
776
781
 
777
782
  M04 P1 relocates the existing public implementation without changing its reference
@@ -1052,3 +1057,187 @@ opt-in browser profile adds no npm entry or UI package export.
1052
1057
  Source contributors record notable changes in package changelog fragments;
1053
1058
  release preparation assembles the shipped CHANGELOG. Follow the
1054
1059
  [public contribution guide](https://github.com/openlup/openlup/blob/main/CONTRIBUTING.md#development-preview-checks).
1060
+
1061
+ ## Payments prepared attempts
1062
+
1063
+ `@openlup/platform/payments` exports `executePreparedAttemptMechanism`: validate before durable preparation, refuse prepared replay, dispatch once unless the host proves no charge, and retry one immutable local finalization. The host owns keys, fingerprints, nominal error trust and persistence. An unknown execution never authorizes redispatch. The reference facade retains its existing binding.
1064
+
1065
+ `./payments/contracts` is type-only: execution/dispatch, transient method handoff, capability overlay, verified money/method evidence, bounded readback/absence, neutral refusals, refund observations and multi-subject conformance fixtures. Verification uses receipt time for freshness; ingress starts processing at receipt time and reuses durable first receipt on redelivery. Event identity includes outcome class. Transient authorization and opaque handoffs never enter persisted diagnostics. Capability support is explicit; timeout/truncation is unknown, never exact absence. Refunds require explicit evidence by default; `legacy-assume-full` is an explicit host opt-in. See the [M07 ledger](../../docs/platform/plans/oss-m07-payments-money-truth.md).
1066
+
1067
+ The payments entry also exports verified ingress, canonical truth fingerprints, method lifecycle/refusal handoff, reconciliation/verify-now and three runner-independent conformance functions. A new internal boundary projects verified envelopes into the contributed processing carrier: original bytes reach verification unchanged, receipt time starts processing, and durable first receipt overrides redelivery time. Full-reversal chargebacks use the existing dispute path. Snapshot and delta observations preserve original payment money; missing observation, required money or identity refuses before terminal application. Missing money, amounts that are not safe positive integers, or blank currencies on succeeded, refunded or disputed adapter evidence use the existing amount-mismatch refusal before ingestion or terminal application; ingress returns the existing processing-failure response. Failed and pending evidence may still omit money. Hosts own durable stores and response transport. Conformance requires safe positive integer amounts and nonblank currencies on settling money and checks exact identity/money, capability/port agreement and transient-secret exclusion; its evidence contains no handoff. Real-store durability still requires a selected-store proof.
1068
+
1069
+ `createPostgresPaymentTruthPort` accepts the platform data executor structural
1070
+ shape and `PostgresPaymentTruthOptions` from the contracts entry. It preserves
1071
+ the native truth ingest, reconciliation, sweep and readback SQL. `PAYMENT_MIGRATIONS`
1072
+ projects canonical units 10/35/56 byte for byte, with path, position, SHA-256 and
1073
+ asset URL; install the complete catalogue, never those three files alone.
1074
+ `paymentSchemaDescriptor` admits direct truth, settlement and later-only cycle
1075
+ alignment, and explicitly refuses prepared durable storage, method setup,
1076
+ absence reopen and cumulative refund. Refunds are purely financial. Seven real
1077
+ PostgreSQL cases cover fresh/prefix installs, replay/conflict, unknown readback,
1078
+ lost acknowledgement, rollback, denied access, dunning/recovery, concurrency and
1079
+ later-only dates; this does not claim managed-store parity or host activation.
1080
+
1081
+ Attempt input adds optional method selection with opaque, persistable channelRef
1082
+ and transient payer email/name. Payer contact is dispatch-only: never persist,
1083
+ audit, log or diagnose it. Missing adapter-required input must refuse before
1084
+ dispatch with exact `notDispatched` evidence. Conformance scans the execution
1085
+ and complete projected stored payload for transient values. Nested normalized
1086
+ evidence copies only declared typed fields, including nested facts; unknown
1087
+ extra properties are excluded. Incomplete chargeback evidence remains stored as
1088
+ a refund and unapplied, a declared operator recovery limit: reclassification
1089
+ would apply the donor dispute path without checking completeness.
1090
+
1091
+ `createCheckoutActivePaymentActionResolver` authorizes the exact owner, order,
1092
+ intent, attempt and execution rail, reads the provider once, then rechecks the
1093
+ complete canonical attempt. Hosts inject synchronous `railHandoffKinds` from
1094
+ adapter capture capabilities; an unknown rail supplies an empty list. Actions
1095
+ carry the provider address and the existing transient `PaymentMethodHandoff`.
1096
+ Pending evidence alone may expose a handoff; terminal, mismatched, unknown or
1097
+ raced evidence refuses it. `createCheckoutRecoveryPaymentResolver` preserves
1098
+ paid/retry/resume/wait/manual-review ordering without creating a new obligation.
1099
+ `createCommercePaymentVerifyHandler` validates the existing identity triple,
1100
+ checks stored ownership before readback, and uses the shared HTTP/responder
1101
+ contracts. A host may inject its responder to preserve request references.
1102
+
1103
+ `PaymentRepairMethodPort` collects a method only; it grants no token redemption,
1104
+ subscription change or payment success. Unsupported setup is explicit. Method
1105
+ evidence may carry neutral registration refs/kind/status. Ingress projects them
1106
+ only with `resolveMethodOwner` supplied by the host; adapter-supplied client or
1107
+ subscription fields never confer ownership. Without host ownership resolution,
1108
+ registration is not projected. Lifecycle carriers copy typed facts only.
1109
+ The existing refusal handoff accepts a failure-reason string, not a typed
1110
+ adapter refusal envelope; envelope forwarding remains unsupported.
1111
+
1112
+ ### Payment service composition
1113
+
1114
+ `createPaymentServices` accepts `PaymentServicesOptions` and returns
1115
+ `PaymentServices` or null when truth schema/capability is unavailable. The host
1116
+ supplies `openTruth`, which opens one port and its asynchronous close operation.
1117
+ `run` closes that scope after success or failure. Construction performs no I/O.
1118
+ Use the existing `createBundleComposer` payments binder for named registration;
1119
+ omitting it leaves the host cold. Schema declarations do not prove installation:
1120
+ retain the existing readiness/schema checks before admitting work. Existing jobs
1121
+ and routes keep their owners; this binding adds no schedule or event handler.
1122
+
1123
+ The reference direct truth binding injects its existing executor, templates and
1124
+ recovery path. The separate verified-ingress selector is explicit and default-off;
1125
+ unknown selections refuse. Its projected carrier includes the adapter fingerprint,
1126
+ so the reference store records stable identity on the first receipt independently
1127
+ of audit payload or clock. On replay the store reads the first stored instant;
1128
+ application and follow-up work reuse it. Missing durable clock evidence refuses
1129
+ rather than advancing a cycle. This D11 behaviour change does not mount a provider
1130
+ route or enable an adapter; hosts must explicitly wire the selected ingress.
1131
+
1132
+ ### Opt-in payment example
1133
+
1134
+ Import `createStripePaymentAdapter`, `type StripePaymentAdapterConfig` and
1135
+ `stripePaymentCapabilities` from `@openlup/platform/payments/stripe`. Supply a
1136
+ structural client, `webhookSigningSecrets`, explicit `mode`, required
1137
+ `supportedCurrencies` (a non-empty list of upper-case three-letter codes) and optionally
1138
+ `toleranceSeconds` (default 300) and `clock` (UTC seconds). The host constructs
1139
+ and configures the SDK, associates saved methods with customers and confirms
1140
+ off-session requests. Interactive methods follow the declared card/wallet offer.
1141
+ Importing creates no I/O or default binding. The adapter advertises the host
1142
+ currency list as a frozen copy; the frozen exported descriptor keeps an empty list.
1143
+ Account-specific readiness remains pending TEST verification. Exact absence,
1144
+ refund creation and split authorization/capture are unsupported. Cancellation
1145
+ is enabled only when the injected client supplies it. See the
1146
+ [A2 ledger](../../docs/platform/plans/oss-a2-payment-adapters.md) for the current
1147
+ preview boundary and the host's responsibilities.
1148
+
1149
+ Verified dispute events retain their distinct money outcome and original payment
1150
+ identity. Audit payloads carry only donor-filtered facts: the source event type,
1151
+ refund charge snapshot and failure-evidence provenance when present. They exclude
1152
+ raw bodies, client handoffs and customer authorization and do not affect event
1153
+ IDs or fingerprints. The offline adapter conformance witness uses two distinct
1154
+ intents and attempts with separate money and provider references.
1155
+
1156
+ Method evidence carries the donor lifecycle and replacement facts through M07
1157
+ projection when provider time is present. Without provider time it retains the
1158
+ method outcome and omits the lifecycle instead of inventing a transition time.
1159
+
1160
+ ### Opt-in bank and code payment example
1161
+
1162
+ Import `createTpayPaymentAdapter`, `type TpayPaymentAdapterConfig` and
1163
+ `tpayPaymentCapabilities` from `@openlup/platform/payments/tpay`. Supply `http`
1164
+ with explicit `baseUrl`, `clientId`, `clientSecret`, `fetchImpl` and optional
1165
+ `timeoutMs`; `urls` with `notificationUrl`, `successUrl`, `errorUrl`;
1166
+ `modelOActivationEnabled`, `mode`, and optional UTC-seconds `clock`.
1167
+ `notification` requires `rootCertificatePem`, `allowedCertificateUrlPrefix`
1168
+ (HTTPS directory ending in `/`) and `resolveCertificate`. The resolver owns
1169
+ redirect/egress policy. Both certificates must be valid at verification time.
1170
+
1171
+ Verify certificate validity and notification freshness using original raw bytes.
1172
+ A signed protected-header `iat` supplies UTC-seconds provider time; absent time
1173
+ stays null. `maxNotificationAgeSeconds` defaults to seven days, a generous
1174
+ assumption pending confirmation of the provider retry schedule. Signed issue time
1175
+ more than `maxClockSkewSeconds` (default 300) after receipt refuses as stale;
1176
+ both freshness limits must be finite and nonnegative. Host dedupe
1177
+ uses exact event identity plus stable fingerprint when time is absent. The age
1178
+ and future-skew limits apply only when the signed header carries a provider issue time. Receipt
1179
+ time is used only for freshness. Transaction identity includes outcome class;
1180
+ method identity includes event/alias plus outcome.
1181
+
1182
+ Bank redirects, one-time codes and unattended Model O alias charges are supported
1183
+ when the host supplies the M07 P3 contract payer and method selection inputs.
1184
+ Supply transient `payer: { email, name? }` on every
1185
+ attempt, including renewals. An omitted or blank name uses the donor
1186
+ neutral display label `Customer`. Select `methodSelection: { family: "bank-redirect",
1187
+ channelRef }` for the bank channel, or `{ family: "one-time-code" }` with
1188
+ `customerAuthorization` as a `TransientSecret`. A `renewal-unattended` attempt
1189
+ uses `storedMethod.reference` and its Model O mandate. Missing payer/channel/code
1190
+ and Model M or unknown mandates refuse before any dispatch with neutral
1191
+ data-correction evidence. Payer and authorization never cross the return boundary
1192
+ in diagnostics or request/response payloads. Readback uses the returned API
1193
+ transaction ID; notification titles remain distinct. The donor's typed no-charge
1194
+ errors return an exact `notDispatched` envelope: proven request-document refusals
1195
+ require customer data correction; OAuth, encoding and exhausted pre-send deadlines
1196
+ remain transient retryable refusals. Host mode/purpose/currency mismatches throw before I/O.
1197
+ A renewal the provider refuses for data validation is classified as needing customer data correction: the host should prompt the customer to update payment details, and the bundled retry schedule keeps its normal retries unless the host treats that class as terminating. The subscription stays active; nothing is paused or suspended by this classification. The contributed adopter applies this classification only when reopening a checkout; the example applies it to every purpose.
1198
+ Every other execution error propagates unchanged as ambiguous.
1199
+
1200
+ The exported capability descriptor and its nested records and arrays are frozen.
1201
+ Currencyless money notifications preserve the paid amount and bind to the adapter's single declared currency; multiple declared currencies refuse as malformed.
1202
+ Alias method evidence preserves the donor lifecycle through M07 projection with
1203
+ signed provider time; absent provider time leaves the lifecycle field omitted.
1204
+ The adapter offers its declared market currency; alias registration and recurring
1205
+ cards are not offered by this factory. Account offers
1206
+ remain `verification_pending` until owner TEST readback. Chargeback observations carry full reversal,
1207
+ original money and stable operation identity; refunded/chargeback readback stays
1208
+ unknown for manual review, including historical attempt/error refusals in either
1209
+ readback purpose. Pending and refused readback report validated configured money,
1210
+ including when the paid amount is zero or absent; a refused result with mismatched
1211
+ nonzero paid money stays unknown for manual review. Succeeded readback requires the donor's
1212
+ observed paid amount to equal expected money; underpayment and overpayment remain
1213
+ unknown for manual review. There is no close or exact-absence port. Refund
1214
+ creation and authorization/capture separation are unsupported. See the
1215
+ [A2 ledger](../../docs/platform/plans/oss-a2-payment-adapters.md#o-p2-boundary-and-named-deltas).
1216
+
1217
+ Verified audit payloads retain only donor-filtered transaction and alias facts,
1218
+ including `eventKind`, alias `event` and `aliasType` when supplied. Missing failure
1219
+ provenance and failure prose stay absent. Payer, authorization, certificates and
1220
+ raw bodies never enter the evidence; audit facts do not affect event identity or
1221
+ fingerprints. The offline M07 P2 conformance witness uses two distinct intents,
1222
+ attempts, amounts and provider references, with replay and refusal boundaries.
1223
+
1224
+ ### Reference-support surface
1225
+
1226
+ The vendor subpaths additionally expose these experimental helpers for the
1227
+ reference application's existing host bindings. Each declaration names its exact
1228
+ reference consumer and carries `@experimental`: Reference-application support
1229
+ surface; may change.
1230
+
1231
+ | Entry | Additional exports |
1232
+ | --- | --- |
1233
+ | `@openlup/platform/payments/stripe` | `createStripeSandboxPaymentExecutionAdapter`, `createStripePaymentReconciliationProvider`, `mapStripeIntent`, `mapSetupIntent`, `normalizeStripeFailureEvidence` |
1234
+ | `@openlup/platform/payments/tpay` | `createTpayPaymentExecutionAdapter`, `createTpayPaymentReconciliationProvider`, `createTpayHttpClient`, `normalizeTpayFailureEvidence`, `aliasValue`, `ProviderAttemptPreDispatchError` |
1235
+
1236
+ Types are inferred from those functions; no extra type export or neutral payment
1237
+ entry is added. These are the existing contributed implementations, including
1238
+ rich execution, recovery and filtered audit carriers. The host still owns SDK
1239
+ construction, environment/feature flags, callback/return presentation, account
1240
+ readiness and simulator composition. Its prepared-attempt facade re-exports the
1241
+ same error class so `instanceof` preserves the no-charge trust boundary.
1242
+ The M07 factories' neutral envelopes and capability limits remain unchanged;
1243
+ reference-support availability establishes no provider activation or stable API.
@@ -1,7 +1,14 @@
1
1
  import type { AnalyticsPort, BlobStoragePort, DataGatewayPort, HttpRuntimePort, MigrationRunnerPort, SchedulerPort, TransactionalRuntimePort } from "@openlup/core/platform-runtime";
2
2
  import { type PlatformBundleDescriptor, type PlatformBundleId } from "../kernel/index.js";
3
+ interface PaymentServices {
4
+ run<T>(work: (port: unknown) => Promise<T>): Promise<T>;
5
+ }
3
6
  type Env = Record<string, string | undefined>;
4
7
  export interface PlatformBundlePorts {
8
+ fulfillment?: {
9
+ runDispatch(): Promise<unknown>;
10
+ } | null;
11
+ payments?: PaymentServices | null;
5
12
  http: HttpRuntimePort | null;
6
13
  scheduler: SchedulerPort | null;
7
14
  blob: BlobStoragePort | null;
@@ -21,6 +28,12 @@ export interface PlatformBundle {
21
28
  * transactional binder also receives the bundle's data capability.
22
29
  */
23
30
  export interface PlatformBundleBinders {
31
+ /** Explicit host selection only; no default binder. */
32
+ fulfillment?: (env: Env) => {
33
+ runDispatch(): Promise<unknown>;
34
+ } | null;
35
+ /** Explicit host selection only; no default payment executor. */
36
+ payments?: (env: Env) => PaymentServices | null;
24
37
  /**
25
38
  * The supabase-js `createClient` used by the default Supabase Storage blob binder. Declared
26
39
  * structurally here so the composition entry's declarations reference no data-module type.
@@ -39,6 +39,10 @@ export function createBundleComposer(binders = {}) {
39
39
  analytics: binders.analytics?.(capabilities.analytics, env) ?? null,
40
40
  transactional: binders.transactional?.(capabilities.transactional, capabilities.data, env) ?? null,
41
41
  };
42
+ if (binders.fulfillment)
43
+ ports.fulfillment = binders.fulfillment(env);
44
+ if (binders.payments)
45
+ ports.payments = binders.payments(env);
42
46
  ports.scheduler = binders.scheduler?.(capabilities.scheduler, env) ?? null;
43
47
  return { id, descriptor, ports };
44
48
  };
@@ -0,0 +1,21 @@
1
+ import type { Contribution, RequiredSchema } from '@openlup/core/readiness';
2
+ /** Structural callables keep composition independent of fulfillment implementation types. */
3
+ export declare function createFulfillmentContribution(input: {
4
+ version: string;
5
+ requiredSchema: RequiredSchema;
6
+ fulfillment: Readonly<Record<string, ((...args: never[]) => unknown) | null>>;
7
+ handlers: Contribution['handlers'];
8
+ schedules: Contribution['schedules'];
9
+ routes: Contribution['routes'];
10
+ }): {
11
+ contributions: Contribution[];
12
+ ports: {
13
+ [k: string]: ((...args: never[]) => unknown) | null;
14
+ };
15
+ routes: {
16
+ [k: string]: (...args: never[]) => unknown;
17
+ };
18
+ triggers: {
19
+ [k: string]: (...args: never[]) => unknown;
20
+ };
21
+ };
@@ -0,0 +1,19 @@
1
+ /** Structural callables keep composition independent of fulfillment implementation types. */
2
+ export function createFulfillmentContribution(input) {
3
+ const contribution = {
4
+ manifest: {
5
+ name: '@openlup/platform', version: input.version, kind: 'rail',
6
+ module: { id: 'fulfillment', kind: 'capability', provides: ['./fulfillment'], dependsOn: [] },
7
+ emits: [], handles: input.handlers.map(handler => handler.eventType),
8
+ schedules: input.schedules.map(({ id, cadenceSeconds }) => ({ id, cadenceSeconds })), env: [],
9
+ requiredPorts: Object.keys(input.fulfillment), routes: input.routes.map(route => route.id), requiredSchema: input.requiredSchema,
10
+ },
11
+ handlers: input.handlers, schedules: input.schedules, routes: input.routes,
12
+ };
13
+ return {
14
+ contributions: [contribution],
15
+ ports: Object.fromEntries(Object.entries(input.fulfillment).filter(([, fn]) => typeof fn === 'function').map(([name, fn]) => [`@openlup/platform/fulfillment:${name}`, fn])),
16
+ routes: Object.fromEntries(input.routes.map(route => [`@openlup/platform/fulfillment:${route.id}`, route.handle])),
17
+ triggers: Object.fromEntries(input.schedules.map(schedule => [`@openlup/platform/fulfillment:${schedule.id}`, schedule.run])),
18
+ };
19
+ }
@@ -4,3 +4,4 @@ export { createNodeHost, type NodeHost, type NodeHostAdmission, type NodeHostDep
4
4
  export { createCatalogContribution, type CatalogContributionInput } from "./catalogContribution.js";
5
5
  export { createInventoryContribution } from "./inventoryContribution.js";
6
6
  export { createShippingContribution } from "./shippingContribution.js";
7
+ export { createFulfillmentContribution } from "./fulfillmentContribution.js";
@@ -1,6 +1,8 @@
1
+ // The existing composer accepts one explicit payments binder; default hosts stay cold.
1
2
  export { createBundleComposer, } from "./composeBundle.js";
2
3
  export { bindNodeHttpPort, createScheduledEntrypointResolver } from "./httpBinding.js";
3
4
  export { createNodeHost, } from "./nodeHost.js";
4
5
  export { createCatalogContribution } from "./catalogContribution.js";
5
6
  export { createInventoryContribution } from "./inventoryContribution.js";
6
7
  export { createShippingContribution } from "./shippingContribution.js";
8
+ export { createFulfillmentContribution } from "./fulfillmentContribution.js";
@@ -0,0 +1,3 @@
1
+ import type { FulfillmentAdapterConformanceEvidence, FulfillmentAdapterConformanceSubject } from "./contracts/index.js";
2
+ /** Runner-independent offline proof using only adapter-owned fixtures. Throws on a violated contract. */
3
+ export declare function runFulfillmentAdapterConformance(subjects: readonly FulfillmentAdapterConformanceSubject[]): Promise<FulfillmentAdapterConformanceEvidence>;
@@ -0,0 +1,223 @@
1
+ import { dispatchEvidence, dispatchResult } from "./dispatchProjection.js";
2
+ import { projectObservation } from "./observationProjection.js";
3
+ import { readFulfillmentCapabilities } from "./providerCapabilities.js";
4
+ import { runFulfillmentDispatchWorker } from "./providerDispatchWorker.js";
5
+ /** Runner-independent offline proof using only adapter-owned fixtures. Throws on a violated contract. */
6
+ export async function runFulfillmentAdapterConformance(subjects) {
7
+ const evidence = [];
8
+ const cases = [];
9
+ for (const subject of subjects) {
10
+ const { adapter, fixtures } = subject;
11
+ const caps = adapter.capabilities;
12
+ const passed = (operation) => { cases.push({ subjectId: subject.subjectId, operation, passed: true }); };
13
+ requireFact(caps.defaultOff === true, "default-off");
14
+ requireFact(readFulfillmentCapabilities([caps], null).kind === "refused", "selection_required");
15
+ const first = fixtures.dispatch[0];
16
+ requireFact(Boolean(first), "dispatch fixture required");
17
+ const disabled = readFulfillmentCapabilities([{ ...caps, selected: false }], first.input.selection);
18
+ requireFact(disabled.kind === "refused" && disabled.refusal.reason === "disabled", "disabled selection");
19
+ const missing = await adapter.dispatch.prepare({ ...first.input, selection: { ...first.input.selection, providerRef: null } });
20
+ requireFact(missing.kind === "refused" && missing.refusal.reason === "selection_required", "adapter selection_required");
21
+ passed("default-off and selection_required");
22
+ for (const fixture of fixtures.dispatch) {
23
+ const before = subject.readIoCount();
24
+ const prepared = await adapter.dispatch.prepare(fixture.input);
25
+ requireSame(prepared, fixture.expectedPrepare, "prepare fixture");
26
+ requireFact(subject.readIoCount() === before, "prepare before I/O");
27
+ assertDurable(prepared, subject);
28
+ if (prepared.kind === "refused") {
29
+ passed("dispatch refused before I/O");
30
+ continue;
31
+ }
32
+ requireFact(caps.operations.dispatch.supported, "unsupported dispatch refuses");
33
+ requireSame(prepared.evidence, dispatchEvidence(prepared.evidence), "prepared evidence allowlist");
34
+ requireFact(prepared.evidence.providerRef === fixture.input.selection.providerRef, "prepared provider identity");
35
+ requireSame(prepared.evidence.contactRevision, fixture.input.contactRevision, "prepared contact identity");
36
+ const mismatch = await adapter.dispatch.dispatch(fixture.input, { ...prepared.evidence, commandFingerprint: `${prepared.evidence.commandFingerprint}:mismatch` });
37
+ requireSame(mismatch, { kind: "not_dispatched", effectMayHaveSucceeded: false,
38
+ refusal: { reason: "not_dispatchable", phase: "dispatch", retryable: false } }, "mismatched preparation refusal");
39
+ requireFact(subject.readIoCount() === before, "mismatch before I/O");
40
+ requireFact(fixture.expectedDispatch !== undefined, "dispatch expected result");
41
+ const result = await adapter.dispatch.dispatch(fixture.input, prepared.evidence);
42
+ requireSame(result, fixture.expectedDispatch, "dispatch fixture");
43
+ requireSame(result, dispatchResult(result), "dispatch allowlist");
44
+ assertDurable(result, subject);
45
+ if (result.kind === "accepted") {
46
+ requireSame(result.evidence, prepared.evidence, "dispatch fingerprint identity");
47
+ requireFact(result.externalRef.length > 0 && result.providerAttemptKey.length > 0 && result.labelKey.length > 0, "accepted proof before local ACK");
48
+ }
49
+ else
50
+ requireFact(result.kind === "unknown" ? result.effectMayHaveSucceeded : !result.effectMayHaveSucceeded, "unknown versus refused");
51
+ if (fixture.replay) {
52
+ const calls = subject.readIoCount();
53
+ requireSame(await adapter.dispatch.dispatch(fixture.input, prepared.evidence), result, "dispatch replay");
54
+ requireFact(subject.readIoCount() === calls, "replay no second I/O");
55
+ }
56
+ passed(`dispatch ${result.kind}, fingerprint, mismatch and replay`);
57
+ }
58
+ for (const operation of ["create", "read", "void"]) {
59
+ const supported = caps.operations[operation === "create" ? "labelCreate" : operation === "read" ? "labelRead" : "labelVoid"].supported;
60
+ const rows = fixtures.label?.[operation] ?? [];
61
+ if (supported)
62
+ requireFact(Boolean(adapter.label) && rows.length > 0, `label ${operation} fixture`);
63
+ if (rows.length)
64
+ requireFact(Boolean(adapter.label), "label port required");
65
+ for (const fixture of rows) {
66
+ const before = subject.readIoCount();
67
+ const result = operation === "create" ? await adapter.label.create(fixture.input[0])
68
+ : operation === "read" ? await adapter.label.read(fixture.input[0])
69
+ : await adapter.label.void(fixture.input[0]);
70
+ requireSame(result, fixture.expected, `label ${operation}`);
71
+ if (!supported && !(operation === "read" && caps.labelReadOwner === "host_storage")) {
72
+ requireFact("refusal" in result && result.refusal?.reason === "unsupported", `unsupported label ${operation}`);
73
+ requireFact(subject.readIoCount() === before, "unsupported label before I/O");
74
+ }
75
+ if (!(operation === "read" && "kind" in result && result.kind === "available"))
76
+ assertDurable(result, subject);
77
+ passed(`label ${operation}`);
78
+ }
79
+ }
80
+ if (caps.operations.verifyObservation.supported)
81
+ requireFact(Boolean(adapter.observation) && Boolean(fixtures.observation?.length), "observation fixtures required");
82
+ const events = new Map();
83
+ for (const fixture of fixtures.observation ?? []) {
84
+ requireFact(Boolean(adapter.observation), "observation port required");
85
+ const result = await adapter.observation.verifyAndNormalize(...fixture.input);
86
+ requireSame(result, fixture.expected, "observation fixture");
87
+ assertDurable(result, subject);
88
+ if (!caps.operations.verifyObservation.supported)
89
+ requireFact(result.kind === "refused" && result.refusal.reason === "unsupported", "unsupported observation");
90
+ if (result.kind === "verified") {
91
+ requireSame(result.observation, projectObservation(result.observation), "observation allowlist");
92
+ const observation = result.observation;
93
+ const identity = stable({ provider: observation.fact.providerKind, reference: observation.fact.fulfillmentReference,
94
+ kind: observation.eventKind, outcome: observation.fact.canonicalStatus, occurredAt: observation.fact.occurredAt });
95
+ const previous = events.get(observation.eventKey);
96
+ if (previous)
97
+ requireFact(previous.identity === identity, "eventKey includes outcome and occurrence");
98
+ events.set(observation.eventKey, { identity, occurredAt: observation.fact.occurredAt });
99
+ const replay = await adapter.observation.verifyAndNormalize(...fixture.input);
100
+ requireSame(replay, result, "observation exact retry");
101
+ }
102
+ passed("observation identity, replay and redaction");
103
+ }
104
+ if (caps.operations.readback.supported)
105
+ requireFact(Boolean(adapter.readback) && Boolean(fixtures.readback?.length), "readback fixtures required");
106
+ for (const fixture of fixtures.readback ?? []) {
107
+ requireFact(Boolean(adapter.readback), "readback port required");
108
+ const result = await adapter.readback.read(...fixture.input);
109
+ requireSame(result, fixture.expected, "readback fixture");
110
+ assertDurable(result, subject);
111
+ if (!caps.operations.readback.supported)
112
+ requireFact(result.kind === "unsupported", "unsupported readback");
113
+ if (fixture.localMissing)
114
+ requireFact(result.kind === "unknown" && result.refusal.reason === "local_missing", "local missing is never absence");
115
+ if (result.kind === "absent") {
116
+ requireFact(caps.operations.exactAbsence.supported, "unsupported exact absence refuses");
117
+ const { mode: _mode, ...scope } = fixture.input[0];
118
+ requireSame(result.scope, scope, "absence scope");
119
+ requireFact(result.proof.kind === "authoritative_exact_lookup" && /^evidence:.+/.test(result.proof.evidenceRef) && Number.isFinite(Date.parse(result.proof.checkedAt)), "absence proof");
120
+ }
121
+ if (result.kind === "found")
122
+ requireFact(result.externalRef === fixture.input[0].externalRef || fixture.input[0].externalRef === null, "found identity");
123
+ passed(`readback ${result.kind}`);
124
+ }
125
+ for (const name of ["stockSync", "productSync"]) {
126
+ const supported = caps.operations[name === "stockSync" ? "syncStock" : "syncProducts"].supported;
127
+ const port = adapter[name];
128
+ const rows = fixtures[name] ?? [];
129
+ if (supported)
130
+ requireFact(Boolean(port) && rows.length > 0, `${name} fixtures required`);
131
+ for (const fixture of rows) {
132
+ requireFact(Boolean(port), `${name} port required`);
133
+ let returned;
134
+ try {
135
+ // Dispatch a typed fixture tuple to its adapter-owned operation.
136
+ const method = port[fixture.operation];
137
+ returned = await method.apply(port, fixture.input);
138
+ }
139
+ catch (error) {
140
+ const refusal = error;
141
+ requireFact(refusal.reason === "unsupported" && refusal.phase === "sync" && refusal.retryable === false, "typed unsupported sync refusal");
142
+ returned = { kind: "refused", refusal };
143
+ }
144
+ requireSame(returned, fixture.expected, `${name} ${fixture.operation}`);
145
+ assertDurable(returned, subject);
146
+ if (!supported)
147
+ requireFact(typeof returned === "object" && returned !== null && "kind" in returned && returned.kind === "refused", "unsupported sync");
148
+ passed(`${name} ${fixture.operation}`);
149
+ }
150
+ }
151
+ if (subject.store) {
152
+ await checkStore(subject);
153
+ passed("store G14 replay, own-key remap and one-remap bound");
154
+ }
155
+ assertDurable({ subjectId: subject.subjectId, providerRef: caps.providerRef }, subject);
156
+ evidence.push({ subjectId: subject.subjectId, providerRef: caps.providerRef });
157
+ }
158
+ return { subjects: evidence, cases };
159
+ }
160
+ async function checkStore(subject) {
161
+ const fixture = subject.store;
162
+ const store = await fixture.create();
163
+ const first = await store.claim(fixture.claim);
164
+ requireFact(first.kind === "claimed", "store initial claim");
165
+ const replay = await store.claim(fixture.claim);
166
+ requireFact(replay.kind === "claimed" && replay.record.replayed, "store same-key claim replay");
167
+ const attempt = () => store.recordProviderAttempt(fixture.mappedAttemptKey, fixture.claim.fulfillmentRef, fixture.claim.evidence, fixture.claim.mode, "recorded");
168
+ requireFact(!(await attempt()).replayed && (await attempt()).replayed, "G14 same key replays");
169
+ requireFact(fixture.mappedAttemptKey !== fixture.remappedAttemptKey, "G14 remap own key");
170
+ requireFact(fixture.claim.requestKey === fixture.remappedClaim.requestKey && fixture.claim.evidence.commandFingerprint !== fixture.remappedClaim.evidence.commandFingerprint, "draft remap fixture");
171
+ const remap = await store.claim(fixture.remappedClaim);
172
+ requireFact(remap.kind === "claimed", "draft re-claim");
173
+ const row = await store.read(fixture.claim.requestKey);
174
+ requireSame(row?.evidence, fixture.remappedClaim.evidence, "atomic remap fingerprint and evidence");
175
+ assertDurable(row, subject);
176
+ requireFact(!(await store.recordProviderAttempt(fixture.remappedAttemptKey, fixture.claim.fulfillmentRef, fixture.remappedClaim.evidence, fixture.claim.mode, "recorded")).replayed, "G14 new mapped attempt");
177
+ const attempts = await store.readMappedAttempts();
178
+ requireFact(attempts.length === 2, "G14 no duplicate durable attempts");
179
+ requireSame(attempts.map(row => row.attemptKey).sort(), [fixture.mappedAttemptKey, fixture.remappedAttemptKey].sort(), "G14 durable remap identity");
180
+ for (const attempt of attempts) {
181
+ requireSame(attempt.preparedEvidence, dispatchEvidence(attempt.preparedEvidence), "G14 sanitized evidence only");
182
+ assertDurable(attempt, subject);
183
+ }
184
+ const stale = await store.begin({ dispatchRef: row.dispatchRef, commandFingerprint: fixture.claim.evidence.commandFingerprint });
185
+ requireFact(stale.kind === "refused", "stale prepared command refuses");
186
+ let claims = 0;
187
+ let calls = 0;
188
+ let reads = 0;
189
+ const bounded = await runFulfillmentDispatchWorker({
190
+ store: { ...await fixture.create(), async read() { return null; }, async readCandidate() { reads += 1; return reads === 1 ? fixture.request : fixture.remappedRequest; },
191
+ async claim() { claims += 1; return { kind: "refused", refusal: { reason: "contact_stale", phase: "claim", retryable: true } }; } },
192
+ provider: { prepare: request => subject.adapter.dispatch.prepare(request), async dispatch() { calls += 1; throw new Error("unexpected dispatch"); } },
193
+ listCandidates: async () => [fixture.request], config: { mode: "stage", batchLimit: 1 },
194
+ keys: { request: () => fixture.claim.requestKey, mappedAttempt: (_key, index) => index === 0 ? fixture.mappedAttemptKey : fixture.remappedAttemptKey,
195
+ acceptance: () => ({ providerAttemptKey: "fixture-attempt", labelKey: "fixture-label" }) },
196
+ });
197
+ requireFact(claims === 2 && calls === 0 && !bounded.ok, "one-remap limit before I/O");
198
+ }
199
+ function assertDurable(value, subject) {
200
+ const text = JSON.stringify(value) ?? "";
201
+ requireFact(!subject.sensitiveValues.filter(Boolean).some(secret => text.includes(secret) || text.includes(JSON.stringify(secret).slice(1, -1))), "durable secret redaction");
202
+ const visit = (node) => {
203
+ if (!node || typeof node !== "object")
204
+ return;
205
+ for (const [key, child] of Object.entries(node)) {
206
+ requireFact(!/^(rawBody|rawPayload|rawCommand|password|secret|credential|authorization|headers|signedUrl)$/i.test(key), "durable field allowlist");
207
+ if (typeof child === "string")
208
+ requireFact(!/[?&](?:signature|sig|token|x-amz-signature|credential)=/i.test(child), "durable signed URL");
209
+ visit(child);
210
+ }
211
+ };
212
+ visit(value);
213
+ }
214
+ function stable(value) {
215
+ if (Array.isArray(value))
216
+ return `[${value.map(stable).join(",")}]`;
217
+ if (value && typeof value === "object")
218
+ return `{${Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, child]) => `${JSON.stringify(key)}:${stable(child)}`).join(",")}}`;
219
+ return JSON.stringify(value);
220
+ }
221
+ function requireSame(actual, expected, label) { requireFact(stable(actual) === stable(expected), label); }
222
+ function requireFact(value, label) { if (!value)
223
+ throw new Error(`fulfillment_adapter_conformance:${label}`); }
@@ -0,0 +1,3 @@
1
+ import type { FulfillmentServices, FulfillmentServicesOptions } from './contracts/index.js';
2
+ /** Explicit selection; no environment readers, implicit provider or automatic dispatch. */
3
+ export declare function createFulfillmentServices(options: FulfillmentServicesOptions): FulfillmentServices;
@@ -0,0 +1,29 @@
1
+ import { FULFILLMENT_NATIVE_UNSUPPORTED } from './nativeUnsupported.js';
2
+ import { readFulfillmentCapabilities } from './providerCapabilities.js';
3
+ import { runFulfillmentDispatchWorker } from './providerDispatchWorker.js';
4
+ /** Explicit selection; no environment readers, implicit provider or automatic dispatch. */
5
+ export function createFulfillmentServices(options) {
6
+ const { enabled, selection, capability, store, provider, readiness: observe, listCandidates, now } = options;
7
+ const config = { ...options.config }, keys = { ...options.keys };
8
+ const readiness = async () => {
9
+ if (enabled !== true)
10
+ return { ready: false, refusal: { reason: 'disabled', phase: 'selection', retryable: false } };
11
+ const selected = readFulfillmentCapabilities(capability ? [capability] : [], selection);
12
+ if (selected.kind === 'refused')
13
+ return { ready: false, refusal: selected.refusal };
14
+ if (!selected.descriptor.operations.dispatch.supported)
15
+ return { ready: false, refusal: { reason: 'unsupported', phase: 'selection', retryable: false } };
16
+ if (!store || !provider)
17
+ return { ready: false, refusal: FULFILLMENT_NATIVE_UNSUPPORTED };
18
+ return observe();
19
+ };
20
+ return {
21
+ readiness,
22
+ async runDispatch() {
23
+ const state = await readiness();
24
+ if (!state.ready)
25
+ return 'kind' in state.refusal ? state.refusal : { kind: 'refused', refusal: state.refusal };
26
+ return runFulfillmentDispatchWorker({ store: store, provider, listCandidates, keys, config, now });
27
+ },
28
+ };
29
+ }