volleyballsimtypes 0.0.482 → 0.0.485

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.
Files changed (119) hide show
  1. package/dist/cjs/src/api/index.d.ts +3 -17
  2. package/dist/cjs/src/data/models/tactics.d.ts +7 -17
  3. package/dist/cjs/src/data/transformers/match-preset-override.test.js +10 -1
  4. package/dist/cjs/src/data/transformers/rally-event.d.ts +2 -1
  5. package/dist/cjs/src/data/transformers/rally-event.js +12 -0
  6. package/dist/cjs/src/data/transformers/rally.js +2 -0
  7. package/dist/cjs/src/data/transformers/rally.test.d.ts +1 -0
  8. package/dist/cjs/src/data/transformers/rally.test.js +62 -0
  9. package/dist/cjs/src/data/transformers/tactics.js +26 -54
  10. package/dist/cjs/src/data/transformers/tactics.test.js +16 -11
  11. package/dist/cjs/src/service/competition/season.d.ts +2 -3
  12. package/dist/cjs/src/service/competition/season.js +0 -11
  13. package/dist/cjs/src/service/event/block.d.ts +0 -1
  14. package/dist/cjs/src/service/event/block.js +0 -6
  15. package/dist/cjs/src/service/event/free-ball.d.ts +0 -1
  16. package/dist/cjs/src/service/event/free-ball.js +0 -5
  17. package/dist/cjs/src/service/event/in-play-event.d.ts +0 -1
  18. package/dist/cjs/src/service/event/in-play-event.js +0 -8
  19. package/dist/cjs/src/service/event/libero-replacement.d.ts +0 -1
  20. package/dist/cjs/src/service/event/libero-replacement.js +0 -7
  21. package/dist/cjs/src/service/event/rally-event.d.ts +0 -1
  22. package/dist/cjs/src/service/event/reception.d.ts +0 -1
  23. package/dist/cjs/src/service/event/reception.js +0 -5
  24. package/dist/cjs/src/service/event/serve.d.ts +0 -1
  25. package/dist/cjs/src/service/event/serve.js +0 -5
  26. package/dist/cjs/src/service/event/set.d.ts +0 -1
  27. package/dist/cjs/src/service/event/set.js +0 -6
  28. package/dist/cjs/src/service/event/spike.d.ts +0 -1
  29. package/dist/cjs/src/service/event/spike.js +0 -5
  30. package/dist/cjs/src/service/event/substitution.d.ts +0 -1
  31. package/dist/cjs/src/service/event/substitution.js +0 -7
  32. package/dist/cjs/src/service/player/improvement.d.ts +0 -1
  33. package/dist/cjs/src/service/player/improvement.js +0 -9
  34. package/dist/cjs/src/service/player/improvement.test.js +0 -15
  35. package/dist/cjs/src/service/team/designated-sub.d.ts +2 -4
  36. package/dist/cjs/src/service/team/energy-band.d.ts +0 -1
  37. package/dist/cjs/src/service/team/energy-band.js +1 -2
  38. package/dist/cjs/src/service/team/formation.d.ts +0 -1
  39. package/dist/cjs/src/service/team/formation.js +0 -3
  40. package/dist/cjs/src/service/team/index.d.ts +1 -0
  41. package/dist/cjs/src/service/team/index.js +1 -0
  42. package/dist/cjs/src/service/team/libero-sub.d.ts +0 -4
  43. package/dist/cjs/src/service/team/pinch-condition.d.ts +11 -3
  44. package/dist/cjs/src/service/team/pinch-condition.js +9 -4
  45. package/dist/cjs/src/service/team/schemas/designated-sub.z.d.ts +30 -32
  46. package/dist/cjs/src/service/team/schemas/designated-sub.z.js +27 -23
  47. package/dist/cjs/src/service/team/schemas/designated-sub.z.test.js +4 -2
  48. package/dist/cjs/src/service/team/schemas/libero-sub.z.d.ts +15 -34
  49. package/dist/cjs/src/service/team/schemas/libero-sub.z.js +10 -26
  50. package/dist/cjs/src/service/team/schemas/libero-sub.z.test.js +74 -35
  51. package/dist/cjs/src/service/team/schemas/tactics.z.d.ts +28 -36
  52. package/dist/cjs/src/service/team/schemas/tactics.z.js +4 -3
  53. package/dist/cjs/src/service/team/schemas/team.z.d.ts +28 -36
  54. package/dist/cjs/src/service/team/sub-config-convert.d.ts +13 -0
  55. package/dist/cjs/src/service/team/sub-config-convert.js +91 -0
  56. package/dist/cjs/src/service/team/sub-config-convert.test.d.ts +1 -0
  57. package/dist/cjs/src/service/team/sub-config-convert.test.js +84 -0
  58. package/dist/cjs/src/service/utils/object-utils.d.ts +0 -1
  59. package/dist/cjs/src/service/utils/object-utils.js +0 -2
  60. package/dist/esm/src/api/index.d.ts +3 -17
  61. package/dist/esm/src/data/models/tactics.d.ts +7 -17
  62. package/dist/esm/src/data/transformers/match-preset-override.test.js +10 -1
  63. package/dist/esm/src/data/transformers/rally-event.d.ts +2 -1
  64. package/dist/esm/src/data/transformers/rally-event.js +12 -1
  65. package/dist/esm/src/data/transformers/rally.js +4 -2
  66. package/dist/esm/src/data/transformers/rally.test.d.ts +1 -0
  67. package/dist/esm/src/data/transformers/rally.test.js +60 -0
  68. package/dist/esm/src/data/transformers/tactics.js +27 -55
  69. package/dist/esm/src/data/transformers/tactics.test.js +16 -11
  70. package/dist/esm/src/service/competition/season.d.ts +2 -3
  71. package/dist/esm/src/service/competition/season.js +0 -11
  72. package/dist/esm/src/service/event/block.d.ts +0 -1
  73. package/dist/esm/src/service/event/block.js +0 -6
  74. package/dist/esm/src/service/event/free-ball.d.ts +0 -1
  75. package/dist/esm/src/service/event/free-ball.js +0 -5
  76. package/dist/esm/src/service/event/in-play-event.d.ts +0 -1
  77. package/dist/esm/src/service/event/in-play-event.js +0 -8
  78. package/dist/esm/src/service/event/libero-replacement.d.ts +0 -1
  79. package/dist/esm/src/service/event/libero-replacement.js +0 -7
  80. package/dist/esm/src/service/event/rally-event.d.ts +0 -1
  81. package/dist/esm/src/service/event/reception.d.ts +0 -1
  82. package/dist/esm/src/service/event/reception.js +0 -5
  83. package/dist/esm/src/service/event/serve.d.ts +0 -1
  84. package/dist/esm/src/service/event/serve.js +0 -5
  85. package/dist/esm/src/service/event/set.d.ts +0 -1
  86. package/dist/esm/src/service/event/set.js +0 -6
  87. package/dist/esm/src/service/event/spike.d.ts +0 -1
  88. package/dist/esm/src/service/event/spike.js +0 -5
  89. package/dist/esm/src/service/event/substitution.d.ts +0 -1
  90. package/dist/esm/src/service/event/substitution.js +0 -7
  91. package/dist/esm/src/service/player/improvement.d.ts +0 -1
  92. package/dist/esm/src/service/player/improvement.js +0 -8
  93. package/dist/esm/src/service/player/improvement.test.js +1 -16
  94. package/dist/esm/src/service/team/designated-sub.d.ts +2 -4
  95. package/dist/esm/src/service/team/energy-band.d.ts +0 -1
  96. package/dist/esm/src/service/team/energy-band.js +0 -1
  97. package/dist/esm/src/service/team/formation.d.ts +0 -1
  98. package/dist/esm/src/service/team/formation.js +0 -3
  99. package/dist/esm/src/service/team/index.d.ts +1 -0
  100. package/dist/esm/src/service/team/index.js +1 -0
  101. package/dist/esm/src/service/team/libero-sub.d.ts +0 -4
  102. package/dist/esm/src/service/team/pinch-condition.d.ts +11 -3
  103. package/dist/esm/src/service/team/pinch-condition.js +9 -4
  104. package/dist/esm/src/service/team/schemas/designated-sub.z.d.ts +30 -32
  105. package/dist/esm/src/service/team/schemas/designated-sub.z.js +26 -22
  106. package/dist/esm/src/service/team/schemas/designated-sub.z.test.js +4 -2
  107. package/dist/esm/src/service/team/schemas/libero-sub.z.d.ts +15 -34
  108. package/dist/esm/src/service/team/schemas/libero-sub.z.js +9 -25
  109. package/dist/esm/src/service/team/schemas/libero-sub.z.test.js +75 -36
  110. package/dist/esm/src/service/team/schemas/tactics.z.d.ts +28 -36
  111. package/dist/esm/src/service/team/schemas/tactics.z.js +4 -3
  112. package/dist/esm/src/service/team/schemas/team.z.d.ts +28 -36
  113. package/dist/esm/src/service/team/sub-config-convert.d.ts +13 -0
  114. package/dist/esm/src/service/team/sub-config-convert.js +85 -0
  115. package/dist/esm/src/service/team/sub-config-convert.test.d.ts +1 -0
  116. package/dist/esm/src/service/team/sub-config-convert.test.js +82 -0
  117. package/dist/esm/src/service/utils/object-utils.d.ts +0 -1
  118. package/dist/esm/src/service/utils/object-utils.js +1 -1
  119. package/package.json +1 -1
