diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-02-14 20:32:47 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-02-14 20:32:47 +0900 |
| commit | 9185367fcd7d95af89fac36dd892d8b064dbd94f (patch) | |
| tree | 6085f0c4ab695d0f83348f32b49b5481f1da6548 | |
| parent | 6bd35e345a4c5d74578b0f8a5c969027e7e15f02 (diff) | |
| download | phperkaigi-2026-albatross-9185367fcd7d95af89fac36dd892d8b064dbd94f.tar.gz phperkaigi-2026-albatross-9185367fcd7d95af89fac36dd892d8b064dbd94f.tar.zst phperkaigi-2026-albatross-9185367fcd7d95af89fac36dd892d8b064dbd94f.zip | |
feat(openapi): generate OpenAPI specs from TypeSpec sources
Migrate hand-written OpenAPI YAML to TypeSpec (.tsp) source files.
TypeSpec compiles to OpenAPI 3.0 YAML, enabling type-safe API definitions.
- Add typespec/ directory with api-server and fortee definitions
- Integrate TypeSpec build into `just gen` and `just build` pipelines
- Update backend handler code to match new generated type names
(inlined error responses, separate GameType/ProblemLanguage enums)
- Regenerate frontend TypeScript types from new OpenAPI output
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| -rw-r--r-- | .gitignore | 4 | ||||
| -rw-r--r-- | backend/api/generated.go | 254 | ||||
| -rw-r--r-- | backend/api/handler.go | 28 | ||||
| -rw-r--r-- | backend/api/handler_wrapper.go | 40 | ||||
| -rw-r--r-- | backend/gen/api/handler_wrapper_gen.go | 8 | ||||
| -rw-r--r-- | frontend/app/api/schema.d.ts | 589 | ||||
| -rw-r--r-- | justfile | 2 | ||||
| -rw-r--r-- | openapi/api-server.yaml | 630 | ||||
| -rw-r--r-- | openapi/fortee.yaml | 52 | ||||
| -rw-r--r-- | typespec/api-server/main.tsp | 17 | ||||
| -rw-r--r-- | typespec/api-server/models.tsp | 119 | ||||
| -rw-r--r-- | typespec/api-server/routes.tsp | 126 | ||||
| -rw-r--r-- | typespec/api-server/tspconfig.yaml | 8 | ||||
| -rw-r--r-- | typespec/fortee/main.tsp | 45 | ||||
| -rw-r--r-- | typespec/fortee/tspconfig.yaml | 8 | ||||
| -rw-r--r-- | typespec/package-lock.json | 1435 | ||||
| -rw-r--r-- | typespec/package.json | 15 |
17 files changed, 2638 insertions, 742 deletions
@@ -1 +1,5 @@ /.env +/typespec/node_modules/ +/typespec/tsp-output/ +/typespec/api-server/tsp-output/ +/typespec/fortee/tsp-output/ diff --git a/backend/api/generated.go b/backend/api/generated.go index 781e709..1cc692c 100644 --- a/backend/api/generated.go +++ b/backend/api/generated.go @@ -34,10 +34,10 @@ const ( WrongAnswer ExecutionStatus = "wrong_answer" ) -// Defines values for GameGameType. +// Defines values for GameType. const ( - Multiplayer GameGameType = "multiplayer" - N1V1 GameGameType = "1v1" + Multiplayer GameType = "multiplayer" + N1V1 GameType = "1v1" ) // Defines values for ProblemLanguage. @@ -56,18 +56,18 @@ type ExecutionStatus string // Game defines model for Game. type Game struct { - DisplayName string `json:"display_name"` - DurationSeconds int `json:"duration_seconds"` - GameID int `json:"game_id"` - GameType GameGameType `json:"game_type"` - IsPublic bool `json:"is_public"` - MainPlayers []User `json:"main_players"` - Problem Problem `json:"problem"` - StartedAt *int64 `json:"started_at,omitempty"` + DisplayName string `json:"display_name"` + DurationSeconds int `json:"duration_seconds"` + GameID int `json:"game_id"` + GameType GameType `json:"game_type"` + IsPublic bool `json:"is_public"` + MainPlayers []User `json:"main_players"` + Problem Problem `json:"problem"` + StartedAt *int64 `json:"started_at,omitempty"` } -// GameGameType defines model for Game.GameType. -type GameGameType string +// GameType defines model for GameType. +type GameType string // LatestGameState defines model for LatestGameState. type LatestGameState struct { @@ -86,7 +86,7 @@ type Problem struct { Title string `json:"title"` } -// ProblemLanguage defines model for Problem.Language. +// ProblemLanguage defines model for ProblemLanguage. type ProblemLanguage string // RankingEntry defines model for RankingEntry. @@ -122,21 +122,6 @@ type User struct { Username string `json:"username"` } -// PathGameID defines model for path_game_id. -type PathGameID = int - -// BadRequest defines model for BadRequest. -type BadRequest = Error - -// Forbidden defines model for Forbidden. -type Forbidden = Error - -// NotFound defines model for NotFound. -type NotFound = Error - -// Unauthorized defines model for Unauthorized. -type Unauthorized = Error - // PostGamePlayCodeJSONBody defines parameters for PostGamePlayCode. type PostGamePlayCodeJSONBody struct { Code string `json:"code"` @@ -173,37 +158,37 @@ type PostLoginJSONRequestBody PostLoginJSONBody // ServerInterface represents all server handlers. type ServerInterface interface { - // List games + // (GET /games) GetGames(ctx echo.Context) error - // Get a game + // (GET /games/{game_id}) - GetGame(ctx echo.Context, gameID PathGameID) error - // Post the latest code + GetGame(ctx echo.Context, gameID int) error + // (POST /games/{game_id}/play/code) - PostGamePlayCode(ctx echo.Context, gameID PathGameID) error - // Get the latest execution result for player + PostGamePlayCode(ctx echo.Context, gameID int) error + // (GET /games/{game_id}/play/latest_state) - GetGamePlayLatestState(ctx echo.Context, gameID PathGameID) error - // Submit the answer + GetGamePlayLatestState(ctx echo.Context, gameID int) error + // (POST /games/{game_id}/play/submit) - PostGamePlaySubmit(ctx echo.Context, gameID PathGameID) error - // Get all the latest game states of the main players + PostGamePlaySubmit(ctx echo.Context, gameID int) error + // (GET /games/{game_id}/watch/latest_states) - GetGameWatchLatestStates(ctx echo.Context, gameID PathGameID) error - // Get the latest player ranking + GetGameWatchLatestStates(ctx echo.Context, gameID int) error + // (GET /games/{game_id}/watch/ranking) - GetGameWatchRanking(ctx echo.Context, gameID PathGameID) error - // User login + GetGameWatchRanking(ctx echo.Context, gameID int) error + // (POST /login) PostLogin(ctx echo.Context) error - // User logout + // (POST /logout) PostLogout(ctx echo.Context) error - // Get current user + // (GET /me) GetMe(ctx echo.Context) error - // Get tournament bracket data + // (GET /tournament) GetTournament(ctx echo.Context, params GetTournamentParams) error } @@ -226,7 +211,7 @@ func (w *ServerInterfaceWrapper) GetGames(ctx echo.Context) error { func (w *ServerInterfaceWrapper) GetGame(ctx echo.Context) error { var err error // ------------- Path parameter "game_id" ------------- - var gameID PathGameID + var gameID int err = runtime.BindStyledParameterWithOptions("simple", "game_id", ctx.Param("game_id"), &gameID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) if err != nil { @@ -242,7 +227,7 @@ func (w *ServerInterfaceWrapper) GetGame(ctx echo.Context) error { func (w *ServerInterfaceWrapper) PostGamePlayCode(ctx echo.Context) error { var err error // ------------- Path parameter "game_id" ------------- - var gameID PathGameID + var gameID int err = runtime.BindStyledParameterWithOptions("simple", "game_id", ctx.Param("game_id"), &gameID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) if err != nil { @@ -258,7 +243,7 @@ func (w *ServerInterfaceWrapper) PostGamePlayCode(ctx echo.Context) error { func (w *ServerInterfaceWrapper) GetGamePlayLatestState(ctx echo.Context) error { var err error // ------------- Path parameter "game_id" ------------- - var gameID PathGameID + var gameID int err = runtime.BindStyledParameterWithOptions("simple", "game_id", ctx.Param("game_id"), &gameID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) if err != nil { @@ -274,7 +259,7 @@ func (w *ServerInterfaceWrapper) GetGamePlayLatestState(ctx echo.Context) error func (w *ServerInterfaceWrapper) PostGamePlaySubmit(ctx echo.Context) error { var err error // ------------- Path parameter "game_id" ------------- - var gameID PathGameID + var gameID int err = runtime.BindStyledParameterWithOptions("simple", "game_id", ctx.Param("game_id"), &gameID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) if err != nil { @@ -290,7 +275,7 @@ func (w *ServerInterfaceWrapper) PostGamePlaySubmit(ctx echo.Context) error { func (w *ServerInterfaceWrapper) GetGameWatchLatestStates(ctx echo.Context) error { var err error // ------------- Path parameter "game_id" ------------- - var gameID PathGameID + var gameID int err = runtime.BindStyledParameterWithOptions("simple", "game_id", ctx.Param("game_id"), &gameID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) if err != nil { @@ -306,7 +291,7 @@ func (w *ServerInterfaceWrapper) GetGameWatchLatestStates(ctx echo.Context) erro func (w *ServerInterfaceWrapper) GetGameWatchRanking(ctx echo.Context) error { var err error // ------------- Path parameter "game_id" ------------- - var gameID PathGameID + var gameID int err = runtime.BindStyledParameterWithOptions("simple", "game_id", ctx.Param("game_id"), &gameID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) if err != nil { @@ -353,35 +338,35 @@ func (w *ServerInterfaceWrapper) GetTournament(ctx echo.Context) error { var params GetTournamentParams // ------------- Required query parameter "game1" ------------- - err = runtime.BindQueryParameter("form", true, true, "game1", ctx.QueryParams(), ¶ms.Game1) + err = runtime.BindQueryParameter("form", false, true, "game1", ctx.QueryParams(), ¶ms.Game1) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter game1: %s", err)) } // ------------- Required query parameter "game2" ------------- - err = runtime.BindQueryParameter("form", true, true, "game2", ctx.QueryParams(), ¶ms.Game2) + err = runtime.BindQueryParameter("form", false, true, "game2", ctx.QueryParams(), ¶ms.Game2) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter game2: %s", err)) } // ------------- Required query parameter "game3" ------------- - err = runtime.BindQueryParameter("form", true, true, "game3", ctx.QueryParams(), ¶ms.Game3) + err = runtime.BindQueryParameter("form", false, true, "game3", ctx.QueryParams(), ¶ms.Game3) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter game3: %s", err)) } // ------------- Required query parameter "game4" ------------- - err = runtime.BindQueryParameter("form", true, true, "game4", ctx.QueryParams(), ¶ms.Game4) + err = runtime.BindQueryParameter("form", false, true, "game4", ctx.QueryParams(), ¶ms.Game4) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter game4: %s", err)) } // ------------- Required query parameter "game5" ------------- - err = runtime.BindQueryParameter("form", true, true, "game5", ctx.QueryParams(), ¶ms.Game5) + err = runtime.BindQueryParameter("form", false, true, "game5", ctx.QueryParams(), ¶ms.Game5) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter game5: %s", err)) } @@ -433,14 +418,6 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL } -type BadRequestJSONResponse Error - -type ForbiddenJSONResponse Error - -type NotFoundJSONResponse Error - -type UnauthorizedJSONResponse Error - type GetGamesRequestObject struct { } @@ -459,7 +436,7 @@ func (response GetGames200JSONResponse) VisitGetGamesResponse(w http.ResponseWri return json.NewEncoder(w).Encode(response) } -type GetGames401JSONResponse struct{ UnauthorizedJSONResponse } +type GetGames401JSONResponse Error func (response GetGames401JSONResponse) VisitGetGamesResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -468,7 +445,7 @@ func (response GetGames401JSONResponse) VisitGetGamesResponse(w http.ResponseWri return json.NewEncoder(w).Encode(response) } -type GetGames403JSONResponse struct{ ForbiddenJSONResponse } +type GetGames403JSONResponse Error func (response GetGames403JSONResponse) VisitGetGamesResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -478,7 +455,7 @@ func (response GetGames403JSONResponse) VisitGetGamesResponse(w http.ResponseWri } type GetGameRequestObject struct { - GameID PathGameID `json:"game_id"` + GameID int `json:"game_id"` } type GetGameResponseObject interface { @@ -496,7 +473,7 @@ func (response GetGame200JSONResponse) VisitGetGameResponse(w http.ResponseWrite return json.NewEncoder(w).Encode(response) } -type GetGame401JSONResponse struct{ UnauthorizedJSONResponse } +type GetGame401JSONResponse Error func (response GetGame401JSONResponse) VisitGetGameResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -505,7 +482,7 @@ func (response GetGame401JSONResponse) VisitGetGameResponse(w http.ResponseWrite return json.NewEncoder(w).Encode(response) } -type GetGame403JSONResponse struct{ ForbiddenJSONResponse } +type GetGame403JSONResponse Error func (response GetGame403JSONResponse) VisitGetGameResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -514,7 +491,7 @@ func (response GetGame403JSONResponse) VisitGetGameResponse(w http.ResponseWrite return json.NewEncoder(w).Encode(response) } -type GetGame404JSONResponse struct{ NotFoundJSONResponse } +type GetGame404JSONResponse Error func (response GetGame404JSONResponse) VisitGetGameResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -524,7 +501,7 @@ func (response GetGame404JSONResponse) VisitGetGameResponse(w http.ResponseWrite } type PostGamePlayCodeRequestObject struct { - GameID PathGameID `json:"game_id"` + GameID int `json:"game_id"` Body *PostGamePlayCodeJSONRequestBody } @@ -540,7 +517,7 @@ func (response PostGamePlayCode200Response) VisitPostGamePlayCodeResponse(w http return nil } -type PostGamePlayCode401JSONResponse struct{ UnauthorizedJSONResponse } +type PostGamePlayCode401JSONResponse Error func (response PostGamePlayCode401JSONResponse) VisitPostGamePlayCodeResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -549,7 +526,7 @@ func (response PostGamePlayCode401JSONResponse) VisitPostGamePlayCodeResponse(w return json.NewEncoder(w).Encode(response) } -type PostGamePlayCode403JSONResponse struct{ ForbiddenJSONResponse } +type PostGamePlayCode403JSONResponse Error func (response PostGamePlayCode403JSONResponse) VisitPostGamePlayCodeResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -558,7 +535,7 @@ func (response PostGamePlayCode403JSONResponse) VisitPostGamePlayCodeResponse(w return json.NewEncoder(w).Encode(response) } -type PostGamePlayCode404JSONResponse struct{ NotFoundJSONResponse } +type PostGamePlayCode404JSONResponse Error func (response PostGamePlayCode404JSONResponse) VisitPostGamePlayCodeResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -568,7 +545,7 @@ func (response PostGamePlayCode404JSONResponse) VisitPostGamePlayCodeResponse(w } type GetGamePlayLatestStateRequestObject struct { - GameID PathGameID `json:"game_id"` + GameID int `json:"game_id"` } type GetGamePlayLatestStateResponseObject interface { @@ -586,7 +563,7 @@ func (response GetGamePlayLatestState200JSONResponse) VisitGetGamePlayLatestStat return json.NewEncoder(w).Encode(response) } -type GetGamePlayLatestState401JSONResponse struct{ UnauthorizedJSONResponse } +type GetGamePlayLatestState401JSONResponse Error func (response GetGamePlayLatestState401JSONResponse) VisitGetGamePlayLatestStateResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -595,7 +572,7 @@ func (response GetGamePlayLatestState401JSONResponse) VisitGetGamePlayLatestStat return json.NewEncoder(w).Encode(response) } -type GetGamePlayLatestState403JSONResponse struct{ ForbiddenJSONResponse } +type GetGamePlayLatestState403JSONResponse Error func (response GetGamePlayLatestState403JSONResponse) VisitGetGamePlayLatestStateResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -604,7 +581,7 @@ func (response GetGamePlayLatestState403JSONResponse) VisitGetGamePlayLatestStat return json.NewEncoder(w).Encode(response) } -type GetGamePlayLatestState404JSONResponse struct{ NotFoundJSONResponse } +type GetGamePlayLatestState404JSONResponse Error func (response GetGamePlayLatestState404JSONResponse) VisitGetGamePlayLatestStateResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -614,7 +591,7 @@ func (response GetGamePlayLatestState404JSONResponse) VisitGetGamePlayLatestStat } type PostGamePlaySubmitRequestObject struct { - GameID PathGameID `json:"game_id"` + GameID int `json:"game_id"` Body *PostGamePlaySubmitJSONRequestBody } @@ -630,7 +607,7 @@ func (response PostGamePlaySubmit200Response) VisitPostGamePlaySubmitResponse(w return nil } -type PostGamePlaySubmit401JSONResponse struct{ UnauthorizedJSONResponse } +type PostGamePlaySubmit401JSONResponse Error func (response PostGamePlaySubmit401JSONResponse) VisitPostGamePlaySubmitResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -639,7 +616,7 @@ func (response PostGamePlaySubmit401JSONResponse) VisitPostGamePlaySubmitRespons return json.NewEncoder(w).Encode(response) } -type PostGamePlaySubmit403JSONResponse struct{ ForbiddenJSONResponse } +type PostGamePlaySubmit403JSONResponse Error func (response PostGamePlaySubmit403JSONResponse) VisitPostGamePlaySubmitResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -648,7 +625,7 @@ func (response PostGamePlaySubmit403JSONResponse) VisitPostGamePlaySubmitRespons return json.NewEncoder(w).Encode(response) } -type PostGamePlaySubmit404JSONResponse struct{ NotFoundJSONResponse } +type PostGamePlaySubmit404JSONResponse Error func (response PostGamePlaySubmit404JSONResponse) VisitPostGamePlaySubmitResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -658,7 +635,7 @@ func (response PostGamePlaySubmit404JSONResponse) VisitPostGamePlaySubmitRespons } type GetGameWatchLatestStatesRequestObject struct { - GameID PathGameID `json:"game_id"` + GameID int `json:"game_id"` } type GetGameWatchLatestStatesResponseObject interface { @@ -676,7 +653,7 @@ func (response GetGameWatchLatestStates200JSONResponse) VisitGetGameWatchLatestS return json.NewEncoder(w).Encode(response) } -type GetGameWatchLatestStates401JSONResponse struct{ UnauthorizedJSONResponse } +type GetGameWatchLatestStates401JSONResponse Error func (response GetGameWatchLatestStates401JSONResponse) VisitGetGameWatchLatestStatesResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -685,7 +662,7 @@ func (response GetGameWatchLatestStates401JSONResponse) VisitGetGameWatchLatestS return json.NewEncoder(w).Encode(response) } -type GetGameWatchLatestStates403JSONResponse struct{ ForbiddenJSONResponse } +type GetGameWatchLatestStates403JSONResponse Error func (response GetGameWatchLatestStates403JSONResponse) VisitGetGameWatchLatestStatesResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -694,7 +671,7 @@ func (response GetGameWatchLatestStates403JSONResponse) VisitGetGameWatchLatestS return json.NewEncoder(w).Encode(response) } -type GetGameWatchLatestStates404JSONResponse struct{ NotFoundJSONResponse } +type GetGameWatchLatestStates404JSONResponse Error func (response GetGameWatchLatestStates404JSONResponse) VisitGetGameWatchLatestStatesResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -704,7 +681,7 @@ func (response GetGameWatchLatestStates404JSONResponse) VisitGetGameWatchLatestS } type GetGameWatchRankingRequestObject struct { - GameID PathGameID `json:"game_id"` + GameID int `json:"game_id"` } type GetGameWatchRankingResponseObject interface { @@ -722,7 +699,7 @@ func (response GetGameWatchRanking200JSONResponse) VisitGetGameWatchRankingRespo return json.NewEncoder(w).Encode(response) } -type GetGameWatchRanking401JSONResponse struct{ UnauthorizedJSONResponse } +type GetGameWatchRanking401JSONResponse Error func (response GetGameWatchRanking401JSONResponse) VisitGetGameWatchRankingResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -731,7 +708,7 @@ func (response GetGameWatchRanking401JSONResponse) VisitGetGameWatchRankingRespo return json.NewEncoder(w).Encode(response) } -type GetGameWatchRanking403JSONResponse struct{ ForbiddenJSONResponse } +type GetGameWatchRanking403JSONResponse Error func (response GetGameWatchRanking403JSONResponse) VisitGetGameWatchRankingResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -740,7 +717,7 @@ func (response GetGameWatchRanking403JSONResponse) VisitGetGameWatchRankingRespo return json.NewEncoder(w).Encode(response) } -type GetGameWatchRanking404JSONResponse struct{ NotFoundJSONResponse } +type GetGameWatchRanking404JSONResponse Error func (response GetGameWatchRanking404JSONResponse) VisitGetGameWatchRankingResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -768,7 +745,7 @@ func (response PostLogin200JSONResponse) VisitPostLoginResponse(w http.ResponseW return json.NewEncoder(w).Encode(response) } -type PostLogin401JSONResponse struct{ UnauthorizedJSONResponse } +type PostLogin401JSONResponse Error func (response PostLogin401JSONResponse) VisitPostLoginResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -792,7 +769,7 @@ func (response PostLogout200Response) VisitPostLogoutResponse(w http.ResponseWri return nil } -type PostLogout401JSONResponse struct{ UnauthorizedJSONResponse } +type PostLogout401JSONResponse Error func (response PostLogout401JSONResponse) VisitPostLogoutResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -819,7 +796,7 @@ func (response GetMe200JSONResponse) VisitGetMeResponse(w http.ResponseWriter) e return json.NewEncoder(w).Encode(response) } -type GetMe401JSONResponse struct{ UnauthorizedJSONResponse } +type GetMe401JSONResponse Error func (response GetMe401JSONResponse) VisitGetMeResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -847,7 +824,7 @@ func (response GetTournament200JSONResponse) VisitGetTournamentResponse(w http.R return json.NewEncoder(w).Encode(response) } -type GetTournament401JSONResponse struct{ UnauthorizedJSONResponse } +type GetTournament401JSONResponse Error func (response GetTournament401JSONResponse) VisitGetTournamentResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -856,7 +833,7 @@ func (response GetTournament401JSONResponse) VisitGetTournamentResponse(w http.R return json.NewEncoder(w).Encode(response) } -type GetTournament403JSONResponse struct{ ForbiddenJSONResponse } +type GetTournament403JSONResponse Error func (response GetTournament403JSONResponse) VisitGetTournamentResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -865,7 +842,7 @@ func (response GetTournament403JSONResponse) VisitGetTournamentResponse(w http.R return json.NewEncoder(w).Encode(response) } -type GetTournament404JSONResponse struct{ NotFoundJSONResponse } +type GetTournament404JSONResponse Error func (response GetTournament404JSONResponse) VisitGetTournamentResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") @@ -876,37 +853,37 @@ func (response GetTournament404JSONResponse) VisitGetTournamentResponse(w http.R // StrictServerInterface represents all server handlers. type StrictServerInterface interface { - // List games + // (GET /games) GetGames(ctx context.Context, request GetGamesRequestObject) (GetGamesResponseObject, error) - // Get a game + // (GET /games/{game_id}) GetGame(ctx context.Context, request GetGameRequestObject) (GetGameResponseObject, error) - // Post the latest code + // (POST /games/{game_id}/play/code) PostGamePlayCode(ctx context.Context, request PostGamePlayCodeRequestObject) (PostGamePlayCodeResponseObject, error) - // Get the latest execution result for player + // (GET /games/{game_id}/play/latest_state) GetGamePlayLatestState(ctx context.Context, request GetGamePlayLatestStateRequestObject) (GetGamePlayLatestStateResponseObject, error) - // Submit the answer + // (POST /games/{game_id}/play/submit) PostGamePlaySubmit(ctx context.Context, request PostGamePlaySubmitRequestObject) (PostGamePlaySubmitResponseObject, error) - // Get all the latest game states of the main players + // (GET /games/{game_id}/watch/latest_states) GetGameWatchLatestStates(ctx context.Context, request GetGameWatchLatestStatesRequestObject) (GetGameWatchLatestStatesResponseObject, error) - // Get the latest player ranking + // (GET /games/{game_id}/watch/ranking) GetGameWatchRanking(ctx context.Context, request GetGameWatchRankingRequestObject) (GetGameWatchRankingResponseObject, error) - // User login + // (POST /login) PostLogin(ctx context.Context, request PostLoginRequestObject) (PostLoginResponseObject, error) - // User logout + // (POST /logout) PostLogout(ctx context.Context, request PostLogoutRequestObject) (PostLogoutResponseObject, error) - // Get current user + // (GET /me) GetMe(ctx context.Context, request GetMeRequestObject) (GetMeResponseObject, error) - // Get tournament bracket data + // (GET /tournament) GetTournament(ctx context.Context, request GetTournamentRequestObject) (GetTournamentResponseObject, error) } @@ -947,7 +924,7 @@ func (sh *strictHandler) GetGames(ctx echo.Context) error { } // GetGame operation middleware -func (sh *strictHandler) GetGame(ctx echo.Context, gameID PathGameID) error { +func (sh *strictHandler) GetGame(ctx echo.Context, gameID int) error { var request GetGameRequestObject request.GameID = gameID @@ -972,7 +949,7 @@ func (sh *strictHandler) GetGame(ctx echo.Context, gameID PathGameID) error { } // PostGamePlayCode operation middleware -func (sh *strictHandler) PostGamePlayCode(ctx echo.Context, gameID PathGameID) error { +func (sh *strictHandler) PostGamePlayCode(ctx echo.Context, gameID int) error { var request PostGamePlayCodeRequestObject request.GameID = gameID @@ -1003,7 +980,7 @@ func (sh *strictHandler) PostGamePlayCode(ctx echo.Context, gameID PathGameID) e } // GetGamePlayLatestState operation middleware -func (sh *strictHandler) GetGamePlayLatestState(ctx echo.Context, gameID PathGameID) error { +func (sh *strictHandler) GetGamePlayLatestState(ctx echo.Context, gameID int) error { var request GetGamePlayLatestStateRequestObject request.GameID = gameID @@ -1028,7 +1005,7 @@ func (sh *strictHandler) GetGamePlayLatestState(ctx echo.Context, gameID PathGam } // PostGamePlaySubmit operation middleware -func (sh *strictHandler) PostGamePlaySubmit(ctx echo.Context, gameID PathGameID) error { +func (sh *strictHandler) PostGamePlaySubmit(ctx echo.Context, gameID int) error { var request PostGamePlaySubmitRequestObject request.GameID = gameID @@ -1059,7 +1036,7 @@ func (sh *strictHandler) PostGamePlaySubmit(ctx echo.Context, gameID PathGameID) } // GetGameWatchLatestStates operation middleware -func (sh *strictHandler) GetGameWatchLatestStates(ctx echo.Context, gameID PathGameID) error { +func (sh *strictHandler) GetGameWatchLatestStates(ctx echo.Context, gameID int) error { var request GetGameWatchLatestStatesRequestObject request.GameID = gameID @@ -1084,7 +1061,7 @@ func (sh *strictHandler) GetGameWatchLatestStates(ctx echo.Context, gameID PathG } // GetGameWatchRanking operation middleware -func (sh *strictHandler) GetGameWatchRanking(ctx echo.Context, gameID PathGameID) error { +func (sh *strictHandler) GetGameWatchRanking(ctx echo.Context, gameID int) error { var request GetGameWatchRankingRequestObject request.GameID = gameID @@ -1211,33 +1188,28 @@ func (sh *strictHandler) GetTournament(ctx echo.Context, params GetTournamentPar // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xaW2/buBL+KwTPAfqixs7lBD3Zp7TbFl20hdELFouiEGhpbDOlSJWk6noL/ffFkJJ1", - "t+XELRJg3yKJM5yZ75vhDOMfNFJJqiRIa+jVD5oyzRKwoIsnuwqXLIGQx/jMJb1yL2lAJUuAXtHya0A1", - "fM24hpheWZ1BQE20goShmN2kuJRLC0vQNM9zXG1SJQ24fZ6y+B18zcBYfIqUtCDdnyxNBY+Y5UpOboyS", - "+K7S+18NC3pF/zOpfJj4r2byXGtVbBWDiTRPUQm9wr2ILjbLA/pC6TmPY5A/f+dqqzygb5V9oTIZ//xt", - "3ypLFm6rPKAfJcvsSmn+N/yCrRu74edCAhV6ISSZViloyz0VEjCGLQH/hO8sSQUy55X8xgSvcAtKShmr", - "uVxST6iSfp+2Sj5vF6r5DUQO8OffIcrQvveW2cztCTJLUEwqCUjkTErUGlCTRREYQwO61kouQybNGjRu", - "zxNQGRqC4eACQnDuOGH8uH1G0mvJRPHic1Bzq1LfciegL112tYMTc5MKtgll8bVShevJaZ+mONMO09BA", - "pGRsGnLnl9Ogk54BraX8dunp4EL/ugrj6Tc0JMmE5WgttLz2nzt2chOm2VzwqLGrLyXF4rlSAphLn4Rx", - "GXrtziNuITH7ePrReKsLdUxrtsHnVKu5gGSf+KxYhjy2TFuIQ2Yb1v7/4vLyycWTaTeoAf3+eKkeV28v", - "LzqsrUppFdZ6XIIm/j3QVq60ItSXCK+ZBWOROJgJPWybg7GhiZSG0GTzhNvdHstMCDbvgLYzApg/cYvK", - "EK0UebQCIRRZKy3iR7/18cUZ1mToCCs8dkXe76xprTLRBsvZXVoRDMZqu10fArOKd608r1fRemw+rLgh", - "3BBGKqA7kRFMLrOyhhY5ma5StGXNF7aZjf5DR0ehflQRMO5jeGskLbeiJVlEpq+itXCoGVpqap5CtXg0", - "Te1D5B2TX7hcPpdWb7qwjPVwgIO16PqyOLJcDTC9B4gRWXqLulRYW5G9xfDBaH5QmcZS5fuL1jnPbLSC", - "8bW70vUGJbtlvN0CFPp32+V1dYwbff750JyORbJYHvYgOqz97DDtZ2O1r7mUnoS71g2cUX1hdXYc0LP8", - "oVaS/K6gtxuIlAzdpNEQmfCELcFMbtRKntyky4FGgsUJb1bOBROmt5EQbA6iuYmxbLEYk8aZAd2hydl5", - "X7BxaTcC6MbeClfuUlPS6QS2PpcOdfFBtVwulBvIfMWl12LOrFbGkLJNJWuYk+vZKxrQb6CNb+OnJ+cn", - "U/RCpSBZyukVPT+Znkyx32B25WCeIDN88oBLd+SA605exdifgus0DG1NfmfT6UFjSDdPx5cQ11Pvqxte", - "ZX/4msPNa24sUQviJfKAXkwHC8HW50lzJEKh8/1CtcnRlfkkYXg+eROK/fOgwGDyo0jSfB8aDr9q3v/U", - "b0a1ZNK4D8g/Hx3LcQj2IDYKsGsXql+GFEpc7JfYXgQ0oX0JlrDC4B5oJ5j9k7IhSZXpQXmmfHs/E2zz", - "zLerd4bbzd9PVby5A9K3bBT7GvB+2Js3UXk/TZvceO9H8UUmxIZkacxsCfq9ZwrCTOwKiHADHXGBGeaM", - "XxWacubbVSCQOX5M9CPifaoXWwd2FYz2jNsmkVcypnj8pTJdRhg9Il704RSTGkOgnG2JBpMJSxZKk6LL", - "HyaO7/rHlZv3fu2/BWdcwdkOVA+ETx5eR6niSrSXNmucrhoFZ2+D+CeK1EqOuX81x/3F4pijCBOzxoqD", - "ilGXSz3VaVwzei1EPcOrCmWwRcUvCeOSlPeBD6gHOtCxYR5qf7czioHFPdC9Il/N/lHjTuMua9/YUyof", - "w7WZizUpRR7kEZi2fEDaCLX0twbD59trt+RY51LKjFkr3bxA2L49PTunA5cOd7hJkOXcV2x9hwPtll5n", - "ZuzVZ4/5owjaOFuRdCAtWnfr87XBJLSNeK6UtFGZ3csb/+/CAxsDoZZLiAnKHtFypw5NT3ZOAG+APjDg", - "n2Vag7QEBYi77DpC1LByRDXFPnS2cbc9FMLaDXjnKHE/pviagd40f01xethvKYJhTWdH03R+NE0XR9P0", - "v8M0HfcwbsI/7h8XHV7XlIxhd6WJxMyyh3TwVpbPNYu+QOlBnuf/BAAA//9b1VG2giQAAA==", + "H4sIAAAAAAAC/+xaW2/bNhT+KwK3R9V2LtuD37IhKAqkgLFm2ENRCJR0bLOjSJWXOF7g/z6QlKwbJctN", + "ssGp3xyJPNfvO+eQyhNKeJZzBkxJNH9CMllDhu3PWyG4MD9ywXMQioB9nIGUeAXmp9rmgOZIKkHYCu12", + "IRLwTRMBKZp/3i/8EpYLefwVEoV2Ibp9hEQrwtknhZW2coHpzGxjnAEKkdCMGakhkjpJQEoUoo3gbBVh", + "JjcgUIgUyYBrhULrA6EQgTXZbjYv938TpkAwTIsHlUWl6SF6jzPoOpsSmVO8jVjxtrMt1QIbPyIJCWep", + "rC0ySlcgzKoVziAi6cBL9/gJ/Sxgiebop2mVlmmRk6kx8d6s24WIyCjXMSVJTWbMOQXMzOsMExYZy0FY", + "k4iCTB6S/6d0BhXisBB4a/7OBY8pZIe2L4pluxBJhYWCNMLK43KIHt+t+Lvq6a/XHeyUAatHp+502MyM", + "Jw+V2a1o+OC4j2wNhxcPF2arpoq4rV7Y3GEFUpn9BskeBMUgVSQTLiCSOs6IquLCNKU4poDmSmgIR8XJ", + "YD31Q9EqGSHX5adg3VBC2yRtJ8laUuoNez3dq/NFflFhq8U8kIkguVHv9ZZittJFHRqByrtyeYXnXkJK", + "nOUUot5AK6LoiPpXU1PuCRtu1ZxoKh0I1F3N7RKp+To3AjZkqbwY/QOzvwlb3TIltt1Al272oKYSU7Bg", + "ZBHZo9ET3xYPvqM+FLZU4GshrjeM91wLUzKY8nQ2rJI1jK+XlayPZme3dLYbYiF/2C4nq2PcYAtx4bgY", + "m5tieTSQI7fk8jiJl0MSN4QxB5/2u57a7wuT1Xd8lyYJZ1GO1dr/VkY4zQjzt1KKY6CjCKIliN4UmZc9", + "9rX8L8XU9nTa3d7k0r5usIxYwpbcKnQVC93QGCvBpQzKiSjYQBzcLD6gED2AkLbaotnkajIzRvMcGM4J", + "mqOryWwyM00Vq7WN+dSkySETLJdMQmwL/pCiOXoPtimaPixA5pxJt/hyNnNFh6mCgzjPKUnszulX6aq9", + "g5efBOP5aUe6Q6R0Iv3ha/QgdL+GwOwEqYI1loGdSyGFdGKUXM8ujnJssPHaKdVjwo2dhAMiA82wVmsu", + "yD97/Vf/pf4lFzFJU2ATs24XFniYPhXs3R1ChsWSwBkoO6J+fkKGgBZfKESOKbUxsEqZI1/lSKeafHlx", + "yI0DmgdYZ1w9B1dG+fXrKzfxlyAeQAQJZoyrYElYGqgqLZAGAiTXIoE+uE9NdZ6Ws1TOpQf5C+5OCguK", + "t7+72fk1KWBN/42n22egv2cG9h0E/FBvGr3zU/PMhzfKB2pPx5Esj8ZDDcGwwp2m3Un6RPrD3rehWLdv", + "CdoEckLOzeKHIoc7so5rF5/c2nPDODeMt8qJDVbJutExDp4u/zJbaj1DnlTTsL9wmhKzBdNFY8VR3aRL", + "JE97OR9yfzQuCXfvO4pFxR3xqRCo5tqoq6DGFfihK6FS+Jkvb5UvlK/cdW//5HVnl7zUWJRjKTdcpN77", + "5+Ouhll5eVZIfMYY9Z3OaDn2M5DH/JNn1R5BXKuDEHL/nnDaI6xzOBs8wH8EdIbYC0dcNT5V9kW+9kGz", + "07vhMaf2PLbEVELoevk3DWLbbOYXx7XycLzky1eTfPVqkq9fTfIv/+fI1ITTuO/aHXrVhJynozc5He12", + "/wYAAP//Hl9qBRMoAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/backend/api/handler.go b/backend/api/handler.go index 3b04665..25aea01 100644 --- a/backend/api/handler.go +++ b/backend/api/handler.go @@ -53,18 +53,14 @@ func (h *Handler) PostLogin(ctx context.Context, request PostLoginRequestObject) msg = "ユーザー名またはパスワードが誤っています" } return PostLogin401JSONResponse{ - UnauthorizedJSONResponse: UnauthorizedJSONResponse{ - Message: msg, - }, + Message: msg, }, nil } dbUser, err := h.q.GetUserByID(ctx, int32(userID)) if err != nil { return PostLogin401JSONResponse{ - UnauthorizedJSONResponse: UnauthorizedJSONResponse{ - Message: "ログインに失敗しました", - }, + Message: "ログインに失敗しました", }, nil } @@ -100,9 +96,7 @@ func (h *Handler) GetMe(ctx context.Context, _ GetMeRequestObject, claims *auth. dbUser, err := h.q.GetUserByID(ctx, int32(claims.UserID)) if err != nil { return GetMe401JSONResponse{ - UnauthorizedJSONResponse: UnauthorizedJSONResponse{ - Message: "Unauthorized", - }, + Message: "Unauthorized", }, nil } return GetMe200JSONResponse{ @@ -157,7 +151,7 @@ func (h *Handler) GetGames(ctx context.Context, _ GetGamesRequestObject, _ *auth } games[i] = Game{ GameID: int(row.GameID), - GameType: GameGameType(row.GameType), + GameType: GameType(row.GameType), IsPublic: row.IsPublic, DisplayName: row.DisplayName, DurationSeconds: int(row.DurationSeconds), @@ -200,18 +194,14 @@ func (h *Handler) GetGame(ctx context.Context, request GetGameRequestObject, use if err != nil { if errors.Is(err, pgx.ErrNoRows) { return GetGame404JSONResponse{ - NotFoundJSONResponse: NotFoundJSONResponse{ - Message: "Game not found", - }, + Message: "Game not found", }, nil } return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) } if !row.IsPublic && !user.IsAdmin { return GetGame404JSONResponse{ - NotFoundJSONResponse: NotFoundJSONResponse{ - Message: "Game not found", - }, + Message: "Game not found", }, nil } var startedAt *int64 @@ -236,7 +226,7 @@ func (h *Handler) GetGame(ctx context.Context, request GetGameRequestObject, use } game := Game{ GameID: int(row.GameID), - GameType: GameGameType(row.GameType), + GameType: GameType(row.GameType), IsPublic: row.IsPublic, DisplayName: row.DisplayName, DurationSeconds: int(row.DurationSeconds), @@ -312,9 +302,7 @@ func (h *Handler) GetGameWatchLatestStates(ctx context.Context, request GetGameW if int(row.UserID) == user.UserID && !user.IsAdmin { return GetGameWatchLatestStates403JSONResponse{ - ForbiddenJSONResponse: ForbiddenJSONResponse{ - Message: "You are one of the main players of this game", - }, + Message: "You are one of the main players of this game", }, nil } } diff --git a/backend/api/handler_wrapper.go b/backend/api/handler_wrapper.go index b88ddb2..5feaac7 100644 --- a/backend/api/handler_wrapper.go +++ b/backend/api/handler_wrapper.go @@ -29,9 +29,7 @@ func (h *HandlerWrapper) GetGame(ctx context.Context, request GetGameRequestObje user, ok := GetJWTClaimsFromContext(ctx) if !ok { return GetGame401JSONResponse{ - UnauthorizedJSONResponse: UnauthorizedJSONResponse{ - Message: "Unauthorized", - }, + Message: "Unauthorized", }, nil } return h.impl.GetGame(ctx, request, user) @@ -41,9 +39,7 @@ func (h *HandlerWrapper) GetGamePlayLatestState(ctx context.Context, request Get user, ok := GetJWTClaimsFromContext(ctx) if !ok { return GetGamePlayLatestState401JSONResponse{ - UnauthorizedJSONResponse: UnauthorizedJSONResponse{ - Message: "Unauthorized", - }, + Message: "Unauthorized", }, nil } return h.impl.GetGamePlayLatestState(ctx, request, user) @@ -53,9 +49,7 @@ func (h *HandlerWrapper) GetGameWatchLatestStates(ctx context.Context, request G user, ok := GetJWTClaimsFromContext(ctx) if !ok { return GetGameWatchLatestStates401JSONResponse{ - UnauthorizedJSONResponse: UnauthorizedJSONResponse{ - Message: "Unauthorized", - }, + Message: "Unauthorized", }, nil } return h.impl.GetGameWatchLatestStates(ctx, request, user) @@ -65,9 +59,7 @@ func (h *HandlerWrapper) GetGameWatchRanking(ctx context.Context, request GetGam user, ok := GetJWTClaimsFromContext(ctx) if !ok { return GetGameWatchRanking401JSONResponse{ - UnauthorizedJSONResponse: UnauthorizedJSONResponse{ - Message: "Unauthorized", - }, + Message: "Unauthorized", }, nil } return h.impl.GetGameWatchRanking(ctx, request, user) @@ -77,9 +69,7 @@ func (h *HandlerWrapper) GetGames(ctx context.Context, request GetGamesRequestOb user, ok := GetJWTClaimsFromContext(ctx) if !ok { return GetGames401JSONResponse{ - UnauthorizedJSONResponse: UnauthorizedJSONResponse{ - Message: "Unauthorized", - }, + Message: "Unauthorized", }, nil } return h.impl.GetGames(ctx, request, user) @@ -89,9 +79,7 @@ func (h *HandlerWrapper) GetMe(ctx context.Context, request GetMeRequestObject) user, ok := GetJWTClaimsFromContext(ctx) if !ok { return GetMe401JSONResponse{ - UnauthorizedJSONResponse: UnauthorizedJSONResponse{ - Message: "Unauthorized", - }, + Message: "Unauthorized", }, nil } return h.impl.GetMe(ctx, request, user) @@ -101,9 +89,7 @@ func (h *HandlerWrapper) GetTournament(ctx context.Context, request GetTournamen user, ok := GetJWTClaimsFromContext(ctx) if !ok { return GetTournament401JSONResponse{ - UnauthorizedJSONResponse: UnauthorizedJSONResponse{ - Message: "Unauthorized", - }, + Message: "Unauthorized", }, nil } return h.impl.GetTournament(ctx, request, user) @@ -113,9 +99,7 @@ func (h *HandlerWrapper) PostGamePlayCode(ctx context.Context, request PostGameP user, ok := GetJWTClaimsFromContext(ctx) if !ok { return PostGamePlayCode401JSONResponse{ - UnauthorizedJSONResponse: UnauthorizedJSONResponse{ - Message: "Unauthorized", - }, + Message: "Unauthorized", }, nil } return h.impl.PostGamePlayCode(ctx, request, user) @@ -125,9 +109,7 @@ func (h *HandlerWrapper) PostGamePlaySubmit(ctx context.Context, request PostGam user, ok := GetJWTClaimsFromContext(ctx) if !ok { return PostGamePlaySubmit401JSONResponse{ - UnauthorizedJSONResponse: UnauthorizedJSONResponse{ - Message: "Unauthorized", - }, + Message: "Unauthorized", }, nil } return h.impl.PostGamePlaySubmit(ctx, request, user) @@ -141,9 +123,7 @@ func (h *HandlerWrapper) PostLogout(ctx context.Context, request PostLogoutReque user, ok := GetJWTClaimsFromContext(ctx) if !ok { return PostLogout401JSONResponse{ - UnauthorizedJSONResponse: UnauthorizedJSONResponse{ - Message: "Unauthorized", - }, + Message: "Unauthorized", }, nil } return h.impl.PostLogout(ctx, request, user) diff --git a/backend/gen/api/handler_wrapper_gen.go b/backend/gen/api/handler_wrapper_gen.go index 5a5ce2d..c6e3e8a 100644 --- a/backend/gen/api/handler_wrapper_gen.go +++ b/backend/gen/api/handler_wrapper_gen.go @@ -131,17 +131,13 @@ func NewHandler(queries *db.Queries, hub GameHubInterface, conf *config.Config) user, ok := GetJWTClaimsFromContext(ctx) if !ok { return {{ .Name }}401JSONResponse{ - UnauthorizedJSONResponse: UnauthorizedJSONResponse{ - Message: "Unauthorized", - }, + Message: "Unauthorized", }, nil } {{ if .RequiresAdminRole -}} if !user.IsAdmin { return {{ .Name }}403JSONResponse{ - ForbiddenJSONResponse: ForbiddenJSONResponse{ - Message: "Forbidden", - }, + Message: "Forbidden", }, nil } {{ end -}} diff --git a/frontend/app/api/schema.d.ts b/frontend/app/api/schema.d.ts index 6f9e270..6d27df0 100644 --- a/frontend/app/api/schema.d.ts +++ b/frontend/app/api/schema.d.ts @@ -4,66 +4,62 @@ */ export interface paths { - "/login": { + "/games": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - get?: never; + get: operations["getGames"]; put?: never; - /** User login */ - post: operations["postLogin"]; + post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; - "/logout": { + "/games/{game_id}": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - get?: never; + get: operations["getGame"]; put?: never; - /** User logout */ - post: operations["postLogout"]; + post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; - "/me": { + "/games/{game_id}/play/code": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - /** Get current user */ - get: operations["getMe"]; + get?: never; put?: never; - post?: never; + post: operations["postGamePlayCode"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; - "/games": { + "/games/{game_id}/play/latest_state": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - /** List games */ - get: operations["getGames"]; + get: operations["getGamePlayLatestState"]; put?: never; post?: never; delete?: never; @@ -72,32 +68,30 @@ export interface paths { patch?: never; trace?: never; }; - "/games/{game_id}": { + "/games/{game_id}/play/submit": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - /** Get a game */ - get: operations["getGame"]; + get?: never; put?: never; - post?: never; + post: operations["postGamePlaySubmit"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; - "/games/{game_id}/play/latest_state": { + "/games/{game_id}/watch/latest_states": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - /** Get the latest execution result for player */ - get: operations["getGamePlayLatestState"]; + get: operations["getGameWatchLatestStates"]; put?: never; post?: never; delete?: never; @@ -106,24 +100,23 @@ export interface paths { patch?: never; trace?: never; }; - "/games/{game_id}/play/code": { + "/games/{game_id}/watch/ranking": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - get?: never; + get: operations["getGameWatchRanking"]; put?: never; - /** Post the latest code */ - post: operations["postGamePlayCode"]; + post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; - "/games/{game_id}/play/submit": { + "/login": { parameters: { query?: never; header?: never; @@ -132,40 +125,37 @@ export interface paths { }; get?: never; put?: never; - /** Submit the answer */ - post: operations["postGamePlaySubmit"]; + post: operations["postLogin"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; - "/games/{game_id}/watch/ranking": { + "/logout": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - /** Get the latest player ranking */ - get: operations["getGameWatchRanking"]; + get?: never; put?: never; - post?: never; + post: operations["postLogout"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; - "/games/{game_id}/watch/latest_states": { + "/me": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - /** Get all the latest game states of the main players */ - get: operations["getGameWatchLatestStates"]; + get: operations["getMe"]; put?: never; post?: never; delete?: never; @@ -181,7 +171,6 @@ export interface paths { path?: never; cookie?: never; }; - /** Get tournament bracket data */ get: operations["getTournament"]; put?: never; post?: never; @@ -196,409 +185,517 @@ export type webhooks = Record<string, never>; export interface components { schemas: { Error: { - /** @example Invalid request */ message: string; }; - User: { - /** @example 123 */ - user_id: number; - /** @example john */ - username: string; - /** @example John Doe */ - display_name: string; - /** @example /images/john.jpg */ - icon_path?: string; - /** @example false */ - is_admin: boolean; - /** @example staff */ - label: string | null; - }; + /** @enum {string} */ + ExecutionStatus: "none" | "running" | "success" | "wrong_answer" | "timeout" | "compile_error" | "runtime_error" | "internal_error"; Game: { - /** @example 1 */ game_id: number; - /** - * @example 1v1 - * @enum {string} - */ - game_type: "1v1" | "multiplayer"; - /** @example true */ + game_type: components["schemas"]["GameType"]; is_public: boolean; - /** @example Game 1 */ display_name: string; - /** @example 360 */ duration_seconds: number; - /** @example 946684800 */ started_at?: number; problem: components["schemas"]["Problem"]; main_players: components["schemas"]["User"][]; }; - Problem: { - /** @example 1 */ - problem_id: number; - /** @example Problem 1 */ - title: string; - /** @example This is a problem */ - description: string; - /** - * @example php - * @enum {string} - */ - language: "php" | "swift"; - /** @example echo 'hello world'; */ - sample_code: string; - }; - /** - * @example success - * @enum {string} - */ - ExecutionStatus: "none" | "running" | "success" | "wrong_answer" | "timeout" | "compile_error" | "runtime_error" | "internal_error"; + /** @enum {string} */ + GameType: "1v1" | "multiplayer"; LatestGameState: { - /** @example echo 'hello world'; */ code: string; - /** @example 100 */ score: number | null; - /** @example 946684800 */ best_score_submitted_at: number | null; status: components["schemas"]["ExecutionStatus"]; }; + Problem: { + problem_id: number; + title: string; + description: string; + language: components["schemas"]["ProblemLanguage"]; + sample_code: string; + }; + /** @enum {string} */ + ProblemLanguage: "php" | "swift"; RankingEntry: { player: components["schemas"]["User"]; - /** @example 100 */ score: number; - /** @example 946684800 */ submitted_at: number; - /** @example echo 'hello world'; */ code: string | null; }; Tournament: { matches: components["schemas"]["TournamentMatch"][]; }; TournamentMatch: { - /** @example 1 */ game_id: number; player1?: components["schemas"]["User"]; player2?: components["schemas"]["User"]; - /** @example 1 */ player1_score?: number; - /** @example 1 */ player2_score?: number; - /** @example 1 */ winner?: number; }; - }; - responses: { - /** @description Bad request */ - BadRequest: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Unauthorized */ - Unauthorized: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Forbidden */ - Forbidden: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Not found */ - NotFound: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; + User: { + user_id: number; + username: string; + display_name: string; + icon_path?: string; + is_admin: boolean; + label: string | null; }; }; - parameters: { - path_game_id: number; - }; + responses: never; + parameters: never; requestBodies: never; headers: never; pathItems: never; } export type $defs = Record<string, never>; export interface operations { - postLogin: { + getGames: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - requestBody: { - content: { - "application/json": { - /** @example john */ - username: string; - /** @example password123 */ - password: string; - }; - }; - }; + requestBody?: never; responses: { - /** @description Successfully authenticated */ + /** @description The request has succeeded. */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": { - user: components["schemas"]["User"]; + games: components["schemas"]["Game"][]; }; }; }; - 401: components["responses"]["Unauthorized"]; + /** @description Access is unauthorized. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Access is forbidden. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; }; }; - postLogout: { + getGame: { parameters: { query?: never; header?: never; - path?: never; + path: { + game_id: number; + }; cookie?: never; }; requestBody?: never; responses: { - /** @description Successfully logged out */ + /** @description The request has succeeded. */ 200: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": { + game: components["schemas"]["Game"]; + }; + }; + }; + /** @description Access is unauthorized. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Access is forbidden. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description The server cannot find the requested resource. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - 401: components["responses"]["Unauthorized"]; }; }; - getMe: { + postGamePlayCode: { parameters: { query?: never; header?: never; - path?: never; + path: { + game_id: number; + }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": { + code: string; + }; + }; + }; responses: { - /** @description Current user info */ + /** @description The request has succeeded. */ 200: { headers: { [name: string]: unknown; }; + content?: never; + }; + /** @description Access is unauthorized. */ + 401: { + headers: { + [name: string]: unknown; + }; content: { - "application/json": { - user: components["schemas"]["User"]; - }; + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Access is forbidden. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description The server cannot find the requested resource. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; }; }; - 401: components["responses"]["Unauthorized"]; }; }; - getGames: { + getGamePlayLatestState: { parameters: { query?: never; header?: never; - path?: never; + path: { + game_id: number; + }; cookie?: never; }; requestBody?: never; responses: { - /** @description List of games */ + /** @description The request has succeeded. */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": { - games: components["schemas"]["Game"][]; + state: components["schemas"]["LatestGameState"]; }; }; }; - 401: components["responses"]["Unauthorized"]; - 403: components["responses"]["Forbidden"]; + /** @description Access is unauthorized. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Access is forbidden. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description The server cannot find the requested resource. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; }; }; - getGame: { + postGamePlaySubmit: { parameters: { query?: never; header?: never; path: { - game_id: components["parameters"]["path_game_id"]; + game_id: number; }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": { + code: string; + }; + }; + }; responses: { - /** @description A game */ + /** @description The request has succeeded. */ 200: { headers: { [name: string]: unknown; }; + content?: never; + }; + /** @description Access is unauthorized. */ + 401: { + headers: { + [name: string]: unknown; + }; content: { - "application/json": { - game: components["schemas"]["Game"]; - }; + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Access is forbidden. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description The server cannot find the requested resource. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; }; }; - 401: components["responses"]["Unauthorized"]; - 403: components["responses"]["Forbidden"]; - 404: components["responses"]["NotFound"]; }; }; - getGamePlayLatestState: { + getGameWatchLatestStates: { parameters: { query?: never; header?: never; path: { - game_id: components["parameters"]["path_game_id"]; + game_id: number; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Your latest game state */ + /** @description The request has succeeded. */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": { - state: components["schemas"]["LatestGameState"]; + states: { + [key: string]: components["schemas"]["LatestGameState"]; + }; }; }; }; - 401: components["responses"]["Unauthorized"]; - 403: components["responses"]["Forbidden"]; - 404: components["responses"]["NotFound"]; + /** @description Access is unauthorized. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Access is forbidden. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description The server cannot find the requested resource. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; }; }; - postGamePlayCode: { + getGameWatchRanking: { parameters: { query?: never; header?: never; path: { - game_id: components["parameters"]["path_game_id"]; + game_id: number; }; cookie?: never; }; - requestBody: { - content: { - "application/json": { - /** @example echo 'hello world'; */ - code: string; - }; - }; - }; + requestBody?: never; responses: { - /** @description Successfully updated */ + /** @description The request has succeeded. */ 200: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": { + ranking: components["schemas"]["RankingEntry"][]; + }; + }; + }; + /** @description Access is unauthorized. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Access is forbidden. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description The server cannot find the requested resource. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - 401: components["responses"]["Unauthorized"]; - 403: components["responses"]["Forbidden"]; - 404: components["responses"]["NotFound"]; }; }; - postGamePlaySubmit: { + postLogin: { parameters: { query?: never; header?: never; - path: { - game_id: components["parameters"]["path_game_id"]; - }; + path?: never; cookie?: never; }; requestBody: { content: { "application/json": { - /** @example echo 'hello world'; */ - code: string; + username: string; + password: string; }; }; }; responses: { - /** @description Successfully submitted */ + /** @description The request has succeeded. */ 200: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": { + user: components["schemas"]["User"]; + }; + }; + }; + /** @description Access is unauthorized. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - 401: components["responses"]["Unauthorized"]; - 403: components["responses"]["Forbidden"]; - 404: components["responses"]["NotFound"]; }; }; - getGameWatchRanking: { + postLogout: { parameters: { query?: never; header?: never; - path: { - game_id: components["parameters"]["path_game_id"]; - }; + path?: never; cookie?: never; }; requestBody?: never; responses: { - /** @description Player ranking */ + /** @description The request has succeeded. */ 200: { headers: { [name: string]: unknown; }; + content?: never; + }; + /** @description Access is unauthorized. */ + 401: { + headers: { + [name: string]: unknown; + }; content: { - "application/json": { - ranking: components["schemas"]["RankingEntry"][]; - }; + "application/json": components["schemas"]["Error"]; }; }; - 401: components["responses"]["Unauthorized"]; - 403: components["responses"]["Forbidden"]; - 404: components["responses"]["NotFound"]; }; }; - getGameWatchLatestStates: { + getMe: { parameters: { query?: never; header?: never; - path: { - game_id: components["parameters"]["path_game_id"]; - }; + path?: never; cookie?: never; }; requestBody?: never; responses: { - /** @description All the latest game states of the main players */ + /** @description The request has succeeded. */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": { - states: { - [key: string]: components["schemas"]["LatestGameState"]; - }; + user: components["schemas"]["User"]; }; }; }; - 401: components["responses"]["Unauthorized"]; - 403: components["responses"]["Forbidden"]; - 404: components["responses"]["NotFound"]; + /** @description Access is unauthorized. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; }; }; getTournament: { @@ -616,7 +713,7 @@ export interface operations { }; requestBody?: never; responses: { - /** @description Tournament data */ + /** @description The request has succeeded. */ 200: { headers: { [name: string]: unknown; @@ -627,9 +724,33 @@ export interface operations { }; }; }; - 401: components["responses"]["Unauthorized"]; - 403: components["responses"]["Forbidden"]; - 404: components["responses"]["NotFound"]; + /** @description Access is unauthorized. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Access is forbidden. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description The server cannot find the requested resource. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; }; }; } @@ -4,6 +4,7 @@ default: down build up build: {{ docker_compose }} build + cd typespec; npm install cd frontend; npm install up: @@ -48,6 +49,7 @@ initdb: just psql-query < ./backend/fixtures/dev.sql gen: + cd typespec; npm run build cd backend; just gen cd frontend; npm run openapi-typescript diff --git a/openapi/api-server.yaml b/openapi/api-server.yaml index 15b75b6..21fb989 100644 --- a/openapi/api-server.yaml +++ b/openapi/api-server.yaml @@ -2,75 +2,15 @@ openapi: 3.0.0 info: title: Albatross internal web API version: 0.3.0 +tags: [] paths: - /login: - post: - operationId: postLogin - summary: User login - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - username: - type: string - example: "john" - password: - type: string - example: "password123" - required: - - username - - password - responses: - '200': - description: Successfully authenticated - content: - application/json: - schema: - type: object - properties: - user: - $ref: '#/components/schemas/User' - required: - - user - '401': - $ref: '#/components/responses/Unauthorized' - /logout: - post: - operationId: postLogout - summary: User logout - responses: - '200': - description: Successfully logged out - '401': - $ref: '#/components/responses/Unauthorized' - /me: - get: - operationId: getMe - summary: Get current user - responses: - '200': - description: Current user info - content: - application/json: - schema: - type: object - properties: - user: - $ref: '#/components/schemas/User' - required: - - user - '401': - $ref: '#/components/responses/Unauthorized' /games: get: operationId: getGames - summary: List games + parameters: [] responses: '200': - description: List of games + description: The request has succeeded. content: application/json: schema: @@ -83,18 +23,29 @@ paths: required: - games '401': - $ref: '#/components/responses/Unauthorized' + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '403': - $ref: '#/components/responses/Forbidden' + description: Access is forbidden. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /games/{game_id}: get: operationId: getGame - summary: Get a game parameters: - - $ref: '#/components/parameters/path_game_id' + - name: game_id + in: path + required: true + schema: + type: integer responses: '200': - description: A game + description: The request has succeeded. content: application/json: schema: @@ -105,41 +56,53 @@ paths: required: - game '401': - $ref: '#/components/responses/Unauthorized' + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '403': - $ref: '#/components/responses/Forbidden' + description: Access is forbidden. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '404': - $ref: '#/components/responses/NotFound' - /games/{game_id}/play/latest_state: - get: - operationId: getGamePlayLatestState - summary: Get the latest execution result for player + description: The server cannot find the requested resource. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /games/{game_id}/play/code: + post: + operationId: postGamePlayCode parameters: - - $ref: '#/components/parameters/path_game_id' + - name: game_id + in: path + required: true + schema: + type: integer responses: '200': - description: Your latest game state + description: The request has succeeded. + '401': + description: Access is unauthorized. content: application/json: schema: - type: object - properties: - state: - $ref: '#/components/schemas/LatestGameState' - required: - - state - '401': - $ref: '#/components/responses/Unauthorized' + $ref: '#/components/schemas/Error' '403': - $ref: '#/components/responses/Forbidden' + description: Access is forbidden. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '404': - $ref: '#/components/responses/NotFound' - /games/{game_id}/play/code: - post: - operationId: postGamePlayCode - summary: Post the latest code - parameters: - - $ref: '#/components/parameters/path_game_id' + description: The server cannot find the requested resource. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' requestBody: required: true content: @@ -149,24 +112,77 @@ paths: properties: code: type: string - example: "echo 'hello world';" required: - code + /games/{game_id}/play/latest_state: + get: + operationId: getGamePlayLatestState + parameters: + - name: game_id + in: path + required: true + schema: + type: integer responses: '200': - description: Successfully updated + description: The request has succeeded. + content: + application/json: + schema: + type: object + properties: + state: + $ref: '#/components/schemas/LatestGameState' + required: + - state '401': - $ref: '#/components/responses/Unauthorized' + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '403': - $ref: '#/components/responses/Forbidden' + description: Access is forbidden. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '404': - $ref: '#/components/responses/NotFound' + description: The server cannot find the requested resource. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /games/{game_id}/play/submit: post: operationId: postGamePlaySubmit - summary: Submit the answer parameters: - - $ref: '#/components/parameters/path_game_id' + - name: game_id + in: path + required: true + schema: + type: integer + responses: + '200': + description: The request has succeeded. + '401': + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Access is forbidden. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: The server cannot find the requested resource. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' requestBody: required: true content: @@ -176,27 +192,61 @@ paths: properties: code: type: string - example: "echo 'hello world';" required: - code + /games/{game_id}/watch/latest_states: + get: + operationId: getGameWatchLatestStates + parameters: + - name: game_id + in: path + required: true + schema: + type: integer responses: '200': - description: Successfully submitted + description: The request has succeeded. + content: + application/json: + schema: + type: object + properties: + states: + type: object + additionalProperties: + $ref: '#/components/schemas/LatestGameState' + required: + - states '401': - $ref: '#/components/responses/Unauthorized' + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '403': - $ref: '#/components/responses/Forbidden' + description: Access is forbidden. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '404': - $ref: '#/components/responses/NotFound' + description: The server cannot find the requested resource. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /games/{game_id}/watch/ranking: get: operationId: getGameWatchRanking - summary: Get the latest player ranking parameters: - - $ref: '#/components/parameters/path_game_id' + - name: game_id + in: path + required: true + schema: + type: integer responses: '200': - description: Player ranking + description: The request has succeeded. content: application/json: schema: @@ -209,70 +259,131 @@ paths: required: - ranking '401': - $ref: '#/components/responses/Unauthorized' + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '403': - $ref: '#/components/responses/Forbidden' + description: Access is forbidden. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '404': - $ref: '#/components/responses/NotFound' - /games/{game_id}/watch/latest_states: + description: The server cannot find the requested resource. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /login: + post: + operationId: postLogin + parameters: [] + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + type: object + properties: + user: + $ref: '#/components/schemas/User' + required: + - user + '401': + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + username: + type: string + password: + type: string + required: + - username + - password + /logout: + post: + operationId: postLogout + parameters: [] + responses: + '200': + description: The request has succeeded. + '401': + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /me: get: - operationId: getGameWatchLatestStates - summary: Get all the latest game states of the main players - parameters: - - $ref: '#/components/parameters/path_game_id' + operationId: getMe + parameters: [] responses: '200': - description: All the latest game states of the main players + description: The request has succeeded. content: application/json: schema: type: object properties: - states: - type: object - additionalProperties: - $ref: '#/components/schemas/LatestGameState' + user: + $ref: '#/components/schemas/User' required: - - states + - user '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '404': - $ref: '#/components/responses/NotFound' + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /tournament: get: operationId: getTournament - summary: Get tournament bracket data parameters: - - in: query - name: game1 + - name: game1 + in: query + required: true schema: type: integer + explode: false + - name: game2 + in: query required: true - - in: query - name: game2 schema: type: integer + explode: false + - name: game3 + in: query required: true - - in: query - name: game3 schema: type: integer + explode: false + - name: game4 + in: query required: true - - in: query - name: game4 schema: type: integer + explode: false + - name: game5 + in: query required: true - - in: query - name: game5 schema: type: integer - required: true + explode: false responses: '200': - description: Tournament data + description: The request has succeeded. content: application/json: schema: @@ -283,105 +394,66 @@ paths: required: - tournament '401': - $ref: '#/components/responses/Unauthorized' + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '403': - $ref: '#/components/responses/Forbidden' + description: Access is forbidden. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '404': - $ref: '#/components/responses/NotFound' + description: The server cannot find the requested resource. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' components: - parameters: - path_game_id: - in: path - name: game_id - schema: - type: integer - required: true - responses: - BadRequest: - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - Unauthorized: - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - Forbidden: - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - NotFound: - description: Not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' schemas: Error: type: object - properties: - message: - type: string - example: "Invalid request" required: - message - User: - type: object properties: - user_id: - type: integer - example: 123 - username: - type: string - example: "john" - display_name: - type: string - example: "John Doe" - icon_path: - type: string - example: "/images/john.jpg" - is_admin: - type: boolean - example: false - label: + message: type: string - nullable: true - example: "staff" - required: - - user_id - - username - - display_name - - is_admin - - label + ExecutionStatus: + type: string + enum: + - none + - running + - success + - wrong_answer + - timeout + - compile_error + - runtime_error + - internal_error Game: type: object + required: + - game_id + - game_type + - is_public + - display_name + - duration_seconds + - problem + - main_players properties: game_id: type: integer - example: 1 game_type: - type: string - example: "1v1" - enum: - - 1v1 - - multiplayer + $ref: '#/components/schemas/GameType' is_public: type: boolean - example: true display_name: type: string - example: "Game 1" duration_seconds: type: integer - example: 360 started_at: type: integer - example: 946684800 x-go-type: int64 problem: $ref: '#/components/schemas/Problem' @@ -389,123 +461,117 @@ components: type: array items: $ref: '#/components/schemas/User' - required: - - game_id - - game_type - - is_public - - display_name - - duration_seconds - - problem - - main_players - Problem: - type: object - properties: - problem_id: - type: integer - example: 1 - title: - type: string - example: "Problem 1" - description: - type: string - example: "This is a problem" - language: - type: string - example: "php" - enum: - - php - - swift - sample_code: - type: string - example: "echo 'hello world';" - required: - - problem_id - - title - - description - - language - - sample_code - ExecutionStatus: + GameType: type: string - example: "success" enum: - - none - - running - - success - - wrong_answer - - timeout - - compile_error - - runtime_error - - internal_error + - 1v1 + - multiplayer LatestGameState: type: object + required: + - code + - score + - best_score_submitted_at + - status properties: code: type: string - example: "echo 'hello world';" score: type: integer nullable: true - example: 100 best_score_submitted_at: type: integer nullable: true - example: 946684800 x-go-type: int64 status: $ref: '#/components/schemas/ExecutionStatus' + Problem: + type: object required: - - code - - score - - best_score_submitted_at - - status + - problem_id + - title + - description + - language + - sample_code + properties: + problem_id: + type: integer + title: + type: string + description: + type: string + language: + $ref: '#/components/schemas/ProblemLanguage' + sample_code: + type: string + ProblemLanguage: + type: string + enum: + - php + - swift RankingEntry: type: object + required: + - player + - score + - submitted_at + - code properties: player: $ref: '#/components/schemas/User' score: type: integer - example: 100 submitted_at: type: integer - example: 946684800 x-go-type: int64 code: type: string nullable: true - example: "echo 'hello world';" - required: - - player - - score - - submitted_at - - code Tournament: type: object + required: + - matches properties: matches: type: array items: $ref: '#/components/schemas/TournamentMatch' - required: - - matches TournamentMatch: type: object + required: + - game_id properties: game_id: type: integer - example: 1 player1: $ref: '#/components/schemas/User' player2: $ref: '#/components/schemas/User' player1_score: type: integer - example: 1 player2_score: type: integer - example: 1 winner: type: integer - example: 1 + User: + type: object required: - - game_id + - user_id + - username + - display_name + - is_admin + - label + properties: + user_id: + type: integer + username: + type: string + display_name: + type: string + icon_path: + type: string + is_admin: + type: boolean + label: + type: string + nullable: true diff --git a/openapi/fortee.yaml b/openapi/fortee.yaml index 7e27f30..89a1842 100644 --- a/openapi/fortee.yaml +++ b/openapi/fortee.yaml @@ -2,30 +2,15 @@ openapi: 3.0.0 info: title: fortee API version: 0.1.0 +tags: [] paths: /api/user/login: post: operationId: postLogin - summary: User login - requestBody: - required: true - content: - application/x-www-form-urlencoded: - schema: - type: object - properties: - username: - type: string - example: "john" - password: - type: string - example: "password123" - required: - - username - - password + parameters: [] responses: '200': - description: Successfully authenticated + description: The request has succeeded. content: application/json: schema: @@ -33,30 +18,41 @@ paths: properties: loggedIn: type: boolean - example: true user: type: object properties: username: type: string - example: "john" required: - username required: - loggedIn + requestBody: + required: true + content: + application/x-www-form-urlencoded: + schema: + type: object + properties: + username: + type: string + password: + type: string + required: + - username + - password /api/user/view/{username}: get: operationId: getUser - summary: Get a user parameters: - - in: path - name: username + - name: username + in: path + required: true schema: type: string - required: true responses: '200': - description: User found + description: The request has succeeded. content: application/json: schema: @@ -64,16 +60,14 @@ paths: properties: uuid: type: string - example: "11111111-1111-1111-1111-111111111111" username: type: string - example: "john" avatar_url: type: string - example: "/files/_user/11111111-1111-1111-1111-111111111111.jpg" required: - uuid - username - avatar_url '404': - description: User not found + description: The server cannot find the requested resource. +components: {} diff --git a/typespec/api-server/main.tsp b/typespec/api-server/main.tsp new file mode 100644 index 0000000..00d1816 --- /dev/null +++ b/typespec/api-server/main.tsp @@ -0,0 +1,17 @@ +import "@typespec/http"; +import "@typespec/openapi"; +import "@typespec/openapi3"; + +import "./models.tsp"; +import "./routes.tsp"; + +using TypeSpec.Http; +using TypeSpec.OpenAPI; + +@service(#{ + title: "Albatross internal web API", +}) +@info(#{ + version: "0.3.0", +}) +namespace AlbatrossApi; diff --git a/typespec/api-server/models.tsp b/typespec/api-server/models.tsp new file mode 100644 index 0000000..47519be --- /dev/null +++ b/typespec/api-server/models.tsp @@ -0,0 +1,119 @@ +using TypeSpec.Http; +using TypeSpec.OpenAPI; + +namespace AlbatrossApi; + +// ---------- Error ---------- + +model Error { + message: string; +} + +// ---------- Error Responses ---------- + +@error +model UnauthorizedError { + @statusCode statusCode: 401; + @body body: Error; +} + +@error +model ForbiddenError { + @statusCode statusCode: 403; + @body body: Error; +} + +@error +model NotFoundError { + @statusCode statusCode: 404; + @body body: Error; +} + +// ---------- Enums ---------- + +enum GameType { + `1v1`, + multiplayer, +} + +enum ProblemLanguage { + php, + swift, +} + +enum ExecutionStatus { + none, + running, + success, + wrong_answer, + timeout, + compile_error, + runtime_error, + internal_error, +} + +// ---------- Models ---------- + +model User { + user_id: integer; + username: string; + display_name: string; + icon_path?: string; + is_admin: boolean; + label: string | null; +} + +model Problem { + problem_id: integer; + title: string; + description: string; + language: ProblemLanguage; + sample_code: string; +} + +model Game { + game_id: integer; + game_type: GameType; + is_public: boolean; + display_name: string; + duration_seconds: integer; + + @extension("x-go-type", "int64") + started_at?: integer; + + problem: Problem; + main_players: User[]; +} + +model LatestGameState { + code: string; + score: integer | null; + + @extension("x-go-type", "int64") + best_score_submitted_at: integer | null; + + status: ExecutionStatus; +} + +model RankingEntry { + player: User; + score: integer; + + @extension("x-go-type", "int64") + submitted_at: integer; + + code: string | null; +} + +model Tournament { + matches: TournamentMatch[]; +} + +model TournamentMatch { + game_id: integer; + player1?: User; + player2?: User; + player1_score?: integer; + player2_score?: integer; + winner?: integer; +} diff --git a/typespec/api-server/routes.tsp b/typespec/api-server/routes.tsp new file mode 100644 index 0000000..3409cea --- /dev/null +++ b/typespec/api-server/routes.tsp @@ -0,0 +1,126 @@ +using TypeSpec.Http; +using TypeSpec.OpenAPI; + +namespace AlbatrossApi; + +// ---------- Auth ---------- + +@route("/login") +@post +@operationId("postLogin") +op postLogin(@body body: { + username: string; + password: string; +}): { + @body body: { + user: User; + }; +} | UnauthorizedError; + +@route("/logout") +@post +@operationId("postLogout") +op postLogout(): { + @statusCode statusCode: 200; +} | UnauthorizedError; + +@route("/me") +@get +@operationId("getMe") +op getMe(): { + @body body: { + user: User; + }; +} | UnauthorizedError; + +// ---------- Games ---------- + +@route("/games") +@get +@operationId("getGames") +op getGames(): { + @body body: { + games: Game[]; + }; +} | UnauthorizedError | ForbiddenError; + +@route("/games/{game_id}") +@get +@operationId("getGame") +op getGame(@path game_id: integer): { + @body body: { + game: Game; + }; +} | UnauthorizedError | ForbiddenError | NotFoundError; + +// ---------- Play ---------- + +@route("/games/{game_id}/play/latest_state") +@get +@operationId("getGamePlayLatestState") +op getGamePlayLatestState(@path game_id: integer): { + @body body: { + state: LatestGameState; + }; +} | UnauthorizedError | ForbiddenError | NotFoundError; + +@route("/games/{game_id}/play/code") +@post +@operationId("postGamePlayCode") +op postGamePlayCode( + @path game_id: integer, + @body body: { + code: string; + }, +): { + @statusCode statusCode: 200; +} | UnauthorizedError | ForbiddenError | NotFoundError; + +@route("/games/{game_id}/play/submit") +@post +@operationId("postGamePlaySubmit") +op postGamePlaySubmit( + @path game_id: integer, + @body body: { + code: string; + }, +): { + @statusCode statusCode: 200; +} | UnauthorizedError | ForbiddenError | NotFoundError; + +// ---------- Watch ---------- + +@route("/games/{game_id}/watch/ranking") +@get +@operationId("getGameWatchRanking") +op getGameWatchRanking(@path game_id: integer): { + @body body: { + ranking: RankingEntry[]; + }; +} | UnauthorizedError | ForbiddenError | NotFoundError; + +@route("/games/{game_id}/watch/latest_states") +@get +@operationId("getGameWatchLatestStates") +op getGameWatchLatestStates(@path game_id: integer): { + @body body: { + states: Record<LatestGameState>; + }; +} | UnauthorizedError | ForbiddenError | NotFoundError; + +// ---------- Tournament ---------- + +@route("/tournament") +@get +@operationId("getTournament") +op getTournament( + @query game1: integer, + @query game2: integer, + @query game3: integer, + @query game4: integer, + @query game5: integer, +): { + @body body: { + tournament: Tournament; + }; +} | UnauthorizedError | ForbiddenError | NotFoundError; diff --git a/typespec/api-server/tspconfig.yaml b/typespec/api-server/tspconfig.yaml new file mode 100644 index 0000000..78ba744 --- /dev/null +++ b/typespec/api-server/tspconfig.yaml @@ -0,0 +1,8 @@ +output-dir: "{project-root}/tsp-output" +emit: + - "@typespec/openapi3" +options: + "@typespec/openapi3": + openapi-versions: + - "3.0.0" + output-file: openapi.yaml diff --git a/typespec/fortee/main.tsp b/typespec/fortee/main.tsp new file mode 100644 index 0000000..03683a7 --- /dev/null +++ b/typespec/fortee/main.tsp @@ -0,0 +1,45 @@ +import "@typespec/http"; +import "@typespec/openapi"; +import "@typespec/openapi3"; + +using TypeSpec.Http; +using TypeSpec.OpenAPI; + +@service(#{ + title: "fortee API", +}) +@info(#{ + version: "0.1.0", +}) +namespace ForteeApi; + +@route("/api/user/login") +@post +@operationId("postLogin") +op postLogin( + @header contentType: "application/x-www-form-urlencoded", + @body body: { + username: string; + password: string; + }, +): { + @body body: { + loggedIn: boolean; + user?: { + username: string; + }; + }; +}; + +@route("/api/user/view/{username}") +@get +@operationId("getUser") +op getUser(@path username: string): { + @body body: { + uuid: string; + username: string; + avatar_url: string; + }; +} | { + @statusCode statusCode: 404; +}; diff --git a/typespec/fortee/tspconfig.yaml b/typespec/fortee/tspconfig.yaml new file mode 100644 index 0000000..78ba744 --- /dev/null +++ b/typespec/fortee/tspconfig.yaml @@ -0,0 +1,8 @@ +output-dir: "{project-root}/tsp-output" +emit: + - "@typespec/openapi3" +options: + "@typespec/openapi3": + openapi-versions: + - "3.0.0" + output-file: openapi.yaml diff --git a/typespec/package-lock.json b/typespec/package-lock.json new file mode 100644 index 0000000..f343eee --- /dev/null +++ b/typespec/package-lock.json @@ -0,0 +1,1435 @@ +{ + "name": "albatross-typespec", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "albatross-typespec", + "dependencies": { + "@typespec/compiler": "^1.9.0", + "@typespec/http": "^1.9.0", + "@typespec/openapi": "^1.9.0", + "@typespec/openapi3": "^1.9.0", + "@typespec/rest": "^0.79.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", + "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@inquirer/ansi": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.3.tgz", + "integrity": "sha512-g44zhR3NIKVs0zUesa4iMzExmZpLUdTLRMCStqX3GE5NT6VkPcxQGJ+uC8tDgBUC/vB1rUhUd55cOf++4NZcmw==", + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + } + }, + "node_modules/@inquirer/checkbox": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.0.4.tgz", + "integrity": "sha512-DrAMU3YBGMUAp6ArwTIp/25CNDtDbxk7UjIrrtM25JVVrlVYlVzHh5HR1BDFu9JMyUoZ4ZanzeaHqNDttf3gVg==", + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.3", + "@inquirer/core": "^11.1.1", + "@inquirer/figures": "^2.0.3", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.0.4.tgz", + "integrity": "sha512-WdaPe7foUnoGYvXzH4jp4wH/3l+dBhZ3uwhKjXjwdrq5tEIFaANxj6zrGHxLdsIA0yKM0kFPVcEalOZXBB5ISA==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.1.1", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.1.1.tgz", + "integrity": "sha512-hV9o15UxX46OyQAtaoMqAOxGR8RVl1aZtDx1jHbCtSJy1tBdTfKxLPKf7utsE4cRy4tcmCQ4+vdV+ca+oNxqNA==", + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.3", + "@inquirer/figures": "^2.0.3", + "@inquirer/type": "^4.0.3", + "cli-width": "^4.1.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^9.0.2" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/editor": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.0.4.tgz", + "integrity": "sha512-QI3Jfqcv6UO2/VJaEFONH8Im1ll++Xn/AJTBn9Xf+qx2M+H8KZAdQ5sAe2vtYlo+mLW+d7JaMJB4qWtK4BG3pw==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.1.1", + "@inquirer/external-editor": "^2.0.3", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.0.4.tgz", + "integrity": "sha512-0I/16YwPPP0Co7a5MsomlZLpch48NzYfToyqYAOWtBmaXSB80RiNQ1J+0xx2eG+Wfxt0nHtpEWSRr6CzNVnOGg==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.1.1", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-2.0.3.tgz", + "integrity": "sha512-LgyI7Agbda74/cL5MvA88iDpvdXI2KuMBCGRkbCl2Dg1vzHeOgs+s0SDcXV7b+WZJrv2+ERpWSM65Fpi9VfY3w==", + "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.2" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.3.tgz", + "integrity": "sha512-y09iGt3JKoOCBQ3w4YrSJdokcD8ciSlMIWsD+auPu+OZpfxLuyz+gICAQ6GCBOmJJt4KEQGHuZSVff2jiNOy7g==", + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + } + }, + "node_modules/@inquirer/input": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.0.4.tgz", + "integrity": "sha512-4B3s3jvTREDFvXWit92Yc6jF1RJMDy2VpSqKtm4We2oVU65YOh2szY5/G14h4fHlyQdpUmazU5MPCFZPRJ0AOw==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.1.1", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.0.4.tgz", + "integrity": "sha512-CmMp9LF5HwE+G/xWsC333TlCzYYbXMkcADkKzcawh49fg2a1ryLc7JL1NJYYt1lJ+8f4slikNjJM9TEL/AljYQ==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.1.1", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.0.4.tgz", + "integrity": "sha512-ZCEPyVYvHK4W4p2Gy6sTp9nqsdHQCfiPXIP9LbJVW4yCinnxL/dDDmPaEZVysGrj8vxVReRnpfS2fOeODe9zjg==", + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.3", + "@inquirer/core": "^11.1.1", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.2.0.tgz", + "integrity": "sha512-rqTzOprAj55a27jctS3vhvDDJzYXsr33WXTjODgVOru21NvBo9yIgLIAf7SBdSV0WERVly3dR6TWyp7ZHkvKFA==", + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^5.0.4", + "@inquirer/confirm": "^6.0.4", + "@inquirer/editor": "^5.0.4", + "@inquirer/expand": "^5.0.4", + "@inquirer/input": "^5.0.4", + "@inquirer/number": "^4.0.4", + "@inquirer/password": "^5.0.4", + "@inquirer/rawlist": "^5.2.0", + "@inquirer/search": "^4.1.0", + "@inquirer/select": "^5.0.4" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.2.0.tgz", + "integrity": "sha512-CciqGoOUMrFo6HxvOtU5uL8fkjCmzyeB6fG7O1vdVAZVSopUBYECOwevDBlqNLyyYmzpm2Gsn/7nLrpruy9RFg==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.1.1", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.1.0.tgz", + "integrity": "sha512-EAzemfiP4IFvIuWnrHpgZs9lAhWDA0GM3l9F4t4mTQ22IFtzfrk8xbkMLcAN7gmVML9O/i+Hzu8yOUyAaL6BKA==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.1.1", + "@inquirer/figures": "^2.0.3", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.0.4.tgz", + "integrity": "sha512-s8KoGpPYMEQ6WXc0dT9blX2NtIulMdLOO3LA1UKOiv7KFWzlJ6eLkEYTDBIi+JkyKXyn8t/CD6TinxGjyLt57g==", + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.3", + "@inquirer/core": "^11.1.1", + "@inquirer/figures": "^2.0.3", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.3.tgz", + "integrity": "sha512-cKZN7qcXOpj1h+1eTTcGDVLaBIHNMT1Rz9JqJP5MnEJ0JhgVWllx7H/tahUp5YEK1qaByH2Itb8wLG/iScD5kw==", + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@scalar/helpers": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@scalar/helpers/-/helpers-0.2.11.tgz", + "integrity": "sha512-Y7DLt1bIZF9dvHzJwSJTcC1lpSr1Tbf4VBhHOCRIHu23Rr7/lhQnddRxFmPV1tZXwEQKz7F7yRrubwCfKPCucw==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/@scalar/json-magic": { + "version": "0.9.6", + "resolved": "https://registry.npmjs.org/@scalar/json-magic/-/json-magic-0.9.6.tgz", + "integrity": "sha512-2TKoqkAophHti1nH+rvQlR4lhD6X9tqQpuNeAE0cytHSX/yndkSOE0yA7cep5T9tFjGN4Km0gMnelvY3LgWs4A==", + "license": "MIT", + "dependencies": { + "@scalar/helpers": "0.2.11", + "yaml": "^2.8.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@scalar/openapi-parser": { + "version": "0.24.9", + "resolved": "https://registry.npmjs.org/@scalar/openapi-parser/-/openapi-parser-0.24.9.tgz", + "integrity": "sha512-uqpwt6ZQJQu4c3CvMsJiXMUj32113yrclsDC31hlL33vEUS5JU9dCYfY27oLSCVoKl8R8KihlnEcbfRnH/O/GA==", + "license": "MIT", + "dependencies": { + "@scalar/helpers": "0.2.11", + "@scalar/json-magic": "0.11.0", + "@scalar/openapi-types": "0.5.3", + "@scalar/openapi-upgrader": "0.1.8", + "ajv": "^8.17.1", + "ajv-draft-04": "^1.0.0", + "ajv-formats": "^3.0.1", + "jsonpointer": "^5.0.1", + "leven": "^4.0.0", + "yaml": "^2.8.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@scalar/openapi-parser/node_modules/@scalar/json-magic": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@scalar/json-magic/-/json-magic-0.11.0.tgz", + "integrity": "sha512-1zBseDDEPkKlAVd9lT1HlK9Nefeh0YEE+pcmyDL3J5derIZn9UYXAFecdkeXMdjDtWDgcrkmWCrHhpoT7zVKdQ==", + "license": "MIT", + "dependencies": { + "@scalar/helpers": "0.2.11", + "yaml": "^2.8.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@scalar/openapi-types": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@scalar/openapi-types/-/openapi-types-0.5.3.tgz", + "integrity": "sha512-m4n/Su3K01d15dmdWO1LlqecdSPKuNjuokrJLdiQ485kW/hRHbXW1QP6tJL75myhw/XhX5YhYAR+jrwnGjXiMw==", + "license": "MIT", + "dependencies": { + "zod": "^4.1.11" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@scalar/openapi-upgrader": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@scalar/openapi-upgrader/-/openapi-upgrader-0.1.8.tgz", + "integrity": "sha512-2xuYLLs0fBadLIk4I1ObjMiCnOyLPEMPf24A1HtHQvhKGDnGlvT63F2rU2Xw8lxCjgHnzveMPnOJEbwIy64RCg==", + "license": "MIT", + "dependencies": { + "@scalar/openapi-types": "0.5.3" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typespec/asset-emitter": { + "version": "0.79.0", + "resolved": "https://registry.npmjs.org/@typespec/asset-emitter/-/asset-emitter-0.79.0.tgz", + "integrity": "sha512-pNMtfSSwgmTQ2ex6bd1l6BUW2RLjSFnWQO5C5bNSleV62YEH5jMLn3THWDU9oUB0JoiBjgomV8cPqNRTJ+iV9w==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.9.0" + } + }, + "node_modules/@typespec/compiler": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.9.0.tgz", + "integrity": "sha512-Rz9fFWQSTJSnhBfZvtA/bDIuO82fknYdtyMsL9lZNJE82rquC6JByHPFsnbGH1VXA0HhMj9L7Oqyp3f0m/BTOA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "~7.28.6", + "@inquirer/prompts": "^8.0.1", + "ajv": "~8.17.1", + "change-case": "~5.4.4", + "env-paths": "^3.0.0", + "globby": "~16.1.0", + "is-unicode-supported": "^2.1.0", + "mustache": "~4.2.0", + "picocolors": "~1.1.1", + "prettier": "~3.8.0", + "semver": "^7.7.1", + "tar": "^7.5.2", + "temporal-polyfill": "^0.3.0", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.12", + "yaml": "~2.8.2", + "yargs": "~18.0.0" + }, + "bin": { + "tsp": "cmd/tsp.js", + "tsp-server": "cmd/tsp-server.js" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@typespec/http": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@typespec/http/-/http-1.9.0.tgz", + "integrity": "sha512-JzlZZsgCo71f2KhWbf4BLOz5e+dVLj7gJJ4kvXvrmuG9QHoT41VaGPpCQamYgpZLMz2LQbsOtw34AmpovhuJSw==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.9.0", + "@typespec/streams": "^0.79.0" + }, + "peerDependenciesMeta": { + "@typespec/streams": { + "optional": true + } + } + }, + "node_modules/@typespec/openapi": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@typespec/openapi/-/openapi-1.9.0.tgz", + "integrity": "sha512-5ieXCWRLcyFLv3IFk26ena/RW/NxvT5KiHaoNVFRd79J0XZjFcE0Od6Lxxqj4dWmCo3C8oKtOwFoQuie18G3lQ==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.9.0", + "@typespec/http": "^1.9.0" + } + }, + "node_modules/@typespec/openapi3": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@typespec/openapi3/-/openapi3-1.9.0.tgz", + "integrity": "sha512-htwhrGHQxuoNwAljeJE8CBt5yfKOv48T9Ugv91Y+4yNnlevJfDT29yrfD2mXYMujVOr3Kte1qilazClafkUIgg==", + "license": "MIT", + "dependencies": { + "@scalar/json-magic": "^0.9.1", + "@scalar/openapi-parser": "^0.24.1", + "@scalar/openapi-types": "^0.5.0", + "@typespec/asset-emitter": "^0.79.0", + "yaml": "~2.8.2" + }, + "bin": { + "tsp-openapi3": "cmd/tsp-openapi3.js" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.9.0", + "@typespec/events": "^0.79.0", + "@typespec/http": "^1.9.0", + "@typespec/json-schema": "^1.9.0", + "@typespec/openapi": "^1.9.0", + "@typespec/sse": "^0.79.0", + "@typespec/streams": "^0.79.0", + "@typespec/versioning": "^0.79.0" + }, + "peerDependenciesMeta": { + "@typespec/events": { + "optional": true + }, + "@typespec/json-schema": { + "optional": true + }, + "@typespec/sse": { + "optional": true + }, + "@typespec/streams": { + "optional": true + }, + "@typespec/versioning": { + "optional": true + }, + "@typespec/xml": { + "optional": true + } + } + }, + "node_modules/@typespec/rest": { + "version": "0.79.0", + "resolved": "https://registry.npmjs.org/@typespec/rest/-/rest-0.79.0.tgz", + "integrity": "sha512-6QIX7oaUGy/z4rseUrC86LjHxZn8rAAY4fXvGnlPRce6GhEdTb9S9OQPmlPeWngXwCx/07P2+FCR915APqmZxg==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.9.0", + "@typespec/http": "^1.9.0" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "license": "MIT", + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/change-case": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", + "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", + "license": "MIT" + }, + "node_modules/chardet": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", + "license": "MIT" + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.1.0.tgz", + "integrity": "sha512-+A4Hq7m7Ze592k9gZRy4gJ27DrXRNnC1vPjxTt1qQxEY8RxagBkBxivkCwg7FxSTG0iLLEMaUx13oOr0R2/qcQ==", + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.5", + "is-path-inside": "^4.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/leven": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-4.1.0.tgz", + "integrity": "sha512-KZ9W9nWDT7rF7Dazg8xyLHGLrmpgq2nVNFUckhqdW3szVP6YhCpp/RAnpmVExA9JvrMynjwSLVrEj3AepHR6ew==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "license": "MIT", + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/mute-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", + "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/tar": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz", + "integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/temporal-polyfill": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-0.3.0.tgz", + "integrity": "sha512-qNsTkX9K8hi+FHDfHmf22e/OGuXmfBm9RqNismxBrnSmZVJKegQ+HYYXT+R7Ha8F/YSm2Y34vmzD4cxMu2u95g==", + "license": "MIT", + "dependencies": { + "temporal-spec": "0.3.0" + } + }, + "node_modules/temporal-spec": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-0.3.0.tgz", + "integrity": "sha512-n+noVpIqz4hYgFSMOSiINNOUOMFtV5cZQNCmmszA6GiVFVRt3G7AqVyhXjhCSmowvQn+NsGn+jMDMKJYHd3bSQ==", + "license": "ISC" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/unicorn-magic": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", + "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "license": "MIT", + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "license": "MIT" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/typespec/package.json b/typespec/package.json new file mode 100644 index 0000000..5f77beb --- /dev/null +++ b/typespec/package.json @@ -0,0 +1,15 @@ +{ + "name": "albatross-typespec", + "private": true, + "scripts": { + "build": "tsp compile api-server/ && tsp compile fortee/ && npm run copy-output", + "copy-output": "cp api-server/tsp-output/@typespec/openapi3/openapi.yaml ../openapi/api-server.yaml && cp fortee/tsp-output/@typespec/openapi3/openapi.yaml ../openapi/fortee.yaml" + }, + "dependencies": { + "@typespec/compiler": "^1.9.0", + "@typespec/http": "^1.9.0", + "@typespec/openapi": "^1.9.0", + "@typespec/openapi3": "^1.9.0", + "@typespec/rest": "^0.79.0" + } +} |
