@my-swu/simulator-client 0.1.0
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/LICENSE +21 -0
- package/README.md +355 -0
- package/dist/actionable.d.ts +61 -0
- package/dist/actionable.js +91 -0
- package/dist/client.d.ts +157 -0
- package/dist/client.js +92 -0
- package/dist/connection/handshake.d.ts +30 -0
- package/dist/connection/handshake.js +62 -0
- package/dist/connection/options.d.ts +36 -0
- package/dist/connection/options.js +1 -0
- package/dist/connection/url.d.ts +55 -0
- package/dist/connection/url.js +46 -0
- package/dist/connection/wait.d.ts +22 -0
- package/dist/connection/wait.js +10 -0
- package/dist/connection.d.ts +110 -0
- package/dist/connection.js +358 -0
- package/dist/generated/index.d.ts +121 -0
- package/dist/generated/index.js +1 -0
- package/dist/generated/public-types.d.ts +2 -0
- package/dist/generated/public-types.js +1 -0
- package/dist/generated/schemas.d.ts +27 -0
- package/dist/generated/schemas.js +21264 -0
- package/dist/generated/types/abandon-match-request.d.ts +1 -0
- package/dist/generated/types/abandon-match-request.js +2 -0
- package/dist/generated/types/abandon-match-response.d.ts +1 -0
- package/dist/generated/types/abandon-match-response.js +2 -0
- package/dist/generated/types/add-lobby-ai-player-request.d.ts +1 -0
- package/dist/generated/types/add-lobby-ai-player-request.js +2 -0
- package/dist/generated/types/ai-driver-error-report-list-response.d.ts +1 -0
- package/dist/generated/types/ai-driver-error-report-list-response.js +2 -0
- package/dist/generated/types/ai-driver-error-report-response.d.ts +1 -0
- package/dist/generated/types/ai-driver-error-report-response.js +2 -0
- package/dist/generated/types/api-error-response.d.ts +1 -0
- package/dist/generated/types/api-error-response.js +2 -0
- package/dist/generated/types/card-catalog-refresh-response.d.ts +1 -0
- package/dist/generated/types/card-catalog-refresh-response.js +2 -0
- package/dist/generated/types/cards-response.d.ts +1 -0
- package/dist/generated/types/cards-response.js +2 -0
- package/dist/generated/types/client-message.d.ts +1 -0
- package/dist/generated/types/client-message.js +2 -0
- package/dist/generated/types/close-tournament-room-request.d.ts +1 -0
- package/dist/generated/types/close-tournament-room-request.js +2 -0
- package/dist/generated/types/common.d.ts +5361 -0
- package/dist/generated/types/common.js +2 -0
- package/dist/generated/types/covered-cards-response.d.ts +47 -0
- package/dist/generated/types/covered-cards-response.js +2 -0
- package/dist/generated/types/create-limited-event-request.d.ts +1 -0
- package/dist/generated/types/create-limited-event-request.js +2 -0
- package/dist/generated/types/create-lobby-request.d.ts +1 -0
- package/dist/generated/types/create-lobby-request.js +2 -0
- package/dist/generated/types/create-match-request.d.ts +1 -0
- package/dist/generated/types/create-match-request.js +2 -0
- package/dist/generated/types/create-meta-window-request.d.ts +1 -0
- package/dist/generated/types/create-meta-window-request.js +2 -0
- package/dist/generated/types/create-tournament-room-request.d.ts +1 -0
- package/dist/generated/types/create-tournament-room-request.js +2 -0
- package/dist/generated/types/create-tournament-table-request.d.ts +1 -0
- package/dist/generated/types/create-tournament-table-request.js +2 -0
- package/dist/generated/types/error-payload.d.ts +1 -0
- package/dist/generated/types/error-payload.js +2 -0
- package/dist/generated/types/format-event-request.d.ts +1 -0
- package/dist/generated/types/format-event-request.js +2 -0
- package/dist/generated/types/format-event-response.d.ts +1 -0
- package/dist/generated/types/format-event-response.js +2 -0
- package/dist/generated/types/game-command.d.ts +1 -0
- package/dist/generated/types/game-command.js +2 -0
- package/dist/generated/types/game-event.d.ts +1 -0
- package/dist/generated/types/game-event.js +2 -0
- package/dist/generated/types/game-state.d.ts +1 -0
- package/dist/generated/types/game-state.js +2 -0
- package/dist/generated/types/get-match-response.d.ts +1 -0
- package/dist/generated/types/get-match-response.js +2 -0
- package/dist/generated/types/health-response.d.ts +1 -0
- package/dist/generated/types/health-response.js +2 -0
- package/dist/generated/types/join-limited-event-request.d.ts +1 -0
- package/dist/generated/types/join-limited-event-request.js +2 -0
- package/dist/generated/types/join-lobby-request.d.ts +1 -0
- package/dist/generated/types/join-lobby-request.js +2 -0
- package/dist/generated/types/join-match-request.d.ts +1 -0
- package/dist/generated/types/join-match-request.js +2 -0
- package/dist/generated/types/join-tournament-room-request.d.ts +1 -0
- package/dist/generated/types/join-tournament-room-request.js +2 -0
- package/dist/generated/types/join-tournament-table-request.d.ts +1 -0
- package/dist/generated/types/join-tournament-table-request.js +2 -0
- package/dist/generated/types/kick-lobby-player-request.d.ts +1 -0
- package/dist/generated/types/kick-lobby-player-request.js +2 -0
- package/dist/generated/types/kick-lobby-spectator-request.d.ts +1 -0
- package/dist/generated/types/kick-lobby-spectator-request.js +2 -0
- package/dist/generated/types/leave-lobby-request.d.ts +1 -0
- package/dist/generated/types/leave-lobby-request.js +2 -0
- package/dist/generated/types/leave-match-request.d.ts +1 -0
- package/dist/generated/types/leave-match-request.js +2 -0
- package/dist/generated/types/leave-match-response.d.ts +1 -0
- package/dist/generated/types/leave-match-response.js +2 -0
- package/dist/generated/types/leave-tournament-room-request.d.ts +1 -0
- package/dist/generated/types/leave-tournament-room-request.js +2 -0
- package/dist/generated/types/limited-event-access-response.d.ts +1 -0
- package/dist/generated/types/limited-event-access-response.js +2 -0
- package/dist/generated/types/limited-event-command-request.d.ts +1 -0
- package/dist/generated/types/limited-event-command-request.js +2 -0
- package/dist/generated/types/limited-event-preflight-response.d.ts +1 -0
- package/dist/generated/types/limited-event-preflight-response.js +2 -0
- package/dist/generated/types/limited-event-response.d.ts +1 -0
- package/dist/generated/types/limited-event-response.js +2 -0
- package/dist/generated/types/list-active-ai-matches-request.d.ts +1 -0
- package/dist/generated/types/list-active-ai-matches-request.js +2 -0
- package/dist/generated/types/list-active-ai-matches-response.d.ts +1 -0
- package/dist/generated/types/list-active-ai-matches-response.js +2 -0
- package/dist/generated/types/lobby-access-response.d.ts +1 -0
- package/dist/generated/types/lobby-access-response.js +2 -0
- package/dist/generated/types/lobby-chat-request.d.ts +1 -0
- package/dist/generated/types/lobby-chat-request.js +2 -0
- package/dist/generated/types/lobby-chat-response.d.ts +1 -0
- package/dist/generated/types/lobby-chat-response.js +2 -0
- package/dist/generated/types/lobby-list-response.d.ts +1 -0
- package/dist/generated/types/lobby-list-response.js +2 -0
- package/dist/generated/types/lobby-list-server-message.d.ts +1 -0
- package/dist/generated/types/lobby-list-server-message.js +2 -0
- package/dist/generated/types/lobby-matchmaking-decision-request.d.ts +1 -0
- package/dist/generated/types/lobby-matchmaking-decision-request.js +2 -0
- package/dist/generated/types/lobby-matchmaking-request.d.ts +1 -0
- package/dist/generated/types/lobby-matchmaking-request.js +2 -0
- package/dist/generated/types/lobby-response.d.ts +1 -0
- package/dist/generated/types/lobby-response.js +2 -0
- package/dist/generated/types/lobby-server-message.d.ts +1 -0
- package/dist/generated/types/lobby-server-message.js +2 -0
- package/dist/generated/types/lobby-sync-request.d.ts +1 -0
- package/dist/generated/types/lobby-sync-request.js +2 -0
- package/dist/generated/types/match-access-response.d.ts +1 -0
- package/dist/generated/types/match-access-response.js +2 -0
- package/dist/generated/types/match-chat-lookup-response.d.ts +1 -0
- package/dist/generated/types/match-chat-lookup-response.js +2 -0
- package/dist/generated/types/match-connection-role.d.ts +1 -0
- package/dist/generated/types/match-connection-role.js +2 -0
- package/dist/generated/types/match-history-deck-stats-request.d.ts +1 -0
- package/dist/generated/types/match-history-deck-stats-request.js +2 -0
- package/dist/generated/types/match-history-deck-stats-response.d.ts +1 -0
- package/dist/generated/types/match-history-deck-stats-response.js +2 -0
- package/dist/generated/types/match-history-entry.d.ts +1 -0
- package/dist/generated/types/match-history-entry.js +2 -0
- package/dist/generated/types/match-history-list-request.d.ts +1 -0
- package/dist/generated/types/match-history-list-request.js +2 -0
- package/dist/generated/types/match-history-list-response.d.ts +1 -0
- package/dist/generated/types/match-history-list-response.js +2 -0
- package/dist/generated/types/match-history-replay-request.d.ts +1 -0
- package/dist/generated/types/match-history-replay-request.js +2 -0
- package/dist/generated/types/match-history-replay-response.d.ts +1 -0
- package/dist/generated/types/match-history-replay-response.js +2 -0
- package/dist/generated/types/match-history-restore-request.d.ts +1 -0
- package/dist/generated/types/match-history-restore-request.js +2 -0
- package/dist/generated/types/match-save-payload.d.ts +1 -0
- package/dist/generated/types/match-save-payload.js +2 -0
- package/dist/generated/types/match-spectator-access-response.d.ts +1 -0
- package/dist/generated/types/match-spectator-access-response.js +2 -0
- package/dist/generated/types/meta-window.d.ts +1 -0
- package/dist/generated/types/meta-window.js +2 -0
- package/dist/generated/types/meta-windows-response.d.ts +1 -0
- package/dist/generated/types/meta-windows-response.js +2 -0
- package/dist/generated/types/prepare-lobby-limited-ai-decks-request.d.ts +1 -0
- package/dist/generated/types/prepare-lobby-limited-ai-decks-request.js +2 -0
- package/dist/generated/types/random-lobby-matchmaking-request.d.ts +173 -0
- package/dist/generated/types/random-lobby-matchmaking-request.js +2 -0
- package/dist/generated/types/ranked-admin-status.d.ts +1 -0
- package/dist/generated/types/ranked-admin-status.js +2 -0
- package/dist/generated/types/ranked-leaderboard-entry.d.ts +1 -0
- package/dist/generated/types/ranked-leaderboard-entry.js +2 -0
- package/dist/generated/types/ranked-leaderboard-query.d.ts +1 -0
- package/dist/generated/types/ranked-leaderboard-query.js +2 -0
- package/dist/generated/types/ranked-leaderboard-response.d.ts +1 -0
- package/dist/generated/types/ranked-leaderboard-response.js +2 -0
- package/dist/generated/types/ranked-matchmaking-request.d.ts +137 -0
- package/dist/generated/types/ranked-matchmaking-request.js +2 -0
- package/dist/generated/types/ranked-matchmaking-view.d.ts +1 -0
- package/dist/generated/types/ranked-matchmaking-view.js +2 -0
- package/dist/generated/types/ranked-profile-request.d.ts +1 -0
- package/dist/generated/types/ranked-profile-request.js +2 -0
- package/dist/generated/types/ranked-profile-response.d.ts +1 -0
- package/dist/generated/types/ranked-profile-response.js +2 -0
- package/dist/generated/types/ranked-queue.d.ts +1 -0
- package/dist/generated/types/ranked-queue.js +2 -0
- package/dist/generated/types/ready-tournament-table-request.d.ts +7 -0
- package/dist/generated/types/ready-tournament-table-request.js +2 -0
- package/dist/generated/types/rematch-match-request.d.ts +1 -0
- package/dist/generated/types/rematch-match-request.js +2 -0
- package/dist/generated/types/rematch-match-response.d.ts +1 -0
- package/dist/generated/types/rematch-match-response.js +2 -0
- package/dist/generated/types/resolve-card-ids-request.d.ts +1 -0
- package/dist/generated/types/resolve-card-ids-request.js +2 -0
- package/dist/generated/types/resolve-card-ids-response.d.ts +1 -0
- package/dist/generated/types/resolve-card-ids-response.js +2 -0
- package/dist/generated/types/restore-history-response.d.ts +1 -0
- package/dist/generated/types/restore-history-response.js +2 -0
- package/dist/generated/types/restore-match-save-request.d.ts +1 -0
- package/dist/generated/types/restore-match-save-request.js +2 -0
- package/dist/generated/types/restore-match-save-response.d.ts +1 -0
- package/dist/generated/types/restore-match-save-response.js +2 -0
- package/dist/generated/types/return-lobby-match-request.d.ts +1 -0
- package/dist/generated/types/return-lobby-match-request.js +2 -0
- package/dist/generated/types/return-tournament-match-request.d.ts +1 -0
- package/dist/generated/types/return-tournament-match-request.js +2 -0
- package/dist/generated/types/save-match-request.d.ts +1 -0
- package/dist/generated/types/save-match-request.js +2 -0
- package/dist/generated/types/server-message.d.ts +1 -0
- package/dist/generated/types/server-message.js +2 -0
- package/dist/generated/types/set-ai-paused-request.d.ts +1 -0
- package/dist/generated/types/set-ai-paused-request.js +2 -0
- package/dist/generated/types/set-ai-paused-response.d.ts +1 -0
- package/dist/generated/types/set-ai-paused-response.js +2 -0
- package/dist/generated/types/set-ranked-admission-request.d.ts +1 -0
- package/dist/generated/types/set-ranked-admission-request.js +2 -0
- package/dist/generated/types/set-simulator-maintenance-request.d.ts +1 -0
- package/dist/generated/types/set-simulator-maintenance-request.js +2 -0
- package/dist/generated/types/simulator-admin-status-response.d.ts +1 -0
- package/dist/generated/types/simulator-admin-status-response.js +2 -0
- package/dist/generated/types/simulator-availability-response.d.ts +1 -0
- package/dist/generated/types/simulator-availability-response.js +2 -0
- package/dist/generated/types/simulator-report-list-response.d.ts +1 -0
- package/dist/generated/types/simulator-report-list-response.js +2 -0
- package/dist/generated/types/simulator-report-response.d.ts +1 -0
- package/dist/generated/types/simulator-report-response.js +2 -0
- package/dist/generated/types/spectate-lobby-request.d.ts +1 -0
- package/dist/generated/types/spectate-lobby-request.js +2 -0
- package/dist/generated/types/spectate-match-request.d.ts +1 -0
- package/dist/generated/types/spectate-match-request.js +2 -0
- package/dist/generated/types/start-lobby-limited-match-request.d.ts +1 -0
- package/dist/generated/types/start-lobby-limited-match-request.js +2 -0
- package/dist/generated/types/start-lobby-request.d.ts +1 -0
- package/dist/generated/types/start-lobby-request.js +2 -0
- package/dist/generated/types/start-tournament-event-request.d.ts +1 -0
- package/dist/generated/types/start-tournament-event-request.js +2 -0
- package/dist/generated/types/stats-response.d.ts +5 -0
- package/dist/generated/types/stats-response.js +2 -0
- package/dist/generated/types/submit-lobby-limited-deck-request.d.ts +1 -0
- package/dist/generated/types/submit-lobby-limited-deck-request.js +2 -0
- package/dist/generated/types/submit-match-deck-request.d.ts +1 -0
- package/dist/generated/types/submit-match-deck-request.js +2 -0
- package/dist/generated/types/submit-match-deck-response.d.ts +1 -0
- package/dist/generated/types/submit-match-deck-response.js +2 -0
- package/dist/generated/types/submit-tournament-deck-request.d.ts +1 -0
- package/dist/generated/types/submit-tournament-deck-request.js +2 -0
- package/dist/generated/types/tournament-event-command-request.d.ts +1 -0
- package/dist/generated/types/tournament-event-command-request.js +2 -0
- package/dist/generated/types/tournament-room-access-response.d.ts +1 -0
- package/dist/generated/types/tournament-room-access-response.js +2 -0
- package/dist/generated/types/tournament-room-chat-request.d.ts +1 -0
- package/dist/generated/types/tournament-room-chat-request.js +2 -0
- package/dist/generated/types/tournament-room-chat-response.d.ts +1 -0
- package/dist/generated/types/tournament-room-chat-response.js +2 -0
- package/dist/generated/types/tournament-room-list-response.d.ts +1 -0
- package/dist/generated/types/tournament-room-list-response.js +2 -0
- package/dist/generated/types/tournament-room-response.d.ts +1 -0
- package/dist/generated/types/tournament-room-response.js +2 -0
- package/dist/generated/types/tournament-room-server-message.d.ts +1 -0
- package/dist/generated/types/tournament-room-server-message.js +2 -0
- package/dist/generated/types/tournament-room-sync-request.d.ts +1 -0
- package/dist/generated/types/tournament-room-sync-request.js +2 -0
- package/dist/generated/types/undo-match-request.d.ts +1 -0
- package/dist/generated/types/undo-match-request.js +2 -0
- package/dist/generated/types/undo-match-response.d.ts +1 -0
- package/dist/generated/types/undo-match-response.js +2 -0
- package/dist/generated/types/undo-respond-match-request.d.ts +1 -0
- package/dist/generated/types/undo-respond-match-request.js +2 -0
- package/dist/generated/types/update-lobby-ai-player-request.d.ts +1 -0
- package/dist/generated/types/update-lobby-ai-player-request.js +2 -0
- package/dist/generated/types/update-lobby-player-request.d.ts +1 -0
- package/dist/generated/types/update-lobby-player-request.js +2 -0
- package/dist/generated/types/update-lobby-settings-request.d.ts +1 -0
- package/dist/generated/types/update-lobby-settings-request.js +2 -0
- package/dist/generated/types/update-tournament-room-player-request.d.ts +1 -0
- package/dist/generated/types/update-tournament-room-player-request.js +2 -0
- package/dist/generated/types/update-tournament-room-settings-request.d.ts +1 -0
- package/dist/generated/types/update-tournament-room-settings-request.js +2 -0
- package/dist/generated/types/update-tournament-table-deck-request.d.ts +123 -0
- package/dist/generated/types/update-tournament-table-deck-request.js +2 -0
- package/dist/generated/types/welcome-payload.d.ts +1 -0
- package/dist/generated/types/welcome-payload.js +2 -0
- package/dist/generated/version.d.ts +16 -0
- package/dist/generated/version.js +16 -0
- package/dist/http/abort.d.ts +57 -0
- package/dist/http/abort.js +60 -0
- package/dist/http/json.d.ts +13 -0
- package/dist/http/json.js +24 -0
- package/dist/http/options.d.ts +40 -0
- package/dist/http/options.js +1 -0
- package/dist/http/request.d.ts +64 -0
- package/dist/http/request.js +182 -0
- package/dist/http/validated-json.d.ts +9 -0
- package/dist/http/validated-json.js +14 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +10 -0
- package/dist/internal/abort-error.d.ts +91 -0
- package/dist/internal/abort-error.js +62 -0
- package/dist/internal/authenticated-socket-session.d.ts +63 -0
- package/dist/internal/authenticated-socket-session.js +170 -0
- package/dist/internal/emitter.d.ts +18 -0
- package/dist/internal/emitter.js +34 -0
- package/dist/internal/errors.d.ts +233 -0
- package/dist/internal/errors.js +238 -0
- package/dist/internal/limits.d.ts +13 -0
- package/dist/internal/limits.js +13 -0
- package/dist/internal/reconnect-backoff.d.ts +33 -0
- package/dist/internal/reconnect-backoff.js +25 -0
- package/dist/internal/socket-frame.d.ts +43 -0
- package/dist/internal/socket-frame.js +47 -0
- package/dist/internal/transport.d.ts +78 -0
- package/dist/internal/transport.js +18 -0
- package/dist/internal/websocket-event.d.ts +15 -0
- package/dist/internal/websocket-event.js +31 -0
- package/dist/local/assets.d.ts +96 -0
- package/dist/local/assets.js +235 -0
- package/dist/local/client.d.ts +32 -0
- package/dist/local/client.js +211 -0
- package/dist/local/engine.d.ts +79 -0
- package/dist/local/engine.js +6 -0
- package/dist/local/index.d.ts +20 -0
- package/dist/local/index.js +17 -0
- package/dist/local/offline-engine.d.ts +46 -0
- package/dist/local/offline-engine.js +74 -0
- package/dist/local/protocol.d.ts +95 -0
- package/dist/local/protocol.js +10 -0
- package/dist/local/routing.d.ts +52 -0
- package/dist/local/routing.js +193 -0
- package/dist/local/server/ai-scheduler.d.ts +31 -0
- package/dist/local/server/ai-scheduler.js +93 -0
- package/dist/local/server/http-router.d.ts +35 -0
- package/dist/local/server/http-router.js +185 -0
- package/dist/local/server/index.d.ts +16 -0
- package/dist/local/server/index.js +140 -0
- package/dist/local/server/sockets.d.ts +25 -0
- package/dist/local/server/sockets.js +141 -0
- package/dist/local/wasm-engine.d.ts +61 -0
- package/dist/local/wasm-engine.js +63 -0
- package/dist/local/worker-boot.d.ts +17 -0
- package/dist/local/worker-boot.js +76 -0
- package/dist/local/worker.d.ts +6 -0
- package/dist/local/worker.js +9 -0
- package/dist/match-session/access.d.ts +6 -0
- package/dist/match-session/access.js +8 -0
- package/dist/match-session/controller.d.ts +63 -0
- package/dist/match-session/controller.js +513 -0
- package/dist/match-session/errors.d.ts +3 -0
- package/dist/match-session/errors.js +34 -0
- package/dist/match-session/methods.d.ts +433 -0
- package/dist/match-session/methods.js +1 -0
- package/dist/match-session/session-state.d.ts +235 -0
- package/dist/match-session/session-state.js +1 -0
- package/dist/match-session/types.d.ts +56 -0
- package/dist/match-session/types.js +1 -0
- package/dist/match-session.d.ts +3 -0
- package/dist/match-session.js +1 -0
- package/dist/messages.d.ts +195 -0
- package/dist/messages.js +240 -0
- package/dist/resources/admin.d.ts +63 -0
- package/dist/resources/admin.js +75 -0
- package/dist/resources/card-deck-json.d.ts +11 -0
- package/dist/resources/card-deck-json.js +164 -0
- package/dist/resources/card-resolution.d.ts +9 -0
- package/dist/resources/card-resolution.js +21 -0
- package/dist/resources/card-resource.d.ts +157 -0
- package/dist/resources/card-resource.js +28 -0
- package/dist/resources/card-types.d.ts +203 -0
- package/dist/resources/card-types.js +1 -0
- package/dist/resources/cards.d.ts +3 -0
- package/dist/resources/cards.js +1 -0
- package/dist/resources/limited-event-types.d.ts +252 -0
- package/dist/resources/limited-event-types.js +1 -0
- package/dist/resources/limited-events.d.ts +7 -0
- package/dist/resources/limited-events.js +49 -0
- package/dist/resources/lobbies.d.ts +53 -0
- package/dist/resources/lobbies.js +50 -0
- package/dist/resources/lobby-list-session.d.ts +13 -0
- package/dist/resources/lobby-list-session.js +198 -0
- package/dist/resources/lobby-session.d.ts +9 -0
- package/dist/resources/lobby-session.js +59 -0
- package/dist/resources/lobby-types.d.ts +357 -0
- package/dist/resources/lobby-types.js +1 -0
- package/dist/resources/match-history.d.ts +49 -0
- package/dist/resources/match-history.js +34 -0
- package/dist/resources/match-types.d.ts +448 -0
- package/dist/resources/match-types.js +1 -0
- package/dist/resources/matches.d.ts +16 -0
- package/dist/resources/matches.js +109 -0
- package/dist/resources/ranked.d.ts +24 -0
- package/dist/resources/ranked.js +47 -0
- package/dist/resources/session.d.ts +62 -0
- package/dist/resources/session.js +26 -0
- package/dist/resources/system.d.ts +51 -0
- package/dist/resources/system.js +9 -0
- package/dist/resources/tournament-room-session.d.ts +9 -0
- package/dist/resources/tournament-room-session.js +53 -0
- package/dist/resources/tournament-room-types.d.ts +44 -0
- package/dist/resources/tournament-room-types.js +1 -0
- package/dist/resources/tournament-rooms.d.ts +33 -0
- package/dist/resources/tournament-rooms.js +33 -0
- package/dist/session.d.ts +56 -0
- package/dist/session.js +1 -0
- package/dist/types.d.ts +73 -0
- package/dist/types.js +27 -0
- package/dist/validators/ajv.d.ts +51 -0
- package/dist/validators/ajv.js +121 -0
- package/dist/validators/discriminants.d.ts +36 -0
- package/dist/validators/discriminants.js +89 -0
- package/dist/validators/validator.d.ts +73 -0
- package/dist/validators/validator.js +26 -0
- package/dist/validators/warm-up.d.ts +25 -0
- package/dist/validators/warm-up.js +59 -0
- package/dist/validators.d.ts +173 -0
- package/dist/validators.js +85 -0
- package/package.json +88 -0
- package/schema/abandon-match-request.schema.json +15 -0
- package/schema/abandon-match-response.schema.json +15 -0
- package/schema/add-lobby-ai-player-request.schema.json +53 -0
- package/schema/api-error-response.schema.json +13 -0
- package/schema/card-catalog-refresh-response.schema.json +31 -0
- package/schema/cards-response.schema.json +17 -0
- package/schema/client-message.schema.json +203 -0
- package/schema/close-tournament-room-request.schema.json +18 -0
- package/schema/common.schema.json +14129 -0
- package/schema/create-limited-event-request.schema.json +60 -0
- package/schema/create-lobby-request.schema.json +67 -0
- package/schema/create-match-request.schema.json +124 -0
- package/schema/create-meta-window-request.schema.json +27 -0
- package/schema/create-tournament-room-request.schema.json +104 -0
- package/schema/create-tournament-table-request.schema.json +14 -0
- package/schema/error-payload.schema.json +34 -0
- package/schema/format-event-request.schema.json +20 -0
- package/schema/format-event-response.schema.json +15 -0
- package/schema/game-command.schema.json +775 -0
- package/schema/game-event.schema.json +2012 -0
- package/schema/game-state.schema.json +273 -0
- package/schema/get-match-response.schema.json +13 -0
- package/schema/health-response.schema.json +13 -0
- package/schema/join-limited-event-request.schema.json +6 -0
- package/schema/join-lobby-request.schema.json +40 -0
- package/schema/join-match-request.schema.json +79 -0
- package/schema/join-tournament-room-request.schema.json +39 -0
- package/schema/join-tournament-table-request.schema.json +14 -0
- package/schema/kick-lobby-player-request.schema.json +13 -0
- package/schema/kick-lobby-spectator-request.schema.json +14 -0
- package/schema/leave-lobby-request.schema.json +13 -0
- package/schema/leave-match-request.schema.json +15 -0
- package/schema/leave-match-response.schema.json +15 -0
- package/schema/leave-tournament-room-request.schema.json +14 -0
- package/schema/limited-event-access-response.schema.json +34 -0
- package/schema/limited-event-command-request.schema.json +20 -0
- package/schema/limited-event-preflight-response.schema.json +25 -0
- package/schema/limited-event-response.schema.json +15 -0
- package/schema/list-active-ai-matches-request.schema.json +23 -0
- package/schema/list-active-ai-matches-response.schema.json +17 -0
- package/schema/lobby-access-response.schema.json +31 -0
- package/schema/lobby-chat-request.schema.json +17 -0
- package/schema/lobby-chat-response.schema.json +17 -0
- package/schema/lobby-list-response.schema.json +16 -0
- package/schema/lobby-list-server-message.schema.json +49 -0
- package/schema/lobby-matchmaking-decision-request.schema.json +13 -0
- package/schema/lobby-matchmaking-request.schema.json +80 -0
- package/schema/lobby-response.schema.json +13 -0
- package/schema/lobby-server-message.schema.json +155 -0
- package/schema/lobby-sync-request.schema.json +13 -0
- package/schema/manifest.json +124 -0
- package/schema/match-access-response.schema.json +32 -0
- package/schema/match-chat-lookup-response.schema.json +34 -0
- package/schema/match-connection-role.schema.json +9 -0
- package/schema/match-history-deck-stats-request.schema.json +26 -0
- package/schema/match-history-deck-stats-response.schema.json +17 -0
- package/schema/match-history-entry.schema.json +78 -0
- package/schema/match-history-list-request.schema.json +48 -0
- package/schema/match-history-list-response.schema.json +25 -0
- package/schema/match-history-replay-request.schema.json +17 -0
- package/schema/match-history-replay-response.schema.json +14 -0
- package/schema/match-history-restore-request.schema.json +23 -0
- package/schema/match-save-payload.schema.json +71 -0
- package/schema/match-spectator-access-response.schema.json +22 -0
- package/schema/meta-window.schema.json +37 -0
- package/schema/meta-windows-response.schema.json +24 -0
- package/schema/prepare-lobby-limited-ai-decks-request.schema.json +14 -0
- package/schema/ranked-admin-status.schema.json +43 -0
- package/schema/ranked-leaderboard-entry.schema.json +61 -0
- package/schema/ranked-leaderboard-query.schema.json +34 -0
- package/schema/ranked-leaderboard-response.schema.json +23 -0
- package/schema/ranked-matchmaking-view.schema.json +15 -0
- package/schema/ranked-profile-request.schema.json +21 -0
- package/schema/ranked-profile-response.schema.json +59 -0
- package/schema/ranked-queue.schema.json +12 -0
- package/schema/rematch-match-request.schema.json +20 -0
- package/schema/rematch-match-response.schema.json +61 -0
- package/schema/resolve-card-ids-request.schema.json +17 -0
- package/schema/resolve-card-ids-response.schema.json +16 -0
- package/schema/restore-history-response.schema.json +15 -0
- package/schema/restore-match-save-request.schema.json +20 -0
- package/schema/restore-match-save-response.schema.json +29 -0
- package/schema/return-lobby-match-request.schema.json +13 -0
- package/schema/return-tournament-match-request.schema.json +14 -0
- package/schema/route-manifest.json +1014 -0
- package/schema/save-match-request.schema.json +15 -0
- package/schema/server-message.schema.json +192 -0
- package/schema/set-ai-paused-request.schema.json +19 -0
- package/schema/set-ai-paused-response.schema.json +18 -0
- package/schema/set-ranked-admission-request.schema.json +15 -0
- package/schema/set-simulator-maintenance-request.schema.json +20 -0
- package/schema/simulator-admin-status-response.schema.json +37 -0
- package/schema/simulator-availability-response.schema.json +27 -0
- package/schema/simulator-report-list-response.schema.json +23 -0
- package/schema/simulator-report-response.schema.json +77 -0
- package/schema/spectate-lobby-request.schema.json +32 -0
- package/schema/spectate-match-request.schema.json +32 -0
- package/schema/start-lobby-limited-match-request.schema.json +13 -0
- package/schema/start-lobby-request.schema.json +13 -0
- package/schema/start-tournament-event-request.schema.json +14 -0
- package/schema/submit-lobby-limited-deck-request.schema.json +33 -0
- package/schema/submit-match-deck-request.schema.json +45 -0
- package/schema/submit-match-deck-response.schema.json +14 -0
- package/schema/submit-tournament-deck-request.schema.json +34 -0
- package/schema/tournament-event-command-request.schema.json +18 -0
- package/schema/tournament-room-access-response.schema.json +32 -0
- package/schema/tournament-room-chat-request.schema.json +18 -0
- package/schema/tournament-room-chat-response.schema.json +18 -0
- package/schema/tournament-room-list-response.schema.json +17 -0
- package/schema/tournament-room-response.schema.json +14 -0
- package/schema/tournament-room-server-message.schema.json +127 -0
- package/schema/tournament-room-sync-request.schema.json +14 -0
- package/schema/undo-match-request.schema.json +14 -0
- package/schema/undo-match-response.schema.json +14 -0
- package/schema/undo-respond-match-request.schema.json +19 -0
- package/schema/update-lobby-ai-player-request.schema.json +65 -0
- package/schema/update-lobby-player-request.schema.json +81 -0
- package/schema/update-lobby-settings-request.schema.json +70 -0
- package/schema/update-tournament-room-player-request.schema.json +45 -0
- package/schema/update-tournament-room-settings-request.schema.json +33 -0
- package/schema/welcome-payload.schema.json +38 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-worker server: binds the RPC protocol to the engine (HTTP router, virtual
|
|
3
|
+
* sockets, record persistence). The worker entry wires this to the real wasm
|
|
4
|
+
* engine; tests drive it with a scripted fake over an in-process port.
|
|
5
|
+
*/
|
|
6
|
+
import { engineFailureResponse, routeHttpRequest } from './http-router.js';
|
|
7
|
+
import { openMatchSocket } from './sockets.js';
|
|
8
|
+
/**
|
|
9
|
+
* Attaches the local engine server to a message port. Returns a disposer.
|
|
10
|
+
*/
|
|
11
|
+
export function createLocalEngineServer(options) {
|
|
12
|
+
const { engine, port } = options;
|
|
13
|
+
const registry = {
|
|
14
|
+
matches: new Map(),
|
|
15
|
+
lobbies: new Map(),
|
|
16
|
+
eventLobbies: new Map(),
|
|
17
|
+
matchChannels: new Map(),
|
|
18
|
+
};
|
|
19
|
+
const channels = new Map();
|
|
20
|
+
let installed = false;
|
|
21
|
+
const respond = (response, transfer) => {
|
|
22
|
+
port.postMessage(response, transfer);
|
|
23
|
+
};
|
|
24
|
+
const onMessage = (event) => {
|
|
25
|
+
const request = event.data;
|
|
26
|
+
switch (request.kind) {
|
|
27
|
+
case 'init': {
|
|
28
|
+
try {
|
|
29
|
+
if (!installed) {
|
|
30
|
+
engine.install(new Uint8Array(request.catalogBytes));
|
|
31
|
+
installed = true;
|
|
32
|
+
}
|
|
33
|
+
respond({ kind: 'ok', id: request.id, body: engine.engineVersion() });
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
respond({ kind: 'error', id: request.id, message: String(error) });
|
|
37
|
+
}
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
case 'http': {
|
|
41
|
+
try {
|
|
42
|
+
const routed = routeHttpRequest(engine, registry, request.method, request.path, request.body, Date.now());
|
|
43
|
+
respond({ kind: 'ok', id: request.id, status: routed.status, body: routed.body });
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
// Engine throws surface as a 4xx `ApiErrorResponse` — a rejected
|
|
47
|
+
// fetch would strip the status/code the app's error handling reads.
|
|
48
|
+
const failure = engineFailureResponse(error);
|
|
49
|
+
respond({ kind: 'ok', id: request.id, status: failure.status, body: failure.body });
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
case 'syncCatalog': {
|
|
54
|
+
if (!installed) {
|
|
55
|
+
respond({ kind: 'error', id: request.id, message: 'card catalog is not installed' });
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
engine.applyCatalogSync(request.catalogSyncJson);
|
|
60
|
+
respond({ kind: 'ok', id: request.id });
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
respond({ kind: 'error', id: request.id, message: String(error) });
|
|
64
|
+
}
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
case 'wsOpen': {
|
|
68
|
+
const channel = openMatchSocket(registry, request.url, request.protocols, {
|
|
69
|
+
opened: () => respond({ kind: 'wsOpened', channelId: request.channelId }),
|
|
70
|
+
message: data => respond({ kind: 'wsMessage', channelId: request.channelId, data }),
|
|
71
|
+
closed: (code, reason) => respond({ kind: 'wsClosed', channelId: request.channelId, code, reason }),
|
|
72
|
+
failed: message => respond({ kind: 'wsFailed', channelId: request.channelId, message }),
|
|
73
|
+
});
|
|
74
|
+
if (channel) {
|
|
75
|
+
channels.set(request.channelId, channel);
|
|
76
|
+
}
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
case 'wsSend': {
|
|
80
|
+
channels.get(request.channelId)?.send(request.data);
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
case 'wsClose': {
|
|
84
|
+
channels.get(request.channelId)?.close();
|
|
85
|
+
channels.delete(request.channelId);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
case 'saveRecord': {
|
|
89
|
+
// Exactly one live match per worker in the offline flows; save the
|
|
90
|
+
// most recently created one.
|
|
91
|
+
const match = [...registry.matches.values()].at(-1);
|
|
92
|
+
if (!match) {
|
|
93
|
+
respond({ kind: 'error', id: request.id, message: 'no live local match to save' });
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const bytes = match.toRecordBytes();
|
|
98
|
+
const buffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
99
|
+
respond({
|
|
100
|
+
kind: 'saved',
|
|
101
|
+
id: request.id,
|
|
102
|
+
matchId: match.matchId,
|
|
103
|
+
seatToken: match.seatToken,
|
|
104
|
+
bytes: buffer,
|
|
105
|
+
}, [buffer]);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
respond({ kind: 'error', id: request.id, message: String(error) });
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
case 'restoreRecord': {
|
|
113
|
+
try {
|
|
114
|
+
const match = engine.restoreRecord(new Uint8Array(request.bytes));
|
|
115
|
+
// One live match per worker: drop stale hosts so `saveRecord` and
|
|
116
|
+
// reconnects always resolve to the restored one.
|
|
117
|
+
registry.matches.clear();
|
|
118
|
+
registry.matches.set(match.matchId, match);
|
|
119
|
+
respond({
|
|
120
|
+
kind: 'ok',
|
|
121
|
+
id: request.id,
|
|
122
|
+
body: JSON.stringify({ matchId: match.matchId, seatToken: match.seatToken }),
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
respond({ kind: 'error', id: request.id, message: String(error) });
|
|
127
|
+
}
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
port.addEventListener('message', onMessage);
|
|
133
|
+
return () => {
|
|
134
|
+
port.removeEventListener('message', onMessage);
|
|
135
|
+
for (const channel of channels.values()) {
|
|
136
|
+
channel.close();
|
|
137
|
+
}
|
|
138
|
+
channels.clear();
|
|
139
|
+
};
|
|
140
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Virtual match sockets: validates the subprotocol token, replays the
|
|
3
|
+
* server-identical handshake (`welcome` → `snapshot` → `historySnapshot` →
|
|
4
|
+
* `aiStatus`), routes `ClientMessage` envelopes into the engine, and pumps the
|
|
5
|
+
* AI between messages. Delay batches are honored with real timers so AI attack
|
|
6
|
+
* pacing reaches the client exactly like the online path.
|
|
7
|
+
*/
|
|
8
|
+
import type { LocalMatchRegistry } from './http-router.js';
|
|
9
|
+
/** Emits worker→main socket frames for one channel. */
|
|
10
|
+
export interface SocketChannelSink {
|
|
11
|
+
opened: () => void;
|
|
12
|
+
message: (data: string) => void;
|
|
13
|
+
closed: (code?: number, reason?: string) => void;
|
|
14
|
+
failed: (message: string) => void;
|
|
15
|
+
}
|
|
16
|
+
/** One live virtual socket. */
|
|
17
|
+
export interface SocketChannel {
|
|
18
|
+
send: (data: string) => void;
|
|
19
|
+
close: () => void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Opens one virtual match socket. Returns `undefined` (after signaling
|
|
23
|
+
* `failed`) when the URL or token does not resolve to a hosted match.
|
|
24
|
+
*/
|
|
25
|
+
export declare function openMatchSocket(registry: LocalMatchRegistry, url: string, protocols: string[], sink: SocketChannelSink): SocketChannel | undefined;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Virtual match sockets: validates the subprotocol token, replays the
|
|
3
|
+
* server-identical handshake (`welcome` → `snapshot` → `historySnapshot` →
|
|
4
|
+
* `aiStatus`), routes `ClientMessage` envelopes into the engine, and pumps the
|
|
5
|
+
* AI between messages. Delay batches are honored with real timers so AI attack
|
|
6
|
+
* pacing reaches the client exactly like the online path.
|
|
7
|
+
*/
|
|
8
|
+
import { MATCH_SEAT_TOKEN_PROTOCOL, MATCH_SPECTATOR_TOKEN_PROTOCOL, PLAYER_TOKEN_PROTOCOL, } from '../../connection/url.js';
|
|
9
|
+
import { createAiScheduler } from './ai-scheduler.js';
|
|
10
|
+
/**
|
|
11
|
+
* Opens one virtual match socket. Returns `undefined` (after signaling
|
|
12
|
+
* `failed`) when the URL or token does not resolve to a hosted match.
|
|
13
|
+
*/
|
|
14
|
+
export function openMatchSocket(registry, url, protocols, sink) {
|
|
15
|
+
const pathSegments = new URL(url).pathname.split('/').filter(Boolean);
|
|
16
|
+
if (pathSegments[pathSegments.length - 2] === 'lobbies') {
|
|
17
|
+
return openLobbySocket(registry, pathSegments[pathSegments.length - 1], protocols, sink);
|
|
18
|
+
}
|
|
19
|
+
const matchId = decodeURIComponent(pathSegments.pop() ?? '');
|
|
20
|
+
const match = registry.matches.get(matchId);
|
|
21
|
+
if (!match) {
|
|
22
|
+
sink.failed(`unknown local match ${matchId}`);
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
if (protocols.includes(MATCH_SPECTATOR_TOKEN_PROTOCOL)) {
|
|
26
|
+
sink.failed('offline matches do not support spectators');
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
const protocolIndex = protocols.indexOf(MATCH_SEAT_TOKEN_PROTOCOL);
|
|
30
|
+
const seatToken = protocolIndex >= 0 ? protocols[protocolIndex + 1] : undefined;
|
|
31
|
+
if (!seatToken || seatToken !== match.seatToken) {
|
|
32
|
+
sink.failed('invalid seat token');
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
let open = true;
|
|
36
|
+
const scheduler = createAiScheduler({
|
|
37
|
+
match,
|
|
38
|
+
deliver: (batch) => {
|
|
39
|
+
if (!open) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
for (const message of batch.messages) {
|
|
43
|
+
sink.message(JSON.stringify(message));
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
failed: (error) => {
|
|
47
|
+
if (!open) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
open = false;
|
|
51
|
+
// `detachChannel` is declared below but only runs after socket setup.
|
|
52
|
+
detachChannel();
|
|
53
|
+
sink.failed(`local engine failed: ${String(error)}`);
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
sink.opened();
|
|
57
|
+
for (const message of match.connect()) {
|
|
58
|
+
sink.message(JSON.stringify(message));
|
|
59
|
+
}
|
|
60
|
+
// The AI may already own the first move (e.g. restored mid-AI-turn).
|
|
61
|
+
scheduler.pump();
|
|
62
|
+
// Lets HTTP twins of socket envelopes (the ai/pause route) broadcast their
|
|
63
|
+
// batches to this open socket and re-pump the AI, like the server does.
|
|
64
|
+
const channelHandle = {
|
|
65
|
+
deliver: (batches) => scheduler.enqueueHuman(() => batches),
|
|
66
|
+
};
|
|
67
|
+
registry.matchChannels.set(matchId, channelHandle);
|
|
68
|
+
const detachChannel = () => {
|
|
69
|
+
if (registry.matchChannels.get(matchId) === channelHandle) {
|
|
70
|
+
registry.matchChannels.delete(matchId);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
send: (data) => {
|
|
75
|
+
if (!open) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// Serialize behind any in-flight paced AI delivery so a human message's
|
|
79
|
+
// reply cannot interleave into the middle of a staggered batch.
|
|
80
|
+
scheduler.enqueueHuman(() => {
|
|
81
|
+
const batches = match.handleMessage(seatToken, data, Date.now());
|
|
82
|
+
return batches;
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
close: () => {
|
|
86
|
+
open = false;
|
|
87
|
+
detachChannel();
|
|
88
|
+
scheduler.stop();
|
|
89
|
+
sink.closed(1000, 'closed by client');
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Minimal lobby socket for the hidden offline bootstrap: handshake
|
|
95
|
+
* (`welcome` + `snapshot`) plus ping/pong. The offline flow reads all lobby
|
|
96
|
+
* state through the HTTP responses, so no pushes are emitted.
|
|
97
|
+
*/
|
|
98
|
+
function openLobbySocket(registry, encodedLobbyId, protocols, sink) {
|
|
99
|
+
const lobbyId = decodeURIComponent(encodedLobbyId);
|
|
100
|
+
const lobby = registry.lobbies.get(lobbyId);
|
|
101
|
+
if (!lobby) {
|
|
102
|
+
sink.failed(`unknown local lobby ${lobbyId}`);
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
const protocolIndex = protocols.indexOf(PLAYER_TOKEN_PROTOCOL);
|
|
106
|
+
const playerToken = protocolIndex >= 0 ? protocols[protocolIndex + 1] : undefined;
|
|
107
|
+
try {
|
|
108
|
+
lobby.authorize(playerToken ?? '');
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
sink.failed('invalid lobby player token');
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
let open = true;
|
|
115
|
+
const access = JSON.parse(lobby.accessJson());
|
|
116
|
+
sink.opened();
|
|
117
|
+
sink.message(JSON.stringify({
|
|
118
|
+
type: 'welcome',
|
|
119
|
+
payload: { lobbyId, playerId: access.playerId },
|
|
120
|
+
}));
|
|
121
|
+
sink.message(JSON.stringify({ type: 'snapshot', payload: access.snapshot }));
|
|
122
|
+
return {
|
|
123
|
+
send: (data) => {
|
|
124
|
+
if (!open) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const message = JSON.parse(data);
|
|
128
|
+
if (message.type === 'ping') {
|
|
129
|
+
sink.message(JSON.stringify({ type: 'pong', payload: { nonce: message.payload?.nonce ?? null } }));
|
|
130
|
+
}
|
|
131
|
+
else if (message.type === 'syncRequest') {
|
|
132
|
+
const current = JSON.parse(lobby.accessJson());
|
|
133
|
+
sink.message(JSON.stringify({ type: 'snapshot', payload: current.snapshot }));
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
close: () => {
|
|
137
|
+
open = false;
|
|
138
|
+
sink.closed(1000, 'closed by client');
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapts the `swu-wasm` bindings to the {@link LocalSimulatorEngine} contract.
|
|
3
|
+
*
|
|
4
|
+
* The wasm module is passed in (already `init()`-ed by the worker entry) so
|
|
5
|
+
* this file stays importable in tests without wasm glue.
|
|
6
|
+
*/
|
|
7
|
+
import type { LocalSimulatorEngine } from './engine.js';
|
|
8
|
+
/** The subset of `swu_wasm.js` exports this adapter consumes. */
|
|
9
|
+
export interface SwuWasmModule {
|
|
10
|
+
install_card_catalog: (bytes: Uint8Array) => void;
|
|
11
|
+
apply_catalog_sync: (catalogSyncJson: string) => void;
|
|
12
|
+
cards_get: (idsJson: string) => string;
|
|
13
|
+
limited_events_preflight: (requestJson: string) => string;
|
|
14
|
+
offline_difficulties: () => string;
|
|
15
|
+
engine_version: () => string;
|
|
16
|
+
LocalMatch: {
|
|
17
|
+
create: (requestJson: string, nowMs: number) => WasmCreatedLocalMatch;
|
|
18
|
+
restoreRecord: (bytes: Uint8Array) => WasmLocalMatch;
|
|
19
|
+
};
|
|
20
|
+
LocalLobby: {
|
|
21
|
+
create: (requestJson: string) => WasmCreatedLocalLobby;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
interface WasmCreatedLocalLobby {
|
|
25
|
+
takeLobby: () => WasmLocalLobby;
|
|
26
|
+
accessJson: () => string;
|
|
27
|
+
}
|
|
28
|
+
interface WasmLocalLobby {
|
|
29
|
+
lobbyId: () => string;
|
|
30
|
+
authorize: (playerToken: string) => void;
|
|
31
|
+
addAiPlayer: (difficulty: string) => string;
|
|
32
|
+
setHostReady: (ready: boolean) => string;
|
|
33
|
+
start: (nowMs: number) => string;
|
|
34
|
+
eventSnapshot: (seatToken: string | null | undefined, nowMs: number) => string;
|
|
35
|
+
eventApplyCommand: (seatToken: string, commandJson: string, nowMs: number) => string;
|
|
36
|
+
submitLimitedDeck: (requestJson: string) => string;
|
|
37
|
+
prepareLimitedAiDecks: () => string;
|
|
38
|
+
limitedMatchRequest: () => string;
|
|
39
|
+
storeStartedMatch: (accessJson: string) => string;
|
|
40
|
+
accessJson: () => string;
|
|
41
|
+
}
|
|
42
|
+
interface WasmCreatedLocalMatch {
|
|
43
|
+
takeMatch: () => WasmLocalMatch;
|
|
44
|
+
accessJson: () => string;
|
|
45
|
+
}
|
|
46
|
+
interface WasmLocalMatch {
|
|
47
|
+
connect: () => string;
|
|
48
|
+
handleMessage: (seatToken: string, messageJson: string, nowMs: number) => string;
|
|
49
|
+
aiHasWork: () => boolean;
|
|
50
|
+
tickAi: (nowMs: number) => string;
|
|
51
|
+
save: () => string;
|
|
52
|
+
toRecordBytes: () => Uint8Array;
|
|
53
|
+
snapshot: () => string;
|
|
54
|
+
matchId: () => string;
|
|
55
|
+
seatToken: () => string | undefined;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Wraps an initialized wasm module into the engine contract.
|
|
59
|
+
*/
|
|
60
|
+
export declare function createWasmEngine(wasm: SwuWasmModule): LocalSimulatorEngine;
|
|
61
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapts the `swu-wasm` bindings to the {@link LocalSimulatorEngine} contract.
|
|
3
|
+
*
|
|
4
|
+
* The wasm module is passed in (already `init()`-ed by the worker entry) so
|
|
5
|
+
* this file stays importable in tests without wasm glue.
|
|
6
|
+
*/
|
|
7
|
+
function wrapMatch(inner) {
|
|
8
|
+
const seatToken = inner.seatToken();
|
|
9
|
+
if (!seatToken) {
|
|
10
|
+
throw new Error('local match has no viewer seat token');
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
matchId: inner.matchId(),
|
|
14
|
+
seatToken,
|
|
15
|
+
connect: () => JSON.parse(inner.connect()),
|
|
16
|
+
handleMessage: (token, messageJson, nowMs) => JSON.parse(inner.handleMessage(token, messageJson, nowMs)),
|
|
17
|
+
aiHasWork: () => inner.aiHasWork(),
|
|
18
|
+
tickAi: nowMs => JSON.parse(inner.tickAi(nowMs)),
|
|
19
|
+
save: () => inner.save(),
|
|
20
|
+
toRecordBytes: () => inner.toRecordBytes(),
|
|
21
|
+
snapshot: () => inner.snapshot(),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Wraps an initialized wasm module into the engine contract.
|
|
26
|
+
*/
|
|
27
|
+
export function createWasmEngine(wasm) {
|
|
28
|
+
return {
|
|
29
|
+
install: (catalogBytes) => {
|
|
30
|
+
wasm.install_card_catalog(catalogBytes);
|
|
31
|
+
},
|
|
32
|
+
applyCatalogSync: catalogSyncJson => wasm.apply_catalog_sync(catalogSyncJson),
|
|
33
|
+
createMatch: (requestJson, nowMs) => {
|
|
34
|
+
const created = wasm.LocalMatch.create(requestJson, nowMs);
|
|
35
|
+
const match = wrapMatch(created.takeMatch());
|
|
36
|
+
return { match, accessJson: created.accessJson() };
|
|
37
|
+
},
|
|
38
|
+
restoreRecord: bytes => wrapMatch(wasm.LocalMatch.restoreRecord(bytes)),
|
|
39
|
+
cardsGet: ids => wasm.cards_get(JSON.stringify(ids)),
|
|
40
|
+
preflightLimitedEvent: requestJson => wasm.limited_events_preflight(requestJson),
|
|
41
|
+
createLobby: (requestJson) => {
|
|
42
|
+
const created = wasm.LocalLobby.create(requestJson);
|
|
43
|
+
const inner = created.takeLobby();
|
|
44
|
+
const lobby = {
|
|
45
|
+
lobbyId: inner.lobbyId(),
|
|
46
|
+
authorize: token => inner.authorize(token),
|
|
47
|
+
addAiPlayer: difficulty => inner.addAiPlayer(difficulty),
|
|
48
|
+
setHostReady: ready => inner.setHostReady(ready),
|
|
49
|
+
start: nowMs => inner.start(nowMs),
|
|
50
|
+
eventSnapshot: (seatToken, nowMs) => inner.eventSnapshot(seatToken ?? undefined, nowMs),
|
|
51
|
+
eventApplyCommand: (seatToken, commandJson, nowMs) => inner.eventApplyCommand(seatToken, commandJson, nowMs),
|
|
52
|
+
submitLimitedDeck: requestJson => inner.submitLimitedDeck(requestJson),
|
|
53
|
+
prepareLimitedAiDecks: () => inner.prepareLimitedAiDecks(),
|
|
54
|
+
limitedMatchRequest: () => inner.limitedMatchRequest(),
|
|
55
|
+
storeStartedMatch: accessJson => inner.storeStartedMatch(accessJson),
|
|
56
|
+
accessJson: () => inner.accessJson(),
|
|
57
|
+
};
|
|
58
|
+
return { lobby, accessJson: created.accessJson() };
|
|
59
|
+
},
|
|
60
|
+
offlineDifficulties: () => JSON.parse(wasm.offline_difficulties()),
|
|
61
|
+
engineVersion: () => wasm.engine_version(),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boot sequence shared by engine worker entries.
|
|
3
|
+
*
|
|
4
|
+
* The worker gets both wasm-bindgen glue and raw wasm bytes from the simulator
|
|
5
|
+
* server through the main thread's offline asset cache. This prevents npm
|
|
6
|
+
* package releases from carrying an engine binary and keeps glue paired with
|
|
7
|
+
* the exact server binary it initializes.
|
|
8
|
+
*/
|
|
9
|
+
import type { WorkerLike } from './protocol.js';
|
|
10
|
+
export interface LocalEngineWorkerBootOptions {
|
|
11
|
+
/** The worker global scope. */
|
|
12
|
+
port: WorkerLike;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Attaches the buffering listener and boots the engine on the `init` frame.
|
|
16
|
+
*/
|
|
17
|
+
export declare function bootLocalEngineWorker(options: LocalEngineWorkerBootOptions): void;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boot sequence shared by engine worker entries.
|
|
3
|
+
*
|
|
4
|
+
* The worker gets both wasm-bindgen glue and raw wasm bytes from the simulator
|
|
5
|
+
* server through the main thread's offline asset cache. This prevents npm
|
|
6
|
+
* package releases from carrying an engine binary and keeps glue paired with
|
|
7
|
+
* the exact server binary it initializes.
|
|
8
|
+
*/
|
|
9
|
+
import { createLocalEngineServer } from './server/index.js';
|
|
10
|
+
import { createWasmEngine } from './wasm-engine.js';
|
|
11
|
+
/**
|
|
12
|
+
* Attaches the buffering listener and boots the engine on the `init` frame.
|
|
13
|
+
*/
|
|
14
|
+
export function bootLocalEngineWorker(options) {
|
|
15
|
+
const { port } = options;
|
|
16
|
+
const scope = globalThis;
|
|
17
|
+
const buffered = [];
|
|
18
|
+
let booting = false;
|
|
19
|
+
const bufferListener = (event) => {
|
|
20
|
+
buffered.push(event);
|
|
21
|
+
const data = event.data;
|
|
22
|
+
if (!booting && data?.kind === 'init' && data.wasmBytes && data.glueSource) {
|
|
23
|
+
booting = true;
|
|
24
|
+
loadWasmModule(data.glueSource)
|
|
25
|
+
.then(async ({ initWasm, wasmModule }) => {
|
|
26
|
+
await initWasm({ module_or_path: data.wasmBytes });
|
|
27
|
+
return wasmModule;
|
|
28
|
+
})
|
|
29
|
+
.then((wasmModule) => {
|
|
30
|
+
scope.removeEventListener('message', bufferListener);
|
|
31
|
+
createLocalEngineServer({ engine: createWasmEngine(wasmModule), port });
|
|
32
|
+
for (const bufferedEvent of buffered.splice(0)) {
|
|
33
|
+
scope.dispatchEvent(new MessageEvent('message', { data: bufferedEvent.data }));
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
.catch((error) => {
|
|
37
|
+
// eslint-disable-next-line no-console
|
|
38
|
+
console.error('[swu-local-worker] wasm init failed', error);
|
|
39
|
+
const message = `wasm init failed: ${String(error)}`;
|
|
40
|
+
port.postMessage({ kind: 'error', id: -1, message });
|
|
41
|
+
// Dead-letter mode: without this, later frames (e.g. a retried
|
|
42
|
+
// `init`) would buffer forever with no response. The worker cannot
|
|
43
|
+
// recover a failed wasm compile — callers must spawn a new one.
|
|
44
|
+
scope.removeEventListener('message', bufferListener);
|
|
45
|
+
const reject = (data) => {
|
|
46
|
+
const id = data?.id;
|
|
47
|
+
if (typeof id === 'number') {
|
|
48
|
+
port.postMessage({ kind: 'error', id, message });
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
for (const bufferedEvent of buffered.splice(0)) {
|
|
52
|
+
reject(bufferedEvent.data);
|
|
53
|
+
}
|
|
54
|
+
scope.addEventListener('message', event => reject(event.data));
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
scope.addEventListener('message', bufferListener);
|
|
59
|
+
}
|
|
60
|
+
/** Imports server-provided wasm-bindgen glue without relying on app bundling. */
|
|
61
|
+
async function loadWasmModule(glueSource) {
|
|
62
|
+
const url = URL.createObjectURL(new Blob([glueSource], { type: 'text/javascript' }));
|
|
63
|
+
try {
|
|
64
|
+
const module = await import(/* @vite-ignore */ url);
|
|
65
|
+
if (typeof module.default !== 'function') {
|
|
66
|
+
throw new Error('wasm glue has no initializer');
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
initWasm: module.default,
|
|
70
|
+
wasmModule: module,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
URL.revokeObjectURL(url);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine worker entry: boots the wasm engine from the transport's `init`
|
|
3
|
+
* frame (which carries server-served wasm, glue, and card asset bytes) and serves the local RPC
|
|
4
|
+
* protocol on the worker port. See `worker-boot.ts` for the sequence.
|
|
5
|
+
*/
|
|
6
|
+
import { bootLocalEngineWorker } from './worker-boot.js';
|
|
7
|
+
bootLocalEngineWorker({
|
|
8
|
+
port: globalThis,
|
|
9
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { MatchAccess, MatchReference, MatchSpectatorAccess } from '../resources/matches.js';
|
|
2
|
+
import type { MatchSessionAccess } from './types.js';
|
|
3
|
+
/** Checks whether access includes response-only session seed fields. */
|
|
4
|
+
export declare function hasAccessSnapshot(access: MatchSessionAccess): access is MatchAccess | MatchSpectatorAccess;
|
|
5
|
+
/** Normalizes a string match id into a match reference. */
|
|
6
|
+
export declare function matchReferenceFrom(match: string | MatchReference): MatchReference;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Checks whether access includes response-only session seed fields. */
|
|
2
|
+
export function hasAccessSnapshot(access) {
|
|
3
|
+
return 'snapshot' in access;
|
|
4
|
+
}
|
|
5
|
+
/** Normalizes a string match id into a match reference. */
|
|
6
|
+
export function matchReferenceFrom(match) {
|
|
7
|
+
return typeof match === 'string' ? { matchId: match } : match;
|
|
8
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { MatchConnection } from '../connection.js';
|
|
2
|
+
import type { CardInteractionCueRequest } from '../generated/types/client-message.js';
|
|
3
|
+
import type { FormatEventCommand } from '../generated/types/format-event-request.js';
|
|
4
|
+
import type { AiStatusPayload, CreateMatchRequest, ErrorPayload, GameCommand, GameEvent, GameState, JoinMatchRequest, SpectateMatchRequest, WelcomePayload } from '../generated/index.js';
|
|
5
|
+
import type { MatchHistoryFeedEntry } from '../generated/types/server-message.js';
|
|
6
|
+
import type { ConnectionState } from '../session.js';
|
|
7
|
+
import type { MatchAccess, MatchConnectionAccessInput, MatchReference, MatchSpectatorAccess, MatchesResource } from '../resources/matches.js';
|
|
8
|
+
import type { MatchSeat, MatchSession, MatchSessionAccess, MatchSessionConnectOptions, MatchSessionEvents, MatchSessionOptions, MatchSessionReconnectState, MatchSessionSnapshotPredicate, MatchSessionState, MatchSessionWaitOptions } from './types.js';
|
|
9
|
+
/** Dependencies required to construct match sessions. */
|
|
10
|
+
export interface MatchSessionControllerOptions {
|
|
11
|
+
/** Initial private access. */
|
|
12
|
+
access?: MatchSessionAccess | undefined;
|
|
13
|
+
/** Default connection/session options. */
|
|
14
|
+
options?: MatchSessionOptions | undefined;
|
|
15
|
+
/** Match HTTP resource used by session lifecycle helpers. */
|
|
16
|
+
matches: MatchesResource;
|
|
17
|
+
/** Opens the internal raw socket connection. */
|
|
18
|
+
openConnection: (access: MatchConnectionAccessInput, options?: MatchSessionConnectOptions) => Promise<MatchConnection>;
|
|
19
|
+
}
|
|
20
|
+
/** SDK-owned live match session implementation. */
|
|
21
|
+
export declare class MatchSessionController implements MatchSession {
|
|
22
|
+
#private;
|
|
23
|
+
/**
|
|
24
|
+
* Vue reactivity opt-out. The controller relies on `#private` class fields
|
|
25
|
+
* which are unreachable through a `Proxy`, so Vue must not wrap it. This
|
|
26
|
+
* is Vue's documented escape hatch (`ReactiveFlags.SKIP`) and is a no-op
|
|
27
|
+
* in non-Vue runtimes.
|
|
28
|
+
*/
|
|
29
|
+
readonly __v_skip = true;
|
|
30
|
+
/** Creates one match session controller. */
|
|
31
|
+
constructor(options: MatchSessionControllerOptions);
|
|
32
|
+
get connectionState(): ConnectionState;
|
|
33
|
+
get aiStatus(): AiStatusPayload | undefined;
|
|
34
|
+
get errors(): readonly ErrorPayload[];
|
|
35
|
+
get events(): readonly GameEvent[];
|
|
36
|
+
get history(): readonly MatchHistoryFeedEntry[];
|
|
37
|
+
get errorMessages(): readonly string[];
|
|
38
|
+
get matchId(): string | undefined;
|
|
39
|
+
get reconnectState(): MatchSessionReconnectState;
|
|
40
|
+
get snapshot(): GameState | undefined;
|
|
41
|
+
get seat(): MatchSeat | undefined;
|
|
42
|
+
get state(): MatchSessionState;
|
|
43
|
+
get welcome(): WelcomePayload | undefined;
|
|
44
|
+
connect(access?: MatchSessionAccess, options?: MatchSessionConnectOptions): Promise<MatchSession>;
|
|
45
|
+
createMatch(request: CreateMatchRequest, options?: MatchSessionConnectOptions): Promise<MatchAccess>;
|
|
46
|
+
joinMatch(match: string | MatchReference, request: JoinMatchRequest, options?: MatchSessionConnectOptions): Promise<MatchAccess>;
|
|
47
|
+
spectateMatch(match: string | MatchReference, request: SpectateMatchRequest, options?: MatchSessionConnectOptions): Promise<MatchSpectatorAccess>;
|
|
48
|
+
close(): void;
|
|
49
|
+
reconnect(options?: MatchSessionConnectOptions): Promise<MatchSession>;
|
|
50
|
+
ready(): void;
|
|
51
|
+
undo(): void;
|
|
52
|
+
respondUndo(approve: boolean): void;
|
|
53
|
+
setAiPaused(paused: boolean): void;
|
|
54
|
+
sync(): void;
|
|
55
|
+
ping(nonce?: string | null): void;
|
|
56
|
+
sendCommand(command: GameCommand): void;
|
|
57
|
+
sendFormatEvent(command: FormatEventCommand): void;
|
|
58
|
+
sendAiFormatEvent(command: FormatEventCommand): void;
|
|
59
|
+
sendChat(message: string): void;
|
|
60
|
+
sendInteractionCue(cue: CardInteractionCueRequest): void;
|
|
61
|
+
on<TKey extends keyof MatchSessionEvents>(event: TKey, listener: (value: MatchSessionEvents[TKey]) => void): () => void;
|
|
62
|
+
waitForSnapshot(predicate?: MatchSessionSnapshotPredicate, options?: MatchSessionWaitOptions): Promise<GameState>;
|
|
63
|
+
}
|