Adding tags command.
Refactoring main and app.go to cmd. Refactoring to adding logrus instead of log. Refactoring handlers to add a global logger.
This commit is contained in:
parent
234b593c26
commit
e3e81130ba
36
app.go
36
app.go
|
@ -1,36 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"gosimplenpm/config"
|
||||
"gosimplenpm/handler"
|
||||
"gosimplenpm/middlewares"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type application struct {
|
||||
logger *log.Logger
|
||||
conf config.Config
|
||||
}
|
||||
|
||||
func (app *application) Routes() *mux.Router {
|
||||
|
||||
// Need to use UseEncodedPath as shown here https://github.com/gorilla/mux/blob/master/mux.go#L269
|
||||
m := mux.NewRouter().StrictSlash(true).UseEncodedPath()
|
||||
|
||||
m.Use(middlewares.LogMiddleware)
|
||||
|
||||
// main handler
|
||||
m.HandleFunc("/{name}", middlewares.AuthMiddleware(app.conf)(handler.Get)).Methods("GET")
|
||||
m.HandleFunc("/{name}", middlewares.AuthMiddleware(app.conf)(handler.Publish)).Methods("PUT")
|
||||
// tar handlers
|
||||
m.HandleFunc("/{name}/-/{tar}", handler.Tar).Methods("GET")
|
||||
// tag handlers
|
||||
m.HandleFunc("/-/package/{name}/dist-tags/{tag}", handler.DistTagDelete).Methods("DELETE")
|
||||
m.HandleFunc("/-/package/{name}/dist-tags/{tag}", handler.DistTagPut).Methods("PUT")
|
||||
m.HandleFunc("/-/package/{name}/dist-tags", handler.DistTagGet).Methods("GET")
|
||||
m.NotFoundHandler = http.HandlerFunc(handler.NotFound)
|
||||
return m
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"gosimplenpm/cmd/npmregserver"
|
||||
"gosimplenpm/config"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log := &logrus.Logger{
|
||||
Out: os.Stdout,
|
||||
Level: logrus.DebugLevel,
|
||||
Formatter: &logrus.TextFormatter{
|
||||
FullTimestamp: true,
|
||||
TimestampFormat: "2009-01-02 15:15:15",
|
||||
},
|
||||
}
|
||||
|
||||
var cfg config.Config
|
||||
err := config.LoadConfiguration("userdata/config.json", &cfg)
|
||||
if err != nil {
|
||||
log.Fatalf("Config is not loaded: %+v\n", err)
|
||||
}
|
||||
|
||||
app := &npmregserver.Application{
|
||||
Conf: cfg,
|
||||
Logger: log,
|
||||
}
|
||||
|
||||
log.Infoln("Starting server on port 4000")
|
||||
err = http.ListenAndServe(":4000", app.Routes())
|
||||
log.Fatal(err)
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package npmregserver
|
||||
|
||||
import (
|
||||
"gosimplenpm/config"
|
||||
"gosimplenpm/handler"
|
||||
"gosimplenpm/middlewares"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type Application struct {
|
||||
Logger *logrus.Logger
|
||||
Conf config.Config
|
||||
}
|
||||
|
||||
func (app *Application) Routes() *mux.Router {
|
||||
|
||||
// Need to use UseEncodedPath as shown here https://github.com/gorilla/mux/blob/master/mux.go#L269
|
||||
m := mux.NewRouter().StrictSlash(true).UseEncodedPath()
|
||||
|
||||
m.Use(middlewares.LogMiddleware(app.Logger))
|
||||
|
||||
// main handler
|
||||
m.HandleFunc("/{name}", handler.Get).Methods("GET")
|
||||
m.HandleFunc("/{name}", middlewares.AuthMiddleware(app.Conf)(handler.Publish)).Methods("PUT")
|
||||
// tar handlers
|
||||
m.HandleFunc("/{name}/-/{tar}", handler.Tar).Methods("GET")
|
||||
// tag handlers
|
||||
m.HandleFunc("/-/package/{name}/dist-tags/{tag}", middlewares.AuthMiddleware(app.Conf)(handler.DistTagDelete(app.Logger))).Methods("DELETE")
|
||||
m.HandleFunc("/-/package/{name}/dist-tags/{tag}", middlewares.AuthMiddleware(app.Conf)(handler.DistTagPut(app.Logger))).Methods("PUT")
|
||||
m.HandleFunc("/-/package/{name}/dist-tags", handler.DistTagGet(app.Logger)).Methods("GET")
|
||||
m.NotFoundHandler = http.HandlerFunc(handler.NotFound)
|
||||
return m
|
||||
}
|
8
go.mod
8
go.mod
|
@ -2,6 +2,12 @@ module gosimplenpm
|
|||
|
||||
go 1.20
|
||||
|
||||
require github.com/gorilla/mux v1.8.0
|
||||
require (
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
golang.org/x/mod v0.11.0
|
||||
)
|
||||
|
||||
require golang.org/x/sys v0.9.0 // indirect
|
||||
|
||||
// replace gosimplenpm/handler => ./handler
|
||||
|
|
18
go.sum
18
go.sum
|
@ -1,2 +1,20 @@
|
|||
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/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
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/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// This handler is executed when the router cannot match any route
|
||||
func NotFound(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Printf("%s - %s - %s\n", r.Method, r.URL, r.Host)
|
||||
http.Error(w, "Invalid url", http.StatusBadRequest)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,79 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"gosimplenpm/serviceidos"
|
||||
"gosimplenpm/storage"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
|
||||
func DistTagDelete(w http.ResponseWriter, r *http.Request) {
|
||||
func DistTagDelete(lg *logrus.Logger) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
escapedName := mux.Vars(r)["name"]
|
||||
packageName, _ := url.PathUnescape(escapedName)
|
||||
lg.Printf("Package name => %s\n", packageName)
|
||||
|
||||
escapedName = mux.Vars(r)["tag"]
|
||||
tag, _ := url.PathUnescape(escapedName)
|
||||
lg.Printf("Tag => %s\n", tag)
|
||||
|
||||
if semver.IsValid(tag) {
|
||||
http.Error(w, "Tag cannot be a semver version", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if tag == "latest" {
|
||||
http.Error(w, "Cannot delete the latest tag", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
fileToServe, found, err := storage.GetIndexJsonFromStore(packageName)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if !found {
|
||||
ret := fmt.Sprintf("Package not found: %s", packageName)
|
||||
http.Error(w, ret, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
var jsonFile serviceidos.IndexJson
|
||||
err = storage.ReadIndexJson(fileToServe, &jsonFile)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
delete(jsonFile.DistTags, tag)
|
||||
|
||||
// Write index.json
|
||||
err = storage.WriteIndexJson(fileToServe, &jsonFile)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
distTagsString, _ := json.Marshal(jsonFile.DistTags)
|
||||
|
||||
response := serviceidos.TagPutResponse{
|
||||
Ok: true,
|
||||
ID: escapedName,
|
||||
DistTags: string(distTagsString),
|
||||
}
|
||||
|
||||
jsonString, _ := json.Marshal(response)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(jsonString)))
|
||||
w.Write(jsonString)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,47 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"gosimplenpm/serviceidos"
|
||||
"gosimplenpm/storage"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func DistTagGet(w http.ResponseWriter, r *http.Request) {
|
||||
func DistTagGet(lg *logrus.Logger) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
escapedName := mux.Vars(r)["name"]
|
||||
packageName, _ := url.PathUnescape(escapedName)
|
||||
lg.Debugf("Package name => %s\n", packageName)
|
||||
|
||||
fileToServe, found, err := storage.GetIndexJsonFromStore(packageName)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if !found {
|
||||
ret := fmt.Sprintf("Package not found: %s", packageName)
|
||||
http.Error(w, ret, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
var jsonFile serviceidos.IndexJson
|
||||
err = storage.ReadIndexJson(fileToServe, &jsonFile)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
jsonString, _ := json.Marshal(jsonFile.DistTags)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(jsonString)))
|
||||
w.Write(jsonString)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,85 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"gosimplenpm/serviceidos"
|
||||
"gosimplenpm/storage"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
|
||||
func DistTagPut(w http.ResponseWriter, r *http.Request) {
|
||||
func DistTagPut(lg *logrus.Logger) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
escapedName := mux.Vars(r)["name"]
|
||||
packageName, _ := url.PathUnescape(escapedName)
|
||||
lg.Printf("Package name => %s\n", packageName)
|
||||
|
||||
escapedName = mux.Vars(r)["tag"]
|
||||
tag, _ := url.PathUnescape(escapedName)
|
||||
lg.Printf("Tag => %s\n", tag)
|
||||
|
||||
if semver.IsValid(tag) {
|
||||
http.Error(w, "Tag cannot be a semver version", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if tag == "latest" {
|
||||
http.Error(w, "Cannot delete the latest tag", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
body, _ := io.ReadAll(r.Body)
|
||||
var version string
|
||||
_ = json.Unmarshal(body, &version)
|
||||
lg.Printf("Body => %s", version)
|
||||
|
||||
fileToServe, found, err := storage.GetIndexJsonFromStore(packageName)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if !found {
|
||||
ret := fmt.Sprintf("Package not found: %s", packageName)
|
||||
http.Error(w, ret, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
var jsonFile serviceidos.IndexJson
|
||||
err = storage.ReadIndexJson(fileToServe, &jsonFile)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
jsonFile.DistTags[tag] = version
|
||||
|
||||
// Write index.json
|
||||
err = storage.WriteIndexJson(fileToServe, &jsonFile)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
distTagsString, _ := json.Marshal(jsonFile.DistTags)
|
||||
|
||||
response := serviceidos.TagPutResponse{
|
||||
Ok: true,
|
||||
ID: escapedName,
|
||||
DistTags: string(distTagsString),
|
||||
}
|
||||
|
||||
jsonString, _ := json.Marshal(response)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(jsonString)))
|
||||
w.Write(jsonString)
|
||||
}
|
||||
}
|
||||
|
|
45
main.go
45
main.go
|
@ -1,45 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"gosimplenpm/config"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var cfg config.Config
|
||||
err := config.LoadConfiguration("userdata/config.json", &cfg)
|
||||
if err != nil {
|
||||
log.Fatalf("Config is not loaded: %+v\n", err)
|
||||
}
|
||||
|
||||
app := &application{
|
||||
conf: cfg,
|
||||
}
|
||||
log.Print("Starting server on port 4000")
|
||||
err = http.ListenAndServe(":4000", app.Routes())
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// func main() {
|
||||
// router := mux.NewRouter()
|
||||
// router.NewRoute().Path("/{name}").Methods("PUT")
|
||||
// router.NewRoute().Path("/{name}").Methods("GET")
|
||||
|
||||
// rMatch := &mux.RouteMatch{}
|
||||
|
||||
// u := url.URL{Path: "/@ookusanya%2fsimplepackone"}
|
||||
// req := http.Request{Method: "GET", URL: &u}
|
||||
|
||||
// x := router.Match(&req, rMatch)
|
||||
// fmt.Println("Is Matched: ", x)
|
||||
|
||||
// reqt := http.Request{Method: "PUT", URL: &u}
|
||||
// g := router.Match(&reqt, rMatch)
|
||||
// fmt.Println("Is Matched: ", g)
|
||||
|
||||
// ut := url.URL{Path: "/@ookusanya%2fsimplepackone/-/simplepackone-1.0.0.tgz"}
|
||||
// rt := http.Request{Method: "PUT", URL: &ut}
|
||||
// gt := router.Match(&rt, rMatch)
|
||||
// fmt.Println("Is Matched: ", gt)
|
||||
// }
|
|
@ -6,7 +6,7 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
func AuthMiddleware(cfg config.Config) Middleware {
|
||||
func AuthMiddleware(cfg config.Config) func(http.HandlerFunc) http.HandlerFunc {
|
||||
return func(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// get headers
|
||||
|
@ -26,30 +26,3 @@ func AuthMiddleware(cfg config.Config) Middleware {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// func AuthMiddleware(next http.HandlerFunc) http.HandlerFunc {
|
||||
// return func(w http.ResponseWriter, r *http.Request) {
|
||||
// if cfg == nil {
|
||||
// log.Println("Config load error")
|
||||
// http.Error(w, "Config load error", http.StatusInternalServerError)
|
||||
// return
|
||||
// }
|
||||
|
||||
// log.Println("Config was loaded")
|
||||
|
||||
// // get headers
|
||||
// authHeader := r.Header.Get("Authorization")
|
||||
// authFields := strings.Fields(authHeader)
|
||||
// if len(authFields) != 2 || strings.ToLower(authFields[0]) != "bearer" {
|
||||
// http.Error(w, "Authentication Error", http.StatusForbidden)
|
||||
// return
|
||||
// }
|
||||
// token := authFields[1]
|
||||
// if token != cfg.Token {
|
||||
// http.Error(w, "Authentication Error", http.StatusForbidden)
|
||||
// return
|
||||
// }
|
||||
// fmt.Println("Authorized")
|
||||
// next(w, r)
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -1,33 +1,29 @@
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func LogMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("%s - %s - %s", r.Method, r.URL, r.Host)
|
||||
func LogMiddleware(lg *logrus.Logger) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
lg.Debugf("%s - %s - %s", r.Method, r.URL, r.Host)
|
||||
|
||||
hasBody := false
|
||||
if r.Method == "PUT" {
|
||||
hasBody = true
|
||||
}
|
||||
hasBody := false
|
||||
if r.Method == "PUT" {
|
||||
hasBody = true
|
||||
}
|
||||
|
||||
requestDump, err := httputil.DumpRequest(r, hasBody)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println("RequestDump: ", string(requestDump))
|
||||
requestDump, err := httputil.DumpRequest(r, hasBody)
|
||||
if err != nil {
|
||||
lg.Debugln(err)
|
||||
}
|
||||
lg.Debugln("RequestDump: ", string(requestDump))
|
||||
|
||||
// fmt.Println("Printing headers")
|
||||
// for name, values := range r.Header {
|
||||
// for _, value := range values {
|
||||
// fmt.Printf("%s:%s\n", name, value)
|
||||
// }
|
||||
// }
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Middleware func(http.HandlerFunc) http.HandlerFunc
|
|
@ -40,3 +40,15 @@ type IndexJson struct {
|
|||
Access string `json:"access"`
|
||||
Attachments map[string]IndexJsonAttachments `json:"_attachments"`
|
||||
}
|
||||
|
||||
type TagPutResponse struct {
|
||||
Ok bool `json:"ok"`
|
||||
ID string `json:"id"`
|
||||
DistTags string `json:"dist-tags"`
|
||||
}
|
||||
|
||||
type TagDeleteResponse struct {
|
||||
Ok bool `json:"ok"`
|
||||
ID string `json:"id"`
|
||||
DistTags string `json:"dist-tags"`
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"_id":"@ookusanya/simplepackone","name":"@ookusanya/simplepackone","description":"This is a very rough implementation of a private npm registry.","dist-tags":{"latest":"1.2.0"},"versions":{"1.0.0":{"name":"@ookusanya/simplepackone","version":"1.0.0","description":"This is a very rough implementation of a private npm registry.","main":"index.js","scripts":{"test":"echo \"Error: no test specified\" \u0026\u0026 exit 1"},"license":"MIT","files":null,"readme":"# Gosimplenpm\n\nThis is a very rough implementation of a private npm registry.\n\n# Features\n\nTODO...\n\n# Enhancements\n\nTODO...\n\n# Work List\n\nTODO...","_id":"@ookusanya/simplepackone@1.0.0","_nodeVersion":"16.20.0","_npmVersion":"8.19.4","dist":{"integrity":"sha512-x9cAEHDPM0dLhdyd8baWLTNYskr41QXLNv5HS5WNDg1CVzwcMaAU+N9lYVuOvLf/xPHLielWmX+wLXEtRWQvGw==","shasum":"545a7737b59b1a6f064339a4ebe056e8a9b1511d","tarball":"http://localhost:4000/@ookusanya/simplepackone/-/@ookusanya/simplepackone-1.0.0.tgz"},"dependencies":{"eslint":"^7.x"}},"1.2.0":{"name":"@ookusanya/simplepackone","version":"1.2.0","description":"This is a very rough implementation of a private npm registry.","main":"index.js","scripts":{"test":"echo \"Error: no test specified\" \u0026\u0026 exit 1"},"license":"MIT","files":null,"readme":"# Gosimplenpm\n\nThis is a very rough implementation of a private npm registry.\n\n# Features\n\nTODO...\n\n# Enhancements\n\nTODO...\n\n# Work List\n\nTODO...","_id":"@ookusanya/simplepackone@1.2.0","_nodeVersion":"16.20.0","_npmVersion":"8.19.4","dist":{"integrity":"sha512-coOiU+ywV/do/+HwK91mfuei9491yfQUedLWjspAjDa58RniJvQNTF/cXDp/sooVdpjgEbCqKVyLOju6C1i3pw==","shasum":"1adafdbe8878372c9f4b554bf30d5bfb1b7896c5","tarball":"http://localhost:4000/@ookusanya%2Fsimplepackone/-/@ookusanya%2Fsimplepackone-1.2.0.tgz"},"dependencies":{"eslint":"^7.x","mocha":"^10.x","uuid":"^9.x"}}},"access":"","_attachments":{"@ookusanya/simplepackone-1.2.0.tgz":{"content_type":"application/octet-stream","data":"H4sIAAAAAAAC/+1XbWvjOBDuZ/+KwQtLCyZ10pfl+uncRGnMOnawne0VlgXVVmJtHctIcl849r/fSEmb9nof73LcXoaA0Lw9M6PMSG5pcUeX7Jg3JXvsfVcH/wD5vn9+egp/xbc0OIGDk7Nzv98/P/dRz+/7nwY+rgc7oE5pKjGUvyFJJHhZ/yNUiEaJmvVqsTx0J0wy9+hgT/8fajf9v1lxAohmx/1/ev6u//tnZ/19/++CfncA3IaumHsB7q9C3HWKNk/0WPFVWzPzrxANcz2jdc+k4qIxiv3eoOevuSVTheSt3kjWzBXldvd8q6y5a0WFAoOKDM2UNmqsqAR8dYmUQl5AI8AIQLWs4AvOyq8ufPwI7JFr6Lto+cN6o52uhNxi1rxgjbJ5TMP8ObiWYQhNwdkrWKZq3ljgb596j1bTxCyKilpm399yu46X7oX77RdkGWjnh/NT9n9KgtGU9Fbl7u//waD/7v4/Oxns+38X9AGuxLrXm3blOHnFFeCPAnb7E0jRLSuw4hVrNDVdDmKB4lbye6oZoBVItuRKy6ee43yAMaO6k0yhr2SU9HqWSZqKNoX18VZwLeQdRGj9wt1fyf9K/0fhkMQZ6elHveP+H/hng3f3f9/f9/9OyBmK9knyZaXhsDiCgfkYS+rugZZ0xWtRU0g2TwLHmTG54sq8AcyIqPBj4fYJlpI2mpUeLCRjZjbgLSqXzAMtAM2gxVeDGRq3Gt8EvFk6FAqENJraDBslFvqBSobKJVClRMFxrpRQiqLbzpwFr5mCQ10xx802Fu6RBSkZrYE36I3BswgeOD4OOo2jCQcTL4wPD5WKuitNDM/imq/4BsGY2zoo47RTmIGJ04OVKPnCrMym1Xa3NVeV55Rm5vHbTiNTGaZ9fngmj2MhQbG6Nh7w5bHOdRud1UEUpzUF1ZsSWdyHSqzeZoIlWnSyQUhW2nQFlswifmeFNl6M+kLUtXjA1BCyKbnJSF2YcY51vRX3zOayPuZGaAx1HYI5gHZ7qhuRqijGfsucdcEQF8tLX6UjDTz2TaM51r4V0uL9OU0c8PmEQJaM8+sgJRBmMEuTL+GIjMANMty7HlyH+SSZ54AaaRDnN5CMIYhv4HMYjzyH/DZLSZZBkkI4nUUhGXkQxsNoPgrjK7hEuzjJIQrxwYdO8wQM4MZVSNBu7ExJOpzgNrgMozC/8WAc5rHxOUanAcyCNA+H8yhIYTZPZ0lGEH7kxEkcxuMUUciUxHkPUREKyBfcQDYJoshCBXOMPrXxDZPZTRpeTXKYJNGIIPOSOFEYXEZkDYVJDaMgnHowCqbBFbFWCXpJwahtorueEMtCvAB/wzxMYgdrMkziPMWth1mm+YvpdZgRD4I0zExBxmmC7k050SKxTtAuJmsvptTw5kRQxeznGdnGMiJBhL4yY/xaeX8x72lPe9rTT0V/APlm4rcAGAAA","length":1089}}}
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue