Simplify whitelabel setup

This commit is contained in:
rxdn 2024-06-18 23:00:34 +01:00
parent 42111df1c6
commit fd5ff3331d
11 changed files with 512 additions and 580 deletions

View File

@ -0,0 +1,20 @@
package api
import (
"github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/utils"
"github.com/gin-gonic/gin"
"net/http"
)
func WhitelabelDelete(ctx *gin.Context) {
userId := ctx.Keys["userid"].(uint64)
// Check if this is a different token
if err := database.Client.Whitelabel.Delete(userId); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
ctx.Status(http.StatusNoContent)
}

View File

@ -2,6 +2,7 @@ package api
import (
"context"
"errors"
"fmt"
"github.com/TicketsBot/GoPanel/botcontext"
"github.com/TicketsBot/GoPanel/database"
@ -34,45 +35,50 @@ func GetWhitelabelCreateInteractions() func(*gin.Context) {
return
}
if err := createInteractions(cm, bot.BotId, bot.Token); err != nil {
if errors.Is(err, ErrInteractionCreateCooldown) {
ctx.JSON(400, utils.ErrorJson(err))
} else {
ctx.JSON(500, utils.ErrorJson(err))
}
return
}
ctx.JSON(200, utils.SuccessResponse)
}
}
var ErrInteractionCreateCooldown = errors.New("Interaction creation on cooldown")
func createInteractions(cm *manager.CommandManager, botId uint64, token string) error {
// Cooldown
key := fmt.Sprintf("tickets:interaction-create-cooldown:%d", bot.BotId)
key := fmt.Sprintf("tickets:interaction-create-cooldown:%d", botId)
// try to set first, prevent race condition
wasSet, err := redis.Client.SetNX(redis.DefaultContext(), key, 1, time.Minute).Result()
if err != nil {
ctx.JSON(500, gin.H{
"success": false,
"error": err.Error(),
})
return
return err
}
// on cooldown, tell user how long left
if !wasSet {
expiration, err := redis.Client.TTL(redis.DefaultContext(), key).Result()
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
return err
}
ctx.JSON(400, utils.ErrorStr(fmt.Sprintf("Interaction creation on cooldown, please wait another %d seconds", int64(expiration.Seconds()))))
return
return fmt.Errorf("%w, please wait another %d seconds", ErrInteractionCreateCooldown, int64(expiration.Seconds()))
}
botContext, err := botcontext.ContextForGuild(0)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
return err
}
commands, _ := cm.BuildCreatePayload(true, nil)
// TODO: Use proper context
if _, err = rest.ModifyGlobalCommands(context.Background(), bot.Token, botContext.RateLimiter, bot.BotId, commands); err == nil {
ctx.JSON(200, utils.SuccessResponse)
} else {
ctx.JSON(500, utils.ErrorJson(err))
}
}
_, err = rest.ModifyGlobalCommands(context.Background(), token, botContext.RateLimiter, botId, commands)
return err
}

View File

