add paste functionality
Some checks failed
Build and Deploy Website / build (push) Failing after 2m46s

This commit is contained in:
2026-02-27 23:38:14 -08:00
parent ed5e40b3f4
commit 3934751615
15 changed files with 959 additions and 260 deletions

View File

@@ -1,3 +1,5 @@
module smpark.in module smpark.in
go 1.23 go 1.24.0
require golang.org/x/time v0.14.0

2
Backend/go.sum Normal file
View File

@@ -0,0 +1,2 @@
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=

View File

@@ -1,31 +1,46 @@
package main package main
import ( import (
"log" "context"
"log/slog"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"time"
"golang.org/x/time/rate"
"smpark.in/paste"
) )
func main() { func main() {
publicDir := "./public" publicDir := "./public"
spaIndex := filepath.Join(publicDir, "app", "index.html") spaIndex := filepath.Join(publicDir, "app", "index.html")
store := paste.NewStore()
go paste.StartExpiryWorker(context.Background(), store, 30*time.Second)
rl := paste.NewRateLimiter(rate.Every(30*time.Second), 1)
handlers := paste.NewHandlers(store)
http.HandleFunc("POST /api/paste", rl.Middleware(handlers.Create))
http.HandleFunc("GET /api/paste/{id}/raw", handlers.GetRaw)
http.HandleFunc("GET /api/paste/{id}", handlers.Get)
fs := http.FileServer(http.Dir(publicDir)) fs := http.FileServer(http.Dir(publicDir))
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// Try to serve the static file
path := filepath.Join(publicDir, filepath.Clean(r.URL.Path)) path := filepath.Join(publicDir, filepath.Clean(r.URL.Path))
if info, err := os.Stat(path); err == nil && !info.IsDir() { if info, err := os.Stat(path); err == nil && !info.IsDir() {
fs.ServeHTTP(w, r) fs.ServeHTTP(w, r)
return return
} }
// Fall back to SPA index for client-side routing
http.ServeFile(w, r, spaIndex) http.ServeFile(w, r, spaIndex)
}) })
addr := ":8080" addr := ":8080"
log.Printf("Listening on %s", addr) slog.Info("listening", "addr", addr)
log.Fatal(http.ListenAndServe(addr, nil)) if err := http.ListenAndServe(addr, nil); err != nil {
slog.Error("server error", "err", err)
}
} }

42
Backend/paste/expiry.go Normal file
View File

@@ -0,0 +1,42 @@
package paste
import (
"context"
"log/slog"
"time"
)
func StartExpiryWorker(ctx context.Context, s *Store, interval time.Duration) {
ticker := time.NewTicker(interval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
deleteExpired(s)
}
}
}
func deleteExpired(s *Store) {
var expired []string
err := s.ForEach(func(p *Paste) error {
if p.ExpiresAt != nil && time.Now().After(*p.ExpiresAt) {
expired = append(expired, p.ID)
}
return nil
})
if err != nil {
slog.Error("expiry scan error", "err", err)
return
}
for _, id := range expired {
if err := s.Delete(id); err != nil {
slog.Error("expiry delete error", "id", id, "err", err)
}
}
if len(expired) > 0 {
slog.Info("deleted expired pastes", "count", len(expired))
}
}

118
Backend/paste/handlers.go Normal file
View File

@@ -0,0 +1,118 @@
package paste
import (
"encoding/json"
"errors"
"net/http"
"time"
)
type Handlers struct {
store *Store
}
func NewHandlers(store *Store) *Handlers {
return &Handlers{store: store}
}
type createRequest struct {
Title string `json:"title"`
Content string `json:"content"`
Language string `json:"language"`
Expiry int `json:"expiry"`
}
func writeJSON(w http.ResponseWriter, status int, v any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(v)
}
func writeError(w http.ResponseWriter, status int, msg string) {
writeJSON(w, status, map[string]string{"error": msg})
}
func (h *Handlers) Create(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, 1_100_000)
var req createRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeError(w, http.StatusBadRequest, "invalid request body")
return
}
if req.Content == "" {
writeError(w, http.StatusBadRequest, "content is required")
return
}
if len(req.Content) > 1_000_000 {
writeError(w, http.StatusRequestEntityTooLarge, "content exceeds 1,000,000 characters")
return
}
if len(req.Title) > 200 {
writeError(w, http.StatusBadRequest, "title exceeds 200 characters")
return
}
p := &Paste{
Title: req.Title,
Content: req.Content,
Language: req.Language,
}
if req.Expiry < 1 || req.Expiry > 10 {
writeError(w, http.StatusBadRequest, "expiry must be between 1 and 10 minutes")
return
}
t := time.Now().Add(time.Duration(req.Expiry) * time.Minute)
p.ExpiresAt = &t
if err := h.store.Create(p); err != nil {
writeError(w, http.StatusInternalServerError, "failed to create paste")
return
}
writeJSON(w, http.StatusCreated, map[string]string{
"id": p.ID,
"url": "/paste/" + p.ID,
})
}
func (h *Handlers) Get(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
p, err := h.store.Get(id)
if errors.Is(err, ErrNotFound) {
writeError(w, http.StatusNotFound, "paste not found")
return
}
if err != nil {
writeError(w, http.StatusInternalServerError, "failed to retrieve paste")
return
}
if p.ExpiresAt != nil && time.Now().After(*p.ExpiresAt) {
h.store.Delete(id)
writeError(w, http.StatusGone, "paste has expired")
return
}
writeJSON(w, http.StatusOK, p)
}
func (h *Handlers) GetRaw(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
p, err := h.store.Get(id)
if errors.Is(err, ErrNotFound) {
http.Error(w, "paste not found", http.StatusNotFound)
return
}
if err != nil {
http.Error(w, "failed to retrieve paste", http.StatusInternalServerError)
return
}
if p.ExpiresAt != nil && time.Now().After(*p.ExpiresAt) {
h.store.Delete(id)
http.Error(w, "paste has expired", http.StatusGone)
return
}
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Write([]byte(p.Content))
}

View File

