diff --git a/.dockerignore b/.dockerignore index 3abf069..3df95af 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,6 +2,7 @@ *.db *.db-shm *.db-wal +results.bin # ---> Go # If you prefer the allow list template instead of the deny list, see community template: diff --git a/.gitignore b/.gitignore index 0e4390f..1f52a82 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.db *.db-shm *.db-wal +results.bin # ---> Go # If you prefer the allow list template instead of the deny list, see community template: diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..27b4d7a --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +golang 1.21.0 diff --git a/Dockerfile b/Dockerfile index f92dd27..b7ca8b0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Load the golang image -FROM golang:1.20.7 as go-builder +FROM golang:1.21.0 as go-builder # Then the node image FROM node:20.5.0 as builder @@ -15,7 +15,6 @@ WORKDIR /go/src/app ENV GOPATH=/go ENV PATH=$GOPATH/bin:/usr/local/go/bin:$PATH ENV GOCACHE=/tmp/.go-build-cache -ENV CGO_ENABLED=0 # This variable communicates to the service that it's running inside # a docker container. ENV ENV_DOCKER=true @@ -51,10 +50,13 @@ WORKDIR /app # Set our runtime environment ENV ENV_DOCKER=true +ENV GOSHORT_PROD=true COPY --from=builder /go/src/app/goshort /usr/local/bin/goshort HEALTHCHECK CMD [ "goshort", "healthcheck" ] +EXPOSE 8080 + ENTRYPOINT [ "goshort" ] CMD [ "serve" ] diff --git a/Makefile b/Makefile index d0a5f14..ee2fe82 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ frontend: VITE_API_URL=/api npm run --prefix frontend build backend: - CGO_ENABLED=0 go build -o goshort goshort.go + go build -o goshort goshort.go all: make frontend diff --git a/cmd/dev/dev.go b/cmd/dev/dev.go index d0200f3..2241611 100644 --- a/cmd/dev/dev.go +++ b/cmd/dev/dev.go @@ -4,6 +4,7 @@ import ( "context" "flag" "fmt" + "log/slog" "net" "net/http" @@ -16,9 +17,11 @@ import ( servermiddleware "git.maronato.dev/maronato/goshort/internal/server/middleware" shortserver "git.maronato.dev/maronato/goshort/internal/server/short" shortservice "git.maronato.dev/maronato/goshort/internal/service/short" + shortlogservice "git.maronato.dev/maronato/goshort/internal/service/shortlog" tokenservice "git.maronato.dev/maronato/goshort/internal/service/token" userservice "git.maronato.dev/maronato/goshort/internal/service/user" handlerutils "git.maronato.dev/maronato/goshort/internal/util/handler" + "git.maronato.dev/maronato/goshort/internal/util/logging" "github.com/go-chi/chi/v5" "github.com/go-chi/cors" "github.com/peterbourgon/ff/v3/ffcli" @@ -50,6 +53,9 @@ func New(cfg *config.Config) *ffcli.Command { } func exec(ctx context.Context, cfg *config.Config) error { + l := logging.FromCtx(ctx) + l.Debug("Executing dev command", slog.Any("config", cfg)) + eg, egCtx := errgroup.WithContext(ctx) // Start the API server @@ -84,11 +90,16 @@ func serveAPI(ctx context.Context, cfg *config.Config) error { shortService := shortservice.NewShortService(storage) userService := userservice.NewUserService(cfg, storage) tokenService := tokenservice.NewTokenService(storage) + shortLogService := shortlogservice.NewShortLogService(storage) + + // Start short log worker + stopWorker := shortLogService.StartWorker(ctx) + defer stopWorker() // Create handlers - apiHandler := apiserver.NewAPIHandler(shortService, userService, tokenService) - shortHandler := shortserver.NewShortHandler(shortService) - healthcheckHandler := healthcheckserver.NewHealthcheckHandler() + apiHandler := apiserver.NewAPIHandler(shortService, userService, tokenService, shortLogService) + shortHandler := shortserver.NewShortHandler(shortService, shortLogService) + healthcheckHandler := healthcheckserver.NewHealthcheckHandler(storage) // Create routers apiRouter := apiserver.NewAPIRouter(apiHandler) @@ -105,7 +116,7 @@ func serveAPI(ctx context.Context, cfg *config.Config) error { AllowedOrigins: []string{ "http://" + net.JoinHostPort(cfg.Host, cfg.UIPort), }, - AllowedMethods: []string{"GET", "POST", "DELETE", "OPTIONS"}, + AllowedMethods: []string{"GET", "POST", "PATCH", "DELETE", "OPTIONS"}, AllowCredentials: true, })) diff --git a/cmd/healthcheck/healthcheck.go b/cmd/healthcheck/healthcheck.go index 89eb6ef..2b2590c 100644 --- a/cmd/healthcheck/healthcheck.go +++ b/cmd/healthcheck/healthcheck.go @@ -4,12 +4,14 @@ import ( "context" "flag" "fmt" + "log/slog" "net" "net/http" "net/url" "git.maronato.dev/maronato/goshort/cmd/shared" "git.maronato.dev/maronato/goshort/internal/config" + "git.maronato.dev/maronato/goshort/internal/util/logging" "github.com/peterbourgon/ff/v3/ffcli" ) @@ -38,6 +40,9 @@ func New(cfg *config.Config) *ffcli.Command { // If the request fails, return an error // Otherwise, return nil. func exec(ctx context.Context, cfg *config.Config) error { + l := logging.FromCtx(ctx) + l.Debug("Executing healthcheck command", slog.Any("config", cfg)) + addr := url.URL{ Host: net.JoinHostPort(cfg.Host, cfg.Port), Scheme: "http", diff --git a/cmd/main.go b/cmd/main.go index 51da6d9..4cad4f3 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -12,6 +12,7 @@ import ( healthcheckcmd "git.maronato.dev/maronato/goshort/cmd/healthcheck" servecmd "git.maronato.dev/maronato/goshort/cmd/serve" "git.maronato.dev/maronato/goshort/internal/config" + "git.maronato.dev/maronato/goshort/internal/util/logging" "github.com/peterbourgon/ff/v3/ffcli" ) @@ -29,6 +30,7 @@ func Run() { } // Look for the env ENV_DOCKER=true to disable the dev command + // since the docker image won't have node installed. if os.Getenv("ENV_DOCKER") != "true" { rootCmd.Subcommands = append(rootCmd.Subcommands, devcmd.New(cfg)) } @@ -45,6 +47,10 @@ func Run() { os.Exit(1) } + // Create system logger + l := logging.NewLogger(cfg) + ctx = logging.WithLogger(ctx, l) + // Run the command. if err := rootCmd.Run(ctx); err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) diff --git a/cmd/serve/serve.go b/cmd/serve/serve.go index f7cc9c4..3f205bb 100644 --- a/cmd/serve/serve.go +++ b/cmd/serve/serve.go @@ -4,6 +4,7 @@ import ( "context" "flag" "fmt" + "log/slog" "git.maronato.dev/maronato/goshort/cmd/shared" "git.maronato.dev/maronato/goshort/internal/config" @@ -14,9 +15,11 @@ import ( shortserver "git.maronato.dev/maronato/goshort/internal/server/short" staticssterver "git.maronato.dev/maronato/goshort/internal/server/static" shortservice "git.maronato.dev/maronato/goshort/internal/service/short" + shortlogservice "git.maronato.dev/maronato/goshort/internal/service/shortlog" tokenservice "git.maronato.dev/maronato/goshort/internal/service/token" userservice "git.maronato.dev/maronato/goshort/internal/service/user" handlerutils "git.maronato.dev/maronato/goshort/internal/util/handler" + "git.maronato.dev/maronato/goshort/internal/util/logging" "github.com/go-chi/chi/v5" "github.com/peterbourgon/ff/v3/ffcli" ) @@ -27,6 +30,7 @@ func New(cfg *config.Config) *ffcli.Command { shared.RegisterBaseFlags(fs, cfg) shared.RegisterServerFlags(fs, cfg) + fs.BoolVar(&cfg.Prod, "prod", config.DefaultProd, "run in production mode") // Create the command and options cmd := shared.NewCommand(cfg, exec) @@ -44,6 +48,9 @@ func New(cfg *config.Config) *ffcli.Command { } func exec(ctx context.Context, cfg *config.Config) error { + l := logging.FromCtx(ctx) + l.Debug("Executing serve command", slog.Any("config", cfg)) + // Create the new server server := server.NewServer(cfg) @@ -58,12 +65,17 @@ func exec(ctx context.Context, cfg *config.Config) error { shortService := shortservice.NewShortService(storage) userService := userservice.NewUserService(cfg, storage) tokenService := tokenservice.NewTokenService(storage) + shortLogService := shortlogservice.NewShortLogService(storage) + + // Start short log worker + stopWorker := shortLogService.StartWorker(ctx) + defer stopWorker() // Create handlers - apiHandler := apiserver.NewAPIHandler(shortService, userService, tokenService) - shortHandler := shortserver.NewShortHandler(shortService) + apiHandler := apiserver.NewAPIHandler(shortService, userService, tokenService, shortLogService) + shortHandler := shortserver.NewShortHandler(shortService, shortLogService) staticHandler := staticssterver.NewStaticHandler(cfg) - healthcheckHandler := healthcheckserver.NewHealthcheckHandler() + healthcheckHandler := healthcheckserver.NewHealthcheckHandler(storage) // Create routers apiRouter := apiserver.NewAPIRouter(apiHandler) diff --git a/cmd/shared/shared.go b/cmd/shared/shared.go index e91c74f..5026e02 100644 --- a/cmd/shared/shared.go +++ b/cmd/shared/shared.go @@ -41,6 +41,7 @@ func RegisterBaseFlags(fs *flag.FlagSet, cfg *config.Config) { fs.BoolVar(&cfg.Debug, "debug", config.DefaultDebug, "enable debug mode") var defaultHost = config.DefaultHost if os.Getenv("ENV_DOCKER") == "true" { + // This is a QOL hack to allow docker to bind the port without manually specifying the host defaultHost = "0.0.0.0" } fs.StringVar(&cfg.Host, "host", defaultHost, "host to listen on") @@ -59,7 +60,6 @@ func RegisterServerFlags(fs *flag.FlagSet, cfg *config.Config) { func InitStorage(cfg *config.Config) storage.Storage { switch cfg.DBType { case config.DBTypeMemory: - cfg.DBURL = ":memory:" return sqlitestorage.NewSQLiteStorage(cfg) case config.DBTypeSQLite: return sqlitestorage.NewSQLiteStorage(cfg) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b66d17b..6bb1c8e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -14,12 +14,13 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.15.0", - "react-use": "^17.4.0" + "ua-parser-js": "^1.0.35" }, "devDependencies": { "@marolint/eslint-config-react": "^1.0.2", "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", + "@types/ua-parser-js": "^0.7.36", "@vitejs/plugin-react-swc": "^3.3.2", "autoprefixer": "^10.4.15", "eslint": "^8.47.0", @@ -55,6 +56,7 @@ "version": "7.22.10", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.10.tgz", "integrity": "sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ==", + "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -856,11 +858,6 @@ "node": ">=10" } }, - "node_modules/@types/js-cookie": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-2.2.7.tgz", - "integrity": "sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==" - }, "node_modules/@types/json-schema": { "version": "7.0.12", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", @@ -911,6 +908,12 @@ "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", "dev": true }, + "node_modules/@types/ua-parser-js": { + "version": "0.7.36", + "resolved": "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz", + "integrity": "sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", @@ -1133,11 +1136,6 @@ "vite": "^4" } }, - "node_modules/@xobotyi/scrollbar-width": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz", - "integrity": "sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==" - }, "node_modules/acorn": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", @@ -1668,14 +1666,6 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/copy-to-clipboard": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", - "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", - "dependencies": { - "toggle-selection": "^1.0.6" - } - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1690,26 +1680,6 @@ "node": ">= 8" } }, - "node_modules/css-in-js-utils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz", - "integrity": "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==", - "dependencies": { - "hyphenate-style-name": "^1.0.3" - } - }, - "node_modules/css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -1725,7 +1695,8 @@ "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", + "dev": true }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -1829,14 +1800,6 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, - "node_modules/error-stack-parser": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", - "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", - "dependencies": { - "stackframe": "^1.3.4" - } - }, "node_modules/es-abstract": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", @@ -2434,7 +2397,8 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true }, "node_modules/fast-diff": { "version": "1.3.0", @@ -2482,21 +2446,6 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, - "node_modules/fast-loops": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fast-loops/-/fast-loops-1.1.3.tgz", - "integrity": "sha512-8EZzEP0eKkEEVX+drtd9mtuQ+/QrlfW/5MlwcwK5Nds6EkZ/tRzEexkzUY2mIssnAyVLT+TKHuRXmFNNXYUd6g==" - }, - "node_modules/fast-shallow-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz", - "integrity": "sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw==" - }, - "node_modules/fastest-stable-stringify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fastest-stable-stringify/-/fastest-stable-stringify-2.0.2.tgz", - "integrity": "sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q==" - }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -2852,11 +2801,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hyphenate-style-name": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", - "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" - }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -2907,15 +2851,6 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "node_modules/inline-style-prefixer": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-6.0.4.tgz", - "integrity": "sha512-FwXmZC2zbeeS7NzGjJ6pAiqRhXR0ugUShSNb6GApMl6da0/XGc4MOJsoWAywia52EEWbXNSy0pzkwz/+Y+swSg==", - "dependencies": { - "css-in-js-utils": "^3.1.0", - "fast-loops": "^1.1.3" - } - }, "node_modules/internal-slot": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", @@ -3290,11 +3225,6 @@ "jiti": "bin/jiti.js" } }, - "node_modules/js-cookie": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", - "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==" - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3438,11 +3368,6 @@ "node": ">=10" } }, - "node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -3503,25 +3428,6 @@ "thenify-all": "^1.0.0" } }, - "node_modules/nano-css": { - "version": "5.3.5", - "resolved": "https://registry.npmjs.org/nano-css/-/nano-css-5.3.5.tgz", - "integrity": "sha512-vSB9X12bbNu4ALBu7nigJgRViZ6ja3OU7CeuiV1zMIbXOdmkLahgtPmh3GBOlDxbKY0CitqlPdOReGlBLSp+yg==", - "dependencies": { - "css-tree": "^1.1.2", - "csstype": "^3.0.6", - "fastest-stable-stringify": "^2.0.2", - "inline-style-prefixer": "^6.0.0", - "rtl-css-js": "^1.14.0", - "sourcemap-codec": "^1.4.8", - "stacktrace-js": "^2.0.2", - "stylis": "^4.0.6" - }, - "peerDependencies": { - "react": "*", - "react-dom": "*" - } - }, "node_modules/nanoid": { "version": "3.3.6", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", @@ -4115,45 +4021,6 @@ "react-dom": ">=16.8" } }, - "node_modules/react-universal-interface": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/react-universal-interface/-/react-universal-interface-0.6.2.tgz", - "integrity": "sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==", - "peerDependencies": { - "react": "*", - "tslib": "*" - } - }, - "node_modules/react-use": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/react-use/-/react-use-17.4.0.tgz", - "integrity": "sha512-TgbNTCA33Wl7xzIJegn1HndB4qTS9u03QUwyNycUnXaweZkE4Kq2SB+Yoxx8qbshkZGYBDvUXbXWRUmQDcZZ/Q==", - "dependencies": { - "@types/js-cookie": "^2.2.6", - "@xobotyi/scrollbar-width": "^1.9.5", - "copy-to-clipboard": "^3.3.1", - "fast-deep-equal": "^3.1.3", - "fast-shallow-equal": "^1.0.0", - "js-cookie": "^2.2.1", - "nano-css": "^5.3.1", - "react-universal-interface": "^0.6.2", - "resize-observer-polyfill": "^1.5.1", - "screenfull": "^5.1.0", - "set-harmonic-interval": "^1.0.1", - "throttle-debounce": "^3.0.1", - "ts-easing": "^0.2.0", - "tslib": "^2.1.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-use/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -4198,7 +4065,8 @@ "node_modules/regenerator-runtime": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "dev": true }, "node_modules/regexp.prototype.flags": { "version": "1.5.0", @@ -4217,11 +4085,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resize-observer-polyfill": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", - "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" - }, "node_modules/resolve": { "version": "1.22.4", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", @@ -4289,14 +4152,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/rtl-css-js": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz", - "integrity": "sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==", - "dependencies": { - "@babel/runtime": "^7.1.2" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -4360,17 +4215,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/screenfull": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/screenfull/-/screenfull-5.2.0.tgz", - "integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==", - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -4386,14 +4230,6 @@ "node": ">=10" } }, - "node_modules/set-harmonic-interval": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz", - "integrity": "sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==", - "engines": { - "node": ">=6.9" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -4438,14 +4274,6 @@ "node": ">=8" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -4455,52 +4283,6 @@ "node": ">=0.10.0" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead" - }, - "node_modules/stack-generator": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.10.tgz", - "integrity": "sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==", - "dependencies": { - "stackframe": "^1.3.4" - } - }, - "node_modules/stackframe": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", - "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==" - }, - "node_modules/stacktrace-gps": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/stacktrace-gps/-/stacktrace-gps-3.1.2.tgz", - "integrity": "sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ==", - "dependencies": { - "source-map": "0.5.6", - "stackframe": "^1.3.4" - } - }, - "node_modules/stacktrace-gps/node_modules/source-map": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stacktrace-js": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stacktrace-js/-/stacktrace-js-2.0.2.tgz", - "integrity": "sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==", - "dependencies": { - "error-stack-parser": "^2.0.6", - "stack-generator": "^2.0.5", - "stacktrace-gps": "^3.0.4" - } - }, "node_modules/string.prototype.matchall": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", @@ -4598,11 +4380,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/stylis": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.0.tgz", - "integrity": "sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ==" - }, "node_modules/sucrase": { "version": "3.34.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", @@ -4733,14 +4510,6 @@ "node": ">=0.8" } }, - "node_modules/throttle-debounce": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-3.0.1.tgz", - "integrity": "sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==", - "engines": { - "node": ">=10" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -4753,16 +4522,6 @@ "node": ">=8.0" } }, - "node_modules/toggle-selection": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", - "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" - }, - "node_modules/ts-easing": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/ts-easing/-/ts-easing-0.2.0.tgz", - "integrity": "sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==" - }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", @@ -4784,7 +4543,8 @@ "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true }, "node_modules/tsutils": { "version": "3.21.0", @@ -4903,6 +4663,24 @@ "node": ">=14.17" } }, + "node_modules/ua-parser-js": { + "version": "1.0.35", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.35.tgz", + "integrity": "sha512-fKnGuqmTBnIE+/KXSzCn4db8RTigUzw1AN0DmdU6hJovUTbYJKyqj+8Mt1c4VfRDnOVJnENmfYkIPZ946UrSAA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "engines": { + "node": "*" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 820e47f..f63e079 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,12 +16,13 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.15.0", - "react-use": "^17.4.0" + "ua-parser-js": "^1.0.35" }, "devDependencies": { "@marolint/eslint-config-react": "^1.0.2", "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", + "@types/ua-parser-js": "^0.7.36", "@vitejs/plugin-react-swc": "^3.3.2", "autoprefixer": "^10.4.15", "eslint": "^8.47.0", diff --git a/frontend/public/adjectives.txt b/frontend/public/adjectives.txt new file mode 100644 index 0000000..c669f0c --- /dev/null +++ b/frontend/public/adjectives.txt @@ -0,0 +1,153 @@ +ancient +antique +aquatic +baby +basic +big +bitter +black +blue +bottle +bottled +brave +breezy +bright +brown +calm +charming +cheerful +chummy +classy +clear +clever +cloudy +cold +cool +crispy +curly +daily +deep +delightful +dizzy +down +dynamic +elated +elegant +excited +exotic +fancy +fast +fearless +festive +fluffy +fragile +fresh +friendly +funny +fuzzy +gentle +gifted +gigantic +graceful +grand +grateful +great +green +happy +heavy +helpful +hot +hungry +husky +icy +imaginary +invisible +jagged +jolly +joyful +joyous +kind +large +light +little +lively +lovely +lucky +lumpy +magical +manic +melodic +mighty +misty +modern +narrow +new +nifty +noisy +normal +odd +old +orange +ordinary +painless +pastel +peaceful +perfect +phobic +pink +polite +precious +pretty +purple +quaint +quick +quiet +rapid +red +rocky +rough +round +royal +rugged +rustic +safe +sandy +shiny +silent +silky +silly +slender +slow +small +smiling +smooth +snug +soft +sour +strange +strong +sunny +sweet +swift +thirsty +thoughtful +tiny +uneven +unusual +vanilla +vast +violet +warm +watery +weak +white +wide +wild +wilde +windy +wise +witty +wonderful +yellow +young +zany diff --git a/frontend/public/nouns.txt b/frontend/public/nouns.txt new file mode 100644 index 0000000..552ff76 --- /dev/null +++ b/frontend/public/nouns.txt @@ -0,0 +1,136 @@ +airplane +apple +automobile +ball +balloon +banana +beach +bird +boat +boot +bottle +box +breeze +bug +bush +butter +canoe +carrot +cartoon +cello +chair +cheese +coast +coconut +comet +cream +curtain +daisy +desk +diamond +door +earth +elephant +emerald +fire +flamingo +flower +flute +forest +free +giant +giraffe +glove +grape +grasshopper +hair +hat +hill +house +ink +iris +jade +jungle +kangaroo +kayak +lake +lemon +lightning +lion +lotus +lump +mango +mint +monkey +moon +motorcycle +mountain +nest +oboe +ocean +octopus +onion +orange +orchestra +owl +path +penguin +phoenix +piano +pineapple +planet +pond +potato +prairie +quail +rabbit +raccoon +raid +rain +raven +river +road +rosebud +ruby +sea +ship +shoe +shore +shrub +sitter +skates +sky +socks +sparrow +spider +squash +squirrel +star +stream +street +sun +table +teapot +terrain +tiger +toast +tomato +trail +train +tree +truck +trumpet +tuba +tulip +umbrella +unicorn +unit +valley +vase +violet +violin +water +wind +window +zebra +zoo diff --git a/frontend/src/components/ItemList.tsx b/frontend/src/components/ItemList.tsx index 2c1631c..d721314 100644 --- a/frontend/src/components/ItemList.tsx +++ b/frontend/src/components/ItemList.tsx @@ -10,7 +10,6 @@ const ItemList = , K extends keyof T>({ idKey: K Item: FunctionComponent }) => { - console.log("list") return ( <>