@@ -40,10 +40,5 @@ class Spike extends in_play_event_1.InPlayEvent {
40
40
  this.type = type;
41
41
  this.failure = failure;
42
42
  }
43
- toString() {
44
- const failure = `"failure":${this.failure}`;
45
- const type = `"type":${this.type}`;
46
- return `{${this._toString()},${failure},${type}}`;
47
- }
48
43
  }
49
44
  exports.Spike = Spike;
@@ -4,5 +4,4 @@ export declare class Substitution extends RallyEvent {
4
4
  readonly injury?: boolean;
5
5
  static create(input: unknown): Substitution;
6
6
  private constructor();
7
- toString(): string;
8
7
  }
@@ -22,12 +22,5 @@ class Substitution extends rally_event_1.RallyEvent {
22
22
  this.playerOut = playerOut;
23
23
  this.injury = injury;
24
24
  }
25
- toString() {
26
- const playerId = `"playerId":"${this.playerId}"`;
27
- const playerOut = `"playerOut":"${this.playerOut}"`;
28
- const eventType = `"eventType":${this.eventType}`;
29
- const injury = this.injury === true ? ',"injury":true' : '';
30
- return `{${playerId},${playerOut},${eventType}${injury}}`;
31
- }
32
25
  }
33
26
  exports.Substitution = Substitution;
@@ -3,7 +3,6 @@ import { Stats } from './stats';
3
3
  import { DeclineProfile } from './decline';
4
4
  export type TrainingFocus = Stats;
5
5
  export declare function getStatCap(rarity: Rarity): number;
6
- export declare function getRarityMultiplier(rarity: Rarity): number;
7
6
  export declare function getImprovementFloor(rarity: Rarity): number;
8
7
  export declare function getImprovementThreshold(statTotal: number, rarity: Rarity): number;
9
8
  export declare function getCoachMultiplier(rarity: Rarity): number;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getStatCap = getStatCap;
4
- exports.getRarityMultiplier = getRarityMultiplier;
5
4
  exports.getImprovementFloor = getImprovementFloor;
6
5
  exports.getImprovementThreshold = getImprovementThreshold;
7
6
  exports.getCoachMultiplier = getCoachMultiplier;
@@ -40,14 +39,6 @@ function getStatCap(rarity) {
40
39
  throw new Error(`UNKNOWN_RARITY: ${rarity}`);
41
40
  return entry.cap;
42
41
  }