@@ -0,0 +1,82 @@
package paste
import (
"log/slog"
"net"
"net/http"
"strings"
"sync"
"time"
"golang.org/x/time/rate"
)
type ipLimiter struct {
limiter *rate.Limiter
lastSeen time.Time
}
type RateLimiter struct {
mu sync.Mutex
limiters map[string]*ipLimiter
rate rate.Limit
burst int
}
func NewRateLimiter(r rate.Limit, burst int) *RateLimiter {
rl := &RateLimiter{
limiters: make(map[string]*ipLimiter),
rate: r,
burst: burst,
}
go rl.cleanup()
return rl
}
func (rl *RateLimiter) get(ip string) *rate.Limiter {
rl.mu.Lock()
defer rl.mu.Unlock()
entry, ok := rl.limiters[ip]
if !ok {
entry = &ipLimiter{limiter: rate.NewLimiter(rl.rate, rl.burst)}
rl.limiters[ip] = entry
}
entry.lastSeen = time.Now()
return entry.limiter
}
func (rl *RateLimiter) cleanup() {
for range time.Tick(5 * time.Minute) {
rl.mu.Lock()
for ip, entry := range rl.limiters {
if time.Since(entry.lastSeen) > 10*time.Minute {
delete(rl.limiters, ip)
}
}
rl.mu.Unlock()
}
}
func (rl *RateLimiter) Middleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ip := extractIP(r)
if !rl.get(ip).Allow() {
slog.Warn("rate limit exceeded", "ip", ip)
writeError(w, http.StatusTooManyRequests, "rate limit exceeded")
return
}
next(w, r)
}
}
func extractIP(r *http.Request) string {
if fwd := r.Header.Get("X-Forwarded-For"); fwd != "" {
parts := strings.SplitN(fwd, ",", 2)
return strings.TrimSpace(parts[0])
}
host, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
return r.RemoteAddr
}
return host
}

95
Backend/paste/store.go Normal file
View File

@@ -0,0 +1,95 @@
package paste
import (
"crypto/rand"
"errors"
"sync"
"time"
)
var ErrNotFound = errors.New("paste not found")
type Paste struct {
ID string `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
Language string `json:"language"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt *time.Time `json:"expires_at"`
}
type Store struct {
mu sync.RWMutex
pastes map[string]*Paste
}
func NewStore() *Store {
return &Store{pastes: make(map[string]*Paste)}
}
func (s *Store) Create(p *Paste) error {
id, err := generateID()
if err != nil {
return err
}
p.ID = id
p.CreatedAt = time.Now().UTC()
s.mu.Lock()
s.pastes[id] = p
s.mu.Unlock()
return nil
}
func (s *Store) Get(id string) (*Paste, error) {
s.mu.RLock()
p, ok := s.pastes[id]
s.mu.RUnlock()
if !ok {
return nil, ErrNotFound
}
return p, nil
}
func (s *Store) Delete(id string) error {
s.mu.Lock()
delete(s.pastes, id)
s.mu.Unlock()
return nil
}
func (s *Store) ForEach(fn func(p *Paste) error) error {
s.mu.RLock()
ids := make([]string, 0, len(s.pastes))
for id := range s.pastes {
ids = append(ids, id)
}
s.mu.RUnlock()
for _, id := range ids {
s.mu.RLock()
p, ok := s.pastes[id]
s.mu.RUnlock()
if !ok {
continue
}
if err := fn(p); err != nil {
return err
}
}
return nil
}
const base62Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
func generateID() (string, error) {
b := make([]byte, 8)
if _, err := rand.Read(b); err != nil {
return "", err
}
result := make([]byte, 8)
for i, v := range b {
result[i] = base62Chars[int(v)%62]
}
return string(result), nil
}

View File

@@ -15,8 +15,7 @@ RUN npm run build -- --outDir dist --emptyOutDir
FROM golang:1.23-alpine AS backend FROM golang:1.23-alpine AS backend
WORKDIR /build WORKDIR /build
COPY Backend/go.mod ./ COPY Backend/ ./
COPY Backend/main.go ./
RUN CGO_ENABLED=0 go build -o server . RUN CGO_ENABLED=0 go build -o server .
# ================================ # ================================

View File

