@my-swu/simulator-client 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/README.md +29 -0
  2. package/dist/client.js +6 -1
  3. package/dist/connection/url.d.ts +2 -0
  4. package/dist/connection/url.js +4 -0
  5. package/dist/generated/index.d.ts +4 -0
  6. package/dist/generated/schemas.d.ts +1 -1
  7. package/dist/generated/schemas.js +2412 -1434
  8. package/dist/generated/types/admin-match-debug-bundle.d.ts +1 -1
  9. package/dist/generated/types/admin-match-list-response.d.ts +1 -1
  10. package/dist/generated/types/admin-match-replay-response.d.ts +1 -1
  11. package/dist/generated/types/client-message.d.ts +1 -1
  12. package/dist/generated/types/common.d.ts +524 -260
  13. package/dist/generated/types/create-limited-event-request.d.ts +1 -1
  14. package/dist/generated/types/format-event-response.d.ts +1 -1
  15. package/dist/generated/types/game-command.d.ts +1 -1
  16. package/dist/generated/types/game-event.d.ts +1 -1
  17. package/dist/generated/types/game-state.d.ts +1 -1
  18. package/dist/generated/types/get-match-response.d.ts +1 -1
  19. package/dist/generated/types/leave-limited-event-request.d.ts +1 -0
  20. package/dist/generated/types/leave-limited-event-request.js +2 -0
  21. package/dist/generated/types/limited-event-server-message.d.ts +1 -0
  22. package/dist/generated/types/limited-event-server-message.js +2 -0
  23. package/dist/generated/types/list-active-ai-matches-response.d.ts +1 -1
  24. package/dist/generated/types/lobby-access-response.d.ts +1 -1
  25. package/dist/generated/types/lobby-chat-response.d.ts +1 -1
  26. package/dist/generated/types/lobby-response.d.ts +1 -1
  27. package/dist/generated/types/lobby-server-message.d.ts +1 -1
  28. package/dist/generated/types/match-access-recovery-response.d.ts +1 -1
  29. package/dist/generated/types/match-access-response.d.ts +1 -1
  30. package/dist/generated/types/match-history-replay-response.d.ts +1 -1
  31. package/dist/generated/types/match-recovery-response.d.ts +1 -1
  32. package/dist/generated/types/match-spectator-access-response.d.ts +1 -1
  33. package/dist/generated/types/rematch-match-response.d.ts +1 -1
  34. package/dist/generated/types/restore-history-response.d.ts +1 -1
  35. package/dist/generated/types/restore-match-save-response.d.ts +1 -1
  36. package/dist/generated/types/server-message.d.ts +1 -1
  37. package/dist/generated/types/shared-match-history-replay-response.d.ts +1 -1
  38. package/dist/generated/types/submit-ai-game-feedback-request.d.ts +1 -0
  39. package/dist/generated/types/submit-ai-game-feedback-request.js +2 -0
  40. package/dist/generated/types/submit-ai-game-feedback-response.d.ts +1 -0
  41. package/dist/generated/types/submit-ai-game-feedback-response.js +2 -0
  42. package/dist/generated/types/submit-match-deck-response.d.ts +1 -1
  43. package/dist/generated/types/tournament-room-access-response.d.ts +1 -1
  44. package/dist/generated/types/tournament-room-server-message.d.ts +1 -1
  45. package/dist/generated/types/undo-match-response.d.ts +1 -1
  46. package/dist/generated/types/update-lobby-settings-request.d.ts +1 -1
  47. package/dist/generated/version.d.ts +1 -1
  48. package/dist/generated/version.js +1 -1
  49. package/dist/http/request.d.ts +2 -0
  50. package/dist/http/request.js +9 -1
  51. package/dist/i18n/card-print-catalog.d.ts +9 -0
  52. package/dist/i18n/card-print-catalog.js +260 -0
  53. package/dist/i18n/catalog.d.ts +8 -0
  54. package/dist/i18n/catalog.js +195 -0
  55. package/dist/i18n/diagnostics.d.ts +6 -0
  56. package/dist/i18n/diagnostics.js +19 -0
  57. package/dist/i18n/fallback.d.ts +3 -0
  58. package/dist/i18n/fallback.js +40 -0
  59. package/dist/i18n/format.d.ts +8 -0
  60. package/dist/i18n/format.js +29 -0
  61. package/dist/i18n/generated/message-types.d.ts +91 -0
  62. package/dist/i18n/generated/message-types.js +3 -0
  63. package/dist/i18n/icu.d.ts +12 -0
  64. package/dist/i18n/icu.js +75 -0
  65. package/dist/i18n/index.d.ts +9 -0
  66. package/dist/i18n/index.js +5 -0
  67. package/dist/i18n/locale.d.ts +9 -0
  68. package/dist/i18n/locale.js +19 -0
  69. package/dist/i18n/types.d.ts +151 -0
  70. package/dist/i18n/types.js +1 -0
  71. package/dist/index.d.ts +5 -4
  72. package/dist/internal/authenticated-socket-session.d.ts +2 -0
  73. package/dist/internal/authenticated-socket-session.js +3 -1
  74. package/dist/local/client.js +7 -2
  75. package/dist/local/server/http-router.js +18 -0
  76. package/dist/resources/admin.d.ts +8 -0
  77. package/dist/resources/admin.js +2 -0
  78. package/dist/resources/limited-event-session.d.ts +10 -0
  79. package/dist/resources/limited-event-session.js +35 -0
  80. package/dist/resources/limited-event-types.d.ts +34 -1
  81. package/dist/resources/limited-events.d.ts +8 -1
  82. package/dist/resources/limited-events.js +18 -1
  83. package/dist/resources/lobbies.d.ts +1 -1
  84. package/dist/resources/lobbies.js +1 -1
  85. package/dist/resources/lobby-types.d.ts +15 -2
  86. package/dist/resources/match-history.d.ts +8 -1
  87. package/dist/resources/match-history.js +10 -0
  88. package/dist/resources/tournament-rooms.d.ts +1 -1
  89. package/dist/resources/tournament-rooms.js +1 -1
  90. package/dist/types.d.ts +1 -1
  91. package/dist/validators.d.ts +5 -1
  92. package/i18n/cards/de.json +121 -0
  93. package/i18n/cards/en.json +121 -0
  94. package/i18n/cards/es.json +121 -0
  95. package/i18n/cards/fr.json +121 -0
  96. package/i18n/cards/it.json +121 -0
  97. package/i18n/cards/manifest.json +2715 -0
  98. package/i18n/de.json +11 -0
  99. package/i18n/en.json +11 -0
  100. package/i18n/es.json +11 -0
  101. package/i18n/fr.json +11 -0
  102. package/i18n/it.json +11 -0
  103. package/i18n/messages.schema.json +28 -0
  104. package/package.json +12 -2
  105. package/schema/common.schema.json +1684 -1005
  106. package/schema/create-limited-event-request.schema.json +11 -0
  107. package/schema/game-event.schema.json +76 -0
  108. package/schema/game-state.schema.json +8 -0
  109. package/schema/leave-limited-event-request.schema.json +15 -0
  110. package/schema/limited-event-server-message.schema.json +63 -0
  111. package/schema/manifest.json +5 -1
  112. package/schema/match-save-payload.schema.json +1 -1
  113. package/schema/route-manifest.json +54 -0
  114. package/schema/submit-ai-game-feedback-request.schema.json +36 -0
  115. package/schema/submit-ai-game-feedback-response.schema.json +19 -0
  116. package/schema/update-lobby-settings-request.schema.json +67 -0