43
- // Retained for config/reference. No longer used by the improvement curve -- superseded by IMPROVEMENT_FLOOR,
44
- // which is the per-rarity adjustment now.
45
- function getRarityMultiplier(rarity) {
46
- const entry = statCaps.find(e => e.rarity === rarity);
47
- if (entry == null)
48
- throw new Error(`UNKNOWN_RARITY: ${rarity}`);
49
- return entry.rarityMultiplier;
50
- }
51
42
  function getImprovementFloor(rarity) {
52
43
  const floor = IMPROVEMENT_FLOOR[rarity];
53
44
  if (floor == null)
@@ -20,21 +20,6 @@ const decline_1 = require("./decline");
20
20
  (0, globals_1.expect)(() => (0, improvement_1.getStatCap)('DIVINE')).toThrow('UNKNOWN_RARITY');
21
21
  });
22
22
  });
23
- // ─── getRarityMultiplier ──────────────────────────────────────────────────────
24
- (0, globals_1.describe)('getRarityMultiplier()', () => {
25
- globals_1.it.each([
26
- [rarity_1.RarityEnum.COMMON, 1.0],
27
- [rarity_1.RarityEnum.RARE, 1.15],
28
- [rarity_1.RarityEnum.LEGENDARY, 1.3],
29
- [rarity_1.RarityEnum.MYTHIC, 1.5],
30
- [rarity_1.RarityEnum.SPECIAL, 1.75]
31
- ])('%s → multiplier %f', (rarity, expected) => {
32
- (0, globals_1.expect)((0, improvement_1.getRarityMultiplier)(rarity)).toBeCloseTo(expected, 5);
33
- });
34
- (0, globals_1.it)('throws UNKNOWN_RARITY for an unrecognised rarity string', () => {
35
- (0, globals_1.expect)(() => (0, improvement_1.getRarityMultiplier)('DIVINE')).toThrow('UNKNOWN_RARITY');
36
- });
37
- });
38
23
  // ─── getImprovementThreshold ──────────────────────────────────────────────────
