volleyballsimtypes 0.0.475 → 0.0.477
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 +9 -1
- package/dist/cjs/src/data/models/auth-session.d.ts +5 -1
- package/dist/cjs/src/data/models/auth-session.js +8 -0
- package/dist/cjs/src/data/models/tactics.d.ts +9 -1
- package/dist/cjs/src/data/transformers/tactics.js +50 -11
- package/dist/cjs/src/data/transformers/tactics.test.js +67 -0
- package/dist/cjs/src/service/team/designated-sub.d.ts +5 -0
- package/dist/cjs/src/service/team/schemas/designated-sub.z.d.ts +109 -0
- package/dist/cjs/src/service/team/schemas/designated-sub.z.js +15 -3
- package/dist/cjs/src/service/team/schemas/designated-sub.z.test.js +73 -0
- package/dist/cjs/src/service/team/schemas/injury-replacement.z.test.js +11 -2
- package/dist/cjs/src/service/team/schemas/libero-sub.z.d.ts +4 -4
- package/dist/cjs/src/service/team/schemas/tactics.z.d.ts +72 -2
- package/dist/cjs/src/service/team/schemas/tactics.z.js +5 -4
- package/dist/cjs/src/service/team/schemas/team.z.d.ts +72 -2
- package/dist/esm/src/api/index.d.ts +9 -1
- package/dist/esm/src/data/models/auth-session.d.ts +5 -1
- package/dist/esm/src/data/models/auth-session.js +8 -0
- package/dist/esm/src/data/models/tactics.d.ts +9 -1
- package/dist/esm/src/data/transformers/tactics.js +50 -11
- package/dist/esm/src/data/transformers/tactics.test.js +67 -0
- package/dist/esm/src/service/team/designated-sub.d.ts +5 -0
- package/dist/esm/src/service/team/schemas/designated-sub.z.d.ts +109 -0
- package/dist/esm/src/service/team/schemas/designated-sub.z.js +14 -2
- package/dist/esm/src/service/team/schemas/designated-sub.z.test.js +73 -0
- package/dist/esm/src/service/team/schemas/injury-replacement.z.test.js +11 -2
- package/dist/esm/src/service/team/schemas/libero-sub.z.d.ts +4 -4
- package/dist/esm/src/service/team/schemas/tactics.z.d.ts +72 -2
- package/dist/esm/src/service/team/schemas/tactics.z.js +5 -4
- package/dist/esm/src/service/team/schemas/team.z.d.ts +72 -2
- package/package.json +1 -1
|
@@ -55,6 +55,41 @@ export declare const TacticsInputSchema: z.ZodObject<{
|
|
|
55
55
|
phase: z.ZodEnum<typeof import("..").MatchPhase>;
|
|
56
56
|
}, z.core.$strip>], "type">>>;
|
|
57
57
|
conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
58
|
+
pinchServer: z.ZodOptional<z.ZodBoolean>;
|
|
59
|
+
subBackMode: z.ZodOptional<z.ZodEnum<{
|
|
60
|
+
FATIGUE: "FATIGUE";
|
|
61
|
+
CONDITIONS: "CONDITIONS";
|
|
62
|
+
}>>;
|
|
63
|
+
subBackConditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
64
|
+
type: z.ZodLiteral<import("..").PinchConditionType.ASAP>;
|
|
65
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
66
|
+
type: z.ZodLiteral<import("..").PinchConditionType.TEAM_SET_POINT>;
|
|
67
|
+
margin: z.ZodNumber;
|
|
68
|
+
opponent: z.ZodEnum<typeof import("..").OpponentRelation>;
|
|
69
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
70
|
+
type: z.ZodLiteral<import("..").PinchConditionType.OPPONENT_SET_POINT>;
|
|
71
|
+
margin: z.ZodNumber;
|
|
72
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
73
|
+
type: z.ZodLiteral<import("..").PinchConditionType.SCORE_DIFF>;
|
|
74
|
+
direction: z.ZodEnum<typeof import("..").ScoreDirection>;
|
|
75
|
+
points: z.ZodNumber;
|
|
76
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
77
|
+
type: z.ZodLiteral<import("..").PinchConditionType.AFTER_ROTATIONS>;
|
|
78
|
+
rotations: z.ZodNumber;
|
|
79
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
80
|
+
type: z.ZodLiteral<import("..").PinchConditionType.FROM_SET>;
|
|
81
|
+
set: z.ZodNumber;
|
|
82
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
83
|
+
type: z.ZodLiteral<import("..").PinchConditionType.MIN_OWN_SCORE>;
|
|
84
|
+
score: z.ZodNumber;
|
|
85
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
86
|
+
type: z.ZodLiteral<import("..").PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
87
|
+
score: z.ZodNumber;
|
|
88
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
89
|
+
type: z.ZodLiteral<import("..").PinchConditionType.PHASE>;
|
|
90
|
+
phase: z.ZodEnum<typeof import("..").MatchPhase>;
|
|
91
|
+
}, z.core.$strip>], "type">>>;
|
|
92
|
+
subBackConditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
58
93
|
}, z.core.$strip>>>;
|
|
59
94
|
mode: z.ZodEnum<{
|
|
60
95
|
NEVER: "NEVER";
|
|
@@ -94,6 +129,41 @@ export declare const TacticsInputSchema: z.ZodObject<{
|
|
|
94
129
|
phase: z.ZodEnum<typeof import("..").MatchPhase>;
|
|
95
130
|
}, z.core.$strip>], "type">>>;
|
|
96
131
|
conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
132
|
+
pinchServer: z.ZodOptional<z.ZodBoolean>;
|
|
133
|
+
subBackMode: z.ZodOptional<z.ZodEnum<{
|
|
134
|
+
FATIGUE: "FATIGUE";
|
|
135
|
+
CONDITIONS: "CONDITIONS";
|
|
136
|
+
}>>;
|
|
137
|
+
subBackConditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
138
|
+
type: z.ZodLiteral<import("..").PinchConditionType.ASAP>;
|
|
139
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
140
|
+
type: z.ZodLiteral<import("..").PinchConditionType.TEAM_SET_POINT>;
|
|
141
|
+
margin: z.ZodNumber;
|
|
142
|
+
opponent: z.ZodEnum<typeof import("..").OpponentRelation>;
|
|
143
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
144
|
+
type: z.ZodLiteral<import("..").PinchConditionType.OPPONENT_SET_POINT>;
|
|
145
|
+
margin: z.ZodNumber;
|
|
146
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
147
|
+
type: z.ZodLiteral<import("..").PinchConditionType.SCORE_DIFF>;
|
|
148
|
+
direction: z.ZodEnum<typeof import("..").ScoreDirection>;
|
|
149
|
+
points: z.ZodNumber;
|
|
150
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
151
|
+
type: z.ZodLiteral<import("..").PinchConditionType.AFTER_ROTATIONS>;
|
|
152
|
+
rotations: z.ZodNumber;
|
|
153
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
154
|
+
type: z.ZodLiteral<import("..").PinchConditionType.FROM_SET>;
|
|
155
|
+
set: z.ZodNumber;
|
|
156
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
157
|
+
type: z.ZodLiteral<import("..").PinchConditionType.MIN_OWN_SCORE>;
|
|
158
|
+
score: z.ZodNumber;
|
|
159
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
160
|
+
type: z.ZodLiteral<import("..").PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
161
|
+
score: z.ZodNumber;
|
|
162
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
163
|
+
type: z.ZodLiteral<import("..").PinchConditionType.PHASE>;
|
|
164
|
+
phase: z.ZodEnum<typeof import("..").MatchPhase>;
|
|
165
|
+
}, z.core.$strip>], "type">>>;
|
|
166
|
+
subBackConditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
97
167
|
starter: z.ZodCustom<Player, Player>;
|
|
98
168
|
}, z.core.$strip>>>;
|
|
99
169
|
substitutionBand: z.ZodDefault<z.ZodUnion<readonly [z.ZodEnum<typeof EnergyBand>, z.ZodLiteral<"NEVER">]>>;
|
|
@@ -103,8 +173,8 @@ export declare const TacticsInputSchema: z.ZodObject<{
|
|
|
103
173
|
mode: z.ZodEnum<{
|
|
104
174
|
NEVER: "NEVER";
|
|
105
175
|
FATIGUE: "FATIGUE";
|
|
106
|
-
ALWAYS: "ALWAYS";
|
|
107
176
|
CONDITIONS: "CONDITIONS";
|
|
177
|
+
ALWAYS: "ALWAYS";
|
|
108
178
|
}>;
|
|
109
179
|
fatigueBand: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
|
|
110
180
|
conditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -141,8 +211,8 @@ export declare const TacticsInputSchema: z.ZodObject<{
|
|
|
141
211
|
mode: z.ZodEnum<{
|
|
142
212
|
NEVER: "NEVER";
|
|
143
213
|
FATIGUE: "FATIGUE";
|
|
144
|
-
ALWAYS: "ALWAYS";
|
|
145
214
|
CONDITIONS: "CONDITIONS";
|
|
215
|
+
ALWAYS: "ALWAYS";
|
|
146
216
|
}>;
|
|
147
217
|
fatigueBand: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
|
|
148
218
|
conditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -198,10 +198,11 @@ exports.TacticsInputSchema = zod_1.z.object({
|
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
|
-
// Per-
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
|
|
201
|
+
// Per-player knock toggle: every key must be a court starter OR the starting libero. The libero may carry its
|
|
202
|
+
// own key so the user can choose to keep a lightly knocked libero on court (owner 2026-07-06). Bench/reserve
|
|
203
|
+
// players still follow the slot they occupy, so they never carry their own key.
|
|
204
|
+
for (const knockedId of Object.keys(data.replaceKnockedImmediately)) {
|
|
205
|
+
if (!starterIds.has(knockedId) && knockedId !== libero?.id) {
|
|
205
206
|
ctx.addIssue({ code: 'custom', message: 'REPLACE_KNOCKED_KEY_NOT_A_STARTER', path: ['replaceKnockedImmediately'] });
|
|
206
207
|
}
|
|
207
208
|
}
|
|
@@ -63,6 +63,41 @@ export declare const TeamInputSchema: z.ZodObject<{
|
|
|
63
63
|
phase: z.ZodEnum<typeof import("..").MatchPhase>;
|
|
64
64
|
}, z.core.$strip>], "type">>>;
|
|
65
65
|
conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
66
|
+
pinchServer: z.ZodOptional<z.ZodBoolean>;
|
|
67
|
+
subBackMode: z.ZodOptional<z.ZodEnum<{
|
|
68
|
+
FATIGUE: "FATIGUE";
|
|
69
|
+
CONDITIONS: "CONDITIONS";
|
|
70
|
+
}>>;
|
|
71
|
+
subBackConditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
72
|
+
type: z.ZodLiteral<import("..").PinchConditionType.ASAP>;
|
|
73
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
74
|
+
type: z.ZodLiteral<import("..").PinchConditionType.TEAM_SET_POINT>;
|
|
75
|
+
margin: z.ZodNumber;
|
|
76
|
+
opponent: z.ZodEnum<typeof import("..").OpponentRelation>;
|
|
77
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
78
|
+
type: z.ZodLiteral<import("..").PinchConditionType.OPPONENT_SET_POINT>;
|
|
79
|
+
margin: z.ZodNumber;
|
|
80
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
81
|
+
type: z.ZodLiteral<import("..").PinchConditionType.SCORE_DIFF>;
|
|
82
|
+
direction: z.ZodEnum<typeof import("..").ScoreDirection>;
|
|
83
|
+
points: z.ZodNumber;
|
|
84
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
85
|
+
type: z.ZodLiteral<import("..").PinchConditionType.AFTER_ROTATIONS>;
|
|
86
|
+
rotations: z.ZodNumber;
|
|
87
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
88
|
+
type: z.ZodLiteral<import("..").PinchConditionType.FROM_SET>;
|
|
89
|
+
set: z.ZodNumber;
|
|
90
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
91
|
+
type: z.ZodLiteral<import("..").PinchConditionType.MIN_OWN_SCORE>;
|
|
92
|
+
score: z.ZodNumber;
|
|
93
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
94
|
+
type: z.ZodLiteral<import("..").PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
95
|
+
score: z.ZodNumber;
|
|
96
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
97
|
+
type: z.ZodLiteral<import("..").PinchConditionType.PHASE>;
|
|
98
|
+
phase: z.ZodEnum<typeof import("..").MatchPhase>;
|
|
99
|
+
}, z.core.$strip>], "type">>>;
|
|
100
|
+
subBackConditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
66
101
|
}, z.core.$strip>>>;
|
|
67
102
|
mode: z.ZodEnum<{
|
|
68
103
|
NEVER: "NEVER";
|
|
@@ -102,6 +137,41 @@ export declare const TeamInputSchema: z.ZodObject<{
|
|
|
102
137
|
phase: z.ZodEnum<typeof import("..").MatchPhase>;
|
|
103
138
|
}, z.core.$strip>], "type">>>;
|
|
104
139
|
conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
140
|
+
pinchServer: z.ZodOptional<z.ZodBoolean>;
|
|
141
|
+
subBackMode: z.ZodOptional<z.ZodEnum<{
|
|
142
|
+
FATIGUE: "FATIGUE";
|
|
143
|
+
CONDITIONS: "CONDITIONS";
|
|
144
|
+
}>>;
|
|
145
|
+
subBackConditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
146
|
+
type: z.ZodLiteral<import("..").PinchConditionType.ASAP>;
|
|
147
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
148
|
+
type: z.ZodLiteral<import("..").PinchConditionType.TEAM_SET_POINT>;
|
|
149
|
+
margin: z.ZodNumber;
|
|
150
|
+
opponent: z.ZodEnum<typeof import("..").OpponentRelation>;
|
|
151
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
152
|
+
type: z.ZodLiteral<import("..").PinchConditionType.OPPONENT_SET_POINT>;
|
|
153
|
+
margin: z.ZodNumber;
|
|
154
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
155
|
+
type: z.ZodLiteral<import("..").PinchConditionType.SCORE_DIFF>;
|
|
156
|
+
direction: z.ZodEnum<typeof import("..").ScoreDirection>;
|
|
157
|
+
points: z.ZodNumber;
|
|
158
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
159
|
+
type: z.ZodLiteral<import("..").PinchConditionType.AFTER_ROTATIONS>;
|
|
160
|
+
rotations: z.ZodNumber;
|
|
161
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
162
|
+
type: z.ZodLiteral<import("..").PinchConditionType.FROM_SET>;
|
|
163
|
+
set: z.ZodNumber;
|
|
164
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
165
|
+
type: z.ZodLiteral<import("..").PinchConditionType.MIN_OWN_SCORE>;
|
|
166
|
+
score: z.ZodNumber;
|
|
167
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
168
|
+
type: z.ZodLiteral<import("..").PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
169
|
+
score: z.ZodNumber;
|
|
170
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
171
|
+
type: z.ZodLiteral<import("..").PinchConditionType.PHASE>;
|
|
172
|
+
phase: z.ZodEnum<typeof import("..").MatchPhase>;
|
|
173
|
+
}, z.core.$strip>], "type">>>;
|
|
174
|
+
subBackConditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
105
175
|
starter: z.ZodCustom<Player, Player>;
|
|
106
176
|
}, z.core.$strip>>>;
|
|
107
177
|
substitutionBand: z.ZodDefault<z.ZodUnion<readonly [z.ZodEnum<typeof import("..").EnergyBand>, z.ZodLiteral<"NEVER">]>>;
|
|
@@ -111,8 +181,8 @@ export declare const TeamInputSchema: z.ZodObject<{
|
|
|
111
181
|
mode: z.ZodEnum<{
|
|
112
182
|
NEVER: "NEVER";
|
|
113
183
|
FATIGUE: "FATIGUE";
|
|
114
|
-
ALWAYS: "ALWAYS";
|
|
115
184
|
CONDITIONS: "CONDITIONS";
|
|
185
|
+
ALWAYS: "ALWAYS";
|
|
116
186
|
}>;
|
|
117
187
|
fatigueBand: z.ZodOptional<z.ZodEnum<typeof import("..").EnergyBand>>;
|
|
118
188
|
conditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -149,8 +219,8 @@ export declare const TeamInputSchema: z.ZodObject<{
|
|
|
149
219
|
mode: z.ZodEnum<{
|
|
150
220
|
NEVER: "NEVER";
|
|
151
221
|
FATIGUE: "FATIGUE";
|
|
152
|
-
ALWAYS: "ALWAYS";
|
|
153
222
|
CONDITIONS: "CONDITIONS";
|
|
223
|
+
ALWAYS: "ALWAYS";
|
|
154
224
|
}>;
|
|
155
225
|
fatigueBand: z.ZodOptional<z.ZodEnum<typeof import("..").EnergyBand>>;
|
|
156
226
|
conditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BoxScore, DataProps, DeclineStatus, Division as _Division, League as _League, Match as _Match, MatchSet as _MatchSet, Player as _Player, PlayerPosition, Qualifier as _Qualifier, QualifierMatch as _QualifierMatch, Rally as _Rally, RallyEvent as _RallyEvent, PointBreakdown, RallyMetrics, Season as _Season, Standing as _Standing, Team as _Team, Tournament as _Tournament, TournamentMatch as _TournamentMatch, National as _National, NationalMatch as _NationalMatch, Country as _Country, CourtPosition, ConditionLogic, EnergyBand, LiberoSubMode, MatchForfeitType, PerformanceStats, PinchCondition, RotationSystemEnum, SubBand, SubMode } from '../service';
|
|
1
|
+
import { BoxScore, DataProps, DeclineStatus, Division as _Division, League as _League, Match as _Match, MatchSet as _MatchSet, Player as _Player, PlayerPosition, Qualifier as _Qualifier, QualifierMatch as _QualifierMatch, Rally as _Rally, RallyEvent as _RallyEvent, PointBreakdown, RallyMetrics, Season as _Season, Standing as _Standing, Team as _Team, Tournament as _Tournament, TournamentMatch as _TournamentMatch, National as _National, NationalMatch as _NationalMatch, Country as _Country, CourtPosition, ConditionLogic, EnergyBand, LiberoSubMode, MatchForfeitType, PerformanceStats, PinchCondition, RotationSystemEnum, SubBackMode, SubBand, SubMode } from '../service';
|
|
2
2
|
export type Rally = DataProps<_Rally> & {
|
|
3
3
|
homePlayerPosition: PlayerPosition[];
|
|
4
4
|
awayPlayerPosition: PlayerPosition[];
|
|
@@ -87,6 +87,10 @@ export interface ApiSetSubConfig {
|
|
|
87
87
|
benchFatigueBand?: EnergyBand;
|
|
88
88
|
conditions?: PinchCondition[];
|
|
89
89
|
conditionLogic?: ConditionLogic;
|
|
90
|
+
pinchServer?: boolean;
|
|
91
|
+
subBackMode?: SubBackMode;
|
|
92
|
+
subBackConditions?: PinchCondition[];
|
|
93
|
+
subBackConditionLogic?: ConditionLogic;
|
|
90
94
|
}
|
|
91
95
|
export interface ApiDesignatedSub {
|
|
92
96
|
starterId: string;
|
|
@@ -96,6 +100,10 @@ export interface ApiDesignatedSub {
|
|
|
96
100
|
benchFatigueBand?: EnergyBand;
|
|
97
101
|
conditions?: PinchCondition[];
|
|
98
102
|
conditionLogic?: ConditionLogic;
|
|
103
|
+
pinchServer?: boolean;
|
|
104
|
+
subBackMode?: SubBackMode;
|
|
105
|
+
subBackConditions?: PinchCondition[];
|
|
106
|
+
subBackConditionLogic?: ConditionLogic;
|
|
99
107
|
sets?: ApiSetSubConfig[];
|
|
100
108
|
}
|
|
101
109
|
export interface ApiOffensivePreference {
|
|
@@ -11,10 +11,12 @@ export interface AuthSessionAttributes {
|
|
|
11
11
|
user_agent?: string | null;
|
|
12
12
|
created_at?: Date;
|
|
13
13
|
updated_at?: Date;
|
|
14
|
+
previous_refresh_token_hash?: string | null;
|
|
15
|
+
previous_token_expires_at?: Date | null;
|
|
14
16
|
}
|
|
15
17
|
export type AuthSessionPk = 'session_id';
|
|
16
18
|
export type AuthSessionId = AuthSessionModel[AuthSessionPk];
|
|
17
|
-
export type AuthSessionOptionalAttributes = 'revoked_at' | 'ip_address' | 'user_agent' | 'created_at' | 'updated_at';
|
|
19
|
+
export type AuthSessionOptionalAttributes = 'revoked_at' | 'ip_address' | 'user_agent' | 'created_at' | 'updated_at' | 'previous_refresh_token_hash' | 'previous_token_expires_at';
|
|
18
20
|
export type AuthSessionCreationAttributes = Optional<AuthSessionAttributes, AuthSessionOptionalAttributes>;
|
|
19
21
|
export declare class AuthSessionModel extends Model<AuthSessionAttributes, AuthSessionCreationAttributes> implements AuthSessionAttributes {
|
|
20
22
|
session_id: string;
|
|
@@ -26,6 +28,8 @@ export declare class AuthSessionModel extends Model<AuthSessionAttributes, AuthS
|
|
|
26
28
|
user_agent?: string | null;
|
|
27
29
|
created_at?: Date;
|
|
28
30
|
updated_at?: Date;
|
|
31
|
+
previous_refresh_token_hash?: string | null;
|
|
32
|
+
previous_token_expires_at?: Date | null;
|
|
29
33
|
user: AuthUserModel;
|
|
30
34
|
getUser: Sequelize.BelongsToGetAssociationMixin<AuthUserModel>;
|
|
31
35
|
setUser: Sequelize.BelongsToSetAssociationMixin<AuthUserModel, AuthUserId>;
|
|
@@ -44,6 +44,14 @@ export class AuthSessionModel extends Model {
|
|
|
44
44
|
type: DataTypes.DATE,
|
|
45
45
|
allowNull: false,
|
|
46
46
|
defaultValue: DataTypes.NOW
|
|
47
|
+
},
|
|
48
|
+
previous_refresh_token_hash: {
|
|
49
|
+
type: DataTypes.STRING,
|
|
50
|
+
allowNull: true
|
|
51
|
+
},
|
|
52
|
+
previous_token_expires_at: {
|
|
53
|
+
type: DataTypes.DATE,
|
|
54
|
+
allowNull: true
|
|
47
55
|
}
|
|
48
56
|
}, {
|
|
49
57
|
sequelize,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as Sequelize from 'sequelize';
|
|
2
2
|
import { Model, Optional } from 'sequelize';
|
|
3
3
|
import { PlayerId, TeamId, TeamModel } from '.';
|
|
4
|
-
import { ConditionLogic, CourtPosition, EnergyBand, LiberoSubMode, PinchCondition, RotationSystemEnum, SubBand, SubMode } from '../../service';
|
|
4
|
+
import { ConditionLogic, CourtPosition, EnergyBand, LiberoSubMode, PinchCondition, RotationSystemEnum, SubBackMode, SubBand, SubMode } from '../../service';
|
|
5
5
|
export interface TacticsLineupAttributes {
|
|
6
6
|
[CourtPosition.LIBERO_ZONE]?: PlayerId;
|
|
7
7
|
[CourtPosition.LEFT_BACK]: PlayerId;
|
|
@@ -19,6 +19,10 @@ export interface SetSubConfigAttributes {
|
|
|
19
19
|
benchFatigueBand?: EnergyBand;
|
|
20
20
|
conditions?: PinchCondition[];
|
|
21
21
|
conditionLogic?: ConditionLogic;
|
|
22
|
+
pinchServer?: boolean;
|
|
23
|
+
subBackMode?: SubBackMode;
|
|
24
|
+
subBackConditions?: PinchCondition[];
|
|
25
|
+
subBackConditionLogic?: ConditionLogic;
|
|
22
26
|
}
|
|
23
27
|
export interface DesignatedSubAttributes {
|
|
24
28
|
starterId: PlayerId;
|
|
@@ -29,6 +33,10 @@ export interface DesignatedSubAttributes {
|
|
|
29
33
|
benchFatigueBand?: EnergyBand;
|
|
30
34
|
conditions?: PinchCondition[];
|
|
31
35
|
conditionLogic?: ConditionLogic;
|
|
36
|
+
pinchServer?: boolean;
|
|
37
|
+
subBackMode?: SubBackMode;
|
|
38
|
+
subBackConditions?: PinchCondition[];
|
|
39
|
+
subBackConditionLogic?: ConditionLogic;
|
|
32
40
|
sets?: SetSubConfigAttributes[];
|
|
33
41
|
}
|
|
34
42
|
export interface OffensivePreferenceAttributes {
|
|
@@ -11,6 +11,12 @@ function subModeFromAttributes(d) {
|
|
|
11
11
|
return 'NEVER';
|
|
12
12
|
return 'FATIGUE';
|
|
13
13
|
}
|
|
14
|
+
// pinchServer only applies to PINCH ("Conditions") mode. A LEGACY PINCH row (no flag) defaults to true so
|
|
15
|
+
// existing pinch servers keep serve-and-return behavior; a new conditional sub persists an explicit false. This
|
|
16
|
+
// default must resolve identically on every READ path (both transformToObject and tacticsColumnsToApiDto).
|
|
17
|
+
function effectivePinchServer(mode, pinchServer) {
|
|
18
|
+
return mode === 'PINCH' ? (pinchServer ?? true) : undefined;
|
|
19
|
+
}
|
|
14
20
|
function findPlayer(id, roster) {
|
|
15
21
|
const player = roster.find((p) => p.id === id);
|
|
16
22
|
if (player == null)
|
|
@@ -59,13 +65,21 @@ function transformToAttributes(tactics, teamId) {
|
|
|
59
65
|
benchFatigueBand: ds.benchFatigueBand,
|
|
60
66
|
conditions: ds.conditions,
|
|
61
67
|
conditionLogic: ds.conditionLogic,
|
|
68
|
+
pinchServer: ds.pinchServer,
|
|
69
|
+
subBackMode: ds.subBackMode,
|
|
70
|
+
subBackConditions: ds.subBackConditions,
|
|
71
|
+
subBackConditionLogic: ds.subBackConditionLogic,
|
|
62
72
|
sets: ds.sets?.map(s => ({
|
|
63
73
|
mode: s.mode,
|
|
64
74
|
benchId: s.bench?.id,
|
|
65
75
|
fatigueBand: s.fatigueBand,
|
|
66
76
|
benchFatigueBand: s.benchFatigueBand,
|
|
67
77
|
conditions: s.conditions,
|
|
68
|
-
conditionLogic: s.conditionLogic
|
|
78
|
+
conditionLogic: s.conditionLogic,
|
|
79
|
+
pinchServer: s.pinchServer,
|
|
80
|
+
subBackMode: s.subBackMode,
|
|
81
|
+
subBackConditions: s.subBackConditions,
|
|
82
|
+
subBackConditionLogic: s.subBackConditionLogic
|
|
69
83
|
}))
|
|
70
84
|
})),
|
|
71
85
|
rotation_system: tactics.rotationSystem,
|
|
@@ -149,13 +163,21 @@ function transformToObject(model, roster) {
|
|
|
149
163
|
benchFatigueBand: d.benchFatigueBand,
|
|
150
164
|
conditions: d.conditions,
|
|
151
165
|
conditionLogic: d.conditionLogic,
|
|
166
|
+
pinchServer: effectivePinchServer(subModeFromAttributes(d), d.pinchServer),
|
|
167
|
+
subBackMode: d.subBackMode,
|
|
168
|
+
subBackConditions: d.subBackConditions,
|
|
169
|
+
subBackConditionLogic: d.subBackConditionLogic,
|
|
152
170
|
sets: d.sets?.map(s => ({
|
|
153
171
|
mode: s.mode,
|
|
154
172
|
bench: s.benchId != null ? findPlayer(s.benchId, roster) : undefined,
|
|
155
173
|
fatigueBand: s.fatigueBand,
|
|
156
174
|
benchFatigueBand: s.benchFatigueBand,
|
|
157
175
|
conditions: s.conditions,
|
|
158
|
-
conditionLogic: s.conditionLogic
|
|
176
|
+
conditionLogic: s.conditionLogic,
|
|
177
|
+
pinchServer: effectivePinchServer(s.mode, s.pinchServer),
|
|
178
|
+
subBackMode: s.subBackMode,
|
|
179
|
+
subBackConditions: s.subBackConditions,
|
|
180
|
+
subBackConditionLogic: s.subBackConditionLogic
|
|
159
181
|
}))
|
|
160
182
|
})),
|
|
161
183
|
rotationSystem: model.rotation_system,
|
|
@@ -172,15 +194,20 @@ function transformToObject(model, roster) {
|
|
|
172
194
|
rotation: p.rotation,
|
|
173
195
|
order: p.order.map((id) => findPlayer(id, roster))
|
|
174
196
|
}))),
|
|
175
|
-
// LENIENT: keep only
|
|
176
|
-
//
|
|
197
|
+
// LENIENT: keep only boolean entries keyed by a court starter or, when a second libero exists, the starting
|
|
198
|
+
// libero (the libero knock toggle is an L2-only feature, owner 2026-07-06) so stale jsonb (an ex-starter's
|
|
199
|
+
// key, a non-boolean value, a libero key left after the L2 was removed) can never fail schema validation
|
|
200
|
+
// and crash a team load; a dropped key = the ON default.
|
|
177
201
|
replaceKnockedImmediately: (() => {
|
|
178
|
-
const
|
|
202
|
+
const allowedIds = new Set([lineup[CourtPosition.LEFT_FRONT], lineup[CourtPosition.MIDDLE_FRONT], lineup[CourtPosition.RIGHT_FRONT],
|
|
179
203
|
lineup[CourtPosition.LEFT_BACK], lineup[CourtPosition.MIDDLE_BACK], lineup[CourtPosition.RIGHT_BACK]]
|
|
180
204
|
.map((p) => p.id));
|
|
205
|
+
const liberoZoneId = lineup[CourtPosition.LIBERO_ZONE]?.id;
|
|
206
|
+
if (liberoZoneId != null && secondLibero != null)
|
|
207
|
+
allowedIds.add(liberoZoneId);
|
|
181
208
|
const healed = {};
|
|
182
209
|
for (const [id, value] of Object.entries(model.replace_knocked_immediately ?? {})) {
|
|
183
|
-
if (
|
|
210
|
+
if (allowedIds.has(id) && typeof value === 'boolean')
|
|
184
211
|
healed[id] = value;
|
|
185
212
|
}
|
|
186
213
|
return healed;
|
|
@@ -301,13 +328,21 @@ function tacticsColumnsToApiDto(model) {
|
|
|
301
328
|
benchFatigueBand: d.benchFatigueBand,
|
|
302
329
|
conditions: d.conditions,
|
|
303
330
|
conditionLogic: d.conditionLogic,
|
|
331
|
+
pinchServer: effectivePinchServer(subModeFromAttributes(d), d.pinchServer),
|
|
332
|
+
subBackMode: d.subBackMode,
|
|
333
|
+
subBackConditions: d.subBackConditions,
|
|
334
|
+
subBackConditionLogic: d.subBackConditionLogic,
|
|
304
335
|
sets: d.sets?.map(s => ({
|
|
305
336
|
mode: s.mode,
|
|
306
337
|
benchId: s.benchId,
|
|
307
338
|
fatigueBand: s.fatigueBand,
|
|
308
339
|
benchFatigueBand: s.benchFatigueBand,
|
|
309
340
|
conditions: s.conditions,
|
|
310
|
-
conditionLogic: s.conditionLogic
|
|
341
|
+
conditionLogic: s.conditionLogic,
|
|
342
|
+
pinchServer: effectivePinchServer(s.mode, s.pinchServer),
|
|
343
|
+
subBackMode: s.subBackMode,
|
|
344
|
+
subBackConditions: s.subBackConditions,
|
|
345
|
+
subBackConditionLogic: s.subBackConditionLogic
|
|
311
346
|
}))
|
|
312
347
|
})),
|
|
313
348
|
rotationSystem: model.rotation_system,
|
|
@@ -315,15 +350,19 @@ function tacticsColumnsToApiDto(model) {
|
|
|
315
350
|
offensivePreferences: model.offensive_preferences,
|
|
316
351
|
systemSets: model.system_sets,
|
|
317
352
|
offensivePreferenceSets: model.offensive_preference_sets,
|
|
318
|
-
// Same stale-data policy as the heals below: only
|
|
319
|
-
//
|
|
353
|
+
// Same stale-data policy as the heals below: only boolean entries keyed by a court starter or, when a second
|
|
354
|
+
// libero exists, the starting libero (the libero knock toggle is an L2-only feature, owner 2026-07-06)
|
|
355
|
+
// survive; an empty map surfaces as absent (missing key = ON).
|
|
320
356
|
replaceKnockedImmediately: (() => {
|
|
321
|
-
const
|
|
357
|
+
const allowedSlotIds = new Set([model.lineup[CourtPosition.LEFT_FRONT], model.lineup[CourtPosition.MIDDLE_FRONT],
|
|
322
358
|
model.lineup[CourtPosition.RIGHT_FRONT], model.lineup[CourtPosition.LEFT_BACK],
|
|
323
359
|
model.lineup[CourtPosition.MIDDLE_BACK], model.lineup[CourtPosition.RIGHT_BACK]]);
|
|
360
|
+
const liberoZoneId = model.lineup[CourtPosition.LIBERO_ZONE];
|
|
361
|
+
if (liberoZoneId != null && validSecondLibero != null)
|
|
362
|
+
allowedSlotIds.add(liberoZoneId);
|
|
324
363
|
const healed = {};
|
|
325
364
|
for (const [id, value] of Object.entries(model.replace_knocked_immediately ?? {})) {
|
|
326
|
-
if (
|
|
365
|
+
if (allowedSlotIds.has(id) && typeof value === 'boolean')
|
|
327
366
|
healed[id] = value;
|
|
328
367
|
}
|
|
329
368
|
return Object.keys(healed).length > 0 ? healed : undefined;
|
|
@@ -58,6 +58,37 @@ describe('tacticsColumnsToApiDto()', () => {
|
|
|
58
58
|
expect(dto.designatedSubs[0].fatigueBand).toBe(EnergyBand.WORN);
|
|
59
59
|
expect(dto.designatedSubs[0].benchFatigueBand).toBe(EnergyBand.TIRED);
|
|
60
60
|
});
|
|
61
|
+
it('defaults a legacy PINCH row (no pinchServer flag) to pinchServer true', () => {
|
|
62
|
+
const dto = tacticsColumnsToApiDto(makeTactics([
|
|
63
|
+
{ starterId: 's1', benchId: 'b1', mode: 'PINCH', conditions: [{ type: 'ASAP' }] }
|
|
64
|
+
]));
|
|
65
|
+
expect(dto.designatedSubs[0].pinchServer).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
it('leaves pinchServer undefined for a non-PINCH row', () => {
|
|
68
|
+
const dto = tacticsColumnsToApiDto(makeTactics([
|
|
69
|
+
{ starterId: 's1', benchId: 'b1', mode: 'FATIGUE', fatigueBand: EnergyBand.TIRED }
|
|
70
|
+
]));
|
|
71
|
+
expect(dto.designatedSubs[0].pinchServer).toBeUndefined();
|
|
72
|
+
});
|
|
73
|
+
it('passes a conditional regular sub (pinchServer false + condition sub-back) through unchanged', () => {
|
|
74
|
+
const dto = tacticsColumnsToApiDto(makeTactics([
|
|
75
|
+
{
|
|
76
|
+
starterId: 's1',
|
|
77
|
+
benchId: 'b1',
|
|
78
|
+
mode: 'PINCH',
|
|
79
|
+
conditions: [{ type: 'SCORE_DIFF', direction: 'TRAILING', points: 3 }],
|
|
80
|
+
pinchServer: false,
|
|
81
|
+
subBackMode: 'CONDITIONS',
|
|
82
|
+
subBackConditions: [{ type: 'TEAM_SET_POINT', margin: 2, opponent: 'EITHER' }],
|
|
83
|
+
subBackConditionLogic: 'ANY'
|
|
84
|
+
}
|
|
85
|
+
]));
|
|
86
|
+
const ds = dto.designatedSubs[0];
|
|
87
|
+
expect(ds.pinchServer).toBe(false);
|
|
88
|
+
expect(ds.subBackMode).toBe('CONDITIONS');
|
|
89
|
+
expect(ds.subBackConditions).toEqual([{ type: 'TEAM_SET_POINT', margin: 2, opponent: 'EITHER' }]);
|
|
90
|
+
expect(ds.subBackConditionLogic).toBe('ANY');
|
|
91
|
+
});
|
|
61
92
|
it('drops a second libero that collides with the starting libero (not a reserve)', () => {
|
|
62
93
|
const model = makeTactics([]);
|
|
63
94
|
model.lineup[CourtPosition.LIBERO_ZONE] = 'libero1';
|
|
@@ -76,6 +107,21 @@ describe('tacticsColumnsToApiDto()', () => {
|
|
|
76
107
|
expect(dto.secondLibero).toBe('reserve1');
|
|
77
108
|
expect(dto.liberoSub).toEqual({ mode: 'FATIGUE' });
|
|
78
109
|
});
|
|
110
|
+
it('keeps a libero-keyed replaceKnockedImmediately entry when a second libero exists (L2-only feature)', () => {
|
|
111
|
+
const model = makeTactics([]);
|
|
112
|
+
model.lineup[CourtPosition.LIBERO_ZONE] = 'libero1';
|
|
113
|
+
model.second_libero = 'reserve1';
|
|
114
|
+
model.replace_knocked_immediately = { libero1: false, lf: false };
|
|
115
|
+
const dto = tacticsColumnsToApiDto(model);
|
|
116
|
+
expect(dto.replaceKnockedImmediately).toEqual({ libero1: false, lf: false });
|
|
117
|
+
});
|
|
118
|
+
it('drops a libero-keyed replaceKnockedImmediately entry when there is no second libero', () => {
|
|
119
|
+
const model = makeTactics([]);
|
|
120
|
+
model.lineup[CourtPosition.LIBERO_ZONE] = 'libero1';
|
|
121
|
+
model.replace_knocked_immediately = { libero1: false, lf: false };
|
|
122
|
+
const dto = tacticsColumnsToApiDto(model);
|
|
123
|
+
expect(dto.replaceKnockedImmediately).toEqual({ lf: false });
|
|
124
|
+
});
|
|
79
125
|
it('passes per-set tactics columns through to the API DTO shape', () => {
|
|
80
126
|
const model = makeTactics([]);
|
|
81
127
|
model.system_sets = [{ rotationSystem: RotationSystemEnum.FIVE_ONE, designatedSetters: ['lf'] }];
|
|
@@ -180,4 +226,25 @@ describe('libero injuries — service <-> row round-trip + lenient heal', () =>
|
|
|
180
226
|
expect(back.liberoInjury?.secondLiberoBackfill).toBeUndefined();
|
|
181
227
|
expect(back.liberoInjury?.inMatchDesignate?.id).toBe(reserveB.id);
|
|
182
228
|
});
|
|
229
|
+
it('keeps a libero-keyed replaceKnockedImmediately entry on load when an L2 exists', () => {
|
|
230
|
+
const withKnock = Tactics.create({
|
|
231
|
+
lineup: { 4: p4, 3: p3, 2: p2, 5: p5, 6: p6, 1: p1, 0: libero, bench: [] },
|
|
232
|
+
liberoReplacements: [],
|
|
233
|
+
secondLibero: l2,
|
|
234
|
+
replaceKnockedImmediately: { [libero.id]: false, [p1.id]: false }
|
|
235
|
+
});
|
|
236
|
+
const attrs = transformFromTactics(withKnock, 'team-1');
|
|
237
|
+
const back = transformToTactics(attrs, roster);
|
|
238
|
+
expect(back.replaceKnockedImmediately).toEqual({ [libero.id]: false, [p1.id]: false });
|
|
239
|
+
});
|
|
240
|
+
it('drops a libero-keyed replaceKnockedImmediately entry on load when there is no L2', () => {
|
|
241
|
+
const withKnock = Tactics.create({
|
|
242
|
+
lineup: { 4: p4, 3: p3, 2: p2, 5: p5, 6: p6, 1: p1, 0: libero, bench: [] },
|
|
243
|
+
liberoReplacements: [],
|
|
244
|
+
replaceKnockedImmediately: { [libero.id]: false, [p1.id]: false }
|
|
245
|
+
});
|
|
246
|
+
const attrs = transformFromTactics(withKnock, 'team-1');
|
|
247
|
+
const back = transformToTactics(attrs, roster);
|
|
248
|
+
expect(back.replaceKnockedImmediately).toEqual({ [p1.id]: false });
|
|
249
|
+
});
|
|
183
250
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Player } from '../player';
|
|
2
2
|
import { EnergyBand, SubMode } from './energy-band';
|
|
3
3
|
import { ConditionLogic, PinchCondition } from './pinch-condition';
|
|
4
|
+
export type SubBackMode = 'FATIGUE' | 'CONDITIONS';
|
|
4
5
|
export interface SetSubConfig {
|
|
5
6
|
readonly mode: SubMode;
|
|
6
7
|
readonly bench?: Player;
|
|
@@ -8,6 +9,10 @@ export interface SetSubConfig {
|
|
|
8
9
|
readonly benchFatigueBand?: EnergyBand;
|
|
9
10
|
readonly conditions?: PinchCondition[];
|
|
10
11
|
readonly conditionLogic?: ConditionLogic;
|
|
12
|
+
readonly pinchServer?: boolean;
|
|
13
|
+
readonly subBackMode?: SubBackMode;
|
|
14
|
+
readonly subBackConditions?: PinchCondition[];
|
|
15
|
+
readonly subBackConditionLogic?: ConditionLogic;
|
|
11
16
|
}
|
|
12
17
|
export interface DesignatedSub extends SetSubConfig {
|
|
13
18
|
readonly starter: Player;
|