@openlup/platform 0.21.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 (263) hide show
  1. package/CHANGELOG.md +210 -47
  2. package/README.md +27 -4
  3. package/dist/composition/composeBundle.d.ts +7 -0
  4. package/dist/composition/composeBundle.js +2 -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 +1 -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/stripe/index.d.ts +25 -0
  170. package/dist/payments/stripe/index.js +25 -0
  171. package/dist/payments/tpay/index.d.ts +30 -0
  172. package/dist/payments/tpay/index.js +30 -0
  173. package/package.json +17 -2
  174. package/release-gates.json +44 -3
  175. package/sql/20260808210000_fulfillment_shipment_rail.sql +810 -0
  176. package/sql/20260819150000_fulfillment_shipment_sequence.sql +98 -0
  177. package/sql/20261022080000_fulfillment_command_ledger.sql +786 -0
  178. package/sql/20261022090000_fulfillment_delivery_alignment.sql +1106 -0
  179. package/src/composition/composeBundle.ts +4 -0
  180. package/src/composition/fulfillmentContribution.ts +28 -0
  181. package/src/composition/index.ts +1 -0
  182. package/src/fulfillment/adapterConformance.ts +195 -0
  183. package/src/fulfillment/bindings.ts +26 -0
  184. package/src/fulfillment/commerceFulfillmentHandlers.ts +263 -0
  185. package/src/fulfillment/commerceFulfillmentReadModel.ts +257 -0
  186. package/src/fulfillment/contracts/alignment.ts +13 -0
  187. package/src/fulfillment/contracts/bindings.ts +30 -0
  188. package/src/fulfillment/contracts/capabilities.ts +15 -0
  189. package/src/fulfillment/contracts/conformance.ts +61 -0
  190. package/src/fulfillment/contracts/customerAlignment.ts +4 -0
  191. package/src/fulfillment/contracts/dispatch.ts +58 -0
  192. package/src/fulfillment/contracts/index.ts +18 -0
  193. package/src/fulfillment/contracts/label.ts +9 -0
  194. package/src/fulfillment/contracts/nativeUnsupported.ts +6 -0
  195. package/src/fulfillment/contracts/observation.ts +18 -0
  196. package/src/fulfillment/contracts/operator.ts +31 -0
  197. package/src/fulfillment/contracts/read.ts +42 -0
  198. package/src/fulfillment/contracts/readback.ts +11 -0
  199. package/src/fulfillment/contracts/replacement.ts +15 -0
  200. package/src/fulfillment/contracts/store.ts +26 -0
  201. package/src/fulfillment/contracts/sync.ts +61 -0
  202. package/src/fulfillment/currentFulfillmentParcel.ts +2 -0
  203. package/src/fulfillment/delayReadModel.ts +60 -0
  204. package/src/fulfillment/deliveryAlignmentReadModel.ts +15 -0
  205. package/src/fulfillment/dispatchProjection.ts +20 -0
  206. package/src/fulfillment/fulfillmentObservationEffects.ts +86 -0
  207. package/src/fulfillment/handlerSchemas.ts +255 -0
  208. package/src/fulfillment/handlerSupport.ts +25 -0
  209. package/src/fulfillment/index.ts +38 -0
  210. package/src/fulfillment/labelLifecycle.ts +11 -0
  211. package/src/fulfillment/lowStockEvidenceHandler.ts +60 -0
  212. package/src/fulfillment/migrations.ts +8 -0
  213. package/src/fulfillment/nativeUnsupported.ts +23 -0
  214. package/src/fulfillment/normalizedFulfillmentFacts.ts +2 -0
  215. package/src/fulfillment/observationProjection.ts +41 -0
  216. package/src/fulfillment/omnipack/capabilities.ts +18 -0
  217. package/src/fulfillment/omnipack/client.ts +258 -0
  218. package/src/fulfillment/omnipack/index.ts +312 -0
  219. package/src/fulfillment/omnipack/mappers.ts +261 -0
  220. package/src/fulfillment/omnipack/observation.ts +61 -0
  221. package/src/fulfillment/omnipack/omnipackDispatchPayload.ts +93 -0
  222. package/src/fulfillment/omnipack/omnipackOutboundOrderPayload.ts +194 -0
  223. package/src/fulfillment/omnipack/omnipackProductPackPayload.ts +47 -0
  224. package/src/fulfillment/omnipack/omnipackProductPayload.ts +67 -0
  225. package/src/fulfillment/omnipack/omnipackReconciliationPayload.ts +7 -0
  226. package/src/fulfillment/omnipack/omnipackStatusVocabulary.ts +103 -0
  227. package/src/fulfillment/omnipack/omnipackWebhookPayload.ts +73 -0
  228. package/src/fulfillment/omnipack/productSyncMappers.ts +74 -0
  229. package/src/fulfillment/omnipack/providerError.ts +64 -0
  230. package/src/fulfillment/omnipack/trackingReferences.ts +77 -0
  231. package/src/fulfillment/paidFulfillmentRecovery.ts +252 -0
  232. package/src/fulfillment/paidHandoff.ts +122 -0
  233. package/src/fulfillment/paidHandoffPorts.ts +21 -0
  234. package/src/fulfillment/postgresDeliveryAlignment.ts +14 -0
  235. package/src/fulfillment/postgresDispatchStore.ts +55 -0
  236. package/src/fulfillment/postgresEvidenceReadPort.ts +59 -0
  237. package/src/fulfillment/postgresPaidFulfillmentRecovery.ts +29 -0
  238. package/src/fulfillment/postgresPaidHandoffStore.ts +11 -0
  239. package/src/fulfillment/postgresShipmentSpine.ts +321 -0
  240. package/src/fulfillment/postgresStockSyncPort.ts +65 -0
  241. package/src/fulfillment/productReconciliationEvidenceHandler.ts +64 -0
  242. package/src/fulfillment/providerCapabilities.ts +18 -0
  243. package/src/fulfillment/providerCommandLedger.ts +53 -0
  244. package/src/fulfillment/providerDispatchAcceptance.ts +31 -0
  245. package/src/fulfillment/providerDispatchError.ts +7 -0
  246. package/src/fulfillment/providerDispatchWorker.ts +131 -0
  247. package/src/fulfillment/providerProductSyncWorker.ts +154 -0
  248. package/src/fulfillment/providerReconciliationError.ts +20 -0
  249. package/src/fulfillment/providerReconciliationTerminalSkip.ts +8 -0
  250. package/src/fulfillment/providerReconciliationTimestamp.ts +34 -0
  251. package/src/fulfillment/providerReconciliationWorker.ts +150 -0
  252. package/src/fulfillment/providerStockAvailability.ts +60 -0
  253. package/src/fulfillment/providerStockSyncWorker.ts +222 -0
  254. package/src/fulfillment/providerTrackingReferences.ts +31 -0
  255. package/src/fulfillment/replacementRefusals.ts +43 -0
  256. package/src/fulfillment/replacementShipmentHandler.ts +47 -0
  257. package/src/fulfillment/schemaCapabilities.ts +7 -0
  258. package/src/fulfillment/shipmentsOverviewHandler.ts +73 -0
  259. package/src/fulfillment/statusMap.ts +2 -0
  260. package/src/fulfillment/trackingProgress.ts +1 -0
  261. package/src/fulfillment/verifiedIngress.ts +80 -0
  262. package/src/payments/stripe/index.ts +30 -0
  263. package/src/payments/tpay/index.ts +36 -0