39
24
  (0, globals_1.describe)('getImprovementThreshold()', () => {
40
25
  (0, globals_1.it)('at or below the floor the threshold is CURVE_BASE (180) — the fastest pace', () => {
@@ -1,15 +1,13 @@
1
1
  import { Player } from '../player';
2
- import { EnergyBand, SubMode } from './energy-band';
2
+ import { EnergyBand } from './energy-band';
3
3
  import { ConditionLogic, PinchCondition } from './pinch-condition';
4
4
  export type SubBackMode = 'FATIGUE' | 'CONDITIONS';
5
5
  export interface SetSubConfig {
6
- readonly mode: SubMode;
7
6
  readonly bench?: Player;
8
- readonly fatigueBand?: EnergyBand;
9
- readonly benchFatigueBand?: EnergyBand;
10
7
  readonly conditions?: PinchCondition[];
11
8
  readonly conditionLogic?: ConditionLogic;
12
9
  readonly pinchServer?: boolean;
10
+ readonly benchFatigueBand?: EnergyBand;
13
11
  readonly subBackMode?: SubBackMode;
14
12
  readonly subBackConditions?: PinchCondition[];
15
13
  readonly subBackConditionLogic?: ConditionLogic;
@@ -6,5 +6,4 @@ export declare enum EnergyBand {
6
6
  }
7
7
  export type SubBand = EnergyBand | 'NEVER';
8
8
  export type SubMode = 'FATIGUE' | 'PINCH' | 'NEVER';
9
- export declare const SUB_MODES: readonly SubMode[];
10
9
  export declare const ENERGY_BAND_ORDER: readonly EnergyBand[];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ENERGY_BAND_ORDER = exports.SUB_MODES = exports.EnergyBand = void 0;
3
+ exports.ENERGY_BAND_ORDER = exports.EnergyBand = void 0;
4
4
  // The named fatigue bands a player's energy falls into. The numeric cutoffs and per-band performance
5
5
  // multipliers live in the simulator (VolleyballSim court-player.ts ENERGY_BANDS); this enum is the shared
6
6
  // vocabulary used by tactics configuration (substitution thresholds) and, later, the UI.
@@ -11,7 +11,6 @@ var EnergyBand;
11
11
  EnergyBand["TIRED"] = "TIRED";
12
12
  EnergyBand["EXHAUSTED"] = "EXHAUSTED";
13
13
  })(EnergyBand || (exports.EnergyBand = EnergyBand = {}));
14
- exports.SUB_MODES = ['FATIGUE', 'PINCH', 'NEVER'];
15
14
  // Ordered best -> worst. Used to compare "is this player at-or-below the configured sub band".
16
15
  exports.ENERGY_BAND_ORDER = [
17
16
  EnergyBand.ENERGETIC,
@@ -25,6 +25,5 @@ export declare class Formation {
25
25
  readonly liberoSubPriority: SubPriority;
26
26
  static create(input: unknown): Formation;
27
27
  private constructor();
28
- static getFormations(): Formation[];
29
28
  }
30
29
  export {};
@@ -23,9 +23,6 @@ class Formation {
23
23
  this.base = base;
24
24
  this.liberoSubPriority = liberoSubPriority;
25
25
  }
26
- static getFormations() {
27
- return [this['4-2'], this['5-1'], this['6-2']];
28
- }
29
26
  }
30
27
  exports.Formation = Formation;
31
28
  Formation['5-1'] = Formation.create({
@@ -7,6 +7,7 @@ export * from './energy-band';
7
7
  export * from './pinch-condition';
8
8
  export * from './designated-sub';
9
9
  export * from './libero-sub';
10
+ export * from './sub-config-convert';
10
11
  export * from './rotation-system';
11
12
  export * from './lineup-function';
12
13
  export * from './base-position';
@@ -23,6 +23,7 @@ __exportStar(require("./energy-band"), exports);
23
23
  __exportStar(require("./pinch-condition"), exports);
24
24
  __exportStar(require("./designated-sub"), exports);
25
25
  __exportStar(require("./libero-sub"), exports);
26
+ __exportStar(require("./sub-config-convert"), exports);
26
27
  __exportStar(require("./rotation-system"), exports);
27
28
  __exportStar(require("./lineup-function"), exports);
28
29
  __exportStar(require("./base-position"), exports);
@@ -1,9 +1,5 @@
1
- import { EnergyBand } from './energy-band';
2
1
  import { ConditionLogic, PinchCondition } from './pinch-condition';
3
- export type LiberoSubMode = 'NEVER' | 'FATIGUE' | 'ALWAYS' | 'CONDITIONS';
4
2
  export interface LiberoSetSubConfig {
5
- readonly mode: LiberoSubMode;
6
- readonly fatigueBand?: EnergyBand;
7
3
  readonly conditions?: PinchCondition[];
8
4
  readonly conditionLogic?: ConditionLogic;
9
5
  }
@@ -1,5 +1,6 @@
1
+ import { EnergyBand, SubBand } from './energy-band';
1
2
  export declare enum PinchConditionType {
2
- ASAP = "ASAP",// every time the linked starter wins back the serve
3
+ ASAP = "ASAP",// unconditionally true (pinch server: every serve gain; libero rule: "Always")
3
4
  TEAM_SET_POINT = "TEAM_SET_POINT",// team within `margin` of winning the set
4
5
  OPPONENT_SET_POINT = "OPPONENT_SET_POINT",// opponent within `margin` of winning the set
5
6
  SCORE_DIFF = "SCORE_DIFF",// team trailing/leading by at least `points`
@@ -7,7 +8,8 @@ export declare enum PinchConditionType {
7
8
  FROM_SET = "FROM_SET",// only set N or later
8
9
  MIN_OWN_SCORE = "MIN_OWN_SCORE",// only once own score >= N
9
10
  MIN_OPPONENT_SCORE = "MIN_OPPONENT_SCORE",// only once opponent score >= N
10
- PHASE = "PHASE"
11
+ PHASE = "PHASE",// the team is serving or receiving this rally (used by the libero deployment rule)
12
+ FATIGUE = "FATIGUE"
11
13
  }
12
14
  export declare enum MatchPhase {
13
15
  SERVING = "SERVING",
@@ -66,7 +68,11 @@ export interface PhaseCondition {
66
68
  readonly type: PinchConditionType.PHASE;
67
69
  readonly phase: MatchPhase;
68
70
  }
69
- export type PinchCondition = AsapCondition | TeamSetPointCondition | OpponentSetPointCondition | ScoreDiffCondition | AfterRotationsCondition | FromSetCondition | MinOwnScoreCondition | MinOpponentScoreCondition | PhaseCondition;
71
+ export interface FatigueCondition {
72
+ readonly type: PinchConditionType.FATIGUE;
73
+ readonly band?: EnergyBand;
74
+ }
75
+ export type PinchCondition = AsapCondition | TeamSetPointCondition | OpponentSetPointCondition | ScoreDiffCondition | AfterRotationsCondition | FromSetCondition | MinOwnScoreCondition | MinOpponentScoreCondition | PhaseCondition | FatigueCondition;
70
76
  export type ConditionLogic = 'ALL' | 'ANY';
71
77
  export interface PinchSetState {
72
78
  readonly ownScore: number;
@@ -75,4 +81,6 @@ export interface PinchSetState {
75
81
  readonly setNumber: number;
76
82
  readonly ownServeTurns: number;
77
83
  readonly phase: MatchPhase;
84
+ readonly subjectBand?: EnergyBand;
85
+ readonly defaultBand?: SubBand;
78
86
  }
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
- // Conditions that gate when a pinch server is forced in to serve (in for its linked starter when the team
3
- // wins back the serve, out the moment the serve is lost). Each condition is evaluated against the live set
4
- // state; a pinch entry combines them with ALL (every condition must hold) or ANY (one is enough).
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.Comparison = exports.ScoreDirection = exports.OpponentRelation = exports.MatchPhase = exports.PinchConditionType = void 0;
4
+ // The ONE condition vocabulary of the substitution engine (owner 2026-07-11): designated substitutions,
5
+ // pinch servers, sub-backs, and the libero deployment rule all evaluate the same catalog against the live
6
+ // set state, combined with ALL (every condition must hold) or ANY (one is enough). A config with NO
7
+ // conditions never fires.
7
8
  var PinchConditionType;
8
9
  (function (PinchConditionType) {
9
10
  PinchConditionType["ASAP"] = "ASAP";
@@ -14,7 +15,11 @@ var PinchConditionType;
14
15
  PinchConditionType["FROM_SET"] = "FROM_SET";
15
16
  PinchConditionType["MIN_OWN_SCORE"] = "MIN_OWN_SCORE";
16
17
  PinchConditionType["MIN_OPPONENT_SCORE"] = "MIN_OPPONENT_SCORE";
17
- PinchConditionType["PHASE"] = "PHASE"; // the team is serving or receiving this rally (used by the libero deployment rule)
18
+ PinchConditionType["PHASE"] = "PHASE";
19
+ // The SUBJECT player's energy is at-or-worse than `band` (absent band = the team `substitutionBand`). The
20
+ // subject comes from the evaluation context, never from the condition: sub-in conditions judge the STARTER
21
+ // on court, sub-back conditions judge the SUBSTITUTE on court, the libero rule judges the STARTING libero.
22
+ PinchConditionType["FATIGUE"] = "FATIGUE";
18
23
  })(PinchConditionType || (exports.PinchConditionType = PinchConditionType = {}));
19
24
  // Which side of the rally the team is on. Known at each dead ball: the serving team is SERVING, the other
20
25
  // RECEIVING. Consumed by the PHASE condition (libero deployment); pinch servers always evaluate while SERVING.
@@ -34,26 +34,17 @@ export declare const PinchConditionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
34
34
  }, z.core.$strip>, z.ZodObject<{
35
35
  type: z.ZodLiteral<PinchConditionType.PHASE>;
36
36
  phase: z.ZodEnum<typeof MatchPhase>;
37
+ }, z.core.$strip>, z.ZodObject<{
38
+ type: z.ZodLiteral<PinchConditionType.FATIGUE>;
39
+ band: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
37
40
  }, z.core.$strip>], "type">;
38
41
  export declare const ConditionLogicSchema: z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>;
39
- export declare const SubModeSchema: z.ZodEnum<{
40
- NEVER: "NEVER";
41
- FATIGUE: "FATIGUE";
42
- PINCH: "PINCH";
43
- }>;
44
42
  export declare const SubBackModeSchema: z.ZodEnum<{
45
43
  FATIGUE: "FATIGUE";
46
44
  CONDITIONS: "CONDITIONS";
47
45
  }>;
48
- export declare const SetSubConfigSchema: z.ZodObject<{
49
- mode: z.ZodEnum<{
50
- NEVER: "NEVER";
51
- FATIGUE: "FATIGUE";
52
- PINCH: "PINCH";
53
- }>;
46
+ export declare const SetSubConfigSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
54
47
  bench: z.ZodOptional<z.ZodCustom<Player, Player>>;
55
- fatigueBand: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
56
- benchFatigueBand: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
57
48
  conditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
58
49
  type: z.ZodLiteral<PinchConditionType.ASAP>;
59
50
  }, z.core.$strip>, z.ZodObject<{
@@ -85,9 +76,13 @@ export declare const SetSubConfigSchema: z.ZodObject<{
85
76
  }, z.core.$strip>, z.ZodObject<{
86
77
  type: z.ZodLiteral<PinchConditionType.PHASE>;
87
78
  phase: z.ZodEnum<typeof MatchPhase>;
79
+ }, z.core.$strip>, z.ZodObject<{
80
+ type: z.ZodLiteral<PinchConditionType.FATIGUE>;
81
+ band: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
88
82
  }, z.core.$strip>], "type">>>;
89
83
  conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
90
84
  pinchServer: z.ZodOptional<z.ZodBoolean>;
85
+ benchFatigueBand: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
91
86
  subBackMode: z.ZodOptional<z.ZodEnum<{
92
87
  FATIGUE: "FATIGUE";
93
88
  CONDITIONS: "CONDITIONS";
@@ -123,19 +118,15 @@ export declare const SetSubConfigSchema: z.ZodObject<{
123
118
  }, z.core.$strip>, z.ZodObject<{
124
119
  type: z.ZodLiteral<PinchConditionType.PHASE>;
125
120
  phase: z.ZodEnum<typeof MatchPhase>;
121
+ }, z.core.$strip>, z.ZodObject<{
122
+ type: z.ZodLiteral<PinchConditionType.FATIGUE>;
123
+ band: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
126
124
  }, z.core.$strip>], "type">>>;
127
125
  subBackConditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
128
- }, z.core.$strip>;
129
- export declare const DesignatedSubSchema: z.ZodObject<{
130
- sets: z.ZodOptional<z.ZodArray<z.ZodObject<{
131
- mode: z.ZodEnum<{
132
- NEVER: "NEVER";
133
- FATIGUE: "FATIGUE";
134
- PINCH: "PINCH";
135
- }>;
126
+ }, z.core.$strip>>;
127
+ export declare const DesignatedSubSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
128
+ sets: z.ZodOptional<z.ZodArray<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
136
129
  bench: z.ZodOptional<z.ZodCustom<Player, Player>>;
137
- fatigueBand: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
138
- benchFatigueBand: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
139
130
  conditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
140
131
  type: z.ZodLiteral<PinchConditionType.ASAP>;
141
132
  }, z.core.$strip>, z.ZodObject<{
@@ -167,9 +158,13 @@ export declare const DesignatedSubSchema: z.ZodObject<{
167
158
  }, z.core.$strip>, z.ZodObject<{
168
159
  type: z.ZodLiteral<PinchConditionType.PHASE>;
169
160
  phase: z.ZodEnum<typeof MatchPhase>;
161
+ }, z.core.$strip>, z.ZodObject<{
162
+ type: z.ZodLiteral<PinchConditionType.FATIGUE>;
163
+ band: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
170
164
  }, z.core.$strip>], "type">>>;
171
165
  conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
172
166
  pinchServer: z.ZodOptional<z.ZodBoolean>;
167
+ benchFatigueBand: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
173
168
  subBackMode: z.ZodOptional<z.ZodEnum<{
174
169
  FATIGUE: "FATIGUE";
175
170
  CONDITIONS: "CONDITIONS";
@@ -205,17 +200,13 @@ export declare const DesignatedSubSchema: z.ZodObject<{
205
200
  }, z.core.$strip>, z.ZodObject<{
206
201
  type: z.ZodLiteral<PinchConditionType.PHASE>;
207
202
  phase: z.ZodEnum<typeof MatchPhase>;
203
+ }, z.core.$strip>, z.ZodObject<{
204
+ type: z.ZodLiteral<PinchConditionType.FATIGUE>;
205
+ band: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
208
206
  }, z.core.$strip>], "type">>>;
209
207
  subBackConditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
210
- }, z.core.$strip>>>;
211
- mode: z.ZodEnum<{
212
- NEVER: "NEVER";
213
- FATIGUE: "FATIGUE";
214
- PINCH: "PINCH";
215
- }>;
208
+ }, z.core.$strip>>>>;
216
209
  bench: z.ZodOptional<z.ZodCustom<Player, Player>>;
217
- fatigueBand: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
218
- benchFatigueBand: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
219
210
  conditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
220
211
  type: z.ZodLiteral<PinchConditionType.ASAP>;
221
212
  }, z.core.$strip>, z.ZodObject<{
@@ -247,9 +238,13 @@ export declare const DesignatedSubSchema: z.ZodObject<{
247
238
  }, z.core.$strip>, z.ZodObject<{
248
239
  type: z.ZodLiteral<PinchConditionType.PHASE>;
249
240
  phase: z.ZodEnum<typeof MatchPhase>;
241
+ }, z.core.$strip>, z.ZodObject<{
242
+ type: z.ZodLiteral<PinchConditionType.FATIGUE>;
243
+ band: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
250
244
  }, z.core.$strip>], "type">>>;
251
245
  conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
252
246
  pinchServer: z.ZodOptional<z.ZodBoolean>;
247
+ benchFatigueBand: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
253
248
  subBackMode: z.ZodOptional<z.ZodEnum<{
254
249
  FATIGUE: "FATIGUE";
255
250
  CONDITIONS: "CONDITIONS";
@@ -285,7 +280,10 @@ export declare const DesignatedSubSchema: z.ZodObject<{
285
280
  }, z.core.$strip>, z.ZodObject<{
286
281
  type: z.ZodLiteral<PinchConditionType.PHASE>;
287
282
  phase: z.ZodEnum<typeof MatchPhase>;
283
+ }, z.core.$strip>, z.ZodObject<{
284
+ type: z.ZodLiteral<PinchConditionType.FATIGUE>;
285
+ band: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
288
286
  }, z.core.$strip>], "type">>>;
289
287
  subBackConditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
290
288
  starter: z.ZodCustom<Player, Player>;
291
- }, z.core.$strip>;
289
+ }, z.core.$strip>>;
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DesignatedSubSchema = exports.SetSubConfigSchema = exports.SubBackModeSchema = exports.SubModeSchema = exports.ConditionLogicSchema = exports.PinchConditionSchema = exports.SubBandSchema = void 0;
3
+ exports.DesignatedSubSchema = exports.SetSubConfigSchema = exports.SubBackModeSchema = exports.ConditionLogicSchema = exports.PinchConditionSchema = exports.SubBandSchema = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const player_1 = require("../../player");
6
6
  const energy_band_1 = require("../energy-band");
