@my-swu/simulator-client 0.1.2 → 0.1.4
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/README.md +1 -1
- package/dist/connection.js +2 -3
- package/dist/generated/index.d.ts +10 -0
- package/dist/generated/schemas.d.ts +1 -1
- package/dist/generated/schemas.js +466 -59
- package/dist/generated/types/admin-match-debug-bundle.d.ts +1 -0
- package/dist/generated/types/admin-match-debug-bundle.js +2 -0
- package/dist/generated/types/admin-match-list-response.d.ts +1 -0
- package/dist/generated/types/admin-match-list-response.js +2 -0
- package/dist/generated/types/admin-match-replay-response.d.ts +1 -0
- package/dist/generated/types/admin-match-replay-response.js +2 -0
- package/dist/generated/types/common.d.ts +143 -15
- package/dist/generated/types/create-match-history-replay-share-request.d.ts +1 -0
- package/dist/generated/types/create-match-history-replay-share-request.js +2 -0
- package/dist/generated/types/create-match-history-replay-share-response.d.ts +1 -0
- package/dist/generated/types/create-match-history-replay-share-response.js +2 -0
- package/dist/generated/types/inactive-match-recovery-request.d.ts +1 -0
- package/dist/generated/types/inactive-match-recovery-request.js +2 -0
- package/dist/generated/types/inactive-match-recovery-response.d.ts +1 -0
- package/dist/generated/types/inactive-match-recovery-response.js +2 -0
- package/dist/generated/types/match-access-recovery-request.d.ts +1 -0
- package/dist/generated/types/match-access-recovery-request.js +2 -0
- package/dist/generated/types/match-access-recovery-response.d.ts +1 -0
- package/dist/generated/types/match-access-recovery-response.js +2 -0
- package/dist/generated/types/match-recovery-request.d.ts +1 -0
- package/dist/generated/types/match-recovery-request.js +2 -0
- package/dist/generated/types/match-recovery-response.d.ts +1 -0
- package/dist/generated/types/match-recovery-response.js +2 -0
- package/dist/generated/types/shared-match-history-replay-response.d.ts +1 -0
- package/dist/generated/types/shared-match-history-replay-response.js +2 -0
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/internal/match-history.d.ts +5 -0
- package/dist/internal/match-history.js +8 -0
- package/dist/local/engine.d.ts +2 -0
- package/dist/local/server/http-router.js +10 -0
- package/dist/local/wasm-engine.d.ts +1 -0
- package/dist/local/wasm-engine.js +1 -0
- package/dist/match-session/controller.d.ts +2 -0
- package/dist/match-session/controller.js +59 -17
- package/dist/match-session/methods.d.ts +8 -0
- package/dist/match-session/session-state.d.ts +5 -1
- package/dist/match-session/types.d.ts +3 -1
- package/dist/match-session.d.ts +1 -1
- package/dist/resources/admin.d.ts +14 -1
- package/dist/resources/admin.js +21 -0
- package/dist/resources/lobby-types.d.ts +4 -4
- package/dist/resources/match-history.d.ts +14 -1
- package/dist/resources/match-history.js +16 -0
- package/dist/resources/match-types.d.ts +11 -2
- package/dist/resources/matches.js +10 -0
- package/dist/validators.d.ts +11 -1
- package/package.json +1 -1
- package/schema/add-lobby-ai-player-request.schema.json +7 -0
- package/schema/admin-match-debug-bundle.schema.json +48 -0
- package/schema/admin-match-list-response.schema.json +23 -0
- package/schema/admin-match-replay-response.schema.json +14 -0
- package/schema/common.schema.json +176 -27
- package/schema/create-limited-event-request.schema.json +2 -4
- package/schema/create-lobby-request.schema.json +4 -8
- package/schema/create-match-history-replay-share-request.schema.json +22 -0
- package/schema/create-match-history-replay-share-response.schema.json +15 -0
- package/schema/create-match-request.schema.json +2 -3
- package/schema/create-tournament-room-request.schema.json +4 -8
- package/schema/limited-event-preflight-response.schema.json +1 -3
- package/schema/manifest.json +11 -1
- package/schema/match-access-recovery-request.schema.json +17 -0
- package/schema/match-access-recovery-response.schema.json +36 -0
- package/schema/match-access-response.schema.json +1 -3
- package/schema/match-history-entry.schema.json +1 -3
- package/schema/match-recovery-request.schema.json +33 -0
- package/schema/match-recovery-response.schema.json +36 -0
- package/schema/route-manifest.json +92 -0
- package/schema/shared-match-history-replay-response.schema.json +14 -0
|
@@ -2,6 +2,7 @@ import { MatchConnection } from '../connection.js';
|
|
|
2
2
|
import { TypedEmitter } from '../internal/emitter.js';
|
|
3
3
|
import { formatErrorMessages } from '../internal/errors.js';
|
|
4
4
|
import { DEFAULT_ERROR_HISTORY_LIMIT, DEFAULT_MATCH_HISTORY_LIMIT } from '../internal/limits.js';
|
|
5
|
+
import { upsertMatchHistoryEntry } from '../internal/match-history.js';
|
|
5
6
|
import { nonNegativeNumber, normalizeReconnectBackoff, reconnectDelayMs, } from '../internal/reconnect-backoff.js';
|
|
6
7
|
import { createMatchSessionHeartbeat } from './heartbeat.js';
|
|
7
8
|
import { hasAccessSnapshot, matchReferenceFrom } from './access.js';
|
|
@@ -91,6 +92,9 @@ export class MatchSessionController {
|
|
|
91
92
|
get reconnectState() {
|
|
92
93
|
return this.#reconnectState;
|
|
93
94
|
}
|
|
95
|
+
get snapshotRevision() {
|
|
96
|
+
return this.#connection?.snapshotRevision ?? 0;
|
|
97
|
+
}
|
|
94
98
|
get snapshot() {
|
|
95
99
|
return this.#snapshot;
|
|
96
100
|
}
|
|
@@ -207,6 +211,21 @@ export class MatchSessionController {
|
|
|
207
211
|
reconnect(options = {}) {
|
|
208
212
|
return this.connect(undefined, options);
|
|
209
213
|
}
|
|
214
|
+
recoverNow() {
|
|
215
|
+
if (this.#manualClose || !this.#autoReconnect.enabled || this.#access == null) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
this.#reconnectGeneration += 1;
|
|
219
|
+
if (this.#reconnectTimer != null) {
|
|
220
|
+
clearTimeout(this.#reconnectTimer);
|
|
221
|
+
this.#reconnectTimer = undefined;
|
|
222
|
+
}
|
|
223
|
+
// Detach before close so this intentional foreground replacement cannot
|
|
224
|
+
// schedule a duplicate close-driven retry.
|
|
225
|
+
this.#closeActiveConnection();
|
|
226
|
+
this.#setConnectionState('closed');
|
|
227
|
+
void this.#runAutoReconnectAttempt(1, this.#reconnectGeneration);
|
|
228
|
+
}
|
|
210
229
|
ready() {
|
|
211
230
|
this.#activeConnection().ready();
|
|
212
231
|
}
|
|
@@ -333,8 +352,7 @@ export class MatchSessionController {
|
|
|
333
352
|
this.#emitChange();
|
|
334
353
|
}
|
|
335
354
|
#recordHistoryEntry(entry) {
|
|
336
|
-
|
|
337
|
-
this.#history = [...withoutDuplicate, entry].slice(-DEFAULT_MATCH_HISTORY_LIMIT);
|
|
355
|
+
this.#history = upsertMatchHistoryEntry(this.#history, entry);
|
|
338
356
|
this.#emitter.emit('historyEntry', entry);
|
|
339
357
|
this.#emitChange();
|
|
340
358
|
}
|
|
@@ -368,15 +386,18 @@ export class MatchSessionController {
|
|
|
368
386
|
}
|
|
369
387
|
#scheduleAutoReconnect(attempt, generation) {
|
|
370
388
|
if (attempt > this.#autoReconnect.maxRetries) {
|
|
389
|
+
const error = {
|
|
390
|
+
code: 'sdk_session_error',
|
|
391
|
+
message: 'automatic reconnect exhausted',
|
|
392
|
+
};
|
|
371
393
|
this.#setReconnectState({
|
|
372
|
-
phase: '
|
|
394
|
+
phase: 'terminal',
|
|
373
395
|
attempts: this.#autoReconnect.maxRetries,
|
|
374
396
|
maxAttempts: this.#autoReconnect.maxRetries,
|
|
397
|
+
cause: 'retriesExhausted',
|
|
398
|
+
error,
|
|
375
399
|
});
|
|
376
|
-
this.#recordError(
|
|
377
|
-
code: 'sdk_session_error',
|
|
378
|
-
message: 'automatic reconnect exhausted',
|
|
379
|
-
});
|
|
400
|
+
this.#recordError(error);
|
|
380
401
|
return;
|
|
381
402
|
}
|
|
382
403
|
const delayMs = reconnectDelayMs(this.#autoReconnect, attempt);
|
|
@@ -418,17 +439,23 @@ export class MatchSessionController {
|
|
|
418
439
|
if (generation !== this.#reconnectGeneration || this.#manualClose) {
|
|
419
440
|
return;
|
|
420
441
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
442
|
+
const payload = errorPayloadFromUnknown(error);
|
|
443
|
+
const cause = terminalCauseForError(payload);
|
|
444
|
+
if (cause != null || attempt >= this.#autoReconnect.maxRetries) {
|
|
445
|
+
const terminalError = cause == null
|
|
446
|
+
? {
|
|
447
|
+
code: 'sdk_session_error',
|
|
448
|
+
message: 'automatic reconnect exhausted',
|
|
449
|
+
}
|
|
450
|
+
: payload;
|
|
427
451
|
this.#setReconnectState({
|
|
428
|
-
phase: '
|
|
452
|
+
phase: 'terminal',
|
|
429
453
|
attempts: attempt,
|
|
430
454
|
maxAttempts: this.#autoReconnect.maxRetries,
|
|
455
|
+
cause: cause ?? 'retriesExhausted',
|
|
456
|
+
error: terminalError,
|
|
431
457
|
});
|
|
458
|
+
this.#recordError(terminalError);
|
|
432
459
|
this.#setConnectionState('closed');
|
|
433
460
|
return;
|
|
434
461
|
}
|
|
@@ -556,9 +583,24 @@ function sameReconnectState(left, right) {
|
|
|
556
583
|
return right.phase === 'connecting'
|
|
557
584
|
&& left.attempt === right.attempt
|
|
558
585
|
&& left.maxAttempts === right.maxAttempts;
|
|
559
|
-
case '
|
|
560
|
-
return right.phase === '
|
|
586
|
+
case 'terminal':
|
|
587
|
+
return right.phase === 'terminal'
|
|
561
588
|
&& left.attempts === right.attempts
|
|
562
|
-
&& left.maxAttempts === right.maxAttempts
|
|
589
|
+
&& left.maxAttempts === right.maxAttempts
|
|
590
|
+
&& left.cause === right.cause
|
|
591
|
+
&& left.error.code === right.error.code
|
|
592
|
+
&& left.error.message === right.error.message;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
/** Maps definitive server rejections to terminal causes without parsing text. */
|
|
596
|
+
function terminalCauseForError(error) {
|
|
597
|
+
switch (error.code) {
|
|
598
|
+
case 'match_not_found':
|
|
599
|
+
return 'matchNotFound';
|
|
600
|
+
case 'invalid_seat_token':
|
|
601
|
+
case 'invalid_spectator_token':
|
|
602
|
+
return 'invalidCredentials';
|
|
603
|
+
default:
|
|
604
|
+
return undefined;
|
|
563
605
|
}
|
|
564
606
|
}
|
|
@@ -159,6 +159,14 @@ export interface MatchSessionMethods {
|
|
|
159
159
|
* @see https://simulator-sdk.my-swu.com/guide/reconnect
|
|
160
160
|
*/
|
|
161
161
|
reconnect(options?: MatchSessionConnectOptions): Promise<MatchSession>;
|
|
162
|
+
/**
|
|
163
|
+
* Immediately starts session-owned automatic recovery using stored access.
|
|
164
|
+
*
|
|
165
|
+
* This is intended for foreground restoration: it preserves automatic
|
|
166
|
+
* backoff after a failed dial instead of turning recovery into a one-shot
|
|
167
|
+
* manual reconnect.
|
|
168
|
+
*/
|
|
169
|
+
recoverNow(): void;
|
|
162
170
|
/**
|
|
163
171
|
* Sends one ready message for the current seat.
|
|
164
172
|
*
|
|
@@ -132,10 +132,14 @@ export type MatchSessionReconnectState = {
|
|
|
132
132
|
attempt: number;
|
|
133
133
|
maxAttempts: number;
|
|
134
134
|
} | {
|
|
135
|
-
phase: '
|
|
135
|
+
phase: 'terminal';
|
|
136
136
|
attempts: number;
|
|
137
137
|
maxAttempts: number;
|
|
138
|
+
cause: MatchSessionTerminalCause;
|
|
139
|
+
error: ErrorPayload;
|
|
138
140
|
};
|
|
141
|
+
/** Server or transport condition which stopped automatic reconnect retries. */
|
|
142
|
+
export type MatchSessionTerminalCause = 'matchNotFound' | 'invalidCredentials' | 'retriesExhausted';
|
|
139
143
|
/**
|
|
140
144
|
* Options for creating one SDK-owned match session.
|
|
141
145
|
*
|
|
@@ -3,7 +3,7 @@ import type { MatchHistoryFeedEntry } from '../generated/types/server-message.js
|
|
|
3
3
|
import type { ConnectionState } from '../session.js';
|
|
4
4
|
import type { MatchSessionMethods } from './methods.js';
|
|
5
5
|
import type { MatchSeat, MatchSessionReconnectState, MatchSessionState } from './session-state.js';
|
|
6
|
-
export type { MatchSeat, MatchSessionAccess, MatchSessionAutoReconnectOptions, MatchSessionAutoReconnectPolicy, MatchSessionConnectOptions, MatchSessionEvents, MatchSessionHeartbeatOptions, MatchSessionHeartbeatPolicy, MatchSessionOptions, MatchSessionReconnectState, MatchSessionSnapshotPredicate, MatchSessionState, MatchSessionWaitOptions, } from './session-state.js';
|
|
6
|
+
export type { MatchSeat, MatchSessionAccess, MatchSessionAutoReconnectOptions, MatchSessionAutoReconnectPolicy, MatchSessionConnectOptions, MatchSessionEvents, MatchSessionHeartbeatOptions, MatchSessionHeartbeatPolicy, MatchSessionOptions, MatchSessionReconnectState, MatchSessionSnapshotPredicate, MatchSessionState, MatchSessionTerminalCause, MatchSessionWaitOptions, } from './session-state.js';
|
|
7
7
|
/**
|
|
8
8
|
* Main ergonomic SDK API for interacting with one live match.
|
|
9
9
|
*
|
|
@@ -45,6 +45,8 @@ export interface MatchSession extends MatchSessionMethods {
|
|
|
45
45
|
readonly matchId: string | undefined;
|
|
46
46
|
/** Automatic reconnect progress after an abnormal socket close. */
|
|
47
47
|
readonly reconnectState: MatchSessionReconnectState;
|
|
48
|
+
/** Monotonic revision of the latest authoritative match snapshot. */
|
|
49
|
+
readonly snapshotRevision: number;
|
|
48
50
|
/** Latest authoritative private snapshot for this seat. */
|
|
49
51
|
readonly snapshot: GameState | undefined;
|
|
50
52
|
/** Seat controlled by this session when known. */
|
package/dist/match-session.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { MatchSessionController } from './match-session/controller.js';
|
|
2
2
|
export type { MatchSessionControllerOptions } from './match-session/controller.js';
|
|
3
|
-
export type { MatchSeat, MatchSession, MatchSessionAccess, MatchSessionAutoReconnectOptions, MatchSessionAutoReconnectPolicy, MatchSessionConnectOptions, MatchSessionEvents, MatchSessionHeartbeatOptions, MatchSessionHeartbeatPolicy, MatchSessionOptions, MatchSessionReconnectState, MatchSessionSnapshotPredicate, MatchSessionState, MatchSessionWaitOptions, } from './match-session/types.js';
|
|
3
|
+
export type { MatchSeat, MatchSession, MatchSessionAccess, MatchSessionAutoReconnectOptions, MatchSessionAutoReconnectPolicy, MatchSessionConnectOptions, MatchSessionEvents, MatchSessionHeartbeatOptions, MatchSessionHeartbeatPolicy, MatchSessionOptions, MatchSessionReconnectState, MatchSessionTerminalCause, MatchSessionSnapshotPredicate, MatchSessionState, MatchSessionWaitOptions, } from './match-session/types.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SimulatorReportListResponse, SimulatorReportResponse, CardCatalogRefreshResponse, CreateMetaWindowRequest, MatchChatLookupResponse, MetaWindowsResponse, RankedLeaderboardQuery, RankedLeaderboardResponse, RankedProfileRequest, RankedProfileResponse, SetRankedAdmissionRequest, SetSimulatorMaintenanceRequest, SimulatorAdminStatusResponse } from '../generated/index.js';
|
|
1
|
+
import type { AdminMatchDebugBundle, AdminMatchListResponse, AdminMatchReplayResponse, SimulatorReportListResponse, SimulatorReportResponse, CardCatalogRefreshResponse, CreateMetaWindowRequest, MatchChatLookupResponse, MetaWindowsResponse, RankedLeaderboardQuery, RankedLeaderboardResponse, RankedProfileRequest, RankedProfileResponse, SetRankedAdmissionRequest, SetSimulatorMaintenanceRequest, SimulatorAdminStatusResponse } from '../generated/index.js';
|
|
2
2
|
import type { SimulatorRequestOptions } from '../http/options.js';
|
|
3
3
|
import type { EngineHttpRequester } from '../http/request.js';
|
|
4
4
|
/**
|
|
@@ -10,6 +10,13 @@ export interface SimulatorReportListOptions {
|
|
|
10
10
|
cursor?: string;
|
|
11
11
|
limit?: number;
|
|
12
12
|
}
|
|
13
|
+
/** Filters and cursor pagination controls for durable simulator admin games. */
|
|
14
|
+
export interface AdminGameListOptions {
|
|
15
|
+
matchId?: string;
|
|
16
|
+
playerSearch?: string;
|
|
17
|
+
cursor?: string;
|
|
18
|
+
limit?: number;
|
|
19
|
+
}
|
|
13
20
|
/**
|
|
14
21
|
* Bearer-token credentials for simulator admin calls.
|
|
15
22
|
*/
|
|
@@ -23,6 +30,12 @@ export interface SimulatorAdminAuth {
|
|
|
23
30
|
* Simulator administration API methods.
|
|
24
31
|
*/
|
|
25
32
|
export interface AdminResource {
|
|
33
|
+
/** Lists durable saved and completed matches for simulator support work. */
|
|
34
|
+
listGames(auth: SimulatorAdminAuth, query?: AdminGameListOptions, options?: SimulatorRequestOptions): Promise<AdminMatchListResponse>;
|
|
35
|
+
/** Returns all durable diagnostics for one match with restore credentials removed. */
|
|
36
|
+
getGameDebugBundle(auth: SimulatorAdminAuth, historyId: string, options?: SimulatorRequestOptions): Promise<AdminMatchDebugBundle>;
|
|
37
|
+
/** Returns a completed replay archive for one match. */
|
|
38
|
+
getGameReplay(auth: SimulatorAdminAuth, historyId: string, options?: SimulatorRequestOptions): Promise<AdminMatchReplayResponse>;
|
|
26
39
|
/** Lists safe metadata for retained simulator diagnostic reports. */
|
|
27
40
|
listSimulatorReports(auth: SimulatorAdminAuth, query?: SimulatorReportListOptions, options?: SimulatorRequestOptions): Promise<SimulatorReportListResponse>;
|
|
28
41
|
/** Returns one full sanitized simulator support bundle. */
|
package/dist/resources/admin.js
CHANGED
|
@@ -4,6 +4,9 @@ import { jsonBody, jsonHeaders } from '../http/json.js';
|
|
|
4
4
|
*/
|
|
5
5
|
export function createAdminResource(requester) {
|
|
6
6
|
return {
|
|
7
|
+
listGames: (auth, query, options) => requester.request('admin-match-list-response', adminGamesPath(query ?? {}), { headers: authHeaders(auth) }, options),
|
|
8
|
+
getGameDebugBundle: (auth, historyId, options) => requester.request('admin-match-debug-bundle', `/api/admin/games/${encodeURIComponent(historyId)}/debug`, { headers: authHeaders(auth) }, options),
|
|
9
|
+
getGameReplay: (auth, historyId, options) => requester.request('admin-match-replay-response', `/api/admin/games/${encodeURIComponent(historyId)}/replay`, { headers: authHeaders(auth) }, options),
|
|
7
10
|
listSimulatorReports: (auth, query, options) => requester.request('simulator-report-list-response', simulatorReportsPath(query ?? {}), { headers: authHeaders(auth) }, options),
|
|
8
11
|
getSimulatorReport: (auth, reportId, options) => requester.request('simulator-report-response', `/api/admin/reports/${encodeURIComponent(reportId)}`, { headers: authHeaders(auth) }, options),
|
|
9
12
|
refreshCardCatalog: (auth, options) => requester.request('card-catalog-refresh-response', '/api/admin/card-catalog/refresh', { headers: authHeaders(auth), method: 'POST' }, options),
|
|
@@ -34,6 +37,24 @@ export function createAdminResource(requester) {
|
|
|
34
37
|
rankedLeaderboard: (auth, windowId, query, options) => requester.request('ranked-leaderboard-response', leaderboardPath(requester, windowId, query ?? {}), { headers: authHeaders(auth) }, options),
|
|
35
38
|
};
|
|
36
39
|
}
|
|
40
|
+
/** Builds an encoded durable-game query without exposing the route shape. */
|
|
41
|
+
function adminGamesPath(options) {
|
|
42
|
+
const parameters = new URLSearchParams();
|
|
43
|
+
if (options.matchId) {
|
|
44
|
+
parameters.set('matchId', options.matchId);
|
|
45
|
+
}
|
|
46
|
+
if (options.playerSearch) {
|
|
47
|
+
parameters.set('playerSearch', options.playerSearch);
|
|
48
|
+
}
|
|
49
|
+
if (options.cursor) {
|
|
50
|
+
parameters.set('cursor', options.cursor);
|
|
51
|
+
}
|
|
52
|
+
if (options.limit != null) {
|
|
53
|
+
parameters.set('limit', String(options.limit));
|
|
54
|
+
}
|
|
55
|
+
const suffix = parameters.size === 0 ? '' : `?${parameters.toString()}`;
|
|
56
|
+
return `/api/admin/games${suffix}`;
|
|
57
|
+
}
|
|
37
58
|
/** Builds a report-list path without exposing pagination implementation. */
|
|
38
59
|
function simulatorReportsPath(options) {
|
|
39
60
|
const parameters = new URLSearchParams();
|
|
@@ -62,9 +62,9 @@ export type LobbyConfig = {
|
|
|
62
62
|
export interface CreateLobbyRequest {
|
|
63
63
|
config: LobbyConfig;
|
|
64
64
|
/** Fixed limited pack/leader seed. */
|
|
65
|
-
packSeed?:
|
|
65
|
+
packSeed?: string | null;
|
|
66
66
|
/** Fixed match seed reused for limited duel matches. */
|
|
67
|
-
matchSeed?:
|
|
67
|
+
matchSeed?: string | null;
|
|
68
68
|
/** Whether the lobby should appear in public browsing surfaces. */
|
|
69
69
|
visibility: LobbyVisibility;
|
|
70
70
|
hostName: string;
|
|
@@ -183,9 +183,9 @@ export interface LobbySnapshot {
|
|
|
183
183
|
visibility: LobbyVisibility;
|
|
184
184
|
config: LobbyConfig;
|
|
185
185
|
/** Fixed limited pack/leader seed when configured. */
|
|
186
|
-
packSeed?:
|
|
186
|
+
packSeed?: string | null;
|
|
187
187
|
/** Fixed match seed when configured. */
|
|
188
|
-
matchSeed?:
|
|
188
|
+
matchSeed?: string | null;
|
|
189
189
|
hostPlayerId: string;
|
|
190
190
|
requiredPlayerCount: number;
|
|
191
191
|
/** Absolute server deadline for the ready-lobby auto-start countdown. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { MatchHistoryDeckStatsRequest, MatchHistoryDeckStatsResponse, MatchHistoryListRequest, MatchHistoryListResponse, MatchHistoryReplayRequest, MatchHistoryReplayResponse, MatchHistoryRestoreRequest, RestoreHistoryResponse } from '../generated/index.js';
|
|
1
|
+
import type { CreateMatchHistoryReplayShareRequest, CreateMatchHistoryReplayShareResponse, MatchRecoveryRequest, MatchRecoveryResponse, MatchHistoryDeckStatsRequest, MatchHistoryDeckStatsResponse, MatchHistoryListRequest, MatchHistoryListResponse, MatchHistoryReplayRequest, MatchHistoryReplayResponse, MatchHistoryRestoreRequest, RestoreHistoryResponse, SharedMatchHistoryReplayResponse } from '../generated/index.js';
|
|
2
2
|
import type { SimulatorRequestOptions } from '../http/options.js';
|
|
3
3
|
import type { EngineHttpRequester } from '../http/request.js';
|
|
4
4
|
/**
|
|
@@ -10,11 +10,18 @@ export interface MatchHistoryRestoreInput extends MatchHistoryRestoreRequest {
|
|
|
10
10
|
*/
|
|
11
11
|
historyId: string;
|
|
12
12
|
}
|
|
13
|
+
/** Recovery request for a source runtime that is no longer available. */
|
|
14
|
+
export type MatchRecoveryInput = MatchRecoveryRequest;
|
|
13
15
|
/** Request used to load a completed server-side replay archive. */
|
|
14
16
|
export interface MatchHistoryReplayInput extends MatchHistoryReplayRequest {
|
|
15
17
|
/** Durable history row id returned by {@link MatchHistoryResource.list}. */
|
|
16
18
|
historyId: string;
|
|
17
19
|
}
|
|
20
|
+
/** Participant-authorized request that creates one scoped replay-share link. */
|
|
21
|
+
export interface CreateMatchHistoryReplayShareInput extends CreateMatchHistoryReplayShareRequest {
|
|
22
|
+
/** Durable history row id returned by {@link MatchHistoryResource.list}. */
|
|
23
|
+
historyId: string;
|
|
24
|
+
}
|
|
18
25
|
/**
|
|
19
26
|
* Server-owned simulator history APIs.
|
|
20
27
|
*/
|
|
@@ -29,10 +36,16 @@ export interface MatchHistoryResource {
|
|
|
29
36
|
list(request: MatchHistoryListRequest, options?: SimulatorRequestOptions): Promise<MatchHistoryListResponse>;
|
|
30
37
|
/** Loads public and post-game reveal-all frames for an authorized result. */
|
|
31
38
|
replay(request: MatchHistoryReplayInput, options?: SimulatorRequestOptions): Promise<MatchHistoryReplayResponse>;
|
|
39
|
+
/** Creates or returns a stable opaque replay link for one disclosure scope. */
|
|
40
|
+
createReplayShare(request: CreateMatchHistoryReplayShareInput, options?: SimulatorRequestOptions): Promise<CreateMatchHistoryReplayShareResponse>;
|
|
41
|
+
/** Loads a replay through an opaque link without participant identities. */
|
|
42
|
+
loadReplayShare(shareToken: string, options?: SimulatorRequestOptions): Promise<SharedMatchHistoryReplayResponse>;
|
|
32
43
|
/**
|
|
33
44
|
* Restores one authorized row whose eligibility is `available`.
|
|
34
45
|
*/
|
|
35
46
|
restore(request: MatchHistoryRestoreInput, options?: SimulatorRequestOptions): Promise<RestoreHistoryResponse>;
|
|
47
|
+
/** Restores an owned Solo-versus-AI source after its runtime is lost. */
|
|
48
|
+
recover(request: MatchRecoveryInput, options?: SimulatorRequestOptions): Promise<MatchRecoveryResponse>;
|
|
36
49
|
}
|
|
37
50
|
/**
|
|
38
51
|
* Dependencies needed by the match-history resource.
|
|
@@ -22,6 +22,17 @@ export function createMatchHistoryResource(options) {
|
|
|
22
22
|
headers: jsonHeaders(),
|
|
23
23
|
method: 'POST',
|
|
24
24
|
}, options),
|
|
25
|
+
createReplayShare: (request, options) => requester.request('create-match-history-replay-share-response', `/api/match-history/${request.historyId}/replay-shares`, {
|
|
26
|
+
body: jsonBody(requester.validate('create-match-history-replay-share-request', {
|
|
27
|
+
identities: request.identities,
|
|
28
|
+
includeHiddenInformation: request.includeHiddenInformation,
|
|
29
|
+
})),
|
|
30
|
+
headers: jsonHeaders(),
|
|
31
|
+
method: 'POST',
|
|
32
|
+
}, options),
|
|
33
|
+
loadReplayShare: (shareToken, options) => requester.request('shared-match-history-replay-response', `/api/match-history/replay-shares/${shareToken}`, {
|
|
34
|
+
method: 'GET',
|
|
35
|
+
}, options),
|
|
25
36
|
restore: (request, options) => requester.request('restore-history-response', `/api/match-history/${request.historyId}/restore`, {
|
|
26
37
|
body: jsonBody(requester.validate('match-history-restore-request', {
|
|
27
38
|
identities: request.identities,
|
|
@@ -30,5 +41,10 @@ export function createMatchHistoryResource(options) {
|
|
|
30
41
|
headers: jsonHeaders(),
|
|
31
42
|
method: 'POST',
|
|
32
43
|
}, options),
|
|
44
|
+
recover: (request, options) => requester.request('match-recovery-response', '/api/match-history/recover', {
|
|
45
|
+
body: jsonBody(requester.validate('match-recovery-request', request)),
|
|
46
|
+
headers: jsonHeaders(),
|
|
47
|
+
method: 'POST',
|
|
48
|
+
}, options),
|
|
33
49
|
};
|
|
34
50
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AiStatusPayload, CreateMatchRequest, GameState, JoinMatchRequest, ListActiveAiMatchesRequest, ListActiveAiMatchesResponse, MatchAccessResponse, MatchSpectatorAccessResponse, MatchSavePayload, RematchMatchResponse, RestoreMatchSaveResponse, SpectateMatchRequest, SubmitMatchDeckRequest } from '../generated/index.js';
|
|
1
|
+
import type { AiStatusPayload, CreateMatchRequest, GameState, JoinMatchRequest, ListActiveAiMatchesRequest, ListActiveAiMatchesResponse, MatchAccessRecoveryRequest, MatchAccessRecoveryResponse, MatchAccessResponse, MatchSpectatorAccessResponse, MatchSavePayload, RematchMatchResponse, RestoreMatchSaveResponse, SpectateMatchRequest, SubmitMatchDeckRequest } from '../generated/index.js';
|
|
2
2
|
import type { FormatEventCommand } from '../generated/types/format-event-request.js';
|
|
3
3
|
import type { SimulatorRequestOptions } from '../http/options.js';
|
|
4
4
|
/**
|
|
@@ -87,7 +87,7 @@ export interface MatchAccessInput extends MatchReference {
|
|
|
87
87
|
/**
|
|
88
88
|
* Resolved seed for a private solo-vs-AI match, retained across reconnects.
|
|
89
89
|
*/
|
|
90
|
-
replaySeed?:
|
|
90
|
+
replaySeed?: string;
|
|
91
91
|
}
|
|
92
92
|
export interface MatchSpectatorAccessInput extends MatchReference {
|
|
93
93
|
/**
|
|
@@ -134,6 +134,15 @@ export type MatchConnectionAccessInput = MatchAccessInput | MatchSpectatorAccess
|
|
|
134
134
|
* @see https://simulator-sdk.my-swu.com/guide/match-session
|
|
135
135
|
*/
|
|
136
136
|
export interface MatchesResource {
|
|
137
|
+
/** Refreshes private seat access after validating its existing seat token. */
|
|
138
|
+
refreshAccess(access: MatchAccessInput, options?: SimulatorRequestOptions): Promise<MatchAccess>;
|
|
139
|
+
/**
|
|
140
|
+
* Recovers current host access for an owned remote Solo-versus-AI match.
|
|
141
|
+
*
|
|
142
|
+
* `unavailable` intentionally hides whether the match is absent, no longer
|
|
143
|
+
* resumable, or not owned by the supplied history identities.
|
|
144
|
+
*/
|
|
145
|
+
recoverAccess(match: MatchReference, request: MatchAccessRecoveryRequest, options?: SimulatorRequestOptions): Promise<MatchAccessRecoveryResponse>;
|
|
137
146
|
/** Records an intentional player departure without conceding the match. */
|
|
138
147
|
leave(access: MatchAccessInput, options?: SimulatorRequestOptions): Promise<void>;
|
|
139
148
|
/**
|
|
@@ -5,6 +5,16 @@ import { jsonBody, jsonHeaders } from '../http/json.js';
|
|
|
5
5
|
export function createMatchesResource(options) {
|
|
6
6
|
const { requester } = options;
|
|
7
7
|
return {
|
|
8
|
+
refreshAccess: (access, requestOptions) => requester.request('match-access-response', `/api/matches/${matchIdFrom(access)}/access`, {
|
|
9
|
+
body: jsonBody(requester.validate('save-match-request', { seatToken: access.seatToken })),
|
|
10
|
+
headers: jsonHeaders(),
|
|
11
|
+
method: 'POST',
|
|
12
|
+
}, requestOptions),
|
|
13
|
+
recoverAccess: (match, request, options) => requester.request('match-access-recovery-response', `/api/matches/${matchIdFrom(match)}/recover-access`, {
|
|
14
|
+
body: jsonBody(requester.validate('match-access-recovery-request', request)),
|
|
15
|
+
headers: jsonHeaders(),
|
|
16
|
+
method: 'POST',
|
|
17
|
+
}, options),
|
|
8
18
|
leave: (access, options) => requester.request('leave-match-response', `/api/matches/${matchIdFrom(access)}/leave`, {
|
|
9
19
|
body: jsonBody(requester.validate('leave-match-request', { seatToken: access.seatToken })),
|
|
10
20
|
headers: jsonHeaders(),
|
package/dist/validators.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SimulatorReportListResponse, SimulatorReportResponse, CloseTournamentRoomRequest, AbandonMatchRequest, AbandonMatchResponse, AddLobbyAiPlayerRequest, ApiErrorResponse, CardCatalogRefreshResponse, CardsResponse, ClientMessage, CreateLimitedEventRequest, CreateLobbyRequest, CreateMetaWindowRequest, CreateMatchRequest, 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, MatchAccessResponse, MatchChatLookupResponse, MatchConnectionRole, MatchHistoryDeckStatsRequest, MatchHistoryDeckStatsResponse, MatchHistoryEntry, MatchHistoryListRequest, MatchHistoryListResponse, MatchHistoryReplayRequest, MatchHistoryReplayResponse, MatchHistoryRestoreRequest, RestoreHistoryResponse, MatchSavePayload, 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, 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, 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, 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, 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';
|
|
2
2
|
import type { SchemaValidator } from './validators/validator.js';
|
|
3
3
|
/**
|
|
4
4
|
* Exact schema-to-type map generated from Rust public wire contracts.
|
|
@@ -9,6 +9,9 @@ import type { SchemaValidator } from './validators/validator.js';
|
|
|
9
9
|
* @see https://simulator-sdk.my-swu.com/guide/versioning
|
|
10
10
|
*/
|
|
11
11
|
export interface SchemaTypeMap {
|
|
12
|
+
'admin-match-list-response': AdminMatchListResponse;
|
|
13
|
+
'admin-match-debug-bundle': AdminMatchDebugBundle;
|
|
14
|
+
'admin-match-replay-response': AdminMatchReplayResponse;
|
|
12
15
|
'simulator-report-list-response': SimulatorReportListResponse;
|
|
13
16
|
'simulator-report-response': SimulatorReportResponse;
|
|
14
17
|
'close-tournament-room-request': CloseTournamentRoomRequest;
|
|
@@ -69,8 +72,15 @@ export interface SchemaTypeMap {
|
|
|
69
72
|
'match-history-list-response': MatchHistoryListResponse;
|
|
70
73
|
'match-history-replay-request': MatchHistoryReplayRequest;
|
|
71
74
|
'match-history-replay-response': MatchHistoryReplayResponse;
|
|
75
|
+
'create-match-history-replay-share-request': CreateMatchHistoryReplayShareRequest;
|
|
76
|
+
'create-match-history-replay-share-response': CreateMatchHistoryReplayShareResponse;
|
|
77
|
+
'shared-match-history-replay-response': SharedMatchHistoryReplayResponse;
|
|
72
78
|
'match-history-restore-request': MatchHistoryRestoreRequest;
|
|
73
79
|
'restore-history-response': RestoreHistoryResponse;
|
|
80
|
+
'match-recovery-request': MatchRecoveryRequest;
|
|
81
|
+
'match-recovery-response': MatchRecoveryResponse;
|
|
82
|
+
'match-access-recovery-request': MatchAccessRecoveryRequest;
|
|
83
|
+
'match-access-recovery-response': MatchAccessRecoveryResponse;
|
|
74
84
|
'match-save-payload': MatchSavePayload;
|
|
75
85
|
'save-match-request': SaveMatchRequest;
|
|
76
86
|
'match-spectator-access-response': MatchSpectatorAccessResponse;
|
package/package.json
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
"title": "AddLobbyAiPlayerRequest",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
6
|
+
"accountToken": {
|
|
7
|
+
"description": "Signed app account proof required to create a server-controlled AI.",
|
|
8
|
+
"type": [
|
|
9
|
+
"string",
|
|
10
|
+
"null"
|
|
11
|
+
]
|
|
12
|
+
},
|
|
6
13
|
"deck": {
|
|
7
14
|
"$ref": "https://simulator-sdk.my-swu.com/schema/common.json#/$defs/DeckInput"
|
|
8
15
|
},
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "AdminMatchDebugBundle",
|
|
4
|
+
"description": "Complete durable diagnostics for one match, excluding restore credentials.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"exportVersion": {
|
|
8
|
+
"type": "integer",
|
|
9
|
+
"format": "uint8",
|
|
10
|
+
"maximum": 255,
|
|
11
|
+
"minimum": 0
|
|
12
|
+
},
|
|
13
|
+
"exportedAtMs": {
|
|
14
|
+
"type": "integer",
|
|
15
|
+
"format": "uint64",
|
|
16
|
+
"minimum": 0
|
|
17
|
+
},
|
|
18
|
+
"game": {
|
|
19
|
+
"$ref": "https://simulator-sdk.my-swu.com/schema/common.json#/$defs/AdminMatchSummary"
|
|
20
|
+
},
|
|
21
|
+
"replay": {
|
|
22
|
+
"anyOf": [
|
|
23
|
+
{
|
|
24
|
+
"$ref": "https://simulator-sdk.my-swu.com/schema/common.json#/$defs/MatchHistoryReplayArchive"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"type": "null"
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"reports": {
|
|
32
|
+
"type": "array",
|
|
33
|
+
"items": {
|
|
34
|
+
"$ref": "https://simulator-sdk.my-swu.com/schema/common.json#/$defs/SimulatorReportResponse"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"save": {
|
|
38
|
+
"$ref": "https://simulator-sdk.my-swu.com/schema/common.json#/$defs/MatchSavePayload"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"required": [
|
|
42
|
+
"exportVersion",
|
|
43
|
+
"exportedAtMs",
|
|
44
|
+
"game",
|
|
45
|
+
"save",
|
|
46
|
+
"reports"
|
|
47
|
+
]
|
|
48
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "AdminMatchListResponse",
|
|
4
|
+
"description": "Cursor-paginated durable match list for simulator administrators.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"games": {
|
|
8
|
+
"type": "array",
|
|
9
|
+
"items": {
|
|
10
|
+
"$ref": "https://simulator-sdk.my-swu.com/schema/common.json#/$defs/AdminMatchSummary"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"nextCursor": {
|
|
14
|
+
"type": [
|
|
15
|
+
"string",
|
|
16
|
+
"null"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"required": [
|
|
21
|
+
"games"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "AdminMatchReplayResponse",
|
|
4
|
+
"description": "Completed replay archive returned to an authenticated simulator administrator.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"archive": {
|
|
8
|
+
"$ref": "https://simulator-sdk.my-swu.com/schema/common.json#/$defs/MatchHistoryReplayArchive"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"required": [
|
|
12
|
+
"archive"
|
|
13
|
+
]
|
|
14
|
+
}
|