diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..aeb90e4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +frontend/node_modules +frontend/.svelte-kit +frontend/build + +backend/pb_data diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aeb90e4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +frontend/node_modules +frontend/.svelte-kit +frontend/build + +backend/pb_data diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d8744c2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,47 @@ +FROM golang:1.24.1 AS gobuild +WORKDIR /usr/src/app + +# Download Go modules +COPY backend/go.mod backend/go.sum . +RUN go mod download + +# Copy the source code. Note the slash at the end, as explained in +# https://docs.docker.com/engine/reference/builder/#copy +COPY backend/*.go ./ + +# Build +RUN CGO_ENABLED=0 GOOS=linux go build -o custom_pocketbase + +FROM oven/bun:latest AS base +WORKDIR /usr/src/app + +# install dependencies into temp directory +# this will cache them and speed up future builds +FROM base AS install +RUN mkdir -p /temp/dev +COPY frontend/package.json frontend/bun.lock /temp/dev/ +RUN cd /temp/dev && bun install --frozen-lockfile + +# copy node_modules from temp directory +# then copy all (non-ignored) project files into the image +FROM base AS prerelease +COPY --from=install /temp/dev/node_modules node_modules +COPY frontend . + +# [optional] tests & build +ENV NODE_ENV=production +RUN bun run build + +# copy production dependencies and source code into final image +FROM oven/bun:alpine AS release +WORKDIR /usr/src/app + +ENV GO_ENV=production +COPY start_server.sh . +COPY --from=prerelease /usr/src/app/build . +COPY --from=gobuild /usr/src/app/custom_pocketbase . +COPY backend/pb_migrations ./pb_migrations + +# run the app +EXPOSE 8090 +ENTRYPOINT [ "./start_server.sh" ] diff --git a/README.md b/README.md new file mode 100644 index 0000000..b5b2950 --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +# sv + +Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli). + +## Creating a project + +If you're seeing this, you've probably already done this step. Congrats! + +```bash +# create a new project in the current directory +npx sv create + +# create a new project in my-app +npx sv create my-app +``` + +## Developing + +Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: + +```bash +npm run dev + +# or start the server and open the app in a new browser tab +npm run dev -- --open +``` + +## Building + +To create a production version of your app: + +```bash +npm run build +``` + +You can preview the production build with `npm run preview`. + +> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment. diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..c5b8e06 --- /dev/null +++ b/TODO.md @@ -0,0 +1,15 @@ +# Choses qu'il me reste à faire pour une 100% parité avec l'ancienne version + +- [x] création de decks + - [x] Backend + - [x] Frontend +- [ ] affichage des top commandants + - [ ] backend (créer le cache commandant) + - [ ] frontend (créer les page avec slug) +- [x] Filtrer les cache par pourcentage d'utilisation +- [x] Affichage des stats par carte commandants + - [x] Backend + - [x] Frontend +- [ ] Affichage des stats par carte normale + - [ ] Backend + - [ ] Frontend diff --git a/backend/cache.go b/backend/cache.go new file mode 100644 index 0000000..4d136c5 --- /dev/null +++ b/backend/cache.go @@ -0,0 +1,295 @@ +package main + +import ( + "fmt" + "log" + "sort" + "strconv" + "strings" + "unsafe" + + "github.com/pocketbase/pocketbase/core" +) + +type CacheBrawlsetListItem struct { + Name string + SanitizedName string + IconsSvgUri []string +} + +type CacheCarteListItem struct { + Name string + Url string + Layout string + SmallImage string + SmallImageBack string + NormalImage string + NormalImageBack string + Price float64 + CardmarketUri string + NumberOfDecks int + NumberOfPossibleDecks int + PercentageOfDecks float64 + Synergy float64 +} + +type CacheCarteListItemWithSynergy struct { + MainCard CacheCarteListItem + CanBeCommander bool + Cards map[string][]CacheCarteListItem +} + +type CacheCarteSearch struct { + Name string + Url string + SetName string +} + +type CacheBrawlsetData struct { + Name string + SanitizedName string + Cards map[string][]CacheCarteListItem +} + +func (app *application) SetupCache() { + app.pb.OnBootstrap().BindFunc(func(e *core.BootstrapEvent) error { + if err := e.Next(); err != nil { + return err + } + + GenerateCache(e.App) + + return nil + }) +} + +func GenerateCache(pb core.App) { + log.Println("Creating json data cache...") + defer timer("Generating cache")() + var totalSize int64 + + brawlsets := []Brawlset{} + mtgSetsQuery := []MtgSet{} + mtgSets := map[string]MtgSet{} + cardsQuery := []Carte{} + cards := map[string]Carte{} + cacheCardsSearch := []CacheCarteSearch{} + cardsBySet := map[string][]Carte{} + decks := []Deck{} + decksByBset := map[string][]Deck{} + + err := pb.DB(). + NewQuery("SELECT * FROM brawlset"). + All(&brawlsets) + if err != nil { + log.Println(fmt.Sprintf("[ERROR] %v", err)) + } + + err = pb.DB(). + NewQuery("SELECT * FROM mtg_set"). + All(&mtgSetsQuery) + if err != nil { + log.Println(fmt.Sprintf("[ERROR] %v", err)) + } + + err = pb.DB(). + NewQuery("SELECT * FROM deck"). + All(&decks) + if err != nil { + log.Println(fmt.Sprintf("[ERROR] %v", err)) + } + + for _, v := range decks { + decksByBset[v.Brawlset] = append(decksByBset[v.Brawlset], v) + } + + err = pb.DB(). + NewQuery("SELECT * FROM carte"). + All(&cardsQuery) + if err != nil { + log.Println(fmt.Sprintf("[ERROR] %v", err)) + } + + for _, v := range mtgSetsQuery { + mtgSets[v.ID] = v + } + + for _, v := range cardsQuery { + cards[v.ID] = v + cardsBySet[v.MtgSet] = append(cardsBySet[v.MtgSet], v) + cacheCardsSearch = append(cacheCardsSearch, CacheCarteSearch{ Name: v.Name, Url: fmt.Sprintf("/card/%s-%s", v.SetCode,v.SanitizedName), SetName: mtgSets[v.MtgSet].Name}) + } + + totalSize += int64(unsafe.Sizeof(cacheCardsSearch)) + pb.Store().Set("searchData", cacheCardsSearch) + + cacheBrawlsetList := []CacheBrawlsetListItem{} + for _, v := range brawlsets { + setIconList := []string{} + numberOfDecksPerColorIdentity := map[string]int{} + cacheBrawlsetData := CacheBrawlsetData{Name: v.Name, SanitizedName: v.SanitizedName, Cards: map[string][]CacheCarteListItem{}} + numberOfDecksPerCard := map[string]int{} + synergyPerCards := map[string]map[string]int{} + + for _, d := range decksByBset[v.ID] { + + possibleColorIdentities := GetAllColorCombination(d.ColorIdentity) + for _, color := range possibleColorIdentities { + if _, ok := numberOfDecksPerColorIdentity[color]; ok { + numberOfDecksPerColorIdentity[color]++ + } else { + numberOfDecksPerColorIdentity[color] += 1 + } + } + // Increment number of deck for commander + if _, ok := numberOfDecksPerCard[fmt.Sprintf("c-%s",d.Commander)]; ok { + numberOfDecksPerCard[fmt.Sprintf("c-%s",d.Commander)]++ + } else { + numberOfDecksPerCard[fmt.Sprintf("c-%s",d.Commander)] = 1 + } + + // Increment number of deck for each card + for _, c := range d.Cards { + if _, ok := synergyPerCards[fmt.Sprintf("c-%s",d.Commander)]; !ok { + synergyPerCards[fmt.Sprintf("c-%s", d.Commander)] = map[string]int{} + } + if _, ok := synergyPerCards[fmt.Sprintf("c-%s",d.Commander)][c.ID]; ok { + synergyPerCards[fmt.Sprintf("c-%s",d.Commander)][c.ID]++ + } else { + synergyPerCards[fmt.Sprintf("c-%s",d.Commander)][c.ID] = 1 + } + + // Add number of decks per card + if _, ok := numberOfDecksPerCard[c.ID]; ok { + numberOfDecksPerCard[c.ID]++ + } else { + numberOfDecksPerCard[c.ID] = 1 + } + + // Add number of decks with the two same cards for synergy + for _, tc := range d.Cards { + if _, ok := synergyPerCards[c.ID]; !ok { + synergyPerCards[c.ID] = map[string]int{} + } + + if _, ok := synergyPerCards[c.ID][tc.ID]; ok { + synergyPerCards[c.ID][tc.ID]++ + } else { + synergyPerCards[c.ID][tc.ID] = 1 + } + } + } + } + + for _, s := range v.Sets { + setIconList = append(setIconList, mtgSets[s].IconUri) + for _, c := range cardsBySet[s] { + obj := CreateCardData(c, decksByBset, numberOfDecksPerColorIdentity, numberOfDecksPerCard, v.ID) + cacheBrawlsetData.Cards[c.CardType] = append(cacheBrawlsetData.Cards[c.CardType], obj) + + if c.CanBeCommander { + obj.NumberOfDecks = numberOfDecksPerCard[fmt.Sprintf("c-%s",c.ID)] + obj.Url = fmt.Sprintf("/commander/%s-%s", c.SetCode,c.SanitizedName) + cacheBrawlsetData.Cards["commander"] = append(cacheBrawlsetData.Cards["commander"], obj) + + detailsObj := CacheCarteListItemWithSynergy{ + MainCard: obj, + CanBeCommander: true, + Cards: map[string][]CacheCarteListItem{}, + } + + // Add each card that already appeared in a deck + for k := range synergyPerCards[fmt.Sprintf("c-%s",c.ID)] { + synergyObj := CreateCardData(cards[k], decksByBset, numberOfDecksPerColorIdentity, numberOfDecksPerCard, v.ID) + + synergy := 0 - synergyObj.PercentageOfDecks + if numberOfDecksPerCard[fmt.Sprintf("c-%s",c.ID)] != 0 { + synergy = (float64(synergyPerCards[fmt.Sprintf("c-%s",c.ID)][k]) / float64(numberOfDecksPerCard[fmt.Sprintf("c-%s",c.ID)])) - synergyObj.PercentageOfDecks + } + synergyObj.Synergy = synergy + + detailsObj.Cards[cards[k].CardType] = append(detailsObj.Cards[cards[k].CardType], synergyObj) + } + + for k := range detailsObj.Cards { + sort.Slice(detailsObj.Cards[k], func(i, j int) bool { + if detailsObj.Cards[k][i].Synergy == detailsObj.Cards[k][j].Synergy { + return detailsObj.Cards[k][i].PercentageOfDecks > detailsObj.Cards[k][j].PercentageOfDecks + } + return detailsObj.Cards[k][i].Synergy > detailsObj.Cards[k][j].Synergy + }) + } + + totalSize += int64(unsafe.Sizeof(detailsObj)) + pb.Store().Set(fmt.Sprintf("json/commander/%s-%s", c.SetCode, c.SanitizedName), detailsObj) + } + } + } + + for k := range cacheBrawlsetData.Cards { + if k == "commander" { + sort.Slice(cacheBrawlsetData.Cards[k], func(i, j int) bool { return cacheBrawlsetData.Cards[k][i].NumberOfDecks > cacheBrawlsetData.Cards[k][j].NumberOfDecks}) + } else { + sort.Slice(cacheBrawlsetData.Cards[k], func(i, j int) bool { + if cacheBrawlsetData.Cards[k][i].PercentageOfDecks == cacheBrawlsetData.Cards[k][j].PercentageOfDecks { + return cacheBrawlsetData.Cards[k][i].NumberOfDecks > cacheBrawlsetData.Cards[k][j].NumberOfDecks + } + return cacheBrawlsetData.Cards[k][i].PercentageOfDecks > cacheBrawlsetData.Cards[k][j].PercentageOfDecks + }) + } + } + + cacheBrawlsetList = append(cacheBrawlsetList, CacheBrawlsetListItem{Name: v.Name, SanitizedName: v.SanitizedName, IconsSvgUri: setIconList}) + + totalSize += int64(unsafe.Sizeof(cacheBrawlsetData)) + pb.Store().Set("json/brawlset/" + v.SanitizedName, cacheBrawlsetData) + } + + totalSize += int64(unsafe.Sizeof(cacheBrawlsetList)) + pb.Store().Set("json/misc/brawlsets", cacheBrawlsetList) + + log.Println(fmt.Sprintf("Total cache size : %d", totalSize)) +} + +func GetAllColorCombination(s []string) []string { + res := []string{strings.Join(s,"")} + for i := 1; i < len(s); i++ { + combinations := CreateCombination(s, i) + res = append(res, combinations...) + } + return res +} + +func CreateCardData(c Carte, decksByBset map[string][]Deck, numberOfDecksPerColorIdentity map[string]int, numberOfDecksPerCard map[string]int, bsetID string) CacheCarteListItem { + price, err := strconv.ParseFloat(c.Price, 64) + if err != nil { + price = 0.0 + } + + numberOfPossibleDecks := 0 + if len(c.ColorIdentity) == 0 { + numberOfPossibleDecks = len(decksByBset[bsetID]) + } else { + numberOfPossibleDecks = numberOfDecksPerColorIdentity[strings.Join(c.ColorIdentity,"")] + } + + percentageOfDecks := 0.0 + if numberOfPossibleDecks != 0 { + percentageOfDecks = float64(numberOfDecksPerCard[c.ID]) / float64(numberOfPossibleDecks) + } + + return CacheCarteListItem{ + Name: c.Name, + Url: fmt.Sprintf("/card/%s-%s", c.SetCode,c.SanitizedName), + Layout: c.Layout, + SmallImage: c.SmallImage, + SmallImageBack: c.SmallImageBack, + NormalImage: c.NormalImage, + NormalImageBack: c.NormalImageBack, + Price: price, + CardmarketUri: c.CardmarketUri, + NumberOfDecks: numberOfDecksPerCard[c.ID], + NumberOfPossibleDecks: numberOfPossibleDecks, + PercentageOfDecks: percentageOfDecks, + } +} diff --git a/backend/crons.go b/backend/crons.go new file mode 100644 index 0000000..2feeb8c --- /dev/null +++ b/backend/crons.go @@ -0,0 +1,70 @@ +package main + +import ( + "log" + "fmt" +) + +func (app *application) SetupCrons() { + app.pb.Cron().MustAdd("update_sets_and_cards", "0 3 * * *", func() { + log.Println("Started updating sets and cards...") + + scryfallSets := fetchApiSets() + + insertQuery := CreateBulkSetsInsertQuery(scryfallSets) + _, err := app.pb.DB(). + NewQuery(insertQuery). + Execute() + if err != nil { + log.Println(fmt.Sprintf("[ERROR] %v",err)) + } + log.Println(fmt.Sprintf("Updated %d sets", len(scryfallSets))) + + setsCodesQuery := []MtgSet{} + err = app.pb.DB(). + NewQuery("SELECT id, code FROM mtg_set"). + All(&setsCodesQuery) + if err != nil { + log.Println(fmt.Sprintf("[ERROR] %v",err)) + } + + setsCodes := map[string]string{} + for _,v := range setsCodesQuery { + setsCodes[v.ID] = v.Code + } + + selectedSets := []Brawlset{} + selectedSetsCodes := []string{} + err = app.pb.DB(). + NewQuery("SELECT sets FROM brawlset"). + All(&selectedSets) + if err != nil { + log.Println(fmt.Sprintf("[ERROR] %v",err)) + } + for _, v := range selectedSets { + for _, set := range v.Sets { + selectedSetsCodes = append(selectedSetsCodes, setsCodes[set]) + } + } + + log.Println(fmt.Sprintf("Fetching %d sets...", len(selectedSetsCodes))) + allCards := []ScryfallCard{} + for _, v := range selectedSetsCodes { + url := "https://api.scryfall.com/cards/search?q=(game%3Apaper)+set%3A" + v + allCards = fetchApiCards(url, allCards) + } + + upsertQuery := CreateBulkCardsUpsertQuery(allCards) + _, err = app.pb.DB(). + NewQuery(upsertQuery). + Execute() + if err != nil { + log.Println(fmt.Sprintf("[ERROR] %v",err)) + } + log.Println(fmt.Sprintf("Updated %d cards", len(allCards))) + }) + + app.pb.Cron().MustAdd("regenerate_cache_json", "30 3 * * *", func() { + GenerateCache(app.pb.App) + }) +} diff --git a/backend/custom_pocketbase b/backend/custom_pocketbase new file mode 100755 index 0000000..606f868 Binary files /dev/null and b/backend/custom_pocketbase differ diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..c489aa6 --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,47 @@ +module brawlset + +go 1.24.1 + +require ( + github.com/labstack/echo v3.3.10+incompatible + github.com/pocketbase/pocketbase v0.26.6 +) + +require ( + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/disintegration/imaging v1.6.2 // indirect + github.com/domodwyer/mailyak/v3 v3.6.2 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/fatih/color v1.18.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.8 // indirect + github.com/ganigeorgiev/fexpr v0.4.1 // indirect + github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect + github.com/golang-jwt/jwt/v5 v5.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/labstack/gommon v0.4.2 // indirect + github.com/lithammer/fuzzysearch v1.1.8 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-sqlite3 v1.14.27 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/pocketbase/dbx v1.11.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/spf13/cast v1.7.1 // indirect + github.com/spf13/cobra v1.9.1 // indirect + github.com/spf13/pflag v1.0.6 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + golang.org/x/crypto v0.36.0 // indirect + golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect + golang.org/x/image v0.25.0 // indirect + golang.org/x/net v0.37.0 // indirect + golang.org/x/oauth2 v0.28.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/text v0.23.0 // indirect + modernc.org/libc v1.61.13 // indirect + modernc.org/mathutil v1.7.1 // indirect + modernc.org/memory v1.8.2 // indirect + modernc.org/sqlite v1.36.3 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..d079bdd --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,164 @@ +github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +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/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= +github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= +github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCOBXMn8= +github.com/domodwyer/mailyak/v3 v3.6.2/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +github.com/ganigeorgiev/fexpr v0.4.1 h1:hpUgbUEEWIZhSDBtf4M9aUNfQQ0BZkGRaMePy7Gcx5k= +github.com/ganigeorgiev/fexpr v0.4.1/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE= +github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es= +github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew= +github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg= +github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= +github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.27 h1:drZCnuvf37yPfs95E5jd9s3XhdVWLal+6BOK6qrv6IU= +github.com/mattn/go-sqlite3 v1.14.27/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +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/pocketbase/dbx v1.11.0 h1:LpZezioMfT3K4tLrqA55wWFw1EtH1pM4tzSVa7kgszU= +github.com/pocketbase/dbx v1.11.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs= +github.com/pocketbase/pocketbase v0.26.6 h1:ya+D2QK5DP3ynntCEJPj5Sc6hl9KZ+ZsfxVKp9UCB4o= +github.com/pocketbase/pocketbase v0.26.6/go.mod h1:Pd+NfdYGBHXJOi9OI5WHS/Shn7J0iDSv5rNcCZ93LJM= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= +golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ= +golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= +golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= +golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= +golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0= +modernc.org/cc/v4 v4.24.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.23.16 h1:Z2N+kk38b7SfySC1ZkpGLN2vthNJP1+ZzGZIlH7uBxo= +modernc.org/ccgo/v4 v4.23.16/go.mod h1:nNma8goMTY7aQZQNTyN9AIoJfxav4nvTnvKThAeMDdo= +modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= +modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= +modernc.org/gc/v2 v2.6.3 h1:aJVhcqAte49LF+mGveZ5KPlsp4tdGdAOT4sipJXADjw= +modernc.org/gc/v2 v2.6.3/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/libc v1.61.13 h1:3LRd6ZO1ezsFiX1y+bHd1ipyEHIJKvuprv0sLTBwLW8= +modernc.org/libc v1.61.13/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.8.2 h1:cL9L4bcoAObu4NkxOlKWBWtNHIsnnACGF/TbqQ6sbcI= +modernc.org/memory v1.8.2/go.mod h1:ZbjSvMO5NQ1A2i3bWeDiVMxIorXwdClKE/0SZ+BMotU= +modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= +modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= +modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= +modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= +modernc.org/sqlite v1.36.3 h1:qYMYlFR+rtLDUzuXoST1SDIdEPbX8xzuhdF90WsX1ss= +modernc.org/sqlite v1.36.3/go.mod h1:ADySlx7K4FdY5MaJcEv86hTJ0PjedAloTUuif0YS3ws= +modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= +modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/backend/main.go b/backend/main.go new file mode 100644 index 0000000..73b18a9 --- /dev/null +++ b/backend/main.go @@ -0,0 +1,52 @@ +package main + +import ( + "os" + "log" + + "github.com/pocketbase/pocketbase" +) + +// Copied from https://github.com/s-petr/longhabit/blob/main/backend/main.go + +// application holds the core application state and configuration. +type application struct { + pb *pocketbase.PocketBase + config appConfig +} + +// appConfig holds the application's configuration settings. +type appConfig struct { + dbDir string +} + +// newApplication creates and initializes a new application instance. +func newApplication() *application { + dbDir := getEnvOrDefault("DB_DIR", "pb_data") + + return &application{ + pb: pocketbase.NewWithConfig(pocketbase.Config{DefaultDataDir: dbDir}), + config: appConfig{ + dbDir: dbDir, + }, + } +} + +func main() { + app := newApplication() + + app.SetupCache() + app.SetupCrons() + app.SetupRoutes() + + log.Fatal(app.pb.Start()) +} + +// getEnvOrDefault retrieves the value of an environment variable by key. +// If the environment variable is empty or not set, it returns the defaultValue. +func getEnvOrDefault(key, defaultValue string) string { + if value := os.Getenv(key); value != "" { + return value + } + return defaultValue +} diff --git a/backend/pb_migrations/1744049420_created_carte.js b/backend/pb_migrations/1744049420_created_carte.js new file mode 100644 index 0000000..d3110ed --- /dev/null +++ b/backend/pb_migrations/1744049420_created_carte.js @@ -0,0 +1,178 @@ +/// +migrate((app) => { + const collection = new Collection({ + "createRule": null, + "deleteRule": null, + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text1579384326", + "max": 0, + "min": 0, + "name": "name", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text3273110370", + "max": 0, + "min": 0, + "name": "sanitized_name", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text3520360348", + "max": 0, + "min": 0, + "name": "released_at", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text976907234", + "max": 0, + "min": 0, + "name": "layout", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "exceptDomains": null, + "hidden": false, + "id": "url1456686396", + "name": "small_image", + "onlyDomains": null, + "presentable": false, + "required": false, + "system": false, + "type": "url" + }, + { + "exceptDomains": null, + "hidden": false, + "id": "url2615033119", + "name": "small_image_back", + "onlyDomains": null, + "presentable": false, + "required": false, + "system": false, + "type": "url" + }, + { + "exceptDomains": null, + "hidden": false, + "id": "url2291853061", + "name": "normal_image", + "onlyDomains": null, + "presentable": false, + "required": false, + "system": false, + "type": "url" + }, + { + "exceptDomains": null, + "hidden": false, + "id": "url2961008824", + "name": "normal_image_back", + "onlyDomains": null, + "presentable": false, + "required": false, + "system": false, + "type": "url" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text2363381545", + "max": 0, + "min": 0, + "name": "type", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "hidden": false, + "id": "select3054531206", + "maxSelect": 2, + "name": "color_identity", + "presentable": false, + "required": false, + "system": false, + "type": "select", + "values": [ + "B", + "W", + "R", + "G", + "U" + ] + }, + { + "hidden": false, + "id": "autodate3332085495", + "name": "updated", + "onCreate": true, + "onUpdate": true, + "presentable": false, + "system": false, + "type": "autodate" + } + ], + "id": "pbc_1905410326", + "indexes": [], + "listRule": null, + "name": "carte", + "system": false, + "type": "base", + "updateRule": null, + "viewRule": null + }); + + return app.save(collection); +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_1905410326"); + + return app.delete(collection); +}) diff --git a/backend/pb_migrations/1744049617_created_set.js b/backend/pb_migrations/1744049617_created_set.js new file mode 100644 index 0000000..580e7a4 --- /dev/null +++ b/backend/pb_migrations/1744049617_created_set.js @@ -0,0 +1,101 @@ +/// +migrate((app) => { + const collection = new Collection({ + "createRule": null, + "deleteRule": null, + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text1579384326", + "max": 0, + "min": 0, + "name": "name", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text3273110370", + "max": 0, + "min": 0, + "name": "sanitized_name", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text1997877400", + "max": 0, + "min": 0, + "name": "code", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "hidden": false, + "id": "date3520360348", + "max": "", + "min": "", + "name": "released_at", + "presentable": false, + "required": false, + "system": false, + "type": "date" + }, + { + "exceptDomains": null, + "hidden": false, + "id": "url659239397", + "name": "icon_uri", + "onlyDomains": null, + "presentable": false, + "required": false, + "system": false, + "type": "url" + } + ], + "id": "pbc_3912384429", + "indexes": [], + "listRule": null, + "name": "set", + "system": false, + "type": "base", + "updateRule": null, + "viewRule": null + }); + + return app.save(collection); +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_3912384429"); + + return app.delete(collection); +}) diff --git a/backend/pb_migrations/1744049690_created_brawlset.js b/backend/pb_migrations/1744049690_created_brawlset.js new file mode 100644 index 0000000..12e99a9 --- /dev/null +++ b/backend/pb_migrations/1744049690_created_brawlset.js @@ -0,0 +1,78 @@ +/// +migrate((app) => { + const collection = new Collection({ + "createRule": null, + "deleteRule": null, + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text1579384326", + "max": 0, + "min": 0, + "name": "name", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text3273110370", + "max": 0, + "min": 0, + "name": "sanitized_name", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "cascadeDelete": false, + "collectionId": "pbc_3912384429", + "hidden": false, + "id": "relation2492286417", + "maxSelect": 999, + "minSelect": 0, + "name": "sets", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + } + ], + "id": "pbc_749385185", + "indexes": [], + "listRule": null, + "name": "brawlset", + "system": false, + "type": "base", + "updateRule": null, + "viewRule": null + }); + + return app.save(collection); +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_749385185"); + + return app.delete(collection); +}) diff --git a/backend/pb_migrations/1744049710_updated_carte.js b/backend/pb_migrations/1744049710_updated_carte.js new file mode 100644 index 0000000..6f97d9b --- /dev/null +++ b/backend/pb_migrations/1744049710_updated_carte.js @@ -0,0 +1,45 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_1905410326") + + // remove field + collection.fields.removeById("text3520360348") + + // add field + collection.fields.addAt(10, new Field({ + "hidden": false, + "id": "date3520360348", + "max": "", + "min": "", + "name": "released_at", + "presentable": false, + "required": false, + "system": false, + "type": "date" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_1905410326") + + // add field + collection.fields.addAt(3, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text3520360348", + "max": 0, + "min": 0, + "name": "released_at", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + // remove field + collection.fields.removeById("date3520360348") + + return app.save(collection) +}) diff --git a/backend/pb_migrations/1744049818_updated_carte.js b/backend/pb_migrations/1744049818_updated_carte.js new file mode 100644 index 0000000..d8c0169 --- /dev/null +++ b/backend/pb_migrations/1744049818_updated_carte.js @@ -0,0 +1,94 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_1905410326") + + // add field + collection.fields.addAt(11, new Field({ + "cascadeDelete": false, + "collectionId": "pbc_3912384429", + "hidden": false, + "id": "relation3860080092", + "maxSelect": 1, + "minSelect": 0, + "name": "set", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + })) + + // add field + collection.fields.addAt(12, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text3805467153", + "max": 0, + "min": 0, + "name": "set_code", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + // add field + collection.fields.addAt(13, new Field({ + "hidden": false, + "id": "number3402113753", + "max": null, + "min": null, + "name": "price", + "onlyInt": false, + "presentable": false, + "required": false, + "system": false, + "type": "number" + })) + + // add field + collection.fields.addAt(14, new Field({ + "exceptDomains": null, + "hidden": false, + "id": "url518645060", + "name": "cardmarket_url", + "onlyDomains": null, + "presentable": false, + "required": false, + "system": false, + "type": "url" + })) + + // add field + collection.fields.addAt(15, new Field({ + "hidden": false, + "id": "bool1734659578", + "name": "can_be_commander", + "presentable": false, + "required": false, + "system": false, + "type": "bool" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_1905410326") + + // remove field + collection.fields.removeById("relation3860080092") + + // remove field + collection.fields.removeById("text3805467153") + + // remove field + collection.fields.removeById("number3402113753") + + // remove field + collection.fields.removeById("url518645060") + + // remove field + collection.fields.removeById("bool1734659578") + + return app.save(collection) +}) diff --git a/backend/pb_migrations/1744049951_created_deck.js b/backend/pb_migrations/1744049951_created_deck.js new file mode 100644 index 0000000..7853061 --- /dev/null +++ b/backend/pb_migrations/1744049951_created_deck.js @@ -0,0 +1,140 @@ +/// +migrate((app) => { + const collection = new Collection({ + "createRule": null, + "deleteRule": null, + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text1579384326", + "max": 0, + "min": 0, + "name": "name", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "hidden": false, + "id": "select3054531206", + "maxSelect": 2, + "name": "color_identity", + "presentable": false, + "required": false, + "system": false, + "type": "select", + "values": [ + "B", + "R", + "G", + "U", + "W" + ] + }, + { + "cascadeDelete": false, + "collectionId": "_pb_users_auth_", + "hidden": false, + "id": "relation3479234172", + "maxSelect": 1, + "minSelect": 0, + "name": "owner", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + }, + { + "cascadeDelete": false, + "collectionId": "pbc_1905410326", + "hidden": false, + "id": "relation3635975509", + "maxSelect": 999, + "minSelect": 0, + "name": "cartes", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + }, + { + "cascadeDelete": false, + "collectionId": "pbc_1905410326", + "hidden": false, + "id": "relation1121130682", + "maxSelect": 1, + "minSelect": 0, + "name": "commander", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + }, + { + "cascadeDelete": false, + "collectionId": "pbc_749385185", + "hidden": false, + "id": "relation1826942456", + "maxSelect": 1, + "minSelect": 0, + "name": "brawlset", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + }, + { + "hidden": false, + "id": "autodate2990389176", + "name": "created", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + }, + { + "hidden": false, + "id": "autodate3332085495", + "name": "updated", + "onCreate": true, + "onUpdate": true, + "presentable": false, + "system": false, + "type": "autodate" + } + ], + "id": "pbc_1755402631", + "indexes": [], + "listRule": null, + "name": "deck", + "system": false, + "type": "base", + "updateRule": null, + "viewRule": null + }); + + return app.save(collection); +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_1755402631"); + + return app.delete(collection); +}) diff --git a/backend/pb_migrations/1744049967_updated_brawlset.js b/backend/pb_migrations/1744049967_updated_brawlset.js new file mode 100644 index 0000000..096040b --- /dev/null +++ b/backend/pb_migrations/1744049967_updated_brawlset.js @@ -0,0 +1,42 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_749385185") + + // update field + collection.fields.addAt(1, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text1579384326", + "max": 0, + "min": 0, + "name": "name", + "pattern": "", + "presentable": true, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_749385185") + + // update field + collection.fields.addAt(1, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text1579384326", + "max": 0, + "min": 0, + "name": "name", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}) diff --git a/backend/pb_migrations/1744049979_updated_carte.js b/backend/pb_migrations/1744049979_updated_carte.js new file mode 100644 index 0000000..802abed --- /dev/null +++ b/backend/pb_migrations/1744049979_updated_carte.js @@ -0,0 +1,74 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_1905410326") + + // update field + collection.fields.addAt(1, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text1579384326", + "max": 0, + "min": 0, + "name": "name", + "pattern": "", + "presentable": true, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + // update field + collection.fields.addAt(12, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text3805467153", + "max": 0, + "min": 0, + "name": "set_code", + "pattern": "", + "presentable": true, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_1905410326") + + // update field + collection.fields.addAt(1, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text1579384326", + "max": 0, + "min": 0, + "name": "name", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + // update field + collection.fields.addAt(12, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text3805467153", + "max": 0, + "min": 0, + "name": "set_code", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}) diff --git a/backend/pb_migrations/1744049986_updated_deck.js b/backend/pb_migrations/1744049986_updated_deck.js new file mode 100644 index 0000000..f6fc4d2 --- /dev/null +++ b/backend/pb_migrations/1744049986_updated_deck.js @@ -0,0 +1,42 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_1755402631") + + // update field + collection.fields.addAt(1, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text1579384326", + "max": 0, + "min": 0, + "name": "name", + "pattern": "", + "presentable": true, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_1755402631") + + // update field + collection.fields.addAt(1, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text1579384326", + "max": 0, + "min": 0, + "name": "name", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}) diff --git a/backend/pb_migrations/1744049999_updated_set.js b/backend/pb_migrations/1744049999_updated_set.js new file mode 100644 index 0000000..4d94331 --- /dev/null +++ b/backend/pb_migrations/1744049999_updated_set.js @@ -0,0 +1,42 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_3912384429") + + // update field + collection.fields.addAt(1, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text1579384326", + "max": 0, + "min": 0, + "name": "name", + "pattern": "", + "presentable": true, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_3912384429") + + // update field + collection.fields.addAt(1, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text1579384326", + "max": 0, + "min": 0, + "name": "name", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}) diff --git a/backend/pb_migrations/1744051259_updated_set.js b/backend/pb_migrations/1744051259_updated_set.js new file mode 100644 index 0000000..a1ce986 --- /dev/null +++ b/backend/pb_migrations/1744051259_updated_set.js @@ -0,0 +1,28 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_3912384429") + + // update collection data + unmarshal({ + "createRule": "", + "deleteRule": "", + "listRule": "", + "updateRule": "", + "viewRule": "" + }, collection) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_3912384429") + + // update collection data + unmarshal({ + "createRule": null, + "deleteRule": null, + "listRule": null, + "updateRule": null, + "viewRule": null + }, collection) + + return app.save(collection) +}) diff --git a/backend/pb_migrations/1744119600_updated_set.js b/backend/pb_migrations/1744119600_updated_set.js new file mode 100644 index 0000000..ba13554 --- /dev/null +++ b/backend/pb_migrations/1744119600_updated_set.js @@ -0,0 +1,20 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_3912384429") + + // update collection data + unmarshal({ + "name": "mtg_set" + }, collection) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_3912384429") + + // update collection data + unmarshal({ + "name": "set" + }, collection) + + return app.save(collection) +}) diff --git a/backend/pb_migrations/1744119800_updated_deck.js b/backend/pb_migrations/1744119800_updated_deck.js new file mode 100644 index 0000000..b1ef7c4 --- /dev/null +++ b/backend/pb_migrations/1744119800_updated_deck.js @@ -0,0 +1,42 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_1755402631") + + // update field + collection.fields.addAt(0, new Field({ + "autogeneratePattern": "[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}", + "hidden": false, + "id": "text3208210256", + "max": 36, + "min": 36, + "name": "id", + "pattern": "^[a-z0-9\\-]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_1755402631") + + // update field + collection.fields.addAt(0, new Field({ + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + })) + + return app.save(collection) +}) diff --git a/backend/pb_migrations/1744119839_updated_mtg_set.js b/backend/pb_migrations/1744119839_updated_mtg_set.js new file mode 100644 index 0000000..cb3ec70 --- /dev/null +++ b/backend/pb_migrations/1744119839_updated_mtg_set.js @@ -0,0 +1,42 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_3912384429") + + // update field + collection.fields.addAt(0, new Field({ + "autogeneratePattern": "[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}", + "hidden": false, + "id": "text3208210256", + "max": 36, + "min": 36, + "name": "id", + "pattern": "^[a-z0-9\\-]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_3912384429") + + // update field + collection.fields.addAt(0, new Field({ + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + })) + + return app.save(collection) +}) diff --git a/backend/pb_migrations/1744125643_updated_mtg_set.js b/backend/pb_migrations/1744125643_updated_mtg_set.js new file mode 100644 index 0000000..fd0c5a8 --- /dev/null +++ b/backend/pb_migrations/1744125643_updated_mtg_set.js @@ -0,0 +1,29 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_3912384429") + + // add field + collection.fields.addAt(6, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text2363381545", + "max": 0, + "min": 0, + "name": "type", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_3912384429") + + // remove field + collection.fields.removeById("text2363381545") + + return app.save(collection) +}) diff --git a/backend/pb_migrations/1744126008_updated_mtg_set.js b/backend/pb_migrations/1744126008_updated_mtg_set.js new file mode 100644 index 0000000..2c1b0a2 --- /dev/null +++ b/backend/pb_migrations/1744126008_updated_mtg_set.js @@ -0,0 +1,42 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_3912384429") + + // update field + collection.fields.addAt(6, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text2363381545", + "max": 0, + "min": 0, + "name": "type", + "pattern": "", + "presentable": true, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_3912384429") + + // update field + collection.fields.addAt(6, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text2363381545", + "max": 0, + "min": 0, + "name": "type", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}) diff --git a/backend/pb_migrations/1744128064_created_posts.js b/backend/pb_migrations/1744128064_created_posts.js new file mode 100644 index 0000000..2b86b25 --- /dev/null +++ b/backend/pb_migrations/1744128064_created_posts.js @@ -0,0 +1,95 @@ +/// +migrate((app) => { + const collection = new Collection({ + "createRule": null, + "deleteRule": null, + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text724990059", + "max": 0, + "min": 0, + "name": "title", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "cascadeDelete": false, + "collectionId": "_pb_users_auth_", + "hidden": false, + "id": "relation3182418120", + "maxSelect": 1, + "minSelect": 0, + "name": "author", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + }, + { + "convertURLs": false, + "hidden": false, + "id": "editor37359206", + "maxSize": 0, + "name": "article", + "presentable": false, + "required": false, + "system": false, + "type": "editor" + }, + { + "hidden": false, + "id": "autodate2990389176", + "name": "created", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + }, + { + "hidden": false, + "id": "autodate3332085495", + "name": "updated", + "onCreate": true, + "onUpdate": true, + "presentable": false, + "system": false, + "type": "autodate" + } + ], + "id": "pbc_1125843985", + "indexes": [], + "listRule": null, + "name": "posts", + "system": false, + "type": "base", + "updateRule": null, + "viewRule": null + }); + + return app.save(collection); +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_1125843985"); + + return app.delete(collection); +}) diff --git a/backend/pb_migrations/1744128183_deleted_posts.js b/backend/pb_migrations/1744128183_deleted_posts.js new file mode 100644 index 0000000..f19668f --- /dev/null +++ b/backend/pb_migrations/1744128183_deleted_posts.js @@ -0,0 +1,95 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_1125843985"); + + return app.delete(collection); +}, (app) => { + const collection = new Collection({ + "createRule": null, + "deleteRule": null, + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text724990059", + "max": 0, + "min": 0, + "name": "title", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "cascadeDelete": false, + "collectionId": "_pb_users_auth_", + "hidden": false, + "id": "relation3182418120", + "maxSelect": 1, + "minSelect": 0, + "name": "author", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + }, + { + "convertURLs": false, + "hidden": false, + "id": "editor37359206", + "maxSize": 0, + "name": "article", + "presentable": false, + "required": false, + "system": false, + "type": "editor" + }, + { + "hidden": false, + "id": "autodate2990389176", + "name": "created", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + }, + { + "hidden": false, + "id": "autodate3332085495", + "name": "updated", + "onCreate": true, + "onUpdate": true, + "presentable": false, + "system": false, + "type": "autodate" + } + ], + "id": "pbc_1125843985", + "indexes": [], + "listRule": null, + "name": "posts", + "system": false, + "type": "base", + "updateRule": null, + "viewRule": null + }); + + return app.save(collection); +}) diff --git a/backend/pb_migrations/1744133653_updated_carte.js b/backend/pb_migrations/1744133653_updated_carte.js new file mode 100644 index 0000000..438b518 --- /dev/null +++ b/backend/pb_migrations/1744133653_updated_carte.js @@ -0,0 +1,42 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_1905410326") + + // update field + collection.fields.addAt(0, new Field({ + "autogeneratePattern": "[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}", + "hidden": false, + "id": "text3208210256", + "max": 36, + "min": 36, + "name": "id", + "pattern": "^[a-z0-9\\-]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_1905410326") + + // update field + collection.fields.addAt(0, new Field({ + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + })) + + return app.save(collection) +}) diff --git a/backend/pb_migrations/1744140479_updated_carte.js b/backend/pb_migrations/1744140479_updated_carte.js new file mode 100644 index 0000000..da5006d --- /dev/null +++ b/backend/pb_migrations/1744140479_updated_carte.js @@ -0,0 +1,40 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_1905410326") + + // update field + collection.fields.addAt(11, new Field({ + "cascadeDelete": false, + "collectionId": "pbc_3912384429", + "hidden": false, + "id": "relation3860080092", + "maxSelect": 1, + "minSelect": 0, + "name": "mtg_set", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_1905410326") + + // update field + collection.fields.addAt(11, new Field({ + "cascadeDelete": false, + "collectionId": "pbc_3912384429", + "hidden": false, + "id": "relation3860080092", + "maxSelect": 1, + "minSelect": 0, + "name": "set", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + })) + + return app.save(collection) +}) diff --git a/backend/pb_migrations/1744149166_updated_carte.js b/backend/pb_migrations/1744149166_updated_carte.js new file mode 100644 index 0000000..e2fbb72 --- /dev/null +++ b/backend/pb_migrations/1744149166_updated_carte.js @@ -0,0 +1,25 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_1905410326") + + // remove field + collection.fields.removeById("autodate3332085495") + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_1905410326") + + // add field + collection.fields.addAt(16, new Field({ + "hidden": false, + "id": "autodate3332085495", + "name": "updated", + "onCreate": true, + "onUpdate": true, + "presentable": false, + "system": false, + "type": "autodate" + })) + + return app.save(collection) +}) diff --git a/backend/pb_migrations/1744150791_updated_deck.js b/backend/pb_migrations/1744150791_updated_deck.js new file mode 100644 index 0000000..598e353 --- /dev/null +++ b/backend/pb_migrations/1744150791_updated_deck.js @@ -0,0 +1,28 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_1755402631") + + // update collection data + unmarshal({ + "createRule": "@request.auth.id != \"\"", + "deleteRule": "owner ?= @request.auth.id", + "listRule": "owner ?= @request.auth.id", + "updateRule": "owner ?= @request.auth.id", + "viewRule": "owner ?= @request.auth.id" + }, collection) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_1755402631") + + // update collection data + unmarshal({ + "createRule": null, + "deleteRule": null, + "listRule": null, + "updateRule": null, + "viewRule": null + }, collection) + + return app.save(collection) +}) diff --git a/backend/routes.go b/backend/routes.go new file mode 100644 index 0000000..231425a --- /dev/null +++ b/backend/routes.go @@ -0,0 +1,176 @@ +package main + +import ( + "fmt" + "log" + "net/http" + "net/http/httputil" + "net/url" + "strings" + "os" + + "github.com/pocketbase/pocketbase/core" + "github.com/pocketbase/pocketbase/apis" +) + +const frontEndDevPort = "5173" +const frontEndProdPort = "3000" + +type DeckImportCard struct { + Name string `json:"name"` + Amount int `json:"amount"` +} + + +type DeckImport struct { + Name string `json:"name"` + Url string `json:"url"` + SelectedBset string `json:"selected_bset"` + Commander string `json:"commander_name"` + Cards []DeckImportCard `json:"cards"` +} + +func (app *application) SetupRoutes() { + app.pb.OnServe().BindFunc(func(se *core.ServeEvent) error { + mode := os.Getenv("GO_ENV") + path := "" + if mode == "" { + log.Fatal("You must the env variable GO_ENV to either 'dev' or 'production'") + } + + if mode == "dev" { + path = fmt.Sprintf("http://localhost:%s", frontEndDevPort) + } else if mode == "production" { + path = fmt.Sprintf("http://localhost:%s", frontEndProdPort) + } else { + log.Fatal(fmt.Sprintf("Error, unrecognized GO_ENV : %s\nSet it to either 'dev' or 'production'", mode)) + } + + target, err := url.Parse(path) + if err != nil { + log.Println("[ERROR] failed to parse proxy target URL: %w", err) + } + + proxy := httputil.NewSingleHostReverseProxy(target) + + proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, fmt.Sprintf("proxy error: %v", err), http.StatusBadGateway) + } + + // Cache Route + se.Router.GET("/json/{path...}", func(re *core.RequestEvent) error { + path := fmt.Sprintf("json/%s",re.Request.PathValue("path")) + + cacheVal := app.pb.Store().Get(path) + if cacheVal != nil { + return re.JSON(http.StatusOK, cacheVal) + } else { + return re.JSON(http.StatusNotFound, map[string]string{"message": "json not found in cache"}) + } + }) + + // Search API + se.Router.GET("/api/search", func(re *core.RequestEvent) error { + searchData := app.pb.Store().Get("searchData").([]CacheCarteSearch) + search := re.Request.URL.Query().Get("q") + + resultData := filter(searchData, func(card CacheCarteSearch) bool { return strings.Contains(strings.ToLower(card.Name), strings.ToLower(search)) }) + return re.JSON(http.StatusOK, resultData) + }) + + // Create deck API + se.Router.POST("/api/deck/create", func(re *core.RequestEvent) error { + authRecord := re.Auth + + data := DeckImport{} + if err := re.BindBody(&data); err != nil { + log.Println(err) + return re.BadRequestError("Failed to read request data", err) + } + + selectedBrawlset := Brawlset{} + err := app.pb.DB(). + NewQuery(fmt.Sprintf("SELECT id, sets FROM brawlset WHERE sanitized_name = '%v'", data.SelectedBset)). + One(&selectedBrawlset) + if err != nil { + log.Println(err) + return re.BadRequestError("No brawlsets with this id", err) + } + + possibleCards := []Carte{} + setsIds := []string{} + for _, v := range selectedBrawlset.Sets { + setsIds = append(setsIds, fmt.Sprintf("'%s'", v)) + } + query := "" + if len(selectedBrawlset.Sets) > 1 { + query = fmt.Sprintf("SELECT id, name, color_identity FROM carte WHERE mtg_set IN (%s)", strings.Join(setsIds, ", ")) + } else { + query = fmt.Sprintf("SELECT id, name, color_identity FROM carte WHERE mtg_set = %s", setsIds[0]) + } + err = app.pb.DB(). + NewQuery(query). + All(&possibleCards) + if err != nil { + log.Println(err) + return re.BadRequestError("Error with cards query", err) + } + + collection, err := app.pb.FindCollectionByNameOrId("deck") + if err != nil { + return err + } + record := core.NewRecord(collection) + record.Set("name", data.Name) + record.Set("url", data.Url) + record.Set("brawlset", selectedBrawlset.ID) + record.Set("owner", authRecord.Id) + + for _, c := range possibleCards { + if data.Commander == strings.Split(c.Name, " // ")[0] { + record.Set("commander", c.ID) + record.Set("color_identity", c.ColorIdentity) + } + } + + cardInDeck := []DeckCard{} + for _, v := range data.Cards { + cardId := "" + for _, c := range possibleCards { + if v.Name == strings.Split(c.Name, " // ")[0] { + cardId = c.ID + } + } + if cardId == "" { + log.Println(fmt.Sprintf("Card not found : %s",v.Name)) + } + cardInDeck = append(cardInDeck, DeckCard{ID: cardId, Amount: v.Amount}) + } + record.Set("cartes", cardInDeck) + + err = app.pb.Save(record) + if err != nil { + log.Println(err) + re.BadRequestError("Problem with creating deck", err) + } + return re.JSON(http.StatusOK, map[string]string{"message": "deck created"}) + }).Bind(apis.RequireAuth()) + + // Proxy to svelte app + se.Router.Any("/{path...}", func(re *core.RequestEvent) error { + proxy.ServeHTTP(re.Response, re.Request) + return nil + }) + + return se.Next() + }) +} + +func filter(ss []CacheCarteSearch, test func(CacheCarteSearch) bool) (ret []CacheCarteSearch) { + for _, s := range ss { + if test(s) { + ret = append(ret, s) + } + } + return +} diff --git a/backend/scryfall_api.go b/backend/scryfall_api.go new file mode 100644 index 0000000..83961bd --- /dev/null +++ b/backend/scryfall_api.go @@ -0,0 +1,252 @@ +package main + +import ( + "log" + "encoding/json" + "io/ioutil" + "net/http" + "time" +) + +type ScryfallCard struct { + Object string `json:"object"` + ID string `json:"id"` + OracleID string `json:"oracle_id"` + MultiverseIds []int `json:"multiverse_ids"` + MtgoID int `json:"mtgo_id"` + MtgoFoilID int `json:"mtgo_foil_id"` + TcgplayerID int `json:"tcgplayer_id"` + CardmarketID int `json:"cardmarket_id"` + Name string `json:"name"` + Lang string `json:"lang"` + ReleasedAt string `json:"released_at"` + URI string `json:"uri"` + ScryfallURI string `json:"scryfall_uri"` + Layout string `json:"layout"` + HighresImage bool `json:"highres_image"` + ImageStatus string `json:"image_status"` + ImageUris struct { + Small string `json:"small"` + Normal string `json:"normal"` + Large string `json:"large"` + Png string `json:"png"` + ArtCrop string `json:"art_crop"` + BorderCrop string `json:"border_crop"` + } `json:"image_uris"` + CardFaces []struct { + Object string `json:"object"` + Name string `json:"name"` + ManaCost string `json:"mana_cost"` + TypeLine string `json:"type_line"` + OracleText string `json:"oracle_text"` + Colors []string `json:"colors"` + Power string `json:"power"` + Toughness string `json:"toughness"` + Artist string `json:"artist"` + ArtistID string `json:"artist_id"` + IllustrationID string `json:"illustration_id"` + ImageUris struct { + Small string `json:"small"` + Normal string `json:"normal"` + Large string `json:"large"` + Png string `json:"png"` + ArtCrop string `json:"art_crop"` + BorderCrop string `json:"border_crop"` + } `json:"image_uris"` + ColorIndicator []string `json:"color_indicator,omitempty"` + } `json:"card_faces"` + ManaCost string `json:"mana_cost"` + Cmc float32 `json:"cmc"` + TypeLine string `json:"type_line"` + OracleText string `json:"oracle_text"` + Power string `json:"power"` + Toughness string `json:"toughness"` + Colors []string `json:"colors"` + ColorIdentity []string `json:"color_identity"` + Keywords []string `json:"keywords"` + Legalities struct { + Standard string `json:"standard"` + Future string `json:"future"` + Historic string `json:"historic"` + Timeless string `json:"timeless"` + Gladiator string `json:"gladiator"` + Pioneer string `json:"pioneer"` + Explorer string `json:"explorer"` + Modern string `json:"modern"` + Legacy string `json:"legacy"` + Pauper string `json:"pauper"` + Vintage string `json:"vintage"` + Penny string `json:"penny"` + Commander string `json:"commander"` + Oathbreaker string `json:"oathbreaker"` + Standardbrawl string `json:"standardbrawl"` + Brawl string `json:"brawl"` + Alchemy string `json:"alchemy"` + Paupercommander string `json:"paupercommander"` + Duel string `json:"duel"` + Oldschool string `json:"oldschool"` + Premodern string `json:"premodern"` + Predh string `json:"predh"` + } `json:"legalities"` + Games []string `json:"games"` + Reserved bool `json:"reserved"` + GameChanger bool `json:"game_changer"` + Foil bool `json:"foil"` + Nonfoil bool `json:"nonfoil"` + Finishes []string `json:"finishes"` + Oversized bool `json:"oversized"` + Promo bool `json:"promo"` + Reprint bool `json:"reprint"` + Variation bool `json:"variation"` + SetID string `json:"set_id"` + Set string `json:"set"` + SetName string `json:"set_name"` + SetType string `json:"set_type"` + SetURI string `json:"set_uri"` + SetSearchURI string `json:"set_search_uri"` + ScryfallSetURI string `json:"scryfall_set_uri"` + RulingsURI string `json:"rulings_uri"` + PrintsSearchURI string `json:"prints_search_uri"` + CollectorNumber string `json:"collector_number"` + Digital bool `json:"digital"` + Rarity string `json:"rarity"` + CardBackID string `json:"card_back_id"` + Artist string `json:"artist"` + ArtistIds []string `json:"artist_ids"` + IllustrationID string `json:"illustration_id"` + BorderColor string `json:"border_color"` + Frame string `json:"frame"` + FullArt bool `json:"full_art"` + Textless bool `json:"textless"` + Booster bool `json:"booster"` + StorySpotlight bool `json:"story_spotlight"` + EdhrecRank int `json:"edhrec_rank"` + PennyRank int `json:"penny_rank"` + Prices struct { + Usd string `json:"usd"` + UsdFoil string `json:"usd_foil"` + UsdEtched interface{} `json:"usd_etched"` + Eur string `json:"eur"` + EurFoil string `json:"eur_foil"` + Tix string `json:"tix"` + } `json:"prices"` + RelatedUris struct { + Gatherer string `json:"gatherer"` + TcgplayerInfiniteArticles string `json:"tcgplayer_infinite_articles"` + TcgplayerInfiniteDecks string `json:"tcgplayer_infinite_decks"` + Edhrec string `json:"edhrec"` + } `json:"related_uris"` + PurchaseUris struct { + Tcgplayer string `json:"tcgplayer"` + Cardmarket string `json:"cardmarket"` + Cardhoarder string `json:"cardhoarder"` + } `json:"purchase_uris"` +} + +type ScryfallCardAPI struct { + Object string `json:"object"` + TotalCards int `json:"total_cards"` + HasMore bool `json:"has_more"` + NextPage string `json:"next_page"` + Data []ScryfallCard `json:"data"` +} + +type ScryfallSet struct { + Object string `json:"object"` + ID string `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Uri string `json:"uri"` + ScryfallUri string `json:"scryfall_uri"` + SearchUri string `json:"search_uri"` + ReleasedAt string `json:"released_at"` + SetType string `json:"set_type"` + CardCount int `json:"card_count"` + ParentSetCode string `json:"parent_set_code"` + Digital bool `json:"digital"` + NonfoilOnly bool `json:"nonfoil_only"` + FoilOnly bool `json:"foil_only"` + IconSvgUri string `json:"icon_svg_uri"` +} + +type ScryfallSetAPI struct { + Object string `json:"object"` + HasMore bool `json:"has_more"` + Data []ScryfallSet `json:"data"` +} + +func fetchApiCards(url string, cards []ScryfallCard) []ScryfallCard { + reqClient := http.Client{ + Timeout: time.Second * 30, // Timeout after 2 seconds + } + + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + log.Fatal(err) + } + + req.Header.Set("User-Agent", "brawlset") + + res, err := reqClient.Do(req) + if err != nil { + log.Fatal(err) + } + + if res.Body != nil { + defer res.Body.Close() + } + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + log.Fatal(err) + } + + var scryfallData ScryfallCardAPI + err = json.Unmarshal(body, &scryfallData) + if err != nil { + log.Fatal(err) + } + cards = append(cards, scryfallData.Data...) + if scryfallData.HasMore { + return fetchApiCards(scryfallData.NextPage, cards) + } else { + return cards + } +} + +func fetchApiSets() []ScryfallSet { + url := "https://api.scryfall.com/sets" + + reqClient := http.Client{ + Timeout: time.Second * 30, // Timeout after 2 seconds + } + + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + log.Fatal(err) + } + + req.Header.Set("User-Agent", "brawlset") + + res, err := reqClient.Do(req) + if err != nil { + log.Fatal(err) + } + + if res.Body != nil { + defer res.Body.Close() + } + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + log.Fatal(err) + } + + var scryFallData ScryfallSetAPI + err = json.Unmarshal(body, &scryFallData) + if err != nil { + log.Fatal(err) + } + + return scryFallData.Data +} diff --git a/backend/types.go b/backend/types.go new file mode 100644 index 0000000..8bab927 --- /dev/null +++ b/backend/types.go @@ -0,0 +1,56 @@ +package main + +import ( + "github.com/pocketbase/pocketbase/tools/types" +) + +type MtgSet struct { + ID string `db:"id" json:"id"` + Code string `db:"code" json:"code"` + Name string `db:"name" json:"name"` + SanitizedName string `db:"sanitized_name" json:"sanitized_name"` + ReleasedAt string `db:"release_at" json:"released_at"` + IconUri string `db:"icon_uri" json:"icon_uri"` + SetType string `db:"type" json:"type"` +} + +type Brawlset struct { + ID string `db:"id" json:"id"` + Name string `db:"name" json:"name"` + SanitizedName string `db:"sanitized_name" json:"sanitized_name"` + Sets types.JSONArray[string] `db:"sets" json:"sets"` +} + +type Carte struct { + ID string `db:"id" json:"id"` + Name string `db:"name" json:"name"` + SanitizedName string `db:"sanitized_name" json:"sanitized_name"` + Layout string `db:"layout" json:"layout"` + SmallImage string `db:"small_image" json:"small_image"` + SmallImageBack string `db:"small_image_back" json:"small_image_back"` + NormalImage string `db:"normal_image" json:"normal_image"` + NormalImageBack string `db:"normal_image_back" json:"normal_image_back"` + CardType string `db:"type" json:"type"` + ColorIdentity types.JSONArray[string] `db:"color_identity" json:"color_identity"` + ReleasedAt string `db:"released_at" json:"released_at"` + MtgSet string `db:"mtg_set" json:"mtg_set"` + SetCode string `db:"set_code" json:"set_code"` + Price string `db:"price" json:"price"` + CardmarketUri string `db:"cardmarket_url" json:"cardmarket_url"` + CanBeCommander bool `db:"can_be_commander" json:"can_be_commander"` +} + +type DeckCard struct { + ID string `json:"id"` + Amount int `json:"amount"` +} + +type Deck struct { + ID string `db:"id"` + Name string `db:"name"` + ColorIdentity types.JSONArray[string] `db:"color_identity"` + Owner string `db:"owner"` + Commander string `db:"commander"` + Brawlset string `db:"brawlset"` + Cards types.JSONArray[DeckCard] `db:"cartes"` +} diff --git a/backend/utils.go b/backend/utils.go new file mode 100644 index 0000000..ec607ea --- /dev/null +++ b/backend/utils.go @@ -0,0 +1,273 @@ +package main + +import ( + "regexp" + "unicode/utf8" + "slices" + "strings" + "sort" + "encoding/json" + "log" + "fmt" + "time" +) + +// https://stackoverflow.com/a/75996347 +var defaultDiacriticsRemovalMap = []struct { + base string + letters string +}{ + {"A", "\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F"}, + {"AA", "\uA732"}, + {"AE", "\u00C6\u01FC\u01E2"}, + {"AO", "\uA734"}, + {"AU", "\uA736"}, + {"AV", "\uA738\uA73A"}, + {"AY", "\uA73C"}, + {"B", "\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181"}, + {"C", "\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E"}, + {"D", "\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779\u00D0"}, + {"DZ", "\u01F1\u01C4"}, + {"Dz", "\u01F2\u01C5"}, + {"E", "\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E"}, + {"F", "\u0046\u24BB\uFF26\u1E1E\u0191\uA77B"}, + {"G", "\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E"}, + {"H", "\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D"}, + {"I", "\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197"}, + {"J", "\u004A\u24BF\uFF2A\u0134\u0248"}, + {"K", "\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2"}, + {"L", "\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780"}, + {"LJ", "\u01C7"}, + {"Lj", "\u01C8"}, + {"M", "\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C"}, + {"N", "\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4"}, + {"NJ", "\u01CA"}, + {"Nj", "\u01CB"}, + {"O", "\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C"}, + {"OI", "\u01A2"}, + {"OO", "\uA74E"}, + {"OU", "\u0222"}, + {"OE", "\u008C\u0152"}, + {"oe", "\u009C\u0153"}, + {"P", "\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754"}, + {"Q", "\u0051\u24C6\uFF31\uA756\uA758\u024A"}, + {"R", "\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782"}, + {"S", "\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784"}, + {"T", "\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786"}, + {"TZ", "\uA728"}, + {"U", "\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244"}, + {"V", "\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245"}, + {"VY", "\uA760"}, + {"W", "\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72"}, + {"X", "\u0058\u24CD\uFF38\u1E8A\u1E8C"}, + {"Y", "\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE"}, + {"Z", "\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762"}, + {"a", "\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250"}, + {"aa", "\uA733"}, + {"ae", "\u00E6\u01FD\u01E3"}, + {"ao", "\uA735"}, + {"au", "\uA737"}, + {"av", "\uA739\uA73B"}, + {"ay", "\uA73D"}, + {"b", "\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253"}, + {"c", "\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184"}, + {"d", "\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A"}, + {"dz", "\u01F3\u01C6"}, + {"e", "\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD"}, + {"f", "\u0066\u24D5\uFF46\u1E1F\u0192\uA77C"}, + {"g", "\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F"}, + {"h", "\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265"}, + {"hv", "\u0195"}, + {"i", "\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131"}, + {"j", "\u006A\u24D9\uFF4A\u0135\u01F0\u0249"}, + {"k", "\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3"}, + {"l", "\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747"}, + {"lj", "\u01C9"}, + {"m", "\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F"}, + {"n", "\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5"}, + {"nj", "\u01CC"}, + {"o", "\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275"}, + {"oi", "\u01A3"}, + {"ou", "\u0223"}, + {"oo", "\uA74F"}, + {"p", "\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755"}, + {"q", "\u0071\u24E0\uFF51\u024B\uA757\uA759"}, + {"r", "\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783"}, + {"s", "\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B"}, + {"t", "\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787"}, + {"tz", "\uA729"}, + {"u", "\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289"}, + {"v", "\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C"}, + {"vy", "\uA761"}, + {"w", "\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73"}, + {"x", "\u0078\u24E7\uFF58\u1E8B\u1E8D"}, + {"y", "\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF"}, + {"z", "\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763"}, +} + +var diacriticsMap = map[rune]string{} + +func removeDiacritics(str string) string { + for _, mapping := range defaultDiacriticsRemovalMap { + letters := mapping.letters + for _, letter := range letters { + diacriticsMap[letter] = mapping.base + } + } + + reg := regexp.MustCompile("[^\u0000-\u007E]") + return reg.ReplaceAllStringFunc(str, func(a string) string { + r, _ := utf8.DecodeRuneInString(a) + if replacement, ok := diacriticsMap[rune(r)]; ok { + return replacement + } + return a + }) +} + +func SanitizeName(str string) string { + re := regexp.MustCompile(`[^a-zA-Z0-9]+`) + return strings.ToLower(re.ReplaceAllString(removeDiacritics(str), "-")) +} + + +// Function to create a SQL query to Upsert cards +// Used in : crons.go +func CreateBulkCardsUpsertQuery(data []ScryfallCard) string { + totalCards := len(data) + twoFacedLayouts := []string{"transform","modal_dfc","double_faced_token","reversible_card"} + values := make([]string, totalCards) + for i := 0; i < totalCards; i++ { + id := data[i].ID + name := data[i].Name + sanitizedName := SanitizeName(data[i].Name) // Sanitized Name + layout := data[i].Layout + smallImage := "" + smallImageBack := "" + normalImage := "" + normalImageBack := "" + // Two Faced + if slices.Contains(twoFacedLayouts,data[i].Layout) { + smallImage = data[i].CardFaces[0].ImageUris.Small + smallImageBack = data[i].CardFaces[0].ImageUris.Normal + normalImage = data[i].CardFaces[1].ImageUris.Small + normalImageBack = data[i].CardFaces[1].ImageUris.Normal + } else { + smallImage = data[i].ImageUris.Small + normalImage = data[i].ImageUris.Normal + } + // Type + cardTypeLine := strings.ToLower(data[i].TypeLine) + cardType := "" + if strings.Contains(cardTypeLine, "creature") { + cardType = "creature" + } else if strings.Contains(cardTypeLine, "planeswalker") { + cardType = "planeswalker" + } else if strings.Contains(cardTypeLine, "artifact") { + cardType = "artifact" + } else if strings.Contains(cardTypeLine, "instant") { + cardType = "instant" + } else if strings.Contains(cardTypeLine, "enchantment") { + cardType = "enchantment" + } else if strings.Contains(cardTypeLine, "sorcery") { + cardType = "sorcery" + } else if strings.Contains(cardTypeLine, "land") { + cardType = "land" + } else { + cardType = "unknown" + } + colorIdentityBytes, err := json.Marshal(data[i].ColorIdentity) + if err != nil { + log.Fatal(err) + } + colorIdentity := string(colorIdentityBytes) + releasedAt := data[i].ReleasedAt + setId := data[i].SetID + setCode := data[i].Set + price := data[i].Prices.Eur + cardmarketUri := data[i].PurchaseUris.Cardmarket + canBeCommander := (strings.Contains(cardTypeLine, "legendary") && cardType == "creature") || cardType == "planeswalker" + + values[i] = fmt.Sprintf(`("%v", "%s", "%v", "%v", "%v", "%v", "%v", "%v", "%v", '%v', "%v", "%v", "%v", "%v", "%v", "%v")`,id, name, sanitizedName, layout, smallImage, smallImageBack, normalImage, normalImageBack, cardType, colorIdentity, releasedAt, setId, setCode, price, cardmarketUri, canBeCommander) + } + + upsertQuery := fmt.Sprintf("INSERT INTO carte(id, name, sanitized_name, layout, small_image, small_image_back, normal_image, normal_image_back, type, color_identity, released_at, mtg_set, set_code, price, cardmarket_url, can_be_commander) VALUES %s ON CONFLICT (id) DO UPDATE SET price = excluded.price", strings.Join(values, ", ")) + + return upsertQuery +} + +// Function to create a SQL query to Insert sets +// Used in : crons.go +func CreateBulkSetsInsertQuery(data []ScryfallSet) string { + totalSets := len(data) + values := make([]string, totalSets) + for i := 0; i < totalSets; i++ { + values[i] = fmt.Sprintf(`("%v", "%v", "%v", "%v", "%v", "%v", "%v")`,data[i].ID, data[i].Name, SanitizeName(data[i].Name), data[i].Code, data[i].IconSvgUri, data[i].SetType, data[i].ReleasedAt) + } + + insertQuery := fmt.Sprintf("INSERT OR IGNORE INTO mtg_set(id, name, sanitized_name, code, icon_uri, type, released_at) VALUES %s", strings.Join(values, ", ")) + + return insertQuery +} + +// Timer used to time a function +// Used in : cache.go +func timer(name string) func() { + start := time.Now() + return func() { + log.Printf("%s took %v\n", name, time.Since(start)) + } +} + +// Function to create all possible combinations of an array with a said length +// Used in : cache.go +// Source (in java) : https://hmkcode.com/calculate-find-all-possible-combinations-of-an-array-using-java/ +func CreateCombination(s []string, k int) []string { + res := []string{} + ignore := make([]int, len(s) - k) + combination := make([]string, k) + for w := 0; w < len(ignore); w++ { + ignore[w] = len(s) - 1 - w + } + // Edit fonction above to make it ascending by default + sort.Slice(ignore, func(i, j int) bool { return ignore[i] < ignore[j]}) + + i := 0 + r := 0 + g := 0 + + terminate := false + for !terminate { + for i < len(s) && r < k { + if i != ignore[g] { + combination[r] = s[i]; + r++ + i++ + } else { + if g != len(ignore) - 1 { + g++ + } + i++ + } + } + i = 0 + r = 0 + g = 0 + + res = append(res, strings.Join(combination,"")) + terminate = true + + for w := 0; w < len(ignore); w++ { + if ignore[w] > w { + ignore[w]-- + + if w > 0 { + ignore[w-1] = ignore[w]-1 + } + terminate = false + break + } + } + } + return res +} diff --git a/frontend/.npmrc b/frontend/.npmrc new file mode 100644 index 0000000..b6f27f1 --- /dev/null +++ b/frontend/.npmrc @@ -0,0 +1 @@ +engine-strict=true diff --git a/frontend/bun.lock b/frontend/bun.lock new file mode 100644 index 0000000..866ae7d --- /dev/null +++ b/frontend/bun.lock @@ -0,0 +1,290 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "brawlset-rewrite", + "dependencies": { + "pocketbase": "^0.25.2", + "svelte-adapter-bun": "^0.5.2", + }, + "devDependencies": { + "@sveltejs/adapter-auto": "^4.0.0", + "@sveltejs/kit": "^2.16.0", + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "@tailwindcss/vite": "^4.0.0", + "svelte": "^5.0.0", + "svelte-check": "^4.0.0", + "tailwindcss": "^4.0.0", + "typescript": "^5.0.0", + "vite": "^6.2.5", + }, + }, + }, + "packages": { + "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.2", "", { "os": "android", "cpu": "arm" }, "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.2", "", { "os": "android", "cpu": "x64" }, "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.2", "", { "os": "linux", "cpu": "arm" }, "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.2", "", { "os": "linux", "cpu": "none" }, "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.2", "", { "os": "linux", "cpu": "none" }, "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.2", "", { "os": "linux", "cpu": "none" }, "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.2", "", { "os": "linux", "cpu": "x64" }, "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.2", "", { "os": "none", "cpu": "arm64" }, "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.2", "", { "os": "none", "cpu": "x64" }, "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.2", "", { "os": "win32", "cpu": "x64" }, "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], + + "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.39.0", "", { "os": "android", "cpu": "arm" }, "sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.39.0", "", { "os": "android", "cpu": "arm64" }, "sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.39.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.39.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.39.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.39.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.39.0", "", { "os": "linux", "cpu": "arm" }, "sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.39.0", "", { "os": "linux", "cpu": "arm" }, "sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.39.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.39.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA=="], + + "@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.39.0", "", { "os": "linux", "cpu": "none" }, "sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw=="], + + "@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.39.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.39.0", "", { "os": "linux", "cpu": "none" }, "sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.39.0", "", { "os": "linux", "cpu": "none" }, "sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.39.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.39.0", "", { "os": "linux", "cpu": "x64" }, "sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.39.0", "", { "os": "linux", "cpu": "x64" }, "sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.39.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.39.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.39.0", "", { "os": "win32", "cpu": "x64" }, "sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug=="], + + "@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.5", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ=="], + + "@sveltejs/adapter-auto": ["@sveltejs/adapter-auto@4.0.0", "", { "dependencies": { "import-meta-resolve": "^4.1.0" }, "peerDependencies": { "@sveltejs/kit": "^2.0.0" } }, "sha512-kmuYSQdD2AwThymQF0haQhM8rE5rhutQXG4LNbnbShwhMO4qQGnKaaTy+88DuNSuoQDi58+thpq8XpHc1+oEKQ=="], + + "@sveltejs/kit": ["@sveltejs/kit@2.20.5", "", { "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^0.6.0", "devalue": "^5.1.0", "esm-env": "^1.2.2", "import-meta-resolve": "^4.1.0", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", "sirv": "^3.0.0" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "vite": "^5.0.3 || ^6.0.0" }, "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-zT/97KvVUo19jEGZa972ls7KICjPCB53j54TVxnEFT5VEwL16G+YFqRVwJbfxh7AmS7/Ptr1rKF7Qt4FBMDNlw=="], + + "@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@5.0.3", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", "debug": "^4.4.0", "deepmerge": "^4.3.1", "kleur": "^4.1.5", "magic-string": "^0.30.15", "vitefu": "^1.0.4" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-MCFS6CrQDu1yGwspm4qtli0e63vaPCehf6V7pIMP15AsWgMKrqDGCPFF/0kn4SP0ii4aySu4Pa62+fIRGFMjgw=="], + + "@sveltejs/vite-plugin-svelte-inspector": ["@sveltejs/vite-plugin-svelte-inspector@4.0.1", "", { "dependencies": { "debug": "^4.3.7" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^5.0.0", "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw=="], + + "@tailwindcss/node": ["@tailwindcss/node@4.1.3", "", { "dependencies": { "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.29.2", "tailwindcss": "4.1.3" } }, "sha512-H/6r6IPFJkCfBJZ2dKZiPJ7Ueb2wbL592+9bQEl2r73qbX6yGnmQVIfiUvDRB2YI0a3PWDrzUwkvQx1XW1bNkA=="], + + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.3", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.3", "@tailwindcss/oxide-darwin-arm64": "4.1.3", "@tailwindcss/oxide-darwin-x64": "4.1.3", "@tailwindcss/oxide-freebsd-x64": "4.1.3", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.3", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.3", "@tailwindcss/oxide-linux-arm64-musl": "4.1.3", "@tailwindcss/oxide-linux-x64-gnu": "4.1.3", "@tailwindcss/oxide-linux-x64-musl": "4.1.3", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.3", "@tailwindcss/oxide-win32-x64-msvc": "4.1.3" } }, "sha512-t16lpHCU7LBxDe/8dCj9ntyNpXaSTAgxWm1u2XQP5NiIu4KGSyrDJJRlK9hJ4U9yJxx0UKCVI67MJWFNll5mOQ=="], + + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.3", "", { "os": "android", "cpu": "arm64" }, "sha512-cxklKjtNLwFl3mDYw4XpEfBY+G8ssSg9ADL4Wm6//5woi3XGqlxFsnV5Zb6v07dxw1NvEX2uoqsxO/zWQsgR+g=="], + + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-mqkf2tLR5VCrjBvuRDwzKNShRu99gCAVMkVsaEOFvv6cCjlEKXRecPu9DEnxp6STk5z+Vlbh1M5zY3nQCXMXhw=="], + + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-7sGraGaWzXvCLyxrc7d+CCpUN3fYnkkcso3rCzwUmo/LteAl2ZGCDlGvDD8Y/1D3ngxT8KgDj1DSwOnNewKhmg=="], + + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-E2+PbcbzIReaAYZe997wb9rId246yDkCwAakllAWSGqe6VTg9hHle67hfH6ExjpV2LSK/siRzBUs5wVff3RW9w=="], + + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.3", "", { "os": "linux", "cpu": "arm" }, "sha512-GvfbJ8wjSSjbLFFE3UYz4Eh8i4L6GiEYqCtA8j2Zd2oXriPuom/Ah/64pg/szWycQpzRnbDiJozoxFU2oJZyfg=="], + + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-35UkuCWQTeG9BHcBQXndDOrpsnt3Pj9NVIB4CgNiKmpG8GnCNXeMczkUpOoqcOhO6Cc/mM2W7kaQ/MTEENDDXg=="], + + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-dm18aQiML5QCj9DQo7wMbt1Z2tl3Giht54uVR87a84X8qRtuXxUqnKQkRDK5B4bCOmcZ580lF9YcoMkbDYTXHQ=="], + + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.3", "", { "os": "linux", "cpu": "x64" }, "sha512-LMdTmGe/NPtGOaOfV2HuO7w07jI3cflPrVq5CXl+2O93DCewADK0uW1ORNAcfu2YxDUS035eY2W38TxrsqngxA=="], + + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.3", "", { "os": "linux", "cpu": "x64" }, "sha512-aalNWwIi54bbFEizwl1/XpmdDrOaCjRFQRgtbv9slWjmNPuJJTIKPHf5/XXDARc9CneW9FkSTqTbyvNecYAEGw=="], + + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-PEj7XR4OGTGoboTIAdXicKuWl4EQIjKHKuR+bFy9oYN7CFZo0eu74+70O4XuERX4yjqVZGAkCdglBODlgqcCXg=="], + + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.3", "", { "os": "win32", "cpu": "x64" }, "sha512-T8gfxECWDBENotpw3HR9SmNiHC9AOJdxs+woasRZ8Q/J4VHN0OMs7F+4yVNZ9EVN26Wv6mZbK0jv7eHYuLJLwA=="], + + "@tailwindcss/vite": ["@tailwindcss/vite@4.1.3", "", { "dependencies": { "@tailwindcss/node": "4.1.3", "@tailwindcss/oxide": "4.1.3", "tailwindcss": "4.1.3" }, "peerDependencies": { "vite": "^5.2.0 || ^6" } }, "sha512-lUI/QaDxLtlV52Lho6pu07CG9pSnRYLOPmKGIQjyHdTBagemc6HmgZxyjGAQ/5HMPrNeWBfTVIpQl0/jLXvWHQ=="], + + "@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="], + + "@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="], + + "acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="], + + "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], + + "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], + + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], + + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + + "cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="], + + "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="], + + "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], + + "detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="], + + "devalue": ["devalue@5.1.1", "", {}, "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw=="], + + "enhanced-resolve": ["enhanced-resolve@5.18.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg=="], + + "esbuild": ["esbuild@0.25.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.2", "@esbuild/android-arm": "0.25.2", "@esbuild/android-arm64": "0.25.2", "@esbuild/android-x64": "0.25.2", "@esbuild/darwin-arm64": "0.25.2", "@esbuild/darwin-x64": "0.25.2", "@esbuild/freebsd-arm64": "0.25.2", "@esbuild/freebsd-x64": "0.25.2", "@esbuild/linux-arm": "0.25.2", "@esbuild/linux-arm64": "0.25.2", "@esbuild/linux-ia32": "0.25.2", "@esbuild/linux-loong64": "0.25.2", "@esbuild/linux-mips64el": "0.25.2", "@esbuild/linux-ppc64": "0.25.2", "@esbuild/linux-riscv64": "0.25.2", "@esbuild/linux-s390x": "0.25.2", "@esbuild/linux-x64": "0.25.2", "@esbuild/netbsd-arm64": "0.25.2", "@esbuild/netbsd-x64": "0.25.2", "@esbuild/openbsd-arm64": "0.25.2", "@esbuild/openbsd-x64": "0.25.2", "@esbuild/sunos-x64": "0.25.2", "@esbuild/win32-arm64": "0.25.2", "@esbuild/win32-ia32": "0.25.2", "@esbuild/win32-x64": "0.25.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ=="], + + "esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="], + + "esrap": ["esrap@1.4.6", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw=="], + + "fdir": ["fdir@6.4.3", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "globalyzer": ["globalyzer@0.1.0", "", {}, "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q=="], + + "globrex": ["globrex@0.1.2", "", {}, "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "import-meta-resolve": ["import-meta-resolve@4.1.0", "", {}, "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw=="], + + "is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="], + + "jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="], + + "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], + + "lightningcss": ["lightningcss@1.29.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.29.2", "lightningcss-darwin-x64": "1.29.2", "lightningcss-freebsd-x64": "1.29.2", "lightningcss-linux-arm-gnueabihf": "1.29.2", "lightningcss-linux-arm64-gnu": "1.29.2", "lightningcss-linux-arm64-musl": "1.29.2", "lightningcss-linux-x64-gnu": "1.29.2", "lightningcss-linux-x64-musl": "1.29.2", "lightningcss-win32-arm64-msvc": "1.29.2", "lightningcss-win32-x64-msvc": "1.29.2" } }, "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA=="], + + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.29.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA=="], + + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.29.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w=="], + + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.29.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg=="], + + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.29.2", "", { "os": "linux", "cpu": "arm" }, "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg=="], + + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.29.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ=="], + + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.29.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ=="], + + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.29.2", "", { "os": "linux", "cpu": "x64" }, "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg=="], + + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.29.2", "", { "os": "linux", "cpu": "x64" }, "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w=="], + + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.29.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw=="], + + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.29.2", "", { "os": "win32", "cpu": "x64" }, "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA=="], + + "locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="], + + "magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="], + + "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], + + "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "pocketbase": ["pocketbase@0.25.2", "", {}, "sha512-ONZl1+qHJMnhR2uacBlBJ90lm7njtL/zy0606+1ROfK9hSL4LRBRc8r89rMcNRzPzRqCNyoFTh2Qg/lYXdEC1w=="], + + "postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="], + + "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + + "rollup": ["rollup@4.39.0", "", { "dependencies": { "@types/estree": "1.0.7" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.39.0", "@rollup/rollup-android-arm64": "4.39.0", "@rollup/rollup-darwin-arm64": "4.39.0", "@rollup/rollup-darwin-x64": "4.39.0", "@rollup/rollup-freebsd-arm64": "4.39.0", "@rollup/rollup-freebsd-x64": "4.39.0", "@rollup/rollup-linux-arm-gnueabihf": "4.39.0", "@rollup/rollup-linux-arm-musleabihf": "4.39.0", "@rollup/rollup-linux-arm64-gnu": "4.39.0", "@rollup/rollup-linux-arm64-musl": "4.39.0", "@rollup/rollup-linux-loongarch64-gnu": "4.39.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.39.0", "@rollup/rollup-linux-riscv64-gnu": "4.39.0", "@rollup/rollup-linux-riscv64-musl": "4.39.0", "@rollup/rollup-linux-s390x-gnu": "4.39.0", "@rollup/rollup-linux-x64-gnu": "4.39.0", "@rollup/rollup-linux-x64-musl": "4.39.0", "@rollup/rollup-win32-arm64-msvc": "4.39.0", "@rollup/rollup-win32-ia32-msvc": "4.39.0", "@rollup/rollup-win32-x64-msvc": "4.39.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-thI8kNc02yNvnmJp8dr3fNWJ9tCONDhp6TV35X6HkKGGs9E6q7YWCHbe5vKiTa7TAiNcFEmXKj3X/pG2b3ci0g=="], + + "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], + + "set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="], + + "sirv": ["sirv@3.0.1", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "svelte": ["svelte@5.25.10", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "esm-env": "^1.2.1", "esrap": "^1.4.6", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-tOUlvm3goAhmELYKWYX3SchYeqlVlIcUfKA4qIgd6Urm7qDw3KiZP/wJtoRv3ZeRUHPorM9f6+lOlbFxUN8QoA=="], + + "svelte-adapter-bun": ["svelte-adapter-bun@0.5.2", "", { "dependencies": { "tiny-glob": "^0.2.9" } }, "sha512-xEtFgaal6UgrCwwkSIcapO9kopoFNUYCYqyKCikdqxX9bz2TDYnrWQZ7qBnkunMxi1HOIERUCvTcebYGiarZLA=="], + + "svelte-check": ["svelte-check@4.1.5", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-Gb0T2IqBNe1tLB9EB1Qh+LOe+JB8wt2/rNBDGvkxQVvk8vNeAoG+vZgFB/3P5+zC7RWlyBlzm9dVjZFph/maIg=="], + + "tailwindcss": ["tailwindcss@4.1.3", "", {}, "sha512-2Q+rw9vy1WFXu5cIxlvsabCwhU2qUwodGq03ODhLJ0jW4ek5BUtoCsnLB0qG+m8AHgEsSJcJGDSDe06FXlP74g=="], + + "tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="], + + "tiny-glob": ["tiny-glob@0.2.9", "", { "dependencies": { "globalyzer": "0.1.0", "globrex": "^0.1.2" } }, "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg=="], + + "totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="], + + "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], + + "vite": ["vite@6.2.6", "", { "dependencies": { "esbuild": "^0.25.0", "postcss": "^8.5.3", "rollup": "^4.30.1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw=="], + + "vitefu": ["vitefu@1.0.6", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" }, "optionalPeers": ["vite"] }, "sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA=="], + + "zimmerframe": ["zimmerframe@1.1.2", "", {}, "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w=="], + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..542c8bf --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,29 @@ +{ + "name": "brawlset-rewrite", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "prepare": "svelte-kit sync || echo ''", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" + }, + "devDependencies": { + "@sveltejs/adapter-auto": "^4.0.0", + "@sveltejs/kit": "^2.16.0", + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "@tailwindcss/vite": "^4.0.0", + "svelte": "^5.0.0", + "svelte-check": "^4.0.0", + "tailwindcss": "^4.0.0", + "typescript": "^5.0.0", + "vite": "^6.2.5" + }, + "dependencies": { + "pocketbase": "^0.25.2", + "svelte-adapter-bun": "^0.5.2" + } +} diff --git a/frontend/src/app.css b/frontend/src/app.css new file mode 100644 index 0000000..dd2c583 --- /dev/null +++ b/frontend/src/app.css @@ -0,0 +1,34 @@ +@import 'tailwindcss'; + +@font-face { + font-family: "Beleren"; + src: url("/fonts/Beleren2016-Bold.woff"); +} + +@font-face { + font-family: "Inter-Tight-Normal"; + src: url("/fonts/inter-tight-latin-400-normal.ttf"); +} + +@font-face { + font-family: "Inter-Tight-Italic"; + src: url("/fonts/inter-tight-latin-400-italic.ttf"); +} + +@font-face { + font-family: "Inter-Tight-Bold"; + src: url("/fonts/inter-tight-latin-800-normal.ttf"); +} + +@font-face { + font-family: "Inter-Tight-Bold-Italic"; + src: url("/fonts/inter-tight-latin-800-italic.ttf"); +} + +.font-beleren { + font-family: 'Beleren'; +} + +.font-inter-tight { + font-family: 'Inter-Tight-Normal'; +} diff --git a/frontend/src/app.d.ts b/frontend/src/app.d.ts new file mode 100644 index 0000000..da08e6d --- /dev/null +++ b/frontend/src/app.d.ts @@ -0,0 +1,13 @@ +// See https://svelte.dev/docs/kit/types#app.d.ts +// for information about these interfaces +declare global { + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface PageState {} + // interface Platform {} + } +} + +export {}; diff --git a/frontend/src/app.html b/frontend/src/app.html new file mode 100644 index 0000000..77a5ff5 --- /dev/null +++ b/frontend/src/app.html @@ -0,0 +1,12 @@ + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/frontend/src/lib/components/Card.svelte b/frontend/src/lib/components/Card.svelte new file mode 100644 index 0000000..36b47e3 --- /dev/null +++ b/frontend/src/lib/components/Card.svelte @@ -0,0 +1,17 @@ + + +
+ {"Scan + {price}€ + {name} + {#if numberOfPossibleDecks == undefined} + {numberOfDecks} Decks + {:else} + {numberOfDecks} Decks sur {numberOfPossibleDecks} ({numberOfPossibleDecks != 0 ? Math.round(100 * (numberOfDecks / numberOfPossibleDecks)) : 0}%) + {/if} + {#if synergy != undefined} + Synergy {synergy > 0 ? "+" + Math.round(100*synergy).toString() : Math.round(100*synergy).toString()}% + {/if} +
diff --git a/frontend/src/lib/components/CardGrid.svelte b/frontend/src/lib/components/CardGrid.svelte new file mode 100644 index 0000000..11c8a12 --- /dev/null +++ b/frontend/src/lib/components/CardGrid.svelte @@ -0,0 +1,7 @@ + + +
+ {@render children()} +
diff --git a/frontend/src/lib/components/CardSearch.svelte b/frontend/src/lib/components/CardSearch.svelte new file mode 100644 index 0000000..35ed782 --- /dev/null +++ b/frontend/src/lib/components/CardSearch.svelte @@ -0,0 +1,38 @@ + + + { if (e.target === dialog) dialog.close(); }}> +
+ +
+ {#if searchResult.length == 0} + Pas de résultat... + {:else} + {#each searchResult as result} + + {result.Name} + {result.SetName} + + {/each} + {/if} +
+
+
diff --git a/frontend/src/lib/components/Footer.svelte b/frontend/src/lib/components/Footer.svelte new file mode 100644 index 0000000..6f0e6b6 --- /dev/null +++ b/frontend/src/lib/components/Footer.svelte @@ -0,0 +1,3 @@ +
+ Brawlset is unofficial Fan Content permitted under the Fan Content Policy. Not approved/endorsed by Wizards. Portions of the materials used are property of Wizards of the Coast. ©Wizards of the Coast LLC. +
diff --git a/frontend/src/lib/components/Navbar.svelte b/frontend/src/lib/components/Navbar.svelte new file mode 100644 index 0000000..1001bae --- /dev/null +++ b/frontend/src/lib/components/Navbar.svelte @@ -0,0 +1,226 @@ + + +
+ + brawlset website logo + BrawlSet + + +
+ + {#if isLoggedIn} + + + + + + {:else} + Connexion + Inscription + {/if} + +
+
+ + + + diff --git a/frontend/src/lib/components/base/Button.svelte b/frontend/src/lib/components/base/Button.svelte new file mode 100644 index 0000000..7385370 --- /dev/null +++ b/frontend/src/lib/components/base/Button.svelte @@ -0,0 +1,8 @@ + + + diff --git a/frontend/src/lib/components/base/Input.svelte b/frontend/src/lib/components/base/Input.svelte new file mode 100644 index 0000000..1afc5b3 --- /dev/null +++ b/frontend/src/lib/components/base/Input.svelte @@ -0,0 +1,5 @@ + + + diff --git a/frontend/src/lib/components/icons/Black.svelte b/frontend/src/lib/components/icons/Black.svelte new file mode 100644 index 0000000..0fc855a --- /dev/null +++ b/frontend/src/lib/components/icons/Black.svelte @@ -0,0 +1,5 @@ + + + diff --git a/frontend/src/lib/components/icons/Blue.svelte b/frontend/src/lib/components/icons/Blue.svelte new file mode 100644 index 0000000..34a5ff1 --- /dev/null +++ b/frontend/src/lib/components/icons/Blue.svelte @@ -0,0 +1,5 @@ + + + diff --git a/frontend/src/lib/components/icons/Colorless.svelte b/frontend/src/lib/components/icons/Colorless.svelte new file mode 100644 index 0000000..c92cf8f --- /dev/null +++ b/frontend/src/lib/components/icons/Colorless.svelte @@ -0,0 +1,5 @@ + + + diff --git a/frontend/src/lib/components/icons/DeckIcon.svelte b/frontend/src/lib/components/icons/DeckIcon.svelte new file mode 100644 index 0000000..b832cf4 --- /dev/null +++ b/frontend/src/lib/components/icons/DeckIcon.svelte @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/lib/components/icons/Green.svelte b/frontend/src/lib/components/icons/Green.svelte new file mode 100644 index 0000000..28e2eb3 --- /dev/null +++ b/frontend/src/lib/components/icons/Green.svelte @@ -0,0 +1,5 @@ + + + diff --git a/frontend/src/lib/components/icons/IconBase.svelte b/frontend/src/lib/components/icons/IconBase.svelte new file mode 100644 index 0000000..d8a4802 --- /dev/null +++ b/frontend/src/lib/components/icons/IconBase.svelte @@ -0,0 +1,5 @@ + + +{alt} diff --git a/frontend/src/lib/components/icons/MenuIcon.svelte b/frontend/src/lib/components/icons/MenuIcon.svelte new file mode 100644 index 0000000..356ce42 --- /dev/null +++ b/frontend/src/lib/components/icons/MenuIcon.svelte @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/lib/components/icons/Red.svelte b/frontend/src/lib/components/icons/Red.svelte new file mode 100644 index 0000000..25b8b8c --- /dev/null +++ b/frontend/src/lib/components/icons/Red.svelte @@ -0,0 +1,5 @@ + + + diff --git a/frontend/src/lib/components/icons/SearchIcon.svelte b/frontend/src/lib/components/icons/SearchIcon.svelte new file mode 100644 index 0000000..3887001 --- /dev/null +++ b/frontend/src/lib/components/icons/SearchIcon.svelte @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/lib/components/icons/White.svelte b/frontend/src/lib/components/icons/White.svelte new file mode 100644 index 0000000..5fe2b47 --- /dev/null +++ b/frontend/src/lib/components/icons/White.svelte @@ -0,0 +1,5 @@ + + + diff --git a/frontend/src/lib/index.ts b/frontend/src/lib/index.ts new file mode 100644 index 0000000..856f2b6 --- /dev/null +++ b/frontend/src/lib/index.ts @@ -0,0 +1 @@ +// place files you want to import through the `$lib` alias in this folder. diff --git a/frontend/src/routes/+layout.svelte b/frontend/src/routes/+layout.svelte new file mode 100644 index 0000000..8be6a08 --- /dev/null +++ b/frontend/src/routes/+layout.svelte @@ -0,0 +1,15 @@ + + +
+ +
+ {@render children()} +
+
+
diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte new file mode 100644 index 0000000..83fc9fb --- /dev/null +++ b/frontend/src/routes/+page.svelte @@ -0,0 +1,6 @@ +
+

CE SITE EST EN COURS DE DEVELOPPEMENT - NE SAUVEGARDEZ PAS VOS DONNÉES UNIQUEMENT SUR BRAWLSET

+

The BrawlSet

+

Un système de règles MTG basé sur le mode de jeu commander et inventé à Rennes, pays de la galette saucisse.
+Pour plus d'informations allez voir les règles ou la FAQ.

+
diff --git a/frontend/src/routes/bset/[slug]/+page.svelte b/frontend/src/routes/bset/[slug]/+page.svelte new file mode 100644 index 0000000..b7354f8 --- /dev/null +++ b/frontend/src/routes/bset/[slug]/+page.svelte @@ -0,0 +1,95 @@ + + +
+

{slug}

+ +

Commandants

+ + {#each commander as card} + + {/each} + + +

Planeswalker

+ + {#each planeswalker as card} + + {/each} + + +

Creature

+ + {#each creature as card} + + {/each} + + +

Rituels

+ + {#each sorcery as card} + + {/each} + + +

Artefacts

+ + {#each artifact as card} + + {/each} + + +

Éphémères

+ + {#each instant as card} + + {/each} + + +

Enchantements

+ + {#each enchantment as card} + + {/each} + + +

Terrains

+ + {#each land as card} + + {/each} + +
diff --git a/frontend/src/routes/bset/[slug]/+page.ts b/frontend/src/routes/bset/[slug]/+page.ts new file mode 100644 index 0000000..fa75e60 --- /dev/null +++ b/frontend/src/routes/bset/[slug]/+page.ts @@ -0,0 +1,6 @@ +import type { PageLoad } from './$types'; + +export const load: PageLoad = ({ params }) => { + console.log("test") + return {slug: params.slug, test: "yeeeeheeee"} +}; diff --git a/frontend/src/routes/bset/all/+page.svelte b/frontend/src/routes/bset/all/+page.svelte new file mode 100644 index 0000000..7be4ca4 --- /dev/null +++ b/frontend/src/routes/bset/all/+page.svelte @@ -0,0 +1,29 @@ + + +
+ + +
diff --git a/frontend/src/routes/commander/[slug]/+page.svelte b/frontend/src/routes/commander/[slug]/+page.svelte new file mode 100644 index 0000000..c0d66fe --- /dev/null +++ b/frontend/src/routes/commander/[slug]/+page.svelte @@ -0,0 +1,90 @@ + + +
+
+ +
+ +

Planeswalker

+ + {#each planeswalker as card} + + {/each} + + +

Creature

+ + {#each creature as card} + + {/each} + + +

Rituels

+ + {#each sorcery as card} + + {/each} + + +

Artefacts

+ + {#each artifact as card} + + {/each} + + +

Éphémères

+ + {#each instant as card} + + {/each} + + +

Enchantements

+ + {#each enchantment as card} + + {/each} + + +

Terrains

+ + {#each land as card} + + {/each} + +
diff --git a/frontend/src/routes/commander/[slug]/+page.ts b/frontend/src/routes/commander/[slug]/+page.ts new file mode 100644 index 0000000..fa75e60 --- /dev/null +++ b/frontend/src/routes/commander/[slug]/+page.ts @@ -0,0 +1,6 @@ +import type { PageLoad } from './$types'; + +export const load: PageLoad = ({ params }) => { + console.log("test") + return {slug: params.slug, test: "yeeeeheeee"} +}; diff --git a/frontend/src/routes/connexion/+page.svelte b/frontend/src/routes/connexion/+page.svelte new file mode 100644 index 0000000..f985605 --- /dev/null +++ b/frontend/src/routes/connexion/+page.svelte @@ -0,0 +1,34 @@ + + +
+
login(e)}> + + + +
+
diff --git a/frontend/src/routes/decks/+page.svelte b/frontend/src/routes/decks/+page.svelte new file mode 100644 index 0000000..d481ff6 --- /dev/null +++ b/frontend/src/routes/decks/+page.svelte @@ -0,0 +1,104 @@ + + +
+
+
+ + Commandant : {commander} +
+
+ + + + +
+
+
diff --git a/frontend/src/routes/faq/+page.svelte b/frontend/src/routes/faq/+page.svelte new file mode 100644 index 0000000..059b409 --- /dev/null +++ b/frontend/src/routes/faq/+page.svelte @@ -0,0 +1,4 @@ +
+

F.A.Q

+

Coming soon...

+
diff --git a/frontend/src/routes/profil/+page.svelte b/frontend/src/routes/profil/+page.svelte new file mode 100644 index 0000000..155a35e --- /dev/null +++ b/frontend/src/routes/profil/+page.svelte @@ -0,0 +1,13 @@ + + +
+ +
diff --git a/frontend/src/routes/regles/+page.svelte b/frontend/src/routes/regles/+page.svelte new file mode 100644 index 0000000..4dbbff2 --- /dev/null +++ b/frontend/src/routes/regles/+page.svelte @@ -0,0 +1,31 @@ +
+
+

BrawlSet Canon Règles Officielles

+

BrawlSet Committee

+

17 Octobre 2022

+
+
+

903.BS. Le mode de jeu BrawlSet

+
    +
  • 903.BS.1 Le BrawlSet est une variante du Commander. Cette variante utilise les règles classiques du Commander avec les modifications suivantes.
  • +
  • 903.BS.2 La Règle d’Or du format est d’utiliser des cartes provenant du même set. Pour des raisons de niveau des cartes et/ou d’histoire, certains sets sont regroupés en « BSet »
  • +
  • 903.BS.3 La liste des BSets est disponible dans le document List_BSet_FR.pdf
  • +
  • 903.BS.4 Une carte fait partie d’un BSet si elle a été imprimée au moins une fois avec le symbole d’édition d’un des sets qui composent le BSet. La liste complète des symboles d’édition peut être trouvée dans la section Card Set Archive du site Magic de Wizard of the Coast (lien)
  • +
  • Exemple : Cela prend en compte les cartes Timeshifted pour Time Spiral, les cartes de Brawl Decks, de Planeswalker Decks et de Theme Boosters, ainsi que les cartes de Buy a Box. Cela ne prend pas en compte les cartes des Masterpiece series (Explorer d’Ixalan, Expeditions de Zendikar, Inventions de Kaladesh, Invocations de Amonkhet, et Planeswalker Mythic Editions de Guilds of Ravnica, Ravnica Allegeance et War of the Spark).
  • +
  • 903.BS.5 Il n’y a pas de sideboard pour modifier son deck entre deux parties de BrawlSet. Cependant, comme certaines cartes permettent d’amener des cartes dans la partie depuis l’extérieur du jeu, les joueur·euses peuvent avoir un « wishboard ». Le nombre maximum de cartes d’un wishboard est 15, il n’y pas de nombre minimum de cartes.
  • +
  • 903.BS.6 Les cartes des wishboard sont hors de la partie, ainsi aucun effet de la partie ne peut permettre à un·e joueur·euse de regarder ou rechercher dans le wishboard d’un·e autre joueur·euse. Un·e joueur·euse ne peut amener une carte hors de la partie dans la partie sauf si cette carte vient de son wishboard ou d’une partie principale d’une sous-partie. Il n’y a pas de restriction sur l’identité colorée des cartes qu’un·e joueur·euse peut amener dans la partie depuis l’extérieur du jeu, ceci est une modification de la règle 903.11.
  • +
  • Exemple : Léon lance Emrakul, the Promised End pour prendre le contrôle de l’adversaire ciblé durant son prochain tour et prend le contrôle du prochain tour de Dylan. Léon peut faire en sorte que Dylan lance Granted, l’aventure de Fae of Wishes pendant qu’il contrôle le tour de Dylan. Léon ne pourra pas chercher ou trouver quoi que ce soit dans le wishboard de Dylan. Parce que l’effet demande de chercher dans le wishboard du joueur / de la joueuse lançant cette carte, Léon ne peut pas chercher dans son wishboard. Aucune carte ne sera amenée dans la partie.
  • +
  • 903.BS.7 Un·e joueur·euse désigne comme commandant un Planeswalker légendaire ou une créature légendaire. Ceci est une modification de la règle 903.3
  • +
  • 903.BS.8 Si un deck de BrawlSet utilise un·e compagnon·ne, le/la compagnon·ne doit respecter l’identité colorée du commandant.
  • +
  • 903.BS.9 La règle de construction en singleton du Commander s’applique à la combinaison du deck et du wishboard. Ceci est une modification de la règle 903.5b
  • +
  • 903.BS.10 Toutes les cartes d’un deck de BrawlSet doivent faire partie du même BSet. Cette règle s’applique à la combinaison du deck et du wishboard. Cette règle s’applique aux terrains de base. Ce BSet est le BSet du deck.
  • +
  • 903.BS.11 Une carte avec un type de terrain de base ne peut être inclue dans un deck que si elle ne produit que du mana de l’identité colorée du commandant. Si aucun terrain de base faisant partie du BSet de ce deck ne vérifie cette propriété, cette règle ne s’applique pas pour les terrains de base pour ce deck. Ceci est une modification de la règle 903.5d.
  • +
  • Exemple : Paul veut construire un deck de BrawlSet War of the Spark avec Karn, the Great Creator en commandant. Comme l’identité colorée de Karn est incolore et que les Wastes n’ont pas été éditées dans War of the Spark, Paul peut utiliser n’importe quel terrain de base édité dans War of the Spark pour construire son deck, par exemple une Forest, huit Islands, neuf Mountains, treize Plains et quinze Swamps.
  • +
  • 903.BS.12 La taille minimum d’un deck de BrawlSet est 60, il n’y a pas de taille maximum de deck. Ceci est une modification de la règle 903.5a.
  • +
  • 903.BS.13 Dans une partie de BrawlSet, le nombre de point de vie de départ est 20. Ceci est une modification de la règle 119.1c
  • +
  • 903.BS.14 Les parties de BrawlSet n’utilisent pas la règle des blessures de commandant, ainsi l’action décrite dans la règle 704.5v, qui fait perdre un·e joueur·euse qui a subi 21 blessures de combat ou plus d’un commandant ne s’applique pas. Ceci est une modification de la règle 704.5v.
  • +
  • 903.BS.15 Au début d’un match, chaque joueur·euse doit déclarer son BSet, il ne peut pas être changé entre les parties d’un même match.
  • +
  • 903.BS.16 Le format de BrawlSet utilise la règle du commander swap. Cela signifie que n’importe quel joueur·euse peut changer de commandant entre deux parties d’un match. Le nouveau commandant doit être une carte du deck, l’ancien commandant devient une carte normale du deck. Le commandant du deck reste secret jusqu’à ce qu’il soit révélé au début de la partie.
  • +
+
+
diff --git a/frontend/static/assets/artifact.svg b/frontend/static/assets/artifact.svg new file mode 100644 index 0000000..1590661 --- /dev/null +++ b/frontend/static/assets/artifact.svg @@ -0,0 +1,38 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/frontend/static/assets/commander.svg b/frontend/static/assets/commander.svg new file mode 100644 index 0000000..98b17f6 --- /dev/null +++ b/frontend/static/assets/commander.svg @@ -0,0 +1,21 @@ + + + + + + + + + diff --git a/frontend/static/assets/creature.svg b/frontend/static/assets/creature.svg new file mode 100644 index 0000000..cef6b0e --- /dev/null +++ b/frontend/static/assets/creature.svg @@ -0,0 +1,38 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/frontend/static/assets/enchantment.svg b/frontend/static/assets/enchantment.svg new file mode 100644 index 0000000..4935ddf --- /dev/null +++ b/frontend/static/assets/enchantment.svg @@ -0,0 +1,38 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/frontend/static/assets/instant.svg b/frontend/static/assets/instant.svg new file mode 100644 index 0000000..3316ad0 --- /dev/null +++ b/frontend/static/assets/instant.svg @@ -0,0 +1,38 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/frontend/static/assets/land.svg b/frontend/static/assets/land.svg new file mode 100644 index 0000000..d5ecc9f --- /dev/null +++ b/frontend/static/assets/land.svg @@ -0,0 +1,38 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/frontend/static/assets/logo.png b/frontend/static/assets/logo.png new file mode 100644 index 0000000..52dfcaf Binary files /dev/null and b/frontend/static/assets/logo.png differ diff --git a/frontend/static/assets/planeswalker.svg b/frontend/static/assets/planeswalker.svg new file mode 100644 index 0000000..7e3851c --- /dev/null +++ b/frontend/static/assets/planeswalker.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/frontend/static/assets/sorcery.svg b/frontend/static/assets/sorcery.svg new file mode 100644 index 0000000..f7a2e16 --- /dev/null +++ b/frontend/static/assets/sorcery.svg @@ -0,0 +1,38 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/frontend/static/favicon.ico b/frontend/static/favicon.ico new file mode 100644 index 0000000..0ad4eeb Binary files /dev/null and b/frontend/static/favicon.ico differ diff --git a/frontend/static/favicon.png b/frontend/static/favicon.png new file mode 100644 index 0000000..52dfcaf Binary files /dev/null and b/frontend/static/favicon.png differ diff --git a/frontend/static/fonts/Beleren2016-Bold.woff b/frontend/static/fonts/Beleren2016-Bold.woff new file mode 100644 index 0000000..b716efa Binary files /dev/null and b/frontend/static/fonts/Beleren2016-Bold.woff differ diff --git a/frontend/static/fonts/GeistMonoVF.woff b/frontend/static/fonts/GeistMonoVF.woff new file mode 100644 index 0000000..f2ae185 Binary files /dev/null and b/frontend/static/fonts/GeistMonoVF.woff differ diff --git a/frontend/static/fonts/GeistVF.woff b/frontend/static/fonts/GeistVF.woff new file mode 100644 index 0000000..1b62daa Binary files /dev/null and b/frontend/static/fonts/GeistVF.woff differ diff --git a/frontend/static/fonts/inter-tight-latin-400-italic.ttf b/frontend/static/fonts/inter-tight-latin-400-italic.ttf new file mode 100644 index 0000000..5c011df Binary files /dev/null and b/frontend/static/fonts/inter-tight-latin-400-italic.ttf differ diff --git a/frontend/static/fonts/inter-tight-latin-400-normal.ttf b/frontend/static/fonts/inter-tight-latin-400-normal.ttf new file mode 100644 index 0000000..4301e14 Binary files /dev/null and b/frontend/static/fonts/inter-tight-latin-400-normal.ttf differ diff --git a/frontend/static/fonts/inter-tight-latin-800-italic.ttf b/frontend/static/fonts/inter-tight-latin-800-italic.ttf new file mode 100644 index 0000000..de14075 Binary files /dev/null and b/frontend/static/fonts/inter-tight-latin-800-italic.ttf differ diff --git a/frontend/static/fonts/inter-tight-latin-800-normal.ttf b/frontend/static/fonts/inter-tight-latin-800-normal.ttf new file mode 100644 index 0000000..3b5ae8e Binary files /dev/null and b/frontend/static/fonts/inter-tight-latin-800-normal.ttf differ diff --git a/frontend/svelte.config.js b/frontend/svelte.config.js new file mode 100644 index 0000000..e64cff3 --- /dev/null +++ b/frontend/svelte.config.js @@ -0,0 +1,31 @@ +import adapter from "svelte-adapter-bun"; +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + // Consult https://svelte.dev/docs/kit/integrations + // for more information about preprocessors + preprocess: vitePreprocess(), + + kit: { + // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list. + // If your environment is not supported, or you settled on a specific environment, switch out the adapter. + // See https://svelte.dev/docs/kit/adapters for more information about adapters. + adapter: adapter({ + out: "build", + assets: true, + envPrefix: "BRAWLSET_", + development: true, + // precompress: true, + precompress: { + brotli: true, + gzip: true, + files: ["htm", "html"], + }, + dynamic_origin: true, + xff_depth: 1, + }), + } +}; + +export default config; diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 0000000..0b2d886 --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } + // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias + // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files + // + // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes + // from the referenced tsconfig.json - TypeScript does not merge them in +} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts new file mode 100644 index 0000000..8ce55e4 --- /dev/null +++ b/frontend/vite.config.ts @@ -0,0 +1,12 @@ +import tailwindcss from '@tailwindcss/vite'; +import { sveltekit } from '@sveltejs/kit/vite'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + plugins: [tailwindcss(), sveltekit()], + server: { + watch: { + ignored: ["**/backend/**"], + }, + }, +}); diff --git a/start_server.sh b/start_server.sh new file mode 100755 index 0000000..adc81d2 --- /dev/null +++ b/start_server.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +bun run start /dev/null & +./custom_pocketbase serve --http=0.0.0.0:8090