@higher.archi/boe 1.0.29 → 1.0.31

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 (241) hide show
  1. package/dist/core/evaluation/decay.d.ts +13 -2
  2. package/dist/core/evaluation/decay.d.ts.map +1 -1
  3. package/dist/core/evaluation/decay.js +24 -0
  4. package/dist/core/evaluation/decay.js.map +1 -1
  5. package/dist/core/types/rule.d.ts +25 -1
  6. package/dist/core/types/rule.d.ts.map +1 -1
  7. package/dist/core/types/rule.js +28 -0
  8. package/dist/core/types/rule.js.map +1 -1
  9. package/dist/engines/bayesian/index.d.ts +1 -1
  10. package/dist/engines/bayesian/index.d.ts.map +1 -1
  11. package/dist/engines/bayesian/index.js +2 -1
  12. package/dist/engines/bayesian/index.js.map +1 -1
  13. package/dist/engines/bayesian/types.d.ts +10 -1
  14. package/dist/engines/bayesian/types.d.ts.map +1 -1
  15. package/dist/engines/bayesian/types.js +16 -1
  16. package/dist/engines/bayesian/types.js.map +1 -1
  17. package/dist/engines/constraint/types.d.ts +36 -5
  18. package/dist/engines/constraint/types.d.ts.map +1 -1
  19. package/dist/engines/constraint/types.js +44 -1
  20. package/dist/engines/constraint/types.js.map +1 -1
  21. package/dist/engines/decay/index.d.ts +1 -1
  22. package/dist/engines/decay/index.d.ts.map +1 -1
  23. package/dist/engines/decay/index.js +5 -1
  24. package/dist/engines/decay/index.js.map +1 -1
  25. package/dist/engines/decay/types.d.ts +26 -4
  26. package/dist/engines/decay/types.d.ts.map +1 -1
  27. package/dist/engines/decay/types.js +30 -1
  28. package/dist/engines/decay/types.js.map +1 -1
  29. package/dist/engines/defeasible/index.d.ts +1 -1
  30. package/dist/engines/defeasible/index.d.ts.map +1 -1
  31. package/dist/engines/defeasible/index.js +8 -1
  32. package/dist/engines/defeasible/index.js.map +1 -1
  33. package/dist/engines/defeasible/types.d.ts +40 -5
  34. package/dist/engines/defeasible/types.d.ts.map +1 -1
  35. package/dist/engines/defeasible/types.js +56 -1
  36. package/dist/engines/defeasible/types.js.map +1 -1
  37. package/dist/engines/ensemble/index.d.ts +1 -0
  38. package/dist/engines/ensemble/index.d.ts.map +1 -1
  39. package/dist/engines/ensemble/index.js +5 -1
  40. package/dist/engines/ensemble/index.js.map +1 -1
  41. package/dist/engines/ensemble/types.d.ts +17 -2
  42. package/dist/engines/ensemble/types.d.ts.map +1 -1
  43. package/dist/engines/ensemble/types.js +23 -0
  44. package/dist/engines/ensemble/types.js.map +1 -1
  45. package/dist/engines/expert/index.d.ts +1 -1
  46. package/dist/engines/expert/index.d.ts.map +1 -1
  47. package/dist/engines/expert/index.js +3 -1
  48. package/dist/engines/expert/index.js.map +1 -1
  49. package/dist/engines/expert/types.d.ts +11 -1
  50. package/dist/engines/expert/types.d.ts.map +1 -1
  51. package/dist/engines/expert/types.js +18 -1
  52. package/dist/engines/expert/types.js.map +1 -1
  53. package/dist/engines/fuzzy/fuzzy.types.d.ts +65 -8
  54. package/dist/engines/fuzzy/fuzzy.types.d.ts.map +1 -1
  55. package/dist/engines/fuzzy/fuzzy.types.js +89 -1
  56. package/dist/engines/fuzzy/fuzzy.types.js.map +1 -1
  57. package/dist/engines/loyalty/compiler.d.ts +11 -0
  58. package/dist/engines/loyalty/compiler.d.ts.map +1 -0
  59. package/dist/engines/loyalty/compiler.js +144 -0
  60. package/dist/engines/loyalty/compiler.js.map +1 -0
  61. package/dist/engines/loyalty/engine.d.ts +76 -0
  62. package/dist/engines/loyalty/engine.d.ts.map +1 -0
  63. package/dist/engines/loyalty/engine.js +132 -0
  64. package/dist/engines/loyalty/engine.js.map +1 -0
  65. package/dist/engines/loyalty/index.d.ts +9 -0
  66. package/dist/engines/loyalty/index.d.ts.map +1 -0
  67. package/dist/engines/loyalty/index.js +24 -0
  68. package/dist/engines/loyalty/index.js.map +1 -0
  69. package/dist/engines/loyalty/strategy.d.ts +35 -0
  70. package/dist/engines/loyalty/strategy.d.ts.map +1 -0
  71. package/dist/engines/loyalty/strategy.js +405 -0
  72. package/dist/engines/loyalty/strategy.js.map +1 -0
  73. package/dist/engines/loyalty/types.d.ts +221 -0
  74. package/dist/engines/loyalty/types.d.ts.map +1 -0
  75. package/dist/engines/loyalty/types.js +51 -0
  76. package/dist/engines/loyalty/types.js.map +1 -0
  77. package/dist/engines/menu-engineering/compiler.d.ts +11 -0
  78. package/dist/engines/menu-engineering/compiler.d.ts.map +1 -0
  79. package/dist/engines/menu-engineering/compiler.js +119 -0
  80. package/dist/engines/menu-engineering/compiler.js.map +1 -0
  81. package/dist/engines/menu-engineering/engine.d.ts +32 -0
  82. package/dist/engines/menu-engineering/engine.d.ts.map +1 -0
  83. package/dist/engines/menu-engineering/engine.js +40 -0
  84. package/dist/engines/menu-engineering/engine.js.map +1 -0
  85. package/dist/engines/menu-engineering/index.d.ts +9 -0
  86. package/dist/engines/menu-engineering/index.d.ts.map +1 -0
  87. package/dist/engines/menu-engineering/index.js +21 -0
  88. package/dist/engines/menu-engineering/index.js.map +1 -0
  89. package/dist/engines/menu-engineering/strategy.d.ts +18 -0
  90. package/dist/engines/menu-engineering/strategy.d.ts.map +1 -0
  91. package/dist/engines/menu-engineering/strategy.js +318 -0
  92. package/dist/engines/menu-engineering/strategy.js.map +1 -0
  93. package/dist/engines/menu-engineering/types.d.ts +187 -0
  94. package/dist/engines/menu-engineering/types.d.ts.map +1 -0
  95. package/dist/engines/menu-engineering/types.js +27 -0
  96. package/dist/engines/menu-engineering/types.js.map +1 -0
  97. package/dist/engines/monte-carlo/index.d.ts +1 -1
  98. package/dist/engines/monte-carlo/index.d.ts.map +1 -1
  99. package/dist/engines/monte-carlo/index.js +5 -1
  100. package/dist/engines/monte-carlo/index.js.map +1 -1
  101. package/dist/engines/monte-carlo/types.d.ts +16 -1
  102. package/dist/engines/monte-carlo/types.d.ts.map +1 -1
  103. package/dist/engines/monte-carlo/types.js +23 -1
  104. package/dist/engines/monte-carlo/types.js.map +1 -1
  105. package/dist/engines/negotiation/index.d.ts +1 -0
  106. package/dist/engines/negotiation/index.d.ts.map +1 -1
  107. package/dist/engines/negotiation/index.js +7 -1
  108. package/dist/engines/negotiation/index.js.map +1 -1
  109. package/dist/engines/negotiation/types.d.ts +23 -4
  110. package/dist/engines/negotiation/types.d.ts.map +1 -1
  111. package/dist/engines/negotiation/types.js +27 -0
  112. package/dist/engines/negotiation/types.js.map +1 -1
  113. package/dist/engines/prediction/index.d.ts +1 -1
  114. package/dist/engines/prediction/index.d.ts.map +1 -1
  115. package/dist/engines/prediction/index.js +6 -1
  116. package/dist/engines/prediction/index.js.map +1 -1
  117. package/dist/engines/prediction/types.d.ts +35 -5
  118. package/dist/engines/prediction/types.d.ts.map +1 -1
  119. package/dist/engines/prediction/types.js +39 -1
  120. package/dist/engines/prediction/types.js.map +1 -1
  121. package/dist/engines/pricing/index.d.ts +2 -2
  122. package/dist/engines/pricing/index.d.ts.map +1 -1
  123. package/dist/engines/pricing/index.js +3 -1
  124. package/dist/engines/pricing/index.js.map +1 -1
  125. package/dist/engines/pricing/types.d.ts +15 -1
  126. package/dist/engines/pricing/types.d.ts.map +1 -1
  127. package/dist/engines/pricing/types.js +16 -1
  128. package/dist/engines/pricing/types.js.map +1 -1
  129. package/dist/engines/ranking/index.d.ts +1 -1
  130. package/dist/engines/ranking/index.d.ts.map +1 -1
  131. package/dist/engines/ranking/index.js +6 -1
  132. package/dist/engines/ranking/index.js.map +1 -1
  133. package/dist/engines/ranking/types.d.ts +32 -5
  134. package/dist/engines/ranking/types.d.ts.map +1 -1
  135. package/dist/engines/ranking/types.js +36 -1
  136. package/dist/engines/ranking/types.js.map +1 -1
  137. package/dist/engines/recipe-costing/compiler.d.ts +11 -0
  138. package/dist/engines/recipe-costing/compiler.d.ts.map +1 -0
  139. package/dist/engines/recipe-costing/compiler.js +177 -0
  140. package/dist/engines/recipe-costing/compiler.js.map +1 -0
  141. package/dist/engines/recipe-costing/engine.d.ts +32 -0
  142. package/dist/engines/recipe-costing/engine.d.ts.map +1 -0
  143. package/dist/engines/recipe-costing/engine.js +40 -0
  144. package/dist/engines/recipe-costing/engine.js.map +1 -0
  145. package/dist/engines/recipe-costing/index.d.ts +9 -0
  146. package/dist/engines/recipe-costing/index.d.ts.map +1 -0
  147. package/dist/engines/recipe-costing/index.js +21 -0
  148. package/dist/engines/recipe-costing/index.js.map +1 -0
  149. package/dist/engines/recipe-costing/strategy.d.ts +20 -0
  150. package/dist/engines/recipe-costing/strategy.d.ts.map +1 -0
  151. package/dist/engines/recipe-costing/strategy.js +265 -0
  152. package/dist/engines/recipe-costing/strategy.js.map +1 -0
  153. package/dist/engines/recipe-costing/types.d.ts +213 -0
  154. package/dist/engines/recipe-costing/types.d.ts.map +1 -0
  155. package/dist/engines/recipe-costing/types.js +36 -0
  156. package/dist/engines/recipe-costing/types.js.map +1 -0
  157. package/dist/engines/scoring/index.d.ts +1 -1
  158. package/dist/engines/scoring/index.d.ts.map +1 -1
  159. package/dist/engines/scoring/index.js +3 -1
  160. package/dist/engines/scoring/index.js.map +1 -1
  161. package/dist/engines/scoring/types.d.ts +8 -1
  162. package/dist/engines/scoring/types.d.ts.map +1 -1
  163. package/dist/engines/scoring/types.js +18 -1
  164. package/dist/engines/scoring/types.js.map +1 -1
  165. package/dist/engines/sentiment/index.d.ts +1 -1
  166. package/dist/engines/sentiment/index.d.ts.map +1 -1
  167. package/dist/engines/sentiment/index.js +3 -1
  168. package/dist/engines/sentiment/index.js.map +1 -1
  169. package/dist/engines/sentiment/types.d.ts +13 -2
  170. package/dist/engines/sentiment/types.d.ts.map +1 -1
  171. package/dist/engines/sentiment/types.js +17 -1
  172. package/dist/engines/sentiment/types.js.map +1 -1
  173. package/dist/engines/state-machine/index.d.ts +1 -1
  174. package/dist/engines/state-machine/index.d.ts.map +1 -1
  175. package/dist/engines/state-machine/index.js +5 -1
  176. package/dist/engines/state-machine/index.js.map +1 -1
  177. package/dist/engines/state-machine/types.d.ts +7 -0
  178. package/dist/engines/state-machine/types.d.ts.map +1 -1
  179. package/dist/engines/state-machine/types.js +14 -0
  180. package/dist/engines/state-machine/types.js.map +1 -1
  181. package/dist/engines/utility/index.d.ts +2 -2
  182. package/dist/engines/utility/index.d.ts.map +1 -1
  183. package/dist/engines/utility/index.js +4 -1
  184. package/dist/engines/utility/index.js.map +1 -1
  185. package/dist/engines/utility/types.d.ts +21 -3
  186. package/dist/engines/utility/types.d.ts.map +1 -1
  187. package/dist/engines/utility/types.js +37 -1
  188. package/dist/engines/utility/types.js.map +1 -1
  189. package/dist/index.d.ts +30 -21
  190. package/dist/index.d.ts.map +1 -1
  191. package/dist/index.js +80 -3
  192. package/dist/index.js.map +1 -1
  193. package/package.json +1 -1
  194. package/src/core/evaluation/decay.ts +13 -2
  195. package/src/core/types/rule.ts +25 -1
  196. package/src/engines/bayesian/index.ts +1 -0
  197. package/src/engines/bayesian/types.ts +10 -8
  198. package/src/engines/constraint/types.ts +40 -11
  199. package/src/engines/decay/index.ts +4 -0
  200. package/src/engines/decay/types.ts +26 -4
  201. package/src/engines/defeasible/index.ts +7 -0
  202. package/src/engines/defeasible/types.ts +42 -18
  203. package/src/engines/ensemble/index.ts +6 -0
  204. package/src/engines/ensemble/types.ts +17 -13
  205. package/src/engines/expert/index.ts +1 -0
  206. package/src/engines/expert/types.ts +11 -9
  207. package/src/engines/fuzzy/fuzzy.types.ts +65 -31
  208. package/src/engines/loyalty/compiler.ts +174 -0
  209. package/src/engines/loyalty/engine.ts +174 -0
  210. package/src/engines/loyalty/index.ts +52 -0
  211. package/src/engines/loyalty/strategy.ts +532 -0
  212. package/src/engines/loyalty/types.ts +283 -0
  213. package/src/engines/menu-engineering/compiler.ts +145 -0
  214. package/src/engines/menu-engineering/engine.ts +48 -0
  215. package/src/engines/menu-engineering/index.ts +47 -0
  216. package/src/engines/menu-engineering/strategy.ts +414 -0
  217. package/src/engines/menu-engineering/types.ts +242 -0
  218. package/src/engines/monte-carlo/index.ts +1 -0
  219. package/src/engines/monte-carlo/types.ts +16 -21
  220. package/src/engines/negotiation/index.ts +8 -0
  221. package/src/engines/negotiation/types.ts +23 -4
  222. package/src/engines/prediction/index.ts +5 -0
  223. package/src/engines/prediction/types.ts +35 -5
  224. package/src/engines/pricing/index.ts +3 -1
  225. package/src/engines/pricing/types.ts +17 -1
  226. package/src/engines/ranking/index.ts +5 -0
  227. package/src/engines/ranking/types.ts +32 -11
  228. package/src/engines/recipe-costing/compiler.ts +219 -0
  229. package/src/engines/recipe-costing/engine.ts +48 -0
  230. package/src/engines/recipe-costing/index.ts +48 -0
  231. package/src/engines/recipe-costing/strategy.ts +357 -0
  232. package/src/engines/recipe-costing/types.ts +269 -0
  233. package/src/engines/scoring/index.ts +2 -0
  234. package/src/engines/scoring/types.ts +8 -6
  235. package/src/engines/sentiment/index.ts +2 -0
  236. package/src/engines/sentiment/types.ts +13 -2
  237. package/src/engines/state-machine/index.ts +3 -0
  238. package/src/engines/state-machine/types.ts +8 -0
  239. package/src/engines/utility/index.ts +5 -0
  240. package/src/engines/utility/types.ts +23 -3
  241. package/src/index.ts +182 -7