@@ -1,7 +1,9 @@
1
- import type { CreateLimitedEventRequest, JoinLimitedEventRequest, LimitedEventAccessResponse, LimitedEventPreflightResponse } from '../generated/index.js';
1
+ import type { CreateLimitedEventRequest, ErrorPayload, JoinLimitedEventRequest, LimitedEventAccessResponse, LimitedEventPreflightResponse, LimitedEventServerMessage } from '../generated/index.js';
2
2
  import type { LimitedEventSnapshot as GeneratedLimitedEventSnapshot } from '../generated/types/limited-event-access-response.js';
3
3
  import type { LimitedEventCommand as GeneratedLimitedEventCommand } from '../generated/types/limited-event-command-request.js';
4
4
  import type { SimulatorRequestOptions } from '../http/options.js';
5
+ import type { ConnectionState, PongPayload } from '../session.js';
6
+ export type { LimitedEventServerMessage };
5
7
  /**
6
8
  * Access token and private snapshot returned after creating or joining a Limited Event.
7
9
  *
@@ -119,6 +121,33 @@ export interface LimitedEventAccessInput extends LimitedEventReference {
119
121
  */
120
122
  seatToken: string;
121
123
  }
124
+ /** Events emitted by a direct Limited Event presence session. */
125
+ export interface LimitedEventSessionEvents {
126
+ change: LimitedEventSessionState;
127
+ connectionState: ConnectionState;
128
+ error: ErrorPayload;
129
+ message: LimitedEventServerMessage;
130
+ pong: PongPayload;
131
+ snapshot: LimitedEventSnapshot;
132
+ }
133
+ /** Aggregated direct Limited Event socket state. */
134
+ export interface LimitedEventSessionState {
135
+ connectionState: ConnectionState;
136
+ errors: readonly ErrorPayload[];
137
+ snapshot: LimitedEventSnapshot | undefined;
138
+ }
139
+ /** Live presence session for one directly-created Limited Event seat. */
140
+ export interface LimitedEventSession {
141
+ readonly __v_skip: true;
142
+ readonly connectionState: ConnectionState;
143
+ readonly errorMessages: readonly string[];
144
+ readonly errors: readonly ErrorPayload[];
145
+ readonly snapshot: LimitedEventSnapshot | undefined;
146
+ close: () => void;
147
+ connect: () => Promise<LimitedEventSession>;
148
+ on: <TKey extends keyof LimitedEventSessionEvents>(event: TKey, listener: (value: LimitedEventSessionEvents[TKey]) => void) => () => void;
149
+ ping: (nonce?: string) => void;
150
+ }
122
151
  /**
123
152
  * Limited Event resource API methods.
124
153
  *
@@ -249,4 +278,8 @@ export interface LimitedEventsResource {
249
278
  * @see https://simulator-sdk.my-swu.com/guide/limited-events#join
250
279
  */
251
280
  join(event: LimitedEventReference, request?: JoinLimitedEventRequest, options?: SimulatorRequestOptions): Promise<LimitedEventAccess>;
281
+ /** Permanently leaves one direct event seat. */
282
+ leave(access: LimitedEventAccessInput, options?: SimulatorRequestOptions): Promise<void>;
283
+ /** Creates live presence for one direct event seat. */
284
+ createSession(access: LimitedEventAccessInput | LimitedEventAccess): LimitedEventSession;
252
285
  }
@@ -1,7 +1,14 @@
1
1
  import type { EngineHttpRequester } from '../http/request.js';
2
+ import type { WebSocketFactory } from '../internal/transport.js';
3
+ import type { SchemaValidator } from '../validators/validator.js';
2
4
  import type { LimitedEventsResource } from './limited-event-types.js';
3
5
  export type * from './limited-event-types.js';
4
6
  /**
5
7
  * Creates the Limited Event resource client.
6
8
  */
7
- export declare function createLimitedEventsResource(requester: EngineHttpRequester): LimitedEventsResource;
9
+ export declare function createLimitedEventsResource(options: {
10
+ requester: EngineHttpRequester;
11
+ validate?: SchemaValidator | undefined;
12
+ webSocketFactory?: WebSocketFactory | undefined;
13
+ wsUrl: string;
14
+ }): LimitedEventsResource;
@@ -1,8 +1,12 @@
1
1
  import { jsonBody, jsonHeaders } from '../http/json.js';
2
+ import { getDefaultWebSocketFactory } from '../internal/transport.js';
3
+ import { createLimitedEventSession } from './limited-event-session.js';
2
4
  /**
3
5
  * Creates the Limited Event resource client.
4
6
  */
