ts-client-lib 0.0.7
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/README.md +76 -0
- package/auth/TSJWT.d.ts +29 -0
- package/auth/TSJWT.js +44 -0
- package/auth/TSOAuth.d.ts +132 -0
- package/auth/TSOAuth.js +230 -0
- package/devices/TSCordova.d.ts +5 -0
- package/devices/TSCordova.js +52 -0
- package/entities/TSCountries.d.ts +14 -0
- package/entities/TSCountries.js +1188 -0
- package/entities/TSCurrencies.d.ts +35 -0
- package/entities/TSCurrencies.js +604 -0
- package/entities/TSMobilePhones.d.ts +167 -0
- package/entities/TSMobilePhones.js +206 -0
- package/entities/TSMoney.d.ts +149 -0
- package/entities/TSMoney.js +311 -0
- package/entities/currency-amount.d.ts +13 -0
- package/entities/currency-amount.js +43 -0
- package/finance/TSBonus.d.ts +197 -0
- package/finance/TSBonus.js +530 -0
- package/finance/TSKYC.d.ts +563 -0
- package/finance/TSKYC.js +1066 -0
- package/finance/TSTax.d.ts +49 -0
- package/finance/TSTax.js +106 -0
- package/finance/bonus-money.d.ts +41 -0
- package/finance/bonus-money.js +61 -0
- package/games/TSBetSlip.d.ts +72 -0
- package/games/TSBetSlip.js +179 -0
- package/games/TSBetSystem.d.ts +4 -0
- package/games/TSBetSystem.js +48 -0
- package/games/TSLotto.d.ts +35 -0
- package/games/TSLotto.js +205 -0
- package/games/TSPool.d.ts +28 -0
- package/games/TSPool.js +88 -0
- package/package.json +93 -0
- package/utils/TSArray.d.ts +9 -0
- package/utils/TSArray.js +87 -0
- package/utils/TSBoolean.d.ts +4 -0
- package/utils/TSBoolean.js +24 -0
- package/utils/TSCache.d.ts +167 -0
- package/utils/TSCache.js +531 -0
- package/utils/TSDate.d.ts +8 -0
- package/utils/TSDate.js +67 -0
- package/utils/TSHeuristic.d.ts +20 -0
- package/utils/TSHeuristic.js +197 -0
- package/utils/TSLZS.d.ts +42 -0
- package/utils/TSLZS.js +343 -0
- package/utils/TSLog.d.ts +40 -0
- package/utils/TSLog.js +110 -0
- package/utils/TSNumber.d.ts +6 -0
- package/utils/TSNumber.js +68 -0
- package/utils/TSObject.d.ts +29 -0
- package/utils/TSObject.js +312 -0
- package/utils/TSPagination.d.ts +282 -0
- package/utils/TSPagination.js +425 -0
- package/utils/TSPaginationMulti.d.ts +77 -0
- package/utils/TSPaginationMulti.js +356 -0
- package/utils/TSString.d.ts +10 -0
- package/utils/TSString.js +107 -0
- package/utils/TSValidator.d.ts +16 -0
- package/utils/TSValidator.js +74 -0
- package/utils/TSWorker.d.ts +3 -0
- package/utils/TSWorker.js +32 -0
- package/utils/diacritics-removal-map.d.ts +5 -0
- package/utils/diacritics-removal-map.js +341 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TSCurrencies = exports.TSMoney = void 0;
|
|
4
|
+
var TSCurrencies_1 = require("./TSCurrencies");
|
|
5
|
+
Object.defineProperty(exports, "TSCurrencies", { enumerable: true, get: function () { return TSCurrencies_1.TSCurrencies; } });
|
|
6
|
+
var isInt = function (n) {
|
|
7
|
+
return Number(n) === n && n % 1 === 0;
|
|
8
|
+
};
|
|
9
|
+
var decimalPlaces = function (num) {
|
|
10
|
+
var match = String(num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
|
|
11
|
+
return !match ? 0 : Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? Number(match[2]) : 0));
|
|
12
|
+
};
|
|
13
|
+
var assertSameCurrency = function (left, right) {
|
|
14
|
+
if (left.currency !== right.currency) {
|
|
15
|
+
throw new Error('Different currencies');
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var assertType = function (other) {
|
|
19
|
+
if (!(other instanceof TSMoney)) {
|
|
20
|
+
throw new TypeError('Instance of TSMoney required');
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
var assertOperand = function (operand) {
|
|
24
|
+
if (isNaN(parseFloat(String(operand))) && !isFinite(operand)) {
|
|
25
|
+
throw new TypeError('Operand must be a number');
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
var getCurrencyObject = function (currency) {
|
|
29
|
+
return (0, TSCurrencies_1.resolveCurrency)(currency);
|
|
30
|
+
};
|
|
31
|
+
var TSMoney = /** @class */ (function () {
|
|
32
|
+
/**
|
|
33
|
+
* Creates a new TSMoney instance. The created TSMoney instances is a value object thus it is immutable.
|
|
34
|
+
*
|
|
35
|
+
* @param {Number} amount
|
|
36
|
+
* @param {Object/String} currency
|
|
37
|
+
* @returns {TSMoney}
|
|
38
|
+
* @constructor
|
|
39
|
+
*/
|
|
40
|
+
function TSMoney(amount, currency) {
|
|
41
|
+
if (typeof currency === 'string') {
|
|
42
|
+
currency = getCurrencyObject(currency);
|
|
43
|
+
}
|
|
44
|
+
if (typeof currency !== 'object') {
|
|
45
|
+
throw new TypeError('Invalid currency');
|
|
46
|
+
}
|
|
47
|
+
if (!isInt(amount)) {
|
|
48
|
+
throw new TypeError('Amount must be an integer');
|
|
49
|
+
}
|
|
50
|
+
this.amount = amount;
|
|
51
|
+
this.currency = currency.code;
|
|
52
|
+
Object.freeze(this);
|
|
53
|
+
}
|
|
54
|
+
TSMoney.fromInteger = function (amount, currency) {
|
|
55
|
+
if (typeof amount === 'object') {
|
|
56
|
+
if (amount.amount === undefined || amount.currency === undefined) {
|
|
57
|
+
throw new TypeError('Missing required parameters amount,currency');
|
|
58
|
+
}
|
|
59
|
+
currency = amount.currency;
|
|
60
|
+
amount = amount.amount;
|
|
61
|
+
}
|
|
62
|
+
if (!isInt(amount)) {
|
|
63
|
+
throw new TypeError('Amount must be an integer value');
|
|
64
|
+
}
|
|
65
|
+
return new TSMoney(amount, currency);
|
|
66
|
+
};
|
|
67
|
+
TSMoney.fromDecimal = function (amount, currency, rounder) {
|
|
68
|
+
if (typeof amount === 'object') {
|
|
69
|
+
if (amount.amount === undefined || amount.currency === undefined) {
|
|
70
|
+
throw new TypeError('Missing required parameters amount,currency');
|
|
71
|
+
}
|
|
72
|
+
rounder = currency;
|
|
73
|
+
currency = amount.currency;
|
|
74
|
+
amount = amount.amount;
|
|
75
|
+
}
|
|
76
|
+
if (typeof currency === 'string') {
|
|
77
|
+
currency = getCurrencyObject(currency);
|
|
78
|
+
}
|
|
79
|
+
if (typeof currency !== 'object') {
|
|
80
|
+
throw new TypeError('Invalid currency');
|
|
81
|
+
}
|
|
82
|
+
if (rounder === undefined) {
|
|
83
|
+
var decimals = decimalPlaces(amount);
|
|
84
|
+
if (decimals > currency.decimal_digits) {
|
|
85
|
+
throw new Error("The currency ".concat(currency.code, " supports only ").concat(currency.decimal_digits, " decimal digits"));
|
|
86
|
+
}
|
|
87
|
+
rounder = Math.round;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
if (['round', 'floor', 'ceil'].indexOf(rounder) === -1 && typeof rounder !== 'function') {
|
|
91
|
+
throw new TypeError('Invalid parameter rounder');
|
|
92
|
+
}
|
|
93
|
+
if (typeof rounder === 'string') {
|
|
94
|
+
var mathRounders = { round: Math.round, floor: Math.floor, ceil: Math.ceil };
|
|
95
|
+
rounder = mathRounders[rounder];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
var precisionMultiplier = Math.pow(10, currency.decimal_digits);
|
|
99
|
+
var resultAmount = amount * precisionMultiplier;
|
|
100
|
+
resultAmount = rounder(resultAmount);
|
|
101
|
+
return new TSMoney(resultAmount, currency);
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Returns true if the two instances of TSMoney are equal, false otherwise.
|
|
105
|
+
*
|
|
106
|
+
* @param {TSMoney} other
|
|
107
|
+
* @returns {Boolean}
|
|
108
|
+
*/
|
|
109
|
+
TSMoney.prototype.equals = function (other) {
|
|
110
|
+
assertType(other);
|
|
111
|
+
return this.amount === other.amount && this.currency === other.currency;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Adds the two objects together creating a new TSMoney instance that holds the result of the operation.
|
|
115
|
+
*
|
|
116
|
+
* @param {TSMoney} other
|
|
117
|
+
* @returns {TSMoney}
|
|
118
|
+
*/
|
|
119
|
+
TSMoney.prototype.add = function (other) {
|
|
120
|
+
assertType(other);
|
|
121
|
+
assertSameCurrency(this, other);
|
|
122
|
+
return new TSMoney(this.amount + other.amount, this.currency);
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Subtracts the two objects creating a new TSMoney instance that holds the result of the operation.
|
|
126
|
+
*
|
|
127
|
+
* @param {TSMoney} other
|
|
128
|
+
* @returns {TSMoney}
|
|
129
|
+
*/
|
|
130
|
+
TSMoney.prototype.subtract = function (other) {
|
|
131
|
+
assertType(other);
|
|
132
|
+
assertSameCurrency(this, other);
|
|
133
|
+
return new TSMoney(this.amount - other.amount, this.currency);
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Multiplies the object by the multiplier returning a new TSMoney instance that holds the result of the operation.
|
|
137
|
+
*
|
|
138
|
+
* @param {Number} multiplier
|
|
139
|
+
* @param {Function} [fn=Math.round]
|
|
140
|
+
* @returns {TSMoney}
|
|
141
|
+
*/
|
|
142
|
+
TSMoney.prototype.multiply = function (multiplier, fn) {
|
|
143
|
+
if (typeof fn !== 'function') {
|
|
144
|
+
fn = Math.round;
|
|
145
|
+
}
|
|
146
|
+
assertOperand(multiplier);
|
|
147
|
+
return new TSMoney(fn(this.amount * multiplier), this.currency);
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Divides the object by the multiplier returning a new TSMoney instance that holds the result of the operation.
|
|
151
|
+
*
|
|
152
|
+
* @param {Number} divisor
|
|
153
|
+
* @param {Function} [fn=Math.round]
|
|
154
|
+
* @returns {TSMoney}
|
|
155
|
+
*/
|
|
156
|
+
TSMoney.prototype.divide = function (divisor, fn) {
|
|
157
|
+
if (typeof fn !== 'function') {
|
|
158
|
+
fn = Math.round;
|
|
159
|
+
}
|
|
160
|
+
assertOperand(divisor);
|
|
161
|
+
return new TSMoney(fn(this.amount / divisor), this.currency);
|
|
162
|
+
};
|
|
163
|
+
/**
|
|
164
|
+
* Allocates fund bases on the ratios provided returing an array of objects as a product of the allocation.
|
|
165
|
+
*
|
|
166
|
+
* @param {Array} other
|
|
167
|
+
* @returns {Array.TSMoney}
|
|
168
|
+
*/
|
|
169
|
+
TSMoney.prototype.allocate = function (ratios) {
|
|
170
|
+
var _this = this;
|
|
171
|
+
var remainder = this.amount;
|
|
172
|
+
var results = [];
|
|
173
|
+
var total = 0;
|
|
174
|
+
ratios.forEach(function (ratio) {
|
|
175
|
+
total += ratio;
|
|
176
|
+
});
|
|
177
|
+
ratios.forEach(function (ratio) {
|
|
178
|
+
var share = Math.floor(_this.amount * ratio / total);
|
|
179
|
+
results.push(new TSMoney(share, _this.currency));
|
|
180
|
+
remainder -= share;
|
|
181
|
+
});
|
|
182
|
+
for (var i = 0; remainder > 0; i++) {
|
|
183
|
+
results[i] = new TSMoney(results[i].amount + 1, results[i].currency);
|
|
184
|
+
remainder--;
|
|
185
|
+
}
|
|
186
|
+
return results;
|
|
187
|
+
};
|
|
188
|
+
/**
|
|
189
|
+
* Compares two instances of TSMoney.
|
|
190
|
+
*
|
|
191
|
+
* @param {TSMoney} other
|
|
192
|
+
* @returns {Number}
|
|
193
|
+
*/
|
|
194
|
+
TSMoney.prototype.compare = function (other) {
|
|
195
|
+
assertType(other);
|
|
196
|
+
assertSameCurrency(this, other);
|
|
197
|
+
if (this.amount === other.amount)
|
|
198
|
+
return 0;
|
|
199
|
+
if (this.amount > other.amount)
|
|
200
|
+
return 1;
|
|
201
|
+
return -1;
|
|
202
|
+
};
|
|
203
|
+
/**
|
|
204
|
+
* Checks whether the value represented by this object is greater than the other.
|
|
205
|
+
*
|
|
206
|
+
* @param {TSMoney} other
|
|
207
|
+
* @returns {boolean}
|
|
208
|
+
*/
|
|
209
|
+
TSMoney.prototype.greaterThan = function (other) {
|
|
210
|
+
return 1 === this.compare(other);
|
|
211
|
+
};
|
|
212
|
+
/**
|
|
213
|
+
* Checks whether the value represented by this object is greater or equal to the other.
|
|
214
|
+
*
|
|
215
|
+
* @param {TSMoney} other
|
|
216
|
+
* @returns {boolean}
|
|
217
|
+
*/
|
|
218
|
+
TSMoney.prototype.greaterThanOrEqual = function (other) {
|
|
219
|
+
return 0 <= this.compare(other);
|
|
220
|
+
};
|
|
221
|
+
/**
|
|
222
|
+
* Checks whether the value represented by this object is less than the other.
|
|
223
|
+
*
|
|
224
|
+
* @param {TSMoney} other
|
|
225
|
+
* @returns {boolean}
|
|
226
|
+
*/
|
|
227
|
+
TSMoney.prototype.lessThan = function (other) {
|
|
228
|
+
return -1 === this.compare(other);
|
|
229
|
+
};
|
|
230
|
+
/**
|
|
231
|
+
* Checks whether the value represented by this object is less than or equal to the other.
|
|
232
|
+
*
|
|
233
|
+
* @param {TSMoney} other
|
|
234
|
+
* @returns {boolean}
|
|
235
|
+
*/
|
|
236
|
+
TSMoney.prototype.lessThanOrEqual = function (other) {
|
|
237
|
+
return 0 >= this.compare(other);
|
|
238
|
+
};
|
|
239
|
+
/**
|
|
240
|
+
* Returns true if the amount is zero.
|
|
241
|
+
*
|
|
242
|
+
* @returns {boolean}
|
|
243
|
+
*/
|
|
244
|
+
TSMoney.prototype.isZero = function () {
|
|
245
|
+
return this.amount === 0;
|
|
246
|
+
};
|
|
247
|
+
/**
|
|
248
|
+
* Returns true if the amount is positive.
|
|
249
|
+
*
|
|
250
|
+
* @returns {boolean}
|
|
251
|
+
*/
|
|
252
|
+
TSMoney.prototype.isPositive = function () {
|
|
253
|
+
return this.amount > 0;
|
|
254
|
+
};
|
|
255
|
+
/**
|
|
256
|
+
* Returns true if the amount is negative.
|
|
257
|
+
*
|
|
258
|
+
* @returns {boolean}
|
|
259
|
+
*/
|
|
260
|
+
TSMoney.prototype.isNegative = function () {
|
|
261
|
+
return this.amount < 0;
|
|
262
|
+
};
|
|
263
|
+
/**
|
|
264
|
+
* Returns the decimal value as a float.
|
|
265
|
+
*
|
|
266
|
+
* @returns {number}
|
|
267
|
+
*/
|
|
268
|
+
TSMoney.prototype.toDecimal = function () {
|
|
269
|
+
return Number(this.toString());
|
|
270
|
+
};
|
|
271
|
+
/**
|
|
272
|
+
* Returns the decimal value as a string.
|
|
273
|
+
*
|
|
274
|
+
* @returns {string}
|
|
275
|
+
*/
|
|
276
|
+
TSMoney.prototype.toString = function () {
|
|
277
|
+
var currency = getCurrencyObject(this.currency);
|
|
278
|
+
return (this.amount / Math.pow(10, currency.decimal_digits)).toFixed(currency.decimal_digits);
|
|
279
|
+
};
|
|
280
|
+
/**
|
|
281
|
+
* Returns a serialised version of the instance.
|
|
282
|
+
*
|
|
283
|
+
* @returns {{amount: number, currency: string}}
|
|
284
|
+
*/
|
|
285
|
+
TSMoney.prototype.toJSON = function () {
|
|
286
|
+
return { amount: this.amount, currency: this.currency };
|
|
287
|
+
};
|
|
288
|
+
/**
|
|
289
|
+
* Returns the amount represented by this object.
|
|
290
|
+
*
|
|
291
|
+
* @returns {number}
|
|
292
|
+
*/
|
|
293
|
+
TSMoney.prototype.getAmount = function () {
|
|
294
|
+
return this.amount;
|
|
295
|
+
};
|
|
296
|
+
/**
|
|
297
|
+
* Returns the currency code represented by this object.
|
|
298
|
+
*/
|
|
299
|
+
TSMoney.prototype.getCurrency = function () {
|
|
300
|
+
return this.currency;
|
|
301
|
+
};
|
|
302
|
+
/**
|
|
303
|
+
* Returns the full currency object
|
|
304
|
+
*/
|
|
305
|
+
TSMoney.prototype.getCurrencyInfo = function () {
|
|
306
|
+
return getCurrencyObject(this.currency);
|
|
307
|
+
};
|
|
308
|
+
return TSMoney;
|
|
309
|
+
}());
|
|
310
|
+
exports.TSMoney = TSMoney;
|
|
311
|
+
Object.assign(TSMoney, TSCurrencies_1.TSCurrencies);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a **decimal** amount (e.g. dollars) to minor units using `decimal_digits` from `TSCurrencies`.
|
|
3
|
+
*/
|
|
4
|
+
export declare function toSmallestUnit(amount: number, currencyCode: string): number;
|
|
5
|
+
/**
|
|
6
|
+
* Convert minor units to a **decimal** display amount.
|
|
7
|
+
*/
|
|
8
|
+
export declare function fromSmallestUnit(amount: number, currencyCode: string): number;
|
|
9
|
+
/**
|
|
10
|
+
* Format **minor-unit** amounts for display (parity with former core-service `formatCurrency`).
|
|
11
|
+
* Unknown codes fall back to `amount + code`.
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatCurrency(amountMinor: number, currencyCode: string, locale?: string): string;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toSmallestUnit = toSmallestUnit;
|
|
4
|
+
exports.fromSmallestUnit = fromSmallestUnit;
|
|
5
|
+
exports.formatCurrency = formatCurrency;
|
|
6
|
+
var TSCurrencies_js_1 = require("./TSCurrencies.js");
|
|
7
|
+
/**
|
|
8
|
+
* Convert a **decimal** amount (e.g. dollars) to minor units using `decimal_digits` from `TSCurrencies`.
|
|
9
|
+
*/
|
|
10
|
+
function toSmallestUnit(amount, currencyCode) {
|
|
11
|
+
var c = (0, TSCurrencies_js_1.resolveCurrency)(currencyCode);
|
|
12
|
+
return Math.round(amount * Math.pow(10, c.decimal_digits));
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Convert minor units to a **decimal** display amount.
|
|
16
|
+
*/
|
|
17
|
+
function fromSmallestUnit(amount, currencyCode) {
|
|
18
|
+
var c = (0, TSCurrencies_js_1.resolveCurrency)(currencyCode);
|
|
19
|
+
return amount / Math.pow(10, c.decimal_digits);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Format **minor-unit** amounts for display (parity with former core-service `formatCurrency`).
|
|
23
|
+
* Unknown codes fall back to `amount + code`.
|
|
24
|
+
*/
|
|
25
|
+
function formatCurrency(amountMinor, currencyCode, locale) {
|
|
26
|
+
if (locale === void 0) { locale = 'en-US'; }
|
|
27
|
+
var currency = (0, TSCurrencies_js_1.tryGetCurrency)(currencyCode);
|
|
28
|
+
if (!currency)
|
|
29
|
+
return "".concat(amountMinor, " ").concat(currencyCode);
|
|
30
|
+
var displayAmount = fromSmallestUnit(amountMinor, currencyCode);
|
|
31
|
+
if ((0, TSCurrencies_js_1.isCryptoCurrencyCode)(currencyCode)) {
|
|
32
|
+
return "".concat(displayAmount.toFixed(Math.min(currency.decimal_digits, 8)), " ").concat(currency.symbol);
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
return new Intl.NumberFormat(locale, {
|
|
36
|
+
style: 'currency',
|
|
37
|
+
currency: currencyCode
|
|
38
|
+
}).format(displayAmount);
|
|
39
|
+
}
|
|
40
|
+
catch (_a) {
|
|
41
|
+
return "".concat(currency.symbol).concat(displayAmount.toFixed(currency.decimal_digits));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { TSMoney } from '../entities/TSMoney';
|
|
2
|
+
import { type CurrencyCode } from '../entities/TSCurrencies';
|
|
3
|
+
import { type TSMoneyJSON } from './bonus-money';
|
|
4
|
+
export type { TSMoneyJSON } from './bonus-money';
|
|
5
|
+
export type { CurrencyCode };
|
|
6
|
+
export { parseMoneyJSON, toMoneyJSON, assertCoherentMoneyFields, assertKnownCurrenciesOnTemplate, hasCurrencyCode } from './bonus-money';
|
|
7
|
+
/**
|
|
8
|
+
* BonusEligibility - Client-Safe Eligibility Checker
|
|
9
|
+
*
|
|
10
|
+
* Single source of truth for bonus eligibility rules. No database dependencies – pure functions only.
|
|
11
|
+
* Use on both client and server so behaviour stays consistent and code is not duplicated.
|
|
12
|
+
*
|
|
13
|
+
* ## Server vs Client
|
|
14
|
+
*
|
|
15
|
+
* - **Client (e.g. app, scripts):** Call `BonusEligibility.check(template, context)` to show
|
|
16
|
+
* “Eligible” / “Not eligible” and reasons, or `findBestForDeposit` / `getEligible` for UX.
|
|
17
|
+
* Server still enforces eligibility on claim (and adds DB-only rules: already claimed, cooldown, stacking).
|
|
18
|
+
*
|
|
19
|
+
* - **Server (bonus-service):** Uses this module via `ValidatorChain`, which runs
|
|
20
|
+
* `BonusEligibility.check()` for all client-safe rules, then server-only validators (max per user,
|
|
21
|
+
* cooldown, already claimed, stacking, referral). See bonus-service/.../validators.ts.
|
|
22
|
+
*
|
|
23
|
+
* Usage:
|
|
24
|
+
* ```typescript
|
|
25
|
+
* import { BonusEligibility } from 'ts-client-lib/finance/TSBonus';
|
|
26
|
+
*
|
|
27
|
+
* // Check single template
|
|
28
|
+
* const result = BonusEligibility.check(template, context);
|
|
29
|
+
* if (result.eligible) {
|
|
30
|
+
* notify(`You're eligible for ${template.name}!`);
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* // Check multiple templates
|
|
34
|
+
* const eligible = BonusEligibility.checkMany(templates, context);
|
|
35
|
+
* eligible.filter(r => r.eligible).forEach(r => {
|
|
36
|
+
* notify(`Eligible: ${r.template.name}`);
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* // Find best bonus for deposit
|
|
40
|
+
* const best = BonusEligibility.findBestForDeposit(templates, 100, 'USD');
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export type BonusType = 'welcome' | 'first_deposit' | 'first_purchase' | 'first_action' | 'reload' | 'top_up' | 'referral' | 'referee' | 'commission' | 'activity' | 'milestone' | 'streak' | 'winback' | 'cashback' | 'consolation' | 'free_credit' | 'trial' | 'loyalty' | 'loyalty_points' | 'vip' | 'tier_upgrade' | 'birthday' | 'anniversary' | 'seasonal' | 'daily_login' | 'flash' | 'achievement' | 'task_completion' | 'challenge' | 'tournament' | 'leaderboard' | 'selection' | 'combo' | 'bundle' | 'promo_code' | 'special_event' | 'custom';
|
|
44
|
+
export type BonusDomain = 'universal' | 'casino' | 'sports' | 'poker' | 'crypto' | 'ecommerce' | 'saas' | 'gaming' | 'fintech' | 'social';
|
|
45
|
+
export type BonusValueType = 'fixed' | 'percentage' | 'tiered' | 'dynamic';
|
|
46
|
+
export type BonusStatus = 'pending' | 'active' | 'in_progress' | 'requirements_met' | 'converted' | 'claimed' | 'expired' | 'cancelled' | 'forfeited' | 'locked';
|
|
47
|
+
/**
|
|
48
|
+
* Minimal BonusTemplate interface for eligibility checking.
|
|
49
|
+
* Your full template may have more fields.
|
|
50
|
+
*/
|
|
51
|
+
export interface BonusTemplate {
|
|
52
|
+
id: string;
|
|
53
|
+
name: string;
|
|
54
|
+
code: string;
|
|
55
|
+
type: BonusType;
|
|
56
|
+
domain: BonusDomain;
|
|
57
|
+
description?: string;
|
|
58
|
+
valueType: BonusValueType;
|
|
59
|
+
value: number;
|
|
60
|
+
currency: CurrencyCode;
|
|
61
|
+
/** Optional strict transport: minor units + ISO code; must match legacy fields when set. */
|
|
62
|
+
valueMoney?: TSMoneyJSON;
|
|
63
|
+
supportedCurrencies?: CurrencyCode[];
|
|
64
|
+
maxValue?: number;
|
|
65
|
+
maxValueMoney?: TSMoneyJSON;
|
|
66
|
+
minDeposit?: number;
|
|
67
|
+
minDepositMoney?: TSMoneyJSON;
|
|
68
|
+
turnoverMultiplier: number;
|
|
69
|
+
activityContributions?: Record<string, number>;
|
|
70
|
+
validFrom: Date | string;
|
|
71
|
+
validUntil: Date | string;
|
|
72
|
+
claimDeadlineDays?: number;
|
|
73
|
+
usageDeadlineDays?: number;
|
|
74
|
+
maxUsesTotal?: number;
|
|
75
|
+
maxUsesPerUser?: number;
|
|
76
|
+
currentUsesTotal?: number;
|
|
77
|
+
eligibleTiers?: string[];
|
|
78
|
+
eligibleCountries?: string[];
|
|
79
|
+
excludedCountries?: string[];
|
|
80
|
+
minAccountAgeDays?: number;
|
|
81
|
+
requiresDeposit?: boolean;
|
|
82
|
+
requiresVerification?: boolean;
|
|
83
|
+
requiredKYCTier?: string;
|
|
84
|
+
stackable?: boolean;
|
|
85
|
+
excludedBonusTypes?: BonusType[];
|
|
86
|
+
minSelections?: number;
|
|
87
|
+
maxSelections?: number;
|
|
88
|
+
min?: number;
|
|
89
|
+
max?: number;
|
|
90
|
+
minTotal?: number;
|
|
91
|
+
maxTotal?: number;
|
|
92
|
+
minActions?: number;
|
|
93
|
+
comboMultiplier?: number;
|
|
94
|
+
eligibleCategories?: string[];
|
|
95
|
+
isActive: boolean;
|
|
96
|
+
priority?: number;
|
|
97
|
+
tags?: string[];
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Context for eligibility checking.
|
|
101
|
+
* Populate with user's current state.
|
|
102
|
+
*/
|
|
103
|
+
export interface BonusEligibilityContext {
|
|
104
|
+
userId?: string;
|
|
105
|
+
tenantId?: string;
|
|
106
|
+
currency?: CurrencyCode;
|
|
107
|
+
userTier?: string;
|
|
108
|
+
country?: string;
|
|
109
|
+
kycTier?: string;
|
|
110
|
+
kycStatus?: string;
|
|
111
|
+
depositAmount?: number;
|
|
112
|
+
isFirstDeposit?: boolean;
|
|
113
|
+
isFirstPurchase?: boolean;
|
|
114
|
+
selectionCount?: number;
|
|
115
|
+
selections?: Array<{
|
|
116
|
+
id: string;
|
|
117
|
+
value?: number;
|
|
118
|
+
category?: string;
|
|
119
|
+
}>;
|
|
120
|
+
selectionsTotal?: number;
|
|
121
|
+
activityCategory?: string;
|
|
122
|
+
activityAmount?: number;
|
|
123
|
+
consecutiveDays?: number;
|
|
124
|
+
isVerified?: boolean;
|
|
125
|
+
accountAgeDays?: number;
|
|
126
|
+
currentDate?: Date;
|
|
127
|
+
metadata?: Record<string, unknown>;
|
|
128
|
+
}
|
|
129
|
+
export interface BonusEligibilityResult {
|
|
130
|
+
template: BonusTemplate;
|
|
131
|
+
eligible: boolean;
|
|
132
|
+
reasons: string[];
|
|
133
|
+
calculatedValue?: number;
|
|
134
|
+
/** Same calculation as `calculatedValue`, as **TSMoney** (minor units for fixed; decimal→minor for %). */
|
|
135
|
+
calculatedValueMoney?: TSMoney;
|
|
136
|
+
turnoverRequired?: number;
|
|
137
|
+
turnoverRequiredMoney?: TSMoney;
|
|
138
|
+
}
|
|
139
|
+
export interface BonusValidationRule {
|
|
140
|
+
name: string;
|
|
141
|
+
check: (template: BonusTemplate, context: BonusEligibilityContext) => boolean;
|
|
142
|
+
message: (template: BonusTemplate, context: BonusEligibilityContext) => string;
|
|
143
|
+
}
|
|
144
|
+
export declare class BonusEligibility {
|
|
145
|
+
/** Parse a date value that may be a Date, ISO string, or numeric timestamp string. */
|
|
146
|
+
private static parseDate;
|
|
147
|
+
private static readonly rules;
|
|
148
|
+
/**
|
|
149
|
+
* Check eligibility for a single bonus template.
|
|
150
|
+
*/
|
|
151
|
+
static check(template: BonusTemplate, context?: BonusEligibilityContext): BonusEligibilityResult;
|
|
152
|
+
/**
|
|
153
|
+
* Check eligibility for multiple templates.
|
|
154
|
+
* Returns all results, sorted by priority (highest first).
|
|
155
|
+
*/
|
|
156
|
+
static checkMany(templates: BonusTemplate[], context?: BonusEligibilityContext): BonusEligibilityResult[];
|
|
157
|
+
/**
|
|
158
|
+
* Get only eligible bonuses from a list.
|
|
159
|
+
*/
|
|
160
|
+
static getEligible(templates: BonusTemplate[], context?: BonusEligibilityContext): BonusEligibilityResult[];
|
|
161
|
+
/**
|
|
162
|
+
* Find the best bonus for a deposit amount.
|
|
163
|
+
*/
|
|
164
|
+
static findBestForDeposit(templates: BonusTemplate[], amount: number, currency: CurrencyCode, context?: Partial<BonusEligibilityContext>): BonusEligibilityResult | null;
|
|
165
|
+
/**
|
|
166
|
+
* Find eligible selection/combo bonuses based on selection count.
|
|
167
|
+
*/
|
|
168
|
+
static findForSelections(templates: BonusTemplate[], selectionCount: number, context?: Partial<BonusEligibilityContext>): BonusEligibilityResult[];
|
|
169
|
+
/**
|
|
170
|
+
* Check if user qualifies for any bonus of a specific type.
|
|
171
|
+
*/
|
|
172
|
+
static hasEligibleOfType(templates: BonusTemplate[], type: BonusType, context?: BonusEligibilityContext): BonusEligibilityResult | null;
|
|
173
|
+
/**
|
|
174
|
+
* Group eligible bonuses by type.
|
|
175
|
+
*/
|
|
176
|
+
static groupByType(templates: BonusTemplate[], context?: BonusEligibilityContext): Map<BonusType, BonusEligibilityResult[]>;
|
|
177
|
+
static calculateValue(template: BonusTemplate, context: BonusEligibilityContext): number;
|
|
178
|
+
static calculateTurnover(template: BonusTemplate, context: BonusEligibilityContext): number;
|
|
179
|
+
/**
|
|
180
|
+
* Bonus value as **TSMoney**. `fixed` uses minor integer units; other value types use `fromDecimal`
|
|
181
|
+
* on the same numeric result as `calculateValue`.
|
|
182
|
+
*/
|
|
183
|
+
static calculateValueMoney(template: BonusTemplate, context: BonusEligibilityContext): TSMoney;
|
|
184
|
+
static calculateTurnoverMoney(template: BonusTemplate, context: BonusEligibilityContext): TSMoney;
|
|
185
|
+
static getContributionRate(template: BonusTemplate, category: string): number;
|
|
186
|
+
static calculateTurnoverContribution(template: BonusTemplate, amount: number, category: string): number;
|
|
187
|
+
private static getTierMultiplier;
|
|
188
|
+
private static calculateDynamicValue;
|
|
189
|
+
static addRule(rule: BonusValidationRule): void;
|
|
190
|
+
static removeRule(name: string): void;
|
|
191
|
+
static getRuleNames(): string[];
|
|
192
|
+
}
|
|
193
|
+
export declare const checkBonusEligibility: typeof BonusEligibility.check;
|
|
194
|
+
export declare const checkManyBonusEligibility: typeof BonusEligibility.checkMany;
|
|
195
|
+
export declare const getEligibleBonuses: typeof BonusEligibility.getEligible;
|
|
196
|
+
export declare const findBestDepositBonus: typeof BonusEligibility.findBestForDeposit;
|
|
197
|
+
export declare const findSelectionBonuses: typeof BonusEligibility.findForSelections;
|