7
7
  const pinch_condition_1 = require("../pinch-condition");
8
+ const sub_config_convert_1 = require("../sub-config-convert");
8
9
  const playerInstanceSchema = zod_1.z.custom((v) => v instanceof player_1.Player, {
9
10
  message: 'INVALID_PLAYER_INSTANCE'
10
11
  });
@@ -21,44 +22,47 @@ exports.PinchConditionSchema = zod_1.z.discriminatedUnion('type', [
21
22
  zod_1.z.object({ type: zod_1.z.literal(pinch_condition_1.PinchConditionType.MIN_OWN_SCORE), score: zod_1.z.number().int().min(0).max(40), comparison: zod_1.z.nativeEnum(pinch_condition_1.Comparison).optional() }),
22
23
  zod_1.z.object({ type: zod_1.z.literal(pinch_condition_1.PinchConditionType.MIN_OPPONENT_SCORE), score: zod_1.z.number().int().min(0).max(40), comparison: zod_1.z.nativeEnum(pinch_condition_1.Comparison).optional() }),
23
24
  // PHASE is used by the libero deployment rule (which reuses this schema); pinch servers never offer it.
24
- zod_1.z.object({ type: zod_1.z.literal(pinch_condition_1.PinchConditionType.PHASE), phase: zod_1.z.nativeEnum(pinch_condition_1.MatchPhase) })
25
+ zod_1.z.object({ type: zod_1.z.literal(pinch_condition_1.PinchConditionType.PHASE), phase: zod_1.z.nativeEnum(pinch_condition_1.MatchPhase) }),
26
+ // The subject player's energy is at-or-worse than `band` (absent = the team `substitutionBand`); the
27
+ // subject comes from the evaluation context (starter / substitute / starting libero).
28
+ zod_1.z.object({ type: zod_1.z.literal(pinch_condition_1.PinchConditionType.FATIGUE), band: zod_1.z.nativeEnum(energy_band_1.EnergyBand).optional() })
25
29
  ]);