@ -1,14 +1,18 @@
package api
import (
"context"
"github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/utils"
"github.com/gin-gonic/gin"
"github.com/rxdn/gdl/objects/user"
"github.com/rxdn/gdl/rest"
)
type whitelabelResponse struct {
Id uint64 `json:"id,string"`
PublicKey string `json:"public_key"`
Username string `json:"username"`
statusUpdateBody
}
@ -27,6 +31,13 @@ func WhitelabelGet(ctx *gin.Context) {
return
}
// Get public key
publicKey, err := database.Client.WhitelabelKeys.Get(bot.BotId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
// Get status
status, statusType, _, err := database.Client.WhitelabelStatuses.Get(bot.BotId)
if err != nil {
@ -34,11 +45,25 @@ func WhitelabelGet(ctx *gin.Context) {
return
}
username := getBotUsername(context.Background(), bot.Token)
ctx.JSON(200, whitelabelResponse{
Id: bot.BotId,
PublicKey: publicKey,
Username: username,
statusUpdateBody: statusUpdateBody{ // Zero values if no status is fine
Status: status,
StatusType: user.ActivityType(statusType),
},
})
}
func getBotUsername(ctx context.Context, token string) string {
user, err := rest.GetCurrentUser(ctx, token, nil)
if err != nil {
// TODO: Log error
return "Unknown User"
}
return user.Username
}

View File

@ -1,48 +0,0 @@
package api
import (
"github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/utils"
"github.com/gin-gonic/gin"
)
func WhitelabelGetPublicKey(ctx *gin.Context) {
type data struct {
PublicKey string `json:"public_key"`
}
userId := ctx.Keys["userid"].(uint64)
// Get bot
bot, err := database.Client.Whitelabel.GetByUserId(userId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
// Ensure bot exists
if bot.BotId == 0 {
ctx.JSON(404, gin.H{
"success": false,
"error": "No bot found",
})
return
}
key, err := database.Client.WhitelabelKeys.Get(bot.BotId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
if key == "" {
ctx.JSON(404, gin.H{
"success": false,
})
} else {
ctx.JSON(200, gin.H{
"success": true,
"key": key,
})
}
}

View File

@ -3,22 +3,34 @@ package api
import (
"context"
"encoding/base64"
"fmt"
dbclient "github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/redis"
"github.com/TicketsBot/GoPanel/utils"
"github.com/TicketsBot/common/tokenchange"
"github.com/TicketsBot/common/whitelabeldelete"
"github.com/TicketsBot/database"
"github.com/TicketsBot/worker/bot/command/manager"
"github.com/gin-gonic/gin"
"github.com/rxdn/gdl/objects/application"
"github.com/rxdn/gdl/rest"
"strconv"
"strings"
)
func WhitelabelPost(ctx *gin.Context) {
func WhitelabelPost() func(*gin.Context) {
cm := new(manager.CommandManager)
cm.RegisterCommands()
return func(ctx *gin.Context) {
userId := ctx.Keys["userid"].(uint64)
type whitelabelPostBody struct {
Token string `json:"token"`
}
// Get token
var data map[string]interface{}
var data whitelabelPostBody
if err := ctx.BindJSON(&data); err != nil {
ctx.JSON(400, gin.H{
"success": false,
@ -27,35 +39,12 @@ func WhitelabelPost(ctx *gin.Context) {
return
}
token, ok := data["token"].(string)
if !ok || token == "" {
ctx.JSON(400, utils.ErrorStr("Missing token"))
return
}
if !validateToken(token) {
ctx.JSON(400, utils.ErrorStr("Invalid token"))
return
}
// Validate token + get bot ID
// TODO: Use proper context
bot, err := rest.GetCurrentUser(context.Background(), token, nil)
bot, err := fetchApplication(data.Token)
if err != nil {
ctx.JSON(400, utils.ErrorJson(err))
return
}
if bot.Id == 0 {
ctx.JSON(400, utils.ErrorStr("Invalid token"))
return
}
if !bot.Bot {
ctx.JSON(400, utils.ErrorStr("Token is not of a bot user"))
return
}
// Check if this is a different token
existing, err := dbclient.Client.Whitelabel.GetByUserId(userId)
if err != nil {
@ -63,19 +52,58 @@ func WhitelabelPost(ctx *gin.Context) {
return
}
if err = dbclient.Client.Whitelabel.Set(database.WhitelabelBot{
// Take existing whitelabel bot offline, if it is a different bot
if existing.BotId != 0 && existing.BotId != bot.Id {
whitelabeldelete.Publish(redis.Client.Client, existing.BotId)
}
// Set token in DB so that http-gateway can use it when Discord validates the interactions endpoint
// TODO: Use a transaction
if err := dbclient.Client.Whitelabel.Set(database.WhitelabelBot{
UserId: userId,
BotId: bot.Id,
Token: token,
Token: data.Token,
}); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
if err := dbclient.Client.WhitelabelKeys.Set(bot.Id, bot.VerifyKey); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
// Set intents
var currentFlags application.Flag = 0
if bot.Flags != nil {
currentFlags = *bot.Flags
}
editData := rest.EditCurrentApplicationData{
Flags: utils.Ptr(application.BuildFlags(
currentFlags,
application.FlagIntentGatewayGuildMembersLimited,
application.FlagGatewayMessageContentLimited,
)),
// TODO: Don't hardcode URL
InteractionsEndpointUrl: utils.Ptr(fmt.Sprintf("https://gateway.ticketsbot.net/handle/%d", bot.InteractionsEndpointUrl)),
}
if _, err := rest.EditCurrentApplication(context.Background(), data.Token, nil, editData); err != nil {
// TODO: Use a transaction
if err := dbclient.Client.Whitelabel.Delete(bot.Id); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
ctx.JSON(500, utils.ErrorJson(err))
return
}
tokenChangeData := tokenchange.TokenChangeData{
Token: token,
Token: data.Token,
NewId: bot.Id,
OldId: existing.BotId,
OldId: 0,
}
if err := tokenchange.PublishTokenChange(redis.Client.Client, tokenChangeData); err != nil {
@ -83,10 +111,16 @@ func WhitelabelPost(ctx *gin.Context) {
return
}
if err := createInteractions(cm, bot.Id, data.Token); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
ctx.JSON(200, gin.H{
"success": true,
"bot": bot,
})
}
}
func validateToken(token string) bool {
@ -115,3 +149,22 @@ func validateToken(token string) bool {
return true
}
func fetchApplication(token string) (*application.Application, error) {
if !validateToken(token) {
return nil, fmt.Errorf("Invalid token")
}
// Validate token + get bot ID
// TODO: Use proper context
app, err := rest.GetCurrentApplication(context.Background(), token, nil)
if err != nil {
return nil, err
}
if app.Id == 0 {
return nil, fmt.Errorf("Invalid token")
}
return &app, nil
}

View File

@ -1,60 +0,0 @@
package api
import (
"encoding/hex"
"github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/utils"
"github.com/gin-gonic/gin"
)
func WhitelabelPostPublicKey(ctx *gin.Context) {
type data struct {
PublicKey string `json:"public_key"`
}
userId := ctx.Keys["userid"].(uint64)
// Get bot
bot, err := database.Client.Whitelabel.GetByUserId(userId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
// Ensure bot exists
if bot.BotId == 0 {
ctx.JSON(404, gin.H{
"success": false,
"error": "No bot found",
})
return
}
// Parse status
var body data
if err := ctx.BindJSON(&body); err != nil {
ctx.JSON(400, gin.H{
"success": false,
"error": "No public key provided",
})
return
}
bytes, err := hex.DecodeString(body.PublicKey)
if err != nil || len(bytes) != 32 {
ctx.JSON(400, gin.H{
"success": false,
"error": "Invalid public key",
})
return
}
if err := database.Client.WhitelabelKeys.Set(bot.BotId, body.PublicKey); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
ctx.JSON(200, gin.H{
"success": true,
})
}

View File

@ -197,11 +197,10 @@ func StartServer(sm *livechat.SocketManager) {
whitelabelGroup.GET("/", api_whitelabel.WhitelabelGet)
whitelabelGroup.GET("/errors", api_whitelabel.WhitelabelGetErrors)
whitelabelGroup.GET("/guilds", api_whitelabel.WhitelabelGetGuilds)
whitelabelGroup.GET("/public-key", api_whitelabel.WhitelabelGetPublicKey)
whitelabelGroup.POST("/public-key", api_whitelabel.WhitelabelPostPublicKey)
whitelabelGroup.POST("/create-interactions", api_whitelabel.GetWhitelabelCreateInteractions())
whitelabelGroup.DELETE("/", api_whitelabel.WhitelabelDelete)
whitelabelGroup.POST("/", rl(middleware.RateLimitTypeUser, 10, time.Minute), api_whitelabel.WhitelabelPost)
whitelabelGroup.POST("/", rl(middleware.RateLimitTypeUser, 5, time.Minute), api_whitelabel.WhitelabelPost())
whitelabelGroup.POST("/status", rl(middleware.RateLimitTypeUser, 1, time.Second*5), api_whitelabel.WhitelabelStatusPost)
}
}

View File

@ -11,7 +11,7 @@
"axios": "^0.21.4",
"sirv-cli": "^1.0.0",
"svelte-emoji-selector": "^1.0.1",
"svelte-router-spa": "^6.0.2",
"svelte-router-spa": "^6.0.3",
"svelte-select": "^5.6.1",
"svelte-tooltip": "^1.2.0"
},
@ -28,7 +28,7 @@
"rollup-plugin-livereload": "^2.0.0",
"rollup-plugin-svelte": "^7.1.0",
"rollup-plugin-terser": "^7.0.0",
"svelte": "^3.48.0",
"svelte": "^3.59.2",
"svelte-toggle": "^3.1.0"
}
},
@ -46,12 +46,13 @@
}
},
"node_modules/@babel/code-frame": {
"version": "7.21.4",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
"integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
"integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==",
"dev": true,
"dependencies": {
"@babel/highlight": "^7.18.6"
"@babel/highlight": "^7.24.7",
"picocolors": "^1.0.0"
},
"engines": {
"node": ">=6.9.0"
@ -97,14 +98,14 @@
}
},
"node_modules/@babel/generator": {
"version": "7.21.4",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz",
"integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz",
"integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==",
"dev": true,
"dependencies": {
"@babel/types": "^7.21.4",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"@babel/types": "^7.24.7",
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^2.5.1"
},
"engines": {
@ -211,10 +212,13 @@
}
},
"node_modules/@babel/helper-environment-visitor": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
"integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz",
"integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==",
"dev": true,
"dependencies": {
"@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
}
@ -232,25 +236,25 @@
}
},
"node_modules/@babel/helper-function-name": {
"version": "7.21.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz",
"integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz",
"integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==",
"dev": true,
"dependencies": {
"@babel/template": "^7.20.7",
"@babel/types": "^7.21.0"
"@babel/template": "^7.24.7",
"@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-hoist-variables": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
"integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz",
"integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==",
"dev": true,
"dependencies": {
"@babel/types": "^7.18.6"
"@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
@ -374,30 +378,30 @@
}
},
"node_modules/@babel/helper-split-export-declaration": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
"integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz",
"integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==",
"dev": true,
"dependencies": {
"@babel/types": "^7.18.6"
"@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.19.4",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
"integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz",
"integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.19.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
"integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
"dev": true,
"engines": {
"node": ">=6.9.0"
@ -442,23 +446,24 @@
}
},
"node_modules/@babel/highlight": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
"integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz",
"integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==",
"dev": true,
"dependencies": {
"@babel/helper-validator-identifier": "^7.18.6",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
"@babel/helper-validator-identifier": "^7.24.7",
"chalk": "^2.4.2",
"js-tokens": "^4.0.0",
"picocolors": "^1.0.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
"version": "7.21.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz",
"integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz",
"integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
@ -1529,34 +1534,34 @@
}
},
"node_modules/@babel/template": {
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
"integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz",
"integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.18.6",
"@babel/parser": "^7.20.7",
"@babel/types": "^7.20.7"
"@babel/code-frame": "^7.24.7",
"@babel/parser": "^7.24.7",
"@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.21.4",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz",
"integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz",
"integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.21.4",
"@babel/generator": "^7.21.4",
"@babel/helper-environment-visitor": "^7.18.9",
"@babel/helper-function-name": "^7.21.0",
"@babel/helper-hoist-variables": "^7.18.6",
"@babel/helper-split-export-declaration": "^7.18.6",
"@babel/parser": "^7.21.4",
"@babel/types": "^7.21.4",
"debug": "^4.1.0",
"@babel/code-frame": "^7.24.7",
"@babel/generator": "^7.24.7",
"@babel/helper-environment-visitor": "^7.24.7",
"@babel/helper-function-name": "^7.24.7",
"@babel/helper-hoist-variables": "^7.24.7",
"@babel/helper-split-export-declaration": "^7.24.7",
"@babel/parser": "^7.24.7",
"@babel/types": "^7.24.7",
"debug": "^4.3.1",
"globals": "^11.1.0"
},
"engines": {
@ -1564,13 +1569,13 @@
}
},
"node_modules/@babel/types": {
"version": "7.21.4",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz",
"integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz",
"integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==",
"dev": true,
"dependencies": {
"@babel/helper-string-parser": "^7.19.4",
"@babel/helper-validator-identifier": "^7.19.1",
"@babel/helper-string-parser": "^7.24.7",
"@babel/helper-validator-identifier": "^7.24.7",
"to-fast-properties": "^2.0.0"
},
"engines": {
@ -1624,14 +1629,14 @@
}
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
"dev": true,
"dependencies": {
"@jridgewell/set-array": "^1.0.1",
"@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.9"
"@jridgewell/trace-mapping": "^0.3.24"
},
"engines": {
"node": ">=6.0.0"
@ -1647,9 +1652,9 @@
}
},
"node_modules/@jridgewell/set-array": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"dev": true,
"engines": {
"node": ">=6.0.0"
@ -1672,21 +1677,15 @@
"dev": true
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.18",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz",
"integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==",
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dev": true,
"dependencies": {
"@jridgewell/resolve-uri": "3.1.0",
"@jridgewell/sourcemap-codec": "1.4.14"
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.14",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
"dev": true
},
"node_modules/@polka/url": {
"version": "1.0.0-next.15",
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.15.tgz",
@ -1944,12 +1943,12 @@
}
},
"node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"dependencies": {
"fill-range": "^7.0.1"
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@ -2225,9 +2224,9 @@
"integrity": "sha512-RqBOWwt7sc+ta9GFjbu5GOwKFRzn3rMPPSqvSGpIwsfVnpMjiI5ttv84lwNsCMEYI6/lu/iH21HUcE3TLz8RGQ=="
},
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
@ -2237,9 +2236,9 @@
}
},
"node_modules/follow-redirects": {
"version": "1.14.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"funding": [
{
"type": "individual",
@ -3094,9 +3093,9 @@
}
},
"node_modules/svelte": {
"version": "3.58.0",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.58.0.tgz",
"integrity": "sha512-brIBNNB76mXFmU/Kerm4wFnkskBbluBDCjx/8TcpYRb298Yh2dztS2kQ6bhtjMcvUhd5ynClfwpz5h2gnzdQ1A==",
"version": "3.59.2",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.2.tgz",
"integrity": "sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==",
"engines": {
"node": ">= 8"
}
@ -3130,9 +3129,9 @@
}
},
"node_modules/svelte-router-spa": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/svelte-router-spa/-/svelte-router-spa-6.0.2.tgz",
"integrity": "sha512-ySs/2TnjdLnvo0tHfdJsRPhPl0Mj4/h2qi0Zb8t4zC+BBBaCr6cZc7MtRfgzD4IMp80Nqe7ZXd/hCJuHSGtf5A==",
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/svelte-router-spa/-/svelte-router-spa-6.0.3.tgz",
"integrity": "sha512-aHgyUVVI/WjipQNmKcXpX0hFZtkW5Y6hwH5aXLr2P/aRQ/qlX8ZbKQJUwKjOD59p7tt/c+wqokiIt68N7aNuKQ==",
"dependencies": {
"url-params-parser": "^1.0.3"
},
@ -3342,9 +3341,9 @@
"dev": true
},
"node_modules/ws": {
"version": "7.4.6",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
"version": "7.5.10",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"dev": true,
"engines": {
"node": ">=8.3.0"
@ -3381,12 +3380,13 @@
}
},
"@babel/code-frame": {
"version": "7.21.4",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
"integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
"integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==",
"dev": true,
"requires": {
"@babel/highlight": "^7.18.6"
"@babel/highlight": "^7.24.7",
"picocolors": "^1.0.0"
}
},
"@babel/compat-data": {
@ -3419,14 +3419,14 @@
}
},
"@babel/generator": {
"version": "7.21.4",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz",
"integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz",
"integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==",
"dev": true,
"requires": {
"@babel/types": "^7.21.4",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"@babel/types": "^7.24.7",
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^2.5.1"
}
},
@ -3503,10 +3503,13 @@
}
},
"@babel/helper-environment-visitor": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
"integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
"dev": true
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz",
"integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==",
"dev": true,
"requires": {
"@babel/types": "^7.24.7"
}
},
"@babel/helper-explode-assignable-expression": {
"version": "7.14.5",
@ -3518,22 +3521,22 @@
}
},
"@babel/helper-function-name": {
"version": "7.21.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz",
"integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz",
"integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==",
"dev": true,
"requires": {
"@babel/template": "^7.20.7",
"@babel/types": "^7.21.0"
"@babel/template": "^7.24.7",
"@babel/types": "^7.24.7"
}
},
"@babel/helper-hoist-variables": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
"integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz",
"integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==",
"dev": true,
"requires": {
"@babel/types": "^7.18.6"
"@babel/types": "^7.24.7"
}
},
"@babel/helper-member-expression-to-functions": {
@ -3627,24 +3630,24 @@
}
},
"@babel/helper-split-export-declaration": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
"integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz",
"integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==",
"dev": true,
"requires": {
"@babel/types": "^7.18.6"
"@babel/types": "^7.24.7"
}
},
"@babel/helper-string-parser": {
"version": "7.19.4",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
"integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz",
"integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==",
"dev": true
},
"@babel/helper-validator-identifier": {
"version": "7.19.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
"integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
"dev": true
},
"@babel/helper-validator-option": {
@ -3677,20 +3680,21 @@
}
},
"@babel/highlight": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
"integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz",
"integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.18.6",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
"@babel/helper-validator-identifier": "^7.24.7",
"chalk": "^2.4.2",
"js-tokens": "^4.0.0",
"picocolors": "^1.0.0"
}
},
"@babel/parser": {
"version": "7.21.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz",
"integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz",
"integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==",
"dev": true
},
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
@ -4404,42 +4408,42 @@
}
},
"@babel/template": {
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
"integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz",
"integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.18.6",
"@babel/parser": "^7.20.7",
"@babel/types": "^7.20.7"
"@babel/code-frame": "^7.24.7",
"@babel/parser": "^7.24.7",
"@babel/types": "^7.24.7"
}
},
"@babel/traverse": {
"version": "7.21.4",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz",
"integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz",
"integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.21.4",
"@babel/generator": "^7.21.4",
"@babel/helper-environment-visitor": "^7.18.9",
"@babel/helper-function-name": "^7.21.0",
"@babel/helper-hoist-variables": "^7.18.6",
"@babel/helper-split-export-declaration": "^7.18.6",
"@babel/parser": "^7.21.4",
"@babel/types": "^7.21.4",
"debug": "^4.1.0",
"@babel/code-frame": "^7.24.7",
"@babel/generator": "^7.24.7",
"@babel/helper-environment-visitor": "^7.24.7",
"@babel/helper-function-name": "^7.24.7",
"@babel/helper-hoist-variables": "^7.24.7",
"@babel/helper-split-export-declaration": "^7.24.7",
"@babel/parser": "^7.24.7",
"@babel/types": "^7.24.7",
"debug": "^4.3.1",
"globals": "^11.1.0"
}
},
"@babel/types": {
"version": "7.21.4",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz",
"integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz",
"integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==",
"dev": true,
"requires": {
"@babel/helper-string-parser": "^7.19.4",
"@babel/helper-validator-identifier": "^7.19.1",
"@babel/helper-string-parser": "^7.24.7",
"@babel/helper-validator-identifier": "^7.24.7",
"to-fast-properties": "^2.0.0"
}
},
@ -4478,14 +4482,14 @@
}
},
"@jridgewell/gen-mapping": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
"dev": true,
"requires": {
"@jridgewell/set-array": "^1.0.1",
"@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.9"
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"@jridgewell/resolve-uri": {
@ -4495,9 +4499,9 @@
"dev": true
},
"@jridgewell/set-array": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"dev": true
},
"@jridgewell/source-map": {
@ -4517,21 +4521,13 @@
"dev": true
},
"@jridgewell/trace-mapping": {
"version": "0.3.18",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz",
"integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==",
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dev": true,
"requires": {
"@jridgewell/resolve-uri": "3.1.0",
"@jridgewell/sourcemap-codec": "1.4.14"
},
"dependencies": {
"@jridgewell/sourcemap-codec": {
"version": "1.4.14",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
"dev": true
}
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"@polka/url": {
@ -4732,12 +4728,12 @@
}
},
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"requires": {
"fill-range": "^7.0.1"
"fill-range": "^7.1.1"
}
},
"browserslist": {
@ -4931,18 +4927,18 @@
"integrity": "sha512-RqBOWwt7sc+ta9GFjbu5GOwKFRzn3rMPPSqvSGpIwsfVnpMjiI5ttv84lwNsCMEYI6/lu/iH21HUcE3TLz8RGQ=="
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"follow-redirects": {
"version": "1.14.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA=="
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA=="
},
"fs.realpath": {
"version": "1.0.0",
@ -5578,9 +5574,9 @@
}
},
"svelte": {
"version": "3.58.0",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.58.0.tgz",
"integrity": "sha512-brIBNNB76mXFmU/Kerm4wFnkskBbluBDCjx/8TcpYRb298Yh2dztS2kQ6bhtjMcvUhd5ynClfwpz5h2gnzdQ1A=="
"version": "3.59.2",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.2.tgz",
"integrity": "sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA=="
},
"svelte-click-outside": {
"version": "1.0.0",
@ -5610,9 +5606,9 @@
}
},
"svelte-router-spa": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/svelte-router-spa/-/svelte-router-spa-6.0.2.tgz",
"integrity": "sha512-ySs/2TnjdLnvo0tHfdJsRPhPl0Mj4/h2qi0Zb8t4zC+BBBaCr6cZc7MtRfgzD4IMp80Nqe7ZXd/hCJuHSGtf5A==",
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/svelte-router-spa/-/svelte-router-spa-6.0.3.tgz",
"integrity": "sha512-aHgyUVVI/WjipQNmKcXpX0hFZtkW5Y6hwH5aXLr2P/aRQ/qlX8ZbKQJUwKjOD59p7tt/c+wqokiIt68N7aNuKQ==",
"requires": {
"url-params-parser": "^1.0.3"
}
@ -5762,9 +5758,9 @@
"dev": true
},
"ws": {
"version": "7.4.6",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
"version": "7.5.10",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"dev": true,
"requires": {}
},

