@classytic/flow 0.1.4

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 (102) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/LICENSE +21 -0
  3. package/README.md +258 -0
  4. package/dist/allocation-policy-my_HfzdV.d.mts +23 -0
  5. package/dist/base-MWBqRFM2.mjs +16 -0
  6. package/dist/catalog-bridge-K8bdkncJ.d.mts +29 -0
  7. package/dist/cost-layer.port-iH9pvZqB.d.mts +30 -0
  8. package/dist/cost-layer.service-BQ1bs-XN.mjs +86 -0
  9. package/dist/cost-layer.service-DWmo9dQz.d.mts +53 -0
  10. package/dist/count.port-BRqwGbi3.d.mts +57 -0
  11. package/dist/counting/index.d.mts +2 -0
  12. package/dist/counting/index.mjs +2 -0
  13. package/dist/counting.service-BiQXqorv.mjs +232 -0
  14. package/dist/counting.service-CpAxU2G0.d.mts +74 -0
  15. package/dist/domain/contracts/index.d.mts +3 -0
  16. package/dist/domain/contracts/index.mjs +1 -0
  17. package/dist/domain/enums/index.d.mts +2 -0
  18. package/dist/domain/enums/index.mjs +4 -0
  19. package/dist/domain/index.d.mts +24 -0
  20. package/dist/domain/index.mjs +10 -0
  21. package/dist/domain/policies/index.d.mts +4 -0
  22. package/dist/domain/policies/index.mjs +1 -0
  23. package/dist/domain-D5cpMpR0.mjs +96 -0
  24. package/dist/domain-errors-D7S9ydNF.mjs +133 -0
  25. package/dist/enums-C3_z6aHC.mjs +82 -0
  26. package/dist/event-bus-BNmyoJb4.mjs +37 -0
  27. package/dist/event-bus-Um_xrcMY.d.mts +21 -0
  28. package/dist/event-emitter.port-BFh2pasY.d.mts +183 -0
  29. package/dist/event-types-BSqQOvXv.mjs +29 -0
  30. package/dist/events/index.d.mts +3 -0
  31. package/dist/events/index.mjs +3 -0
  32. package/dist/idempotency.port-CTC70JON.d.mts +55 -0
  33. package/dist/index-Bia4m8d2.d.mts +67 -0
  34. package/dist/index-BmNm3oNU2.d.mts +107 -0
  35. package/dist/index-C5PciI9P.d.mts +203 -0
  36. package/dist/index-CMTUKEK_.d.mts +308 -0
  37. package/dist/index-C_aEnozN.d.mts +220 -0
  38. package/dist/index-CulWO137.d.mts +107 -0
  39. package/dist/index-DFF0GJ4J.d.mts +36 -0
  40. package/dist/index-DsE7lZdO.d.mts +11 -0
  41. package/dist/index-DwO9IdNa.d.mts +1 -0
  42. package/dist/index-dtWUZr2a2.d.mts +350 -0
  43. package/dist/index.d.mts +128 -0
  44. package/dist/index.mjs +102 -0
  45. package/dist/insufficient-stock.error-Dyr4BYaV.mjs +15 -0
  46. package/dist/location.port-CValXIpb.d.mts +52 -0
  47. package/dist/lot.port-ChsmvZqs.d.mts +32 -0
  48. package/dist/models/index.d.mts +2 -0
  49. package/dist/models/index.mjs +2 -0
  50. package/dist/models-CHTMbp-G.mjs +1020 -0
  51. package/dist/move-group.port-DHGoQA3d.d.mts +56 -0
  52. package/dist/move-status-DkaFp2GD.mjs +38 -0
  53. package/dist/move.port-Qg1CYp7h.d.mts +89 -0
  54. package/dist/package.service-4tcAwBbr.mjs +95 -0
  55. package/dist/package.service-C605NaBQ.d.mts +42 -0
  56. package/dist/packaging/index.d.mts +2 -0
  57. package/dist/packaging/index.mjs +2 -0
  58. package/dist/procurement/index.d.mts +2 -0
  59. package/dist/procurement/index.mjs +2 -0
  60. package/dist/quant.port-BBa66PBT.d.mts +42 -0
  61. package/dist/removal-policy-BItBB8FD.d.mts +29 -0
  62. package/dist/replenishment-rule.port-DnEYtbyD.d.mts +78 -0
  63. package/dist/replenishment.service-BT9P-HKM.mjs +284 -0
  64. package/dist/replenishment.service-HO0sDhB_.d.mts +89 -0
  65. package/dist/reporting/index.d.mts +2 -0
  66. package/dist/reporting/index.mjs +2 -0
  67. package/dist/reporting-CL5ffrKM.mjs +243 -0
  68. package/dist/repositories/index.d.mts +2 -0
  69. package/dist/repositories/index.mjs +2 -0
  70. package/dist/repositories-nZXJKvLW.mjs +842 -0
  71. package/dist/reservation-status-ZfuTaWG0.mjs +22 -0
  72. package/dist/reservation.port-l9NFQ0si.d.mts +85 -0
  73. package/dist/reservations/index.d.mts +2 -0
  74. package/dist/reservations/index.mjs +2 -0
  75. package/dist/reservations-Cg4wN0QB.mjs +112 -0
  76. package/dist/routing/index.d.mts +362 -0
  77. package/dist/routing/index.mjs +582 -0
  78. package/dist/runtime-config-C0ggPkiK.mjs +40 -0
  79. package/dist/runtime-config-CQLtPPqY.d.mts +38 -0
  80. package/dist/scan-token-CNM9QVLY.d.mts +26 -0
  81. package/dist/scanning/index.d.mts +45 -0
  82. package/dist/scanning/index.mjs +228 -0
  83. package/dist/services/index.d.mts +8 -0
  84. package/dist/services/index.mjs +8 -0
  85. package/dist/services-_lLO4Xbl.mjs +1009 -0
  86. package/dist/stock-move-group-C0DqUfPY.mjs +88 -0
  87. package/dist/stock-package-BIarxbDS.d.mts +19 -0
  88. package/dist/stock-quant-CZhgvTu7.d.mts +41 -0
  89. package/dist/tenant-guard-6Ne-BILP.mjs +12 -0
  90. package/dist/tenant-isolation.error-D3OcKUdx.mjs +11 -0
  91. package/dist/trace.service-B9vAh-l-.d.mts +55 -0
  92. package/dist/trace.service-DE6Eh8_8.mjs +71 -0
  93. package/dist/traceability/index.d.mts +2 -0
  94. package/dist/traceability/index.mjs +2 -0
  95. package/dist/types/index.d.mts +2 -0
  96. package/dist/types/index.mjs +1 -0
  97. package/dist/unit-of-work.port-CWEkrDKu.d.mts +17 -0
  98. package/dist/valuation/index.d.mts +78 -0
  99. package/dist/valuation/index.mjs +103 -0
  100. package/dist/valuation-policy-Dco8c9Vw.d.mts +14 -0
  101. package/dist/virtual-locations-B9zXqPdi.d.mts +38 -0
  102. package/package.json +155 -0