26
30
  exports.ConditionLogicSchema = zod_1.z.union([zod_1.z.literal('ALL'), zod_1.z.literal('ANY')]);
27
- exports.SubModeSchema = zod_1.z.enum(['FATIGUE', 'PINCH', 'NEVER']);
28
31
  exports.SubBackModeSchema = zod_1.z.enum(['FATIGUE', 'CONDITIONS']);
29
- // Fields shared by the all-sets config and each per-set config.
32
+ // Fields shared by the all-sets config and each per-set config. Pure condition engine (owner 2026-07-11):
33
+ // no mode; `conditions` is the sub-in trigger and an EMPTY/absent list means the starter is never substituted
34
+ // by this rule. Legacy mode-shaped inputs are auto-converted by the preprocess below.
30
35
  const setSubConfigShape = {
31
- mode: exports.SubModeSchema,
32
36
  bench: playerInstanceSchema.optional(),
33
- fatigueBand: zod_1.z.nativeEnum(energy_band_1.EnergyBand).optional(),
34
- benchFatigueBand: zod_1.z.nativeEnum(energy_band_1.EnergyBand).optional(),
35
37
  conditions: zod_1.z.array(exports.PinchConditionSchema).optional(),
36
38
  conditionLogic: exports.ConditionLogicSchema.optional(),
37
- // pinch ("Conditions") mode. true = serve-and-return pinch server; false/absent = regular conditional sub.
39
+ // true = serve-and-return pinch server; false/absent = regular conditional sub (stays until sub-back).
38
40
  pinchServer: zod_1.z.boolean().optional(),
39
- // a regular conditional sub's sub-back trigger + its condition set (subBackMode === 'CONDITIONS').
41
+ // The substitute's own pull band for FATIGUE sub-backs (absent = the team `substitutionBand`).
42
+ benchFatigueBand: zod_1.z.nativeEnum(energy_band_1.EnergyBand).optional(),
40
43
  subBackMode: exports.SubBackModeSchema.optional(),
41
44
  subBackConditions: zod_1.z.array(exports.PinchConditionSchema).optional(),
42
45
  subBackConditionLogic: exports.ConditionLogicSchema.optional()
43
46
  };