5
- export function createLimitedEventsResource(requester) {
7
+ export function createLimitedEventsResource(options) {
8
+ const { requester } = options;
9
+ const webSocketFactory = options.webSocketFactory ?? getDefaultWebSocketFactory();
6
10
  return {
7
11
  applyCommand: (access, command, options) => requester.request('limited-event-response', `/api/limited-events/${eventIdFrom(access)}/commands`, {
8
12
  body: jsonBody(requester.validate('limited-event-command-request', {
@@ -33,6 +37,19 @@ export function createLimitedEventsResource(requester) {
33
37
  headers: jsonHeaders(),
34
38
  method: 'POST',
35
39
  }, options),
40
+ leave: (access, requestOptions) => requester.requestVoid(`/api/limited-events/${eventIdFrom(access)}/leave`, {
41
+ body: jsonBody(requester.validate('leave-limited-event-request', {
42
+ seatToken: access.seatToken,
43
+ })),
44
+ headers: jsonHeaders(),
45
+ method: 'POST',
46
+ }, requestOptions),
47
+ createSession: access => createLimitedEventSession({
48
+ access,
49
+ webSocketFactory,
50
+ wsUrl: options.wsUrl,
51
+ ...(options.validate == null ? {} : { validate: options.validate }),
52
+ }),
36
53
  };
37
54
  }
38
55
  /**
@@ -40,7 +40,7 @@ export interface LobbiesResource {
40
40
  submitLimitedDeck(lobbyId: string, request: SubmitLobbyLimitedDeckRequest, options?: SimulatorRequestOptions): Promise<LobbyAccessResponse>;
41
41
  prepareLimitedAiDecks(lobbyId: string, request: PrepareLobbyLimitedAiDecksRequest, options?: SimulatorRequestOptions): Promise<LobbyAccessResponse>;
42
42
  startLimitedMatch(lobbyId: string, request: StartLobbyLimitedMatchRequest, options?: SimulatorRequestOptions): Promise<LobbyAccessResponse>;
43
- leave(lobbyId: string, request: LeaveLobbyRequest, options?: SimulatorRequestOptions): Promise<LobbyAccessResponse>;
43
+ leave(lobbyId: string, request: LeaveLobbyRequest, options?: SimulatorRequestOptions): Promise<void>;
44
44
  createSession(access: LobbyAccessInput | LobbyAccessResponse): LobbySession;
45
45
  }
46
46
  export interface LobbiesResourceOptions {
@@ -29,7 +29,7 @@ export function createLobbiesResource(options) {
29
29
  submitLimitedDeck: (lobbyId, request, options) => requestResource(requester, 'lobby-access-response', `/api/lobbies/${lobbyId}/limited-deck`, jsonPost('submit-lobby-limited-deck-request', request), options),
30
30
  prepareLimitedAiDecks: (lobbyId, request, options) => requestResource(requester, 'lobby-access-response', `/api/lobbies/${lobbyId}/prepare-limited-ai-decks`, jsonPost('prepare-lobby-limited-ai-decks-request', request), options),
31
31
  startLimitedMatch: (lobbyId, request, options) => requestResource(requester, 'lobby-access-response', `/api/lobbies/${lobbyId}/start-limited-match`, jsonPost('start-lobby-limited-match-request', request), options),
32
- leave: (lobbyId, request, options) => requestResource(requester, 'lobby-access-response', `/api/lobbies/${lobbyId}/leave`, jsonPost('leave-lobby-request', request), options),
32
+ leave: (lobbyId, request, options) => requester.requestVoid(`/api/lobbies/${lobbyId}/leave`, jsonPost('leave-lobby-request', request), options),
33
33
  createSession: access => createLobbySession({
34
34
  access,
35
35
  webSocketFactory,
@@ -1,4 +1,4 @@
1
- import type { AddLobbyAiPlayerRequest, ErrorPayload, JoinLobbyRequest, KickLobbyPlayerRequest, KickLobbySpectatorRequest, LeaveLobbyRequest, LobbyChatRequest, LobbyMatchmakingDecisionRequest, LobbySyncRequest, PrepareLobbyLimitedAiDecksRequest, ReturnLobbyMatchRequest, SpectateLobbyRequest, StartLobbyLimitedMatchRequest, StartLobbyRequest, SubmitLobbyLimitedDeckRequest, UpdateLobbyAiPlayerRequest, UpdateLobbyPlayerRequest } from '../generated/index.js';
1
+ import type { AddLobbyAiPlayerRequest, DraftLobbyTimerSettings, ErrorPayload, JoinLobbyRequest, KickLobbyPlayerRequest, KickLobbySpectatorRequest, LeaveLobbyRequest, LobbyChatRequest, LobbyGameTimerSettings, LobbyMatchmakingDecisionRequest, LobbySyncRequest, LobbyTimerSettings, LimitedLobbyTimerSettings, PrepareLobbyLimitedAiDecksRequest, ReturnLobbyMatchRequest, SpectateLobbyRequest, StartLobbyLimitedMatchRequest, StartLobbyRequest, SubmitLobbyLimitedDeckRequest, UpdateLobbyAiPlayerRequest, UpdateLobbyPlayerRequest } from '../generated/index.js';
2
2
  import type { LobbyChatMessage, LobbyDeckPreview, LobbyDeckSetPreview, LobbyMatchmakingKind as GeneratedLobbyMatchmakingKind, LobbyParticipantRole, LobbyPlayerController, LobbyPlayerView, LobbyPrivateAiPlayerView, LobbyPrivateView, LobbySpectatorView, LobbyStartedAccess, LobbyStatus, LobbyVisibility, PlayerPresenceStatus, RoomPlayerPresenceEvent } from '../generated/types/lobby-access-response.js';
3
3
  import type { LobbyKickedPayload, LobbyRemovalReason } from '../generated/types/lobby-server-message.js';
4
4
  import type { HistoryIdentityInput } from '../generated/types/match-history-list-request.js';
@@ -33,7 +33,7 @@ import type { DeckInput } from './card-types.js';
33
33
  * `trilogyFormatMode` optional where the server always sends it.
34
34
  * `test/lobby-wire-parity.test.ts` now pins each of them against its schema.
35
35
  */
36
- export type { AddLobbyAiPlayerRequest, JoinLobbyRequest, KickLobbyPlayerRequest, KickLobbySpectatorRequest, LeaveLobbyRequest, LobbyChatMessage, LobbyChatRequest, LobbyDeckPreview, LobbyDeckSetPreview, LobbyKickedPayload, LobbyMatchmakingDecisionRequest, LobbyParticipantRole, LobbyPlayerController, LobbyPlayerView, LobbyPrivateAiPlayerView, LobbyPrivateView, LobbyRemovalReason, LobbySpectatorView, LobbyStartedAccess, LobbyStatus, LobbySyncRequest, LobbyVisibility, PlayerPresenceStatus, PrepareLobbyLimitedAiDecksRequest, RoomPlayerPresenceEvent, SpectateLobbyRequest, StartLobbyLimitedMatchRequest, StartLobbyRequest, SubmitLobbyLimitedDeckRequest, UpdateLobbyAiPlayerRequest, UpdateLobbyPlayerRequest, };
36
+ export type { AddLobbyAiPlayerRequest, JoinLobbyRequest, KickLobbyPlayerRequest, KickLobbySpectatorRequest, LeaveLobbyRequest, LobbyChatMessage, LobbyChatRequest, LobbyDeckPreview, LobbyDeckSetPreview, LobbyKickedPayload, LobbyMatchmakingDecisionRequest, LobbyGameTimerSettings, LobbyParticipantRole, LobbyPlayerController, LobbyPlayerView, LobbyPrivateAiPlayerView, LobbyPrivateView, LobbyRemovalReason, LobbySpectatorView, LobbyStartedAccess, LobbyStatus, LobbySyncRequest, LobbyTimerSettings, LimitedLobbyTimerSettings, DraftLobbyTimerSettings, LobbyVisibility, PlayerPresenceStatus, PrepareLobbyLimitedAiDecksRequest, RoomPlayerPresenceEvent, SpectateLobbyRequest, StartLobbyLimitedMatchRequest, StartLobbyRequest, SubmitLobbyLimitedDeckRequest, UpdateLobbyAiPlayerRequest, UpdateLobbyPlayerRequest, };
37
37
  export type LobbyConfig = {
38
38
  type: 'match';
39
39
  format: MatchFormat;
@@ -124,6 +124,17 @@ export interface UpdateLobbySettingsRequest {
124
124
  visibility?: LobbyVisibility | null;
125
125
  playerCount?: number | null;
126
126
  gameTimerEnabled?: boolean | null;
127
+ timerSettings?: LobbyTimerSettings | null;
128
+ setCode?: string | null;
129
+ sealedPackCount?: number | null;
130
+ draftRounds?: Array<{
131
+ setCode: string;
132
+ }> | null;
133
+ pickTimerEnabled?: boolean | null;
134
+ packSeed?: string | null;
135
+ clearPackSeed?: boolean;
136
+ matchSeed?: string | null;
137
+ clearMatchSeed?: boolean;
127
138
  matchFormat?: ConstructedFormat | null;
128
139
  bestOfMatches?: 1 | 3 | null;
129
140
  trilogyFormat?: ConstructedFormat | null;
@@ -182,6 +193,8 @@ export interface LobbySnapshot {
182
193
  status: LobbyStatus;
183
194
  visibility: LobbyVisibility;
184
195
  config: LobbyConfig;
196
+ /** Host-selected timer schedule. Missing for legacy lobby records. */
197
+ timerSettings?: LobbyTimerSettings | null;
185
198
  /** Fixed limited pack/leader seed when configured. */
186
199
  packSeed?: string | null;
187
200
  /** Fixed match seed when configured. */
@@ -1,4 +1,4 @@
1
- import type { CreateMatchHistoryReplayShareRequest, CreateMatchHistoryReplayShareResponse, MatchRecoveryRequest, MatchRecoveryResponse, MatchHistoryDeckStatsRequest, MatchHistoryDeckStatsResponse, MatchHistoryListRequest, MatchHistoryListResponse, MatchHistoryReplayRequest, MatchHistoryReplayResponse, MatchHistoryRestoreRequest, RestoreHistoryResponse, SharedMatchHistoryReplayResponse } from '../generated/index.js';
1
+ import type { CreateMatchHistoryReplayShareRequest, CreateMatchHistoryReplayShareResponse, MatchRecoveryRequest, MatchRecoveryResponse, MatchHistoryDeckStatsRequest, MatchHistoryDeckStatsResponse, MatchHistoryListRequest, MatchHistoryListResponse, MatchHistoryReplayRequest, MatchHistoryReplayResponse, MatchHistoryRestoreRequest, RestoreHistoryResponse, SharedMatchHistoryReplayResponse, SubmitAiGameFeedbackRequest, SubmitAiGameFeedbackResponse } from '../generated/index.js';
2
2
  import type { SimulatorRequestOptions } from '../http/options.js';
3
3
  import type { EngineHttpRequester } from '../http/request.js';
4
4
  /**
@@ -22,6 +22,11 @@ export interface CreateMatchHistoryReplayShareInput extends CreateMatchHistoryRe
22
22
  /** Durable history row id returned by {@link MatchHistoryResource.list}. */
23
23
  historyId: string;
24
24
  }
25
+ /** Participant-authorized feedback for one completed AI game. */
26
+ export interface SubmitAiGameFeedbackInput extends SubmitAiGameFeedbackRequest {
27
+ /** Original server match id, never the opaque history row id. */
28
+ sourceMatchId: string;
29
+ }
25
30
  /**
26
31
  * Server-owned simulator history APIs.
27
32
  */
@@ -46,6 +51,8 @@ export interface MatchHistoryResource {
46
51
  restore(request: MatchHistoryRestoreInput, options?: SimulatorRequestOptions): Promise<RestoreHistoryResponse>;
47
52
  /** Restores an owned Solo-versus-AI source after its runtime is lost. */
48
53
  recover(request: MatchRecoveryInput, options?: SimulatorRequestOptions): Promise<MatchRecoveryResponse>;
54
+ /** Creates feedback once for one completed Solo-versus-AI game. */
55
+ submitAiGameFeedback(request: SubmitAiGameFeedbackInput, options?: SimulatorRequestOptions): Promise<SubmitAiGameFeedbackResponse>;
49
56
  }
50
57
  /**
51
58
  * Dependencies needed by the match-history resource.
@@ -46,5 +46,15 @@ export function createMatchHistoryResource(options) {
46
46
  headers: jsonHeaders(),
47
47
  method: 'POST',
48
48
  }, options),
49
+ submitAiGameFeedback: (request, options) => requester.request('submit-ai-game-feedback-response', `/api/match-history/${encodeURIComponent(request.sourceMatchId)}/ai-feedback`, {
50
+ body: jsonBody(requester.validate('submit-ai-game-feedback-request', {
51
+ identities: request.identities,
52
+ gameNumber: request.gameNumber,
53
+ rating: request.rating,
54
+ comments: request.comments,
55
+ })),
56
+ headers: jsonHeaders(),
57
+ method: 'POST',
58
+ }, options),
49
59
  };
50
60
  }
@@ -19,7 +19,7 @@ export interface TournamentRoomsResource {
19
19
  createTable(roomId: string, request: CreateTournamentTableRequest, options?: SimulatorRequestOptions): Promise<TournamentRoomAccessResponse>;
20
20
  joinTable(roomId: string, tableId: string, request: JoinTournamentTableRequest, options?: SimulatorRequestOptions): Promise<TournamentRoomAccessResponse>;
21
21
  returnMatch(roomId: string, request: ReturnTournamentMatchRequest, options?: SimulatorRequestOptions): Promise<TournamentRoomAccessResponse>;
22
- leave(roomId: string, request: LeaveTournamentRoomRequest, options?: SimulatorRequestOptions): Promise<TournamentRoomAccessResponse>;
22
+ leave(roomId: string, request: LeaveTournamentRoomRequest, options?: SimulatorRequestOptions): Promise<void>;
23
23
  close(roomId: string, request: CloseTournamentRoomRequest, options?: SimulatorRequestOptions): Promise<TournamentRoomResponse>;
24
24
  createSession(access: TournamentRoomAccessInput | TournamentRoomAccessResponse): TournamentRoomSession;
25
25
  }
@@ -21,7 +21,7 @@ export function createTournamentRoomsResource(options) {
21
21
  join: (roomId, request, options) => requester.request('tournament-room-access-response', `/api/tournament-rooms/${roomId}/join`, jsonPost('join-tournament-room-request', request), options),
22
22
  joinTable: (roomId, tableId, request, options) => requester.request('tournament-room-access-response', `/api/tournament-rooms/${roomId}/tables/${tableId}/join`, jsonPost('join-tournament-table-request', request), options),
23
23
  list: options => requester.request('tournament-room-list-response', '/api/tournament-rooms', {}, options),
24
- leave: (roomId, request, options) => requester.request('tournament-room-access-response', `/api/tournament-rooms/${roomId}/leave`, jsonPost('leave-tournament-room-request', request), options),
24
+ leave: (roomId, request, options) => requester.requestVoid(`/api/tournament-rooms/${roomId}/leave`, jsonPost('leave-tournament-room-request', request), options),
25
25
  returnMatch: (roomId, request, options) => requester.request('tournament-room-access-response', `/api/tournament-rooms/${roomId}/return-match`, jsonPost('return-tournament-match-request', request), options),
26
26
  sendChat: (roomId, request, options) => requester.request('tournament-room-chat-response', `/api/tournament-rooms/${roomId}/chat`, jsonPost('tournament-room-chat-request', request), options),
27
27
  startEvent: (roomId, request, options) => requester.request('tournament-room-access-response', `/api/tournament-rooms/${roomId}/start-event`, jsonPost('start-tournament-event-request', request), options),
package/dist/types.d.ts CHANGED
@@ -25,7 +25,7 @@
25
25
  * `test/type-smoke.test.ts` enforces.
26
26
  */
27
27
  export type { AiDifficulty, AiOpponentConfig, AiTrilogyFormatMode, FormatSetupInput, MatchScenarioInput, MctsConfigOverride, } from "./generated/types/create-match-request.js";
28
- export type { AbilityWindow, ActionAbilitySource, ActionAbilityView, ActiveEffectDescriptionView, ActiveEffectView, AbilityTarget, AttachmentMode, AttackChoiceView, AttackTarget, AvailableAttackView, CapturedUnitView, CaptureOptionsView, CaptureSelection, CardArena, CardChoiceResourcePaymentOptionView, CardInstanceView, ConstructedFormat, CurrentAttackStateView, CurrentAttackView, DeckRegistrationView, DelayedEffectDescriptionView, DelayedEffectTimingView, DelayedEffectView, DistributionAssignment, DistributionDamageKindView, DistributionItemView, DistributionTargetView, DistributionTokenKindView, DynamicPowerLimit, EffectCardScopeView, EffectDurationView, EffectResolutionDraftStepView, EffectResolutionDraftView, EffectRestrictionView, EffectSourceView, EffectTargetView, ExploitOptionsView, FormatSeatView, GameTimerActiveClockView, GameTimerReserveView, GameTimerStateView, HiddenCardChoiceMode, HiddenZoneKind, InitiativeChoiceReason, InitiativeState, InstructedAttackView, LeaderActionView, LeaderDeployActionView, LeaderDeployCostView, LeaderDeployMode, LeaderDeployThresholdBonus, LeaderStateView, LimitedEventView, MatchEndReason, MatchFormat, MatchPhase, MatchResult, MatchSeriesView, MatchStatus, ModeChoiceView, NamedCardEffectDescriptionView, PendingAbilityAspectChoiceView, PendingAbilityAttackChoiceView, PendingAbilityCardChoiceView, PendingAbilityFamily, PendingAbilityModeChoiceView, PendingAbilityNameChoiceView, PendingAbilityOrderAbilityView, PendingAbilityOrderChoiceView, PendingAbilityOrderGroupView, PendingAbilityView, PendingChoiceView, PendingDistributionView, PendingUndoRequest, PlayActionView, PlayCardSourceView, PlayCardZone, PlayerTargetPattern, PresenceFilter, PromptState, RejectedPlayView, RelationFilter, ResourceCardView, ResourcePaymentOptionView, Seat, SeatDirection, SeatOfferIntent, SeatState, SelectionScope, SeriesEndReason, SeriesGameRecord, SeriesResultView, SharedCounterState, SmuggleActionView, SmuggleKind, TargetGroupPurpose, TargetSelectionGroup, TargetSelectionPlanView, TriggerWindowView, TwinSunsCounter, TwinSunsCountersView, UndoRequestReason, UniquenessFilter, UnitAbilitySuppressionView, UnitExtremum, UnitFilter, UnitStateView, UpgradeStateView, } from "./generated/types/get-match-response.js";
28
+ export type { AbilityWindow, ActionAbilitySource, ActionAbilityView, ActiveEffectDescriptionView, ActiveEffectView, AbilityTarget, AttachmentMode, AttackChoiceView, AttackTarget, AvailableAttackView, CapturedUnitView, CaptureOptionsView, CaptureSelection, CardArena, CardChoiceResourcePaymentOptionView, CardInstanceView, ConstructedFormat, CurrentAttackStateView, CurrentAttackView, DeckRegistrationView, DelayedEffectDescriptionView, DelayedEffectTimingView, DelayedEffectView, DistributionAssignment, DistributionDamageKindView, DistributionItemView, DistributionTargetView, DistributionTokenKindView, EffectCardScopeView, EffectDurationView, EffectResolutionDraftStepView, EffectResolutionDraftView, EffectRestrictionView, EffectSourceView, EffectTargetView, ExploitOptionsView, FormatSeatView, GameTimerActiveClockView, GameTimerReserveView, GameTimerStateView, HiddenCardChoiceMode, HiddenZoneKind, InitiativeChoiceReason, InitiativeState, InstructedAttackView, LeaderActionView, LeaderDeployActionView, LeaderDeployCostView, LeaderDeployMode, LeaderDeployThresholdBonus, LeaderStateView, LimitedEventView, MatchEndReason, MatchFormat, MatchPhase, MatchResult, MatchSeriesView, MatchStatus, ModeChoiceView, NamedCardEffectDescriptionView, PendingAbilityAspectChoiceView, PendingAbilityAttackChoiceView, PendingAbilityCardChoiceView, PendingAbilityFamily, PendingAbilityModeChoiceView, PendingAbilityNameChoiceView, PendingAbilityOrderAbilityView, PendingAbilityOrderChoiceView, PendingAbilityOrderGroupView, PendingAbilityView, PendingChoiceView, PendingDistributionView, PendingUndoRequest, PlayActionView, PlayCardSourceView, PlayCardZone, PromptState, RejectedPlayView, RelationFilter, ResourceCardView, ResourcePaymentOptionView, Seat, SeatOfferIntent, SeatState, SeriesEndReason, SeriesGameRecord, SeriesResultView, SharedCounterState, SmuggleActionView, SmuggleKind, TargetGroupPurpose, TargetSelectionGroup, TargetSelectionPlanView, TriggerWindowView, TwinSunsCounter, TwinSunsCountersView, UndoRequestReason, UnitAbilitySuppressionView, UnitStateView, UpgradeStateView, } from "./generated/types/get-match-response.js";
29
29
  export type { AspectCount } from "./generated/types/cards-response.js";
30
30
  export type { CloseTournamentRoomActiveMatches } from "./generated/types/close-tournament-room-request.js";
31
31
  export type { CardDrawSource, TurnPassSource, UnitDefeatCause, } from "./generated/types/game-event.js";
@@ -1,4 +1,4 @@
1
- import type { AdminMatchDebugBundle, AdminMatchListResponse, AdminMatchReplayResponse, SimulatorReportListResponse, SimulatorReportResponse, CloseTournamentRoomRequest, AbandonMatchRequest, AbandonMatchResponse, AddLobbyAiPlayerRequest, ApiErrorResponse, CardCatalogRefreshResponse, CardsResponse, ClientMessage, CreateMatchHistoryReplayShareRequest, CreateMatchHistoryReplayShareResponse, CreateLimitedEventRequest, CreateLobbyRequest, CreateMetaWindowRequest, CreateMatchRequest, CreatePlaygroundShareResponse, CreateTournamentRoomRequest, CreateTournamentTableRequest, ErrorPayload, FormatEventRequest, FormatEventResponse, GameCommand, GameEvent, GameState, GetMatchResponse, HealthResponse, JoinLimitedEventRequest, JoinLobbyRequest, JoinMatchRequest, JoinTournamentRoomRequest, JoinTournamentTableRequest, KickLobbyPlayerRequest, KickLobbySpectatorRequest, LeaveLobbyRequest, LeaveMatchRequest, LeaveMatchResponse, LeaveTournamentRoomRequest, LimitedEventAccessResponse, LimitedEventCommandRequest, LimitedEventPreflightResponse, LimitedEventResponse, LobbyAccessResponse, LobbyChatRequest, LobbyChatResponse, LobbyListResponse, LobbyListServerMessage, LobbyMatchmakingDecisionRequest, PrepareLobbyLimitedAiDecksRequest, LobbyResponse, LobbyServerMessage, LobbySyncRequest, ListActiveAiMatchesRequest, ListActiveAiMatchesResponse, MatchAccessRecoveryRequest, MatchAccessRecoveryResponse, MatchAccessResponse, MatchChatLookupResponse, MatchConnectionRole, MatchHistoryDeckStatsRequest, MatchHistoryDeckStatsResponse, MatchHistoryEntry, MatchHistoryListRequest, MatchHistoryListResponse, MatchHistoryReplayRequest, MatchHistoryReplayResponse, MatchHistoryRestoreRequest, MatchRecoveryRequest, MatchRecoveryResponse, RestoreHistoryResponse, MatchSavePayload, PlaygroundExportPayload, MatchSpectatorAccessResponse, MetaWindow, MetaWindowsResponse, LobbyMatchmakingRequest, ResolveCardIdsRequest, ResolveCardIdsResponse, RankedAdminStatus, RankedLeaderboardEntry, RankedLeaderboardQuery, RankedLeaderboardResponse, RankedMatchmakingView, RankedProfileRequest, RankedProfileResponse, RankedQueue, RematchMatchRequest, RematchMatchResponse, SaveMatchRequest, ReturnLobbyMatchRequest, ReturnTournamentMatchRequest, RestoreMatchSaveRequest, RestoreMatchSaveResponse, ServerMessage, AiStatusPayload, SetRankedAdmissionRequest, SetSimulatorMaintenanceRequest, SetAiPausedRequest, SetPlaygroundAiSeatRequest, SharedMatchHistoryReplayResponse, SimulatorAdminStatusResponse, SimulatorAvailabilityResponse, SpectateLobbyRequest, SpectateMatchRequest, StartLobbyLimitedMatchRequest, StartLobbyRequest, StartTournamentEventRequest, SubmitLobbyLimitedDeckRequest, SubmitMatchDeckRequest, SubmitMatchDeckResponse, SubmitTournamentDeckRequest, TournamentEventCommandRequest, TournamentRoomAccessResponse, TournamentRoomChatRequest, TournamentRoomChatResponse, TournamentRoomListResponse, TournamentRoomResponse, TournamentRoomServerMessage, TournamentRoomSyncRequest, UndoMatchRequest, UndoMatchResponse, UndoRespondMatchRequest, UpdateLobbyAiPlayerRequest, UpdateLobbyPlayerRequest, UpdateLobbySettingsRequest, UpdateTournamentRoomPlayerRequest, UpdateTournamentRoomSettingsRequest, WelcomePayload } from './generated/index.js';
1
+ import type { AdminMatchDebugBundle, AdminMatchListResponse, AdminMatchReplayResponse, SimulatorReportListResponse, SimulatorReportResponse, CloseTournamentRoomRequest, AbandonMatchRequest, AbandonMatchResponse, AddLobbyAiPlayerRequest, ApiErrorResponse, CardCatalogRefreshResponse, CardsResponse, ClientMessage, CreateMatchHistoryReplayShareRequest, CreateMatchHistoryReplayShareResponse, CreateLimitedEventRequest, CreateLobbyRequest, CreateMetaWindowRequest, CreateMatchRequest, CreatePlaygroundShareResponse, CreateTournamentRoomRequest, CreateTournamentTableRequest, ErrorPayload, FormatEventRequest, FormatEventResponse, GameCommand, GameEvent, GameState, GetMatchResponse, HealthResponse, JoinLimitedEventRequest, LeaveLimitedEventRequest, JoinLobbyRequest, JoinMatchRequest, JoinTournamentRoomRequest, JoinTournamentTableRequest, KickLobbyPlayerRequest, KickLobbySpectatorRequest, LeaveLobbyRequest, LeaveMatchRequest, LeaveMatchResponse, LeaveTournamentRoomRequest, LimitedEventAccessResponse, LimitedEventCommandRequest, LimitedEventPreflightResponse, LimitedEventResponse, LimitedEventServerMessage, LobbyAccessResponse, LobbyChatRequest, LobbyChatResponse, LobbyListResponse, LobbyListServerMessage, LobbyMatchmakingDecisionRequest, PrepareLobbyLimitedAiDecksRequest, LobbyResponse, LobbyServerMessage, LobbySyncRequest, ListActiveAiMatchesRequest, ListActiveAiMatchesResponse, MatchAccessRecoveryRequest, MatchAccessRecoveryResponse, MatchAccessResponse, MatchChatLookupResponse, MatchConnectionRole, MatchHistoryDeckStatsRequest, MatchHistoryDeckStatsResponse, MatchHistoryEntry, MatchHistoryListRequest, MatchHistoryListResponse, MatchHistoryReplayRequest, MatchHistoryReplayResponse, MatchHistoryRestoreRequest, MatchRecoveryRequest, MatchRecoveryResponse, RestoreHistoryResponse, MatchSavePayload, PlaygroundExportPayload, MatchSpectatorAccessResponse, MetaWindow, MetaWindowsResponse, LobbyMatchmakingRequest, ResolveCardIdsRequest, ResolveCardIdsResponse, RankedAdminStatus, RankedLeaderboardEntry, RankedLeaderboardQuery, RankedLeaderboardResponse, RankedMatchmakingView, RankedProfileRequest, RankedProfileResponse, RankedQueue, RematchMatchRequest, RematchMatchResponse, SaveMatchRequest, ReturnLobbyMatchRequest, ReturnTournamentMatchRequest, RestoreMatchSaveRequest, RestoreMatchSaveResponse, ServerMessage, AiStatusPayload, SetRankedAdmissionRequest, SetSimulatorMaintenanceRequest, SetAiPausedRequest, SetPlaygroundAiSeatRequest, SharedMatchHistoryReplayResponse, SubmitAiGameFeedbackRequest, SubmitAiGameFeedbackResponse, SimulatorAdminStatusResponse, SimulatorAvailabilityResponse, SpectateLobbyRequest, SpectateMatchRequest, StartLobbyLimitedMatchRequest, StartLobbyRequest, StartTournamentEventRequest, SubmitLobbyLimitedDeckRequest, SubmitMatchDeckRequest, SubmitMatchDeckResponse, SubmitTournamentDeckRequest, TournamentEventCommandRequest, TournamentRoomAccessResponse, TournamentRoomChatRequest, TournamentRoomChatResponse, TournamentRoomListResponse, TournamentRoomResponse, TournamentRoomServerMessage, TournamentRoomSyncRequest, UndoMatchRequest, UndoMatchResponse, UndoRespondMatchRequest, UpdateLobbyAiPlayerRequest, UpdateLobbyPlayerRequest, UpdateLobbySettingsRequest, UpdateTournamentRoomPlayerRequest, UpdateTournamentRoomSettingsRequest, WelcomePayload } from './generated/index.js';
2
2
  import type { SchemaValidator } from './validators/validator.js';
3
3
  /**
4
4
  * Exact schema-to-type map generated from Rust public wire contracts.
@@ -41,6 +41,7 @@ export interface SchemaTypeMap {
41
41
  'get-match-response': GetMatchResponse;
42
42
  'health-response': HealthResponse;
43
43
  'join-limited-event-request': JoinLimitedEventRequest;
44
+ 'leave-limited-event-request': LeaveLimitedEventRequest;
44
45
  'join-lobby-request': JoinLobbyRequest;
45
46
  'join-match-request': JoinMatchRequest;
46
47
  'join-tournament-room-request': JoinTournamentRoomRequest;
@@ -52,6 +53,7 @@ export interface SchemaTypeMap {
52
53
  'limited-event-command-request': LimitedEventCommandRequest;
53
54
  'limited-event-preflight-response': LimitedEventPreflightResponse;
54
55
  'limited-event-response': LimitedEventResponse;
56
+ 'limited-event-server-message': LimitedEventServerMessage;
55
57
  'add-lobby-ai-player-request': AddLobbyAiPlayerRequest;
56
58
  'lobby-access-response': LobbyAccessResponse;
57
59
  'lobby-chat-request': LobbyChatRequest;
@@ -76,6 +78,8 @@ export interface SchemaTypeMap {
76
78
  'create-match-history-replay-share-response': CreateMatchHistoryReplayShareResponse;
77
79
  'shared-match-history-replay-response': SharedMatchHistoryReplayResponse;
78
80
  'match-history-restore-request': MatchHistoryRestoreRequest;
81
+ 'submit-ai-game-feedback-request': SubmitAiGameFeedbackRequest;
82
+ 'submit-ai-game-feedback-response': SubmitAiGameFeedbackResponse;
79
83
  'restore-history-response': RestoreHistoryResponse;
80
84
  'match-recovery-request': MatchRecoveryRequest;
81
85
  'match-recovery-response': MatchRecoveryResponse;
@@ -0,0 +1,121 @@
1
+ {
2
+ "formatVersion": 1,
3
+ "locale": "de",
4
+ "cards": {
5
+ "942": {
6
+ "boost-first": {
7
+ "plainText": "Gib einer befreundeten Einheit für diese Phase +3/+3.",
8
+ "sourceLocale": "de",
9
+ "status": {
10
+ "kind": "source"
11
+ }
12
+ },
13
+ "boost-second": {
14
+ "plainText": "Gib einer anderen befreundeten Einheit für diese Phase +2/+2.",
15
+ "sourceLocale": "de",
16
+ "status": {
17
+ "kind": "source"
18
+ }
19
+ },
20
+ "boost-third": {
21
+ "plainText": "Gib einer dritten befreundeten Einheit für diese Phase +1/+1.",
22
+ "sourceLocale": "de",
23
+ "status": {
24
+ "kind": "source"
25
+ }
26
+ },
27
+ "resolve": {
28
+ "plainText": "Gib einer befreundeten Einheit für diese Phase +3/+3.\n\nGib einer anderen befreundeten Einheit für diese Phase +2/+2.\n\nGib einer dritten befreundeten Einheit für diese Phase +1/+1.",
29
+ "sourceLocale": "de",
30
+ "status": {
31
+ "kind": "source"
32
+ }
33
+ }
34
+ },
35
+ "6186": {
36
+ "attach-to": {
37
+ "plainText": "Hänge dieses Upgrade an eine \nNicht-Fahrzeug-Einheit an.",
38
+ "sourceLocale": "de",
39
+ "status": {
40
+ "kind": "source"
41
+ }
42
+ },
43
+ "damage": {
44
+ "plainText": "Du darfst 3 Schaden zufügen, die du nach Wahl auf feindliche Boden-Einheiten aufteilst.",
45
+ "sourceLocale": "de",
46
+ "status": {
47
+ "kind": "source"
48
+ }
49
+ },
50
+ "on-attack": {
51
+ "plainText": "Die Einheit mit diesem Upgrade erhält: \n„Beim Angriff: Du darfst 3 Schaden zufügen, die du nach Wahl auf feindliche Boden-Einheiten aufteilst.”",
52
+ "sourceLocale": "de",
53
+ "status": {
54
+ "kind": "source"
55
+ }
56
+ }
57
+ },
58
+ "6406": {
59
+ "attack": {
60
+ "plainText": "Du darfst mit der Einheit mit diesem Upgrade angreifen. (Sie kann nur angreifen, wenn sie spielbereit ist.)",
61
+ "sourceLocale": "de",
62
+ "status": {
63
+ "kind": "source"
64
+ }
65
+ },
66
+ "when-played": {
67
+ "plainText": "Wenn gespielt: Du darfst mit der Einheit mit diesem Upgrade angreifen. (Sie kann nur angreifen, wenn sie spielbereit ist.)",
68
+ "sourceLocale": "de",
69
+ "status": {
70
+ "kind": "source"
71
+ }
72
+ }
73
+ },
74
+ "19756": {
75
+ "heal": {
76
+ "plainText": "Du darfst 2 Schaden von einer Einheit heilen.",
77
+ "sourceLocale": "de",
78
+ "status": {
79
+ "kind": "source"
80
+ }
81
+ },
82
+ "piloting": {
83
+ "plainText": "Pilotieren [2 ressourcen Wachsamkeit] (Du darfst diese Karte als Upgrade an ein befreundetes Fahrzeug ohne angehängten Piloten spielen.)",
84
+ "sourceLocale": "de",
85
+ "status": {
86
+ "kind": "source"
87
+ }
88
+ },
89
+ "upgrade-play": {
90
+ "plainText": "Wenn als Upgrade gespielt: Du darfst 2 Schaden von einer Einheit heilen.",
91
+ "sourceLocale": "de",
92
+ "status": {
93
+ "kind": "source"
94
+ }
95
+ }
96
+ },
97
+ "19801": {
98
+ "heal": {
99
+ "plainText": "Du darfst insgesamt 2 Schaden von beliebig vielen Einheiten heilen.",
100
+ "sourceLocale": "de",
101
+ "status": {
102
+ "kind": "source"
103
+ }
104
+ },
105
+ "on-attack": {
106
+ "plainText": "Die Einheit mit diesem Upgrade erhält:\n„Beim Angriff: Du darfst insgesamt 2 Schaden von beliebig vielen Einheiten heilen.“",
107
+ "sourceLocale": "de",
108
+ "status": {
109
+ "kind": "source"
110
+ }
111
+ },
112
+ "piloting": {
113
+ "plainText": "Pilotieren [1 ressource Wachsamkeit] ",
114
+ "sourceLocale": "de",
115
+ "status": {
116
+ "kind": "source"
117
+ }
118
+ }
119
+ }
120
+ }
121
+ }
@@ -0,0 +1,121 @@
1
+ {
2
+ "formatVersion": 1,
3
+ "locale": "en",
4
+ "cards": {
5
+ "942": {
6
+ "boost-first": {
7
+ "plainText": "Give a friendly unit +3/+3 for this phase.",
8
+ "sourceLocale": "en",
9
+ "status": {
10
+ "kind": "source"
11
+ }
12
+ },
13
+ "boost-second": {
14
+ "plainText": "Give another friendly unit +2/+2 for this phase.",
15
+ "sourceLocale": "en",
16
+ "status": {
17
+ "kind": "source"
18
+ }
19
+ },
20
+ "boost-third": {
21
+ "plainText": "Give a third friendly unit +1/+1 for this phase.",
22
+ "sourceLocale": "en",
23
+ "status": {
24
+ "kind": "source"
25
+ }
26
+ },
27
+ "resolve": {
28
+ "plainText": "Give a friendly unit +3/+3 for this phase.\n\nGive another friendly unit +2/+2 for this phase.\n\nGive a third friendly unit +1/+1 for this phase.",
29
+ "sourceLocale": "en",
30
+ "status": {
31
+ "kind": "source"
32
+ }
33
+ }
34
+ },
35
+ "6186": {
36
+ "attach-to": {
37
+ "plainText": "Attach to a non-Vehicle unit.",
38
+ "sourceLocale": "en",
39
+ "status": {
40
+ "kind": "source"
41
+ }
42
+ },
43
+ "damage": {
44
+ "plainText": "You may deal 3 damage divided as you choose among enemy ground units.",
45
+ "sourceLocale": "en",
46
+ "status": {
47
+ "kind": "source"
48
+ }
49
+ },
50
+ "on-attack": {
51
+ "plainText": "Attached unit gains: “On Attack: You may deal 3 damage divided as you choose among enemy ground units.”",
52
+ "sourceLocale": "en",
53
+ "status": {
54
+ "kind": "source"
55
+ }
56
+ }
57
+ },
58
+ "6406": {
59
+ "attack": {
60
+ "plainText": "You may attack with attached unit. (It can only attack if it's ready.)",
61
+ "sourceLocale": "en",
62
+ "status": {
63
+ "kind": "source"
64
+ }
65
+ },
66
+ "when-played": {
67
+ "plainText": "When Played: You may attack with attached unit. (It can only attack if it's ready.)",
68
+ "sourceLocale": "en",
69
+ "status": {
70
+ "kind": "source"
71
+ }
72
+ }
73
+ },
74
+ "19756": {
75
+ "heal": {
76
+ "plainText": "You may heal 2 damage from a unit.",
77
+ "sourceLocale": "en",
78
+ "status": {
79
+ "kind": "source"
80
+ }
81
+ },
82
+ "piloting": {
83
+ "plainText": "Piloting [2 resources Vigilance] (You may play this as an upgrade on a friendly Vehicle without a Pilot.)",
84
+ "sourceLocale": "en",
85
+ "status": {
86
+ "kind": "source"
87
+ }
88
+ },
89
+ "upgrade-play": {
90
+ "plainText": "When played as an upgrade: You may heal 2 damage from a unit.",
91
+ "sourceLocale": "en",
92
+ "status": {
93
+ "kind": "source"
94
+ }
95
+ }
96
+ },
97
+ "19801": {
98
+ "heal": {
99
+ "plainText": "You may heal 2 total damage from any number of units.",
100
+ "sourceLocale": "en",
101
+ "status": {
102
+ "kind": "source"
103
+ }
104
+ },
105
+ "on-attack": {
106
+ "plainText": "Attached unit gains: “On Attack: You may heal 2 total damage from any number of units.”",
107
+ "sourceLocale": "en",
108
+ "status": {
109
+ "kind": "source"
110
+ }
111
+ },
112
+ "piloting": {
113
+ "plainText": "Piloting [1 resource Vigilance] (You may play this as an upgrade on a friendly Vehicle without a Pilot.)",
114
+ "sourceLocale": "en",
115
+ "status": {
116
+ "kind": "source"
117
+ }
118
+ }
119
+ }
120
+ }
121
+ }