initial commit

This commit is contained in:
Семен Каменецкий
2026-09-15 15:31:54 +03:00
parent 702f108aff
commit 09dd1f7217
65 changed files with 4640 additions and 0 deletions
+2
View File
@@ -8,6 +8,8 @@
*.dll
*.so
*.dylib
bin/*
!bin/.gitkeep
# Test binary, built with `go test -c`
*.test
+10
View File
@@ -0,0 +1,10 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Ignored default folder with query files
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="Go" enabled="true" />
</module>
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GoImports">
<option name="excludedPackages">
<array>
<option value="golang.org/x/net/context" />
</array>
</option>
</component>
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/backbone.iml" filepath="$PROJECT_DIR$/.idea/backbone.iml" />
</modules>
</component>
</project>
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProtobufLanguageSettings">
<option name="importPathEntries">
<list>
<ImportPathEntry>
<option name="location" value="file://$PROJECT_DIR$/pkg/3rdparty" />
</ImportPathEntry>
</list>
</option>
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+32
View File
@@ -0,0 +1,32 @@
FROM node:24-alpine AS frontend_dependencies
RUN mkdir -p /app
WORKDIR /app
ADD static/app/package.json .
ADD static/app/yarn.lock .
RUN yarn install --frozen-lockfile
FROM frontend_dependencies AS frontend_build
ADD static/app .
RUN yarn build
FROM golang:1.26-alpine AS backend_dependencies
RUN apk add git make
RUN mkdir -p /app
WORKDIR /app
ADD go.mod .
ADD go.sum .
RUN go mod download
FROM backend_dependencies AS backend_build
ADD . .
RUN rm -rf static/app/dist
COPY --from=frontend_build /app/dist /app/static/app/dist
RUN make build
FROM alpine:latest AS final
FROM final
EXPOSE 8000
EXPOSE 9000
COPY --from=backend_build /app/bin/app /app
CMD ["/app"]
+41
View File
@@ -0,0 +1,41 @@
ROOT := $(shell pwd)
LOCAL_BIN := $(ROOT)/bin
VERSION := $(shell git show-ref --tags -d || git rev-parse --short HEAD)
.PHONY: build
build:
echo "$(VERSION)" > static/app/dist/version.txt
go build \
-ldflags "-X backbone/internal/pkg/version.Version=$(VERSION)" \
-o $(LOCAL_BIN)/app \
internal/app/cmd/main.go
.PHONY: deps
proto-deps:
GOBIN=$(LOCAL_BIN) go install google.golang.org/protobuf/cmd/protoc-gen-go
GOBIN=$(LOCAL_BIN) go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
GOBIN=$(LOCAL_BIN) go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2
GOBIN=$(LOCAL_BIN) go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway
.PHONY: proto
proto:
@PATH=$(PATH):$(LOCAL_BIN) protoc \
-I . \
-I pkg/3rdparty \
--go_out=pkg/pb \
--go_opt=Mgoogle/api/http.proto=google.golang.org/genproto/googleapis/api/annotations \
--go-grpc_opt=Mgoogle/api/http.proto=google.golang.org/genproto/googleapis/api/annotations \
--go_opt=Mgoogle/api/annotations.proto=google.golang.org/genproto/googleapis/api/annotations \
--go-grpc_opt=Mgoogle/api/annotations.proto=google.golang.org/genproto/googleapis/api/annotations \
--go_opt=paths=source_relative \
--go-grpc_out=pkg/pb \
--go-grpc_opt=paths=source_relative \
--grpc-gateway_out=pkg/pb \
--grpc-gateway_opt=Mgoogle/api/http.proto=google.golang.org/genproto/googleapis/api/annotations \
--grpc-gateway_opt=Mgoogle/api/annotations.proto=google.golang.org/genproto/googleapis/api/annotations \
--grpc-gateway_opt=paths=source_relative \
--openapiv2_opt=Mgoogle/api/http.proto=google.golang.org/genproto/googleapis/api/annotations \
--openapiv2_opt=Mgoogle/api/annotations.proto=google.golang.org/genproto/googleapis/api/annotations \
--openapiv2_out=logtostderr=true,allow_merge=true,merge_file_name=api:./api \
api/messages/*.proto \
api/services/*.proto
+80
View File
@@ -0,0 +1,80 @@
{
"swagger": "2.0",
"info": {
"title": "Application",
"version": "%version%"
},
"tags": [
{
"name": "DebugAPI"
}
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/api/v1/version": {
"get": {
"operationId": "DebugAPI_GetVersion",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/servicesGetVersionResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"tags": [
"DebugAPI"
]
}
}
},
"definitions": {
"protobufAny": {
"type": "object",
"properties": {
"@type": {
"type": "string"
}
},
"additionalProperties": {}
},
"rpcStatus": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"details": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/protobufAny"
}
}
}
},
"servicesGetVersionResponse": {
"type": "object",
"properties": {
"version": {
"type": "string"
}
}
}
}
}
View File
+6
View File
@@ -0,0 +1,6 @@
syntax = "proto3";
package api.messages;
option go_package = "pkg/pb/api/messages";
message Message{}
+8
View File
@@ -0,0 +1,8 @@
package api
import (
_ "embed"
)
//go:embed api.swagger.json
var OpenAPI []byte
+16
View File
@@ -0,0 +1,16 @@
syntax = "proto3";
package api.services;
option go_package = "pkg/pb/api/services";
import "protoc-gen-openapiv2/options/annotations.proto";
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
info: {
title: "Application"
version: "%version%"
}
security_definitions: {
}
};
+21
View File
@@ -0,0 +1,21 @@
syntax = "proto3";
package api.services;
option go_package = "pkg/pb/api/services";
import "google/api/annotations.proto";
service DebugAPI {
rpc GetVersion (GetVersion.Request) returns (GetVersion.Response) {
option (google.api.http) = {
get: "/api/v1/version"
};
};
}
message GetVersion {
message Request {}
message Response {
string version = 1;
}
}
View File
+41
View File
@@ -0,0 +1,41 @@
module backbone
go 1.26.5
tool (
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2
google.golang.org/grpc/cmd/protoc-gen-go-grpc
google.golang.org/protobuf/cmd/protoc-gen-go
)
//replace git.kamenetskii.ru/core/backbone/pkg/pb => ./pkg/pb
require (
github.com/go-chi/chi/v5 v5.3.2
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0
github.com/jackc/pgx/v5 v5.11.0
github.com/jmoiron/sqlx v1.4.0
go.mongodb.org/mongo-driver/v2 v2.9.1
google.golang.org/grpc v1.83.0
google.golang.org/protobuf v1.36.12
)
require (
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/klauspost/compress v1.19.2 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.2.0 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.yaml.in/yaml/v3 v3.0.5 // indirect
golang.org/x/crypto v0.54.0 // indirect
golang.org/x/net v0.57.0 // indirect
golang.org/x/sync v0.23.0 // indirect
golang.org/x/sys v0.47.0 // indirect
golang.org/x/text v0.42.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d // indirect
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.2 // indirect
)
+120
View File
@@ -0,0 +1,120 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-chi/chi/v5 v5.3.2 h1:5YQkICvTCSZ25hoRsyJazN0scjzKGiu4VAUc7H1o1nY=
github.com/go-chi/chi/v5 v5.3.2/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 h1:/Tnpcb2E0Pz/tN9s3bfEY2Q8ePCEX9iuS+cneUwncnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0/go.mod h1:zOBXOsUaBSjKgmH4OGzV1esUpR3oUSCPYVd2cUBjKYY=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.11.0 h1:IzBBtyK9AHqf98cctWFifYSci2hgQR/cd56wB4p+ogg=
github.com/jackc/pgx/v5 v5.11.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8=
github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs=
github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.mongodb.org/mongo-driver/v2 v2.9.1 h1:jewiFs2m1/VOQp8qhFshX6hWZ+EAXDhZHXExAUMcOgQ=
go.mongodb.org/mongo-driver/v2 v2.9.1/go.mod h1:SHKN0IWkKmEVGHLjXnni6s4wPKX4v86FTgOeJJFuXcA=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.45.0 h1:pdrWmLHofpubmArBv1LgFSv1Z0Ie/ppdZzu+kUN5EeU=
go.opentelemetry.io/otel v1.45.0/go.mod h1:XZxIqPapzEYnhNSScF5DIqXhm/rYi0FzCe2XddAwZfQ=
go.opentelemetry.io/otel/metric v1.45.0 h1:7Eg1uH7CJ5cXv9is6tnBe1FI6rj1nwUdbFypRm3br/M=
go.opentelemetry.io/otel/metric v1.45.0/go.mod h1:HAPbm1nd3p1PmFH7v2dR+6BjXxw+Lq4a2+pndMAm08s=
go.opentelemetry.io/otel/sdk v1.45.0 h1:4VVSMgQ83dUgW2aoX5f6JgLvHwIvzcuLnF9lUdCSpCw=
go.opentelemetry.io/otel/sdk v1.45.0/go.mod h1:Sr40LgXV7DsKMMJMKOhUWOgMWTfAaqvm2kF0g7ilwuA=
go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
go.opentelemetry.io/otel/trace v1.45.0 h1:l/mP6Uv7oNO7/TblbhpbgMidxhq1uO/rPsikOyVhxag=
go.opentelemetry.io/otel/trace v1.45.0/go.mod h1:qoJJA2xNMnxRrdISU/kLtfUH2wNeQbiv+jhs/CxI8bc=
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw=
golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE=
golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk=
golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI=
golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d h1:FarXi840EJWSHYTN3ERkADbPWjl307+FGrA22KAVjjc=
google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d/go.mod h1:K/+WGbmBY7aNW1HDw1fJnKYo10i0DkAX6pows00dLig=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d h1:IL4hdHzcUv2l/gcg98/Rj3FbtE6axwqslOW8SW0C+S0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.83.0 h1:JeNZEKJFbQxArAMl+hiytHauacDNqJUllNfmIMmpqnQ=
google.golang.org/grpc v1.83.0/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.2 h1:rgSNvqscFZ1JgV/4wH5GOsZFSFkR2Eua9As3KIr2LlM=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.2/go.mod h1:iMEtFwDlAhjDU9L5mY6U1XLwlIId/G3h+QcBHDIvrJ8=
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+31
View File
@@ -0,0 +1,31 @@
package main
import (
"backbone/internal/app/handler/debugh"
"backbone/internal/pkg/app"
svc "backbone/pkg/pb/api/services"
"log"
"google.golang.org/grpc"
)
func main() {
a := app.New(
app.WithSwaggerUI(),
app.WithStatic(),
)
debugH := debugh.New()
a.RegisterServices(func(gs *grpc.Server) {
svc.RegisterDebugAPIServer(gs, debugH)
})
a.RegisterGateways(
svc.RegisterDebugAPIHandler,
)
if err := a.ListenAndServe(); err != nil {
log.Fatal(err)
}
}
@@ -0,0 +1,13 @@
package debugh
import (
"backbone/internal/pkg/version"
svc "backbone/pkg/pb/api/services"
"context"
)
func (h *Handler) GetVersion(_ context.Context, _ *svc.GetVersion_Request) (*svc.GetVersion_Response, error) {
return &svc.GetVersion_Response{
Version: version.Version,
}, nil
}
+11
View File
@@ -0,0 +1,11 @@
package debugh
import svc "backbone/pkg/pb/api/services"
func New() *Handler {
return new(Handler)
}
type Handler struct {
svc.UnimplementedDebugAPIServer
}
+79
View File
@@ -0,0 +1,79 @@
package app
import (
"context"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/jmoiron/sqlx"
"go.mongodb.org/mongo-driver/v2/mongo"
"google.golang.org/grpc"
"google.golang.org/protobuf/proto"
)
func New(options ...Option) *App {
a := &App{
ctx: context.Background(),
router: chi.NewRouter(),
grpcServer: grpc.NewServer(),
httpServer: new(http.Server),
}
for _, option := range options {
option(a)
}
return a
}
type App struct {
ctx context.Context
router *chi.Mux
grpcServer *grpc.Server
httpServer *http.Server
mux *runtime.ServeMux
postgres *sqlx.DB
mongo *mongo.Client
closers []closeFunc
serviceRegistry []registerServiceFunc
gatewayRegistry []registerGatewayFunc
config struct {
grpcAddr string
httpAddr string
postgresURI string
mongoURI string
withGrpc bool
withSwagger bool
withStatic bool
forwardResponse forwardResponseFunc
}
}
const (
defaultHttpAddr = ":8000"
defaultGrpcAddr = ":9000"
)
type forwardResponseFunc func(context.Context, http.ResponseWriter, proto.Message) error
type closeFunc func() error
type registerServiceFunc func(gs *grpc.Server)
type registerGatewayFunc func(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error
func (a *App) RegisterServices(fn registerServiceFunc) {
a.serviceRegistry = append(a.serviceRegistry, fn)
}
func (a *App) RegisterGateways(fns ...registerGatewayFunc) {
a.gatewayRegistry = append(a.gatewayRegistry, fns...)
}
func (a *App) GRPC() *grpc.Server {
return a.grpcServer
}
func (a *App) HTTP() *http.Server {
return a.httpServer
}
func (a *App) Router() *chi.Mux {
return a.router
}
+140
View File
@@ -0,0 +1,140 @@
package app
import (
"backbone/static"
"context"
"errors"
"fmt"
"net"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/protobuf/encoding/protojson"
)
func (a *App) ListenAndServe() error {
a.httpServer.Handler = a.router
a.httpServer.Addr = a.getHTTPAddr()
muxOptions := []runtime.ServeMuxOption{
runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{
MarshalOptions: protojson.MarshalOptions{
EmitUnpopulated: true,
EmitDefaultValues: true,
},
}),
}
if a.config.forwardResponse != nil {
muxOptions = append(muxOptions,
runtime.WithForwardResponseOption(a.config.forwardResponse))
}
a.mux = runtime.NewServeMux(muxOptions...)
a.router.Handle("/api/*", a.mux)
if a.config.withSwagger {
a.router.Handle("/api/openapi.json", openApiServer)
a.router.Handle("/swagger*", swaggerUIHandler)
}
if a.config.withStatic {
a.router.NotFound(static.Handler)
}
// register services
for _, s := range a.serviceRegistry {
s(a.grpcServer)
}
// register gateways
conn, err := grpc.NewClient(a.getGRPCAddr(),
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
return fmt.Errorf("failed to init local grpc client: %w", err)
}
for _, g := range a.gatewayRegistry {
if err = g(a.ctx, a.mux, conn); err != nil {
return fmt.Errorf("failed to init gateway: %w", err)
}
}
errChan := make(chan error)
go a.startGRPC(errChan)
go a.startHTTP(errChan)
go a.wait(errChan)
for {
select {
case err := <-errChan:
return err
case <-a.ctx.Done():
return a.ctx.Err()
}
}
}
func (a *App) startHTTP(errChan chan error) {
if err := a.httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
errChan <- fmt.Errorf("failed to start http server: %w", err)
}
}
func (a *App) startGRPC(errChan chan error) {
listener, err := net.Listen("tcp", a.getGRPCAddr())
if err != nil {
errChan <- fmt.Errorf("failed to start grpc server: %w", err)
}
if err = a.grpcServer.Serve(listener); err != nil {
errChan <- fmt.Errorf("failed to serve grpc: %w", err)
}
}
func (a *App) getHTTPAddr() string {
if a.config.httpAddr != "" {
return a.config.httpAddr
}
if v := os.Getenv("HTTP_ADDR"); v != "" {
return v
}
return defaultHttpAddr
}
func (a *App) getGRPCAddr() string {
if a.config.grpcAddr != "" {
return a.config.grpcAddr
}
if v := os.Getenv("GRPC_ADDR"); v != "" {
return v
}
return defaultGrpcAddr
}
func (a *App) wait(errChan chan error) {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigs
shutdownCtx, cancel := context.WithTimeout(a.ctx, 30*time.Second)
defer cancel()
if err := a.httpServer.Shutdown(shutdownCtx); err != nil {
errChan <- err
}
a.grpcServer.GracefulStop()
for _, closer := range a.closers {
if err := closer(); err != nil {
errChan <- err
}
}
errChan <- nil
}()
}
+19
View File
@@ -0,0 +1,19 @@
package app
import (
"log"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options"
)
func (a *App) initMongo() {
if a.config.mongoURI == "" {
return
}
client, err := mongo.Connect(options.Client().ApplyURI(a.config.mongoURI))
if err != nil {
log.Fatalln("failed to connect mongo:", err)
}
a.mongo = client
}
+33
View File
@@ -0,0 +1,33 @@
package app
import (
"backbone/api"
"backbone/internal/pkg/version"
"bytes"
"embed"
"net/http"
"time"
)
//go:embed swagger
var swaggerFS embed.FS
var swaggerUIHandler = func() http.Handler {
//sub,err := fs.Sub(swaggerFS, "swagger")
return http.FileServerFS(swaggerFS)
}()
var openApiServer = func() http.Handler {
content := bytes.ReplaceAll(api.OpenAPI, []byte("%version%"), []byte(version.Version))
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.ServeContent(w, r, "openapi.json", time.Now(), bytes.NewReader(content))
})
}()
//
//func (a *App) serveOpenAPIFile(w http.ResponseWriter, r *http.Request) {
//
// //w.Header().Set("Content-Type", "application/json")
// //w.WriteHeader(http.StatusOK)
// //_, _ = w.Write(api.OpenAPI)
//}
+45
View File
@@ -0,0 +1,45 @@
package app
type Option func(*App)
func WithHTTPAddr(addr string) Option {
return func(a *App) {
a.config.httpAddr = addr
}
}
func WithGRPCAddr(addr string) Option {
return func(a *App) {
a.config.grpcAddr = addr
}
}
func WithPostgresDatabase(uri string) Option {
return func(a *App) {
a.config.postgresURI = uri
}
}
func WithMongoDatabase(uri string) Option {
return func(a *App) {
a.config.mongoURI = uri
}
}
func WithSwaggerUI() Option {
return func(a *App) {
a.config.withSwagger = true
}
}
func WithStatic() Option {
return func(a *App) {
a.config.withStatic = true
}
}
func WithForwardResponse(fn forwardResponseFunc) Option {
return func(a *App) {
a.config.forwardResponse = fn
}
}
+20
View File
@@ -0,0 +1,20 @@
package app
import (
"log"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/jackc/pgx/v5/stdlib"
"github.com/jmoiron/sqlx"
)
func (a *App) initPostgres() {
if a.config.postgresURI == "" {
return
}
pool, err := pgxpool.New(a.ctx, a.config.postgresURI)
if err != nil {
log.Fatalln("failed to connect to postgres:", err)
}
a.postgres = sqlx.NewDb(stdlib.OpenDBFromPool(pool), "postgres")
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

+16
View File
@@ -0,0 +1,16 @@
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 0;
background: #fafafa;
}
+19
View File
@@ -0,0 +1,19 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="index.css" />
<link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16" />
</head>
<body>
<div id="swagger-ui"></div>
<script src="swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script src="swagger-initializer.js" charset="UTF-8"> </script>
</body>
</html>
@@ -0,0 +1,29 @@
window.onload = function () {
//<editor-fold desc="Changeable Configuration Block">
const HideInfoUrlPartsPlugin = () => {
return {
wrapComponents: {
InfoUrl: () => () => null
}
}
}
// the following lines will be replaced by docker/configurator, when it runs in a docker-container
window.ui = SwaggerUIBundle({
url: "/api/openapi.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl,
HideInfoUrlPartsPlugin,
],
layout: "StandaloneLayout"
});
//</editor-fold>
};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
package version
var Version string = "dev"
+30
View File
@@ -0,0 +1,30 @@
// Copyright (c) 2015, Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package google.api;
import "google/api/http.proto";
import "google/protobuf/descriptor.proto";
option java_multiple_files = true;
option java_outer_classname = "AnnotationsProto";
option java_package = "com.google.api";
option objc_class_prefix = "GAPI";
extend google.protobuf.MethodOptions {
// See `HttpRule`.
HttpRule http = 72295728;
}
+285
View File
@@ -0,0 +1,285 @@
// Copyright 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package google.api;
option cc_enable_arenas = true;
option java_multiple_files = true;
option java_outer_classname = "HttpProto";
option java_package = "com.google.api";
option objc_class_prefix = "GAPI";
// Defines the HTTP configuration for a service. It contains a list of
// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method
// to one or more HTTP REST API methods.
message Http {
// A list of HTTP configuration rules that apply to individual API methods.
//
// **NOTE:** All service configuration rules follow "last one wins" order.
repeated HttpRule rules = 1;
}
// `HttpRule` defines the mapping of an RPC method to one or more HTTP
// REST APIs. The mapping determines what portions of the request
// message are populated from the path, query parameters, or body of
// the HTTP request. The mapping is typically specified as an
// `google.api.http` annotation, see "google/api/annotations.proto"
// for details.
//
// The mapping consists of a field specifying the path template and
// method kind. The path template can refer to fields in the request
// message, as in the example below which describes a REST GET
// operation on a resource collection of messages:
//
// ```proto
// service Messaging {
// rpc GetMessage(GetMessageRequest) returns (Message) {
// option (google.api.http).get = "/v1/messages/{message_id}/{sub.subfield}";
// }
// }
// message GetMessageRequest {
// message SubMessage {
// string subfield = 1;
// }
// string message_id = 1; // mapped to the URL
// SubMessage sub = 2; // `sub.subfield` is url-mapped
// }
// message Message {
// string text = 1; // content of the resource
// }
// ```
//
// This definition enables an automatic, bidrectional mapping of HTTP
// JSON to RPC. Example:
//
// HTTP | RPC
// -----|-----
// `GET /v1/messages/123456/foo` | `GetMessage(message_id: "123456" sub: SubMessage(subfield: "foo"))`
//
// In general, not only fields but also field paths can be referenced
// from a path pattern. Fields mapped to the path pattern cannot be
// repeated and must have a primitive (non-message) type.
//
// Any fields in the request message which are not bound by the path
// pattern automatically become (optional) HTTP query
// parameters. Assume the following definition of the request message:
//
// ```proto
// message GetMessageRequest {
// message SubMessage {
// string subfield = 1;
// }
// string message_id = 1; // mapped to the URL
// int64 revision = 2; // becomes a parameter
// SubMessage sub = 3; // `sub.subfield` becomes a parameter
// }
// ```
//
// This enables a HTTP JSON to RPC mapping as below:
//
// HTTP | RPC
// -----|-----
// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: "foo"))`
//
// Note that fields which are mapped to HTTP parameters must have a
// primitive type or a repeated primitive type. Message types are not
// allowed. In the case of a repeated type, the parameter can be
// repeated in the URL, as in `...?param=A&param=B`.
//
// For HTTP method kinds which allow a request body, the `body` field
// specifies the mapping. Consider a REST update method on the
// message resource collection:
//
// ```proto
// service Messaging {
// rpc UpdateMessage(UpdateMessageRequest) returns (Message) {
// option (google.api.http) = {
// put: "/v1/messages/{message_id}"
// body: "message"
// };
// }
// }
// message UpdateMessageRequest {
// string message_id = 1; // mapped to the URL
// Message message = 2; // mapped to the body
// }
// ```
//
// The following HTTP JSON to RPC mapping is enabled, where the
// representation of the JSON in the request body is determined by
// protos JSON encoding:
//
// HTTP | RPC
// -----|-----
// `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" message { text: "Hi!" })`
//
// The special name `*` can be used in the body mapping to define that
// every field not bound by the path template should be mapped to the
// request body. This enables the following alternative definition of
// the update method:
//
// ```proto
// service Messaging {
// rpc UpdateMessage(Message) returns (Message) {
// option (google.api.http) = {
// put: "/v1/messages/{message_id}"
// body: "*"
// };
// }
// }
// message Message {
// string message_id = 1;
// string text = 2;
// }
// ```
//
// The following HTTP JSON to RPC mapping is enabled:
//
// HTTP | RPC
// -----|-----
// `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" text: "Hi!")`
//
// Note that when using `*` in the body mapping, it is not possible to
// have HTTP parameters, as all fields not bound by the path end in
// the body. This makes this option more rarely used in practice of
// defining REST APIs. The common usage of `*` is in custom methods
// which don't use the URL at all for transferring data.
//
// It is possible to define multiple HTTP methods for one RPC by using
// the `additional_bindings` option. Example:
//
// ```proto
// service Messaging {
// rpc GetMessage(GetMessageRequest) returns (Message) {
// option (google.api.http) = {
// get: "/v1/messages/{message_id}"
// additional_bindings {
// get: "/v1/users/{user_id}/messages/{message_id}"
// }
// };
// }
// }
// message GetMessageRequest {
// string message_id = 1;
// string user_id = 2;
// }
// ```
//
// This enables the following two alternative HTTP JSON to RPC
// mappings:
//
// HTTP | RPC
// -----|-----
// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")`
// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: "123456")`
//
// # Rules for HTTP mapping
//
// The rules for mapping HTTP path, query parameters, and body fields
// to the request message are as follows:
//
// 1. The `body` field specifies either `*` or a field path, or is
// omitted. If omitted, it assumes there is no HTTP body.
// 2. Leaf fields (recursive expansion of nested messages in the
// request) can be classified into three types:
// (a) Matched in the URL template.
// (b) Covered by body (if body is `*`, everything except (a) fields;
// else everything under the body field)
// (c) All other fields.
// 3. URL query parameters found in the HTTP request are mapped to (c) fields.
// 4. Any body sent with an HTTP request can contain only (b) fields.
//
// The syntax of the path template is as follows:
//
// Template = "/" Segments [ Verb ] ;
// Segments = Segment { "/" Segment } ;
// Segment = "*" | "**" | LITERAL | Variable ;
// Variable = "{" FieldPath [ "=" Segments ] "}" ;
// FieldPath = IDENT { "." IDENT } ;
// Verb = ":" LITERAL ;
//
// The syntax `*` matches a single path segment. It follows the semantics of
// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String
// Expansion.
//
// The syntax `**` matches zero or more path segments. It follows the semantics
// of [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.3 Reserved
// Expansion.
//
// The syntax `LITERAL` matches literal text in the URL path.
//
// The syntax `Variable` matches the entire path as specified by its template;
// this nested template must not contain further variables. If a variable
// matches a single path segment, its template may be omitted, e.g. `{var}`
// is equivalent to `{var=*}`.
//
// NOTE: the field paths in variables and in the `body` must not refer to
// repeated fields or map fields.
//
// Use CustomHttpPattern to specify any HTTP method that is not included in the
// `pattern` field, such as HEAD, or "*" to leave the HTTP method unspecified for
// a given URL path rule. The wild-card rule is useful for services that provide
// content to Web (HTML) clients.
message HttpRule {
// Selects methods to which this rule applies.
//
// Refer to [selector][google.api.DocumentationRule.selector] for syntax details.
string selector = 1;
// Determines the URL pattern is matched by this rules. This pattern can be
// used with any of the {get|put|post|delete|patch} methods. A custom method
// can be defined using the 'custom' field.
oneof pattern {
// Used for listing and getting information about resources.
string get = 2;
// Used for updating a resource.
string put = 3;
// Used for creating a resource.
string post = 4;
// Used for deleting a resource.
string delete = 5;
// Used for updating a resource.
string patch = 6;
// Custom pattern is used for defining custom verbs.
CustomHttpPattern custom = 8;
}
// The name of the request field whose value is mapped to the HTTP body, or
// `*` for mapping all fields not captured by the path pattern to the HTTP
// body. NOTE: the referred field must not be a repeated field and must be
// present at the top-level of response message type.
string body = 7;
// Additional HTTP bindings for the selector. Nested bindings must
// not contain an `additional_bindings` field themselves (that is,
// the nesting may only be one level deep).
repeated HttpRule additional_bindings = 11;
}
// A custom pattern is used for defining custom HTTP verb.
message CustomHttpPattern {
// The name of this custom HTTP verb.
string kind = 1;
// The path matched by this custom verb.
string path = 2;
}
@@ -0,0 +1,51 @@
syntax = "proto3";
package grpc.gateway.protoc_gen_openapiv2.options;
import "google/protobuf/descriptor.proto";
import "protoc-gen-openapiv2/options/openapiv2.proto";
option go_package = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options";
extend google.protobuf.FileOptions {
// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
//
// All IDs are the same, as assigned. It is okay that they are the same, as they extend
// different descriptor messages.
Swagger openapiv2_swagger = 1042;
}
extend google.protobuf.MethodOptions {
// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
//
// All IDs are the same, as assigned. It is okay that they are the same, as they extend
// different descriptor messages.
Operation openapiv2_operation = 1042;
}
extend google.protobuf.MessageOptions {
// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
//
// All IDs are the same, as assigned. It is okay that they are the same, as they extend
// different descriptor messages.
Schema openapiv2_schema = 1042;
}
extend google.protobuf.EnumOptions {
// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
//
// All IDs are the same, as assigned. It is okay that they are the same, as they extend
// different descriptor messages.
EnumSchema openapiv2_enum = 1042;
}
extend google.protobuf.ServiceOptions {
// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
//
// All IDs are the same, as assigned. It is okay that they are the same, as they extend
// different descriptor messages.
Tag openapiv2_tag = 1042;
}
extend google.protobuf.FieldOptions {
// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
//
// All IDs are the same, as assigned. It is okay that they are the same, as they extend
// different descriptor messages.
JSONSchema openapiv2_field = 1042;
}
@@ -0,0 +1,762 @@
syntax = "proto3";
package grpc.gateway.protoc_gen_openapiv2.options;
import "google/protobuf/struct.proto";
option go_package = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options";
// Scheme describes the schemes supported by the OpenAPI Swagger
// and Operation objects.
enum Scheme {
UNKNOWN = 0;
HTTP = 1;
HTTPS = 2;
WS = 3;
WSS = 4;
}
// `Swagger` is a representation of OpenAPI v2 specification's Swagger object.
//
// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject
//
// Example:
//
// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
// info: {
// title: "Echo API";
// version: "1.0";
// description: "";
// contact: {
// name: "gRPC-Gateway project";
// url: "https://github.com/grpc-ecosystem/grpc-gateway";
// email: "none@example.com";
// };
// license: {
// name: "BSD 3-Clause License";
// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE";
// };
// };
// schemes: HTTPS;
// consumes: "application/json";
// produces: "application/json";
// };
//
message Swagger {
// Specifies the OpenAPI Specification version being used. It can be
// used by the OpenAPI UI and other clients to interpret the API listing. The
// value MUST be "2.0".
string swagger = 1;
// Provides metadata about the API. The metadata can be used by the
// clients if needed.
Info info = 2;
// The host (name or ip) serving the API. This MUST be the host only and does
// not include the scheme nor sub-paths. It MAY include a port. If the host is
// not included, the host serving the documentation is to be used (including
// the port). The host does not support path templating.
string host = 3;
// The base path on which the API is served, which is relative to the host. If
// it is not included, the API is served directly under the host. The value
// MUST start with a leading slash (/). The basePath does not support path
// templating.
// Note that using `base_path` does not change the endpoint paths that are
// generated in the resulting OpenAPI file. If you wish to use `base_path`
// with relatively generated OpenAPI paths, the `base_path` prefix must be
// manually removed from your `google.api.http` paths and your code changed to
// serve the API from the `base_path`.
string base_path = 4;
// The transfer protocol of the API. Values MUST be from the list: "http",
// "https", "ws", "wss". If the schemes is not included, the default scheme to
// be used is the one used to access the OpenAPI definition itself.
repeated Scheme schemes = 5;
// A list of MIME types the APIs can consume. This is global to all APIs but
// can be overridden on specific API calls. Value MUST be as described under
// Mime Types.
repeated string consumes = 6;
// A list of MIME types the APIs can produce. This is global to all APIs but
// can be overridden on specific API calls. Value MUST be as described under
// Mime Types.
repeated string produces = 7;
// field 8 is reserved for 'paths'.
reserved 8;
// field 9 is reserved for 'definitions', which at this time are already
// exposed as and customizable as proto messages.
reserved 9;
// An object to hold responses that can be used across operations. This
// property does not define global responses for all operations.
map<string, Response> responses = 10;
// Security scheme definitions that can be used across the specification.
SecurityDefinitions security_definitions = 11;
// A declaration of which security schemes are applied for the API as a whole.
// The list of values describes alternative security schemes that can be used
// (that is, there is a logical OR between the security requirements).
// Individual operations can override this definition.
repeated SecurityRequirement security = 12;
// A list of tags for API documentation control. Tags can be used for logical
// grouping of operations by resources or any other qualifier.
repeated Tag tags = 13;
// Additional external documentation.
ExternalDocumentation external_docs = 14;
// Custom properties that start with "x-" such as "x-foo" used to describe
// extra functionality that is not covered by the standard OpenAPI Specification.
// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
map<string, google.protobuf.Value> extensions = 15;
}
// `Operation` is a representation of OpenAPI v2 specification's Operation object.
//
// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#operationObject
//
// Example:
//
// service EchoService {
// rpc Echo(SimpleMessage) returns (SimpleMessage) {
// option (google.api.http) = {
// get: "/v1/example/echo/{id}"
// };
//
// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
// summary: "Get a message.";
// operation_id: "getMessage";
// tags: "echo";
// responses: {
// key: "200"
// value: {
// description: "OK";
// }
// }
// };
// }
// }
message Operation {
// A list of tags for API documentation control. Tags can be used for logical
// grouping of operations by resources or any other qualifier.
repeated string tags = 1;
// A short summary of what the operation does. For maximum readability in the
// swagger-ui, this field SHOULD be less than 120 characters.
string summary = 2;
// A verbose explanation of the operation behavior. GFM syntax can be used for
// rich text representation.
string description = 3;
// Additional external documentation for this operation.
ExternalDocumentation external_docs = 4;
// Unique string used to identify the operation. The id MUST be unique among
// all operations described in the API. Tools and libraries MAY use the
// operationId to uniquely identify an operation, therefore, it is recommended
// to follow common programming naming conventions.
string operation_id = 5;
// A list of MIME types the operation can consume. This overrides the consumes
// definition at the OpenAPI Object. An empty value MAY be used to clear the
// global definition. Value MUST be as described under Mime Types.
repeated string consumes = 6;
// A list of MIME types the operation can produce. This overrides the produces
// definition at the OpenAPI Object. An empty value MAY be used to clear the
// global definition. Value MUST be as described under Mime Types.
repeated string produces = 7;
// field 8 is reserved for 'parameters'.
reserved 8;
// The list of possible responses as they are returned from executing this
// operation.
map<string, Response> responses = 9;
// The transfer protocol for the operation. Values MUST be from the list:
// "http", "https", "ws", "wss". The value overrides the OpenAPI Object
// schemes definition.
repeated Scheme schemes = 10;
// Declares this operation to be deprecated. Usage of the declared operation
// should be refrained. Default value is false.
bool deprecated = 11;
// A declaration of which security schemes are applied for this operation. The
// list of values describes alternative security schemes that can be used
// (that is, there is a logical OR between the security requirements). This
// definition overrides any declared top-level security. To remove a top-level
// security declaration, an empty array can be used.
repeated SecurityRequirement security = 12;
// Custom properties that start with "x-" such as "x-foo" used to describe
// extra functionality that is not covered by the standard OpenAPI Specification.
// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
map<string, google.protobuf.Value> extensions = 13;
// Custom parameters such as HTTP request headers.
// See: https://swagger.io/docs/specification/2-0/describing-parameters/
// and https://swagger.io/specification/v2/#parameter-object.
Parameters parameters = 14;
}
// `Parameters` is a representation of OpenAPI v2 specification's parameters object.
// Note: This technically breaks compatibility with the OpenAPI 2 definition structure as we only
// allow header parameters to be set here since we do not want users specifying custom non-header
// parameters beyond those inferred from the Protobuf schema.
// See: https://swagger.io/specification/v2/#parameter-object
message Parameters {
// `Headers` is one or more HTTP header parameter.
// See: https://swagger.io/docs/specification/2-0/describing-parameters/#header-parameters
repeated HeaderParameter headers = 1;
}
// `HeaderParameter` a HTTP header parameter.
// See: https://swagger.io/specification/v2/#parameter-object
message HeaderParameter {
// `Type` is a supported HTTP header type.
// See https://swagger.io/specification/v2/#parameterType.
enum Type {
UNKNOWN = 0;
STRING = 1;
NUMBER = 2;
INTEGER = 3;
BOOLEAN = 4;
}
// `Name` is the header name.
string name = 1;
// `Description` is a short description of the header.
string description = 2;
// `Type` is the type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported.
// See: https://swagger.io/specification/v2/#parameterType.
Type type = 3;
// `Format` The extending format for the previously mentioned type.
string format = 4;
// `Required` indicates if the header is optional
bool required = 5;
// field 6 is reserved for 'items', but in OpenAPI-specific way.
reserved 6;
// field 7 is reserved `Collection Format`. Determines the format of the array if type array is used.
reserved 7;
}
// `Header` is a representation of OpenAPI v2 specification's Header object.
//
// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#headerObject
//
message Header {
// `Description` is a short description of the header.
string description = 1;
// The type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported.
string type = 2;
// `Format` The extending format for the previously mentioned type.
string format = 3;
// field 4 is reserved for 'items', but in OpenAPI-specific way.
reserved 4;
// field 5 is reserved `Collection Format` Determines the format of the array if type array is used.
reserved 5;
// `Default` Declares the value of the header that the server will use if none is provided.
// See: https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2.
// Unlike JSON Schema this value MUST conform to the defined type for the header.
string default = 6;
// field 7 is reserved for 'maximum'.
reserved 7;
// field 8 is reserved for 'exclusiveMaximum'.
reserved 8;
// field 9 is reserved for 'minimum'.
reserved 9;
// field 10 is reserved for 'exclusiveMinimum'.
reserved 10;
// field 11 is reserved for 'maxLength'.
reserved 11;
// field 12 is reserved for 'minLength'.
reserved 12;
// 'Pattern' See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3.
string pattern = 13;
// field 14 is reserved for 'maxItems'.
reserved 14;
// field 15 is reserved for 'minItems'.
reserved 15;
// field 16 is reserved for 'uniqueItems'.
reserved 16;
// field 17 is reserved for 'enum'.
reserved 17;
// field 18 is reserved for 'multipleOf'.
reserved 18;
}
// `Response` is a representation of OpenAPI v2 specification's Response object.
//
// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responseObject
//
message Response {
// `Description` is a short description of the response.
// GFM syntax can be used for rich text representation.
string description = 1;
// `Schema` optionally defines the structure of the response.
// If `Schema` is not provided, it means there is no content to the response.
Schema schema = 2;
// `Headers` A list of headers that are sent with the response.
// `Header` name is expected to be a string in the canonical format of the MIME header key
// See: https://golang.org/pkg/net/textproto/#CanonicalMIMEHeaderKey
map<string, Header> headers = 3;
// `Examples` gives per-mimetype response examples.
// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object
map<string, string> examples = 4;
// Custom properties that start with "x-" such as "x-foo" used to describe
// extra functionality that is not covered by the standard OpenAPI Specification.
// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
map<string, google.protobuf.Value> extensions = 5;
}
// `Info` is a representation of OpenAPI v2 specification's Info object.
//
// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#infoObject
//
// Example:
//
// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
// info: {
// title: "Echo API";
// version: "1.0";
// description: "";
// contact: {
// name: "gRPC-Gateway project";
// url: "https://github.com/grpc-ecosystem/grpc-gateway";
// email: "none@example.com";
// };
// license: {
// name: "BSD 3-Clause License";
// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE";
// };
// };
// ...
// };
//
message Info {
// The title of the application.
string title = 1;
// A short description of the application. GFM syntax can be used for rich
// text representation.
string description = 2;
// The Terms of Service for the API.
string terms_of_service = 3;
// The contact information for the exposed API.
Contact contact = 4;
// The license information for the exposed API.
License license = 5;
// Provides the version of the application API (not to be confused
// with the specification version).
string version = 6;
// Custom properties that start with "x-" such as "x-foo" used to describe
// extra functionality that is not covered by the standard OpenAPI Specification.
// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
map<string, google.protobuf.Value> extensions = 7;
}
// `Contact` is a representation of OpenAPI v2 specification's Contact object.
//
// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#contactObject
//
// Example:
//
// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
// info: {
// ...
// contact: {
// name: "gRPC-Gateway project";
// url: "https://github.com/grpc-ecosystem/grpc-gateway";
// email: "none@example.com";
// };
// ...
// };
// ...
// };
//
message Contact {
// The identifying name of the contact person/organization.
string name = 1;
// The URL pointing to the contact information. MUST be in the format of a
// URL.
string url = 2;
// The email address of the contact person/organization. MUST be in the format
// of an email address.
string email = 3;
}
// `License` is a representation of OpenAPI v2 specification's License object.
//
// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#licenseObject
//
// Example:
//
// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
// info: {
// ...
// license: {
// name: "BSD 3-Clause License";
// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE";
// };
// ...
// };
// ...
// };
//
message License {
// The license name used for the API.
string name = 1;
// A URL to the license used for the API. MUST be in the format of a URL.
string url = 2;
}
// `ExternalDocumentation` is a representation of OpenAPI v2 specification's
// ExternalDocumentation object.
//
// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#externalDocumentationObject
//
// Example:
//
// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
// ...
// external_docs: {
// description: "More about gRPC-Gateway";
// url: "https://github.com/grpc-ecosystem/grpc-gateway";
// }
// ...
// };
//
message ExternalDocumentation {
// A short description of the target documentation. GFM syntax can be used for
// rich text representation.
string description = 1;
// The URL for the target documentation. Value MUST be in the format
// of a URL.
string url = 2;
}
// `Schema` is a representation of OpenAPI v2 specification's Schema object.
//
// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
//
message Schema {
JSONSchema json_schema = 1;
// Adds support for polymorphism. The discriminator is the schema property
// name that is used to differentiate between other schema that inherit this
// schema. The property name used MUST be defined at this schema and it MUST
// be in the required property list. When used, the value MUST be the name of
// this schema or any schema that inherits it.
string discriminator = 2;
// Relevant only for Schema "properties" definitions. Declares the property as
// "read only". This means that it MAY be sent as part of a response but MUST
// NOT be sent as part of the request. Properties marked as readOnly being
// true SHOULD NOT be in the required list of the defined schema. Default
// value is false.
bool read_only = 3;
// field 4 is reserved for 'xml'.
reserved 4;
// Additional external documentation for this schema.
ExternalDocumentation external_docs = 5;
// A free-form property to include an example of an instance for this schema in JSON.
// This is copied verbatim to the output.
string example = 6;
}
// `EnumSchema` is subset of fields from the OpenAPI v2 specification's Schema object.
// Only fields that are applicable to Enums are included
// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
//
// Example:
//
// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_enum) = {
// ...
// title: "MyEnum";
// description:"This is my nice enum";
// example: "ZERO";
// required: true;
// ...
// };
//
message EnumSchema {
// A short description of the schema.
string description = 1;
string default = 2;
// The title of the schema.
string title = 3;
bool required = 4;
bool read_only = 5;
// Additional external documentation for this schema.
ExternalDocumentation external_docs = 6;
string example = 7;
// Ref is used to define an external reference to include in the message.
// This could be a fully qualified proto message reference, and that type must
// be imported into the protofile. If no message is identified, the Ref will
// be used verbatim in the output.
// For example:
// `ref: ".google.protobuf.Timestamp"`.
string ref = 8;
// Custom properties that start with "x-" such as "x-foo" used to describe
// extra functionality that is not covered by the standard OpenAPI Specification.
// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
map<string, google.protobuf.Value> extensions = 9;
}
// `JSONSchema` represents properties from JSON Schema taken, and as used, in
// the OpenAPI v2 spec.
//
// This includes changes made by OpenAPI v2.
//
// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
//
// See also: https://cswr.github.io/JsonSchema/spec/basic_types/,
// https://github.com/json-schema-org/json-schema-spec/blob/master/schema.json
//
// Example:
//
// message SimpleMessage {
// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
// json_schema: {
// title: "SimpleMessage"
// description: "A simple message."
// required: ["id"]
// }
// };
//
// // Id represents the message identifier.
// string id = 1; [
// (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
// description: "The unique identifier of the simple message."
// }];
// }
//
message JSONSchema {
// field 1 is reserved for '$id', omitted from OpenAPI v2.
reserved 1;
// field 2 is reserved for '$schema', omitted from OpenAPI v2.
reserved 2;
// Ref is used to define an external reference to include in the message.
// This could be a fully qualified proto message reference, and that type must
// be imported into the protofile. If no message is identified, the Ref will
// be used verbatim in the output.
// For example:
// `ref: ".google.protobuf.Timestamp"`.
string ref = 3;
// field 4 is reserved for '$comment', omitted from OpenAPI v2.
reserved 4;
// The title of the schema.
string title = 5;
// A short description of the schema.
string description = 6;
string default = 7;
bool read_only = 8;
// A free-form property to include a JSON example of this field. This is copied
// verbatim to the output swagger.json. Quotes must be escaped.
// This property is the same for 2.0 and 3.0.0 https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/3.0.0.md#schemaObject https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
string example = 9;
double multiple_of = 10;
// Maximum represents an inclusive upper limit for a numeric instance. The
// value of MUST be a number,
double maximum = 11;
bool exclusive_maximum = 12;
// minimum represents an inclusive lower limit for a numeric instance. The
// value of MUST be a number,
double minimum = 13;
bool exclusive_minimum = 14;
uint64 max_length = 15;
uint64 min_length = 16;
string pattern = 17;
// field 18 is reserved for 'additionalItems', omitted from OpenAPI v2.
reserved 18;
// field 19 is reserved for 'items', but in OpenAPI-specific way.
// TODO(ivucica): add 'items'?
reserved 19;
uint64 max_items = 20;
uint64 min_items = 21;
bool unique_items = 22;
// field 23 is reserved for 'contains', omitted from OpenAPI v2.
reserved 23;
uint64 max_properties = 24;
uint64 min_properties = 25;
repeated string required = 26;
// field 27 is reserved for 'additionalProperties', but in OpenAPI-specific
// way. TODO(ivucica): add 'additionalProperties'?
reserved 27;
// field 28 is reserved for 'definitions', omitted from OpenAPI v2.
reserved 28;
// field 29 is reserved for 'properties', but in OpenAPI-specific way.
// TODO(ivucica): add 'additionalProperties'?
reserved 29;
// following fields are reserved, as the properties have been omitted from
// OpenAPI v2:
// patternProperties, dependencies, propertyNames, const
reserved 30 to 33;
// Items in 'array' must be unique.
repeated string array = 34;
enum JSONSchemaSimpleTypes {
UNKNOWN = 0;
ARRAY = 1;
BOOLEAN = 2;
INTEGER = 3;
NULL = 4;
NUMBER = 5;
OBJECT = 6;
STRING = 7;
}
repeated JSONSchemaSimpleTypes type = 35;
// `Format`
string format = 36;
// following fields are reserved, as the properties have been omitted from
// OpenAPI v2: contentMediaType, contentEncoding, if, then, else
reserved 37 to 41;
// field 42 is reserved for 'allOf', but in OpenAPI-specific way.
// TODO(ivucica): add 'allOf'?
reserved 42;
// following fields are reserved, as the properties have been omitted from
// OpenAPI v2:
// anyOf, oneOf, not
reserved 43 to 45;
// Items in `enum` must be unique https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1
repeated string enum = 46;
// Additional field level properties used when generating the OpenAPI v2 file.
FieldConfiguration field_configuration = 1001;
// 'FieldConfiguration' provides additional field level properties used when generating the OpenAPI v2 file.
// These properties are not defined by OpenAPIv2, but they are used to control the generation.
message FieldConfiguration {
// Alternative parameter name when used as path parameter. If set, this will
// be used as the complete parameter name when this field is used as a path
// parameter. Use this to avoid having auto generated path parameter names
// for overlapping paths.
string path_param_name = 47;
// Declares this field to be deprecated. Allows for the generated OpenAPI
// parameter to be marked as deprecated without affecting the proto field.
bool deprecated = 49;
}
// Custom properties that start with "x-" such as "x-foo" used to describe
// extra functionality that is not covered by the standard OpenAPI Specification.
// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
map<string, google.protobuf.Value> extensions = 48;
}
// `Tag` is a representation of OpenAPI v2 specification's Tag object.
//
// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#tagObject
//
message Tag {
// The name of the tag. Use it to allow override of the name of a
// global Tag object, then use that name to reference the tag throughout the
// OpenAPI file.
string name = 1;
// A short description for the tag. GFM syntax can be used for rich text
// representation.
string description = 2;
// Additional external documentation for this tag.
ExternalDocumentation external_docs = 3;
// Custom properties that start with "x-" such as "x-foo" used to describe
// extra functionality that is not covered by the standard OpenAPI Specification.
// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
map<string, google.protobuf.Value> extensions = 4;
}
// `SecurityDefinitions` is a representation of OpenAPI v2 specification's
// Security Definitions object.
//
// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityDefinitionsObject
//
// A declaration of the security schemes available to be used in the
// specification. This does not enforce the security schemes on the operations
// and only serves to provide the relevant details for each scheme.
message SecurityDefinitions {
// A single security scheme definition, mapping a "name" to the scheme it
// defines.
map<string, SecurityScheme> security = 1;
}
// `SecurityScheme` is a representation of OpenAPI v2 specification's
// Security Scheme object.
//
// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securitySchemeObject
//
// Allows the definition of a security scheme that can be used by the
// operations. Supported schemes are basic authentication, an API key (either as
// a header or as a query parameter) and OAuth2's common flows (implicit,
// password, application and access code).
message SecurityScheme {
// The type of the security scheme. Valid values are "basic",
// "apiKey" or "oauth2".
enum Type {
TYPE_INVALID = 0;
TYPE_BASIC = 1;
TYPE_API_KEY = 2;
TYPE_OAUTH2 = 3;
}
// The location of the API key. Valid values are "query" or "header".
enum In {
IN_INVALID = 0;
IN_QUERY = 1;
IN_HEADER = 2;
}
// The flow used by the OAuth2 security scheme. Valid values are
// "implicit", "password", "application" or "accessCode".
enum Flow {
FLOW_INVALID = 0;
FLOW_IMPLICIT = 1;
FLOW_PASSWORD = 2;
FLOW_APPLICATION = 3;
FLOW_ACCESS_CODE = 4;
}
// The type of the security scheme. Valid values are "basic",
// "apiKey" or "oauth2".
Type type = 1;
// A short description for security scheme.
string description = 2;
// The name of the header or query parameter to be used.
// Valid for apiKey.
string name = 3;
// The location of the API key. Valid values are "query" or
// "header".
// Valid for apiKey.
In in = 4;
// The flow used by the OAuth2 security scheme. Valid values are
// "implicit", "password", "application" or "accessCode".
// Valid for oauth2.
Flow flow = 5;
// The authorization URL to be used for this flow. This SHOULD be in
// the form of a URL.
// Valid for oauth2/implicit and oauth2/accessCode.
string authorization_url = 6;
// The token URL to be used for this flow. This SHOULD be in the
// form of a URL.
// Valid for oauth2/password, oauth2/application and oauth2/accessCode.
string token_url = 7;
// The available scopes for the OAuth2 security scheme.
// Valid for oauth2.
Scopes scopes = 8;
// Custom properties that start with "x-" such as "x-foo" used to describe
// extra functionality that is not covered by the standard OpenAPI Specification.
// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
map<string, google.protobuf.Value> extensions = 9;
}
// `SecurityRequirement` is a representation of OpenAPI v2 specification's
// Security Requirement object.
//
// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityRequirementObject
//
// Lists the required security schemes to execute this operation. The object can
// have multiple security schemes declared in it which are all required (that
// is, there is a logical AND between the schemes).
//
// The name used for each property MUST correspond to a security scheme
// declared in the Security Definitions.
message SecurityRequirement {
// If the security scheme is of type "oauth2", then the value is a list of
// scope names required for the execution. For other security scheme types,
// the array MUST be empty.
message SecurityRequirementValue {
repeated string scope = 1;
}
// Each name must correspond to a security scheme which is declared in
// the Security Definitions. If the security scheme is of type "oauth2",
// then the value is a list of scope names required for the execution.
// For other security scheme types, the array MUST be empty.
map<string, SecurityRequirementValue> security_requirement = 1;
}
// `Scopes` is a representation of OpenAPI v2 specification's Scopes object.
//
// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#scopesObject
//
// Lists the available scopes for an OAuth2 security scheme.
message Scopes {
// Maps between a name of a scope to a short description of it (as the value
// of the property).
map<string, string> scope = 1;
}
+113
View File
@@ -0,0 +1,113 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.12
// protoc v7.36.0
// source: api/messages/message.proto
package messages
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Message struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Message) Reset() {
*x = Message{}
mi := &file_api_messages_message_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Message) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Message) ProtoMessage() {}
func (x *Message) ProtoReflect() protoreflect.Message {
mi := &file_api_messages_message_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Message.ProtoReflect.Descriptor instead.
func (*Message) Descriptor() ([]byte, []int) {
return file_api_messages_message_proto_rawDescGZIP(), []int{0}
}
var File_api_messages_message_proto protoreflect.FileDescriptor
const file_api_messages_message_proto_rawDesc = "" +
"\n" +
"\x1aapi/messages/message.proto\x12\fapi.messages\"\t\n" +
"\aMessageB\x15Z\x13pkg/pb/api/messagesb\x06proto3"
var (
file_api_messages_message_proto_rawDescOnce sync.Once
file_api_messages_message_proto_rawDescData []byte
)
func file_api_messages_message_proto_rawDescGZIP() []byte {
file_api_messages_message_proto_rawDescOnce.Do(func() {
file_api_messages_message_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_api_messages_message_proto_rawDesc), len(file_api_messages_message_proto_rawDesc)))
})
return file_api_messages_message_proto_rawDescData
}
var file_api_messages_message_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_api_messages_message_proto_goTypes = []any{
(*Message)(nil), // 0: api.messages.Message
}
var file_api_messages_message_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_api_messages_message_proto_init() }
func file_api_messages_message_proto_init() {
if File_api_messages_message_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_api_messages_message_proto_rawDesc), len(file_api_messages_message_proto_rawDesc)),
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_api_messages_message_proto_goTypes,
DependencyIndexes: file_api_messages_message_proto_depIdxs,
MessageInfos: file_api_messages_message_proto_msgTypes,
}.Build()
File_api_messages_message_proto = out.File
file_api_messages_message_proto_goTypes = nil
file_api_messages_message_proto_depIdxs = nil
}
+61
View File
@@ -0,0 +1,61 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.12
// protoc v7.36.0
// source: api/services/core.proto
package services
import (
_ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
var File_api_services_core_proto protoreflect.FileDescriptor
const file_api_services_core_proto_rawDesc = "" +
"\n" +
"\x17api/services/core.proto\x12\fapi.services\x1a.protoc-gen-openapiv2/options/annotations.protoB4\x92A\x1c\x12\x18\n" +
"\vApplication2\t%version%Z\x00Z\x13pkg/pb/api/servicesb\x06proto3"
var file_api_services_core_proto_goTypes = []any{}
var file_api_services_core_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_api_services_core_proto_init() }
func file_api_services_core_proto_init() {
if File_api_services_core_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_api_services_core_proto_rawDesc), len(file_api_services_core_proto_rawDesc)),
NumEnums: 0,
NumMessages: 0,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_api_services_core_proto_goTypes,
DependencyIndexes: file_api_services_core_proto_depIdxs,
}.Build()
File_api_services_core_proto = out.File
file_api_services_core_proto_goTypes = nil
file_api_services_core_proto_depIdxs = nil
}
+205
View File
@@ -0,0 +1,205 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.12
// protoc v7.36.0
// source: api/services/debug_service.proto
package services
import (
_ "google.golang.org/genproto/googleapis/api/annotations"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type GetVersion struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetVersion) Reset() {
*x = GetVersion{}
mi := &file_api_services_debug_service_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetVersion) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetVersion) ProtoMessage() {}
func (x *GetVersion) ProtoReflect() protoreflect.Message {
mi := &file_api_services_debug_service_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetVersion.ProtoReflect.Descriptor instead.
func (*GetVersion) Descriptor() ([]byte, []int) {
return file_api_services_debug_service_proto_rawDescGZIP(), []int{0}
}
type GetVersion_Request struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetVersion_Request) Reset() {
*x = GetVersion_Request{}
mi := &file_api_services_debug_service_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetVersion_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetVersion_Request) ProtoMessage() {}
func (x *GetVersion_Request) ProtoReflect() protoreflect.Message {
mi := &file_api_services_debug_service_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetVersion_Request.ProtoReflect.Descriptor instead.
func (*GetVersion_Request) Descriptor() ([]byte, []int) {
return file_api_services_debug_service_proto_rawDescGZIP(), []int{0, 0}
}
type GetVersion_Response struct {
state protoimpl.MessageState `protogen:"open.v1"`
Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetVersion_Response) Reset() {
*x = GetVersion_Response{}
mi := &file_api_services_debug_service_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetVersion_Response) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetVersion_Response) ProtoMessage() {}
func (x *GetVersion_Response) ProtoReflect() protoreflect.Message {
mi := &file_api_services_debug_service_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetVersion_Response.ProtoReflect.Descriptor instead.
func (*GetVersion_Response) Descriptor() ([]byte, []int) {
return file_api_services_debug_service_proto_rawDescGZIP(), []int{0, 1}
}
func (x *GetVersion_Response) GetVersion() string {
if x != nil {
return x.Version
}
return ""
}
var File_api_services_debug_service_proto protoreflect.FileDescriptor
const file_api_services_debug_service_proto_rawDesc = "" +
"\n" +
" api/services/debug_service.proto\x12\fapi.services\x1a\x1cgoogle/api/annotations.proto\"=\n" +
"\n" +
"GetVersion\x1a\t\n" +
"\aRequest\x1a$\n" +
"\bResponse\x12\x18\n" +
"\aversion\x18\x01 \x01(\tR\aversion2v\n" +
"\bDebugAPI\x12j\n" +
"\n" +
"GetVersion\x12 .api.services.GetVersion.Request\x1a!.api.services.GetVersion.Response\"\x17\x82\xd3\xe4\x93\x02\x11\x12\x0f/api/v1/versionB\x15Z\x13pkg/pb/api/servicesb\x06proto3"
var (
file_api_services_debug_service_proto_rawDescOnce sync.Once
file_api_services_debug_service_proto_rawDescData []byte
)
func file_api_services_debug_service_proto_rawDescGZIP() []byte {
file_api_services_debug_service_proto_rawDescOnce.Do(func() {
file_api_services_debug_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_api_services_debug_service_proto_rawDesc), len(file_api_services_debug_service_proto_rawDesc)))
})
return file_api_services_debug_service_proto_rawDescData
}
var file_api_services_debug_service_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_api_services_debug_service_proto_goTypes = []any{
(*GetVersion)(nil), // 0: api.services.GetVersion
(*GetVersion_Request)(nil), // 1: api.services.GetVersion.Request
(*GetVersion_Response)(nil), // 2: api.services.GetVersion.Response
}
var file_api_services_debug_service_proto_depIdxs = []int32{
1, // 0: api.services.DebugAPI.GetVersion:input_type -> api.services.GetVersion.Request
2, // 1: api.services.DebugAPI.GetVersion:output_type -> api.services.GetVersion.Response
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_api_services_debug_service_proto_init() }
func file_api_services_debug_service_proto_init() {
if File_api_services_debug_service_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_api_services_debug_service_proto_rawDesc), len(file_api_services_debug_service_proto_rawDesc)),
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_api_services_debug_service_proto_goTypes,
DependencyIndexes: file_api_services_debug_service_proto_depIdxs,
MessageInfos: file_api_services_debug_service_proto_msgTypes,
}.Build()
File_api_services_debug_service_proto = out.File
file_api_services_debug_service_proto_goTypes = nil
file_api_services_debug_service_proto_depIdxs = nil
}
+151
View File
@@ -0,0 +1,151 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: api/services/debug_service.proto
/*
Package services is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package services
import (
"context"
"errors"
"io"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
)
// Suppress "imported and not used" errors
var (
_ codes.Code
_ io.Reader
_ status.Status
_ = errors.New
_ = runtime.String
_ = utilities.NewDoubleArray
_ = metadata.Join
)
func request_DebugAPI_GetVersion_0(ctx context.Context, marshaler runtime.Marshaler, client DebugAPIClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq GetVersion_Request
metadata runtime.ServerMetadata
)
if req.Body != nil {
_, _ = io.Copy(io.Discard, req.Body)
}
msg, err := client.GetVersion(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_DebugAPI_GetVersion_0(ctx context.Context, marshaler runtime.Marshaler, server DebugAPIServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq GetVersion_Request
metadata runtime.ServerMetadata
)
msg, err := server.GetVersion(ctx, &protoReq)
return msg, metadata, err
}
// RegisterDebugAPIHandlerServer registers the http handlers for service DebugAPI to "mux".
// UnaryRPC :call DebugAPIServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterDebugAPIHandlerFromEndpoint instead.
// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call.
func RegisterDebugAPIHandlerServer(ctx context.Context, mux *runtime.ServeMux, server DebugAPIServer) error {
mux.Handle(http.MethodGet, pattern_DebugAPI_GetVersion_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/api.services.DebugAPI/GetVersion", runtime.WithHTTPPathPattern("/api/v1/version"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_DebugAPI_GetVersion_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_DebugAPI_GetVersion_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterDebugAPIHandlerFromEndpoint is same as RegisterDebugAPIHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterDebugAPIHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.NewClient(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterDebugAPIHandler(ctx, mux, conn)
}
// RegisterDebugAPIHandler registers the http handlers for service DebugAPI to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterDebugAPIHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterDebugAPIHandlerClient(ctx, mux, NewDebugAPIClient(conn))
}
// RegisterDebugAPIHandlerClient registers the http handlers for service DebugAPI
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "DebugAPIClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "DebugAPIClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "DebugAPIClient" to call the correct interceptors. This client ignores the HTTP middlewares.
func RegisterDebugAPIHandlerClient(ctx context.Context, mux *runtime.ServeMux, client DebugAPIClient) error {
mux.Handle(http.MethodGet, pattern_DebugAPI_GetVersion_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/api.services.DebugAPI/GetVersion", runtime.WithHTTPPathPattern("/api/v1/version"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_DebugAPI_GetVersion_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_DebugAPI_GetVersion_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_DebugAPI_GetVersion_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "version"}, ""))
)
var (
forward_DebugAPI_GetVersion_0 = runtime.ForwardResponseMessage
)
@@ -0,0 +1,121 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.2
// - protoc v7.36.0
// source: api/services/debug_service.proto
package services
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
DebugAPI_GetVersion_FullMethodName = "/api.services.DebugAPI/GetVersion"
)
// DebugAPIClient is the client API for DebugAPI service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type DebugAPIClient interface {
GetVersion(ctx context.Context, in *GetVersion_Request, opts ...grpc.CallOption) (*GetVersion_Response, error)
}
type debugAPIClient struct {
cc grpc.ClientConnInterface
}
func NewDebugAPIClient(cc grpc.ClientConnInterface) DebugAPIClient {
return &debugAPIClient{cc}
}
func (c *debugAPIClient) GetVersion(ctx context.Context, in *GetVersion_Request, opts ...grpc.CallOption) (*GetVersion_Response, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetVersion_Response)
err := c.cc.Invoke(ctx, DebugAPI_GetVersion_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// DebugAPIServer is the server API for DebugAPI service.
// All implementations must embed UnimplementedDebugAPIServer
// for forward compatibility.
type DebugAPIServer interface {
GetVersion(context.Context, *GetVersion_Request) (*GetVersion_Response, error)
mustEmbedUnimplementedDebugAPIServer()
}
// UnimplementedDebugAPIServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedDebugAPIServer struct{}
func (UnimplementedDebugAPIServer) GetVersion(context.Context, *GetVersion_Request) (*GetVersion_Response, error) {
return nil, status.Error(codes.Unimplemented, "method GetVersion not implemented")
}
func (UnimplementedDebugAPIServer) mustEmbedUnimplementedDebugAPIServer() {}
func (UnimplementedDebugAPIServer) testEmbeddedByValue() {}
// UnsafeDebugAPIServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to DebugAPIServer will
// result in compilation errors.
type UnsafeDebugAPIServer interface {
mustEmbedUnimplementedDebugAPIServer()
}
func RegisterDebugAPIServer(s grpc.ServiceRegistrar, srv DebugAPIServer) {
// If the following call panics, it indicates UnimplementedDebugAPIServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&DebugAPI_ServiceDesc, srv)
}
func _DebugAPI_GetVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetVersion_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DebugAPIServer).GetVersion(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: DebugAPI_GetVersion_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DebugAPIServer).GetVersion(ctx, req.(*GetVersion_Request))
}
return interceptor(ctx, in, info, handler)
}
// DebugAPI_ServiceDesc is the grpc.ServiceDesc for DebugAPI service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var DebugAPI_ServiceDesc = grpc.ServiceDesc{
ServiceName: "api.services.DebugAPI",
HandlerType: (*DebugAPIServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetVersion",
Handler: _DebugAPI_GetVersion_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "api/services/debug_service.proto",
}
+25
View File
@@ -0,0 +1,25 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
!dist/.gitkeep
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
+75
View File
@@ -0,0 +1,75 @@
# React + TypeScript + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
## React Compiler
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
## Expanding the ESLint configuration
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
```js
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,
// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
```
You can also install [eslint-plugin-react-x](https://npmx.dev/package/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://npmx.dev/package/eslint-plugin-react-dom) for React-specific lint rules:
```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
```
+22
View File
@@ -0,0 +1,22 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
import { defineConfig, globalIgnores } from 'eslint/config'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs.flat.recommended,
reactRefresh.configs.vite,
],
languageOptions: {
globals: globals.browser,
},
},
])
+13
View File
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>app</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+30
View File
@@ -0,0 +1,30 @@
{
"name": "app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"react": "^19.2.8",
"react-dom": "^19.2.8"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@types/node": "^24.13.3",
"@types/react": "^19.2.18",
"@types/react-dom": "^19.2.7",
"@vitejs/plugin-react": "^6.1.1",
"eslint": "^10.10.0",
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.6",
"globals": "^17.12.0",
"typescript": "~6.0.2",
"typescript-eslint": "^8.69.0",
"vite": "^8.3.0"
}
}
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.3 KiB

+24
View File
@@ -0,0 +1,24 @@
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="bluesky-icon" viewBox="0 0 16 17">
<g clip-path="url(#bluesky-clip)"><path fill="#08060d" d="M7.75 7.735c-.693-1.348-2.58-3.86-4.334-5.097-1.68-1.187-2.32-.981-2.74-.79C.188 2.065.1 2.812.1 3.251s.241 3.602.398 4.13c.52 1.744 2.367 2.333 4.07 2.145-2.495.37-4.71 1.278-1.805 4.512 3.196 3.309 4.38-.71 4.987-2.746.608 2.036 1.307 5.91 4.93 2.746 2.72-2.746.747-4.143-1.747-4.512 1.702.189 3.55-.4 4.07-2.145.156-.528.397-3.691.397-4.13s-.088-1.186-.575-1.406c-.42-.19-1.06-.395-2.741.79-1.755 1.24-3.64 3.752-4.334 5.099"/></g>
<defs><clipPath id="bluesky-clip"><path fill="#fff" d="M.1.85h15.3v15.3H.1z"/></clipPath></defs>
</symbol>
<symbol id="discord-icon" viewBox="0 0 20 19">
<path fill="#08060d" d="M16.224 3.768a14.5 14.5 0 0 0-3.67-1.153c-.158.286-.343.67-.47.976a13.5 13.5 0 0 0-4.067 0c-.128-.306-.317-.69-.476-.976A14.4 14.4 0 0 0 3.868 3.77C1.546 7.28.916 10.703 1.231 14.077a14.7 14.7 0 0 0 4.5 2.306q.545-.748.965-1.587a9.5 9.5 0 0 1-1.518-.74q.191-.14.372-.293c2.927 1.369 6.107 1.369 8.999 0q.183.152.372.294-.723.437-1.52.74.418.838.963 1.588a14.6 14.6 0 0 0 4.504-2.308c.37-3.911-.63-7.302-2.644-10.309m-9.13 8.234c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.894 0 1.614.82 1.599 1.82.001 1-.705 1.82-1.6 1.82m5.91 0c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.893 0 1.614.82 1.599 1.82 0 1-.706 1.82-1.6 1.82"/>
</symbol>
<symbol id="documentation-icon" viewBox="0 0 21 20">
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="m15.5 13.333 1.533 1.322c.645.555.967.833.967 1.178s-.322.623-.967 1.179L15.5 18.333m-3.333-5-1.534 1.322c-.644.555-.966.833-.966 1.178s.322.623.966 1.179l1.534 1.321"/>
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M17.167 10.836v-4.32c0-1.41 0-2.117-.224-2.68-.359-.906-1.118-1.621-2.08-1.96-.599-.21-1.349-.21-2.848-.21-2.623 0-3.935 0-4.983.369-1.684.591-3.013 1.842-3.641 3.428C3 6.449 3 7.684 3 10.154v2.122c0 2.558 0 3.838.706 4.726q.306.383.713.671c.76.536 1.79.64 3.581.66"/>
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M3 10a2.78 2.78 0 0 1 2.778-2.778c.555 0 1.209.097 1.748-.047.48-.129.854-.503.982-.982.145-.54.048-1.194.048-1.749a2.78 2.78 0 0 1 2.777-2.777"/>
</symbol>
<symbol id="github-icon" viewBox="0 0 19 19">
<path fill="#08060d" fill-rule="evenodd" d="M9.356 1.85C5.05 1.85 1.57 5.356 1.57 9.694a7.84 7.84 0 0 0 5.324 7.44c.387.079.528-.168.528-.376 0-.182-.013-.805-.013-1.454-2.165.467-2.616-.935-2.616-.935-.349-.91-.864-1.143-.864-1.143-.71-.48.051-.48.051-.48.787.051 1.2.805 1.2.805.695 1.194 1.817.857 2.268.649.064-.507.27-.857.49-1.052-1.728-.182-3.545-.857-3.545-3.87 0-.857.31-1.558.8-2.104-.078-.195-.349-1 .077-2.078 0 0 .657-.208 2.14.805a7.5 7.5 0 0 1 1.946-.26c.657 0 1.328.092 1.946.26 1.483-1.013 2.14-.805 2.14-.805.426 1.078.155 1.883.078 2.078.502.546.799 1.247.799 2.104 0 3.013-1.818 3.675-3.558 3.87.284.247.528.714.528 1.454 0 1.052-.012 1.896-.012 2.156 0 .208.142.455.528.377a7.84 7.84 0 0 0 5.324-7.441c.013-4.338-3.48-7.844-7.773-7.844" clip-rule="evenodd"/>
</symbol>
<symbol id="social-icon" viewBox="0 0 20 20">
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M12.5 6.667a4.167 4.167 0 1 0-8.334 0 4.167 4.167 0 0 0 8.334 0"/>
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M2.5 16.667a5.833 5.833 0 0 1 8.75-5.053m3.837.474.513 1.035c.07.144.257.282.414.309l.93.155c.596.1.736.536.307.965l-.723.73a.64.64 0 0 0-.152.531l.207.903c.164.715-.213.991-.84.618l-.872-.52a.63.63 0 0 0-.577 0l-.872.52c-.624.373-1.003.094-.84-.618l.207-.903a.64.64 0 0 0-.152-.532l-.723-.729c-.426-.43-.289-.864.306-.964l.93-.156a.64.64 0 0 0 .412-.31l.513-1.034c.28-.562.735-.562 1.012 0"/>
</symbol>
<symbol id="x-icon" viewBox="0 0 19 19">
<path fill="#08060d" fill-rule="evenodd" d="M1.893 1.98c.052.072 1.245 1.769 2.653 3.77l2.892 4.114c.183.261.333.48.333.486s-.068.089-.152.183l-.522.593-.765.867-3.597 4.087c-.375.426-.734.834-.798.905a1 1 0 0 0-.118.148c0 .01.236.017.664.017h.663l.729-.83c.4-.457.796-.906.879-.999a692 692 0 0 0 1.794-2.038c.034-.037.301-.34.594-.675l.551-.624.345-.392a7 7 0 0 1 .34-.374c.006 0 .93 1.306 2.052 2.903l2.084 2.965.045.063h2.275c1.87 0 2.273-.003 2.266-.021-.008-.02-1.098-1.572-3.894-5.547-2.013-2.862-2.28-3.246-2.273-3.266.008-.019.282-.332 2.085-2.38l2-2.274 1.567-1.782c.022-.028-.016-.03-.65-.03h-.674l-.3.342a871 871 0 0 1-1.782 2.025c-.067.075-.405.458-.75.852a100 100 0 0 1-.803.91c-.148.172-.299.344-.99 1.127-.304.343-.32.358-.345.327-.015-.019-.904-1.282-1.976-2.808L6.365 1.85H1.8zm1.782.91 8.078 11.294c.772 1.08 1.413 1.973 1.425 1.984.016.017.241.02 1.05.017l1.03-.004-2.694-3.766L7.796 5.75 5.722 2.852l-1.039-.004-1.039-.004z" clip-rule="evenodd"/>
</symbol>
</svg>

After

Width:  |  Height:  |  Size: 4.9 KiB

+184
View File
@@ -0,0 +1,184 @@
.counter {
font-size: 16px;
padding: 5px 10px;
border-radius: 5px;
color: var(--accent);
background: var(--accent-bg);
border: 2px solid transparent;
transition: border-color 0.3s;
margin-bottom: 24px;
&:hover {
border-color: var(--accent-border);
}
&:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
}
.hero {
position: relative;
.base,
.framework,
.vite {
inset-inline: 0;
margin: 0 auto;
}
.base {
width: 170px;
position: relative;
z-index: 0;
}
.framework,
.vite {
position: absolute;
}
.framework {
z-index: 1;
top: 34px;
height: 28px;
transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg)
scale(1.4);
}
.vite {
z-index: 0;
top: 107px;
height: 26px;
width: auto;
transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg)
scale(0.8);
}
}
#center {
display: flex;
flex-direction: column;
gap: 25px;
place-content: center;
place-items: center;
flex-grow: 1;
@media (max-width: 1024px) {
padding: 32px 20px 24px;
gap: 18px;
}
}
#next-steps {
display: flex;
border-top: 1px solid var(--border);
text-align: left;
& > div {
flex: 1 1 0;
padding: 32px;
@media (max-width: 1024px) {
padding: 24px 20px;
}
}
.icon {
margin-bottom: 16px;
width: 22px;
height: 22px;
}
@media (max-width: 1024px) {
flex-direction: column;
text-align: center;
}
}
#docs {
border-right: 1px solid var(--border);
@media (max-width: 1024px) {
border-right: none;
border-bottom: 1px solid var(--border);
}
}
#next-steps ul {
list-style: none;
padding: 0;
display: flex;
gap: 8px;
margin: 32px 0 0;
.logo {
height: 18px;
}
a {
color: var(--text-h);
font-size: 16px;
border-radius: 6px;
background: var(--social-bg);
display: flex;
padding: 6px 12px;
align-items: center;
gap: 8px;
text-decoration: none;
transition: box-shadow 0.3s;
&:hover {
box-shadow: var(--shadow);
}
.button-icon {
height: 18px;
width: 18px;
}
}
@media (max-width: 1024px) {
margin-top: 20px;
flex-wrap: wrap;
justify-content: center;
li {
flex: 1 1 calc(50% - 8px);
}
a {
width: 100%;
justify-content: center;
box-sizing: border-box;
}
}
}
#spacer {
height: 88px;
border-top: 1px solid var(--border);
@media (max-width: 1024px) {
height: 48px;
}
}
.ticks {
position: relative;
width: 100%;
&::before,
&::after {
content: '';
position: absolute;
top: -4.5px;
border: 5px solid transparent;
}
&::before {
left: 0;
border-left-color: var(--border);
}
&::after {
right: 0;
border-right-color: var(--border);
}
}
+122
View File
@@ -0,0 +1,122 @@
import { useState } from 'react'
import heroImg from './assets/hero.png'
import reactLogo from './assets/react.svg'
import viteLogo from './assets/vite.svg'
import './App.css'
function App() {
const [count, setCount] = useState(0)
return (
<>
<section id="center">
<div className="hero">
<img src={heroImg} className="base" width="170" height="179" alt="" />
<img src={reactLogo} className="framework" alt="React logo" />
<img src={viteLogo} className="vite" alt="Vite logo" />
</div>
<div>
<h1>Get started</h1>
<p>
Edit <code>src/App.tsx</code> and save to test <code>HMR</code>
</p>
</div>
<button
type="button"
className="counter"
onClick={() => setCount((count) => count + 1)}
>
Count is {count}
</button>
</section>
<div className="ticks"></div>
<section id="next-steps">
<div id="docs">
<svg className="icon" role="presentation" aria-hidden="true">
<use href="/icons.svg#documentation-icon"></use>
</svg>
<h2>Documentation</h2>
<p>Your questions, answered</p>
<ul>
<li>
<a href="https://vite.dev/" target="_blank">
<img className="logo" src={viteLogo} alt="" />
Explore Vite
</a>
</li>
<li>
<a href="https://react.dev/" target="_blank">
<img className="button-icon" src={reactLogo} alt="" />
Learn more
</a>
</li>
</ul>
</div>
<div id="social">
<svg className="icon" role="presentation" aria-hidden="true">
<use href="/icons.svg#social-icon"></use>
</svg>
<h2>Connect with us</h2>
<p>Join the Vite community</p>
<ul>
<li>
<a href="https://github.com/vitejs/vite" target="_blank">
<svg
className="button-icon"
role="presentation"
aria-hidden="true"
>
<use href="/icons.svg#github-icon"></use>
</svg>
GitHub
</a>
</li>
<li>
<a href="https://chat.vite.dev/" target="_blank">
<svg
className="button-icon"
role="presentation"
aria-hidden="true"
>
<use href="/icons.svg#discord-icon"></use>
</svg>
Discord
</a>
</li>
<li>
<a href="https://x.com/vite_js" target="_blank">
<svg
className="button-icon"
role="presentation"
aria-hidden="true"
>
<use href="/icons.svg#x-icon"></use>
</svg>
X.com
</a>
</li>
<li>
<a href="https://bsky.app/profile/vite.dev" target="_blank">
<svg
className="button-icon"
role="presentation"
aria-hidden="true"
>
<use href="/icons.svg#bluesky-icon"></use>
</svg>
Bluesky
</a>
</li>
</ul>
</div>
</section>
<div className="ticks"></div>
<section id="spacer"></section>
</>
)
}
export default App
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.5 KiB

+111
View File
@@ -0,0 +1,111 @@
:root {
--text: #6b6375;
--text-h: #08060d;
--bg: #fff;
--border: #e5e4e7;
--code-bg: #f4f3ec;
--accent: #aa3bff;
--accent-bg: rgba(170, 59, 255, 0.1);
--accent-border: rgba(170, 59, 255, 0.5);
--social-bg: rgba(244, 243, 236, 0.5);
--shadow:
rgba(0, 0, 0, 0.1) 0 10px 15px -3px, rgba(0, 0, 0, 0.05) 0 4px 6px -2px;
--sans: system-ui, 'Segoe UI', Roboto, sans-serif;
--heading: system-ui, 'Segoe UI', Roboto, sans-serif;
--mono: ui-monospace, Consolas, monospace;
font: 18px/145% var(--sans);
letter-spacing: 0.18px;
color-scheme: light dark;
color: var(--text);
background: var(--bg);
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@media (max-width: 1024px) {
font-size: 16px;
}
}
@media (prefers-color-scheme: dark) {
:root {
--text: #9ca3af;
--text-h: #f3f4f6;
--bg: #16171d;
--border: #2e303a;
--code-bg: #1f2028;
--accent: #c084fc;
--accent-bg: rgba(192, 132, 252, 0.15);
--accent-border: rgba(192, 132, 252, 0.5);
--social-bg: rgba(47, 48, 58, 0.5);
--shadow:
rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px;
}
#social .button-icon {
filter: invert(1) brightness(2);
}
}
#root {
width: 1126px;
max-width: 100%;
margin: 0 auto;
text-align: center;
border-inline: 1px solid var(--border);
min-height: 100svh;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
body {
margin: 0;
}
h1,
h2 {
font-family: var(--heading);
font-weight: 500;
color: var(--text-h);
}
h1 {
font-size: 56px;
letter-spacing: -1.68px;
margin: 32px 0;
@media (max-width: 1024px) {
font-size: 36px;
margin: 20px 0;
}
}
h2 {
font-size: 24px;
line-height: 118%;
letter-spacing: -0.24px;
margin: 0 0 8px;
@media (max-width: 1024px) {
font-size: 20px;
}
}
p {
margin: 0;
}
code,
.counter {
font-family: var(--mono);
display: inline-flex;
border-radius: 4px;
color: var(--text-h);
}
code {
font-size: 15px;
line-height: 135%;
padding: 4px 8px;
background: var(--code-bg);
}
+10
View File
@@ -0,0 +1,10 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
)
+26
View File
@@ -0,0 +1,26 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "es2023",
"lib": ["ES2023", "DOM"],
"module": "esnext",
"types": ["vite/client"],
"allowArbitraryExtensions": true,
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
}
+7
View File
@@ -0,0 +1,7 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}
+23
View File
@@ -0,0 +1,23 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "es2023",
"lib": ["ES2023"],
"types": ["node"],
"skipLibCheck": true,
/* Bundler mode */
"module": "nodenext",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true
},
"include": ["vite.config.ts"]
}
+7
View File
@@ -0,0 +1,7 @@
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
})
+1260
View File
File diff suppressed because it is too large Load Diff
+37
View File
@@ -0,0 +1,37 @@
package static
import (
"embed"
"io"
"io/fs"
"log"
"net/http"
"strings"
)
//go:embed app/dist
var appFS embed.FS
var Handler = func() http.HandlerFunc {
distFS, err := fs.Sub(appFS, "app/dist")
if err != nil {
log.Fatalln(err)
}
fileServer := http.FileServer(http.FS(distFS))
return func(w http.ResponseWriter, r *http.Request) {
path := strings.TrimPrefix(r.URL.Path, "/")
_, err := distFS.Open(path)
if err == nil || path == "" {
fileServer.ServeHTTP(w, r)
return
}
indexFile, err := distFS.Open("index.html")
if err != nil {
http.Error(w, "frontend build not found", http.StatusInternalServerError)
return
}
defer func() { _ = indexFile.Close() }()
stat, _ := indexFile.Stat()
http.ServeContent(w, r, "index.html", stat.ModTime(), indexFile.(io.ReadSeeker))
}
}()