@higher.archi/boe 1.0.28 → 1.0.30
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.
- package/dist/engines/decay/engine.d.ts +32 -1
- package/dist/engines/decay/engine.d.ts.map +1 -1
- package/dist/engines/decay/engine.js +69 -0
- package/dist/engines/decay/engine.js.map +1 -1
- package/dist/engines/decay/index.d.ts +1 -1
- package/dist/engines/decay/index.d.ts.map +1 -1
- package/dist/engines/decay/index.js.map +1 -1
- package/dist/engines/decay/strategy.d.ts +4 -2
- package/dist/engines/decay/strategy.d.ts.map +1 -1
- package/dist/engines/decay/strategy.js +24 -0
- package/dist/engines/decay/strategy.js.map +1 -1
- package/dist/engines/decay/types.d.ts +9 -0
- package/dist/engines/decay/types.d.ts.map +1 -1
- package/dist/engines/loyalty/compiler.d.ts +11 -0
- package/dist/engines/loyalty/compiler.d.ts.map +1 -0
- package/dist/engines/loyalty/compiler.js +144 -0
- package/dist/engines/loyalty/compiler.js.map +1 -0
- package/dist/engines/loyalty/engine.d.ts +76 -0
- package/dist/engines/loyalty/engine.d.ts.map +1 -0
- package/dist/engines/loyalty/engine.js +132 -0
- package/dist/engines/loyalty/engine.js.map +1 -0
- package/dist/engines/loyalty/index.d.ts +8 -0
- package/dist/engines/loyalty/index.d.ts.map +1 -0
- package/dist/engines/loyalty/index.js +17 -0
- package/dist/engines/loyalty/index.js.map +1 -0
- package/dist/engines/loyalty/strategy.d.ts +35 -0
- package/dist/engines/loyalty/strategy.d.ts.map +1 -0
- package/dist/engines/loyalty/strategy.js +405 -0
- package/dist/engines/loyalty/strategy.js.map +1 -0
- package/dist/engines/loyalty/types.d.ts +190 -0
- package/dist/engines/loyalty/types.d.ts.map +1 -0
- package/dist/engines/loyalty/types.js +11 -0
- package/dist/engines/loyalty/types.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/engines/decay/engine.ts +93 -1
- package/src/engines/decay/index.ts +2 -1
- package/src/engines/decay/strategy.ts +33 -0
- package/src/engines/decay/types.ts +10 -0
- package/src/engines/loyalty/compiler.ts +174 -0
- package/src/engines/loyalty/engine.ts +174 -0
- package/src/engines/loyalty/index.ts +43 -0
- package/src/engines/loyalty/strategy.ts +532 -0
- package/src/engines/loyalty/types.ts +252 -0
- package/src/index.ts +39 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Loyalty Engine
|
|
4
|
+
*
|
|
5
|
+
* Point ledger engine that manages earning rules with category multipliers,
|
|
6
|
+
* point transactions, tier-qualified balances, and promotion stacking.
|
|
7
|
+
* Unlike other BOE engines, the Loyalty engine maintains a running balance
|
|
8
|
+
* ledger across operations.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const engine = new LoyaltyEngine();
|
|
13
|
+
* const compiled = compileLoyaltyRuleSet({ ... });
|
|
14
|
+
*
|
|
15
|
+
* // Stream purchases as they arrive
|
|
16
|
+
* const r1 = engine.ingest({ memberId: 'M001', amount: 250, category: 'dining' }, compiled);
|
|
17
|
+
* // r1.pointsEarned: 500, r1.newBalance: 500
|
|
18
|
+
*
|
|
19
|
+
* engine.getBalance('M001'); // { currentBalance: 500, ... }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.LoyaltyEngine = void 0;
|
|
24
|
+
const core_1 = require("../../core");
|
|
25
|
+
const strategy_1 = require("./strategy");
|
|
26
|
+
class LoyaltyEngine {
|
|
27
|
+
wm;
|
|
28
|
+
strategy;
|
|
29
|
+
_ledger = new Map();
|
|
30
|
+
constructor(workingMemory) {
|
|
31
|
+
this.wm = workingMemory ?? new core_1.WorkingMemory();
|
|
32
|
+
this.strategy = new strategy_1.LoyaltyExecutor();
|
|
33
|
+
}
|
|
34
|
+
// ========================================
|
|
35
|
+
// IWorkingMemory Implementation
|
|
36
|
+
// ========================================
|
|
37
|
+
add(input) {
|
|
38
|
+
return this.wm.add(input);
|
|
39
|
+
}
|
|
40
|
+
remove(factId) {
|
|
41
|
+
return this.wm.remove(factId);
|
|
42
|
+
}
|
|
43
|
+
update(input) {
|
|
44
|
+
return this.wm.update(input);
|
|
45
|
+
}
|
|
46
|
+
get(factId) {
|
|
47
|
+
return this.wm.get(factId);
|
|
48
|
+
}
|
|
49
|
+
getByType(type) {
|
|
50
|
+
return this.wm.getByType(type);
|
|
51
|
+
}
|
|
52
|
+
getAll() {
|
|
53
|
+
return this.wm.getAll();
|
|
54
|
+
}
|
|
55
|
+
has(factId) {
|
|
56
|
+
return this.wm.has(factId);
|
|
57
|
+
}
|
|
58
|
+
size() {
|
|
59
|
+
return this.wm.size();
|
|
60
|
+
}
|
|
61
|
+
clear() {
|
|
62
|
+
this.wm.clear();
|
|
63
|
+
}
|
|
64
|
+
getChanges() {
|
|
65
|
+
return this.wm.getChanges();
|
|
66
|
+
}
|
|
67
|
+
clearChanges() {
|
|
68
|
+
this.wm.clearChanges();
|
|
69
|
+
}
|
|
70
|
+
// ========================================
|
|
71
|
+
// Engine Execution
|
|
72
|
+
// ========================================
|
|
73
|
+
/**
|
|
74
|
+
* Execute a loyalty ruleset against all facts in working memory.
|
|
75
|
+
*
|
|
76
|
+
* @param ruleSet - Compiled loyalty ruleset
|
|
77
|
+
* @param options - Runtime options (asOf date)
|
|
78
|
+
* @returns Loyalty result (earning, redemption, or tier-evaluation)
|
|
79
|
+
*/
|
|
80
|
+
execute(ruleSet, options = {}) {
|
|
81
|
+
return this.strategy.run(ruleSet, this.wm, this._ledger, options);
|
|
82
|
+
}
|
|
83
|
+
// ========================================
|
|
84
|
+
// Streaming Ingest
|
|
85
|
+
// ========================================
|
|
86
|
+
/**
|
|
87
|
+
* Process a single purchase/activity event incrementally.
|
|
88
|
+
*
|
|
89
|
+
* Each call computes points earned, updates the internal ledger,
|
|
90
|
+
* evaluates tier status, and returns the result with the new balance.
|
|
91
|
+
* Only works with earning strategy rulesets.
|
|
92
|
+
*
|
|
93
|
+
* @param eventData - Event data with memberId, amount, and optional category
|
|
94
|
+
* @param ruleSet - Compiled earning ruleset
|
|
95
|
+
* @param asOf - Reference time (default: now)
|
|
96
|
+
* @returns Earning result with updated balance
|
|
97
|
+
*/
|
|
98
|
+
ingest(eventData, ruleSet, asOf = new Date()) {
|
|
99
|
+
return this.strategy.earnSingle(eventData, ruleSet, this._ledger, asOf);
|
|
100
|
+
}
|
|
101
|
+
// ========================================
|
|
102
|
+
// Ledger Operations
|
|
103
|
+
// ========================================
|
|
104
|
+
/**
|
|
105
|
+
* Get the current balance for a member.
|
|
106
|
+
* Returns undefined if the member has no transactions.
|
|
107
|
+
*/
|
|
108
|
+
getBalance(memberId) {
|
|
109
|
+
return this._ledger.get(memberId);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Get the full ledger state (all member balances).
|
|
113
|
+
*/
|
|
114
|
+
getLedger() {
|
|
115
|
+
return new Map(this._ledger);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Reset the ledger, clearing all member balances.
|
|
119
|
+
* Does not affect working memory.
|
|
120
|
+
*/
|
|
121
|
+
resetLedger() {
|
|
122
|
+
this._ledger.clear();
|
|
123
|
+
}
|
|
124
|
+
// ========================================
|
|
125
|
+
// Utility Methods
|
|
126
|
+
// ========================================
|
|
127
|
+
getWorkingMemory() {
|
|
128
|
+
return this.wm;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
exports.LoyaltyEngine = LoyaltyEngine;
|
|
132
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/engines/loyalty/engine.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;AAEH,qCAKoB;AAWpB,yCAA6C;AAE7C,MAAa,aAAa;IAChB,EAAE,CAAgB;IAClB,QAAQ,CAAkB;IAC1B,OAAO,GAA+B,IAAI,GAAG,EAAE,CAAC;IAExD,YAAY,aAA6B;QACvC,IAAI,CAAC,EAAE,GAAG,aAAa,IAAI,IAAI,oBAAa,EAAE,CAAC;QAC/C,IAAI,CAAC,QAAQ,GAAG,IAAI,0BAAe,EAAE,CAAC;IACxC,CAAC;IAED,2CAA2C;IAC3C,gCAAgC;IAChC,2CAA2C;IAE3C,GAAG,CAA0B,KAAmB;QAC9C,OAAO,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,MAAM,CAAC,MAAc;QACnB,OAAO,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,CAA0B,KAAmB;QACjD,OAAO,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED,GAAG,CAAC,MAAc;QAChB,OAAO,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IAED,SAAS,CAAC,IAAY;QACpB,OAAO,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC;IAC1B,CAAC;IAED,GAAG,CAAC,MAAc;QAChB,OAAO,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC;IAC9B,CAAC;IAED,YAAY;QACV,IAAI,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC;IACzB,CAAC;IAED,2CAA2C;IAC3C,mBAAmB;IACnB,2CAA2C;IAE3C;;;;;;OAMG;IACH,OAAO,CACL,OAA+B,EAC/B,UAA0B,EAAE;QAE5B,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACpE,CAAC;IAED,2CAA2C;IAC3C,mBAAmB;IACnB,2CAA2C;IAE3C;;;;;;;;;;;OAWG;IACH,MAAM,CACJ,SAA8B,EAC9B,OAA+B,EAC/B,OAAa,IAAI,IAAI,EAAE;QAEvB,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC1E,CAAC;IAED,2CAA2C;IAC3C,oBAAoB;IACpB,2CAA2C;IAE3C;;;OAGG;IACH,UAAU,CAAC,QAAgB;QACzB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACH,WAAW;QACT,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED,2CAA2C;IAC3C,kBAAkB;IAClB,2CAA2C;IAE3C,gBAAgB;QACd,OAAO,IAAI,CAAC,EAAE,CAAC;IACjB,CAAC;CACF;AAtID,sCAsIC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loyalty Engine -- Point Ledger Management
|
|
3
|
+
*/
|
|
4
|
+
export type { LoyaltyStrategy, PointTransactionType, TierStatus, QualifyingMetric, EvaluationPeriod, EarningRule, RedemptionOption, LoyaltyTierDefinition, PromotionRule, ExpirationPolicy, PointTransaction, MemberBalance, EarningRuleSet, RedemptionRuleSet, TierEvaluationRuleSet, LoyaltyRuleSet, CompiledEarningRuleSet, CompiledRedemptionRuleSet, CompiledTierEvaluationRuleSet, CompiledLoyaltyRuleSet, EarningResult, RedemptionResult, MemberTierResult, TierEvaluationResult, LoyaltyResult, LoyaltyOptions, LoyaltyIngestResult } from './types';
|
|
5
|
+
export { compileLoyaltyRuleSet } from './compiler';
|
|
6
|
+
export { LoyaltyExecutor, loyaltyStrategy } from './strategy';
|
|
7
|
+
export { LoyaltyEngine } from './engine';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engines/loyalty/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,YAAY,EACV,eAAe,EACf,oBAAoB,EACpB,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,qBAAqB,EACrB,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,cAAc,EACd,sBAAsB,EACtB,yBAAyB,EACzB,6BAA6B,EAC7B,sBAAsB,EACtB,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAGnD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAG9D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Loyalty Engine -- Point Ledger Management
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LoyaltyEngine = exports.loyaltyStrategy = exports.LoyaltyExecutor = exports.compileLoyaltyRuleSet = void 0;
|
|
7
|
+
// Compiler
|
|
8
|
+
var compiler_1 = require("./compiler");
|
|
9
|
+
Object.defineProperty(exports, "compileLoyaltyRuleSet", { enumerable: true, get: function () { return compiler_1.compileLoyaltyRuleSet; } });
|
|
10
|
+
// Strategy
|
|
11
|
+
var strategy_1 = require("./strategy");
|
|
12
|
+
Object.defineProperty(exports, "LoyaltyExecutor", { enumerable: true, get: function () { return strategy_1.LoyaltyExecutor; } });
|
|
13
|
+
Object.defineProperty(exports, "loyaltyStrategy", { enumerable: true, get: function () { return strategy_1.loyaltyStrategy; } });
|
|
14
|
+
// Engine
|
|
15
|
+
var engine_1 = require("./engine");
|
|
16
|
+
Object.defineProperty(exports, "LoyaltyEngine", { enumerable: true, get: function () { return engine_1.LoyaltyEngine; } });
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engines/loyalty/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAiCH,WAAW;AACX,uCAAmD;AAA1C,iHAAA,qBAAqB,OAAA;AAE9B,WAAW;AACX,uCAA8D;AAArD,2GAAA,eAAe,OAAA;AAAE,2GAAA,eAAe,OAAA;AAEzC,SAAS;AACT,mCAAyC;AAAhC,uGAAA,aAAa,OAAA"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loyalty Engine Strategy
|
|
3
|
+
*
|
|
4
|
+
* Core execution logic for all loyalty strategies:
|
|
5
|
+
* - earning: compute points from purchase/activity events with category multipliers and promotion stacking
|
|
6
|
+
* - redemption: process point redemption with balance validation
|
|
7
|
+
* - tier-evaluation: evaluate members against tier thresholds with upgrade/downgrade detection
|
|
8
|
+
*/
|
|
9
|
+
import type { IWorkingMemory } from '../../core';
|
|
10
|
+
import type { CompiledLoyaltyRuleSet, CompiledEarningRuleSet, LoyaltyOptions, EarningResult, LoyaltyResult, PointTransaction, MemberBalance } from './types';
|
|
11
|
+
export declare class LoyaltyExecutor {
|
|
12
|
+
run(ruleSet: CompiledLoyaltyRuleSet, wm: IWorkingMemory, ledger: Map<string, MemberBalance>, options?: LoyaltyOptions): LoyaltyResult;
|
|
13
|
+
runEarning(ruleSet: CompiledEarningRuleSet, wm: IWorkingMemory, ledger: Map<string, MemberBalance>, options?: LoyaltyOptions): EarningResult;
|
|
14
|
+
/**
|
|
15
|
+
* Process a single earning event (for streaming ingest).
|
|
16
|
+
*/
|
|
17
|
+
earnSingle(eventData: Record<string, any>, ruleSet: CompiledEarningRuleSet, ledger: Map<string, MemberBalance>, asOf?: Date): {
|
|
18
|
+
memberId: string;
|
|
19
|
+
pointsEarned: number;
|
|
20
|
+
bonusPointsEarned: number;
|
|
21
|
+
promotionsApplied: string[];
|
|
22
|
+
newBalance: number;
|
|
23
|
+
transactions: PointTransaction[];
|
|
24
|
+
};
|
|
25
|
+
private runRedemption;
|
|
26
|
+
private runTierEvaluation;
|
|
27
|
+
private findMatchingEarningRules;
|
|
28
|
+
getOrCreateBalance(ledger: Map<string, MemberBalance>, memberId: string): MemberBalance;
|
|
29
|
+
private evaluateMemberTier;
|
|
30
|
+
private getTierMultiplierBonus;
|
|
31
|
+
private resolveTierStatus;
|
|
32
|
+
}
|
|
33
|
+
/** Singleton instance */
|
|
34
|
+
export declare const loyaltyStrategy: LoyaltyExecutor;
|
|
35
|
+
//# sourceMappingURL=strategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strategy.d.ts","sourceRoot":"","sources":["../../../src/engines/loyalty/strategy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,KAAK,EACV,sBAAsB,EACtB,sBAAsB,EAGtB,cAAc,EACd,aAAa,EAGb,aAAa,EACb,gBAAgB,EAChB,aAAa,EAMd,MAAM,SAAS,CAAC;AAyCjB,qBAAa,eAAe;IAC1B,GAAG,CACD,OAAO,EAAE,sBAAsB,EAC/B,EAAE,EAAE,cAAc,EAClB,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EAClC,OAAO,GAAE,cAAmB,GAC3B,aAAa;IAiBhB,UAAU,CACR,OAAO,EAAE,sBAAsB,EAC/B,EAAE,EAAE,cAAc,EAClB,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EAClC,OAAO,GAAE,cAAmB,GAC3B,aAAa;IAkGhB;;OAEG;IACH,UAAU,CACR,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC9B,OAAO,EAAE,sBAAsB,EAC/B,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EAClC,IAAI,GAAE,IAAiB,GACtB;QACD,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,iBAAiB,EAAE,MAAM,EAAE,CAAC;QAC5B,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,gBAAgB,EAAE,CAAC;KAClC;IAkFD,OAAO,CAAC,aAAa;IAqErB,OAAO,CAAC,iBAAiB;IAyFzB,OAAO,CAAC,wBAAwB;IAShC,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa;IAgBvF,OAAO,CAAC,kBAAkB;IAoB1B,OAAO,CAAC,sBAAsB;IAS9B,OAAO,CAAC,iBAAiB;CAwB1B;AAED,yBAAyB;AACzB,eAAO,MAAM,eAAe,iBAAwB,CAAC"}
|
|
@@ -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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"}
|