@@ -0,0 +1,405 @@
1
+ "use strict";
2
+ /**
3
+ * Loyalty Engine Strategy
4
+ *
5
+ * Core execution logic for all loyalty strategies:
6
+ * - earning: compute points from purchase/activity events with category multipliers and promotion stacking
7
+ * - redemption: process point redemption with balance validation
8
+ * - tier-evaluation: evaluate members against tier thresholds with upgrade/downgrade detection
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.loyaltyStrategy = exports.LoyaltyExecutor = void 0;
12
+ // ========================================
13
+ // Helpers
14
+ // ========================================
15
+ function round(value, decimals) {
16
+ const factor = Math.pow(10, decimals);
17
+ return Math.round(value * factor) / factor;
18
+ }
19
+ function generateTxId() {
20
+ return `tx-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
21
+ }
22
+ function resolveDotPath(obj, path) {
23
+ const parts = path.split('.');
24
+ let current = obj;
25
+ for (const part of parts) {
26
+ if (current == null)
27
+ return undefined;
28
+ current = current[part];
29
+ }
30
+ return current;
31
+ }
32
+ function isPromotionActive(promo, asOf) {
33
+ if (promo.startDate && new Date(promo.startDate) > asOf)
34
+ return false;
35
+ if (promo.endDate && new Date(promo.endDate) < asOf)
36
+ return false;
37
+ return true;
38
+ }
39
+ function matchesCategory(promo, category) {
40
+ if (!promo.categories || promo.categories.length === 0)
41
+ return true;
42
+ if (!category)
43
+ return false;
44
+ return promo.categories.includes(category);
45
+ }
46
+ // ========================================
47
+ // Strategy Executor
48
+ // ========================================
49
+ class LoyaltyExecutor {
50
+ run(ruleSet, wm, ledger, options = {}) {
51
+ switch (ruleSet.strategy) {
52
+ case 'earning':
53
+ return this.runEarning(ruleSet, wm, ledger, options);
54
+ case 'redemption':
55
+ return this.runRedemption(ruleSet, wm, ledger, options);
56
+ case 'tier-evaluation':
57
+ return this.runTierEvaluation(ruleSet, wm, ledger, options);
58
+ default:
59
+ throw new Error(`Unknown loyalty strategy: '${ruleSet.strategy}'`);
60
+ }
61
+ }
62
+ // ========================================
63
+ // Earning Strategy
64
+ // ========================================
65
+ runEarning(ruleSet, wm, ledger, options = {}) {
66
+ const startTime = performance.now();
67
+ const asOf = options.asOf ?? new Date();
68
+ const asOfIso = asOf.toISOString();
69
+ // Get all purchase/activity events from WM
70
+ const events = wm.getAll();
71
+ const allTransactions = [];
72
+ let totalPointsEarned = 0;
73
+ let totalBonusPoints = 0;
74
+ const promotionsApplied = new Set();
75
+ let memberId = '';
76
+ for (const event of events) {
77
+ const eventMemberId = resolveDotPath(event.data, 'memberId');
78
+ if (!eventMemberId)
79
+ continue;
80
+ memberId = eventMemberId;
81
+ const amount = resolveDotPath(event.data, 'amount') ?? 0;
82
+ const category = resolveDotPath(event.data, 'category');
83
+ // Find matching earning rules
84
+ const matchingRules = this.findMatchingEarningRules(ruleSet.earningRules, category);
85
+ const rule = matchingRules.length > 0 ? matchingRules[0] : null;
86
+ // Calculate base points
87
+ const baseRate = rule ? rule.baseRate : ruleSet.defaultRate;
88
+ const multiplier = rule?.multiplier ?? 1;
89
+ let basePoints = round(amount * baseRate * multiplier, 0);
90
+ let bonusPoints = rule?.bonusPoints ?? 0;
91
+ // Apply active promotions
92
+ const activePromos = ruleSet.promotions.filter(p => isPromotionActive(p, asOf) && matchesCategory(p, category));
93
+ let promoMultiplier = 1;
94
+ for (const promo of activePromos) {
95
+ if (promo.multiplier) {
96
+ promoMultiplier *= promo.multiplier;
97
+ promotionsApplied.add(promo.id);
98
+ }
99
+ if (promo.bonusPoints) {
100
+ bonusPoints += promo.bonusPoints;
101
+ promotionsApplied.add(promo.id);
102
+ }
103
+ }
104
+ // Apply tier multiplier bonus
105
+ const balance = this.getOrCreateBalance(ledger, memberId);
106
+ const tierBonus = this.getTierMultiplierBonus(balance.currentTier, ruleSet.tiers);
107
+ promoMultiplier *= (1 + tierBonus);
108
+ basePoints = round(basePoints * promoMultiplier, 0);
109
+ const totalForEvent = basePoints + bonusPoints;
110
+ if (totalForEvent > 0) {
111
+ const tx = {
112
+ id: generateTxId(),
113
+ memberId,
114
+ type: 'earn',
115
+ points: totalForEvent,
116
+ category,
117
+ ruleId: rule?.id,
118
+ timestamp: asOfIso,
119
+ metadata: { amount, baseRate, multiplier: multiplier * promoMultiplier, bonusPoints }
120
+ };
121
+ allTransactions.push(tx);
122
+ totalPointsEarned += basePoints;
123
+ totalBonusPoints += bonusPoints;
124
+ // Update ledger
125
+ balance.totalEarned += totalForEvent;
126
+ balance.currentBalance += totalForEvent;
127
+ balance.qualifyingPoints += totalForEvent;
128
+ }
129
+ }
130
+ // Update tier if tiers are defined
131
+ if (memberId && ruleSet.tiers.length > 0) {
132
+ const balance = this.getOrCreateBalance(ledger, memberId);
133
+ this.evaluateMemberTier(balance, ruleSet.tiers, asOfIso);
134
+ }
135
+ const finalBalance = memberId ? this.getOrCreateBalance(ledger, memberId) : { currentBalance: 0 };
136
+ const executionTimeMs = round((performance.now() - startTime) * 100, 0) / 100;
137
+ return {
138
+ memberId,
139
+ transactions: allTransactions,
140
+ pointsEarned: totalPointsEarned,
141
+ bonusPointsEarned: totalBonusPoints,
142
+ promotionsApplied: Array.from(promotionsApplied),
143
+ newBalance: finalBalance.currentBalance,
144
+ executionTimeMs
145
+ };
146
+ }
147
+ /**
148
+ * Process a single earning event (for streaming ingest).
149
+ */
150
+ earnSingle(eventData, ruleSet, ledger, asOf = new Date()) {
151
+ const asOfIso = asOf.toISOString();
152
+ const memberId = eventData.memberId;
153
+ if (!memberId) {
154
+ return { memberId: '', pointsEarned: 0, bonusPointsEarned: 0, promotionsApplied: [], newBalance: 0, transactions: [] };
155
+ }
156
+ const amount = eventData.amount ?? 0;
157
+ const category = eventData.category;
158
+ const matchingRules = this.findMatchingEarningRules(ruleSet.earningRules, category);
159
+ const rule = matchingRules.length > 0 ? matchingRules[0] : null;
160
+ const baseRate = rule ? rule.baseRate : ruleSet.defaultRate;
161
+ const multiplier = rule?.multiplier ?? 1;
162
+ let basePoints = round(amount * baseRate * multiplier, 0);
163
+ let bonusPoints = rule?.bonusPoints ?? 0;
164
+ const promotionsApplied = [];
165
+ const activePromos = ruleSet.promotions.filter(p => isPromotionActive(p, asOf) && matchesCategory(p, category));
166
+ let promoMultiplier = 1;
167
+ for (const promo of activePromos) {
168
+ if (promo.multiplier) {
169
+ promoMultiplier *= promo.multiplier;
170
+ promotionsApplied.push(promo.id);
171
+ }
172
+ if (promo.bonusPoints) {
173
+ bonusPoints += promo.bonusPoints;
174
+ promotionsApplied.push(promo.id);
175
+ }
176
+ }
177
+ // Apply tier multiplier bonus
178
+ const balance = this.getOrCreateBalance(ledger, memberId);
179
+ const tierBonus = this.getTierMultiplierBonus(balance.currentTier, ruleSet.tiers);
180
+ promoMultiplier *= (1 + tierBonus);
181
+ basePoints = round(basePoints * promoMultiplier, 0);
182
+ const totalForEvent = basePoints + bonusPoints;
183
+ const transactions = [];
184
+ if (totalForEvent > 0) {
185
+ const tx = {
186
+ id: generateTxId(),
187
+ memberId,
188
+ type: 'earn',
189
+ points: totalForEvent,
190
+ category,
191
+ ruleId: rule?.id,
192
+ timestamp: asOfIso,
193
+ metadata: { amount, baseRate, multiplier: multiplier * promoMultiplier, bonusPoints }
194
+ };
195
+ transactions.push(tx);
196
+ balance.totalEarned += totalForEvent;
197
+ balance.currentBalance += totalForEvent;
198
+ balance.qualifyingPoints += totalForEvent;
199
+ }
200
+ // Update tier
201
+ if (ruleSet.tiers.length > 0) {
202
+ this.evaluateMemberTier(balance, ruleSet.tiers, asOfIso);
203
+ }
204
+ return {
205
+ memberId,
206
+ pointsEarned: basePoints,
207
+ bonusPointsEarned: bonusPoints,
208
+ promotionsApplied,
209
+ newBalance: balance.currentBalance,
210
+ transactions
211
+ };
212
+ }
213
+ // ========================================
214
+ // Redemption Strategy
215
+ // ========================================
216
+ runRedemption(ruleSet, wm, ledger, options = {}) {
217
+ const startTime = performance.now();
218
+ const asOf = options.asOf ?? new Date();
219
+ const asOfIso = asOf.toISOString();
220
+ // Get redemption request from WM
221
+ const requests = wm.getAll();
222
+ if (requests.length === 0) {
223
+ throw new Error('No redemption request found in working memory');
224
+ }
225
+ const request = requests[0];
226
+ const memberId = resolveDotPath(request.data, 'memberId');
227
+ const optionId = resolveDotPath(request.data, 'optionId');
228
+ if (!memberId)
229
+ throw new Error('Redemption request requires memberId');
230
+ if (!optionId)
231
+ throw new Error('Redemption request requires optionId');
232
+ // Find matching redemption option
233
+ const option = ruleSet.redemptionOptions.find(o => o.id === optionId);
234
+ if (!option) {
235
+ throw new Error(`Unknown redemption option: '${optionId}'`);
236
+ }
237
+ // Validate sufficient balance
238
+ const balance = this.getOrCreateBalance(ledger, memberId);
239
+ if (balance.currentBalance < option.pointsRequired) {
240
+ throw new Error(`Insufficient balance: ${balance.currentBalance} points available, ` +
241
+ `${option.pointsRequired} required for '${option.id}'`);
242
+ }
243
+ // Build redemption transaction
244
+ const tx = {
245
+ id: generateTxId(),
246
+ memberId,
247
+ type: 'redeem',
248
+ points: -option.pointsRequired,
249
+ ruleId: option.id,
250
+ timestamp: asOfIso,
251
+ metadata: { optionId: option.id, value: option.value, unit: option.unit }
252
+ };
253
+ // Update balance
254
+ balance.totalRedeemed += option.pointsRequired;
255
+ balance.currentBalance -= option.pointsRequired;
256
+ const executionTimeMs = round((performance.now() - startTime) * 100, 0) / 100;
257
+ return {
258
+ memberId,
259
+ redemption: tx,
260
+ pointsRedeemed: option.pointsRequired,
261
+ redemptionValue: option.value,
262
+ remainingBalance: balance.currentBalance,
263
+ executionTimeMs
264
+ };
265
+ }
266
+ // ========================================
267
+ // Tier Evaluation Strategy
268
+ // ========================================
269
+ runTierEvaluation(ruleSet, wm, ledger, _options = {}) {
270
+ const startTime = performance.now();
271
+ // Get all members from WM
272
+ const memberFacts = wm.getAll();
273
+ const members = [];
274
+ const tierDistribution = {};
275
+ // Initialize tier distribution
276
+ for (const tier of ruleSet.tiers) {
277
+ tierDistribution[tier.id] = 0;
278
+ }
279
+ tierDistribution['none'] = 0;
280
+ for (const fact of memberFacts) {
281
+ const memberId = resolveDotPath(fact.data, 'memberId');
282
+ if (!memberId)
283
+ continue;
284
+ const balance = this.getOrCreateBalance(ledger, memberId);
285
+ // If qualifying points are provided in the fact, use them
286
+ const factQualifying = resolveDotPath(fact.data, 'qualifyingPoints');
287
+ if (factQualifying !== undefined) {
288
+ balance.qualifyingPoints = factQualifying;
289
+ }
290
+ const previousTier = balance.currentTier;
291
+ // Find the highest qualifying tier
292
+ let matchedTier;
293
+ for (let i = ruleSet.tiers.length - 1; i >= 0; i--) {
294
+ if (balance.qualifyingPoints >= ruleSet.tiers[i].qualifyingThreshold) {
295
+ matchedTier = ruleSet.tiers[i];
296
+ break;
297
+ }
298
+ }
299
+ const currentTierId = matchedTier?.id ?? 'none';
300
+ const status = this.resolveTierStatus(balance, matchedTier, previousTier, ruleSet.tiers);
301
+ // Find next tier
302
+ let nextTier;
303
+ if (matchedTier) {
304
+ const currentIdx = ruleSet.tiers.findIndex(t => t.id === matchedTier.id);
305
+ if (currentIdx < ruleSet.tiers.length - 1) {
306
+ nextTier = ruleSet.tiers[currentIdx + 1];
307
+ }
308
+ }
309
+ else if (ruleSet.tiers.length > 0) {
310
+ nextTier = ruleSet.tiers[0];
311
+ }
312
+ const result = {
313
+ memberId,
314
+ currentTier: currentTierId,
315
+ previousTier: previousTier !== currentTierId ? previousTier : undefined,
316
+ qualifyingPoints: balance.qualifyingPoints,
317
+ nextTierThreshold: nextTier?.qualifyingThreshold,
318
+ pointsToNextTier: nextTier
319
+ ? Math.max(0, nextTier.qualifyingThreshold - balance.qualifyingPoints)
320
+ : undefined,
321
+ status,
322
+ benefits: matchedTier?.benefits ?? []
323
+ };
324
+ members.push(result);
325
+ tierDistribution[currentTierId] = (tierDistribution[currentTierId] ?? 0) + 1;
326
+ // Update ledger with new tier
327
+ balance.currentTier = currentTierId;
328
+ }
329
+ const executionTimeMs = round((performance.now() - startTime) * 100, 0) / 100;
330
+ return {
331
+ members,
332
+ tierDistribution,
333
+ executionTimeMs
334
+ };
335
+ }
336
+ // ========================================
337
+ // Shared Helpers
338
+ // ========================================
339
+ findMatchingEarningRules(rules, category) {
340
+ if (!category) {
341
+ return rules.filter(r => !r.category);
342
+ }
343
+ const categoryMatch = rules.filter(r => r.category === category);
344
+ if (categoryMatch.length > 0)
345
+ return categoryMatch;
346
+ return rules.filter(r => !r.category);
347
+ }
348
+ getOrCreateBalance(ledger, memberId) {
349
+ let balance = ledger.get(memberId);
350
+ if (!balance) {
351
+ balance = {
352
+ memberId,
353
+ totalEarned: 0,
354
+ totalRedeemed: 0,
355
+ totalExpired: 0,
356
+ currentBalance: 0,
357
+ qualifyingPoints: 0
358
+ };
359
+ ledger.set(memberId, balance);
360
+ }
361
+ return balance;
362
+ }
363
+ evaluateMemberTier(balance, tiers, asOfIso) {
364
+ let matchedTier;
365
+ for (let i = tiers.length - 1; i >= 0; i--) {
366
+ if (balance.qualifyingPoints >= tiers[i].qualifyingThreshold) {
367
+ matchedTier = tiers[i];
368
+ break;
369
+ }
370
+ }
371
+ const newTierId = matchedTier?.id;
372
+ if (newTierId && newTierId !== balance.currentTier) {
373
+ balance.currentTier = newTierId;
374
+ balance.tierQualifiedAt = asOfIso;
375
+ }
376
+ }
377
+ getTierMultiplierBonus(currentTierId, tiers) {
378
+ if (!currentTierId)
379
+ return 0;
380
+ const tier = tiers.find(t => t.id === currentTierId);
381
+ return tier?.multiplierBonus ?? 0;
382
+ }
383
+ resolveTierStatus(balance, matchedTier, previousTier, allTiers) {
384
+ if (!matchedTier)
385
+ return 'at-risk';
386
+ // Check if this is a downgrade
387
+ if (previousTier) {
388
+ const prevIdx = allTiers.findIndex(t => t.id === previousTier);
389
+ const currIdx = allTiers.findIndex(t => t.id === matchedTier.id);
390
+ if (prevIdx > currIdx)
391
+ return 'downgrade-pending';
392
+ }
393
+ // Check if near retention threshold
394
+ if (matchedTier.retentionThreshold !== undefined) {
395
+ if (balance.qualifyingPoints < matchedTier.retentionThreshold) {
396
+ return 'at-risk';
397
+ }
398
+ }
399
+ return 'qualified';
400
+ }
401
+ }
402
+ exports.LoyaltyExecutor = LoyaltyExecutor;
403
+ /** Singleton instance */
404
+ exports.loyaltyStrategy = new LoyaltyExecutor();
405
+ //# sourceMappingURL=strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strategy.js","sourceRoot":"","sources":["../../../src/engines/loyalty/strategy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,221 @@
1
+ /**
2
+ * Loyalty Engine Types
3
+ *
4
+ * Point ledger engine that manages earning rules with category multipliers,
5
+ * point transactions (earn/redeem/transfer/expire), tier-qualified balances,
6
+ * and promotion stacking. Unlike other BOE engines, the Loyalty engine
7
+ * maintains running balance state across operations.
8
+ */
9
+ import type { Condition } from '../../core/types/condition';
10
+ /** Loyalty strategy to use */
11
+ export declare const LoyaltyStrategies: {
12
+ readonly earning: "earning";
13
+ readonly redemption: "redemption";
14
+ readonly tierEvaluation: "tier-evaluation";
15
+ };
16
+ export type LoyaltyStrategy = typeof LoyaltyStrategies[keyof typeof LoyaltyStrategies];
17
+ /** Point transaction type */
18
+ export declare const PointTransactionTypes: {
19
+ readonly earn: "earn";
20
+ readonly redeem: "redeem";
21
+ readonly expire: "expire";
22
+ readonly transfer: "transfer";
23
+ readonly adjust: "adjust";
24
+ };
25
+ export type PointTransactionType = typeof PointTransactionTypes[keyof typeof PointTransactionTypes];
26
+ /** Member tier status */
27
+ export declare const TierStatuses: {
28
+ readonly qualified: "qualified";
29
+ readonly atRisk: "at-risk";
30
+ readonly downgradePending: "downgrade-pending";
31
+ readonly locked: "locked";
32
+ };
33
+ export type TierStatus = typeof TierStatuses[keyof typeof TierStatuses];
34
+ /** Qualifying metric for tier evaluation */
35
+ export declare const QualifyingMetrics: {
36
+ readonly pointsEarned: "points-earned";
37
+ readonly qualifyingSpend: "qualifying-spend";
38
+ readonly qualifyingNights: "qualifying-nights";
39
+ readonly qualifyingFlights: "qualifying-flights";
40
+ readonly qualifyingRentalDays: "qualifying-rental-days";
41
+ readonly qualifyingCruiseDays: "qualifying-cruise-days";
42
+ };
43
+ export type QualifyingMetric = typeof QualifyingMetrics[keyof typeof QualifyingMetrics];
44
+ /** Evaluation period for tier assessment */
45
+ export declare const EvaluationPeriods: {
46
+ readonly rolling12Months: "rolling-12-months";
47
+ readonly calendarYear: "calendar-year";
48
+ readonly custom: "custom";
49
+ };
50
+ export type EvaluationPeriod = typeof EvaluationPeriods[keyof typeof EvaluationPeriods];
51
+ /** An earning rule that maps activities to points */
52
+ export type EarningRule = {
53
+ id: string;
54
+ name?: string;
55
+ category?: string;
56
+ baseRate: number;
57
+ multiplier?: number;
58
+ conditions?: Condition[];
59
+ bonusPoints?: number;
60
+ promotionId?: string;
61
+ };
62
+ /** A redemption option specifying how points can be spent */
63
+ export type RedemptionOption = {
64
+ id: string;
65
+ name?: string;
66
+ type: string;
67
+ pointsRequired: number;
68
+ value: number;
69
+ unit?: string;
70
+ conditions?: Condition[];
71
+ };
72
+ /** A tier definition with qualifying thresholds and benefits */
73
+ export type LoyaltyTierDefinition = {
74
+ id: string;
75
+ name: string;
76
+ qualifyingThreshold: number;
77
+ qualifyingMetric: QualifyingMetric;
78
+ benefits: string[];
79
+ multiplierBonus?: number;
80
+ retentionThreshold?: number;
81
+ };
82
+ /** A promotion rule that stacks multipliers or bonus points */
83
+ export type PromotionRule = {
84
+ id: string;
85
+ name?: string;
86
+ multiplier?: number;
87
+ bonusPoints?: number;
88
+ categories?: string[];
89
+ startDate?: string;
90
+ endDate?: string;
91
+ };
92
+ /** Expiration policy for points */
93
+ export type ExpirationPolicy = {
94
+ inactivityDays?: number;
95
+ absoluteMonths?: number;
96
+ graceDays?: number;
97
+ };
98
+ /** A single point transaction record */
99
+ export type PointTransaction = {
100
+ id: string;
101
+ memberId: string;
102
+ type: PointTransactionType;
103
+ points: number;
104
+ category?: string;
105
+ ruleId?: string;
106
+ timestamp: string;
107
+ metadata?: Record<string, any>;
108
+ };
109
+ /** Running balance for a member */
110
+ export type MemberBalance = {
111
+ memberId: string;
112
+ totalEarned: number;
113
+ totalRedeemed: number;
114
+ totalExpired: number;
115
+ currentBalance: number;
116
+ qualifyingPoints: number;
117
+ currentTier?: string;
118
+ tierQualifiedAt?: string;
119
+ };
120
+ type LoyaltyRuleSetBase = {
121
+ id: string;
122
+ name?: string;
123
+ mode: 'loyalty';
124
+ tiers?: LoyaltyTierDefinition[];
125
+ expirationPolicy?: ExpirationPolicy;
126
+ promotions?: PromotionRule[];
127
+ };
128
+ /** Earning strategy: compute points earned from purchase/activity events */
129
+ export type EarningRuleSet = LoyaltyRuleSetBase & {
130
+ strategy: 'earning';
131
+ earningRules: EarningRule[];
132
+ defaultRate?: number;
133
+ };
134
+ /** Redemption strategy: process point redemption requests */
135
+ export type RedemptionRuleSet = LoyaltyRuleSetBase & {
136
+ strategy: 'redemption';
137
+ redemptionOptions: RedemptionOption[];
138
+ };
139
+ /** Tier evaluation strategy: evaluate members against tier thresholds */
140
+ export type TierEvaluationRuleSet = LoyaltyRuleSetBase & {
141
+ strategy: 'tier-evaluation';
142
+ evaluationPeriod?: EvaluationPeriod;
143
+ tiers: LoyaltyTierDefinition[];
144
+ };
145
+ export type LoyaltyRuleSet = EarningRuleSet | RedemptionRuleSet | TierEvaluationRuleSet;
146
+ type CompiledLoyaltyRuleSetBase = {
147
+ id: string;
148
+ name?: string;
149
+ mode: 'loyalty';
150
+ tiers: LoyaltyTierDefinition[];
151
+ expirationPolicy: ExpirationPolicy;
152
+ promotions: PromotionRule[];
153
+ };
154
+ export type CompiledEarningRuleSet = CompiledLoyaltyRuleSetBase & {
155
+ strategy: 'earning';
156
+ earningRules: EarningRule[];
157
+ defaultRate: number;
158
+ };
159
+ export type CompiledRedemptionRuleSet = CompiledLoyaltyRuleSetBase & {
160
+ strategy: 'redemption';
161
+ redemptionOptions: RedemptionOption[];
162
+ };
163
+ export type CompiledTierEvaluationRuleSet = CompiledLoyaltyRuleSetBase & {
164
+ strategy: 'tier-evaluation';
165
+ evaluationPeriod: EvaluationPeriod;
166
+ tiers: LoyaltyTierDefinition[];
167
+ };
168
+ export type CompiledLoyaltyRuleSet = CompiledEarningRuleSet | CompiledRedemptionRuleSet | CompiledTierEvaluationRuleSet;
169
+ /** Result from earning strategy execution */
170
+ export type EarningResult = {
171
+ memberId: string;
172
+ transactions: PointTransaction[];
173
+ pointsEarned: number;
174
+ bonusPointsEarned: number;
175
+ promotionsApplied: string[];
176
+ newBalance: number;
177
+ executionTimeMs: number;
178
+ };
179
+ /** Result from redemption strategy execution */
180
+ export type RedemptionResult = {
181
+ memberId: string;
182
+ redemption: PointTransaction;
183
+ pointsRedeemed: number;
184
+ redemptionValue: number;
185
+ remainingBalance: number;
186
+ executionTimeMs: number;
187
+ };
188
+ /** Per-member tier evaluation result */
189
+ export type MemberTierResult = {
190
+ memberId: string;
191
+ currentTier: string;
192
+ previousTier?: string;
193
+ qualifyingPoints: number;
194
+ nextTierThreshold?: number;
195
+ pointsToNextTier?: number;
196
+ status: TierStatus;
197
+ benefits: string[];
198
+ };
199
+ /** Result from tier-evaluation strategy execution */
200
+ export type TierEvaluationResult = {
201
+ members: MemberTierResult[];
202
+ tierDistribution: Record<string, number>;
203
+ executionTimeMs: number;
204
+ };
205
+ /** Union of all loyalty results */
206
+ export type LoyaltyResult = EarningResult | RedemptionResult | TierEvaluationResult;
207
+ /** Options for earning execution */
208
+ export type LoyaltyOptions = {
209
+ asOf?: Date;
210
+ };
211
+ /** Result from ingest() -- streaming earning with running balance */
212
+ export type LoyaltyIngestResult = {
213
+ memberId: string;
214
+ pointsEarned: number;
215
+ bonusPointsEarned: number;
216
+ promotionsApplied: string[];
217
+ newBalance: number;
218
+ transactions: PointTransaction[];
219
+ };
220
+ export {};
221
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/engines/loyalty/types.ts"],"names":[],"mappings":"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"}