@@ -0,0 +1,110 @@
1
+ import type { SubscriptionCycleStatus } from '@openlup/core/subscription';
2
+ import type { PaymentIntentStatus } from '@openlup/core/payment';
3
+ import type { FulfillmentNativeUnsupported } from './nativeUnsupported.js';
4
+ export type FulfillmentOrderStatus = 'draft' | 'pending_payment' | 'paid' | 'failed' | 'expired' | 'fulfillment_pending' | 'cancelled' | 'fulfilled' | 'refunded';
5
+ export type FulfillmentPaymentStatus = 'not_started' | PaymentIntentStatus;
6
+ export interface FulfillmentCommerceOrder {
7
+ id: string;
8
+ orderId: string;
9
+ clientId: string | null;
10
+ status: 'created' | 'packed' | 'label_pending' | 'label_created' | 'handed_over' | 'in_transit' | 'delivered' | 'exception' | 'cancelled';
11
+ providerKind: string | null;
12
+ providerTrackingId: string | null;
13
+ shippingAddress: {
14
+ addressId: string;
15
+ clientId: string;
16
+ label: string | null;
17
+ line1: string;
18
+ line2: string | null;
19
+ city: string;
20
+ postalCode: string;
21
+ country: string;
22
+ };
23
+ lines: {
24
+ id: string | null;
25
+ orderItemId: string;
26
+ skuId: string;
27
+ sku: string;
28
+ title: string | null;
29
+ quantity: number;
30
+ inventoryReservationIds: string[];
31
+ productSnapshot: Record<string, unknown>;
32
+ }[];
33
+ payment: {
34
+ paymentIntentId: string;
35
+ paymentStatus: FulfillmentPaymentStatus;
36
+ providerPaymentId: string | null;
37
+ };
38
+ inventory: {
39
+ status: 'not_checked' | 'reserved' | 'missing' | 'released' | 'expired' | 'consumed' | 'review_required';
40
+ reservationId: string | null;
41
+ reservationStatus: 'reserved' | 'consumed' | 'released' | 'expired' | null;
42
+ expiresAt: string | null;
43
+ locationId: string | null;
44
+ locationCode: string | null;
45
+ };
46
+ omsEligibility: {
47
+ allowed: boolean;
48
+ reason: 'order_not_paid' | 'payment_not_succeeded' | 'subscription_cycle_not_paid' | 'active_hold' | 'missing_shipping_address' | 'inventory_review' | 'risk_review' | null;
49
+ };
50
+ latestOperation: {
51
+ id: string;
52
+ type: 'created' | 'packed' | 'provider_attempt_recorded' | 'label_created' | 'handed_over' | 'tracking_event_recorded' | 'cancelled';
53
+ occurredAt: string;
54
+ actorUserId: string | null;
55
+ payload: Record<string, unknown>;
56
+ } | null;
57
+ createdAt: string;
58
+ updatedAt: string;
59
+ }
60
+ export interface FulfillmentOrdersListRequest {
61
+ page: number;
62
+ pageSize: number;
63
+ status?: FulfillmentCommerceOrder['status'];
64
+ }
65
+ export interface FulfillmentOrderDetailRequest {
66
+ fulfillmentOrderId?: string;
67
+ orderId?: string;
68
+ }
69
+ export interface FulfillmentOrdersListResponse {
70
+ contractVersion: 'commerce.fulfillment.v0';
71
+ orders: FulfillmentCommerceOrder[];
72
+ totalCount: number;
73
+ page: number;
74
+ pageSize: number;
75
+ }
76
+ export interface FulfillmentOrderDetailResponse {
77
+ contractVersion: 'commerce.fulfillment.v0';
78
+ order: FulfillmentCommerceOrder;
79
+ }
80
+ /** Host-owned persisted projections. Payment statuses already come from the payments projection. */
81
+ export interface FulfillmentCommerceReadPort {
82
+ listCommerceFulfillmentOrders(request: FulfillmentOrdersListRequest): Promise<FulfillmentOrdersListResponse | FulfillmentNativeUnsupported>;
83
+ getCommerceFulfillmentOrderDetail(request: FulfillmentOrderDetailRequest): Promise<FulfillmentOrderDetailResponse | null | FulfillmentNativeUnsupported>;
84
+ }
85
+ export interface FulfillmentShipmentsOverviewRequest {
86
+ shippedFilter: 'today' | '7d' | '30d' | 'all';
87
+ }
88
+ /** Bucket rows are opaque host data; native shipment counts cannot replace these buckets. */
89
+ export interface FulfillmentShipmentsOverviewResponse {
90
+ approved: Record<string, unknown>[];
91
+ packing: Record<string, unknown>[];
92
+ shippedToday: number;
93
+ shipped: Record<string, unknown>[];
94
+ }
95
+ export interface FulfillmentShipmentsOverviewPort {
96
+ getShipmentsOverview(request: FulfillmentShipmentsOverviewRequest): Promise<FulfillmentShipmentsOverviewResponse | FulfillmentNativeUnsupported>;
97
+ }
98
+ /** Existing commerce eligibility remains host-owned; the read model only supplies its facts. */
99
+ export interface FulfillmentCommerceReadPolicy {
100
+ evaluateCommerceFulfillmentEligibility(input: {
101
+ orderMode: 'one_time' | 'subscription_cycle';
102
+ orderStatus: FulfillmentOrderStatus;
103
+ paymentStatus: FulfillmentPaymentStatus;
104
+ subscriptionCycleStatus: SubscriptionCycleStatus | null;
105
+ activeHoldCount: number;
106
+ hasShippingAddress: boolean;
107
+ inventoryStatus: FulfillmentCommerceOrder['inventory']['status'];
108
+ }): FulfillmentCommerceOrder['omsEligibility'];
109
+ }
110
+ export type { FulfillmentProgressInput, FulfillmentProgressPresentation } from "@openlup/core/fulfillment";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,38 @@
1
+ import type { FulfillmentObservation } from "./observation.js";
2
+ import type { FulfillmentRefusal } from "./dispatch.js";
3
+ export type FulfillmentReadbackResult = {
4
+ kind: "found";
5
+ externalRef: string;
6
+ createdAt: string | null;
7
+ updatedAt: string | null;
8
+ observation: FulfillmentObservation;
9
+ } | {
10
+ kind: "absent";
11
+ scope: {
12
+ providerRef: string;
13
+ requestKey: string;
14
+ fulfillmentRef: string;
15
+ externalRef: string | null;
16
+ };
17
+ proof: {
18
+ kind: "authoritative_exact_lookup";
19
+ evidenceRef: `evidence:${string}`;
20
+ checkedAt: string;
21
+ };
22
+ } | {
23
+ kind: "unknown";
24
+ refusal: FulfillmentRefusal;
25
+ } | {
26
+ kind: "unsupported";
27
+ refusal: FulfillmentRefusal;
28
+ };
29
+ export interface FulfillmentReadbackPort {
30
+ /** Empty pages and missing local rows cannot certify external absence. */
31
+ read(input: {
32
+ providerRef: string;
33
+ requestKey: string;
34
+ fulfillmentRef: string;
35
+ externalRef: string | null;
36
+ mode: "command" | "parcel";
37
+ }): Promise<FulfillmentReadbackResult>;
38
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,34 @@
1
+ import type { FulfillmentNativeUnsupported } from './nativeUnsupported.js';
2
+ export interface FulfillmentReplacementRequest {
3
+ idempotencyKey: string;
4
+ actorUserId: string;
5
+ orderId: string;
6
+ reason: 'damaged' | 'lost' | 'returned_undelivered' | 'other';
7
+ metadata?: Record<string, unknown>;
8
+ }
9
+ export interface FulfillmentReplacementResult {
10
+ contractVersion: 'commerce.v0';
11
+ operation: {
12
+ id: string;
13
+ orderId: string;
14
+ type: 'hold_created' | 'hold_released' | 'fulfillment_reviewed' | 'support_note' | 'shipping_address_updated' | 'order_marked_refunded' | 'order_cancelled_manual' | 'replacement_shipment_requested';
15
+ holdId: string | null;
16
+ actorUserId: string | null;
17
+ occurredAt: string;
18
+ payload: Record<string, unknown>;
19
+ };
20
+ replacement: {
21
+ fulfillmentOrderId: string;
22
+ orderId: string;
23
+ sequenceNo: number;
24
+ replacesFulfillmentOrderId: string;
25
+ reason: FulfillmentReplacementRequest['reason'];
26
+ status: string;
27
+ };
28
+ releasedHoldIds: string[];
29
+ replayed: boolean;
30
+ }
31
+ /** Host owns atomic paid/contact/current-parcel/hold/reservation checks and actor-bound fingerprint/replay receipts. No confirmation or dispatch operation exists here. */
32
+ export interface FulfillmentReplacementPort {
33
+ requestReplacementShipment(request: FulfillmentReplacementRequest): Promise<FulfillmentReplacementResult | FulfillmentNativeUnsupported>;
34
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,86 @@
1
+ import type { DispatchEvidence, FulfillmentDispatchRequest, FulfillmentDispatchResult, FulfillmentRefusal } from "./dispatch.js";
2
+ export interface DispatchRecord {
3
+ dispatchRef: string;
4
+ requestKey: string;
5
+ fulfillmentRef: string;
6
+ orderRef: string;
7
+ parcelRef: string | null;
8
+ externalRef: string | null;
9
+ mode: "shadow" | "stage" | "live";
10
+ status: "draft" | "submitting" | "created" | "uncertain" | "failed" | "cancel_requested" | "cancelled";
11
+ evidence: DispatchEvidence;
12
+ replayed: boolean;
13
+ }
14
+ export interface FulfillmentStorePort {
15
+ read(requestKey: string): Promise<DispatchRecord | null>;
16
+ readCandidate(fulfillmentRef: string): Promise<FulfillmentDispatchRequest | null>;
17
+ prepare(fulfillmentRef: string): Promise<{
18
+ disposition: "ready" | "withheld";
19
+ contactRevision: number | null;
20
+ }>;
21
+ /** Evidence comes from adapter prepare, before any external submission. */
22
+ claim(input: {
23
+ requestKey: string;
24
+ fulfillmentRef: string;
25
+ orderRef: string;
26
+ parcelRef: string | null;
27
+ mode: DispatchRecord["mode"];
28
+ evidence: DispatchEvidence;
29
+ }): Promise<{
30
+ kind: "claimed";
31
+ record: DispatchRecord;
32
+ } | {
33
+ kind: "refused";
34
+ refusal: FulfillmentRefusal;
35
+ }>;
36
+ /** G14: idempotent mapped attempt; persist only prepared, sanitized evidence. */
37
+ recordProviderAttempt(attemptKey: string, fulfillmentRef: string, preparedEvidence: DispatchEvidence, mode: DispatchRecord["mode"], status: "recorded"): Promise<{
38
+ replayed: boolean;
39
+ }>;
40
+ /** Bind submission to the same prepared command fingerprint recorded by claim. */
41
+ begin(input: {
42
+ dispatchRef: string;
43
+ commandFingerprint: string;
44
+ }): Promise<{
45
+ kind: "begun";
46
+ record: DispatchRecord;
47
+ begun: boolean;
48
+ replayed: boolean;
49
+ } | {
50
+ kind: "refused";
51
+ refusal: FulfillmentRefusal;
52
+ }>;
53
+ /** Accepted rescue retains externalRef as uncertain; only acknowledge closes the local acceptance atomically. */
54
+ finalize(input: {
55
+ dispatchRef: string;
56
+ result: FulfillmentDispatchResult;
57
+ }): Promise<DispatchRecord>;
58
+ acknowledge(input: {
59
+ dispatchRef: string;
60
+ acceptance: Extract<FulfillmentDispatchResult, {
61
+ kind: "accepted";
62
+ }>;
63
+ }): Promise<{
64
+ acknowledged: boolean;
65
+ replayed: boolean;
66
+ record: DispatchRecord;
67
+ }>;
68
+ markStaleSubmissionsUncertain(staleBefore: string): Promise<number>;
69
+ }
70
+ export interface FulfillmentPaidHandoffPort {
71
+ ensureObligation(input: {
72
+ requestKey: string;
73
+ orderRef: string;
74
+ paidFactRef: string;
75
+ }): Promise<{
76
+ fulfillmentRef: string;
77
+ replayed: boolean;
78
+ }>;
79
+ acknowledge(input: {
80
+ requestKey: string;
81
+ fulfillmentRef: string;
82
+ }): Promise<{
83
+ acknowledged: boolean;
84
+ replayed: boolean;
85
+ }>;
86
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,170 @@
1
+ import type { FulfillmentRefusal } from "./dispatch.js";
2
+ /** Collection identity never masquerades as a monotonic provider revision. */
3
+ interface SyncIdentity {
4
+ providerRef: string;
5
+ syncRunId: string;
6
+ collectedAt: string;
7
+ sourceRevision: string | null;
8
+ revisionSource: "provider" | "collection" | "unknown";
9
+ }
10
+ export interface StockSnapshot extends SyncIdentity {
11
+ skuRef: string;
12
+ quantityKind: "snapshot";
13
+ totalQuantity: number;
14
+ forSaleQuantity: number;
15
+ reservedOrUnavailableQuantity: number;
16
+ }
17
+ export interface StockMovement extends SyncIdentity {
18
+ skuRef: string;
19
+ quantityKind: "movement";
20
+ quantity: number;
21
+ occurredAt: string | null;
22
+ operationType: string | null;
23
+ documentRef: string | null;
24
+ lotRef: string | null;
25
+ expirationDate: string | null;
26
+ }
27
+ export interface SyncCursor {
28
+ status: "idle" | "running" | "succeeded" | "failed";
29
+ lastStockSyncedAt: string | null;
30
+ lastMovementOccurredAt: string | null;
31
+ /** Sanitized continuation only; no credentials, URLs or arbitrary provider payload. */
32
+ continuation: {
33
+ nextRef: string | null;
34
+ startLocalDate: string | null;
35
+ endLocalDate: string | null;
36
+ };
37
+ /** G15: successful sellable coverage gaps; legacy absent values read as []. */
38
+ coverageGapSkus?: readonly string[];
39
+ refusal: FulfillmentRefusal | null;
40
+ }
41
+ export interface LocalStock {
42
+ skuRef: string;
43
+ onHand: number;
44
+ reserved: number;
45
+ unavailable: number;
46
+ safetyStock: number;
47
+ }
48
+ type Threshold = "safety_stock" | "reservation_coverage" | "forecast" | "stale_sync";
49
+ type Conflict = "unknown_sku" | "ean_conflict" | "kind_quantity_conflict";
50
+ export interface FulfillmentStockSyncProvider {
51
+ getStock(): Promise<StockSnapshot[]>;
52
+ getStockMovements(input?: {
53
+ startLocalDate?: string;
54
+ endLocalDate?: string;
55
+ size?: number;
56
+ }): Promise<StockMovement[]>;
57
+ }
58
+ export interface FulfillmentStockSyncPort {
59
+ readCursor(): Promise<SyncCursor | null>;
60
+ /** G16: unaggregated lines at the worker clock; quantity retains the four local balances. */
61
+ readLocalInventoryStock(requestedAt: string): Promise<readonly {
62
+ skuRef: string;
63
+ quantity: Pick<LocalStock, "onHand" | "reserved" | "unavailable" | "safetyStock">;
64
+ fulfillable: boolean;
65
+ locationStatus: "active" | "inactive";
66
+ lotStatus: "available" | "quarantined" | "expired" | "recalled" | null;
67
+ expiresAt: string | null;
68
+ }[]>;
69
+ readSkuInventoryClasses(skus: string[]): Promise<Map<string, "sellable" | "packaging" | null>>;
70
+ readActiveReservations(skus: string[], requestedAt: string): Promise<Map<string, number>>;
71
+ recordCursor(input: SyncCursor): Promise<void>;
72
+ recordStockSnapshot(input: {
73
+ requestKey: string;
74
+ snapshot: StockSnapshot;
75
+ local: LocalStock;
76
+ mismatchKind: "none";
77
+ inventoryClass: "sellable" | "packaging" | null;
78
+ }): Promise<{
79
+ replayed: boolean;
80
+ readBack: boolean;
81
+ }>;
82
+ recordProviderStockCurrent(input: {
83
+ requestKey: string;
84
+ snapshot: StockSnapshot;
85
+ inventoryClass: "sellable" | "packaging" | null;
86
+ lastSyncedAt: string;
87
+ staleAfter: string;
88
+ }): Promise<{
89
+ replayed: boolean;
90
+ readBack: boolean;
91
+ }>;
92
+ recordMovement(input: {
93
+ requestKey: string;
94
+ movement: StockMovement;
95
+ }): Promise<{
96
+ replayed: boolean;
97
+ readBack: boolean;
98
+ }>;
99
+ recordLowStockEvidence(input: {
100
+ requestKey: string;
101
+ skuRef: string;
102
+ thresholdKind: Exclude<Threshold, "forecast">;
103
+ severity: "info" | "warning" | "critical";
104
+ providerForSaleQuantity: number;
105
+ localAvailableQuantity: number;
106
+ syncRunId: string;
107
+ }): Promise<{
108
+ replayed: boolean;
109
+ }>;
110
+ resolveLowStockEvidence(input: {
111
+ skuRef: string;
112
+ activeThresholdKinds: Threshold[];
113
+ syncRunId: string;
114
+ }): Promise<{
115
+ resolved: number;
116
+ }>;
117
+ }
118
+ interface ProductPack {
119
+ ean: string;
120
+ quantity: number;
121
+ }
122
+ export interface FulfillmentProductSyncProvider {
123
+ /** null means skipped (no private push metadata), never a newly created local SKU. */
124
+ ensureProduct(sku: string): Promise<{
125
+ replayed: boolean;
126
+ } | null>;
127
+ getProductPacks(sku: string): Promise<ProductPack[]>;
128
+ addProductPack(sku: string, pack: ProductPack): Promise<void>;
129
+ listStockedSkus(): Promise<string[]>;
130
+ }
131
+ export interface FulfillmentProductSyncPort {
132
+ listLocalProductPacks(): Promise<{
133
+ sku: string;
134
+ packs: (ProductPack & {
135
+ kind: "unit" | "collective";
136
+ })[];
137
+ }[]>;
138
+ markPackSynced(input: {
139
+ sku: string;
140
+ ean: string;
141
+ }): Promise<void>;
142
+ upsertPulledPack(input: {
143
+ sku: string;
144
+ ean: string;
145
+ quantity: number;
146
+ kind: "unit" | "collective";
147
+ }): Promise<{
148
+ conflict: "none" | "local_locked_mismatch" | "ean_owned_by_other_sku" | "sku_not_found";
149
+ replayed: boolean;
150
+ }>;
151
+ recordReconciliationEvidence(input: {
152
+ requestKey: string;
153
+ sku: string;
154
+ ean: string | null;
155
+ conflictKind: Conflict;
156
+ providerQuantity: number;
157
+ identity: SyncIdentity;
158
+ refusal: FulfillmentRefusal | null;
159
+ }): Promise<{
160
+ replayed: boolean;
161
+ }>;
162
+ resolveReconciliationEvidence(input: {
163
+ sku: string;
164
+ activeConflictKinds: Conflict[];
165
+ syncRunId: string;
166
+ }): Promise<{
167
+ resolved: number;
168
+ }>;
169
+ }
170
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export { parcelSequenceNo, compareParcelPrecedence, currentParcel, currentParcelFor, currentParcelPerOrder, currentParcelFirst, belongsToParcel, rowsForParcel } from "@openlup/core/fulfillment";
2
+ export type { FulfillmentParcelRow, ParcelAttributedRow } from "@openlup/core/fulfillment";
@@ -0,0 +1 @@
1
+ export { parcelSequenceNo, compareParcelPrecedence, currentParcel, currentParcelFor, currentParcelPerOrder, currentParcelFirst, belongsToParcel, rowsForParcel } from "@openlup/core/fulfillment";
@@ -0,0 +1,11 @@
1
+ import type { CustomerDeliveryAlignment, FulfillmentCustomerAlignmentRowsReader } from './contracts/customerAlignment.js';
2
+ import type { FulfillmentNativeUnsupported } from './contracts/nativeUnsupported.js';
3
+ export type DeliveryAlignmentRow = Record<string, unknown>;
4
+ export type DeliveryAlignmentRowsReader = FulfillmentCustomerAlignmentRowsReader;
5
+ /**
6
+ * Reads only customer-safe current cases. An aligned case remains current while
7
+ * its aligned schedule is still the subscription's next schedule; once a paid
8
+ * cycle advances `next_cycle_at`, the historical ledger row disappears from UI.
9
+ */
10
+ export declare function readFulfillmentDelay(readRows: DeliveryAlignmentRowsReader | undefined, nextCycleAtBySubscription: ReadonlyMap<string, string | null>): Promise<Map<string, CustomerDeliveryAlignment> | FulfillmentNativeUnsupported>;
11
+ export declare function mapCurrentDeliveryAlignments(rows: DeliveryAlignmentRow[], nextCycleAtBySubscription: ReadonlyMap<string, string | null>): Map<string, CustomerDeliveryAlignment>;
@@ -0,0 +1,45 @@
1
+ import { isNativeUnsupported } from './handlerSupport.js';
2
+ /**
3
+ * Reads only customer-safe current cases. An aligned case remains current while
4
+ * its aligned schedule is still the subscription's next schedule; once a paid
5
+ * cycle advances `next_cycle_at`, the historical ledger row disappears from UI.
6
+ */
7
+ export async function readFulfillmentDelay(readRows, nextCycleAtBySubscription) {
8
+ const subscriptionIds = [...nextCycleAtBySubscription.keys()].filter(Boolean);
9
+ if (!readRows || subscriptionIds.length === 0)
10
+ return new Map();
11
+ const rows = await readRows(subscriptionIds);
12
+ if (isNativeUnsupported(rows))
13
+ return rows;
14
+ return mapCurrentDeliveryAlignments(rows, nextCycleAtBySubscription);
15
+ }
16
+ export function mapCurrentDeliveryAlignments(rows, nextCycleAtBySubscription) {
17
+ const result = new Map();
18
+ for (const row of rows) {
19
+ const subscriptionId = text(row.subscription_id);
20
+ if (!subscriptionId || result.has(subscriptionId))
21
+ continue;
22
+ const state = text(row.state);
23
+ if (state === "protected") {
24
+ result.set(subscriptionId, { state });
25
+ continue;
26
+ }
27
+ if (state === "aligned" && sameInstant(nullableText(row.aligned_next_cycle_at), nextCycleAtBySubscription.get(subscriptionId) ?? null)) {
28
+ result.set(subscriptionId, { state });
29
+ }
30
+ }
31
+ return result;
32
+ }
33
+ function sameInstant(left, right) {
34
+ if (!left || !right)
35
+ return false;
36
+ const leftTime = new Date(left).getTime();
37
+ const rightTime = new Date(right).getTime();
38
+ return Number.isFinite(leftTime) && leftTime === rightTime;
39
+ }
40
+ function text(value) {
41
+ return typeof value === "string" ? value : "";
42
+ }
43
+ function nullableText(value) {
44
+ return typeof value === "string" && value ? value : null;
45
+ }
@@ -0,0 +1,4 @@
1
+ import type { DeliveryAlignmentPort } from './contracts/index.js';
2
+ import type { PgExecutor } from './postgresDispatchStore.js';
3
+ /** Server-authorized projection; database browser roles have no direct access. */
4
+ export declare function readDeliveryAlignment(db: PgExecutor, fulfillmentRef: string): ReturnType<DeliveryAlignmentPort['read']>;
@@ -0,0 +1,12 @@
1
+ /** Server-authorized projection; database browser roles have no direct access. */
2
+ export async function readDeliveryAlignment(db, fulfillmentRef) {
3
+ const result = await db.query(`SELECT alignment.state, alignment.aligned_next_cycle_at
4
+ FROM public.fulfillment_shipments shipment
5
+ LEFT JOIN public.subscription_delivery_alignment_cases alignment ON alignment.predecessor_order_id=shipment.order_id
6
+ WHERE shipment.id=$1::uuid
7
+ ORDER BY (alignment.state IN ('protected','manual_review')) DESC, alignment.created_at ASC LIMIT 1`, [fulfillmentRef]);
8
+ const row = result.rows[0];
9
+ const date = row?.aligned_next_cycle_at;
10
+ return { disposition: row?.state === 'aligned' ? 'aligned' : row?.state === 'protected' ? 'outstanding' : 'manual_review',
11
+ nextCycleAt: date instanceof Date ? date.toISOString() : typeof date === 'string' ? date : null };
12
+ }
@@ -0,0 +1,7 @@
1
+ import type { DispatchEvidence, DispatchRecord, FulfillmentDispatchResult } from "./contracts/index.js";
2
+ /** Copy only the durable allowlist, including when an adapter object has extra runtime properties. */
3
+ export declare function dispatchEvidence(evidence: DispatchEvidence): DispatchEvidence;
4
+ export declare function dispatchResult(result: FulfillmentDispatchResult): FulfillmentDispatchResult;
5
+ export declare function acceptedProviderProof(record: DispatchRecord | null): record is DispatchRecord & {
6
+ externalRef: string;
7
+ };
@@ -0,0 +1,18 @@
1
+ /** Copy only the durable allowlist, including when an adapter object has extra runtime properties. */
2
+ export function dispatchEvidence(evidence) {
3
+ return {
4
+ commandFingerprint: evidence.commandFingerprint,
5
+ contactRevision: { schemaVersion: evidence.contactRevision.schemaVersion, source: evidence.contactRevision.source, revision: evidence.contactRevision.revision },
6
+ providerRef: evidence.providerRef, carrierRef: evidence.carrierRef, serviceRef: evidence.serviceRef,
7
+ };
8
+ }
9
+ export function dispatchResult(result) {
10
+ switch (result.kind) {
11
+ case "accepted": return { kind: "accepted", externalRef: result.externalRef, providerAttemptKey: result.providerAttemptKey, labelKey: result.labelKey, evidence: dispatchEvidence(result.evidence) };
12
+ case "not_dispatched": return { kind: "not_dispatched", effectMayHaveSucceeded: false, refusal: { reason: result.refusal.reason, phase: result.refusal.phase, retryable: result.refusal.retryable } };
13
+ case "unknown": return { kind: "unknown", effectMayHaveSucceeded: true, refusal: { reason: result.refusal.reason, phase: result.refusal.phase, retryable: result.refusal.retryable } };
14
+ }
15
+ }
16
+ export function acceptedProviderProof(record) {
17
+ return Boolean(record?.externalRef && (record.status === "created" || record.status === "uncertain"));
18
+ }
@@ -0,0 +1,66 @@
1
+ import type { FulfillmentObservation } from "./contracts/index.js";
2
+ /** Ledger effects for an already accepted observation; acceptance and retry belong to the caller. */
3
+ interface FulfillmentObservationPort<TrackingStatus> {
4
+ markProviderStockConsumed(input: {
5
+ idempotencyKey: string;
6
+ fulfillmentOrderId: string;
7
+ }): Promise<{
8
+ replayed: boolean;
9
+ }>;
10
+ markHandedOver(input: {
11
+ idempotencyKey: string;
12
+ fulfillmentOrderId: string;
13
+ suppressDispatched: boolean;
14
+ }): Promise<{
15
+ replayed: boolean;
16
+ }>;
17
+ recordTrackingReference(input: {
18
+ idempotencyKey: string;
19
+ orderId: string;
20
+ fulfillmentOrderId: string;
21
+ trackingNumber: string;
22
+ trackingUrl: string | null;
23
+ carrierKind: string | null;
24
+ service: string | null;
25
+ status: TrackingStatus;
26
+ observation: FulfillmentObservation;
27
+ }): Promise<{
28
+ replayed: boolean;
29
+ readBack: boolean;
30
+ }>;
31
+ }
32
+ interface FulfillmentObservationTrackingReference {
33
+ trackingNumber: string;
34
+ trackingUrl?: string | null;
35
+ carrierKind?: string | null;
36
+ service?: string | null;
37
+ }
38
+ interface FulfillmentObservationInput<LocalStatus, TrackingStatus> {
39
+ port: FulfillmentObservationPort<TrackingStatus>;
40
+ localStatus: LocalStatus;
41
+ ids: {
42
+ orderId: string;
43
+ fulfillmentOrderId: string;
44
+ };
45
+ observation: FulfillmentObservation;
46
+ trackingRefs: readonly FulfillmentObservationTrackingReference[];
47
+ stockIdempotencyKey: string;
48
+ handoffIdempotencyKey: string;
49
+ trackingIdempotencyKey: (trackingNumber: string) => string;
50
+ issueAccountingInvoice?: () => Promise<void>;
51
+ onReplayed?: () => void;
52
+ onTrackingRecorded?: (result: {
53
+ replayed: boolean;
54
+ readBack: boolean;
55
+ }) => void;
56
+ }
57
+ /** Pure status decisions/projection; the mechanism owns every effect and await. */
58
+ interface FulfillmentObservationStatusPolicy<LocalStatus, TrackingStatus> {
59
+ consumesStock(status: LocalStatus): boolean;
60
+ handsOver(status: LocalStatus): boolean;
61
+ suppressDispatched(status: LocalStatus): boolean;
62
+ trackingStatus(status: LocalStatus): TrackingStatus;
63
+ }
64
+ /** Stock → durable handover → every tracking reference → optional invoice. No catches or retries. */
65
+ export declare function applyFulfillmentObservationEffects<LocalStatus, TrackingStatus>(input: FulfillmentObservationInput<LocalStatus, TrackingStatus>, policy: FulfillmentObservationStatusPolicy<LocalStatus, TrackingStatus>): Promise<void>;
66
+ export {};