volleyballsimtypes 0.0.525 → 0.0.527
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/cjs/src/api/index.d.ts +2 -2
- package/dist/cjs/src/data/init-models.js +4 -22
- package/dist/cjs/src/data/models/national-team-claim.d.ts +5 -5
- package/dist/cjs/src/data/models/national-team-claim.js +8 -0
- package/dist/cjs/src/data/models/national-team.d.ts +1 -7
- package/dist/cjs/src/data/models/team-jersey.d.ts +3 -1
- package/dist/cjs/src/data/models/team-jersey.js +4 -0
- package/dist/cjs/src/data/models/wnl-callup.d.ts +0 -10
- package/dist/cjs/src/data/models/wnl-season.d.ts +0 -7
- package/dist/cjs/src/data/models/wnl-squad.d.ts +0 -13
- package/dist/cjs/src/data/transformers/team.js +2 -1
- package/dist/cjs/src/service/notification/catalog/en.json +13 -0
- package/dist/cjs/src/service/notification/catalog/es.json +13 -0
- package/dist/cjs/src/service/notification/catalog/fr.json +13 -0
- package/dist/cjs/src/service/notification/catalog/it.json +13 -0
- package/dist/cjs/src/service/notification/catalog/pl.json +13 -0
- package/dist/cjs/src/service/notification/catalog/pt-BR.json +13 -0
- package/dist/cjs/src/service/notification/catalog/tr.json +13 -0
- package/dist/cjs/src/service/notification/notification-type.d.ts +1 -1
- package/dist/cjs/src/service/notification/notification-type.js +4 -1
- package/dist/cjs/src/service/notification/payloads.d.ts +7 -1
- package/dist/cjs/src/service/notification/registry.d.ts +1 -2
- package/dist/cjs/src/service/notification/registry.js +52 -25
- package/dist/cjs/src/service/team/index.d.ts +1 -0
- package/dist/cjs/src/service/team/index.js +1 -0
- package/dist/cjs/src/service/team/jersey-defaults.d.ts +13 -0
- package/dist/cjs/src/service/team/jersey-defaults.js +79 -0
- package/dist/cjs/src/service/team/jersey.d.ts +29 -0
- package/dist/cjs/src/service/team/jersey.js +125 -1
- package/dist/cjs/src/service/team/schemas/team.z.d.ts +24 -0
- package/dist/cjs/src/service/team/schemas/team.z.js +2 -1
- package/dist/cjs/src/service/team/team.d.ts +2 -1
- package/dist/cjs/src/service/team/team.js +2 -1
- package/dist/esm/src/api/index.d.ts +2 -2
- package/dist/esm/src/data/init-models.js +4 -22
- package/dist/esm/src/data/models/national-team-claim.d.ts +5 -5
- package/dist/esm/src/data/models/national-team-claim.js +8 -0
- package/dist/esm/src/data/models/national-team.d.ts +1 -7
- package/dist/esm/src/data/models/team-jersey.d.ts +3 -1
- package/dist/esm/src/data/models/team-jersey.js +4 -0
- package/dist/esm/src/data/models/wnl-callup.d.ts +0 -10
- package/dist/esm/src/data/models/wnl-season.d.ts +0 -7
- package/dist/esm/src/data/models/wnl-squad.d.ts +0 -13
- package/dist/esm/src/data/transformers/team.js +2 -1
- package/dist/esm/src/service/notification/catalog/en.json +13 -0
- package/dist/esm/src/service/notification/catalog/es.json +13 -0
- package/dist/esm/src/service/notification/catalog/fr.json +13 -0
- package/dist/esm/src/service/notification/catalog/it.json +13 -0
- package/dist/esm/src/service/notification/catalog/pl.json +13 -0
- package/dist/esm/src/service/notification/catalog/pt-BR.json +13 -0
- package/dist/esm/src/service/notification/catalog/tr.json +13 -0
- package/dist/esm/src/service/notification/notification-type.d.ts +1 -1
- package/dist/esm/src/service/notification/notification-type.js +4 -1
- package/dist/esm/src/service/notification/payloads.d.ts +7 -1
- package/dist/esm/src/service/notification/registry.d.ts +1 -2
- package/dist/esm/src/service/notification/registry.js +51 -24
- package/dist/esm/src/service/team/index.d.ts +1 -0
- package/dist/esm/src/service/team/index.js +1 -0
- package/dist/esm/src/service/team/jersey-defaults.d.ts +13 -0
- package/dist/esm/src/service/team/jersey-defaults.js +75 -0
- package/dist/esm/src/service/team/jersey.d.ts +29 -0
- package/dist/esm/src/service/team/jersey.js +120 -0
- package/dist/esm/src/service/team/schemas/team.z.d.ts +24 -0
- package/dist/esm/src/service/team/schemas/team.z.js +3 -2
- package/dist/esm/src/service/team/team.d.ts +2 -1
- package/dist/esm/src/service/team/team.js +2 -1
- package/package.json +1 -1
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PUSH_PREF_KEYS = exports.PUSH_NOTIFICATION_TYPES = exports.NOTIFICATION_REGISTRY = void 0;
|
|
3
|
+
exports.PUSH_PREF_KEYS = exports.PUSH_NOTIFICATION_TYPES = exports.NOTIFICATION_REGISTRY = exports.NATIONAL_ACCESS_PREF_KEY = void 0;
|
|
4
4
|
exports.pushPrefKeyFor = pushPrefKeyFor;
|
|
5
5
|
exports.pushEnabledForType = pushEnabledForType;
|
|
6
6
|
const notification_type_1 = require("./notification-type");
|
|
7
7
|
function readString(value) {
|
|
8
8
|
return typeof value === 'string' && value !== '' ? value : null;
|
|
9
9
|
}
|
|
10
|
+
// The preference key the three national-team access types share. Deliberately NOT the 'WNL' group: muting routine
|
|
11
|
+
// call-up chatter must never also mute "you are about to lose your national team" (owner 2026-08-29).
|
|
12
|
+
exports.NATIONAL_ACCESS_PREF_KEY = 'NATIONAL_ACCESS';
|
|
13
|
+
// Whole days from now until an ISO instant, floored at 0. NATIONAL_ACCESS_EXPIRING stores the ABSOLUTE deadline
|
|
14
|
+
// rather than a day count because the in-app bell renders a stored payload at READ time: a stored "3" would still
|
|
15
|
+
// read "3 days" two days later. Push resolves the number here at SEND time and the bell resolves it again at render,
|
|
16
|
+
// so neither surface can go stale.
|
|
17
|
+
function daysUntilIso(value) {
|
|
18
|
+
const iso = readString(value);
|
|
19
|
+
if (iso == null)
|
|
20
|
+
return 0;
|
|
21
|
+
const ms = new Date(iso).getTime() - Date.now();
|
|
22
|
+
if (!Number.isFinite(ms) || ms <= 0)
|
|
23
|
+
return 0;
|
|
24
|
+
return Math.ceil(ms / 86400000);
|
|
25
|
+
}
|
|
10
26
|
function teamPath(payload) {
|
|
11
27
|
const teamId = readString(payload.teamId);
|
|
12
28
|
return teamId != null ? `/team/${encodeURIComponent(teamId)}` : '/';
|
|
@@ -42,7 +58,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
42
58
|
return `matchResult.${outcome}${named}`;
|
|
43
59
|
},
|
|
44
60
|
params: (p) => ({ opponent: matchOpponent(p) ?? '' }),
|
|
45
|
-
richRender: 'MATCH_RESULT',
|
|
46
61
|
catalogKeys: ['matchResult.title', 'matchResult.wonNamed', 'matchResult.wonUnnamed', 'matchResult.lostNamed', 'matchResult.lostUnnamed']
|
|
47
62
|
},
|
|
48
63
|
INJURY: {
|
|
@@ -50,7 +65,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
50
65
|
deepLink: () => '/infirmary',
|
|
51
66
|
pushTitleKey: 'injury.title',
|
|
52
67
|
pushBodyKey: 'injury.body',
|
|
53
|
-
inAppMessageKey: 'injury.body',
|
|
54
68
|
params: (p) => ({ name: injuredName(p) }),
|
|
55
69
|
catalogKeys: ['injury.title', 'injury.body']
|
|
56
70
|
},
|
|
@@ -59,7 +73,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
59
73
|
deepLink: teamPath,
|
|
60
74
|
pushTitleKey: 'injuryRecovered.title',
|
|
61
75
|
pushBodyKey: 'injuryRecovered.body',
|
|
62
|
-
inAppMessageKey: 'injuryRecovered.body',
|
|
63
76
|
params: (p) => ({ name: injuredName(p) }),
|
|
64
77
|
catalogKeys: ['injuryRecovered.title', 'injuryRecovered.body']
|
|
65
78
|
},
|
|
@@ -71,7 +84,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
71
84
|
},
|
|
72
85
|
pushTitleKey: 'seasonEnd.title',
|
|
73
86
|
pushBodyKey: 'seasonEnd.body',
|
|
74
|
-
inAppMessageKey: 'seasonEnd.body',
|
|
75
87
|
catalogKeys: ['seasonEnd.title', 'seasonEnd.body']
|
|
76
88
|
},
|
|
77
89
|
GRANT_RECEIVED: {
|
|
@@ -79,7 +91,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
79
91
|
deepLink: () => '/recruit',
|
|
80
92
|
pushTitleKey: 'grant.title',
|
|
81
93
|
pushBodyKey: 'grant.body',
|
|
82
|
-
inAppMessageKey: 'grant.body',
|
|
83
94
|
catalogKeys: ['grant.title', 'grant.body']
|
|
84
95
|
},
|
|
85
96
|
PROMOTION: {
|
|
@@ -87,7 +98,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
87
98
|
deepLink: teamPath,
|
|
88
99
|
pushTitleKey: 'promotion.title',
|
|
89
100
|
pushBodyKey: 'promotion.body',
|
|
90
|
-
inAppMessageKey: 'promotion.body',
|
|
91
101
|
catalogKeys: ['promotion.title', 'promotion.body']
|
|
92
102
|
},
|
|
93
103
|
// In-game events. All five deep-link to the Events section, which is where every phase of an event lives.
|
|
@@ -98,7 +108,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
98
108
|
deepLink: () => '/events',
|
|
99
109
|
pushTitleKey: 'eventRegistrationOpen.title',
|
|
100
110
|
pushBodyKey: 'eventRegistrationOpen.body',
|
|
101
|
-
inAppMessageKey: 'eventRegistrationOpen.body',
|
|
102
111
|
catalogKeys: ['eventRegistrationOpen.title', 'eventRegistrationOpen.body']
|
|
103
112
|
},
|
|
104
113
|
EVENT_REGISTRATION_CLOSING: {
|
|
@@ -106,7 +115,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
106
115
|
deepLink: () => '/events',
|
|
107
116
|
pushTitleKey: 'eventRegistrationClosing.title',
|
|
108
117
|
pushBodyKey: 'eventRegistrationClosing.body',
|
|
109
|
-
inAppMessageKey: 'eventRegistrationClosing.body',
|
|
110
118
|
catalogKeys: ['eventRegistrationClosing.title', 'eventRegistrationClosing.body']
|
|
111
119
|
},
|
|
112
120
|
EVENT_STARTED: {
|
|
@@ -114,7 +122,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
114
122
|
deepLink: () => '/events',
|
|
115
123
|
pushTitleKey: 'eventStarted.title',
|
|
116
124
|
pushBodyKey: 'eventStarted.body',
|
|
117
|
-
inAppMessageKey: 'eventStarted.body',
|
|
118
125
|
catalogKeys: ['eventStarted.title', 'eventStarted.body']
|
|
119
126
|
},
|
|
120
127
|
EVENT_FINAL_ROUND: {
|
|
@@ -122,7 +129,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
122
129
|
deepLink: () => '/events',
|
|
123
130
|
pushTitleKey: 'eventFinalRound.title',
|
|
124
131
|
pushBodyKey: 'eventFinalRound.body',
|
|
125
|
-
inAppMessageKey: 'eventFinalRound.body',
|
|
126
132
|
catalogKeys: ['eventFinalRound.title', 'eventFinalRound.body']
|
|
127
133
|
},
|
|
128
134
|
EVENT_FINISHED: {
|
|
@@ -133,9 +139,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
133
139
|
pushBodyKey: (p) => readString(p.position) != null || typeof p.position === 'number'
|
|
134
140
|
? 'eventFinished.placed'
|
|
135
141
|
: 'eventFinished.body',
|
|
136
|
-
inAppMessageKey: (p) => readString(p.position) != null || typeof p.position === 'number'
|
|
137
|
-
? 'eventFinished.placed'
|
|
138
|
-
: 'eventFinished.body',
|
|
139
142
|
params: (p) => ({
|
|
140
143
|
position: typeof p.position === 'number' ? String(p.position) : (readString(p.position) ?? ''),
|
|
141
144
|
entrants: typeof p.entrants === 'number' ? String(p.entrants) : (readString(p.entrants) ?? '')
|
|
@@ -148,7 +151,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
148
151
|
deepLink: () => '/daily-login',
|
|
149
152
|
pushTitleKey: 'dailyLogin.title',
|
|
150
153
|
pushBodyKey: 'dailyLogin.body',
|
|
151
|
-
inAppMessageKey: 'dailyLogin.body',
|
|
152
154
|
catalogKeys: ['dailyLogin.title', 'dailyLogin.body']
|
|
153
155
|
},
|
|
154
156
|
WELCOME: {
|
|
@@ -156,13 +158,11 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
156
158
|
deepLink: () => '/recruit',
|
|
157
159
|
pushTitleKey: 'welcome.title',
|
|
158
160
|
pushBodyKey: 'welcome.body',
|
|
159
|
-
richRender: 'WELCOME',
|
|
160
161
|
catalogKeys: ['welcome.title', 'welcome.body']
|
|
161
162
|
},
|
|
162
163
|
// In-app only (no push); the UI keeps a bespoke renderer (amount formatting) and its own `compensation` label.
|
|
163
164
|
COMPENSATION: {
|
|
164
165
|
emitsPush: false,
|
|
165
|
-
richRender: 'COMPENSATION',
|
|
166
166
|
catalogKeys: []
|
|
167
167
|
},
|
|
168
168
|
// One-off relocation warning: sent to users whose team is being moved to Kyorin. Informational; opens their team.
|
|
@@ -171,7 +171,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
171
171
|
deepLink: teamPath,
|
|
172
172
|
pushTitleKey: 'regionRelocation.title',
|
|
173
173
|
pushBodyKey: 'regionRelocation.body',
|
|
174
|
-
inAppMessageKey: 'regionRelocation.body',
|
|
175
174
|
catalogKeys: ['regionRelocation.title', 'regionRelocation.body']
|
|
176
175
|
},
|
|
177
176
|
// World Nations League (owner 2026-08-28). All seven share the single 'WNL' preference toggle. The three callup
|
|
@@ -183,7 +182,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
183
182
|
deepLink: () => '/wnl/callup',
|
|
184
183
|
pushTitleKey: 'wnlCallupOpen.title',
|
|
185
184
|
pushBodyKey: 'wnlCallupOpen.body',
|
|
186
|
-
inAppMessageKey: 'wnlCallupOpen.body',
|
|
187
185
|
// The deadline arrives pre-formatted (locale-neutral 'YYYY-MM-DD HH:mm UTC') because the stored payload is
|
|
188
186
|
// shared by the push and the in-app bell and cannot be re-localised per render.
|
|
189
187
|
params: (p) => ({ date: readString(p.deadline) ?? '' }),
|
|
@@ -195,7 +193,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
195
193
|
deepLink: () => '/wnl/callup',
|
|
196
194
|
pushTitleKey: 'wnlCallupDeadline.title',
|
|
197
195
|
pushBodyKey: 'wnlCallupDeadline.body',
|
|
198
|
-
inAppMessageKey: 'wnlCallupDeadline.body',
|
|
199
196
|
catalogKeys: ['wnlCallupDeadline.title', 'wnlCallupDeadline.body']
|
|
200
197
|
},
|
|
201
198
|
WNL_CALLUP_CLOSED: {
|
|
@@ -204,7 +201,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
204
201
|
deepLink: () => '/wnl/manage/lineup',
|
|
205
202
|
pushTitleKey: 'wnlCallupClosed.title',
|
|
206
203
|
pushBodyKey: 'wnlCallupClosed.body',
|
|
207
|
-
inAppMessageKey: 'wnlCallupClosed.body',
|
|
208
204
|
catalogKeys: ['wnlCallupClosed.title', 'wnlCallupClosed.body']
|
|
209
205
|
},
|
|
210
206
|
WNL_LEAGUE_START: {
|
|
@@ -213,7 +209,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
213
209
|
deepLink: () => '/wnl',
|
|
214
210
|
pushTitleKey: 'wnlLeagueStart.title',
|
|
215
211
|
pushBodyKey: 'wnlLeagueStart.body',
|
|
216
|
-
inAppMessageKey: 'wnlLeagueStart.body',
|
|
217
212
|
catalogKeys: ['wnlLeagueStart.title', 'wnlLeagueStart.body']
|
|
218
213
|
},
|
|
219
214
|
WNL_FINALS_START: {
|
|
@@ -222,7 +217,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
222
217
|
deepLink: () => '/wnl/finals',
|
|
223
218
|
pushTitleKey: 'wnlFinalsStart.title',
|
|
224
219
|
pushBodyKey: 'wnlFinalsStart.body',
|
|
225
|
-
inAppMessageKey: 'wnlFinalsStart.body',
|
|
226
220
|
catalogKeys: ['wnlFinalsStart.title', 'wnlFinalsStart.body']
|
|
227
221
|
},
|
|
228
222
|
WNL_CHAMPION: {
|
|
@@ -232,7 +226,6 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
232
226
|
pushTitleKey: 'wnlChampion.title',
|
|
233
227
|
// A missing team name never renders a subjectless sentence (mirrors the MATCH_RESULT named/unnamed split).
|
|
234
228
|
pushBodyKey: (p) => readString(p.team) != null ? 'wnlChampion.body' : 'wnlChampion.bodyUnnamed',
|
|
235
|
-
inAppMessageKey: (p) => readString(p.team) != null ? 'wnlChampion.body' : 'wnlChampion.bodyUnnamed',
|
|
236
229
|
params: (p) => ({ team: readString(p.team) ?? '' }),
|
|
237
230
|
catalogKeys: ['wnlChampion.title', 'wnlChampion.body', 'wnlChampion.bodyUnnamed']
|
|
238
231
|
},
|
|
@@ -242,8 +235,42 @@ exports.NOTIFICATION_REGISTRY = {
|
|
|
242
235
|
deepLink: () => '/wnl/teams',
|
|
243
236
|
pushTitleKey: 'wnlPlayerCalledUp.title',
|
|
244
237
|
pushBodyKey: 'wnlPlayerCalledUp.body',
|
|
245
|
-
inAppMessageKey: 'wnlPlayerCalledUp.body',
|
|
246
238
|
catalogKeys: ['wnlPlayerCalledUp.title', 'wnlPlayerCalledUp.body']
|
|
239
|
+
},
|
|
240
|
+
// National-team ACCESS lifecycle (owner 2026-08-29): the free Tier-2 trial is granted, is about to end, and the
|
|
241
|
+
// team is released. These share their OWN toggle rather than the 'WNL' group so that muting call-up chatter
|
|
242
|
+
// cannot silence the warning that a team is about to be lost. They are also intentionally not named WNL_*: the
|
|
243
|
+
// completeness test asserts every WNL_-prefixed type resolves to the 'WNL' key.
|
|
244
|
+
NATIONAL_TRIAL_GRANTED: {
|
|
245
|
+
emitsPush: true,
|
|
246
|
+
prefKey: exports.NATIONAL_ACCESS_PREF_KEY,
|
|
247
|
+
deepLink: () => '/wnl/claim',
|
|
248
|
+
pushTitleKey: 'nationalTrialGranted.title',
|
|
249
|
+
pushBodyKey: 'nationalTrialGranted.body',
|
|
250
|
+
// The end date arrives pre-formatted (locale-neutral 'YYYY-MM-DD'), same reason as wnlCallupOpen: one stored
|
|
251
|
+
// payload serves both the push and the bell and cannot be re-localised per render.
|
|
252
|
+
params: (p) => ({ date: readString(p.endsOn) ?? '' }),
|
|
253
|
+
catalogKeys: ['nationalTrialGranted.title', 'nationalTrialGranted.body']
|
|
254
|
+
},
|
|
255
|
+
NATIONAL_ACCESS_EXPIRING: {
|
|
256
|
+
emitsPush: true,
|
|
257
|
+
prefKey: exports.NATIONAL_ACCESS_PREF_KEY,
|
|
258
|
+
// Settings is where the Patreon card lives, so the action the copy asks for is one tap away.
|
|
259
|
+
deepLink: () => '/settings',
|
|
260
|
+
pushTitleKey: 'nationalAccessExpiring.title',
|
|
261
|
+
// The catalog has no pluralisation (interpolate is a bare {{param}} replace), so the final day is its own key
|
|
262
|
+
// instead of rendering "1 days" (mirrors the wnlChampion named/unnamed split).
|
|
263
|
+
pushBodyKey: (p) => daysUntilIso(p.expiresAt) <= 1 ? 'nationalAccessExpiring.bodyLastDay' : 'nationalAccessExpiring.bodyDays',
|
|
264
|
+
params: (p) => ({ days: String(daysUntilIso(p.expiresAt)) }),
|
|
265
|
+
catalogKeys: ['nationalAccessExpiring.title', 'nationalAccessExpiring.bodyDays', 'nationalAccessExpiring.bodyLastDay']
|
|
266
|
+
},
|
|
267
|
+
NATIONAL_TEAM_REVOKED: {
|
|
268
|
+
emitsPush: true,
|
|
269
|
+
prefKey: exports.NATIONAL_ACCESS_PREF_KEY,
|
|
270
|
+
deepLink: () => '/wnl/teams',
|
|
271
|
+
pushTitleKey: 'nationalTeamRevoked.title',
|
|
272
|
+
pushBodyKey: 'nationalTeamRevoked.body',
|
|
273
|
+
catalogKeys: ['nationalTeamRevoked.title', 'nationalTeamRevoked.body']
|
|
247
274
|
}
|
|
248
275
|
};
|
|
249
276
|
// The notification types that emit a mobile push (everything except COMPENSATION). Source of truth = each
|
|
@@ -16,6 +16,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./team"), exports);
|
|
18
18
|
__exportStar(require("./jersey"), exports);
|
|
19
|
+
__exportStar(require("./jersey-defaults"), exports);
|
|
19
20
|
__exportStar(require("./team-generator"), exports);
|
|
20
21
|
__exportStar(require("./formation"), exports);
|
|
21
22
|
__exportStar(require("./tactics"), exports);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { JerseyConfig, JerseyClothing, JerseyPattern, JerseyFont } from './jersey';
|
|
2
|
+
export interface JerseyPalette {
|
|
3
|
+
color1: string;
|
|
4
|
+
color2: string;
|
|
5
|
+
color3: string;
|
|
6
|
+
number1: string;
|
|
7
|
+
number2: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const JERSEY_PALETTES: readonly JerseyPalette[];
|
|
10
|
+
export declare const JERSEY_PATTERN_ORDER: readonly JerseyPattern[];
|
|
11
|
+
export declare const JERSEY_CLOTHING_ORDER: readonly JerseyClothing[];
|
|
12
|
+
export declare const JERSEY_FONT_ORDER: readonly JerseyFont[];
|
|
13
|
+
export declare function jerseyFromTeamId(teamId: string): JerseyConfig;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JERSEY_FONT_ORDER = exports.JERSEY_CLOTHING_ORDER = exports.JERSEY_PATTERN_ORDER = exports.JERSEY_PALETTES = void 0;
|
|
4
|
+
exports.jerseyFromTeamId = jerseyFromTeamId;
|
|
5
|
+
// FNV-1a hash of a string, used to seed the PRNG below from a team id.
|
|
6
|
+
function hashSeed(str) {
|
|
7
|
+
let h = 2166136261;
|
|
8
|
+
for (let i = 0; i < str.length; i++) {
|
|
9
|
+
h ^= str.charCodeAt(i);
|
|
10
|
+
h = Math.imul(h, 16777619);
|
|
11
|
+
}
|
|
12
|
+
return h >>> 0;
|
|
13
|
+
}
|
|
14
|
+
// mulberry32: a tiny deterministic PRNG. Same seed -> same stream, so a team's kit is stable and reproducible.
|
|
15
|
+
function mulberry32(seed) {
|
|
16
|
+
let a = seed;
|
|
17
|
+
return () => {
|
|
18
|
+
a = (a + 0x6d2b79f5) | 0;
|
|
19
|
+
let t = Math.imul(a ^ (a >>> 15), 1 | a);
|
|
20
|
+
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
21
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
exports.JERSEY_PALETTES = [
|
|
25
|
+
{ color1: '#606c38', color2: '#dda15e', color3: '#bc6c25', number1: '#fefae0', number2: '#283618' },
|
|
26
|
+
{ color1: '#780000', color2: '#669bbc', color3: '#c1121f', number1: '#fdf0d5', number2: '#003049' },
|
|
27
|
+
{ color1: '#2a9d8f', color2: '#f4a261', color3: '#e76f51', number1: '#264653', number2: '#e9c46a' },
|
|
28
|
+
{ color1: '#219ebc', color2: '#fb8500', color3: '#8ecae6', number1: '#023047', number2: '#ffb703' },
|
|
29
|
+
{ color1: '#1d3557', color2: '#e63946', color3: '#a8dadc', number1: '#f1faee', number2: '#457b9d' },
|
|
30
|
+
{ color1: '#003566', color2: '#ffc300', color3: '#001d3d', number1: '#ffd60a', number2: '#000814' },
|
|
31
|
+
{ color1: '#bc4749', color2: '#6a994e', color3: '#a7c957', number1: '#f2e8cf', number2: '#386641' },
|
|
32
|
+
{ color1: '#6f1d1b', color2: '#99582a', color3: '#bb9457', number1: '#ffe6a7', number2: '#432818' },
|
|
33
|
+
{ color1: '#ef476f', color2: '#118ab2', color3: '#ffd166', number1: '#ffd166', number2: '#073b4c' },
|
|
34
|
+
{ color1: '#16425b', color2: '#3a7ca5', color3: '#81c3d7', number1: '#d9dcd6', number2: '#2f6690' },
|
|
35
|
+
{ color1: '#ee6c4d', color2: '#3d5a80', color3: '#98c1d9', number1: '#e0fbfc', number2: '#293241' },
|
|
36
|
+
{ color1: '#e09f3e', color2: '#335c67', color3: '#9e2a2b', number1: '#fff3b0', number2: '#540b0e' },
|
|
37
|
+
{ color1: '#9a031e', color2: '#fb8b24', color3: '#e36414', number1: '#0f4c5c', number2: '#5f0f40' },
|
|
38
|
+
{ color1: '#127475', color2: '#f2542d', color3: '#0e9594', number1: '#f5dfbb', number2: '#562c2c' },
|
|
39
|
+
{ color1: '#bc4b51', color2: '#8cb369', color3: '#f4a259', number1: '#f4e285', number2: '#5b8e7d' },
|
|
40
|
+
{ color1: '#7678ed', color2: '#f18701', color3: '#f35b04', number1: '#f7b801', number2: '#3d348b' },
|
|
41
|
+
{ color1: '#14213d', color2: '#fca311', color3: '#e5e5e5', number1: '#ffffff', number2: '#000000' },
|
|
42
|
+
{ color1: '#e07a5f', color2: '#81b29a', color3: '#f2cc8f', number1: '#f4f1de', number2: '#3d405b' },
|
|
43
|
+
{ color1: '#f79824', color2: '#33a1fd', color3: '#fdca40', number1: '#33a1fd', number2: '#31393c' },
|
|
44
|
+
{ color1: '#619b8a', color2: '#fe7f2d', color3: '#a1c181', number1: '#fcca46', number2: '#233d4d' },
|
|
45
|
+
{ color1: '#227c9d', color2: '#17c3b2', color3: '#ffcb77', number1: '#fef9ef', number2: '#fe6d73' },
|
|
46
|
+
{ color1: '#19647e', color2: '#119da4', color3: '#1f2041', number1: '#4b3f72', number2: '#ffc857' }
|
|
47
|
+
];
|
|
48
|
+
exports.JERSEY_PATTERN_ORDER = [
|
|
49
|
+
'solid', 'verticalStripes', 'verticalBars', 'pinstripes', 'hoops', 'checkered', 'diagonalSash', 'splitHalves',
|
|
50
|
+
'chevron', 'shoulderYoke', 'sidePanels', 'centerBand', 'gradientFade', 'twoToneSplit'
|
|
51
|
+
];
|
|
52
|
+
exports.JERSEY_CLOTHING_ORDER = [
|
|
53
|
+
'shirtCrewNeck', 'shirtCrewNeckSleeveless', 'shirtVNeck', 'shirtVNeckSleeveless', 'collarAndSweater', 'collarAndSweaterSleeveless'
|
|
54
|
+
];
|
|
55
|
+
// Free-user fonts: the id-derived random for a team's default kit picks ONLY from these (premium fonts are vector
|
|
56
|
+
// glyph paths that require the UI rendering pipeline).
|
|
57
|
+
exports.JERSEY_FONT_ORDER = ['sans', 'wide', 'mono', 'serif', 'block'];
|
|
58
|
+
// The full jersey a team wears by default: every category is drawn deterministically from the team id, so each team
|
|
59
|
+
// gets its own stable, distinct kit. Colours come from ONE randomly-assigned JERSEY_PALETTE (harmonious by design);
|
|
60
|
+
// clothing / pattern / font stay random per team.
|
|
61
|
+
function jerseyFromTeamId(teamId) {
|
|
62
|
+
const rng = mulberry32(hashSeed(teamId));
|
|
63
|
+
const pickFrom = (arr) => arr[Math.floor(rng() * arr.length)];
|
|
64
|
+
const palette = pickFrom(exports.JERSEY_PALETTES);
|
|
65
|
+
return {
|
|
66
|
+
clothing: pickFrom(exports.JERSEY_CLOTHING_ORDER),
|
|
67
|
+
pattern: pickFrom(exports.JERSEY_PATTERN_ORDER),
|
|
68
|
+
colors: [palette.color1, palette.color2, palette.color3],
|
|
69
|
+
font: pickFrom(exports.JERSEY_FONT_ORDER),
|
|
70
|
+
numberColor: palette.number1,
|
|
71
|
+
numberOutline: palette.number2,
|
|
72
|
+
numberOutlineEnabled: true,
|
|
73
|
+
numberSpacing: 0,
|
|
74
|
+
numberSize: 46,
|
|
75
|
+
brand: 'none',
|
|
76
|
+
brandColor1: '#ffffff',
|
|
77
|
+
brandColor2: '#1e293b'
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -72,3 +72,32 @@ export type JerseyConfig = z.infer<typeof JerseySchema>;
|
|
|
72
72
|
export type JerseyClothing = JerseyConfig['clothing'];
|
|
73
73
|
export type JerseyPattern = JerseyConfig['pattern'];
|
|
74
74
|
export type JerseyFont = JerseyConfig['font'];
|
|
75
|
+
export declare const AlternateJerseySchema: z.ZodObject<{
|
|
76
|
+
pattern: z.ZodEnum<{
|
|
77
|
+
solid: "solid";
|
|
78
|
+
verticalStripes: "verticalStripes";
|
|
79
|
+
verticalBars: "verticalBars";
|
|
80
|
+
pinstripes: "pinstripes";
|
|
81
|
+
hoops: "hoops";
|
|
82
|
+
checkered: "checkered";
|
|
83
|
+
diagonalSash: "diagonalSash";
|
|
84
|
+
splitHalves: "splitHalves";
|
|
85
|
+
chevron: "chevron";
|
|
86
|
+
shoulderYoke: "shoulderYoke";
|
|
87
|
+
sidePanels: "sidePanels";
|
|
88
|
+
centerBand: "centerBand";
|
|
89
|
+
gradientFade: "gradientFade";
|
|
90
|
+
twoToneSplit: "twoToneSplit";
|
|
91
|
+
}>;
|
|
92
|
+
colors: z.ZodArray<z.ZodString>;
|
|
93
|
+
numberColor: z.ZodString;
|
|
94
|
+
numberOutline: z.ZodString;
|
|
95
|
+
numberOutlineEnabled: z.ZodDefault<z.ZodBoolean>;
|
|
96
|
+
brandColor1: z.ZodDefault<z.ZodString>;
|
|
97
|
+
brandColor2: z.ZodDefault<z.ZodString>;
|
|
98
|
+
}, z.core.$strip>;
|
|
99
|
+
export type AlternateJerseyConfig = z.infer<typeof AlternateJerseySchema>;
|
|
100
|
+
export declare function complementaryHex(hex: string): string;
|
|
101
|
+
export declare function relativeLuminance(hex: string): number;
|
|
102
|
+
export declare function computeComplementaryJersey(main: JerseyConfig): JerseyConfig;
|
|
103
|
+
export declare function mergeAlternateJersey(main: JerseyConfig, alt: AlternateJerseyConfig): JerseyConfig;
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.JerseySchema = void 0;
|
|
3
|
+
exports.AlternateJerseySchema = exports.JerseySchema = void 0;
|
|
4
|
+
exports.complementaryHex = complementaryHex;
|
|
5
|
+
exports.relativeLuminance = relativeLuminance;
|
|
6
|
+
exports.computeComplementaryJersey = computeComplementaryJersey;
|
|
7
|
+
exports.mergeAlternateJersey = mergeAlternateJersey;
|
|
4
8
|
const zod_1 = require("zod");
|
|
5
9
|
// 6-digit hex (#rrggbb) or 8-digit hex with alpha (#rrggbbaa). The 8-digit form comes from the UI's opacity-enabled
|
|
6
10
|
// colour pickers; SVG fills render both natively.
|
|
@@ -31,3 +35,123 @@ exports.JerseySchema = zod_1.z.object({
|
|
|
31
35
|
brandColor1: hexColor.default('#ffffff'),
|
|
32
36
|
brandColor2: hexColor.default('#1e293b')
|
|
33
37
|
});
|
|
38
|
+
// The alternate (libero) kit stores only the fields the premium editor allows changing. Locked fields (clothing,
|
|
39
|
+
// font, brand icon, numberSpacing, numberSize) are always inherited from the main kit at render time.
|
|
40
|
+
exports.AlternateJerseySchema = zod_1.z.object({
|
|
41
|
+
pattern: exports.JerseySchema.shape.pattern,
|
|
42
|
+
colors: exports.JerseySchema.shape.colors,
|
|
43
|
+
numberColor: hexColor,
|
|
44
|
+
numberOutline: hexColor,
|
|
45
|
+
numberOutlineEnabled: zod_1.z.boolean().default(true),
|
|
46
|
+
brandColor1: hexColor.default('#ffffff'),
|
|
47
|
+
brandColor2: hexColor.default('#1e293b')
|
|
48
|
+
});
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// Colour utilities (pure math, zero deps)
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
function hexToRgb(hex) {
|
|
53
|
+
const h = hex.replace('#', '').slice(0, 6);
|
|
54
|
+
return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
|
|
55
|
+
}
|
|
56
|
+
function rgbToHex(r, g, b) {
|
|
57
|
+
return '#' + [r, g, b].map(v => Math.round(Math.max(0, Math.min(255, v))).toString(16).padStart(2, '0')).join('');
|
|
58
|
+
}
|
|
59
|
+
function rgbToHsl(r, g, b) {
|
|
60
|
+
r /= 255;
|
|
61
|
+
g /= 255;
|
|
62
|
+
b /= 255;
|
|
63
|
+
const max = Math.max(r, g, b);
|
|
64
|
+
const min = Math.min(r, g, b);
|
|
65
|
+
const l = (max + min) / 2;
|
|
66
|
+
if (max === min)
|
|
67
|
+
return [0, 0, l];
|
|
68
|
+
const d = max - min;
|
|
69
|
+
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
70
|
+
let h = 0;
|
|
71
|
+
if (max === r)
|
|
72
|
+
h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
73
|
+
else if (max === g)
|
|
74
|
+
h = ((b - r) / d + 2) / 6;
|
|
75
|
+
else
|
|
76
|
+
h = ((r - g) / d + 4) / 6;
|
|
77
|
+
return [h, s, l];
|
|
78
|
+
}
|
|
79
|
+
function hslToRgb(h, s, l) {
|
|
80
|
+
if (s === 0) {
|
|
81
|
+
const v = Math.round(l * 255);
|
|
82
|
+
return [v, v, v];
|
|
83
|
+
}
|
|
84
|
+
const hue2rgb = (p, q, t) => {
|
|
85
|
+
if (t < 0)
|
|
86
|
+
t += 1;
|
|
87
|
+
if (t > 1)
|
|
88
|
+
t -= 1;
|
|
89
|
+
if (t < 1 / 6)
|
|
90
|
+
return p + (q - p) * 6 * t;
|
|
91
|
+
if (t < 1 / 2)
|
|
92
|
+
return q;
|
|
93
|
+
if (t < 2 / 3)
|
|
94
|
+
return p + (q - p) * (2 / 3 - t) * 6;
|
|
95
|
+
return p;
|
|
96
|
+
};
|
|
97
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
98
|
+
const p = 2 * l - q;
|
|
99
|
+
return [Math.round(hue2rgb(p, q, h + 1 / 3) * 255), Math.round(hue2rgb(p, q, h) * 255), Math.round(hue2rgb(p, q, h - 1 / 3) * 255)];
|
|
100
|
+
}
|
|
101
|
+
// Rotate a hex colour's hue by 180 degrees (complementary).
|
|
102
|
+
function complementaryHex(hex) {
|
|
103
|
+
const [r, g, b] = hexToRgb(hex);
|
|
104
|
+
const [h, s, l] = rgbToHsl(r, g, b);
|
|
105
|
+
const [cr, cg, cb] = hslToRgb((h + 0.5) % 1, s, l);
|
|
106
|
+
return rgbToHex(cr, cg, cb);
|
|
107
|
+
}
|
|
108
|
+
// Relative luminance (WCAG 2.x formula, 0 = black, 1 = white).
|
|
109
|
+
function relativeLuminance(hex) {
|
|
110
|
+
const [r, g, b] = hexToRgb(hex);
|
|
111
|
+
const srgb = [r, g, b].map(v => {
|
|
112
|
+
v /= 255;
|
|
113
|
+
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
114
|
+
});
|
|
115
|
+
return 0.2126 * srgb[0] + 0.7152 * srgb[1] + 0.0722 * srgb[2];
|
|
116
|
+
}
|
|
117
|
+
// Build the libero alternate kit from the main kit using complementary colours. Every colour in the
|
|
118
|
+
// pattern and the brand is hue-rotated 180 degrees; the chest-number fill/outline are picked for
|
|
119
|
+
// readability against the new primary colour (dark number on light, light number on dark).
|
|
120
|
+
function computeComplementaryJersey(main) {
|
|
121
|
+
const compColors = main.colors.map(c => complementaryHex(c));
|
|
122
|
+
const lum = relativeLuminance(compColors[0]);
|
|
123
|
+
return {
|
|
124
|
+
// Locked fields: inherited from main
|
|
125
|
+
clothing: main.clothing,
|
|
126
|
+
font: main.font,
|
|
127
|
+
brand: main.brand,
|
|
128
|
+
numberSpacing: main.numberSpacing,
|
|
129
|
+
numberSize: main.numberSize,
|
|
130
|
+
// Editable fields: complementary-derived
|
|
131
|
+
pattern: main.pattern,
|
|
132
|
+
colors: compColors,
|
|
133
|
+
numberColor: lum > 0.4 ? '#1a1a1a' : '#ffffff',
|
|
134
|
+
numberOutline: lum > 0.4 ? '#ffffff' : '#1a1a1a',
|
|
135
|
+
numberOutlineEnabled: main.numberOutlineEnabled,
|
|
136
|
+
brandColor1: complementaryHex(main.brandColor1),
|
|
137
|
+
brandColor2: complementaryHex(main.brandColor2)
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
// Merge a stored alternate (partial, editable fields only) with the main kit's locked fields to
|
|
141
|
+
// produce a full JerseyConfig for rendering.
|
|
142
|
+
function mergeAlternateJersey(main, alt) {
|
|
143
|
+
return {
|
|
144
|
+
clothing: main.clothing,
|
|
145
|
+
font: main.font,
|
|
146
|
+
brand: main.brand,
|
|
147
|
+
numberSpacing: main.numberSpacing,
|
|
148
|
+
numberSize: main.numberSize,
|
|
149
|
+
pattern: alt.pattern,
|
|
150
|
+
colors: alt.colors,
|
|
151
|
+
numberColor: alt.numberColor,
|
|
152
|
+
numberOutline: alt.numberOutline,
|
|
153
|
+
numberOutlineEnabled: alt.numberOutlineEnabled,
|
|
154
|
+
brandColor1: alt.brandColor1,
|
|
155
|
+
brandColor2: alt.brandColor2
|
|
156
|
+
};
|
|
157
|
+
}
|
|
@@ -414,5 +414,29 @@ export declare const TeamInputSchema: z.ZodObject<{
|
|
|
414
414
|
brandColor1: z.ZodDefault<z.ZodString>;
|
|
415
415
|
brandColor2: z.ZodDefault<z.ZodString>;
|
|
416
416
|
}, z.core.$strip>>;
|
|
417
|
+
alternateJerseyConfig: z.ZodOptional<z.ZodObject<{
|
|
418
|
+
pattern: z.ZodEnum<{
|
|
419
|
+
solid: "solid";
|
|
420
|
+
verticalStripes: "verticalStripes";
|
|
421
|
+
verticalBars: "verticalBars";
|
|
422
|
+
pinstripes: "pinstripes";
|
|
423
|
+
hoops: "hoops";
|
|
424
|
+
checkered: "checkered";
|
|
425
|
+
diagonalSash: "diagonalSash";
|
|
426
|
+
splitHalves: "splitHalves";
|
|
427
|
+
chevron: "chevron";
|
|
428
|
+
shoulderYoke: "shoulderYoke";
|
|
429
|
+
sidePanels: "sidePanels";
|
|
430
|
+
centerBand: "centerBand";
|
|
431
|
+
gradientFade: "gradientFade";
|
|
432
|
+
twoToneSplit: "twoToneSplit";
|
|
433
|
+
}>;
|
|
434
|
+
colors: z.ZodArray<z.ZodString>;
|
|
435
|
+
numberColor: z.ZodString;
|
|
436
|
+
numberOutline: z.ZodString;
|
|
437
|
+
numberOutlineEnabled: z.ZodDefault<z.ZodBoolean>;
|
|
438
|
+
brandColor1: z.ZodDefault<z.ZodString>;
|
|
439
|
+
brandColor2: z.ZodDefault<z.ZodString>;
|
|
440
|
+
}, z.core.$strip>>;
|
|
417
441
|
}, z.core.$strip>;
|
|
418
442
|
export type TeamInput = z.infer<typeof TeamInputSchema>;
|
|
@@ -22,7 +22,8 @@ exports.TeamInputSchema = zod_1.z.object({
|
|
|
22
22
|
country: countrySchema,
|
|
23
23
|
legacyFlagCountry: countrySchema.optional(),
|
|
24
24
|
tactics: tactics_z_1.TacticsInputSchema.optional(),
|
|
25
|
-
jerseyConfig: jersey_1.JerseySchema.optional()
|
|
25
|
+
jerseyConfig: jersey_1.JerseySchema.optional(),
|
|
26
|
+
alternateJerseyConfig: jersey_1.AlternateJerseySchema.optional()
|
|
26
27
|
}).superRefine((data, ctx) => {
|
|
27
28
|
const ids = data.roster.map(p => p.id);
|
|
28
29
|
if (new Set(ids).size !== ids.length) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Player } from '../player';
|
|
2
2
|
import { Country } from '../country';
|
|
3
3
|
import { Tactics } from './tactics';
|
|
4
|
-
import type { JerseyConfig } from './jersey';
|
|
4
|
+
import type { JerseyConfig, AlternateJerseyConfig } from './jersey';
|
|
5
5
|
export declare class Team {
|
|
6
6
|
readonly id: string;
|
|
7
7
|
readonly roster: Player[];
|
|
@@ -12,6 +12,7 @@ export declare class Team {
|
|
|
12
12
|
readonly country: Country;
|
|
13
13
|
readonly legacyFlagCountry?: Country;
|
|
14
14
|
readonly jerseyConfig?: JerseyConfig;
|
|
15
|
+
readonly alternateJerseyConfig?: AlternateJerseyConfig;
|
|
15
16
|
private _rating;
|
|
16
17
|
static create(input: unknown): Team;
|
|
17
18
|
private constructor();
|
|
@@ -19,7 +19,7 @@ class Team {
|
|
|
19
19
|
tactics: result.data.tactics != null ? tactics_1.Tactics.create(result.data.tactics) : undefined
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
|
-
constructor({ id, rating, name, shortName, divisionId, country, legacyFlagCountry, roster, tactics, jerseyConfig }) {
|
|
22
|
+
constructor({ id, rating, name, shortName, divisionId, country, legacyFlagCountry, roster, tactics, jerseyConfig, alternateJerseyConfig }) {
|
|
23
23
|
this.id = id;
|
|
24
24
|
this._rating = rating;
|
|
25
25
|
this.roster = roster;
|
|
@@ -30,6 +30,7 @@ class Team {
|
|
|
30
30
|
this.country = country;
|
|
31
31
|
this.legacyFlagCountry = legacyFlagCountry;
|
|
32
32
|
this.jerseyConfig = jerseyConfig;
|
|
33
|
+
this.alternateJerseyConfig = alternateJerseyConfig;
|
|
33
34
|
}
|
|
34
35
|
get rating() {
|
|
35
36
|
return this._rating;
|
|
@@ -17,7 +17,7 @@ export interface Results {
|
|
|
17
17
|
away: number[];
|
|
18
18
|
}
|
|
19
19
|
export interface MatchCompetition {
|
|
20
|
-
type: 'LEAGUE' | 'NATIONAL' | 'QUALIFIER' | 'TOURNAMENT' | 'EVENT';
|
|
20
|
+
type: 'LEAGUE' | 'NATIONAL' | 'QUALIFIER' | 'TOURNAMENT' | 'EVENT' | 'WNL' | 'WNLF';
|
|
21
21
|
countryName?: string;
|
|
22
22
|
countryAlpha2?: string;
|
|
23
23
|
countryAlpha3?: string;
|
|
@@ -196,7 +196,7 @@ export type Team = Omit<DataProps<_Team>, 'roster' | '_rating' | 'rating' | 'tac
|
|
|
196
196
|
nationalManager?: {
|
|
197
197
|
displayName: string;
|
|
198
198
|
teamId: string;
|
|
199
|
-
|
|
199
|
+
teamName: string;
|
|
200
200
|
};
|
|
201
201
|
};
|
|
202
202
|
export type Standing = DataProps<_Standing> & {
|
|
@@ -233,28 +233,10 @@ export function initModels(sequelize) {
|
|
|
233
233
|
Competition.hasOne(NationalCountry, { as: 'NationalCountry', foreignKey: 'competition_id' });
|
|
234
234
|
Country.hasMany(NationalCountry, { as: 'NationalCountries', foreignKey: 'country_id' });
|
|
235
235
|
Iteration.hasMany(NationalCountry, { as: 'NationalCountries', foreignKey: 'iteration' });
|
|
236
|
-
// National teams (WNL)
|
|
237
|
-
//
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
Country.hasOne(NationalTeam, { as: 'NationalTeam', foreignKey: 'country_id' });
|
|
241
|
-
Team.hasOne(NationalTeam, { as: 'NationalTeam', foreignKey: 'team_id' });
|
|
242
|
-
NationalTeam.hasOne(NationalTeamClaim, { as: 'claim', foreignKey: 'country_id' });
|
|
243
|
-
NationalTeamClaim.belongsTo(NationalTeam, { as: 'nationalTeam', foreignKey: 'country_id' });
|
|
244
|
-
NationalTeamClaim.belongsTo(AuthUser, { as: 'user', foreignKey: 'user_id' });
|
|
245
|
-
AuthUser.hasOne(NationalTeamClaim, { as: 'NationalTeamClaim', foreignKey: 'user_id' });
|
|
246
|
-
WnlSquad.belongsTo(Competition, { as: 'competition', foreignKey: 'competition_id' });
|
|
247
|
-
WnlSquad.belongsTo(Country, { as: 'country', foreignKey: 'country_id' });
|
|
248
|
-
WnlSquad.belongsTo(Team, { as: 'team', foreignKey: 'team_id' });
|
|
249
|
-
WnlSquad.belongsTo(AuthUser, { as: 'manager', foreignKey: 'manager_user_id' });
|
|
250
|
-
Competition.hasMany(WnlSquad, { as: 'WnlSquads', foreignKey: 'competition_id' });
|
|
251
|
-
WnlCallup.belongsTo(Competition, { as: 'competition', foreignKey: 'competition_id' });
|
|
252
|
-
WnlCallup.belongsTo(Player, { as: 'player', foreignKey: 'player_id' });
|
|
253
|
-
WnlCallup.belongsTo(Country, { as: 'country', foreignKey: 'country_id' });
|
|
254
|
-
Competition.hasMany(WnlCallup, { as: 'WnlCallups', foreignKey: 'competition_id' });
|
|
255
|
-
WnlSeason.belongsTo(Competition, { as: 'competition', foreignKey: 'competition_id' });
|
|
256
|
-
WnlSeason.belongsTo(Competition, { as: 'finalsCompetition', foreignKey: 'finals_competition_id' });
|
|
257
|
-
Competition.hasOne(WnlSeason, { as: 'WnlSeason', foreignKey: 'competition_id' });
|
|
236
|
+
// National teams (WNL): NO associations on purpose. Every consumer of the five WNL tables (Sim scheduler,
|
|
237
|
+
// API /wnl routes) reads them with direct model queries or raw SQL joins; the alias wiring that once lived
|
|
238
|
+
// here was confirmed unused in all four repos and removed as dead code (review fleet 2026-08-28). Add an
|
|
239
|
+
// association back only together with the include that uses it.
|
|
258
240
|
VPER.belongsTo(Player, { as: 'Player', foreignKey: 'player_id' });
|
|
259
241
|
VPER.belongsTo(Match, { as: 'Match', foreignKey: 'match_id' });
|
|
260
242
|
Team.hasOne(Coach, { as: 'Coach', foreignKey: 'team_id' });
|