From 1b1229c867c6ee45de4c583c7a76c60af7275b83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93lafur=20P=C3=A1ll=20Geirsson?= Date: Wed, 14 Aug 2024 12:47:00 +0200 Subject: [PATCH] feat/API: implement `/models` and `/models/{modelId}` using TypeSpec (#64421) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes CODY-3085 Fixes CODY-3086 Previously, there was no way for OpenAI clients to list the available models on Sourcegraph or query metadata about a given model ID ("model ref" using our internal terminology). This PR fixes that problem AND additionally adds infrastructure to auto-generate Go models from a TypeSpec specification. [TypeSpec](https://typespec.io/) is an IDL to document REST APIs, created by Microsoft. Historically, the Go code in this repository has been the single source of truth about what exact JSON structures are expected in HTTP request/response pairs in our REST endpoints. This new TypeSpec infrastructure allows us to document these shapes at a higher abstraction level, which has several benefits including automatic OpenAPI generation, which we can use to generate docs on sourcegraph.com/docs or automatically generate client bindings in TypeScript (among many other use-cases). I am planning to write an RFC to propose we start using TypeSpec for new REST endpoints going forward. If the RFC is not approved then we can just delete the new `tools/typespec_codegen` directory and keep the generated code in the repo. It won't be a big difference in the end compared our current manual approach of writing Go structs for HTTP APIs. ## Test plan See test cases. I additionally wrote a basic python script with the official OpenAI client to test that it works with this endpoint. First, I ran `sg start minimal`. Then I wrote this script ```py import os from openai import OpenAI from dotenv import load_dotenv import httpx load_dotenv() openai = OpenAI( # base_url="https://api.openai.com/v1", # api_key=os.getenv("OPENAI_API_KEY"), base_url="https://sourcegraph.test:3443/api/v1", api_key=os.getenv("SRC_ACCESS_TOKEN"), http_client=httpx.Client(verify=False) ) def main(): response = openai.models.list() for model in response.data: print(model.id) if __name__ == "__main__": main() ``` Finally, I ran ``` ❯ python3 models.py anthropic::unknown::claude-3-haiku-20240307 anthropic::unknown::claude-3-sonnet-20240229 fireworks::unknown::starcoder ``` ## Changelog * New `GET /.api/llm/models` and `GET /.api/llm/models/{modelId}` REST API endpoints to list available LLM models on the instance and to get information about a given model. This endpoints is compatible with the `/models` and `/models/{modelId}` endpoints from OpenAI. --- .bazelignore | 1 + cmd/frontend/internal/llmapi/BUILD.bazel | 13 +- ...handler.go => handler_chat_completions.go} | 31 +- ...st.go => handler_chat_completions_test.go} | 3 +- .../internal/llmapi/handler_models.go | 41 ++ .../internal/llmapi/handler_models_modelid.go | 48 +++ .../llmapi/handler_models_modelid_test.go | 78 ++++ .../internal/llmapi/handler_models_test.go | 59 +++ cmd/frontend/internal/llmapi/httpapi.go | 23 ++ dev/generate-openapi-models.sh | 38 ++ internal/openapi/.gitignore | 9 + internal/openapi/.openapi-generator-ignore | 17 + internal/openapi/.openapi-generator/FILES | 4 + internal/openapi/.openapi-generator/VERSION | 1 + .../openapi/.openapi-generator/config.yml | 4 + internal/openapi/api/openapi.yaml | 123 ++++++ internal/openapi/cody.tsp | 47 +++ internal/openapi/goapi/BUILD.bazel | 52 +++ internal/openapi/goapi/error.go | 14 + internal/openapi/goapi/helpers.go | 10 + .../openapi/goapi/model_chat_completions.go | 2 +- .../goapi/model_chat_completions_test.go | 2 +- internal/openapi/goapi/model_error.go | 37 ++ .../goapi/model_list_models_response.go | 47 +++ internal/openapi/goapi/model_model.go | 49 +++ internal/openapi/main.tsp | 1 + internal/openapi/package.json | 21 + internal/openapi/tspconfig.yaml | 2 + pnpm-lock.yaml | 387 +++++++++++++++--- pnpm-workspace.yaml | 1 + 30 files changed, 1088 insertions(+), 77 deletions(-) rename cmd/frontend/internal/llmapi/{chat_completions_handler.go => handler_chat_completions.go} (87%) rename cmd/frontend/internal/llmapi/{chat_completions_handler_test.go => handler_chat_completions_test.go} (97%) create mode 100644 cmd/frontend/internal/llmapi/handler_models.go create mode 100644 cmd/frontend/internal/llmapi/handler_models_modelid.go create mode 100644 cmd/frontend/internal/llmapi/handler_models_modelid_test.go create mode 100644 cmd/frontend/internal/llmapi/handler_models_test.go create mode 100755 dev/generate-openapi-models.sh create mode 100644 internal/openapi/.gitignore create mode 100644 internal/openapi/.openapi-generator-ignore create mode 100644 internal/openapi/.openapi-generator/FILES create mode 100644 internal/openapi/.openapi-generator/VERSION create mode 100644 internal/openapi/.openapi-generator/config.yml create mode 100644 internal/openapi/api/openapi.yaml create mode 100644 internal/openapi/cody.tsp create mode 100644 internal/openapi/goapi/BUILD.bazel create mode 100644 internal/openapi/goapi/error.go create mode 100644 internal/openapi/goapi/helpers.go rename cmd/frontend/internal/llmapi/chat_completions_models.go => internal/openapi/goapi/model_chat_completions.go (99%) rename cmd/frontend/internal/llmapi/chat_completions_models_test.go => internal/openapi/goapi/model_chat_completions_test.go (99%) create mode 100644 internal/openapi/goapi/model_error.go create mode 100644 internal/openapi/goapi/model_list_models_response.go create mode 100644 internal/openapi/goapi/model_model.go create mode 100644 internal/openapi/main.tsp create mode 100644 internal/openapi/package.json create mode 100644 internal/openapi/tspconfig.yaml diff --git a/.bazelignore b/.bazelignore index b1bb86434a9..02d073c1c4c 100644 --- a/.bazelignore +++ b/.bazelignore @@ -26,6 +26,7 @@ client/web/node_modules client/web-sveltekit/node_modules client/wildcard/node_modules internal/appliance/frontend/maintenance/node_modules +internal/openapi/node_modules cmd/symbols/internal/squirrel/test_repos/starlark diff --git a/cmd/frontend/internal/llmapi/BUILD.bazel b/cmd/frontend/internal/llmapi/BUILD.bazel index d1ef2947150..4d1717be352 100644 --- a/cmd/frontend/internal/llmapi/BUILD.bazel +++ b/cmd/frontend/internal/llmapi/BUILD.bazel @@ -4,8 +4,9 @@ load("//dev:go_defs.bzl", "go_test") go_library( name = "llmapi", srcs = [ - "chat_completions_handler.go", - "chat_completions_models.go", + "handler_chat_completions.go", + "handler_models.go", + "handler_models_modelid.go", "httpapi.go", ], importpath = "github.com/sourcegraph/sourcegraph/cmd/frontend/internal/llmapi", @@ -13,6 +14,7 @@ go_library( deps = [ "//internal/completions/types", "//internal/modelconfig/types", + "//internal/openapi/goapi", "//lib/errors", "@com_github_google_uuid//:uuid", "@com_github_gorilla_mux//:mux", @@ -23,8 +25,9 @@ go_library( go_test( name = "llmapi_test", srcs = [ - "chat_completions_handler_test.go", - "chat_completions_models_test.go", + "handler_chat_completions_test.go", + "handler_models_modelid_test.go", + "handler_models_test.go", "utils_test.go", ], data = glob(["golly-recordings/**"]), @@ -33,8 +36,10 @@ go_test( "//internal/golly", "//internal/httpcli", "//internal/modelconfig/types", + "//internal/openapi/goapi", "@com_github_gorilla_mux//:mux", "@com_github_hexops_autogold_v2//:autogold", "@com_github_stretchr_testify//assert", + "@com_github_stretchr_testify//require", ], ) diff --git a/cmd/frontend/internal/llmapi/chat_completions_handler.go b/cmd/frontend/internal/llmapi/handler_chat_completions.go similarity index 87% rename from cmd/frontend/internal/llmapi/chat_completions_handler.go rename to cmd/frontend/internal/llmapi/handler_chat_completions.go index 1dd03e6fa88..c945d569e43 100644 --- a/cmd/frontend/internal/llmapi/chat_completions_handler.go +++ b/cmd/frontend/internal/llmapi/handler_chat_completions.go @@ -11,13 +11,13 @@ import ( "time" "github.com/google/uuid" - "github.com/sourcegraph/log" sglog "github.com/sourcegraph/log" "github.com/sourcegraph/sourcegraph/lib/errors" completions "github.com/sourcegraph/sourcegraph/internal/completions/types" types "github.com/sourcegraph/sourcegraph/internal/modelconfig/types" + "github.com/sourcegraph/sourcegraph/internal/openapi/goapi" ) // chatCompletionsHandler implements the REST endpoint /chat/completions @@ -34,12 +34,10 @@ type chatCompletionsHandler struct { GetModelConfig GetModelConfigurationFunc } -type GetModelConfigurationFunc func() (*types.ModelConfiguration, error) - var _ http.Handler = (*chatCompletionsHandler)(nil) func (h *chatCompletionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - var chatCompletionRequest CreateChatCompletionRequest + var chatCompletionRequest goapi.CreateChatCompletionRequest body, err := io.ReadAll(r.Body) if err != nil { http.Error(w, fmt.Sprintf("io.ReadAll: %v", err), http.StatusInternalServerError) @@ -78,19 +76,14 @@ func (h *chatCompletionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques chatCompletionResponse := transformToOpenAIResponse(sgResp, chatCompletionRequest) - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - if err = json.NewEncoder(w).Encode(chatCompletionResponse); err != nil { - h.logger.Error("writing /chat/completions response body", log.Error(err)) - } - + serveJSON(w, r, h.logger, chatCompletionResponse) } // validateRequestedModel checks that are only use the modelref syntax // (${ProviderID}::${APIVersionID}::${ModelID}). If the user passes the old // syntax `${ProviderID}/${ModelID}`, then we try to return a helpful error // message suggesting to use the new modelref syntax. -func validateRequestedModel(chatCompletionRequest CreateChatCompletionRequest, modelConfig *types.ModelConfiguration) string { +func validateRequestedModel(chatCompletionRequest goapi.CreateChatCompletionRequest, modelConfig *types.ModelConfiguration) string { closestModelRef := "" for _, model := range modelConfig.Models { if string(model.ModelRef) == chatCompletionRequest.Model { @@ -109,7 +102,7 @@ func validateRequestedModel(chatCompletionRequest CreateChatCompletionRequest, m return fmt.Sprintf("model %s is not supported%s", chatCompletionRequest.Model, didYouMean) } -func validateChatCompletionRequest(chatCompletionRequest CreateChatCompletionRequest) string { +func validateChatCompletionRequest(chatCompletionRequest goapi.CreateChatCompletionRequest) string { if chatCompletionRequest.N != nil && *chatCompletionRequest.N != 1 { return "n must be nil or 1" @@ -148,7 +141,7 @@ func validateChatCompletionRequest(chatCompletionRequest CreateChatCompletionReq return "" } -func transformToSGRequest(openAIReq CreateChatCompletionRequest) completions.CodyCompletionRequestParameters { +func transformToSGRequest(openAIReq goapi.CreateChatCompletionRequest) completions.CodyCompletionRequestParameters { maxTokens := 16 // Default in OpenAI openapi.yaml spec if openAIReq.MaxTokens != nil { maxTokens = *openAIReq.MaxTokens @@ -178,7 +171,7 @@ func transformToSGRequest(openAIReq CreateChatCompletionRequest) completions.Cod } } -func transformMessages(messages []ChatCompletionRequestMessage) []completions.Message { +func transformMessages(messages []goapi.ChatCompletionRequestMessage) []completions.Message { // Transform OpenAI messages to Sourcegraph format transformed := make([]completions.Message, len(messages)) for i, msg := range messages { @@ -248,23 +241,23 @@ func (h *chatCompletionsHandler) forwardToAPIHandler(sgReq completions.CodyCompl return &sgResp, nil } -func transformToOpenAIResponse(sgResp *completions.CompletionResponse, openAIReq CreateChatCompletionRequest) CreateChatCompletionResponse { - return CreateChatCompletionResponse{ +func transformToOpenAIResponse(sgResp *completions.CompletionResponse, openAIReq goapi.CreateChatCompletionRequest) goapi.CreateChatCompletionResponse { + return goapi.CreateChatCompletionResponse{ ID: "chat-" + generateUUID(), Object: "chat.completion", Created: time.Now().Unix(), Model: openAIReq.Model, - Choices: []ChatCompletionChoice{ + Choices: []goapi.ChatCompletionChoice{ { Index: 0, - Message: ChatCompletionResponseMessage{ + Message: goapi.ChatCompletionResponseMessage{ Role: "assistant", Content: sgResp.Completion, }, FinishReason: sgResp.StopReason, }, }, - Usage: CompletionUsage{}, + Usage: goapi.CompletionUsage{}, } } diff --git a/cmd/frontend/internal/llmapi/chat_completions_handler_test.go b/cmd/frontend/internal/llmapi/handler_chat_completions_test.go similarity index 97% rename from cmd/frontend/internal/llmapi/chat_completions_handler_test.go rename to cmd/frontend/internal/llmapi/handler_chat_completions_test.go index d601e1c5aa8..bf0ebee2ff8 100644 --- a/cmd/frontend/internal/llmapi/chat_completions_handler_test.go +++ b/cmd/frontend/internal/llmapi/handler_chat_completions_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/assert" types "github.com/sourcegraph/sourcegraph/internal/modelconfig/types" + "github.com/sourcegraph/sourcegraph/internal/openapi/goapi" ) func TestChatCompletionsHandler(t *testing.T) { @@ -89,7 +90,7 @@ func TestChatCompletionsHandler(t *testing.T) { t.Fatalf("Expected status code %d, got %d. Body: %s%s", http.StatusOK, rr.Code, rr.Body.String(), extraMessage) } - var resp CreateChatCompletionResponse + var resp goapi.CreateChatCompletionResponse responseBytes := rr.Body.Bytes() err := json.Unmarshal(responseBytes, &resp) if err != nil { diff --git a/cmd/frontend/internal/llmapi/handler_models.go b/cmd/frontend/internal/llmapi/handler_models.go new file mode 100644 index 00000000000..d1b7b53639d --- /dev/null +++ b/cmd/frontend/internal/llmapi/handler_models.go @@ -0,0 +1,41 @@ +package llmapi + +import ( + "fmt" + "net/http" + + sglog "github.com/sourcegraph/log" + + "github.com/sourcegraph/sourcegraph/internal/openapi/goapi" +) + +type modelsHandler struct { + logger sglog.Logger + GetModelConfig GetModelConfigurationFunc +} + +var _ http.Handler = (*modelsHandler)(nil) + +func (m *modelsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + currentModelConfig, err := m.GetModelConfig() + if err != nil { + http.Error(w, fmt.Sprintf("modelConfigSvc.Get: %v", err), http.StatusInternalServerError) + return + } + + var data []goapi.Model + for _, model := range currentModelConfig.Models { + data = append(data, goapi.Model{ + Object: "model", + Id: string(model.ModelRef), + OwnedBy: string(model.ModelRef.ProviderID()), + }) + } + + response := goapi.ListModelsResponse{ + Object: "list", + Data: data, + } + + serveJSON(w, r, m.logger, response) +} diff --git a/cmd/frontend/internal/llmapi/handler_models_modelid.go b/cmd/frontend/internal/llmapi/handler_models_modelid.go new file mode 100644 index 00000000000..1e0830823cc --- /dev/null +++ b/cmd/frontend/internal/llmapi/handler_models_modelid.go @@ -0,0 +1,48 @@ +package llmapi + +import ( + "fmt" + "net/http" + + "github.com/gorilla/mux" + sglog "github.com/sourcegraph/log" + + "github.com/sourcegraph/sourcegraph/internal/openapi/goapi" +) + +type modelsModelIDHandler struct { + logger sglog.Logger + GetModelConfig GetModelConfigurationFunc +} + +var _ http.Handler = (*modelsModelIDHandler)(nil) + +func (m *modelsModelIDHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + modelId := vars["modelId"] + + if modelId == "" { + http.Error(w, "modelId is required", http.StatusBadRequest) + return + } + + currentModelConfig, err := m.GetModelConfig() + if err != nil { + http.Error(w, fmt.Sprintf("modelConfigSvc.Get: %v", err), http.StatusInternalServerError) + return + } + + for _, model := range currentModelConfig.Models { + if string(model.ModelRef) == modelId { + response := goapi.Model{ + Object: "model", + Id: string(model.ModelRef), + OwnedBy: string(model.ModelRef.ProviderID()), + } + serveJSON(w, r, m.logger, response) + return + } + } + + http.Error(w, "Model not found", http.StatusNotFound) +} diff --git a/cmd/frontend/internal/llmapi/handler_models_modelid_test.go b/cmd/frontend/internal/llmapi/handler_models_modelid_test.go new file mode 100644 index 00000000000..6376f14f6d4 --- /dev/null +++ b/cmd/frontend/internal/llmapi/handler_models_modelid_test.go @@ -0,0 +1,78 @@ +package llmapi + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + types "github.com/sourcegraph/sourcegraph/internal/modelconfig/types" + "github.com/sourcegraph/sourcegraph/internal/openapi/goapi" +) + +func TestModelsModelIDHandler(t *testing.T) { + mockModels := []types.Model{ + { + ModelRef: "anthropic::unknown::claude-3-sonnet-20240229", + DisplayName: "Claude 3 Sonnet", + }, + { + ModelRef: "openai::unknown::gpt-4", + DisplayName: "GPT-4", + }, + } + + c := newTest(t, func() (*types.ModelConfiguration, error) { + return &types.ModelConfiguration{Models: mockModels}, nil + }) + + testCases := []struct { + name string + modelID string + expectedStatus int + expectedModel *goapi.Model + }{ + { + name: "Existing model", + modelID: "anthropic::unknown::claude-3-sonnet-20240229", + expectedStatus: http.StatusOK, + expectedModel: &goapi.Model{ + Id: "anthropic::unknown::claude-3-sonnet-20240229", + Object: "model", + OwnedBy: "anthropic", + }, + }, + { + name: "Non-existent model", + modelID: "non-existent-model", + expectedStatus: http.StatusNotFound, + expectedModel: nil, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + req, err := http.NewRequest("GET", "/.api/llm/models/"+tc.modelID, nil) + require.NoError(t, err) + + rr := httptest.NewRecorder() + + c.Handler.ServeHTTP(rr, req) + + assert.Equal(t, tc.expectedStatus, rr.Code) + if rr.Code == http.StatusOK { + assert.Equal(t, "application/json", rr.Header().Get("Content-Type")) + } + + if tc.expectedModel != nil { + var response goapi.Model + err = json.Unmarshal(rr.Body.Bytes(), &response) + require.NoError(t, err) + assert.Equal(t, response, *tc.expectedModel) + } + }) + } +} diff --git a/cmd/frontend/internal/llmapi/handler_models_test.go b/cmd/frontend/internal/llmapi/handler_models_test.go new file mode 100644 index 00000000000..a6094e15c37 --- /dev/null +++ b/cmd/frontend/internal/llmapi/handler_models_test.go @@ -0,0 +1,59 @@ +package llmapi + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/hexops/autogold/v2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + types "github.com/sourcegraph/sourcegraph/internal/modelconfig/types" + "github.com/sourcegraph/sourcegraph/internal/openapi/goapi" +) + +func TestModelsHandler(t *testing.T) { + + mockModels := []types.Model{ + { + ModelRef: "anthropic::unknown::claude-3-sonnet-20240229", + DisplayName: "Claude 3 Sonnet", + }, + { + ModelRef: "openai::unknown::gpt-4", + DisplayName: "GPT-4", + }, + } + c := newTest(t, func() (*types.ModelConfiguration, error) { + return &types.ModelConfiguration{Models: mockModels}, nil + }) + + req, err := http.NewRequest("GET", "/.api/llm/models", nil) + require.NoError(t, err) + + rr := httptest.NewRecorder() + + c.Handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusOK, rr.Code) + assert.Equal(t, "application/json", rr.Header().Get("Content-Type")) + + var response goapi.ListModelsResponse + err = json.Unmarshal(rr.Body.Bytes(), &response) + require.NoError(t, err) + autogold.Expect(goapi.ListModelsResponse{Object: "list", Data: []goapi.Model{ + { + Id: "anthropic::unknown::claude-3-sonnet-20240229", + Object: "model", + OwnedBy: "anthropic", + }, + { + Id: "openai::unknown::gpt-4", + Object: "model", + OwnedBy: "openai", + }, + }}).Equal(t, response) + +} diff --git a/cmd/frontend/internal/llmapi/httpapi.go b/cmd/frontend/internal/llmapi/httpapi.go index 038182e540d..65117f1b6ef 100644 --- a/cmd/frontend/internal/llmapi/httpapi.go +++ b/cmd/frontend/internal/llmapi/httpapi.go @@ -1,12 +1,19 @@ package llmapi import ( + "encoding/json" + "fmt" "net/http" "github.com/gorilla/mux" + "github.com/sourcegraph/log" sglog "github.com/sourcegraph/log" + + types "github.com/sourcegraph/sourcegraph/internal/modelconfig/types" ) +type GetModelConfigurationFunc func() (*types.ModelConfiguration, error) + func RegisterHandlers(m *mux.Router, apiHandler http.Handler, getModelConfigFunc GetModelConfigurationFunc) { logger := sglog.Scoped("llmapi") @@ -15,4 +22,20 @@ func RegisterHandlers(m *mux.Router, apiHandler http.Handler, getModelConfigFunc apiHandler: apiHandler, GetModelConfig: getModelConfigFunc, }) + m.Path("/models").Methods("GET").Handler(&modelsHandler{ + logger: logger, + GetModelConfig: getModelConfigFunc, + }) + m.Path("/models/{modelId}").Methods("GET").Handler(&modelsModelIDHandler{ + logger: logger, + GetModelConfig: getModelConfigFunc, + }) +} + +func serveJSON(w http.ResponseWriter, r *http.Request, logger sglog.Logger, v interface{}) { + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(v); err != nil { + logger.Error(fmt.Sprintf("writing %s JSON response body", r.URL.Path), log.Error(err)) + http.Error(w, "writing response", http.StatusInternalServerError) + } } diff --git a/dev/generate-openapi-models.sh b/dev/generate-openapi-models.sh new file mode 100755 index 00000000000..6e3d2a75be5 --- /dev/null +++ b/dev/generate-openapi-models.sh @@ -0,0 +1,38 @@ +#!/bin/sh +set -eu +# Script to generate Go models from TypeSpec, which defines REST APIs +# Ideally, this bash script should be replaced with a `bazel run` command +# but we keep it as a bash script for now to bootstrap our usage of TypeSpec. + +# Check if openapi-generator is installed +if ! command -v openapi-generator > /dev/null 2>&1 +then + echo "openapi-generator not found, installing from Homebrew..." + brew install openapi-generator +fi + +# Check if main.tsp exists +MAIN_TSP="internal/openapi/main.tsp" +if [ ! -f "$MAIN_TSP" ]; then + echo "Error: $MAIN_TSP not found. The working directory must be at the root of the repo." + exit 1 +fi + +pnpm install +pnpm -C internal/openapi compile +mv internal/openapi/goapi internal/openapi/go +openapi-generator generate \ + -g go \ + -i internal/openapi/tsp-output/@typespec/openapi3/openapi.yaml \ + -o internal/openapi \ + -c internal/openapi/.openapi-generator/config.yml +mv internal/openapi/go internal/openapi/goapi + +# Read the file content into a variable +content=$(cat internal/openapi/api/openapi.yaml) + +# Prepend the comment and write back to the file +echo "# Code generated by OpenAPI Generator - DO NOT EDIT" > internal/openapi/api/openapi.yaml +echo "$content" >> internal/openapi/api/openapi.yaml + +echo "internal/openapi/goapi" diff --git a/internal/openapi/.gitignore b/internal/openapi/.gitignore new file mode 100644 index 00000000000..33b804b419d --- /dev/null +++ b/internal/openapi/.gitignore @@ -0,0 +1,9 @@ +# MacOS +.DS_Store + +# Default TypeSpec output +tsp-output/ +dist/ + +# Dependency directories +node_modules/ diff --git a/internal/openapi/.openapi-generator-ignore b/internal/openapi/.openapi-generator-ignore new file mode 100644 index 00000000000..706861c9322 --- /dev/null +++ b/internal/openapi/.openapi-generator-ignore @@ -0,0 +1,17 @@ +# OpenAPI Generator Ignore +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +go/logger.go +go/impl.go +go/helpers.go +go/api_default.go +go/api_default_service.go +go/api.go +go/error.go +go/routers.go +go/api_default_service.go +go.mod +main.go +Dockerfile +README.md diff --git a/internal/openapi/.openapi-generator/FILES b/internal/openapi/.openapi-generator/FILES new file mode 100644 index 00000000000..ecc06e2c97a --- /dev/null +++ b/internal/openapi/.openapi-generator/FILES @@ -0,0 +1,4 @@ +api/openapi.yaml +go/model_error.go +go/model_list_models_response.go +go/model_model.go diff --git a/internal/openapi/.openapi-generator/VERSION b/internal/openapi/.openapi-generator/VERSION new file mode 100644 index 00000000000..1985849fb58 --- /dev/null +++ b/internal/openapi/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.7.0 diff --git a/internal/openapi/.openapi-generator/config.yml b/internal/openapi/.openapi-generator/config.yml new file mode 100644 index 00000000000..d5cd794c1cb --- /dev/null +++ b/internal/openapi/.openapi-generator/config.yml @@ -0,0 +1,4 @@ +additionalProperties: + packageName: goapi +globalProperties: + models: true diff --git a/internal/openapi/api/openapi.yaml b/internal/openapi/api/openapi.yaml new file mode 100644 index 00000000000..a71cbddc116 --- /dev/null +++ b/internal/openapi/api/openapi.yaml @@ -0,0 +1,123 @@ +# Code generated by OpenAPI Generator - DO NOT EDIT +openapi: 3.0.0 +info: + title: Cody Service + version: 0.0.0 +servers: + - url: / +paths: + /models: + get: + operationId: Models_list + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ListModelsResponse' + description: The request has succeeded. + default: + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: An unexpected error response. + summary: "Lists the currently available models, and provides basic information\ + \ about each one such as the owner and availability." + /models/{modelId}: + get: + operationId: Models_retrieveModel + parameters: + - explode: false + in: path + name: modelId + required: true + schema: + type: string + style: simple + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Model' + description: The request has succeeded. + default: + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: An unexpected error response. + summary: "Retrieves a model instance, providing basic information about the\ + \ model such as the owner and permissioning." +components: + schemas: + Error: + example: + code: 6 + message: message + properties: + code: + format: int32 + type: integer + message: + type: string + required: + - code + - message + type: object + ListModelsResponse: + example: + data: + - created: 0 + owned_by: owned_by + id: id + object: model + - created: 0 + owned_by: owned_by + id: id + object: model + object: list + properties: + object: + enum: + - list + type: string + data: + items: + $ref: '#/components/schemas/Model' + type: array + required: + - data + - object + type: object + Model: + description: Describes an OpenAI model offering that can be used with the API. + example: + created: 0 + owned_by: owned_by + id: id + object: model + properties: + id: + description: 'The model identifier, which can be referenced in the API endpoints.' + type: string + object: + description: 'The object type, which is always "model".' + enum: + - model + type: string + created: + description: The Unix timestamp (in seconds) when the model was created. + format: int64 + type: integer + owned_by: + description: The organization that owns the model. + type: string + required: + - created + - id + - object + - owned_by + type: object diff --git a/internal/openapi/cody.tsp b/internal/openapi/cody.tsp new file mode 100644 index 00000000000..4319f2364ca --- /dev/null +++ b/internal/openapi/cody.tsp @@ -0,0 +1,47 @@ +import "@typespec/http"; +import "@typespec/rest"; + +using TypeSpec.Http; +using TypeSpec.Rest; + +@service({ + title: "Cody Service", +}) +namespace CodyService; + +@route("/models") +interface Models { + @get + @summary("Lists the currently available models, and provides basic information about each one such as the owner and availability.") + list(): ListModelsResponse | Error; + + @get + @summary("Retrieves a model instance, providing basic information about the model such as the owner and permissioning.") + retrieveModel(@path modelId: string): Model | Error; +} + +@doc("Describes an OpenAI model offering that can be used with the API.") +model Model { + @doc("The model identifier, which can be referenced in the API endpoints.") + id: string; + + @doc("The object type, which is always \"model\".") + object: "model"; + + @doc("The Unix timestamp (in seconds) when the model was created.") + created: int64; + + @doc("The organization that owns the model.") + owned_by: string; +} + +model ListModelsResponse { + object: "list"; + data: Model[]; +} + +@error +model Error { + code: int32; + message: string; +} diff --git a/internal/openapi/goapi/BUILD.bazel b/internal/openapi/goapi/BUILD.bazel new file mode 100644 index 00000000000..45ba8accce4 --- /dev/null +++ b/internal/openapi/goapi/BUILD.bazel @@ -0,0 +1,52 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("//dev:go_defs.bzl", "go_test") + +go_library( + name = "go", + srcs = [ + "error.go", + "helpers.go", + "model_chat_completions.go", + "model_error.go", + "model_list_models_response.go", + "model_model.go", + ], + importpath = "github.com/sourcegraph/sourcegraph/internal/openapi/go", + visibility = ["//cmd/frontend:__subpackages__"], + deps = ["//lib/errors"], +) + +go_test( + name = "go_test", + srcs = ["model_chat_completions_test.go"], + embed = [":go"], + deps = [ + "@com_github_hexops_autogold_v2//:autogold", + "@com_github_stretchr_testify//assert", + ], +) + +go_library( + name = "goapi", + srcs = [ + "error.go", + "helpers.go", + "model_chat_completions.go", + "model_error.go", + "model_list_models_response.go", + "model_model.go", + ], + importpath = "github.com/sourcegraph/sourcegraph/internal/openapi/goapi", + visibility = ["//:__subpackages__"], + deps = ["//lib/errors"], +) + +go_test( + name = "goapi_test", + srcs = ["model_chat_completions_test.go"], + embed = [":goapi"], + deps = [ + "@com_github_hexops_autogold_v2//:autogold", + "@com_github_stretchr_testify//assert", + ], +) diff --git a/internal/openapi/goapi/error.go b/internal/openapi/goapi/error.go new file mode 100644 index 00000000000..c2fb8a37afa --- /dev/null +++ b/internal/openapi/goapi/error.go @@ -0,0 +1,14 @@ +package goapi + +import ( + "fmt" +) + +// RequiredError indicates that an error has occurred when parsing request parameters +type RequiredError struct { + Field string +} + +func (e *RequiredError) Error() string { + return fmt.Sprintf("required field '%s' is zero value.", e.Field) +} diff --git a/internal/openapi/goapi/helpers.go b/internal/openapi/goapi/helpers.go new file mode 100644 index 00000000000..e2afa302e09 --- /dev/null +++ b/internal/openapi/goapi/helpers.go @@ -0,0 +1,10 @@ +package goapi + +import ( + "reflect" +) + +// IsZeroValue checks if the val is the zero-ed value. +func IsZeroValue(val interface{}) bool { + return val == nil || reflect.DeepEqual(val, reflect.Zero(reflect.TypeOf(val)).Interface()) +} diff --git a/cmd/frontend/internal/llmapi/chat_completions_models.go b/internal/openapi/goapi/model_chat_completions.go similarity index 99% rename from cmd/frontend/internal/llmapi/chat_completions_models.go rename to internal/openapi/goapi/model_chat_completions.go index 5df41866fe7..832d4738651 100644 --- a/cmd/frontend/internal/llmapi/chat_completions_models.go +++ b/internal/openapi/goapi/model_chat_completions.go @@ -1,4 +1,4 @@ -package llmapi +package goapi import ( "encoding/json" diff --git a/cmd/frontend/internal/llmapi/chat_completions_models_test.go b/internal/openapi/goapi/model_chat_completions_test.go similarity index 99% rename from cmd/frontend/internal/llmapi/chat_completions_models_test.go rename to internal/openapi/goapi/model_chat_completions_test.go index 761d2c6480f..74980c84a75 100644 --- a/cmd/frontend/internal/llmapi/chat_completions_models_test.go +++ b/internal/openapi/goapi/model_chat_completions_test.go @@ -1,4 +1,4 @@ -package llmapi +package goapi import ( "encoding/json" diff --git a/internal/openapi/goapi/model_error.go b/internal/openapi/goapi/model_error.go new file mode 100644 index 00000000000..12429f27b55 --- /dev/null +++ b/internal/openapi/goapi/model_error.go @@ -0,0 +1,37 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +/* + * Cody Service + * + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * API version: 0.0.0 + */ + +package goapi + +type Error struct { + Code int32 `json:"code"` + + Message string `json:"message"` +} + +// AssertErrorRequired checks if the required fields are not zero-ed +func AssertErrorRequired(obj Error) error { + elements := map[string]interface{}{ + "code": obj.Code, + "message": obj.Message, + } + for name, el := range elements { + if isZero := IsZeroValue(el); isZero { + return &RequiredError{Field: name} + } + } + + return nil +} + +// AssertErrorConstraints checks if the values respects the defined constraints +func AssertErrorConstraints(obj Error) error { + return nil +} diff --git a/internal/openapi/goapi/model_list_models_response.go b/internal/openapi/goapi/model_list_models_response.go new file mode 100644 index 00000000000..dc1f53c38d6 --- /dev/null +++ b/internal/openapi/goapi/model_list_models_response.go @@ -0,0 +1,47 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +/* + * Cody Service + * + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * API version: 0.0.0 + */ + +package goapi + +type ListModelsResponse struct { + Object string `json:"object"` + + Data []Model `json:"data"` +} + +// AssertListModelsResponseRequired checks if the required fields are not zero-ed +func AssertListModelsResponseRequired(obj ListModelsResponse) error { + elements := map[string]interface{}{ + "object": obj.Object, + "data": obj.Data, + } + for name, el := range elements { + if isZero := IsZeroValue(el); isZero { + return &RequiredError{Field: name} + } + } + + for _, el := range obj.Data { + if err := AssertModelRequired(el); err != nil { + return err + } + } + return nil +} + +// AssertListModelsResponseConstraints checks if the values respects the defined constraints +func AssertListModelsResponseConstraints(obj ListModelsResponse) error { + for _, el := range obj.Data { + if err := AssertModelConstraints(el); err != nil { + return err + } + } + return nil +} diff --git a/internal/openapi/goapi/model_model.go b/internal/openapi/goapi/model_model.go new file mode 100644 index 00000000000..94034833ba7 --- /dev/null +++ b/internal/openapi/goapi/model_model.go @@ -0,0 +1,49 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +/* + * Cody Service + * + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * API version: 0.0.0 + */ + +package goapi + +// Model - Describes an OpenAI model offering that can be used with the API. +type Model struct { + + // The model identifier, which can be referenced in the API endpoints. + Id string `json:"id"` + + // The object type, which is always \"model\". + Object string `json:"object"` + + // The Unix timestamp (in seconds) when the model was created. + Created int64 `json:"created"` + + // The organization that owns the model. + OwnedBy string `json:"owned_by"` +} + +// AssertModelRequired checks if the required fields are not zero-ed +func AssertModelRequired(obj Model) error { + elements := map[string]interface{}{ + "id": obj.Id, + "object": obj.Object, + "created": obj.Created, + "owned_by": obj.OwnedBy, + } + for name, el := range elements { + if isZero := IsZeroValue(el); isZero { + return &RequiredError{Field: name} + } + } + + return nil +} + +// AssertModelConstraints checks if the values respects the defined constraints +func AssertModelConstraints(obj Model) error { + return nil +} diff --git a/internal/openapi/main.tsp b/internal/openapi/main.tsp new file mode 100644 index 00000000000..3120834c8fa --- /dev/null +++ b/internal/openapi/main.tsp @@ -0,0 +1 @@ +import "./cody.tsp"; diff --git a/internal/openapi/package.json b/internal/openapi/package.json new file mode 100644 index 00000000000..7a7c9194022 --- /dev/null +++ b/internal/openapi/package.json @@ -0,0 +1,21 @@ +{ + "name": "sourcegraph-rest-api", + "version": "0.1.0", + "type": "module", + "scripts": { + "compile": "tsp compile ." + }, + "peerDependencies": { + "@typespec/compiler": "0.59.0", + "@typespec/http": "0.59.0", + "@typespec/rest": "0.59.0", + "@typespec/openapi3": "0.59.0" + }, + "devDependencies": { + "@typespec/compiler": "0.59.0", + "@typespec/http": "0.59.0", + "@typespec/rest": "0.59.0", + "@typespec/openapi3": "0.59.0" + }, + "private": true +} diff --git a/internal/openapi/tspconfig.yaml b/internal/openapi/tspconfig.yaml new file mode 100644 index 00000000000..a3fe48f13e9 --- /dev/null +++ b/internal/openapi/tspconfig.yaml @@ -0,0 +1,2 @@ +emit: + - "@typespec/openapi3" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e81f23fc6e1..5e4e25bfb65 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1785,6 +1785,21 @@ importers: specifier: ^9.12.4 version: 9.12.4 + internal/openapi: + devDependencies: + '@typespec/compiler': + specifier: 0.59.0 + version: 0.59.0 + '@typespec/http': + specifier: 0.59.0 + version: 0.59.0(@typespec/compiler@0.59.0) + '@typespec/openapi3': + specifier: 0.59.0 + version: 0.59.0(@typespec/compiler@0.59.0)(@typespec/http@0.59.0)(@typespec/openapi@0.59.0)(@typespec/versioning@0.59.0)(openapi-types@12.1.3) + '@typespec/rest': + specifier: 0.59.0 + version: 0.59.0(@typespec/compiler@0.59.0)(@typespec/http@0.59.0) + internal/appliance/frontend/maintenance: dependencies: '@emotion/react': @@ -1901,6 +1916,10 @@ packages: js-yaml: 3.14.1 dev: true + /@apidevtools/swagger-methods@3.0.2: + resolution: {integrity: sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==} + dev: true + /@apollo/client@3.8.0-alpha.7(graphql-ws@5.15.0)(graphql@15.4.0)(react-dom@18.1.0)(react@18.1.0): resolution: {integrity: sha512-pwyACANhC4R0VnEXn4Uv7DEIOr3V6kmKC+Eh3wlspuhP7RLHsU31oFYXmNs2THHAMDdXAK96axutd6qP86eZ+Q==} peerDependencies: @@ -2018,7 +2037,7 @@ packages: resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/highlight': 7.23.4 + '@babel/highlight': 7.24.7 chalk: 2.4.2 /@babel/code-frame@7.24.7: @@ -2026,7 +2045,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/highlight': 7.24.7 - picocolors: 1.0.0 + picocolors: 1.0.1 /@babel/compat-data@7.24.1: resolution: {integrity: sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==} @@ -2063,7 +2082,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.24.7 '@babel/generator': 7.23.6 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0) @@ -2274,7 +2293,7 @@ packages: '@babel/helper-module-imports': 7.24.7 '@babel/helper-simple-access': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-validator-identifier': 7.24.7 dev: true /@babel/helper-module-transforms@7.24.7(@babel/core@7.18.5): @@ -2418,14 +2437,6 @@ packages: '@babel/template': 7.24.7 '@babel/types': 7.24.7 - /@babel/highlight@7.23.4: - resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.24.7 - chalk: 2.4.2 - js-tokens: 4.0.0 - /@babel/highlight@7.24.7: resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} engines: {node: '>=6.9.0'} @@ -2433,7 +2444,7 @@ packages: '@babel/helper-validator-identifier': 7.24.7 chalk: 2.4.2 js-tokens: 4.0.0 - picocolors: 1.0.0 + picocolors: 1.0.1 /@babel/parser@7.10.5: resolution: {integrity: sha512-wfryxy4bE1UivvQKSQDU4/X6dr+i8bctjUjj8Zyt3DQy7NtPizJXT8M52nqpNKL+nq2PW8lxk4ZqLj0fD4B4hQ==} @@ -3505,7 +3516,7 @@ packages: resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.24.7 '@babel/parser': 7.24.0 '@babel/types': 7.24.0 dev: true @@ -3536,7 +3547,7 @@ packages: resolution: {integrity: sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.24.7 '@babel/generator': 7.23.6 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 @@ -5895,6 +5906,11 @@ packages: resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} + /@humanwhocodes/momoa@2.0.4: + resolution: {integrity: sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==} + engines: {node: '>=10.10.0'} + dev: true + /@humanwhocodes/object-schema@1.2.1: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} deprecated: Use @eslint/object-schema instead @@ -7134,7 +7150,7 @@ packages: '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0) '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) '@opentelemetry/semantic-conventions': 1.24.1 - semver: 7.6.0 + semver: 7.6.3 dev: false /@opentelemetry/instrumentation-ioredis@0.40.0(@opentelemetry/api@1.8.0): @@ -7259,7 +7275,7 @@ packages: '@types/shimmer': 1.0.5 import-in-the-middle: 1.4.2 require-in-the-middle: 7.3.0 - semver: 7.6.0 + semver: 7.6.3 shimmer: 1.2.1 dev: false optional: true @@ -7275,7 +7291,7 @@ packages: '@types/shimmer': 1.0.5 import-in-the-middle: 1.7.4 require-in-the-middle: 7.3.0 - semver: 7.6.0 + semver: 7.6.3 shimmer: 1.2.1 dev: false @@ -8428,10 +8444,10 @@ packages: hermes-profile-transformer: 0.0.6 node-stream-zip: 1.15.0 ora: 5.4.1 - semver: 7.6.0 + semver: 7.6.3 strip-ansi: 5.2.0 wcwidth: 1.0.1 - yaml: 2.4.1 + yaml: 2.4.5 transitivePeerDependencies: - encoding dev: false @@ -8505,7 +8521,7 @@ packages: node-fetch: 2.7.0 open: 6.4.0 ora: 5.4.1 - semver: 7.6.0 + semver: 7.6.3 shell-quote: 1.8.1 sudo-prompt: 9.2.1 transitivePeerDependencies: @@ -8540,7 +8556,7 @@ packages: fs-extra: 8.1.0 graceful-fs: 4.2.11 prompts: 2.4.2 - semver: 7.6.0 + semver: 7.6.3 transitivePeerDependencies: - bufferutil - encoding @@ -8877,6 +8893,53 @@ packages: zustand: 3.7.2(react@18.1.0) dev: false + /@readme/better-ajv-errors@1.6.0(ajv@8.17.1): + resolution: {integrity: sha512-9gO9rld84Jgu13kcbKRU+WHseNhaVt76wYMeRDGsUGYxwJtI3RmEJ9LY9dZCYQGI8eUZLuxb5qDja0nqklpFjQ==} + engines: {node: '>=14'} + peerDependencies: + ajv: 4.11.8 - 8 + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/runtime': 7.24.0 + '@humanwhocodes/momoa': 2.0.4 + ajv: 8.17.1 + chalk: 4.1.2 + json-to-ast: 2.1.0 + jsonpointer: 5.0.1 + leven: 3.1.0 + dev: true + + /@readme/json-schema-ref-parser@1.2.0: + resolution: {integrity: sha512-Bt3QVovFSua4QmHa65EHUmh2xS0XJ3rgTEUPH998f4OW4VVJke3BuS16f+kM0ZLOGdvIrzrPRqwihuv5BAjtrA==} + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + call-me-maybe: 1.0.1 + js-yaml: 4.1.0 + dev: true + + /@readme/openapi-parser@2.6.0(openapi-types@12.1.3): + resolution: {integrity: sha512-pyFJXezWj9WI1O+gdp95CoxfY+i+Uq3kKk4zXIFuRAZi9YnHpHOpjumWWr67wkmRTw19Hskh9spyY0Iyikf3fA==} + engines: {node: '>=18'} + peerDependencies: + openapi-types: '>=7' + dependencies: + '@apidevtools/swagger-methods': 3.0.2 + '@jsdevtools/ono': 7.1.3 + '@readme/better-ajv-errors': 1.6.0(ajv@8.17.1) + '@readme/json-schema-ref-parser': 1.2.0 + '@readme/openapi-schemas': 3.1.0 + ajv: 8.17.1 + ajv-draft-04: 1.0.0(ajv@8.17.1) + call-me-maybe: 1.0.1 + openapi-types: 12.1.3 + dev: true + + /@readme/openapi-schemas@3.1.0: + resolution: {integrity: sha512-9FC/6ho8uFa8fV50+FPy/ngWN53jaUu4GRXlAjcxIRrzhltJnpKkBG2Tp0IDraFJeWrOpk84RJ9EMEEYzaI1Bw==} + engines: {node: '>=18'} + dev: true + /@remix-run/router@1.17.1: resolution: {integrity: sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q==} engines: {node: '>=14.0.0'} @@ -9601,6 +9664,11 @@ packages: engines: {node: '>=10'} dev: false + /@sindresorhus/merge-streams@2.3.0: + resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} + engines: {node: '>=18'} + dev: true + /@sinonjs/commons@1.8.3: resolution: {integrity: sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==} dependencies: @@ -10634,10 +10702,10 @@ packages: jscodeshift: 0.15.2(@babel/preset-env@7.24.3) leven: 3.1.0 ora: 5.4.1 - prettier: 3.2.5 + prettier: 3.3.3 prompts: 2.4.2 read-pkg-up: 7.0.1 - semver: 7.6.0 + semver: 7.6.3 strip-json-comments: 3.1.1 tempy: 1.0.1 tiny-invariant: 1.3.3 @@ -10710,7 +10778,7 @@ packages: globby: 11.1.0 jscodeshift: 0.15.2(@babel/preset-env@7.24.3) lodash: 4.17.21 - prettier: 3.2.5 + prettier: 3.3.3 recast: 0.23.6 tiny-invariant: 1.3.3 dev: true @@ -10875,7 +10943,7 @@ packages: pkg-dir: 5.0.0 pretty-hrtime: 1.0.3 resolve-from: 5.0.0 - semver: 7.6.0 + semver: 7.6.3 tempy: 1.0.1 tiny-invariant: 1.3.3 ts-dedent: 2.2.0 @@ -10938,7 +11006,7 @@ packages: pretty-hrtime: 1.0.3 prompts: 2.4.2 read-pkg-up: 7.0.1 - semver: 7.6.0 + semver: 7.6.3 telejson: 7.2.0 tiny-invariant: 1.3.3 ts-dedent: 2.2.0 @@ -10990,7 +11058,7 @@ packages: pretty-hrtime: 1.0.3 prompts: 2.4.2 read-pkg-up: 7.0.1 - semver: 7.6.0 + semver: 7.6.3 telejson: 7.2.0 tiny-invariant: 1.3.3 ts-dedent: 2.2.0 @@ -11164,7 +11232,7 @@ packages: memoizerific: 1.11.3 react: 18.1.0 react-dom: 18.1.0(react@18.1.0) - semver: 7.6.0 + semver: 7.6.3 store2: 2.14.3 telejson: 7.2.0 ts-dedent: 2.2.0 @@ -11776,7 +11844,7 @@ packages: resolution: {integrity: sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==} engines: {node: '>=14'} dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.24.7 '@babel/runtime': 7.24.0 '@types/aria-query': 5.0.4 aria-query: 5.1.3 @@ -12830,7 +12898,7 @@ packages: graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 - semver: 7.6.0 + semver: 7.6.3 ts-api-utils: 1.0.3(typescript@5.4.2) typescript: 5.4.2 dev: true @@ -12960,7 +13028,7 @@ packages: debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.6.0 + semver: 7.6.3 tsutils: 3.21.0(typescript@5.4.2) typescript: 5.4.2 dev: true @@ -12979,7 +13047,7 @@ packages: debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.6.0 + semver: 7.6.3 tsutils: 3.21.0(typescript@5.4.2) typescript: 5.4.2 dev: true @@ -12999,7 +13067,7 @@ packages: globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 - semver: 7.6.0 + semver: 7.6.3 ts-api-utils: 1.0.3(typescript@5.4.2) typescript: 5.4.2 dev: true @@ -13018,7 +13086,7 @@ packages: '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.2) eslint: 8.57.0 eslint-scope: 5.1.1 - semver: 7.6.0 + semver: 7.6.3 transitivePeerDependencies: - typescript dev: true @@ -13036,7 +13104,7 @@ packages: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.2) eslint: 8.57.0 - semver: 7.6.0 + semver: 7.6.3 transitivePeerDependencies: - typescript dev: true @@ -13065,6 +13133,87 @@ packages: eslint-visitor-keys: 3.4.3 dev: true + /@typespec/compiler@0.59.0: + resolution: {integrity: sha512-fqh2TeAWQyt70f7NkfwOvoQMqHAfGzIfvcUi+XW55+ms6opiqNXBIT822Jr+T4fNo1PgsnbKC34n6SSIMxnOqw==} + engines: {node: '>=18.0.0'} + hasBin: true + dependencies: + '@babel/code-frame': 7.24.7 + ajv: 8.17.1 + change-case: 5.4.4 + globby: 14.0.2 + mustache: 4.2.0 + picocolors: 1.0.1 + prettier: 3.3.3 + prompts: 2.4.2 + semver: 7.6.3 + temporal-polyfill: 0.2.5 + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + yaml: 2.4.5 + yargs: 17.7.2 + dev: true + + /@typespec/http@0.59.0(@typespec/compiler@0.59.0): + resolution: {integrity: sha512-P8kJBHmkqYHhojO97Tnj8FH+UInWzGBl2I9Z6ZX6sVUVW9/87hoovgCcVmvU1xMUD/xvKzX3m70fbRXhkocsGQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + '@typespec/compiler': ~0.59.0 + dependencies: + '@typespec/compiler': 0.59.0 + dev: true + + /@typespec/openapi3@0.59.0(@typespec/compiler@0.59.0)(@typespec/http@0.59.0)(@typespec/openapi@0.59.0)(@typespec/versioning@0.59.0)(openapi-types@12.1.3): + resolution: {integrity: sha512-xwdWPPRtjsLxXjsebNppaHrFPF6rJiWkAEHCsK0elwvaPSruZvYfPhXpx1HnNkC2glb0NHgmxvXg7EmMwIYYcA==} + engines: {node: '>=18.0.0'} + hasBin: true + peerDependencies: + '@typespec/compiler': ~0.59.0 + '@typespec/http': ~0.59.0 + '@typespec/openapi': ~0.59.0 + '@typespec/versioning': ~0.59.0 + dependencies: + '@readme/openapi-parser': 2.6.0(openapi-types@12.1.3) + '@typespec/compiler': 0.59.0 + '@typespec/http': 0.59.0(@typespec/compiler@0.59.0) + '@typespec/openapi': 0.59.0(@typespec/compiler@0.59.0)(@typespec/http@0.59.0) + '@typespec/versioning': 0.59.0(@typespec/compiler@0.59.0) + yaml: 2.4.5 + transitivePeerDependencies: + - openapi-types + dev: true + + /@typespec/openapi@0.59.0(@typespec/compiler@0.59.0)(@typespec/http@0.59.0): + resolution: {integrity: sha512-do1Dm5w0MuK3994gYTBg6qMfgeIxmmsDqnz3zimYKMPpbnUBi4F6/o4iCfn0Fn9kaNl+H6UlOzZpsZW9xHui1Q==} + engines: {node: '>=18.0.0'} + peerDependencies: + '@typespec/compiler': ~0.59.0 + '@typespec/http': ~0.59.0 + dependencies: + '@typespec/compiler': 0.59.0 + '@typespec/http': 0.59.0(@typespec/compiler@0.59.0) + dev: true + + /@typespec/rest@0.59.0(@typespec/compiler@0.59.0)(@typespec/http@0.59.0): + resolution: {integrity: sha512-wGrmjRDUMgMn9fqusRhu36hC2GOvirz5O01VSrmAEOH6k1L2GX0Mq70gOdZa4kkkWyHYDKb7GdjfaLe8v+OH6w==} + engines: {node: '>=18.0.0'} + peerDependencies: + '@typespec/compiler': ~0.59.0 + '@typespec/http': ~0.59.0 + dependencies: + '@typespec/compiler': 0.59.0 + '@typespec/http': 0.59.0(@typespec/compiler@0.59.0) + dev: true + + /@typespec/versioning@0.59.0(@typespec/compiler@0.59.0): + resolution: {integrity: sha512-aihO/ux0lLmsuYAdGVkiBflSudcZokYG42SELk1FtMFo609G3Pd7ep7hau6unBnMIceQZejB0ow5UGRupK4X5A==} + engines: {node: '>=18.0.0'} + peerDependencies: + '@typespec/compiler': ~0.59.0 + dependencies: + '@typespec/compiler': 0.59.0 + dev: true + /@ungap/promise-all-settled@1.1.2: resolution: {integrity: sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==} dev: true @@ -13827,6 +13976,17 @@ packages: indent-string: 4.0.0 dev: true + /ajv-draft-04@1.0.0(ajv@8.17.1): + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + dependencies: + ajv: 8.17.1 + dev: true + /ajv-formats@2.1.1(ajv@8.11.2): resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: @@ -13861,6 +14021,16 @@ packages: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 uri-js: 4.4.1 + dev: false + + /ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.0.1 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + dev: true /anser@1.4.10: resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} @@ -14878,6 +15048,10 @@ packages: tslib: 2.1.0 dev: true + /change-case@5.4.4: + resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} + dev: true + /character-entities-legacy@1.1.2: resolution: {integrity: sha512-9NB2VbXtXYWdXzqrvAHykE/f0QJxzaKIpZ5QzNZrrgQ7Iyxr2vnfS8fCBNVW9nUEZE0lo57nxKRqnzY/dKrwlA==} dev: true @@ -15195,6 +15369,11 @@ packages: engines: {node: '>=6'} dev: false + /code-error-fragment@0.0.230: + resolution: {integrity: sha512-cadkfKp6932H8UkhzE/gcUqhRMNf8jHzkAN7+5Myabswaghu4xABTgPHDCjW+dBAJxj/SpkTYokpzDqY4pCzQw==} + engines: {node: '>= 4'} + dev: true + /code-point-at@1.1.0: resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} engines: {node: '>=0.10.0'} @@ -17295,7 +17474,7 @@ packages: eslint: 8.57.0 esquery: 1.5.0 is-builtin-module: 3.2.1 - semver: 7.6.0 + semver: 7.6.3 spdx-expression-parse: 3.0.1 dev: true @@ -17435,7 +17614,7 @@ packages: peerDependencies: eslint: '>=8.44.0' dependencies: - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-validator-identifier': 7.24.7 '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) ci-info: 3.9.0 clean-regexp: 1.0.0 @@ -17449,7 +17628,7 @@ packages: read-pkg-up: 7.0.1 regexp-tree: 0.1.27 regjsparser: 0.10.0 - semver: 7.6.0 + semver: 7.6.3 strip-indent: 3.0.0 dev: true @@ -17554,7 +17733,7 @@ packages: optionator: 0.9.3 progress: 2.0.3 regexpp: 3.2.0 - semver: 7.6.0 + semver: 7.6.3 strip-ansi: 6.0.1 strip-json-comments: 3.1.1 text-table: 0.2.0 @@ -17924,6 +18103,10 @@ packages: resolution: {integrity: sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==} dev: true + /fast-uri@3.0.1: + resolution: {integrity: sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==} + dev: true + /fast-url-parser@1.1.3: resolution: {integrity: sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==} dependencies: @@ -18666,6 +18849,18 @@ packages: merge2: 1.4.1 slash: 4.0.0 + /globby@14.0.2: + resolution: {integrity: sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==} + engines: {node: '>=18'} + dependencies: + '@sindresorhus/merge-streams': 2.3.0 + fast-glob: 3.3.2 + ignore: 5.3.1 + path-type: 5.0.0 + slash: 5.1.0 + unicorn-magic: 0.1.0 + dev: true + /globby@7.1.1: resolution: {integrity: sha512-yANWAN2DUcBtuus5Cpd+SKROzXHs2iVXFZt/Ykrfz6SAXqacLX25NZpltE+39ceMexYF4TtEadjuSTw8+3wX4g==} engines: {node: '>=4'} @@ -18808,6 +19003,10 @@ packages: /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + /grapheme-splitter@1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + dev: true + /graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} @@ -18900,7 +19099,7 @@ packages: dependencies: graphql: 15.4.0 nullthrows: 1.1.1 - vscode-languageserver-types: 3.17.2 + vscode-languageserver-types: 3.17.5 dev: false /graphql-request@5.0.0(graphql@15.4.0): @@ -20207,7 +20406,7 @@ packages: resolution: {integrity: sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.24.7 '@jest/types': 27.5.1 '@types/stack-utils': 2.0.3 chalk: 4.1.2 @@ -20542,6 +20741,14 @@ packages: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} dev: true + /json-to-ast@2.1.0: + resolution: {integrity: sha512-W9Lq347r8tA1DfMvAGn9QNcgYm4Wm7Yc+k8e6vezpMnRT+NHbtlxgNBXRVjXe9YM6eTn6+p/MKOlV/aABJcSnQ==} + engines: {node: '>= 4'} + dependencies: + code-error-fragment: 0.0.230 + grapheme-splitter: 1.0.4 + dev: true + /json-to-pretty-yaml@1.2.2: resolution: {integrity: sha512-rvm6hunfCcqegwYaG5T4yKJWxc9FXFgBVrcTZ4XfSVRwa5HA/Xs+vB/Eo9treYYHCeNM0nrSUr82V/M31Urc7A==} engines: {node: '>= 0.2.0'} @@ -20581,6 +20788,11 @@ packages: resolution: {integrity: sha512-trvBk1ki43VZptdBI5rIlG4YOzyeH/WefQt5rj1grasPn4iiZWKet8nkgc4GlsAylaztn0qZfUYOiTsASJFdNA==} dev: true + /jsonpointer@5.0.1: + resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} + engines: {node: '>=0.10.0'} + dev: true + /jsonwebtoken@8.5.1: resolution: {integrity: sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==} engines: {node: '>=4', npm: '>=1.4.28'} @@ -22252,6 +22464,11 @@ packages: - encoding dev: true + /mustache@4.2.0: + resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} + hasBin: true + dev: true + /mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} dev: true @@ -22345,7 +22562,7 @@ packages: engines: {node: '>=10'} requiresBuild: true dependencies: - semver: 7.6.0 + semver: 7.6.3 dev: true /node-abort-controller@3.1.1: @@ -22462,7 +22679,7 @@ packages: dependencies: hosted-git-info: 3.0.8 resolve: 1.22.8 - semver: 7.6.0 + semver: 7.6.3 validate-npm-package-license: 3.0.4 dev: true @@ -22711,6 +22928,10 @@ packages: is-wsl: 2.2.0 dev: true + /openapi-types@12.1.3: + resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} + dev: true + /opentelemetry-instrumentation-fetch-node@1.2.0: resolution: {integrity: sha512-aiSt/4ubOTyb1N5C2ZbGrBvaJOXIZhZvpRPYuUVxQJe27wJZqf/o65iPrqgLcgfeOLaQ8cS2Q+762jrYvniTrA==} engines: {node: '>18.0.0'} @@ -23184,6 +23405,11 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + /path-type@5.0.0: + resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==} + engines: {node: '>=12'} + dev: true + /path@0.12.7: resolution: {integrity: sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==} dependencies: @@ -23257,6 +23483,9 @@ packages: /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + /picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} @@ -23670,8 +23899,8 @@ packages: hasBin: true dev: true - /prettier@3.2.5: - resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + /prettier@3.3.3: + resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} engines: {node: '>=14'} hasBin: true dev: true @@ -25349,6 +25578,11 @@ packages: dependencies: lru-cache: 6.0.0 + /semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + /send@0.18.0: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} @@ -25554,7 +25788,7 @@ packages: resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} engines: {node: '>=10'} dependencies: - semver: 7.6.0 + semver: 7.6.3 dev: true /sinon@10.0.0: @@ -25619,6 +25853,11 @@ packages: resolution: {integrity: sha512-n6KkmvKS0623igEVj3FF0OZs1gYYJ0o0Hj939yc1fyxl2xt+xYpLnzJB6xBSqOfV9ZFLEWodBBN/heZJahuIJQ==} engines: {node: '>=14.16'} + /slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + dev: true + /slice-ansi@2.1.0: resolution: {integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==} engines: {node: '>=6'} @@ -26363,7 +26602,7 @@ packages: mime: 2.6.0 qs: 6.12.0 readable-stream: 3.6.2 - semver: 7.6.0 + semver: 7.6.3 dev: true /supports-color@2.0.0: @@ -26570,7 +26809,7 @@ packages: resolution: {integrity: sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==} engines: {node: '>=10.0.0'} dependencies: - ajv: 8.11.2 + ajv: 8.17.1 lodash.truncate: 4.4.2 slice-ansi: 4.0.0 string-width: 4.2.3 @@ -26635,6 +26874,16 @@ packages: dependencies: rimraf: 2.6.3 + /temporal-polyfill@0.2.5: + resolution: {integrity: sha512-ye47xp8Cb0nDguAhrrDS1JT1SzwEV9e26sSsrWzVu+yPZ7LzceEcH0i2gci9jWfOfSCCgM3Qv5nOYShVUUFUXA==} + dependencies: + temporal-spec: 0.2.4 + dev: true + + /temporal-spec@0.2.4: + resolution: {integrity: sha512-lDMFv4nKQrSjlkHKAlHVqKrBG4DyFfa9F74cmBZ3Iy3ed8yvWnlWSIdi4IKfSqwmazAohBNwiN64qGx4y5Q3IQ==} + dev: true + /tempy@1.0.1: resolution: {integrity: sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==} engines: {node: '>=10'} @@ -27289,6 +27538,11 @@ packages: resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} engines: {node: '>=4'} + /unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} + dev: true + /unimport@3.7.1: resolution: {integrity: sha512-V9HpXYfsZye5bPPYUgs0Otn3ODS1mDUciaBlXljI4C2fTwfFpvFZRywmlOu943puN9sncxROMZhsZCjNXEpzEQ==} dependencies: @@ -27492,7 +27746,7 @@ packages: dependencies: browserslist: 4.23.0 escalade: 3.1.1 - picocolors: 1.0.0 + picocolors: 1.0.1 /upper-case-first@2.0.2: resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} @@ -27756,7 +28010,7 @@ packages: cac: 6.7.14 debug: 4.3.4 pathe: 1.1.2 - picocolors: 1.0.0 + picocolors: 1.0.1 vite: 5.1.5(@types/node@20.8.0)(sass@1.32.4) transitivePeerDependencies: - '@types/node' @@ -28125,6 +28379,22 @@ packages: yazl: 2.5.1 dev: true + /vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + dev: true + + /vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + dev: true + + /vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + dev: true + /vscode-languageserver-textdocument@1.0.2: resolution: {integrity: sha512-T7uPC18+f8mYE4lbVZwb3OSmvwTZm3cuFhrdx9Bn2l11lmp3SvSuSVjy2JtvrghzjAo4G6Trqny2m9XGnFnWVA==} dev: false @@ -28133,6 +28403,16 @@ packages: resolution: {integrity: sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA==} dev: false + /vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + /vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + dependencies: + vscode-languageserver-protocol: 3.17.5 + dev: true + /vscode-uri@3.0.7: resolution: {integrity: sha512-eOpPHogvorZRobNqJGhapa0JdwaxpjVvyBp0QIUMRMSf8ZAlqOdEquKuRmw9Qwu0qXtJIWqFtMkmvJjUZmMjVA==} dev: false @@ -28682,6 +28962,11 @@ packages: engines: {node: '>= 14'} hasBin: true + /yaml@2.4.5: + resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==} + engines: {node: '>= 14'} + hasBin: true + /yargs-parser@13.1.2: resolution: {integrity: sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==} dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4017ef4fec1..e0487b0f3aa 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,3 +4,4 @@ packages: - '!client/cody-context-filters-test-dataset' - 'schema' - 'internal/appliance/frontend/maintenance' + - 'internal/openapi'