View File

@ -20,14 +20,14 @@
"rollup-plugin-livereload": "^2.0.0",
"rollup-plugin-svelte": "^7.1.0",
"rollup-plugin-terser": "^7.0.0",
"svelte": "^3.48.0",
"svelte": "^3.59.2",
"svelte-toggle": "^3.1.0"
},
"dependencies": {
"axios": "^0.21.4",
"sirv-cli": "^1.0.0",
"svelte-emoji-selector": "^1.0.1",
"svelte-router-spa": "^6.0.2",
"svelte-router-spa": "^6.0.3",
"svelte-select": "^5.6.1",
"svelte-tooltip": "^1.2.0"
}

View File

@ -57,6 +57,7 @@ export default {
// consult the documentation for details:
// https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({
preferBuiltins: true,
browser: true,
dedupe: ['svelte']
}),

View File

@ -1,62 +1,27 @@
<div class="wrapper">
<div class="content">
<div class="content-col">
<div class="col">
{#if active}
<Card footer="{false}" fill="{false}">
<h4 slot="title">Bot Token</h4>
<h4 slot="title">Manage Bot</h4>
<div slot="body" class="full-width">
<form class="full-width" onsubmit="return false;">
<label class="form-label">Bot Token</label>
<input name="token" type="text" bind:value={token} class="form-input full-width"
placeholder="xxxxxxxxxxxxxxxxxxxxxxxx.xxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxx">
<p>Note: You will not be able to view the token after submitting it</p>
<p>Your whitelabel bot <b>{bot.username}</b> is active.</p>
<div class="buttons">
<div class="col">
<Button icon="fas fa-paper-plane" on:click={submitToken} fullWidth="{true}">Submit
</Button>
</div>
<div class="col">
<Button icon="fas fa-plus" on:click={invite} fullWidth="{true}"
disabled="{bot.id === undefined}">
<Button icon="fas fa-plus" on:click={invite}>
Generate Invite Link
</Button>
</div>
</div>
</form>
</div>
</Card>
</div>
<div class="content-col">
<Card footer="{false}" fill="{false}">
<h4 slot="title">Slash Commands</h4>
<div slot="body" class="full-width">
<form class="full-width" onsubmit="return false;">
<label class="form-label">Interactions Endpoint URL</label>
<input name="token" type="text" bind:value={interactionUrl} class="form-input full-width"
readonly>
<label class="form-label">Public Key</label>
<input name="token" type="text" bind:value={publicKey} class="form-input full-width">
<div class="buttons">
<div class="col">
<Button icon="fas fa-paper-plane" on:click={updatePublicKey} fullWidth="{true}"
disabled="{bot.id === undefined}">Submit Key
<Button icon="fas fa-paper-plane" on:click={createSlashCommands}>
Re-create Slash Commands
</Button>
</div>
<div class="col">
<Button icon="fas fa-paper-plane" on:click={createSlashCommands} fullWidth="{true}"
disabled="{!publicKeyOk}">Create Slash Commands
<Button icon="fas fa-trash-can" on:click={disable} danger>
Disable Whitelabel
</Button>
</div>
</div>
</form>
</div>
</Card>
</div>
</div>
<div class="content">
<div class="content-col">
<Card footer="{false}" fill="{false}">
<h4 slot="title">Custom Status</h4>
<div slot="body" class="full-width">
@ -69,20 +34,39 @@
</Dropdown>
<div class="col-2-3">
<Input col1 label="Status Text" placeholder="/help" bind:value={bot.status} />
<Input col1 label="Status Text" placeholder="/help" bind:value={bot.status}/>
</div>
</div>
<div class="buttons">
<Button icon="fas fa-paper-plane" on:click={updateStatus} fullWidth="{true}"
disabled="{bot.id === undefined}">Submit
<Button icon="fas fa-paper-plane" on:click={updateStatus} fullWidth="{true}">
Submit
</Button>
</div>
</form>
</div>
</Card>
{:else}
<Card footer="{false}" fill="{false}">
<h4 slot="title">Bot Token</h4>
<div slot="body" class="full-width">
<form class="full-width" onsubmit="return false;">
<label class="form-label">Bot Token</label>
<input name="token" type="text" bind:value={token} class="form-input full-width"
placeholder="xxxxxxxxxxxxxxxxxxxxxxxx.xxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxx">
<p>Note: You will not be able to view the token after submitting it</p>
<div class="buttons">
<Button icon="fas fa-paper-plane" on:click={submitToken} fullWidth="{true}">Submit
</Button>
</div>
<div class="content-col">
</form>
</div>
</Card>
{/if}
</div>
<div class="col">
<Card footer="{false}" fill="{false}">
<h4 slot="title">Error Log</h4>
<div slot="body" class="full-width">
@ -105,45 +89,32 @@
</div>
</Card>
</div>
</div>
</div>
<style>
.wrapper {
display: flex;
flex-direction: column;
flex-direction: row;
height: 100%;
width: 100%;
align-items: center;
}
.content {
display: flex;
justify-content: space-around;
flex-direction: row;
width: 95%;
margin-top: 2%;
padding: 2%;
gap: 2%;
}
.col {
width: 48%;
height: 100%;
}
.content-col {
width: 48%;
height: 100%;
display: flex;
flex-direction: column;
width: 50%;
gap: 2%;
}
@media only screen and (max-width: 900px) {
.content {
.wrapper {
flex-direction: column;
}
.content-col {
.col {
width: 100%;
margin-top: 2%;
}
}
@ -173,10 +144,16 @@
.buttons {
display: flex;
flex-direction: row;
justify-content: space-between;
gap: 12px;
margin-top: 12px;
}
@media only screen and (max-width: 576px) {
.buttons {
flex-direction: column;
}
}
.error-log {
width: 100%;
border-collapse: collapse;
@ -216,15 +193,13 @@
import Button from '../components/Button.svelte'
import {API_URL} from "../js/constants";
import {setDefaultHeaders} from '../includes/Auth.svelte'
import Input from "../components/form/Input.svelte";
import Dropdown from "../components/form/Dropdown.svelte";
import Input from "../components/form/Input.svelte";
setDefaultHeaders()
let active = false;
let token;
let publicKey;
let publicKeyOk = false;
let interactionUrl;
let bot = {};
let errors = [];
@ -252,25 +227,8 @@
$: token = '';
await loadInteractionUrl();
await loadBot();
notifySuccess(`Started tickets whitelabel on ${res.data.bot.username}#${res.data.bot.discriminator}`);
}
async function updatePublicKey() {
const data = {
public_key: publicKey,
};
const res = await axios.post(`${API_URL}/user/whitelabel/public-key`, data);
if (res.status !== 200 || !res.data.success) {
notifyError(res.data.error);
return;
}
$: publicKeyOk = true;
notifySuccess('Updated slash command settings successfully')
notifySuccess(`Started tickets whitelabel on ${res.data.bot.username}`);
}
async function updateStatus() {
@ -309,6 +267,8 @@
}
bot = res.data;
active = true;
return true;
}
@ -325,35 +285,6 @@
}
}
async function loadPublicKey() {
const res = await axios.get(`${API_URL}/user/whitelabel/public-key`);
if (res.status === 404) {
return;
}
if ((res.status !== 200 || !res.data.success)) {
notifyError(res.data.error);
return;
}
publicKey = res.data.key;
$: publicKeyOk = true;
}
async function loadInteractionUrl() {
const res = await axios.get(`${API_URL}/user/whitelabel/`);
if (res.status === 404) {
return;
}
if (res.status !== 200) {
notifyError(res.data.error);
return;
}
interactionUrl = 'https://gateway.ticketsbot.net/handle/' + res.data.id;
}
async function createSlashCommands() {
const opts = {
timeout: 20 * 1000
@ -365,15 +296,24 @@
return;
}
notifySuccess('Slash commands have been created. Please note, Discord may take up to an hour to show them in your client');
notifySuccess('Slash commands have been created. Please note, they may take a few minutes before they are visible.');
}
async function disable() {
const res = await axios.delete(`${API_URL}/user/whitelabel/`);
if (res.status !== 204) {
notifyError(res.data.error);
return;
}
active = false;
notifySuccess('Whitelabel has been disabled');
}
withLoadingScreen(async () => {
if (await loadBot()) {
await Promise.all([
loadErrors(),
loadInteractionUrl(),
loadPublicKey()
loadErrors()
]);
}
});