@@ -8,6 +8,7 @@
"name": "frontend", "name": "frontend",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@cloudscape-design/code-view": "^3.0.102",
"@cloudscape-design/components": "^3.0.1200", "@cloudscape-design/components": "^3.0.1200",
"@cloudscape-design/global-styles": "^1.0.50", "@cloudscape-design/global-styles": "^1.0.50",
"react": "^19.2.0", "react": "^19.2.0",
@@ -321,6 +322,21 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@cloudscape-design/code-view": {
"version": "3.0.103",
"resolved": "https://registry.npmjs.org/@cloudscape-design/code-view/-/code-view-3.0.103.tgz",
"integrity": "sha512-zzn/bKZBl/l/A0Z4SL+kymjpyJB0vzb2verAxMzXbrQFnZz4gyFvV/VzP9HnbmHkM+nFJEFbqW7jLcuSPkin1g==",
"license": "Apache-2.0",
"dependencies": {
"@cloudscape-design/component-toolkit": "^1.0.0-beta",
"ace-code": "^1.32.3",
"clsx": "^1.2.1"
},
"peerDependencies": {
"@cloudscape-design/components": "^3",
"react": ">=18.2.0"
}
},
"node_modules/@cloudscape-design/collection-hooks": { "node_modules/@cloudscape-design/collection-hooks": {
"version": "1.0.82", "version": "1.0.82",
"resolved": "https://registry.npmjs.org/@cloudscape-design/collection-hooks/-/collection-hooks-1.0.82.tgz", "resolved": "https://registry.npmjs.org/@cloudscape-design/collection-hooks/-/collection-hooks-1.0.82.tgz",
@@ -346,16 +362,10 @@
"react": ">=16.8.0" "react": ">=16.8.0"
} }
}, },
"node_modules/@cloudscape-design/component-toolkit/node_modules/weekstart": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/weekstart/-/weekstart-2.0.0.tgz",
"integrity": "sha512-HjYc14IQUwDcnGICuc8tVtqAd6EFpoAQMqgrqcNtWWZB+F1b7iTq44GzwM1qvnH4upFgbhJsaNHuK93NOFheSg==",
"license": "MIT"
},
"node_modules/@cloudscape-design/components": { "node_modules/@cloudscape-design/components": {
"version": "3.0.1200", "version": "3.0.1214",
"resolved": "https://registry.npmjs.org/@cloudscape-design/components/-/components-3.0.1200.tgz", "resolved": "https://registry.npmjs.org/@cloudscape-design/components/-/components-3.0.1214.tgz",
"integrity": "sha512-V/2Ah+f2D4IbNTGu5gI+9dZTWf0V+CVpyKCVxSGlfiti/OLH5kjzeZTzFxSVVDH2ZzMm0CdZH1W8iw94wGnVvQ==", "integrity": "sha512-N7Bp14swR/nrCc8vX88O70JlGg/kVmLWh6Sfuy320DtOD6n1bbYRrQ5PYtuty+5PZhbZiXoI+XgQO5NJBzaLcQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@cloudscape-design/collection-hooks": "^1.0.0", "@cloudscape-design/collection-hooks": "^1.0.0",
@@ -371,7 +381,7 @@
"date-fns": "^2.25.0", "date-fns": "^2.25.0",
"intl-messageformat": "^10.3.1", "intl-messageformat": "^10.3.1",
"mnth": "^2.0.0", "mnth": "^2.0.0",
"react-keyed-flatten-children": "^2.2.1", "react-is": "^18.2.0",
"react-transition-group": "^4.4.2", "react-transition-group": "^4.4.2",
"tslib": "^2.4.0", "tslib": "^2.4.0",
"weekstart": "^1.1.0" "weekstart": "^1.1.0"
@@ -380,6 +390,12 @@
"react": ">=16.8.0" "react": ">=16.8.0"
} }
}, },
"node_modules/@cloudscape-design/components/node_modules/weekstart": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/weekstart/-/weekstart-1.1.0.tgz",
"integrity": "sha512-ZO3I7c7J9nwGN1PZKZeBYAsuwWEsCOZi5T68cQoVNYrzrpp5Br0Bgi0OF4l8kH/Ez7nKfxa5mSsXjsgris3+qg==",
"license": "MIT"
},
"node_modules/@cloudscape-design/global-styles": { "node_modules/@cloudscape-design/global-styles": {
"version": "1.0.50", "version": "1.0.50",
"resolved": "https://registry.npmjs.org/@cloudscape-design/global-styles/-/global-styles-1.0.50.tgz", "resolved": "https://registry.npmjs.org/@cloudscape-design/global-styles/-/global-styles-1.0.50.tgz",
@@ -397,9 +413,9 @@
} }
}, },
"node_modules/@cloudscape-design/theming-runtime": { "node_modules/@cloudscape-design/theming-runtime": {
"version": "1.0.91", "version": "1.0.95",
"resolved": "https://registry.npmjs.org/@cloudscape-design/theming-runtime/-/theming-runtime-1.0.91.tgz", "resolved": "https://registry.npmjs.org/@cloudscape-design/theming-runtime/-/theming-runtime-1.0.95.tgz",
"integrity": "sha512-umIE/M+tzrFo9c4Skrh4AFFtaDC4eANkjp+xYikUj7ng6wTXj6kkSzxbVbg2fBEmIUgLYAzMHYbyKUzQWuz0ag==", "integrity": "sha512-jTksnxcD/tgrwnv+e6+qcG+ivcbCDJTO5D6QB7HxLPOtfELPNsiuDV13QPpxB7WJMmU3GEDI8m01dpRFQMRy7Q==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@material/material-color-utilities": "^0.3.0", "@material/material-color-utilities": "^0.3.0",
@@ -985,20 +1001,20 @@
} }
}, },
"node_modules/@eslint/eslintrc": { "node_modules/@eslint/eslintrc": {
"version": "3.3.3", "version": "3.3.4",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.4.tgz",
"integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", "integrity": "sha512-4h4MVF8pmBsncB60r0wSJiIeUKTSD4m7FmTFThG8RHlsg9ajqckLm9OraguFGZE4vVdpiI1Q4+hFnisopmG6gQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ajv": "^6.12.4", "ajv": "^6.14.0",
"debug": "^4.3.2", "debug": "^4.3.2",
"espree": "^10.0.1", "espree": "^10.0.1",
"globals": "^14.0.0", "globals": "^14.0.0",
"ignore": "^5.2.0", "ignore": "^5.2.0",
"import-fresh": "^3.2.1", "import-fresh": "^3.2.1",
"js-yaml": "^4.1.1", "js-yaml": "^4.1.1",
"minimatch": "^3.1.2", "minimatch": "^3.1.3",
"strip-json-comments": "^3.1.1" "strip-json-comments": "^3.1.1"
}, },
"engines": { "engines": {
@@ -1022,9 +1038,9 @@
} }
}, },
"node_modules/@eslint/js": { "node_modules/@eslint/js": {
"version": "9.39.2", "version": "9.39.3",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.3.tgz",
"integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", "integrity": "sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -1225,9 +1241,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@rollup/rollup-android-arm-eabi": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz",
"integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -1239,9 +1255,9 @@
] ]
}, },
"node_modules/@rollup/rollup-android-arm64": { "node_modules/@rollup/rollup-android-arm64": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz",
"integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1253,9 +1269,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-arm64": { "node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz",
"integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1267,9 +1283,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-x64": { "node_modules/@rollup/rollup-darwin-x64": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz",
"integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1281,9 +1297,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-arm64": { "node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz",
"integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1295,9 +1311,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-x64": { "node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz",
"integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1309,9 +1325,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-gnueabihf": { "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz",
"integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -1323,9 +1339,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-musleabihf": { "node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz",
"integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -1337,9 +1353,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-gnu": { "node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz",
"integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1351,9 +1367,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-musl": { "node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz",
"integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1365,9 +1381,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-loong64-gnu": { "node_modules/@rollup/rollup-linux-loong64-gnu": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz",
"integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
@@ -1379,9 +1395,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-loong64-musl": { "node_modules/@rollup/rollup-linux-loong64-musl": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz",
"integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
@@ -1393,9 +1409,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-ppc64-gnu": { "node_modules/@rollup/rollup-linux-ppc64-gnu": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz",
"integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -1407,9 +1423,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-ppc64-musl": { "node_modules/@rollup/rollup-linux-ppc64-musl": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz",
"integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -1421,9 +1437,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-gnu": { "node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz",
"integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@@ -1435,9 +1451,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-musl": { "node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz",
"integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@@ -1449,9 +1465,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-s390x-gnu": { "node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz",
"integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@@ -1463,9 +1479,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-gnu": { "node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz",
"integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1477,9 +1493,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-musl": { "node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz",
"integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1491,9 +1507,9 @@
] ]
}, },
"node_modules/@rollup/rollup-openbsd-x64": { "node_modules/@rollup/rollup-openbsd-x64": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz",
"integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1505,9 +1521,9 @@
] ]
}, },
"node_modules/@rollup/rollup-openharmony-arm64": { "node_modules/@rollup/rollup-openharmony-arm64": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz",
"integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1519,9 +1535,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-arm64-msvc": { "node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz",
"integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1533,9 +1549,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-ia32-msvc": { "node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz",
"integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -1547,9 +1563,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-x64-gnu": { "node_modules/@rollup/rollup-win32-x64-gnu": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz",
"integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1561,9 +1577,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-x64-msvc": { "node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz",
"integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1634,9 +1650,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "24.10.13", "version": "24.11.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.13.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.11.0.tgz",
"integrity": "sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg==", "integrity": "sha512-fPxQqz4VTgPI/IQ+lj9r0h+fDR66bzoeMGHp8ASee+32OSGIkeASsoZuJixsQoVef1QJbeubcPBxKk22QVoWdw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -1664,17 +1680,17 @@
} }
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.55.0", "version": "8.56.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.55.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz",
"integrity": "sha512-1y/MVSz0NglV1ijHC8OT49mPJ4qhPYjiK08YUQVbIOyu+5k862LKUHFkpKHWu//zmr7hDR2rhwUm6gnCGNmGBQ==", "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.12.2", "@eslint-community/regexpp": "^4.12.2",
"@typescript-eslint/scope-manager": "8.55.0", "@typescript-eslint/scope-manager": "8.56.1",
"@typescript-eslint/type-utils": "8.55.0", "@typescript-eslint/type-utils": "8.56.1",
"@typescript-eslint/utils": "8.55.0", "@typescript-eslint/utils": "8.56.1",
"@typescript-eslint/visitor-keys": "8.55.0", "@typescript-eslint/visitor-keys": "8.56.1",
"ignore": "^7.0.5", "ignore": "^7.0.5",
"natural-compare": "^1.4.0", "natural-compare": "^1.4.0",
"ts-api-utils": "^2.4.0" "ts-api-utils": "^2.4.0"
@@ -1687,8 +1703,8 @@
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"@typescript-eslint/parser": "^8.55.0", "@typescript-eslint/parser": "^8.56.1",
"eslint": "^8.57.0 || ^9.0.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.0.0" "typescript": ">=4.8.4 <6.0.0"
} }
}, },
@@ -1703,16 +1719,16 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "8.55.0", "version": "8.56.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.55.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz",
"integrity": "sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==", "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.55.0", "@typescript-eslint/scope-manager": "8.56.1",
"@typescript-eslint/types": "8.55.0", "@typescript-eslint/types": "8.56.1",
"@typescript-eslint/typescript-estree": "8.55.0", "@typescript-eslint/typescript-estree": "8.56.1",
"@typescript-eslint/visitor-keys": "8.55.0", "@typescript-eslint/visitor-keys": "8.56.1",
"debug": "^4.4.3" "debug": "^4.4.3"
}, },
"engines": { "engines": {
@@ -1723,19 +1739,19 @@
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.0.0" "typescript": ">=4.8.4 <6.0.0"
} }
}, },
"node_modules/@typescript-eslint/project-service": { "node_modules/@typescript-eslint/project-service": {
"version": "8.55.0", "version": "8.56.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.55.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz",
"integrity": "sha512-zRcVVPFUYWa3kNnjaZGXSu3xkKV1zXy8M4nO/pElzQhFweb7PPtluDLQtKArEOGmjXoRjnUZ29NjOiF0eCDkcQ==", "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.55.0", "@typescript-eslint/tsconfig-utils": "^8.56.1",
"@typescript-eslint/types": "^8.55.0", "@typescript-eslint/types": "^8.56.1",
"debug": "^4.4.3" "debug": "^4.4.3"
}, },
"engines": { "engines": {
@@ -1750,14 +1766,14 @@
} }
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "8.55.0", "version": "8.56.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.55.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz",
"integrity": "sha512-fVu5Omrd3jeqeQLiB9f1YsuK/iHFOwb04bCtY4BSCLgjNbOD33ZdV6KyEqplHr+IlpgT0QTZ/iJ+wT7hvTx49Q==", "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.55.0", "@typescript-eslint/types": "8.56.1",
"@typescript-eslint/visitor-keys": "8.55.0" "@typescript-eslint/visitor-keys": "8.56.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1768,9 +1784,9 @@
} }
}, },
"node_modules/@typescript-eslint/tsconfig-utils": { "node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.55.0", "version": "8.56.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.55.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz",
"integrity": "sha512-1R9cXqY7RQd7WuqSN47PK9EDpgFUK3VqdmbYrvWJZYDd0cavROGn+74ktWBlmJ13NXUQKlZ/iAEQHI/V0kKe0Q==", "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -1785,15 +1801,15 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "8.55.0", "version": "8.56.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.55.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz",
"integrity": "sha512-x1iH2unH4qAt6I37I2CGlsNs+B9WGxurP2uyZLRz6UJoZWDBx9cJL1xVN/FiOmHEONEg6RIufdvyT0TEYIgC5g==", "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.55.0", "@typescript-eslint/types": "8.56.1",
"@typescript-eslint/typescript-estree": "8.55.0", "@typescript-eslint/typescript-estree": "8.56.1",
"@typescript-eslint/utils": "8.55.0", "@typescript-eslint/utils": "8.56.1",
"debug": "^4.4.3", "debug": "^4.4.3",
"ts-api-utils": "^2.4.0" "ts-api-utils": "^2.4.0"
}, },
@@ -1805,14 +1821,14 @@
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.0.0" "typescript": ">=4.8.4 <6.0.0"
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "8.55.0", "version": "8.56.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.55.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz",
"integrity": "sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w==", "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -1824,18 +1840,18 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "8.55.0", "version": "8.56.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.55.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz",
"integrity": "sha512-EwrH67bSWdx/3aRQhCoxDaHM+CrZjotc2UCCpEDVqfCE+7OjKAGWNY2HsCSTEVvWH2clYQK8pdeLp42EVs+xQw==", "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/project-service": "8.55.0", "@typescript-eslint/project-service": "8.56.1",
"@typescript-eslint/tsconfig-utils": "8.55.0", "@typescript-eslint/tsconfig-utils": "8.56.1",
"@typescript-eslint/types": "8.55.0", "@typescript-eslint/types": "8.56.1",
"@typescript-eslint/visitor-keys": "8.55.0", "@typescript-eslint/visitor-keys": "8.56.1",
"debug": "^4.4.3", "debug": "^4.4.3",
"minimatch": "^9.0.5", "minimatch": "^10.2.2",
"semver": "^7.7.3", "semver": "^7.7.3",
"tinyglobby": "^0.2.15", "tinyglobby": "^0.2.15",
"ts-api-utils": "^2.4.0" "ts-api-utils": "^2.4.0"
@@ -1851,27 +1867,40 @@
"typescript": ">=4.8.4 <6.0.0" "typescript": ">=4.8.4 <6.0.0"
} }
}, },
"node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "18 || 20 || >=22"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
"version": "2.0.2", "version": "5.0.4",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"balanced-match": "^1.0.0" "balanced-match": "^4.0.2"
},
"engines": {
"node": "18 || 20 || >=22"
} }
}, },
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
"version": "9.0.5", "version": "10.2.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==",
"dev": true, "dev": true,
"license": "ISC", "license": "BlueOak-1.0.0",
"dependencies": { "dependencies": {
"brace-expansion": "^2.0.1" "brace-expansion": "^5.0.2"
}, },
"engines": { "engines": {
"node": ">=16 || 14 >=14.17" "node": "18 || 20 || >=22"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
@@ -1891,16 +1920,16 @@
} }
}, },
"node_modules/@typescript-eslint/utils": { "node_modules/@typescript-eslint/utils": {
"version": "8.55.0", "version": "8.56.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.55.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz",
"integrity": "sha512-BqZEsnPGdYpgyEIkDC1BadNY8oMwckftxBT+C8W0g1iKPdeqKZBtTfnvcq0nf60u7MkjFO8RBvpRGZBPw4L2ow==", "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.9.1", "@eslint-community/eslint-utils": "^4.9.1",
"@typescript-eslint/scope-manager": "8.55.0", "@typescript-eslint/scope-manager": "8.56.1",
"@typescript-eslint/types": "8.55.0", "@typescript-eslint/types": "8.56.1",
"@typescript-eslint/typescript-estree": "8.55.0" "@typescript-eslint/typescript-estree": "8.56.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1910,19 +1939,19 @@
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.0.0" "typescript": ">=4.8.4 <6.0.0"
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "8.55.0", "version": "8.56.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.55.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz",
"integrity": "sha512-AxNRwEie8Nn4eFS1FzDMJWIISMGoXMb037sgCBJ3UR6o0fQTzr2tqN9WT+DkWJPhIdQCfV7T6D387566VtnCJA==", "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.55.0", "@typescript-eslint/types": "8.56.1",
"eslint-visitor-keys": "^4.2.1" "eslint-visitor-keys": "^5.0.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1932,6 +1961,19 @@
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
} }
}, },
"node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
"integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@vitejs/plugin-react": { "node_modules/@vitejs/plugin-react": {
"version": "5.1.4", "version": "5.1.4",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz",
@@ -1959,10 +2001,19 @@
"integrity": "sha512-L1ddibQ7F3vyXR2k2fg+I8TQTPWVA6CKeDQr/h2+8CeyTp3W6EQL8xNFZRTztuP8xNOAqL3IYPqdzs31GCjDvg==", "integrity": "sha512-L1ddibQ7F3vyXR2k2fg+I8TQTPWVA6CKeDQr/h2+8CeyTp3W6EQL8xNFZRTztuP8xNOAqL3IYPqdzs31GCjDvg==",
"license": "BSD-3-Clause" "license": "BSD-3-Clause"
}, },
"node_modules/ace-code": {
"version": "1.43.6",
"resolved": "https://registry.npmjs.org/ace-code/-/ace-code-1.43.6.tgz",
"integrity": "sha512-yFkGfSm4h+hxUeUn/6aGbl8QFfwRjcA/iCg6qqmgJpb2ry6ZHWjXvm/MKhI/zRXQAFmeFxPZ8UbT/Ux56Vjlzw==",
"license": "BSD-3-Clause",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.15.0", "version": "8.16.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"bin": { "bin": {
@@ -1983,9 +2034,9 @@
} }
}, },
"node_modules/ajv": { "node_modules/ajv": {
"version": "6.12.6", "version": "6.14.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -2030,13 +2081,16 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/baseline-browser-mapping": { "node_modules/baseline-browser-mapping": {
"version": "2.9.19", "version": "2.10.0",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz",
"integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
"baseline-browser-mapping": "dist/cli.js" "baseline-browser-mapping": "dist/cli.cjs"
},
"engines": {
"node": ">=6.0.0"
} }
}, },
"node_modules/brace-expansion": { "node_modules/brace-expansion": {
@@ -2095,9 +2149,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001769", "version": "1.0.30001774",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001774.tgz",
"integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==", "integrity": "sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@@ -2310,9 +2364,9 @@
} }
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.5.286", "version": "1.5.302",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz",
"integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@@ -2382,9 +2436,9 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "9.39.2", "version": "9.39.3",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.3.tgz",
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -2394,7 +2448,7 @@
"@eslint/config-helpers": "^0.4.2", "@eslint/config-helpers": "^0.4.2",
"@eslint/core": "^0.17.0", "@eslint/core": "^0.17.0",
"@eslint/eslintrc": "^3.3.1", "@eslint/eslintrc": "^3.3.1",
"@eslint/js": "9.39.2", "@eslint/js": "9.39.3",
"@eslint/plugin-kit": "^0.4.1", "@eslint/plugin-kit": "^0.4.1",
"@humanfs/node": "^0.16.6", "@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",
@@ -2954,9 +3008,9 @@
} }
}, },
"node_modules/minimatch": { "node_modules/minimatch": {
"version": "3.1.2", "version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
@@ -3239,18 +3293,6 @@
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/react-keyed-flatten-children": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/react-keyed-flatten-children/-/react-keyed-flatten-children-2.2.1.tgz",
"integrity": "sha512-6yBLVO6suN8c/OcJk1mzIrUHdeEzf5rtRVBhxEXAHO49D7SlJ70cG4xrSJrBIAG7MMeQ+H/T151mM2dRDNnFaA==",
"license": "MIT",
"dependencies": {
"react-is": "^18.2.0"
},
"peerDependencies": {
"react": ">=15.0.0"
}
},
"node_modules/react-refresh": { "node_modules/react-refresh": {
"version": "0.18.0", "version": "0.18.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
@@ -3262,9 +3304,9 @@
} }
}, },
"node_modules/react-router": { "node_modules/react-router": {
"version": "7.13.0", "version": "7.13.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.0.tgz", "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.1.tgz",
"integrity": "sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==", "integrity": "sha512-td+xP4X2/6BJvZoX6xw++A2DdEi++YypA69bJUV5oVvqf6/9/9nNlD70YO1e9d3MyamJEBQFEzk6mbfDYbqrSA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"cookie": "^1.0.1", "cookie": "^1.0.1",
@@ -3284,12 +3326,12 @@
} }
}, },
"node_modules/react-router-dom": { "node_modules/react-router-dom": {
"version": "7.13.0", "version": "7.13.1",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.0.tgz", "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.1.tgz",
"integrity": "sha512-5CO/l5Yahi2SKC6rGZ+HDEjpjkGaG/ncEP7eWFTvFxbHP8yeeI0PxTDjimtpXYlR3b3i9/WIL4VJttPrESIf2g==", "integrity": "sha512-UJnV3Rxc5TgUPJt2KJpo1Jpy0OKQr0AjgbZzBFjaPJcFOb2Y8jA5H3LT8HUJAiRLlWrEXWHbF1Z4SCZaQjWDHw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"react-router": "7.13.0" "react-router": "7.13.1"
}, },
"engines": { "engines": {
"node": ">=20.0.0" "node": ">=20.0.0"
@@ -3326,9 +3368,9 @@
} }
}, },
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.57.1", "version": "4.59.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz",
"integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -3342,31 +3384,31 @@
"npm": ">=8.0.0" "npm": ">=8.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.57.1", "@rollup/rollup-android-arm-eabi": "4.59.0",
"@rollup/rollup-android-arm64": "4.57.1", "@rollup/rollup-android-arm64": "4.59.0",
"@rollup/rollup-darwin-arm64": "4.57.1", "@rollup/rollup-darwin-arm64": "4.59.0",
"@rollup/rollup-darwin-x64": "4.57.1", "@rollup/rollup-darwin-x64": "4.59.0",
"@rollup/rollup-freebsd-arm64": "4.57.1", "@rollup/rollup-freebsd-arm64": "4.59.0",
"@rollup/rollup-freebsd-x64": "4.57.1", "@rollup/rollup-freebsd-x64": "4.59.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.57.1", "@rollup/rollup-linux-arm-gnueabihf": "4.59.0",
"@rollup/rollup-linux-arm-musleabihf": "4.57.1", "@rollup/rollup-linux-arm-musleabihf": "4.59.0",
"@rollup/rollup-linux-arm64-gnu": "4.57.1", "@rollup/rollup-linux-arm64-gnu": "4.59.0",
"@rollup/rollup-linux-arm64-musl": "4.57.1", "@rollup/rollup-linux-arm64-musl": "4.59.0",
"@rollup/rollup-linux-loong64-gnu": "4.57.1", "@rollup/rollup-linux-loong64-gnu": "4.59.0",
"@rollup/rollup-linux-loong64-musl": "4.57.1", "@rollup/rollup-linux-loong64-musl": "4.59.0",
"@rollup/rollup-linux-ppc64-gnu": "4.57.1", "@rollup/rollup-linux-ppc64-gnu": "4.59.0",
"@rollup/rollup-linux-ppc64-musl": "4.57.1", "@rollup/rollup-linux-ppc64-musl": "4.59.0",
"@rollup/rollup-linux-riscv64-gnu": "4.57.1", "@rollup/rollup-linux-riscv64-gnu": "4.59.0",
"@rollup/rollup-linux-riscv64-musl": "4.57.1", "@rollup/rollup-linux-riscv64-musl": "4.59.0",
"@rollup/rollup-linux-s390x-gnu": "4.57.1", "@rollup/rollup-linux-s390x-gnu": "4.59.0",
"@rollup/rollup-linux-x64-gnu": "4.57.1", "@rollup/rollup-linux-x64-gnu": "4.59.0",
"@rollup/rollup-linux-x64-musl": "4.57.1", "@rollup/rollup-linux-x64-musl": "4.59.0",
"@rollup/rollup-openbsd-x64": "4.57.1", "@rollup/rollup-openbsd-x64": "4.59.0",
"@rollup/rollup-openharmony-arm64": "4.57.1", "@rollup/rollup-openharmony-arm64": "4.59.0",
"@rollup/rollup-win32-arm64-msvc": "4.57.1", "@rollup/rollup-win32-arm64-msvc": "4.59.0",
"@rollup/rollup-win32-ia32-msvc": "4.57.1", "@rollup/rollup-win32-ia32-msvc": "4.59.0",
"@rollup/rollup-win32-x64-gnu": "4.57.1", "@rollup/rollup-win32-x64-gnu": "4.59.0",
"@rollup/rollup-win32-x64-msvc": "4.57.1", "@rollup/rollup-win32-x64-msvc": "4.59.0",
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
@@ -3515,16 +3557,16 @@
} }
}, },
"node_modules/typescript-eslint": { "node_modules/typescript-eslint": {
"version": "8.55.0", "version": "8.56.1",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.55.0.tgz", "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.56.1.tgz",
"integrity": "sha512-HE4wj+r5lmDVS9gdaN0/+iqNvPZwGfnJ5lZuz7s5vLlg9ODw0bIiiETaios9LvFI1U94/VBXGm3CB2Y5cNFMpw==", "integrity": "sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/eslint-plugin": "8.55.0", "@typescript-eslint/eslint-plugin": "8.56.1",
"@typescript-eslint/parser": "8.55.0", "@typescript-eslint/parser": "8.56.1",
"@typescript-eslint/typescript-estree": "8.55.0", "@typescript-eslint/typescript-estree": "8.56.1",
"@typescript-eslint/utils": "8.55.0" "@typescript-eslint/utils": "8.56.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3534,7 +3576,7 @@
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.0.0" "typescript": ">=4.8.4 <6.0.0"
} }
}, },
@@ -3662,9 +3704,9 @@
} }
}, },
"node_modules/weekstart": { "node_modules/weekstart": {
"version": "1.1.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/weekstart/-/weekstart-1.1.0.tgz", "resolved": "https://registry.npmjs.org/weekstart/-/weekstart-2.0.0.tgz",
"integrity": "sha512-ZO3I7c7J9nwGN1PZKZeBYAsuwWEsCOZi5T68cQoVNYrzrpp5Br0Bgi0OF4l8kH/Ez7nKfxa5mSsXjsgris3+qg==", "integrity": "sha512-HjYc14IQUwDcnGICuc8tVtqAd6EFpoAQMqgrqcNtWWZB+F1b7iTq44GzwM1qvnH4upFgbhJsaNHuK93NOFheSg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/which": { "node_modules/which": {

View File

@@ -12,6 +12,7 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@cloudscape-design/code-view": "^3.0.102",
"@cloudscape-design/components": "^3.0.1200", "@cloudscape-design/components": "^3.0.1200",
"@cloudscape-design/global-styles": "^1.0.50", "@cloudscape-design/global-styles": "^1.0.50",
"react": "^19.2.0", "react": "^19.2.0",

View File

@@ -5,6 +5,8 @@ import "@cloudscape-design/global-styles/index.css";
import "./App.css"; import "./App.css";
import Home from "./pages/Home"; import Home from "./pages/Home";
import Resume from "./pages/Resume"; import Resume from "./pages/Resume";
import Paste from "./pages/Paste";
import PasteView from "./pages/PasteView";
import NotFound from "./pages/NotFound"; import NotFound from "./pages/NotFound";
function AppContent() { function AppContent() {
@@ -32,6 +34,8 @@ function AppContent() {
<Routes> <Routes>
<Route path="/" element={<Home />} /> <Route path="/" element={<Home />} />
<Route path="/resume" element={<Resume />} /> <Route path="/resume" element={<Resume />} />
<Route path="/paste" element={<Paste />} />
<Route path="/paste/:id" element={<PasteView />} />
<Route path="*" element={<NotFound />} /> <Route path="*" element={<NotFound />} />
</Routes> </Routes>
} }

View File

@@ -0,0 +1,129 @@
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import ContentLayout from "@cloudscape-design/components/content-layout";
import Header from "@cloudscape-design/components/header";
import Container from "@cloudscape-design/components/container";
import FormField from "@cloudscape-design/components/form-field";
import Input from "@cloudscape-design/components/input";
import Textarea from "@cloudscape-design/components/textarea";
import Select from "@cloudscape-design/components/select";
import Slider from "@cloudscape-design/components/slider";
import Button from "@cloudscape-design/components/button";
import Alert from "@cloudscape-design/components/alert";
import SpaceBetween from "@cloudscape-design/components/space-between";
const LANGUAGE_OPTIONS = [
{ label: "Plain Text", value: "plaintext" },
{ label: "Bash", value: "bash" },
{ label: "C", value: "c" },
{ label: "C++", value: "cpp" },
{ label: "CSS", value: "css" },
{ label: "Dockerfile", value: "dockerfile" },
{ label: "Go", value: "go" },
{ label: "HTML", value: "html" },
{ label: "Java", value: "java" },
{ label: "JavaScript", value: "javascript" },
{ label: "JSON", value: "json" },
{ label: "Kotlin", value: "kotlin" },
{ label: "Markdown", value: "markdown" },
{ label: "Python", value: "python" },
{ label: "Ruby", value: "ruby" },
{ label: "Rust", value: "rust" },
{ label: "SQL", value: "sql" },
{ label: "Swift", value: "swift" },
{ label: "TypeScript", value: "typescript" },
{ label: "YAML", value: "yaml" },
];
export default function Paste() {
const navigate = useNavigate();
const [title, setTitle] = useState("");
const [content, setContent] = useState("");
const [language, setLanguage] = useState(LANGUAGE_OPTIONS[0]);
const [expiry, setExpiry] = useState(5);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
async function handleSubmit() {
if (!content.trim()) {
setError("Content is required.");
return;
}
setLoading(true);
setError(null);
try {
const res = await fetch("/api/paste", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
title: title.trim(),
content,
language: language.value,
expiry,
}),
});
const data = await res.json();
if (!res.ok) {
setError(data.error ?? "Failed to create paste.");
return;
}
navigate(`/paste/${data.id}`);
} catch {
setError("Network error. Please try again.");
} finally {
setLoading(false);
}
}
return (
<ContentLayout header={<Header variant="h1">New Paste</Header>}>
<Container>
<SpaceBetween size="m">
{error && (
<Alert type="error" onDismiss={() => setError(null)} dismissible>
{error}
</Alert>
)}
<FormField label="Title" description="Optional title for your paste.">
<Input
value={title}
onChange={(e) => setTitle(e.detail.value)}
placeholder="Untitled"
/>
</FormField>
<FormField label="Content" constraintText="Required. Maximum 1 MB.">
<Textarea
value={content}
onChange={(e) => setContent(e.detail.value)}
placeholder="Paste your content here..."
rows={20}
spellcheck={false}
/>
</FormField>
<FormField label="Language">
<Select
selectedOption={language}
onChange={(e) =>
setLanguage(e.detail.selectedOption as { label: string; value: string })
}
options={LANGUAGE_OPTIONS}
/>
</FormField>
<FormField label="Expires" description={`${expiry} minute${expiry === 1 ? "" : "s"}`}>
<Slider
value={expiry}
onChange={(e) => setExpiry(e.detail.value)}
min={1}
max={10}
tickMarks
valueFormatter={(v) => `${v}m`}
/>
</FormField>
<Button variant="primary" onClick={handleSubmit} loading={loading}>
Create Paste
</Button>
</SpaceBetween>
</Container>
</ContentLayout>
);
}

View File

@@ -0,0 +1,159 @@
import { useEffect, useState } from "react";
import { useParams, Link } from "react-router-dom";
import ContentLayout from "@cloudscape-design/components/content-layout";
import Header from "@cloudscape-design/components/header";
import Container from "@cloudscape-design/components/container";
import Box from "@cloudscape-design/components/box";
import Button from "@cloudscape-design/components/button";
import SpaceBetween from "@cloudscape-design/components/space-between";
import Spinner from "@cloudscape-design/components/spinner";
import Alert from "@cloudscape-design/components/alert";
import ColumnLayout from "@cloudscape-design/components/column-layout";
import { CodeView } from "@cloudscape-design/code-view";
interface Paste {
id: string;
title: string;
content: string;
language: string;
created_at: string;
expires_at: string | null;
}
function formatDate(iso: string) {
return new Date(iso).toLocaleString();
}
export default function PasteView() {
const { id } = useParams<{ id: string }>();
const [paste, setPaste] = useState<Paste | null>(null);
const [status, setStatus] = useState<"loading" | "ok" | "notfound" | "expired" | "error">(
"loading",
);
const [copied, setCopied] = useState(false);
useEffect(() => {
if (!id) return;
fetch(`/api/paste/${id}`)
.then((res) => {
if (res.status === 404) {
setStatus("notfound");
return null;
}
if (res.status === 410) {
setStatus("expired");
return null;
}
if (!res.ok) {
setStatus("error");
return null;
}
return res.json();
})
.then((data) => {
if (data) {
setPaste(data);
setStatus("ok");
}
})
.catch(() => setStatus("error"));
}, [id]);
function handleCopy() {
if (!paste) return;
navigator.clipboard.writeText(paste.content).then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 2000);
});
}
if (status === "loading") {
return (
<ContentLayout header={<Header variant="h1">Loading</Header>}>
<Container>
<Spinner size="large" />
</Container>
</ContentLayout>
);
}
if (status === "notfound") {
return (
<ContentLayout header={<Header variant="h1">Not Found</Header>}>
<Container>
<SpaceBetween size="m">
<Alert type="error">This paste does not exist.</Alert>
<Link to="/paste">Create a new paste</Link>
</SpaceBetween>
</Container>
</ContentLayout>
);
}
if (status === "expired") {
return (
<ContentLayout header={<Header variant="h1">Expired</Header>}>
<Container>
<SpaceBetween size="m">
<Alert type="warning">This paste has expired and is no longer available.</Alert>
<Link to="/paste">Create a new paste</Link>
</SpaceBetween>
</Container>
</ContentLayout>
);
}
if (status === "error" || !paste) {
return (
<ContentLayout header={<Header variant="h1">Error</Header>}>
<Container>
<Alert type="error">Failed to load paste. Please try again.</Alert>
</Container>
</ContentLayout>
);
}
return (
<ContentLayout
header={
<Header
variant="h1"
actions={
<SpaceBetween direction="horizontal" size="xs">
<Button onClick={handleCopy} iconName={copied ? "status-positive" : "copy"}>
{copied ? "Copied!" : "Copy"}
</Button>
<Button href={`/api/paste/${id}/raw`} target="_blank" iconName="external">
Raw
</Button>
</SpaceBetween>
}
>
{paste.title || "Untitled"}
</Header>
}
>
<SpaceBetween size="m">
<Container>
<ColumnLayout columns={3} variant="text-grid">
<div>
<Box variant="awsui-key-label">Language</Box>
<Box>{paste.language || "Plain Text"}</Box>
</div>
<div>
<Box variant="awsui-key-label">Created</Box>
<Box>{formatDate(paste.created_at)}</Box>
</div>
<div>
<Box variant="awsui-key-label">Expires</Box>
<Box>{paste.expires_at ? formatDate(paste.expires_at) : "Never"}</Box>
</div>
</ColumnLayout>
</Container>
<Container>
<CodeView content={paste.content} lineNumbers wrapLines />
</Container>
</SpaceBetween>
</ContentLayout>
);
}

View File

@@ -5,6 +5,11 @@ import react from '@vitejs/plugin-react'
export default defineConfig({ export default defineConfig({
plugins: [react()], plugins: [react()],
base: '/app/', base: '/app/',
server: {
proxy: {
'/api': 'http://localhost:8080',
},
},
build: { build: {
outDir: '../Backend/public/app', outDir: '../Backend/public/app',
emptyOutDir: true, emptyOutDir: true,

View File

@@ -1,4 +1,4 @@
.PHONY: all frontend backend run dev clean .PHONY: all frontend backend run dev clean upgrade
all: frontend backend all: frontend backend
@@ -16,3 +16,7 @@ dev:
clean: clean:
rm -rf Backend/server Backend/public/app rm -rf Backend/server Backend/public/app
upgrade:
cd Frontend && npm upgrade
cd Backend && go get -u ./... && go mod tidy