44
- // Pinch ("Conditions") mode needs a designated bench player and at least one sub-in condition. A regular
45
- // conditional sub (pinchServer !== true) with a CONDITIONS sub-back also needs at least one sub-back condition.
46
- function refinePinch(data, ctx) {
47
- if (data.mode !== 'PINCH')
48
- return;
49
- if (data.bench == null) {
50
- ctx.addIssue({ code: 'custom', message: 'PINCH_SERVER_REQUIRES_BENCH', path: ['bench'] });
51
- }
52
- if (data.conditions == null || data.conditions.length === 0) {
53
- ctx.addIssue({ code: 'custom', message: 'PINCH_SERVER_REQUIRES_CONDITIONS', path: ['conditions'] });
47
+ // A pinch server needs a designated bench player and at least one sub-in condition. A regular conditional sub
48
+ // with a CONDITIONS sub-back needs at least one sub-back condition. Empty sub-in conditions are otherwise
49
+ // VALID (= never fires).
50
+ function refineSubConfig(data, ctx) {
51
+ if (data.pinchServer === true) {
52
+ if (data.bench == null) {
53
+ ctx.addIssue({ code: 'custom', message: 'PINCH_SERVER_REQUIRES_BENCH', path: ['bench'] });
54
+ }
55
+ if (data.conditions == null || data.conditions.length === 0) {
56
+ ctx.addIssue({ code: 'custom', message: 'PINCH_SERVER_REQUIRES_CONDITIONS', path: ['conditions'] });
57
+ }
54
58
  }
55
59
  if (data.pinchServer !== true && data.subBackMode === 'CONDITIONS' &&
56
60
  (data.subBackConditions == null || data.subBackConditions.length === 0)) {
57
61
  ctx.addIssue({ code: 'custom', message: 'CONDITIONAL_SUB_BACK_REQUIRES_CONDITIONS', path: ['subBackConditions'] });
58
62
  }
59
63
  }
60
- exports.SetSubConfigSchema = zod_1.z.object(setSubConfigShape).superRefine(refinePinch);
61
- exports.DesignatedSubSchema = zod_1.z.object({
64
+ exports.SetSubConfigSchema = zod_1.z.preprocess(sub_config_convert_1.convertLegacySetSubConfig, zod_1.z.object(setSubConfigShape).superRefine(refineSubConfig));
65
+ exports.DesignatedSubSchema = zod_1.z.preprocess(sub_config_convert_1.convertLegacyDesignatedSub, zod_1.z.object({
62
66
  starter: playerInstanceSchema,
63
67
  ...setSubConfigShape,
64
68
  // Optional per-set overrides (index 0 = set 1 ... index 4 = set 5); absent => the flat config for all sets.
@@ -67,5 +71,5 @@ exports.DesignatedSubSchema = zod_1.z.object({
67
71
  // The flat config is the fallback for any set a partial `sets` array doesn't cover, so validate it whenever
68
72
  // `sets` is absent or covers fewer than 5 sets (each present per-set config is validated by SetSubConfigSchema).
69
73
  if (data.sets == null || data.sets.length < 5)
70
- refinePinch(data, ctx);
71
- });
74
+ refineSubConfig(data, ctx);
75
+ }));
@@ -116,12 +116,14 @@ const test_helpers_1 = require("../../test-helpers");
116
116
  });
117
117
  (0, globals_1.expect)(res.success).toBe(true);
118
118
  });
119
- (0, globals_1.it)('rejects an unknown mode', () => {
119
+ (0, globals_1.it)('heals an unknown legacy mode by stripping it (lenient conversion, config stays valid)', () => {
120
120
  const res = designated_sub_z_1.DesignatedSubSchema.safeParse({
121
121
  starter,
122
122
  mode: 'SOMETIMES'
123
123
  });
124
- (0, globals_1.expect)(res.success).toBe(false);
124
+ (0, globals_1.expect)(res.success).toBe(true);
125
+ if (res.success)
126
+ (0, globals_1.expect)(res.data.mode).toBeUndefined();
125
127
  });
126
128
  (0, globals_1.it)('accepts a pinch-mode entry with a bench server and conditions', () => {
127
129
  const res = designated_sub_z_1.DesignatedSubSchema.safeParse({
@@ -1,19 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { EnergyBand } from '../energy-band';
3
- export declare const LiberoSubModeSchema: z.ZodEnum<{
4
- NEVER: "NEVER";
5
- FATIGUE: "FATIGUE";
6
- CONDITIONS: "CONDITIONS";
7
- ALWAYS: "ALWAYS";
8
- }>;
9
- export declare const LiberoSetSubConfigSchema: z.ZodObject<{
10
- mode: z.ZodEnum<{
11
- NEVER: "NEVER";
12
- FATIGUE: "FATIGUE";
13
- CONDITIONS: "CONDITIONS";
14
- ALWAYS: "ALWAYS";
15
- }>;
16
- fatigueBand: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
2
+ export declare const LiberoSetSubConfigSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
17
3
  conditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
18
4
  type: z.ZodLiteral<import("..").PinchConditionType.ASAP>;
19
5
  }, z.core.$strip>, z.ZodObject<{
@@ -45,18 +31,14 @@ export declare const LiberoSetSubConfigSchema: z.ZodObject<{
45
31
  }, z.core.$strip>, z.ZodObject<{
46
32
  type: z.ZodLiteral<import("..").PinchConditionType.PHASE>;
47
33
  phase: z.ZodEnum<typeof import("..").MatchPhase>;
34
+ }, z.core.$strip>, z.ZodObject<{
35
+ type: z.ZodLiteral<import("..").PinchConditionType.FATIGUE>;
36
+ band: z.ZodOptional<z.ZodEnum<typeof import("..").EnergyBand>>;
48
37
  }, z.core.$strip>], "type">>>;
49
38
  conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
50
- }, z.core.$strip>;
51
- export declare const LiberoSubConfigSchema: z.ZodObject<{
52
- sets: z.ZodOptional<z.ZodArray<z.ZodObject<{
53
- mode: z.ZodEnum<{
54
- NEVER: "NEVER";
55
- FATIGUE: "FATIGUE";
56
- CONDITIONS: "CONDITIONS";
57
- ALWAYS: "ALWAYS";
58
- }>;
59
- fatigueBand: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
39
+ }, z.core.$strip>>;
40
+ export declare const LiberoSubConfigSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
41
+ sets: z.ZodOptional<z.ZodArray<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
60
42
  conditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
61
43
  type: z.ZodLiteral<import("..").PinchConditionType.ASAP>;
62
44
  }, z.core.$strip>, z.ZodObject<{
@@ -88,16 +70,12 @@ export declare const LiberoSubConfigSchema: z.ZodObject<{
88
70
  }, z.core.$strip>, z.ZodObject<{
89
71
  type: z.ZodLiteral<import("..").PinchConditionType.PHASE>;
90
72
  phase: z.ZodEnum<typeof import("..").MatchPhase>;
73
+ }, z.core.$strip>, z.ZodObject<{
74
+ type: z.ZodLiteral<import("..").PinchConditionType.FATIGUE>;
75
+ band: z.ZodOptional<z.ZodEnum<typeof import("..").EnergyBand>>;
91
76
  }, z.core.$strip>], "type">>>;
92
77
  conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
93
- }, z.core.$strip>>>;
94
- mode: z.ZodEnum<{
95
- NEVER: "NEVER";
96
- FATIGUE: "FATIGUE";
97
- CONDITIONS: "CONDITIONS";
98
- ALWAYS: "ALWAYS";
99
- }>;
100
- fatigueBand: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
78
+ }, z.core.$strip>>>>;
101
79
  conditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
102
80
  type: z.ZodLiteral<import("..").PinchConditionType.ASAP>;
103
81
  }, z.core.$strip>, z.ZodObject<{
@@ -129,6 +107,9 @@ export declare const LiberoSubConfigSchema: z.ZodObject<{
129
107
  }, z.core.$strip>, z.ZodObject<{
130
108
  type: z.ZodLiteral<import("..").PinchConditionType.PHASE>;
131
109
  phase: z.ZodEnum<typeof import("..").MatchPhase>;
110
+ }, z.core.$strip>, z.ZodObject<{
111
+ type: z.ZodLiteral<import("..").PinchConditionType.FATIGUE>;
112
+ band: z.ZodOptional<z.ZodEnum<typeof import("..").EnergyBand>>;
132
113
  }, z.core.$strip>], "type">>>;
133
114
  conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
134
- }, z.core.$strip>;
115
+ }, z.core.$strip>>;
@@ -1,37 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LiberoSubConfigSchema = exports.LiberoSetSubConfigSchema = exports.LiberoSubModeSchema = void 0;
3
+ exports.LiberoSubConfigSchema = exports.LiberoSetSubConfigSchema = void 0;
4
4
  const zod_1 = require("zod");