@@ -0,0 +1,22 @@
1
+ //#region src/domain/enums/group-type.ts
2
+ const GroupType = {
3
+ receipt: "receipt",
4
+ transfer: "transfer",
5
+ shipment: "shipment",
6
+ return: "return",
7
+ adjustment: "adjustment",
8
+ pick_wave: "pick_wave",
9
+ count_reconciliation: "count_reconciliation"
10
+ };
11
+ //#endregion
12
+ //#region src/domain/enums/reservation-status.ts
13
+ const ReservationStatus = {
14
+ active: "active",
15
+ partially_consumed: "partially_consumed",
16
+ consumed: "consumed",
17
+ released: "released",
18
+ expired: "expired",
19
+ cancelled: "cancelled"
20
+ };
21
+ //#endregion
22
+ export { GroupType as n, ReservationStatus as t };
@@ -0,0 +1,85 @@
1
+ import { a as ReservationStatus } from "./index-CulWO137.mjs";
2
+ import { t as FlowContext } from "./index-DFF0GJ4J.mjs";
3
+ import { t as TransactionSession } from "./unit-of-work.port-CWEkrDKu.mjs";
4
+
5
+ //#region src/domain/entities/inventory-node.d.ts
6
+ interface Address {
7
+ street?: string;
8
+ city?: string;
9
+ state?: string;
10
+ postalCode?: string;
11
+ country?: string;
12
+ coordinates?: {
13
+ lat: number;
14
+ lng: number;
15
+ };
16
+ }
17
+ interface InventoryNode {
18
+ _id: string;
19
+ organizationId: string;
20
+ code: string;
21
+ name: string;
22
+ type: string;
23
+ status: 'active' | 'inactive';
24
+ timezone?: string;
25
+ currency?: string;
26
+ address?: Address;
27
+ capabilities?: string[];
28
+ isDefault?: boolean;
29
+ metadata?: Record<string, unknown>;
30
+ createdAt?: Date;
31
+ updatedAt?: Date;
32
+ }
33
+ //#endregion
34
+ //#region src/domain/entities/reservation.d.ts
35
+ interface Reservation {
36
+ _id: string;
37
+ organizationId: string;
38
+ reservationType: 'soft' | 'hard';
39
+ ownerType: string;
40
+ ownerId: string;
41
+ skuRef: string;
42
+ locationId: string;
43
+ lotId?: string;
44
+ quantity: number;
45
+ quantityConsumed?: number;
46
+ status: ReservationStatus;
47
+ expiresAt?: Date;
48
+ allocationPolicy?: string;
49
+ createdBy?: string;
50
+ createdAt?: Date;
51
+ releasedAt?: Date;
52
+ updatedAt?: Date;
53
+ }
54
+ //#endregion
55
+ //#region src/domain/ports/node.port.d.ts
56
+ interface NodePort {
57
+ findById(id: string, ctx: FlowContext, session?: TransactionSession): Promise<InventoryNode | null>;
58
+ findDefault(ctx: FlowContext, session?: TransactionSession): Promise<InventoryNode | null>;
59
+ list(ctx: FlowContext, session?: TransactionSession): Promise<InventoryNode[]>;
60
+ create(input: Omit<InventoryNode, '_id' | 'createdAt' | 'updatedAt'>, session?: TransactionSession): Promise<InventoryNode>;
61
+ update(id: string, updates: Partial<InventoryNode>, ctx: FlowContext, session?: TransactionSession): Promise<InventoryNode>;
62
+ }
63
+ //#endregion
64
+ //#region src/domain/ports/reservation.port.d.ts
65
+ interface CreateReservationInput {
66
+ organizationId: string;
67
+ reservationType: 'soft' | 'hard';
68
+ ownerType: string;
69
+ ownerId: string;
70
+ skuRef: string;
71
+ locationId: string;
72
+ lotId?: string;
73
+ quantity: number;
74
+ expiresAt?: Date;
75
+ allocationPolicy?: string;
76
+ }
77
+ interface ReservationPort {
78
+ create(input: CreateReservationInput, session?: TransactionSession): Promise<Reservation>;
79
+ findById(id: string, ctx: FlowContext, session?: TransactionSession): Promise<Reservation | null>;
80
+ findByOwner(ownerType: string, ownerId: string, ctx: FlowContext, session?: TransactionSession): Promise<Reservation[]>;
81
+ updateStatus(id: string, status: ReservationStatus, updates: Partial<Reservation>, session?: TransactionSession): Promise<Reservation>;
82
+ findExpired(asOf: Date, ctx: FlowContext, session?: TransactionSession): Promise<Reservation[]>;
83
+ }
84
+ //#endregion
85
+ export { Address as a, Reservation as i, ReservationPort as n, InventoryNode as o, NodePort as r, CreateReservationInput as t };
@@ -0,0 +1,2 @@
1
+ import { a as FefoStrategy, i as allocateFromSorted, n as LifoStrategy, o as ExactLotStrategy, r as FifoStrategy, t as NearestStrategy } from "../index-Bia4m8d2.mjs";
2
+ export { ExactLotStrategy, FefoStrategy, FifoStrategy, LifoStrategy, NearestStrategy, allocateFromSorted };
@@ -0,0 +1,2 @@
1
+ import { a as FifoStrategy, i as FefoStrategy, n as ExactLotStrategy, o as allocateFromSorted, r as LifoStrategy, t as NearestStrategy } from "../reservations-Cg4wN0QB.mjs";
2
+ export { ExactLotStrategy, FefoStrategy, FifoStrategy, LifoStrategy, NearestStrategy, allocateFromSorted };
@@ -0,0 +1,112 @@
1
+ //#region src/reservations/fifo.strategy.ts
2
+ /**
3
+ * FIFO allocation — consume oldest stock first (by inDate).
4
+ * Default strategy for most operations.
5
+ */
6
+ var FifoStrategy = class {
7
+ name = "fifo";
8
+ resolve(_skuRef, quantity, candidates) {
9
+ return allocateFromSorted([...candidates].sort((a, b) => new Date(a.inDate).getTime() - new Date(b.inDate).getTime()), quantity);
10
+ }
11
+ };
12
+ /**
13
+ * Shared allocation logic — iterates sorted candidates and picks until quantity is met.
14
+ * Used by all strategies after sorting.
15
+ */
16
+ function allocateFromSorted(sorted, quantity) {
17
+ const allocations = [];
18
+ let remaining = quantity;
19
+ for (const q of sorted) {
20
+ if (remaining <= 0) break;
21
+ const available = q.quantityOnHand - q.quantityReserved;
22
+ if (available <= 0) continue;
23
+ const take = Math.min(available, remaining);
24
+ allocations.push({
25
+ quantId: q._id,
26
+ locationId: q.locationId,
27
+ lotId: q.lotId,
28
+ quantity: take
29
+ });
30
+ remaining -= take;
31
+ }
32
+ return {
33
+ fulfilled: remaining <= 0,
34
+ allocations,
35
+ shortfall: Math.max(0, remaining)
36
+ };
37
+ }
38
+ //#endregion
39
+ //#region src/reservations/fefo.strategy.ts
40
+ /**
41
+ * FEFO allocation — consume nearest-expiry stock first.
42
+ * Requires quants to carry lot expiry info. Quants without expiry sort last.
43
+ *
44
+ * Used for perishable goods: food, pharma, cosmetics.
45
+ */
46
+ var FefoStrategy = class {
47
+ name = "fefo";
48
+ constructor(minShelfLifeDays) {
49
+ this.minShelfLifeDays = minShelfLifeDays;
50
+ }
51
+ resolve(_skuRef, quantity, candidates) {
52
+ let eligible = candidates;
53
+ if (this.minShelfLifeDays != null) {
54
+ const threshold = new Date(Date.now() + this.minShelfLifeDays * 864e5);
55
+ eligible = candidates.filter((q) => !q.lotExpiresAt || new Date(q.lotExpiresAt).getTime() > threshold.getTime());
56
+ }
57
+ return allocateFromSorted([...eligible].sort((a, b) => {
58
+ return (a.lotExpiresAt ? new Date(a.lotExpiresAt).getTime() : Number.POSITIVE_INFINITY) - (b.lotExpiresAt ? new Date(b.lotExpiresAt).getTime() : Number.POSITIVE_INFINITY);
59
+ }), quantity);
60
+ }
61
+ };
62
+ //#endregion
63
+ //#region src/reservations/lifo.strategy.ts
64
+ /**
65
+ * LIFO allocation — consume newest stock first (by inDate DESC).
66
+ * Useful when freshness matters less and you want to keep oldest stock for auditing.
67
+ */
68
+ var LifoStrategy = class {
69
+ name = "lifo";
70
+ resolve(_skuRef, quantity, candidates) {
71
+ return allocateFromSorted([...candidates].sort((a, b) => new Date(b.inDate).getTime() - new Date(a.inDate).getTime()), quantity);
72
+ }
73
+ };
74
+ //#endregion
75
+ //#region src/reservations/exact-lot.strategy.ts
76
+ /**
77
+ * Exact-lot allocation — only allocate from a specific lot.
78
+ * Used when a customer or regulation requires a specific batch.
79
+ */
80
+ var ExactLotStrategy = class {
81
+ name = "exact_lot";
82
+ constructor(targetLotId) {
83
+ this.targetLotId = targetLotId;
84
+ }
85
+ resolve(_skuRef, quantity, candidates) {
86
+ const filtered = candidates.filter((q) => q.lotId === this.targetLotId);
87
+ if (filtered.length === 0) return {
88
+ fulfilled: false,
89
+ allocations: [],
90
+ shortfall: quantity
91
+ };
92
+ return allocateFromSorted([...filtered].sort((a, b) => new Date(a.inDate).getTime() - new Date(b.inDate).getTime()), quantity);
93
+ }
94
+ };
95
+ //#endregion
96
+ //#region src/reservations/nearest.strategy.ts
97
+ /**
98
+ * Nearest allocation — consume stock closest to pick face (by location sortOrder ASC).
99
+ * Minimizes warehouse travel distance.
100
+ *
101
+ * Requires quants to carry locationSortOrder (set by repository join or denormalized).
102
+ */
103
+ var NearestStrategy = class {
104
+ name = "nearest";
105
+ resolve(_skuRef, quantity, candidates) {
106
+ return allocateFromSorted([...candidates].sort((a, b) => {
107
+ return (a.locationSortOrder ?? Number.MAX_SAFE_INTEGER) - (b.locationSortOrder ?? Number.MAX_SAFE_INTEGER);
108
+ }), quantity);
109
+ }
110
+ };
111
+ //#endregion
112
+ export { FifoStrategy as a, FefoStrategy as i, ExactLotStrategy as n, allocateFromSorted as o, LifoStrategy as r, NearestStrategy as t };
@@ -0,0 +1,362 @@
1
+ import { n as MovePort, r as StockMove } from "../move.port-Qg1CYp7h.mjs";
2
+ import { t as FlowContext } from "../index-DFF0GJ4J.mjs";
3
+ import { n as Location, t as LocationPort } from "../location.port-CValXIpb.mjs";
4
+ import { n as StockQuant } from "../stock-quant-CZhgvTu7.mjs";
5
+ import { r as QuantPort } from "../quant.port-BBa66PBT.mjs";
6
+ import { n as AllocationResult } from "../allocation-policy-my_HfzdV.mjs";
7
+ import { n as PutawayPolicy, t as RemovalPolicy } from "../removal-policy-BItBB8FD.mjs";
8
+
9
+ //#region src/routing/cross-dock.engine.d.ts
10
+ /**
11
+ * Per-destination cross-dock assignment.
12
+ * Each assignment maps exact quantities to exact shipping destinations.
13
+ */
14
+ interface CrossDockAssignment {
15
+ destinationLocationId: string;
16
+ quantity: number;
17
+ moveIds: string[];
18
+ }
19
+ /**
20
+ * Cross-dock evaluation result with multi-destination routing.
21
+ */
22
+ interface CrossDockResult {
23
+ hasDemand: boolean;
24
+ demandQuantity: number;
25
+ crossDockQuantity: number;
26
+ remainingToStorage: number;
27
+ /** Per-destination assignments (replaces single crossDockDestination) */
28
+ assignments: CrossDockAssignment[];
29
+ /** @deprecated Use assignments[0].destinationLocationId — kept for backward compat */
30
+ crossDockDestination: string | null;
31
+ waitingMoveIds: string[];
32
+ }
33
+ /**
34
+ * Cross-Dock Engine
35
+ *
36
+ * Evaluates whether incoming stock should bypass storage and route directly
37
+ * to shipping destinations. Supports multi-destination routing:
38
+ *
39
+ * Normal: Receive → Storage → Pick → Pack → Ship
40
+ * Cross-dock: Receive → Ship-Dock-1 (15 units for Order A)
41
+ * → Ship-Dock-2 (10 units for Order B)
42
+ * → Storage (remaining 5 units)
43
+ */
44
+ declare class CrossDockEngine {
45
+ private movePort;
46
+ constructor(movePort: MovePort, _quantPort: QuantPort);
47
+ evaluate(skuRef: string, incomingQuantity: number, _nodeId: string, ctx: FlowContext): Promise<CrossDockResult>;
48
+ }
49
+ //#endregion
50
+ //#region src/routing/putaway.engine.d.ts
51
+ /**
52
+ * Putaway engine — resolves where received goods should be stored.
53
+ * Tries registered strategies in priority order, then falls back to default.
54
+ */
55
+ declare class PutawayEngine {
56
+ private defaultLocationResolver;
57
+ private strategies;
58
+ constructor(_locationPort: LocationPort, defaultLocationResolver: (nodeId: string, ctx: FlowContext) => Promise<string | null>);
59
+ registerStrategy(strategy: PutawayPolicy): void;
60
+ resolve(skuRef: string, quantity: number, nodeId: string, context: {
61
+ lotId?: string;
62
+ vendorRef?: string;
63
+ skuCategory?: string;
64
+ }, ctx: FlowContext): Promise<{
65
+ locationId: string;
66
+ }>;
67
+ }
68
+ //#endregion
69
+ //#region src/routing/removal.engine.d.ts
70
+ /**
71
+ * Removal engine — delegates stock removal decisions to a RemovalPolicy.
72
+ */
73
+ declare class RemovalEngine {
74
+ private defaultPolicy;
75
+ constructor(defaultPolicy: RemovalPolicy);
76
+ resolve(skuRef: string, quantity: number, candidates: StockQuant[]): AllocationResult;
77
+ }
78
+ //#endregion
79
+ //#region src/routing/route-expander.d.ts
80
+ interface RouteStep {
81
+ sourceLocationType: string;
82
+ destinationLocationType: string;
83
+ operationType: string;
84
+ }
85
+ interface RouteTemplate {
86
+ name: string;
87
+ steps: RouteStep[];
88
+ }
89
+ interface RouteConfig {
90
+ receptionSteps: 1 | 2 | 3;
91
+ deliverySteps: 1 | 2 | 3;
92
+ customRoutes?: RouteTemplate[];
93
+ }
94
+ interface ExpandedRoute {
95
+ steps: Array<{
96
+ sourceLocationId: string;
97
+ destinationLocationId: string;
98
+ operationType: string;
99
+ sequence: number;
100
+ }>;
101
+ }
102
+ /**
103
+ * Interface for resolving location types to actual location IDs.
104
+ * Consumer provides this — typically queries Location by (nodeId, type).
105
+ */
106
+ interface LocationResolver {
107
+ resolveByType(nodeId: string, locationType: string): Promise<string>;
108
+ }
109
+ declare class RouteExpander {
110
+ private config;
111
+ private customRoutes;
112
+ constructor(config?: RouteConfig);
113
+ /**
114
+ * Register a custom route template.
115
+ */
116
+ registerRoute(route: RouteTemplate): void;
117
+ /**
118
+ * Expand a high-level operation into planned move steps.
119
+ * Resolves location types to actual location IDs using the LocationResolver.
120
+ *
121
+ * Route matching priority (6-level resolution):
122
+ * 1. Demand-specific routes (options.routeId) — highest
123
+ * 2. Packaging/UoM routes
124
+ * 3. SKU-specific routes
125
+ * 4. SKU category routes
126
+ * 5. Node/warehouse routes
127
+ * 6. Operation type default route — lowest
128
+ */
129
+ expand(operationType: 'receipt' | 'shipment' | 'transfer', nodeId: string, locations: LocationResolver, options?: {
130
+ skuRef?: string;
131
+ routeId?: string;
132
+ }): Promise<ExpandedRoute>;
133
+ /**
134
+ * Get the default route template based on operation type and configured step count.
135
+ *
136
+ * Complexity modes:
137
+ * - One-step: ship (small shop)
138
+ * - Two-step: pick → ship (standard warehouse)
139
+ * - Three-step: pick → pack → ship (e-commerce fulfillment)
140
+ *
141
+ * Cross-dock (transfer): receive → ship (bypass storage)
142
+ */
143
+ getDefaultTemplate(operationType: 'receipt' | 'shipment' | 'transfer'): RouteStep[];
144
+ /**
145
+ * Auto-generated reception routes per warehouse:
146
+ * one_step: [vendor → stock]
147
+ * two_steps: [vendor → input, input → stock]
148
+ * three_steps: [vendor → input, input → qc, qc → stock]
149
+ */
150
+ private getReceptionTemplate;
151
+ /**
152
+ * Auto-generated delivery routes per warehouse:
153
+ * one_step: [stock → customer]
154
+ * two_steps: [stock → shipping, shipping → customer]
155
+ * three_steps: [stock → packing, packing → shipping, shipping → customer]
156
+ */
157
+ private getDeliveryTemplate;
158
+ /**
159
+ * Resolve location type references to actual location IDs.
160
+ */
161
+ private resolveSteps;
162
+ }
163
+ //#endregion
164
+ //#region src/routing/strategies/abc-velocity.strategy.d.ts
165
+ type VelocityClass = 'A' | 'B' | 'C';
166
+ interface AbcZoneMapping {
167
+ A: string;
168
+ B: string;
169
+ C: string;
170
+ }
171
+ /**
172
+ * ABC-velocity putaway strategy.
173
+ * Classifies SKUs by velocity (A/B/C) and routes to appropriate zones.
174
+ * A-items go near dock (low sortOrder), C-items go far back.
175
+ */
176
+ declare class AbcVelocityStrategy implements PutawayPolicy {
177
+ private velocityClassifier;
178
+ private zoneMappings;
179
+ readonly name = "abc_velocity";
180
+ constructor(velocityClassifier: (skuRef: string) => VelocityClass, zoneMappings: AbcZoneMapping);
181
+ resolve(skuRef: string, _quantity: number, _nodeId: string, _context: {
182
+ lotId?: string;
183
+ vendorRef?: string;
184
+ skuCategory?: string;
185
+ }): Promise<{
186
+ locationId: string;
187
+ } | null>;
188
+ }
189
+ //#endregion
190
+ //#region src/routing/strategies/category-zone.strategy.d.ts
191
+ /**
192
+ * Category-zone putaway strategy.
193
+ * Routes goods to zones based on their SKU category.
194
+ */
195
+ declare class CategoryZoneStrategy implements PutawayPolicy {
196
+ private categoryZoneMap;
197
+ readonly name = "category_zone";
198
+ constructor(categoryZoneMap: Map<string, string>);
199
+ resolve(_skuRef: string, _quantity: number, _nodeId: string, context: {
200
+ lotId?: string;
201
+ vendorRef?: string;
202
+ skuCategory?: string;
203
+ }): Promise<{
204
+ locationId: string;
205
+ } | null>;
206
+ }
207
+ //#endregion
208
+ //#region src/routing/strategies/closest-to-pick.strategy.d.ts
209
+ /**
210
+ * Closest-to-pick putaway strategy.
211
+ * Selects the storage location with the lowest sortOrder (closest to pick face)
212
+ * that has remaining capacity.
213
+ */
214
+ declare class ClosestToPickStrategy implements PutawayPolicy {
215
+ private locationPort;
216
+ private ctx;
217
+ readonly name = "closest_to_pick";
218
+ constructor(locationPort: LocationPort, ctx: FlowContext);
219
+ resolve(_skuRef: string, quantity: number, nodeId: string, _context: {
220
+ lotId?: string;
221
+ vendorRef?: string;
222
+ skuCategory?: string;
223
+ }): Promise<{
224
+ locationId: string;
225
+ } | null>;
226
+ }
227
+ //#endregion
228
+ //#region src/routing/strategies/empty-bin.strategy.d.ts
229
+ /**
230
+ * Empty-bin putaway strategy.
231
+ * Finds the first storage location in the node that has zero quants.
232
+ */
233
+ declare class EmptyBinStrategy implements PutawayPolicy {
234
+ private locationPort;
235
+ private quantPort;
236
+ private ctx;
237
+ readonly name = "empty_bin";
238
+ constructor(locationPort: LocationPort, quantPort: QuantPort, ctx: FlowContext);
239
+ resolve(_skuRef: string, _quantity: number, nodeId: string, _context: {
240
+ lotId?: string;
241
+ vendorRef?: string;
242
+ skuCategory?: string;
243
+ }): Promise<{
244
+ locationId: string;
245
+ } | null>;
246
+ }
247
+ //#endregion
248
+ //#region src/routing/strategies/fixed-location.strategy.d.ts
249
+ /**
250
+ * Fixed-location putaway strategy.
251
+ * Maps specific SKUs to predetermined storage locations.
252
+ */
253
+ declare class FixedLocationStrategy implements PutawayPolicy {
254
+ private skuLocationMap;
255
+ readonly name = "fixed_location";
256
+ constructor(skuLocationMap: Map<string, string>);
257
+ resolve(skuRef: string, _quantity: number, _nodeId: string, _context: {
258
+ lotId?: string;
259
+ vendorRef?: string;
260
+ skuCategory?: string;
261
+ }): Promise<{
262
+ locationId: string;
263
+ } | null>;
264
+ }
265
+ //#endregion
266
+ //#region src/routing/wave.engine.d.ts
267
+ interface ConsolidatedPick {
268
+ skuRef: string;
269
+ locationId: string;
270
+ totalQuantity: number;
271
+ moveIds: string[];
272
+ sortKey: string;
273
+ }
274
+ interface WaveSummary {
275
+ totalMoves: number;
276
+ totalQuantity: number;
277
+ uniqueLocations: number;
278
+ uniqueSkus: number;
279
+ }
280
+ /** Cart constraint for sub-wave batching */
281
+ interface CartConstraints {
282
+ maxWeight?: number;
283
+ maxVolume?: number;
284
+ maxItems?: number;
285
+ }
286
+ /** A single cart-load (sub-wave) */
287
+ interface CartBatch {
288
+ picks: ConsolidatedPick[];
289
+ totalWeight: number;
290
+ totalVolume: number;
291
+ totalItems: number;
292
+ }
293
+ /**
294
+ * Wave Engine — production-grade pick-path optimization.
295
+ *
296
+ * Two sorting modes:
297
+ * 1. **sortOrder** (simple) — single integer, works for small warehouses
298
+ * 2. **coordinates** (3D) — zone/aisle/bay/level/bin tuple, serpentine path for large fulfillment centers
299
+ *
300
+ * Also supports:
301
+ * - Location consolidation (merge picks for same SKU at same bin)
302
+ * - Weight/volume/item batching (split into cart-sized sub-waves with pick splitting)
303
+ * - Wave summary for display
304
+ */
305
+ declare class WaveEngine {
306
+ /**
307
+ * Sort moves by location for optimal pick path.
308
+ * Uses 3D coordinates if available, falls back to sortOrder.
309
+ * Does not mutate input.
310
+ */
311
+ optimizePickPath(moves: StockMove[], locationMap?: Map<string, Location>): StockMove[];
312
+ /**
313
+ * Consolidate moves for same SKU at same location into single pick lines.
314
+ */
315
+ consolidateByLocation(moves: StockMove[], locationMap?: Map<string, Location>): ConsolidatedPick[];
316
+ /**
317
+ * Split a consolidated pick list into cart-sized batches.
318
+ * Each batch respects weight, volume, and item count constraints.
319
+ * Oversized picks are split across multiple carts — no quantity is lost.
320
+ */
321
+ batchIntoCarts(picks: ConsolidatedPick[], constraints: CartConstraints, skuWeights?: Map<string, number>, skuVolumes?: Map<string, number>): CartBatch[];
322
+ /**
323
+ * Create a summary of the wave.
324
+ */
325
+ createWaveSummary(moves: StockMove[]): WaveSummary;
326
+ /**
327
+ * Build a lexicographic sort key from location coordinates or metadata.
328
+ *
329
+ * Uses boustrophedon (serpentine/ox-plow) traversal for 3D coordinates:
330
+ * - Odd aisles: bays ascending (1→2→3→…)
331
+ * - Even aisles: bays descending (…→3→2→1)
332
+ * This eliminates dead-walking back to the front of each aisle.
333
+ */
334
+ private buildSortKey;
335
+ private buildCoordinateSortKey;
336
+ private buildMetadataSortKey;
337
+ private padSortOrder;
338
+ private createEmptyBatch;
339
+ private addPickToBatch;
340
+ private wouldExceedConstraints;
341
+ /**
342
+ * Flush the current batch, optionally fitting a partial quantity first.
343
+ * Item-count overflow skips partial fitting (the constraint is on lines, not units).
344
+ */
345
+ private flushAndFillPartial;
346
+ /**
347
+ * Recalculate remaining quantity for a pick after batches have been flushed.
348
+ */
349
+ private recalculateRemaining;
350
+ /**
351
+ * Calculate how many units fit in the cart. Returns `wanted` if no
352
+ * weight/volume constraints apply (item-count-only or unconstrained).
353
+ */
354
+ private calculateFittingQuantity;
355
+ /**
356
+ * Maximum units that fit in the remaining cart capacity by weight/volume.
357
+ * Returns 0 if even 1 unit won't fit.
358
+ */
359
+ private maxFittingUnits;
360
+ }
361
+ //#endregion
362
+ export { AbcVelocityStrategy, type AbcZoneMapping, CategoryZoneStrategy, ClosestToPickStrategy, type ConsolidatedPick, type CrossDockAssignment, CrossDockEngine, type CrossDockResult, EmptyBinStrategy, type ExpandedRoute, FixedLocationStrategy, type LocationResolver, PutawayEngine, RemovalEngine, type RouteConfig, RouteExpander, type RouteStep, type RouteTemplate, type VelocityClass, WaveEngine, type WaveSummary };