shufflecom-calculations 3.3.9 → 3.3.10
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/lib/regex/index.d.ts +1 -0
- package/lib/regex/index.js +3 -2
- package/lib/regex/index.js.map +1 -1
- package/lib/sports/calculate-sports-payout-odds.d.ts +2 -1
- package/lib/sports/calculate-sports-payout-odds.js +12 -1
- package/lib/sports/calculate-sports-payout-odds.js.map +1 -1
- package/lib/sports/sports.types.d.ts +11 -1
- package/lib/sports/sports.types.js +9 -3
- package/lib/sports/sports.types.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/regex/index.ts +5 -1
- package/src/regex/regex.spec.ts +41 -6
- package/src/sports/calculate-sports-payout-odds.ts +26 -1
- package/src/sports/sports.types.ts +14 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shufflecom-calculations",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.10",
|
|
4
4
|
"description": "",
|
|
5
5
|
"types": "lib/index.d.ts",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -14,5 +14,5 @@
|
|
|
14
14
|
},
|
|
15
15
|
"author": "",
|
|
16
16
|
"license": "ISC",
|
|
17
|
-
"gitHead": "
|
|
17
|
+
"gitHead": "7d9ea4668009e9c62e2f8a5abb00be87cf1ec11d"
|
|
18
18
|
}
|
package/src/regex/index.ts
CHANGED
|
@@ -17,5 +17,9 @@ export const TIMEZONE_OFFSET_REGEX = /^(?:Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])
|
|
|
17
17
|
export const TXN_URL_REGEX = /^https:\/\/.*\{txId\}.*$/;
|
|
18
18
|
|
|
19
19
|
export const ADDRESS_URL_REGEX = /^https:\/\/.*\{address\}.*$/;
|
|
20
|
-
export const VALID_NAME_REGEX = /^[^0-9!@#$%^&*`~()+=[{\]};:"
|
|
20
|
+
export const VALID_NAME_REGEX = /^[^0-9!@#$%^&*`~()+=[{\]};:"\\|<>\/?]*$/;
|
|
21
|
+
// Rejects invisible/blank Unicode chars commonly used to spoof empty or hidden names:
|
|
22
|
+
// U+2800 Braille Blank, U+FFA0 Halfwidth Hangul Filler, U+115F Hangul Choseong Filler,
|
|
23
|
+
// U+1160 Hangul Jungseong Filler, U+3164 Hangul Filler
|
|
24
|
+
export const NO_INVISIBLE_CHAR_REGEX = /^[^\u2800\uFFA0\u115F\u1160\u3164]*$/;
|
|
21
25
|
export const US_PHONE_NUMBER_REGEX = /^\+1\d{10}$/;
|
package/src/regex/regex.spec.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
ADDRESS_URL_REGEX,
|
|
8
8
|
VALID_NAME_REGEX,
|
|
9
9
|
US_PHONE_NUMBER_REGEX,
|
|
10
|
+
NO_INVISIBLE_CHAR_REGEX,
|
|
10
11
|
} from '.';
|
|
11
12
|
|
|
12
13
|
describe('regex', () => {
|
|
@@ -21,10 +22,9 @@ describe('regex', () => {
|
|
|
21
22
|
});
|
|
22
23
|
|
|
23
24
|
it('should allow passwords between 8-24 characters', () => {
|
|
24
|
-
expect(PWD_REGEX.test('12345678')).toBe(true);
|
|
25
|
-
expect(PWD_REGEX.test('abcdefgh')).toBe(true);
|
|
26
|
-
expect(PWD_REGEX.test('Password123!')).toBe(true);
|
|
27
|
-
|
|
25
|
+
expect(PWD_REGEX.test('12345678')).toBe(true);
|
|
26
|
+
expect(PWD_REGEX.test('abcdefgh')).toBe(true);
|
|
27
|
+
expect(PWD_REGEX.test('Password123!')).toBe(true);
|
|
28
28
|
});
|
|
29
29
|
});
|
|
30
30
|
|
|
@@ -139,9 +139,44 @@ describe('regex', () => {
|
|
|
139
139
|
it('should allow for empty string', () => {
|
|
140
140
|
expect(VALID_NAME_REGEX.test('')).toBe(true);
|
|
141
141
|
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe('NO_INVISIBLE_CHAR_REGEX', () => {
|
|
145
|
+
const BRAILLE_BLANK = String.fromCodePoint(0x2800);
|
|
146
|
+
const HALFWIDTH_HANGUL_FILLER = String.fromCodePoint(0xffa0);
|
|
147
|
+
const HANGUL_CHOSEONG_FILLER = String.fromCodePoint(0x115f);
|
|
148
|
+
const HANGUL_JUNGSEONG_FILLER = String.fromCodePoint(0x1160);
|
|
149
|
+
const HANGUL_FILLER = String.fromCodePoint(0x3164);
|
|
150
|
+
|
|
151
|
+
it('should not allow for U+2800 (Braille Blank) unicode character', () => {
|
|
152
|
+
expect(NO_INVISIBLE_CHAR_REGEX.test(BRAILLE_BLANK)).toBe(false);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should not allow for U+FFA0 (Halfwidth Hangul Filler) unicode character', () => {
|
|
156
|
+
expect(NO_INVISIBLE_CHAR_REGEX.test(HALFWIDTH_HANGUL_FILLER)).toBe(false);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('should not allow for U+115F (Hangul Choseong Filler) unicode character', () => {
|
|
160
|
+
expect(NO_INVISIBLE_CHAR_REGEX.test(HANGUL_CHOSEONG_FILLER)).toBe(false);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('should not allow for U+1160 (Hangul Jungseong Filler) unicode character', () => {
|
|
164
|
+
expect(NO_INVISIBLE_CHAR_REGEX.test(HANGUL_JUNGSEONG_FILLER)).toBe(false);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should not allow for U+3164 (Hangul Filler) unicode character', () => {
|
|
168
|
+
expect(NO_INVISIBLE_CHAR_REGEX.test(HANGUL_FILLER)).toBe(false);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('should not allow strings with multiple invisible chars', () => {
|
|
172
|
+
expect(NO_INVISIBLE_CHAR_REGEX.test(`${BRAILLE_BLANK}${HANGUL_FILLER}${HALFWIDTH_HANGUL_FILLER}`)).toBe(false);
|
|
173
|
+
});
|
|
142
174
|
|
|
143
|
-
it('should
|
|
144
|
-
expect(
|
|
175
|
+
it('should allow clean strings without invisible chars', () => {
|
|
176
|
+
expect(NO_INVISIBLE_CHAR_REGEX.test('superman')).toBe(true);
|
|
177
|
+
expect(NO_INVISIBLE_CHAR_REGEX.test('SuPERman 123!')).toBe(true);
|
|
178
|
+
expect(NO_INVISIBLE_CHAR_REGEX.test('我喜欢bingchiling')).toBe(true);
|
|
179
|
+
expect(NO_INVISIBLE_CHAR_REGEX.test("m_r's don-nut.")).toBe(true);
|
|
145
180
|
});
|
|
146
181
|
});
|
|
147
182
|
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import BigNumber from 'bignumber.js';
|
|
2
2
|
import { limitTotalOddsDecimalPlaces, oddsFractionToDecimal } from './odds';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
OutcomeResult,
|
|
5
|
+
SportsBetLegInterface,
|
|
6
|
+
SportsBetLegType,
|
|
7
|
+
SportsBetSelectionInterface,
|
|
8
|
+
SportsBetSelectionStatus,
|
|
9
|
+
SportsBetType,
|
|
10
|
+
SportsMarketSelectionInterface,
|
|
11
|
+
} from './sports.types';
|
|
4
12
|
import { SportsSystemBetType, SportsSystemBetTypeCombinations, SportsSystemBetTypeSelectionCountsToBetCounts } from './system-bet.types';
|
|
5
13
|
|
|
6
14
|
export const MARGIN_MIN_BPS = 100; // hard limit min 1% for cashout
|
|
@@ -273,3 +281,20 @@ function calculateSelectionCashoutOdds(
|
|
|
273
281
|
.multipliedBy(selectionOddsDecimal)
|
|
274
282
|
.dividedBy(oddsFractionToDecimal(marketSelection.oddsNumerator, marketSelection.oddsDenominator));
|
|
275
283
|
}
|
|
284
|
+
|
|
285
|
+
// Structural mapping from (bet type, selections) → legs. The placement writer and the backfill
|
|
286
|
+
// service both consume this so that the leg-shape rule for each bet type lives in one place.
|
|
287
|
+
export function deriveLegsFromSelections(
|
|
288
|
+
sportsBetType: SportsBetType,
|
|
289
|
+
selections: SportsBetSelectionInterface[],
|
|
290
|
+
customBetTotalOddsDecimal: BigNumber,
|
|
291
|
+
): SportsBetLegInterface[] {
|
|
292
|
+
if (sportsBetType === SportsBetType.CUSTOM_BET) {
|
|
293
|
+
return [{ type: SportsBetLegType.CUSTOM, oddsDecimal: customBetTotalOddsDecimal, selections }];
|
|
294
|
+
}
|
|
295
|
+
return selections.map(selection => ({
|
|
296
|
+
type: SportsBetLegType.REGULAR,
|
|
297
|
+
oddsDecimal: oddsFractionToDecimal(selection.oddsNumerator, selection.oddsDenominator),
|
|
298
|
+
selections: [selection],
|
|
299
|
+
}));
|
|
300
|
+
}
|
|
@@ -46,8 +46,8 @@ export enum SportsFixtureStatus {
|
|
|
46
46
|
export enum SportsMarketStatus {
|
|
47
47
|
OPEN = 'OPEN',
|
|
48
48
|
CLOSED = 'CLOSED', // gets reverted back to OPEN very often with the radar line market cases
|
|
49
|
-
RESULTED = 'RESULTED', // aka, finalized, no longer used in any query + index, updated by update-market-status job
|
|
50
49
|
SUSPENDED = 'SUSPENDED',
|
|
50
|
+
RESULTED = 'RESULTED', // aka, finalized, no longer used in any query + index, updated by update-market-status job
|
|
51
51
|
/**
|
|
52
52
|
* @deprecated
|
|
53
53
|
*/
|
|
@@ -135,6 +135,17 @@ export interface SportsBetSelectionInterface {
|
|
|
135
135
|
oddsDenominator: BigNumber;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
export enum SportsBetLegType {
|
|
139
|
+
REGULAR = 'REGULAR',
|
|
140
|
+
CUSTOM = 'CUSTOM',
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export interface SportsBetLegInterface {
|
|
144
|
+
type: SportsBetLegType;
|
|
145
|
+
oddsDecimal: BigNumber;
|
|
146
|
+
selections: SportsBetSelectionInterface[];
|
|
147
|
+
}
|
|
148
|
+
|
|
138
149
|
export interface SportsFixtureInterface {
|
|
139
150
|
id: string;
|
|
140
151
|
status: SportsFixtureStatus;
|
|
@@ -539,6 +550,8 @@ export enum SportsMarketGroup {
|
|
|
539
550
|
LAST_TO_MARKETS = 'LAST_TO_MARKETS',
|
|
540
551
|
OTHER_MARKETS = 'OTHER_MARKETS', // this doesnt really exist in db, for query purpose only
|
|
541
552
|
SAME_GAME_MULTI_MARKETS = 'SAME_GAME_MULTI_MARKETS',
|
|
553
|
+
QUICK_COMBOS = 'QUICK_COMBOS', // for managing tab visibility only — no SportsMarketGrouping rows. queries for tab content happen through quickCombos query, not sportsMarketInfo
|
|
554
|
+
|
|
542
555
|
KILL_MARKETS = 'KILL_MARKETS',
|
|
543
556
|
ROSHAN_MARKETS = 'ROSHAN_MARKETS',
|
|
544
557
|
TURRET_MARKETS = 'TURRET_MARKETS',
|