5
- const energy_band_1 = require("../energy-band");
5
+ const sub_config_convert_1 = require("../sub-config-convert");
6
6
  const designated_sub_z_1 = require("./designated-sub.z");
7
- exports.LiberoSubModeSchema = zod_1.z.enum(['NEVER', 'FATIGUE', 'ALWAYS', 'CONDITIONS']);
8
- // Fields shared by the all-sets config and each per-set config. The swapped-in player is always the dedicated
9
- // `secondLibero`, so there is no bench to validate; the CONDITIONS mode reuses the pinch-server condition
10
- // catalog (PinchConditionSchema, which includes the libero-only PHASE condition) + ALL/ANY logic.
7
+ // Pure condition engine (owner 2026-07-11): the second libero is active while `conditions` hold (combined
8
+ // per `conditionLogic`, default ALL; the STARTING libero is the FATIGUE-condition subject). No conditions =
9
+ // the starting libero always plays; [{ASAP}] = always the second libero (the old ALWAYS). The swapped-in
10
+ // player is always the dedicated `secondLibero`, so there is no bench to validate. Legacy mode-shaped
11
+ // configs (NEVER/FATIGUE/ALWAYS/CONDITIONS) are auto-converted by the preprocess.
11
12
  const liberoSetSubConfigShape = {
12
- mode: exports.LiberoSubModeSchema,
13
- // fatigue mode only (absent => the team default `substitutionBand`):
14
- fatigueBand: zod_1.z.nativeEnum(energy_band_1.EnergyBand).optional(),
15
- // conditions mode only:
16
13
  conditions: zod_1.z.array(designated_sub_z_1.PinchConditionSchema).optional(),
17
14
  conditionLogic: designated_sub_z_1.ConditionLogicSchema.optional()
18
15
  };
19
- // CONDITIONS mode needs at least one condition (mirrors the designated-sub pinch refine).
20
- function refineConditions(data, ctx) {
21
- if (data.mode !== 'CONDITIONS')
22
- return;
23
- if (data.conditions == null || data.conditions.length === 0) {
24
- ctx.addIssue({ code: 'custom', message: 'LIBERO_CONDITIONS_REQUIRE_A_CONDITION', path: ['conditions'] });
25
- }
26
- }
27
- exports.LiberoSetSubConfigSchema = zod_1.z.object(liberoSetSubConfigShape).superRefine(refineConditions);
28
- exports.LiberoSubConfigSchema = zod_1.z.object({
16
+ exports.LiberoSetSubConfigSchema = zod_1.z.preprocess(sub_config_convert_1.convertLegacyLiberoSetSubConfig, zod_1.z.object(liberoSetSubConfigShape));
17
+ exports.LiberoSubConfigSchema = zod_1.z.preprocess(sub_config_convert_1.convertLegacyLiberoSubConfig, zod_1.z.object({
29
18
  ...liberoSetSubConfigShape,
30
19
  // Optional per-set overrides (index 0 = set 1 ... index 4 = set 5); absent => the flat config for all sets.
31
20
  sets: zod_1.z.array(exports.LiberoSetSubConfigSchema).max(5).optional()
32
- }).superRefine((data, ctx) => {
33
- // The flat config is the fallback for any set a partial `sets` array doesn't cover, so validate it whenever
34
- // `sets` is absent or covers fewer than 5 sets (each present per-set config is validated by its own schema).
35
- if (data.sets == null || data.sets.length < 5)
36
- refineConditions(data, ctx);
37
- });
21
+ }));