diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 0000000..e9e0e75 --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,25 @@ +name: Go + +on: + push: + branches: [main] + paths-ignore: + - "web/**" + pull_request: + paths-ignore: + - "web/**" + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - name: Vet + run: go vet ./... + - name: Test + run: go test ./... + - name: Build + run: go build -o wallbit ./cmd/wallbit diff --git a/.github/workflows/web.yml b/.github/workflows/web.yml new file mode 100644 index 0000000..aff0e01 --- /dev/null +++ b/.github/workflows/web.yml @@ -0,0 +1,26 @@ +name: Web + +on: + push: + branches: [main] + paths: + - "web/**" + pull_request: + paths: + - "web/**" + +jobs: + build: + runs-on: ubuntu-latest + defaults: + run: + working-directory: web + steps: + - uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + - name: Install + run: bun install --frozen-lockfile + - name: Build + run: bun run build diff --git a/.gitignore b/.gitignore index ffa6502..750102d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,10 @@ *.dylib # Test binary, built with `go test -c` -*.test \ No newline at end of file +*.test + +# Web (Next.js + Bun) +web/node_modules +web/.next +web/out +web/.turbo \ No newline at end of file diff --git a/internal/cli/accountdetails.go b/internal/cli/accountdetails.go index fd3575a..6ab82f9 100644 --- a/internal/cli/accountdetails.go +++ b/internal/cli/accountdetails.go @@ -2,7 +2,6 @@ package cli import ( "context" - "encoding/json" "fmt" "strings" @@ -47,12 +46,17 @@ func runAccountDetailsGet(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } - out, err := svc.AccountDetails.Get(ctx, req) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + res, err := svc.AccountDetails.Get(ctx, req) + if err != nil { + return err + } + out = res + return nil + }) if err != nil { return fmt.Errorf("%w", err) } - - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(out, cmd) } diff --git a/internal/cli/apikey.go b/internal/cli/apikey.go index 15379dd..08fe29a 100644 --- a/internal/cli/apikey.go +++ b/internal/cli/apikey.go @@ -2,7 +2,6 @@ package cli import ( "context" - "encoding/json" "errors" "fmt" @@ -40,12 +39,17 @@ func runAPIKeyRevoke(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } - out, err := svc.APIKey.Revoke(ctx) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + res, err := svc.APIKey.Revoke(ctx) + if err != nil { + return err + } + out = res + return nil + }) if err != nil { return fmt.Errorf("%w", err) } - - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(out, cmd) } diff --git a/internal/cli/assets.go b/internal/cli/assets.go index cfe85ef..05ca652 100644 --- a/internal/cli/assets.go +++ b/internal/cli/assets.go @@ -2,7 +2,6 @@ package cli import ( "context" - "encoding/json" "errors" "fmt" "strings" @@ -67,14 +66,19 @@ func runAssetsList(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } - out, err := svc.Assets.List(ctx, req) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + res, err := svc.Assets.List(ctx, req) + if err != nil { + return err + } + out = res + return nil + }) if err != nil { return fmt.Errorf("%w", err) } - - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(out, cmd) } func runAssetsGet(cmd *cobra.Command, args []string) error { @@ -90,12 +94,17 @@ func runAssetsGet(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } - out, err := svc.Assets.Get(ctx, symbol) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + res, err := svc.Assets.Get(ctx, symbol) + if err != nil { + return err + } + out = res + return nil + }) if err != nil { return fmt.Errorf("%w", err) } - - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(out, cmd) } diff --git a/internal/cli/auth.go b/internal/cli/auth.go index 0ce12e1..4cf3812 100644 --- a/internal/cli/auth.go +++ b/internal/cli/auth.go @@ -4,10 +4,12 @@ import ( "bufio" "errors" "fmt" + "os" "strings" "github.com/jeremyjsx/wallbit-cli/internal/credentials" "github.com/spf13/cobra" + "golang.org/x/term" ) var authCmd = &cobra.Command{ @@ -40,12 +42,22 @@ func init() { func runAuthLogin(cmd *cobra.Command, args []string) error { key := strings.TrimSpace(app.APIKeyFlag()) if key == "" { - fmt.Fprint(cmd.ErrOrStderr(), "Enter API key: ") - line, err := bufio.NewReader(cmd.InOrStdin()).ReadString('\n') - if err != nil { - return fmt.Errorf("read API key: %w", err) + if term.IsTerminal(int(os.Stdin.Fd())) { + fmt.Fprint(cmd.ErrOrStderr(), "Enter API key (hidden): ") + secret, err := term.ReadPassword(int(os.Stdin.Fd())) + fmt.Fprintln(cmd.ErrOrStderr()) + if err != nil { + return fmt.Errorf("read hidden API key: %w", err) + } + key = strings.TrimSpace(string(secret)) + } else { + fmt.Fprint(cmd.ErrOrStderr(), "Enter API key: ") + line, err := bufio.NewReader(cmd.InOrStdin()).ReadString('\n') + if err != nil { + return fmt.Errorf("read API key: %w", err) + } + key = strings.TrimSpace(line) } - key = strings.TrimSpace(line) } if err := credentials.Save(key); err != nil { return err diff --git a/internal/cli/balance.go b/internal/cli/balance.go index 3949b16..4696795 100644 --- a/internal/cli/balance.go +++ b/internal/cli/balance.go @@ -2,7 +2,6 @@ package cli import ( "context" - "encoding/json" "fmt" "github.com/spf13/cobra" @@ -38,13 +37,19 @@ func runBalanceGetChecking(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } - out, err := svc.Balance.GetChecking(ctx) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + res, err := svc.Balance.GetChecking(ctx) + if err != nil { + return err + } + out = res + return nil + }) if err != nil { return fmt.Errorf("%w", err) } - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(out, cmd) } func runBalanceGetStocks(cmd *cobra.Command, args []string) error { @@ -55,11 +60,17 @@ func runBalanceGetStocks(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } - out, err := svc.Balance.GetStocks(ctx) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + res, err := svc.Balance.GetStocks(ctx) + if err != nil { + return err + } + out = res + return nil + }) if err != nil { return fmt.Errorf("%w", err) } - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(out, cmd) } diff --git a/internal/cli/cards.go b/internal/cli/cards.go index 6318bdf..9fbd8e7 100644 --- a/internal/cli/cards.go +++ b/internal/cli/cards.go @@ -2,7 +2,6 @@ package cli import ( "context" - "encoding/json" "errors" "fmt" "strings" @@ -48,14 +47,19 @@ func runCardsList(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } - out, err := svc.Cards.List(ctx) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + res, err := svc.Cards.List(ctx) + if err != nil { + return err + } + out = res + return nil + }) if err != nil { return fmt.Errorf("%w", err) } - - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(out, cmd) } func runCardsBlock(cmd *cobra.Command, args []string) error { @@ -71,14 +75,19 @@ func runCardsBlock(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } - out, err := svc.Cards.Block(ctx, uuid) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + res, err := svc.Cards.Block(ctx, uuid) + if err != nil { + return err + } + out = res + return nil + }) if err != nil { return fmt.Errorf("%w", err) } - - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(out, cmd) } func runCardsUnblock(cmd *cobra.Command, args []string) error { @@ -94,12 +103,17 @@ func runCardsUnblock(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } - out, err := svc.Cards.Unblock(ctx, uuid) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + res, err := svc.Cards.Unblock(ctx, uuid) + if err != nil { + return err + } + out = res + return nil + }) if err != nil { return fmt.Errorf("%w", err) } - - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(out, cmd) } diff --git a/internal/cli/fees.go b/internal/cli/fees.go index eb142fe..5179970 100644 --- a/internal/cli/fees.go +++ b/internal/cli/fees.go @@ -2,7 +2,6 @@ package cli import ( "context" - "encoding/json" "errors" "fmt" "strings" @@ -45,12 +44,17 @@ func runFeesGet(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } - out, err := svc.Fees.Get(ctx, req) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + res, err := svc.Fees.Get(ctx, req) + if err != nil { + return err + } + out = res + return nil + }) if err != nil { return fmt.Errorf("%w", err) } - - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(out, cmd) } diff --git a/internal/cli/io_helpers.go b/internal/cli/io_helpers.go new file mode 100644 index 0000000..f0cc641 --- /dev/null +++ b/internal/cli/io_helpers.go @@ -0,0 +1,13 @@ +package cli + +import ( + "encoding/json" + + "github.com/spf13/cobra" +) + +func writeJSON(out any, cmd *cobra.Command) error { + enc := json.NewEncoder(cmd.OutOrStdout()) + enc.SetIndent("", " ") + return enc.Encode(out) +} diff --git a/internal/cli/loading.go b/internal/cli/loading.go new file mode 100644 index 0000000..54813b9 --- /dev/null +++ b/internal/cli/loading.go @@ -0,0 +1,115 @@ +package cli + +import ( + "fmt" + "io" + "os" + "strings" + "time" +) + +// ANSI: erase entire line + cursor to column 0 (Windows Terminal / modern conhost). +const ansiClearLine = "\x1b[2K\r" +const ansiReset = "\x1b[0m" + +// wallbitDotRGB — brand blues from web/app/globals.css (wallbit-500 / 400 / 300). +var wallbitDotRGB = [3][3]uint8{ + {13, 153, 255}, // #0d99ff + {71, 176, 255}, // #47b0ff + {127, 200, 255}, // #7fc8ff +} + +// Braille frames — shape changes every tick (visible motion); used for mono and color rows. +var brailleFrames = []rune{ + '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏', +} + +func writerIsCharDevice(w io.Writer) bool { + f, ok := w.(*os.File) + if !ok { + return false + } + fi, err := f.Stat() + if err != nil { + return false + } + return fi.Mode()&os.ModeCharDevice != 0 +} + +func useANSIColor() bool { + if os.Getenv("NO_COLOR") != "" { + return false + } + if strings.EqualFold(os.Getenv("TERM"), "dumb") { + return false + } + return true +} + +func ansiTrueColorFG(r, g, b uint8) string { + return fmt.Sprintf("\x1b[38;2;%d;%d;%dm", r, g, b) +} + +// coloredWallbitBraille: one braille cell; shape and Wallbit hue both advance per frame. +func coloredWallbitBraille(frame int) string { + n := len(brailleFrames) + ch := brailleFrames[frame%n] + rgb := wallbitDotRGB[frame%len(wallbitDotRGB)] + return fmt.Sprintf("%s%s%c%s", ansiClearLine, ansiTrueColorFG(rgb[0], rgb[1], rgb[2]), ch, ansiReset) +} + +func monoBrailleLine(frame int) string { + ch := brailleFrames[frame%len(brailleFrames)] + return fmt.Sprintf("%s%c", ansiClearLine, ch) +} + +func flushWriter(w io.Writer) { + if f, ok := w.(*os.File); ok { + _ = f.Sync() + } +} + +// runWithLoading draws animated dots on stderr while fn runs, then clears the line. +func runWithLoading(w io.Writer, fn func() error) error { + useTTY := writerIsCharDevice(w) + if !useTTY { + return fn() + } + + color := useANSIColor() + stop := make(chan struct{}) + done := make(chan struct{}) + + go func() { + defer close(done) + i := 0 + paint := func() { + if color { + _, _ = fmt.Fprint(w, coloredWallbitBraille(i)) + } else { + _, _ = fmt.Fprint(w, monoBrailleLine(i)) + } + flushWriter(w) + } + paint() + ticker := time.NewTicker(90 * time.Millisecond) + defer ticker.Stop() + + for { + select { + case <-stop: + _, _ = fmt.Fprint(w, ansiClearLine) + flushWriter(w) + return + case <-ticker.C: + i++ + paint() + } + } + }() + + err := fn() + close(stop) + <-done + return err +} diff --git a/internal/cli/rates.go b/internal/cli/rates.go index e274f81..1c110da 100644 --- a/internal/cli/rates.go +++ b/internal/cli/rates.go @@ -2,7 +2,6 @@ package cli import ( "context" - "encoding/json" "errors" "fmt" "strings" @@ -53,12 +52,17 @@ func runRatesGet(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } - out, err := svc.Rates.Get(ctx, req) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + res, err := svc.Rates.Get(ctx, req) + if err != nil { + return err + } + out = res + return nil + }) if err != nil { return fmt.Errorf("%w", err) } - - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(out, cmd) } diff --git a/internal/cli/roboadvisor.go b/internal/cli/roboadvisor.go index 13eead2..3e414c1 100644 --- a/internal/cli/roboadvisor.go +++ b/internal/cli/roboadvisor.go @@ -2,7 +2,6 @@ package cli import ( "context" - "encoding/json" "errors" "fmt" "strings" @@ -80,14 +79,19 @@ func runRoboadvisorBalance(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } - out, err := svc.RoboAdvisor.GetBalance(ctx) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + res, err := svc.RoboAdvisor.GetBalance(ctx) + if err != nil { + return err + } + out = res + return nil + }) if err != nil { return fmt.Errorf("%w", err) } - - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(out, cmd) } func runRoboadvisorDeposit(cmd *cobra.Command, args []string) error { @@ -115,14 +119,19 @@ func runRoboadvisorDeposit(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } - out, err := svc.RoboAdvisor.Deposit(ctx, req) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + res, err := svc.RoboAdvisor.Deposit(ctx, req) + if err != nil { + return err + } + out = res + return nil + }) if err != nil { return fmt.Errorf("%w", err) } - - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(out, cmd) } func runRoboadvisorWithdraw(cmd *cobra.Command, args []string) error { @@ -150,12 +159,17 @@ func runRoboadvisorWithdraw(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } - out, err := svc.RoboAdvisor.Withdraw(ctx, req) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + res, err := svc.RoboAdvisor.Withdraw(ctx, req) + if err != nil { + return err + } + out = res + return nil + }) if err != nil { return fmt.Errorf("%w", err) } - - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(out, cmd) } diff --git a/internal/cli/root.go b/internal/cli/root.go index c72a342..737aabd 100644 --- a/internal/cli/root.go +++ b/internal/cli/root.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/cobra" ) -var app = NewApp("", "https://api.wallbit.io", 30*time.Second) +var app = NewApp("", "https://api.dev.wallbit.io", 30*time.Second) var rootCmd = &cobra.Command{ Use: "wallbit", @@ -23,7 +23,7 @@ func Execute() { func init() { rootCmd.PersistentFlags().StringVar(&app.apiKeyFlag, "api-key", "", "Wallbit API key (optional; overrides env and stored credentials)") - rootCmd.PersistentFlags().StringVar(&app.baseURL, "base-url", "https://api.wallbit.io", "Wallbit API base URL") + rootCmd.PersistentFlags().StringVar(&app.baseURL, "base-url", app.baseURL, "Wallbit API base URL") rootCmd.PersistentFlags().DurationVar(&app.timeout, "timeout", 30*time.Second, "HTTP client timeout") rootCmd.AddCommand(authCmd) diff --git a/internal/cli/trades.go b/internal/cli/trades.go index 38fc30b..b179553 100644 --- a/internal/cli/trades.go +++ b/internal/cli/trades.go @@ -2,7 +2,6 @@ package cli import ( "context" - "encoding/json" "errors" "fmt" "strings" @@ -105,10 +104,10 @@ func runTradesCreate(cmd *cobra.Command, args []string) error { } req := wallbittrades.CreateRequest{ - Symbol: strings.TrimSpace(tradeSymbol), - Direction: direction, - Currency: currency, - OrderType: orderType, + Symbol: strings.TrimSpace(tradeSymbol), + Direction: direction, + Currency: currency, + OrderType: orderType, } if req.Symbol == "" { @@ -140,12 +139,17 @@ func runTradesCreate(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } - out, err := svc.Trades.Create(ctx, req) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + res, err := svc.Trades.Create(ctx, req) + if err != nil { + return err + } + out = res + return nil + }) if err != nil { return fmt.Errorf("%w", err) } - - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(out, cmd) } diff --git a/internal/cli/transactions.go b/internal/cli/transactions.go index 23ce58c..24a25f5 100644 --- a/internal/cli/transactions.go +++ b/internal/cli/transactions.go @@ -2,7 +2,6 @@ package cli import ( "context" - "encoding/json" "fmt" wallbittx "github.com/jeremyjsx/wallbit-go/services/transactions" @@ -61,12 +60,17 @@ func runTransactionsList(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } - out, err := svc.Transactions.List(ctx, req) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + res, err := svc.Transactions.List(ctx, req) + if err != nil { + return err + } + out = res + return nil + }) if err != nil { return fmt.Errorf("%w", err) } - - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(out, cmd) } diff --git a/internal/cli/wallets.go b/internal/cli/wallets.go index 0ba5d9e..3a630b3 100644 --- a/internal/cli/wallets.go +++ b/internal/cli/wallets.go @@ -2,7 +2,6 @@ package cli import ( "context" - "encoding/json" "fmt" "strings" @@ -47,12 +46,17 @@ func runWalletsGet(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } - out, err := svc.Wallets.Get(ctx, req) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + res, err := svc.Wallets.Get(ctx, req) + if err != nil { + return err + } + out = res + return nil + }) if err != nil { return fmt.Errorf("%w", err) } - - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(out, cmd) } diff --git a/internal/cli/workflow.go b/internal/cli/workflow.go index 5ead49f..ebe7764 100644 --- a/internal/cli/workflow.go +++ b/internal/cli/workflow.go @@ -2,7 +2,6 @@ package cli import ( "context" - "encoding/json" "fmt" "os" @@ -22,8 +21,15 @@ var workflowRunCmd = &cobra.Command{ RunE: runWorkflowRun, } +var workflowValidateCmd = &cobra.Command{ + Use: "validate ", + Short: "Validate a workflow YAML file without running it", + Args: cobra.ExactArgs(1), + RunE: runWorkflowValidate, +} + func init() { - workflowCmd.AddCommand(workflowRunCmd) + workflowCmd.AddCommand(workflowRunCmd, workflowValidateCmd) rootCmd.AddCommand(workflowCmd) } @@ -36,6 +42,12 @@ func runWorkflowRun(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("%w", err) } + if err := workflow.ValidateSupportedRuns(spec); err != nil { + return fmt.Errorf("%w", err) + } + if err := workflow.ValidateStepInputs(spec); err != nil { + return fmt.Errorf("%w", err) + } svc, err := app.Services() if err != nil { @@ -45,9 +57,37 @@ func runWorkflowRun(cmd *cobra.Command, args []string) error { ctx, cancel := context.WithTimeout(cmd.Context(), app.Timeout()) defer cancel() - out := workflow.Run(ctx, spec, svc) + var out any + err = runWithLoading(cmd.ErrOrStderr(), func() error { + out = workflow.Run(ctx, spec, svc) + return nil + }) + if err != nil { + return fmt.Errorf("%w", err) + } + return writeJSON(out, cmd) +} + +func runWorkflowValidate(cmd *cobra.Command, args []string) error { + data, err := os.ReadFile(args[0]) + if err != nil { + return fmt.Errorf("%w", err) + } + spec, err := workflow.ParseSpec(data) + if err != nil { + return fmt.Errorf("%w", err) + } + if err := workflow.ValidateSupportedRuns(spec); err != nil { + return fmt.Errorf("%w", err) + } + if err := workflow.ValidateStepInputs(spec); err != nil { + return fmt.Errorf("%w", err) + } - enc := json.NewEncoder(cmd.OutOrStdout()) - enc.SetIndent("", " ") - return enc.Encode(out) + return writeJSON(map[string]any{ + "ok": true, + "name": spec.Name, + "steps": len(spec.Steps), + "version": spec.Version, + }, cmd) } diff --git a/internal/workflow/registry.go b/internal/workflow/registry.go index 87eac4f..19f9afe 100644 --- a/internal/workflow/registry.go +++ b/internal/workflow/registry.go @@ -6,15 +6,44 @@ import ( "strings" "github.com/jeremyjsx/wallbit-cli/internal/services" + wallbitaccountdetails "github.com/jeremyjsx/wallbit-go/services/accountdetails" + wallbitassets "github.com/jeremyjsx/wallbit-go/services/assets" wallbitrates "github.com/jeremyjsx/wallbit-go/services/rates" + wallbitroboadvisor "github.com/jeremyjsx/wallbit-go/services/roboadvisor" + wallbittrades "github.com/jeremyjsx/wallbit-go/services/trades" + wallbittransactions "github.com/jeremyjsx/wallbit-go/services/transactions" + wallbitwallets "github.com/jeremyjsx/wallbit-go/services/wallets" ) type StepHandler func(ctx context.Context, svc *services.Services, with map[string]any) (any, error) +type StepInputValidator func(with map[string]any) error var Registry = map[string]StepHandler{ "rates.get": runRatesGet, "balance.get_checking": runBalanceGetChecking, "balance.get_stocks": runBalanceGetStocks, + "wallets.get": runWalletsGet, + "assets.list": runAssetsList, + "assets.get": runAssetsGet, + "account_details.get": runAccountDetailsGet, + "transactions.list": runTransactionsList, + "cards.list": runCardsList, + "cards.block": runCardsBlock, + "cards.unblock": runCardsUnblock, + "trades.create": runTradesCreate, + "roboadvisor.deposit": runRoboadvisorDeposit, + "roboadvisor.withdraw": runRoboadvisorWithdraw, + "apikey.revoke": runAPIKeyRevoke, +} + +var InputValidators = map[string]StepInputValidator{ + "rates.get": validateRatesGetInput, + "assets.get": validateAssetsGetInput, + "cards.block": validateCardsBlockInput, + "cards.unblock": validateCardsBlockInput, + "trades.create": validateTradesCreateInput, + "roboadvisor.deposit": validateRoboadvisorDepositInput, + "roboadvisor.withdraw": validateRoboadvisorWithdrawInput, } func runRatesGet(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { @@ -40,6 +69,182 @@ func runBalanceGetStocks(ctx context.Context, svc *services.Services, with map[s return svc.Balance.GetStocks(ctx) } +func runWalletsGet(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + return svc.Wallets.Get(ctx, &wallbitwallets.GetRequest{ + Currency: strings.ToUpper(getOptionalString(with, "currency")), + Network: strings.ToLower(getOptionalString(with, "network")), + }) +} + +func runAssetsList(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + req := &wallbitassets.ListRequest{ + Category: strings.ToUpper(getOptionalString(with, "category")), + Search: getOptionalString(with, "search"), + } + if v, ok, err := getOptionalInt(with, "page"); err != nil { + return nil, err + } else if ok { + req.Page = &v + } + if v, ok, err := getOptionalInt(with, "limit"); err != nil { + return nil, err + } else if ok { + req.Limit = &v + } + return svc.Assets.List(ctx, req) +} + +func runAssetsGet(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + symbol, err := getRequiredString(with, "symbol") + if err != nil { + return nil, err + } + return svc.Assets.Get(ctx, strings.ToUpper(strings.TrimSpace(symbol))) +} + +func runAccountDetailsGet(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + return svc.AccountDetails.Get(ctx, &wallbitaccountdetails.GetRequest{ + Country: strings.ToUpper(getOptionalString(with, "country")), + Currency: strings.ToUpper(getOptionalString(with, "currency")), + }) +} + +func runTransactionsList(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + req := &wallbittransactions.ListRequest{ + Status: getOptionalString(with, "status"), + Type: getOptionalString(with, "type"), + Currency: getOptionalString(with, "currency"), + } + if v, ok, err := getOptionalInt(with, "page"); err != nil { + return nil, err + } else if ok { + req.Page = &v + } + if v, ok, err := getOptionalInt(with, "limit"); err != nil { + return nil, err + } else if ok { + req.Limit = &v + } + return svc.Transactions.List(ctx, req) +} + +func runCardsList(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + return svc.Cards.List(ctx) +} + +func runCardsBlock(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + cardUUID, err := getRequiredString(with, "card_uuid") + if err != nil { + return nil, err + } + return svc.Cards.Block(ctx, cardUUID) +} + +func runCardsUnblock(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + cardUUID, err := getRequiredString(with, "card_uuid") + if err != nil { + return nil, err + } + return svc.Cards.Unblock(ctx, cardUUID) +} + +func runTradesCreate(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + symbol, err := getRequiredString(with, "symbol") + if err != nil { + return nil, err + } + direction, err := getRequiredString(with, "direction") + if err != nil { + return nil, err + } + currency, err := getRequiredString(with, "currency") + if err != nil { + return nil, err + } + orderType, err := getRequiredString(with, "order_type") + if err != nil { + return nil, err + } + + req := wallbittrades.CreateRequest{ + Symbol: strings.ToUpper(strings.TrimSpace(symbol)), + Direction: strings.ToUpper(strings.TrimSpace(direction)), + Currency: strings.ToUpper(strings.TrimSpace(currency)), + OrderType: strings.ToUpper(strings.TrimSpace(orderType)), + } + if v, ok, err := getOptionalFloat(with, "amount"); err != nil { + return nil, err + } else if ok { + req.Amount = &v + } + if v, ok, err := getOptionalFloat(with, "shares"); err != nil { + return nil, err + } else if ok { + req.Shares = &v + } + if v, ok, err := getOptionalFloat(with, "stop_price"); err != nil { + return nil, err + } else if ok { + req.StopPrice = &v + } + if v, ok, err := getOptionalFloat(with, "limit_price"); err != nil { + return nil, err + } else if ok { + req.LimitPrice = &v + } + if v := getOptionalString(with, "time_in_force"); v != "" { + timeInForce := strings.ToUpper(v) + req.TimeInForce = &timeInForce + } + return svc.Trades.Create(ctx, req) +} + +func runRoboadvisorDeposit(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + roboAdvisorID, err := getRequiredInt(with, "robo_advisor_id") + if err != nil { + return nil, err + } + amount, err := getRequiredFloat(with, "amount") + if err != nil { + return nil, err + } + from, err := getRequiredString(with, "from") + if err != nil { + return nil, err + } + req := wallbitroboadvisor.DepositRequest{ + RoboAdvisorID: roboAdvisorID, + Amount: amount, + From: wallbitroboadvisor.AccountType(strings.ToUpper(strings.TrimSpace(from))), + } + return svc.RoboAdvisor.Deposit(ctx, req) +} + +func runRoboadvisorWithdraw(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + roboAdvisorID, err := getRequiredInt(with, "robo_advisor_id") + if err != nil { + return nil, err + } + amount, err := getRequiredFloat(with, "amount") + if err != nil { + return nil, err + } + to, err := getRequiredString(with, "to") + if err != nil { + return nil, err + } + req := wallbitroboadvisor.WithdrawRequest{ + RoboAdvisorID: roboAdvisorID, + Amount: amount, + To: wallbitroboadvisor.AccountType(strings.ToUpper(strings.TrimSpace(to))), + } + return svc.RoboAdvisor.Withdraw(ctx, req) +} + +func runAPIKeyRevoke(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + return svc.APIKey.Revoke(ctx) +} + func getRequiredString(with map[string]any, key string) (string, error) { if with == nil { return "", fmt.Errorf("with.%s is required", key) @@ -58,3 +263,169 @@ func getRequiredString(with map[string]any, key string) (string, error) { } return s, nil } + +func getOptionalString(with map[string]any, key string) string { + if with == nil { + return "" + } + raw, ok := with[key] + if !ok || raw == nil { + return "" + } + s, ok := raw.(string) + if !ok { + return "" + } + return strings.TrimSpace(s) +} + +func getOptionalInt(with map[string]any, key string) (int, bool, error) { + if with == nil { + return 0, false, nil + } + raw, ok := with[key] + if !ok || raw == nil { + return 0, false, nil + } + switch v := raw.(type) { + case int: + return v, true, nil + case int64: + return int(v), true, nil + case float64: + return int(v), true, nil + default: + return 0, false, fmt.Errorf("with.%s must be a number", key) + } +} + +func getRequiredInt(with map[string]any, key string) (int, error) { + v, ok, err := getOptionalInt(with, key) + if err != nil { + return 0, err + } + if !ok { + return 0, fmt.Errorf("with.%s is required", key) + } + return v, nil +} + +func getOptionalFloat(with map[string]any, key string) (float64, bool, error) { + if with == nil { + return 0, false, nil + } + raw, ok := with[key] + if !ok || raw == nil { + return 0, false, nil + } + switch v := raw.(type) { + case float64: + return v, true, nil + case float32: + return float64(v), true, nil + case int: + return float64(v), true, nil + case int64: + return float64(v), true, nil + default: + return 0, false, fmt.Errorf("with.%s must be a number", key) + } +} + +func getRequiredFloat(with map[string]any, key string) (float64, error) { + v, ok, err := getOptionalFloat(with, key) + if err != nil { + return 0, err + } + if !ok { + return 0, fmt.Errorf("with.%s is required", key) + } + return v, nil +} + +func validateRatesGetInput(with map[string]any) error { + if _, err := getRequiredString(with, "source"); err != nil { + return err + } + if _, err := getRequiredString(with, "dest"); err != nil { + return err + } + return nil +} + +func validateAssetsGetInput(with map[string]any) error { + _, err := getRequiredString(with, "symbol") + return err +} + +func validateCardsBlockInput(with map[string]any) error { + _, err := getRequiredString(with, "card_uuid") + return err +} + +func validateTradesCreateInput(with map[string]any) error { + if _, err := getRequiredString(with, "symbol"); err != nil { + return err + } + if _, err := getRequiredString(with, "direction"); err != nil { + return err + } + if _, err := getRequiredString(with, "currency"); err != nil { + return err + } + if _, err := getRequiredString(with, "order_type"); err != nil { + return err + } + _, hasAmount, err := getOptionalFloat(with, "amount") + if err != nil { + return err + } + _, hasShares, err := getOptionalFloat(with, "shares") + if err != nil { + return err + } + if hasAmount == hasShares { + return fmt.Errorf("with.amount or with.shares must be provided (exactly one)") + } + return nil +} + +func validateRoboadvisorDepositInput(with map[string]any) error { + if _, err := getRequiredInt(with, "robo_advisor_id"); err != nil { + return err + } + if amount, err := getRequiredFloat(with, "amount"); err != nil { + return err + } else if amount <= 0 { + return fmt.Errorf("with.amount must be positive") + } + from, err := getRequiredString(with, "from") + if err != nil { + return err + } + v := strings.ToUpper(strings.TrimSpace(from)) + if v != "DEFAULT" && v != "INVESTMENT" { + return fmt.Errorf("with.from must be DEFAULT or INVESTMENT") + } + return nil +} + +func validateRoboadvisorWithdrawInput(with map[string]any) error { + if _, err := getRequiredInt(with, "robo_advisor_id"); err != nil { + return err + } + if amount, err := getRequiredFloat(with, "amount"); err != nil { + return err + } else if amount <= 0 { + return fmt.Errorf("with.amount must be positive") + } + to, err := getRequiredString(with, "to") + if err != nil { + return err + } + v := strings.ToUpper(strings.TrimSpace(to)) + if v != "DEFAULT" && v != "INVESTMENT" { + return fmt.Errorf("with.to must be DEFAULT or INVESTMENT") + } + return nil +} diff --git a/internal/workflow/resolve.go b/internal/workflow/resolve.go new file mode 100644 index 0000000..5b08337 --- /dev/null +++ b/internal/workflow/resolve.go @@ -0,0 +1,152 @@ +package workflow + +import ( + "fmt" + "reflect" + "regexp" + "strings" +) + +// ${steps..} — path is resolved with case-insensitive struct fields +// and case-insensitive map keys; pointers are followed automatically. +var stepRefPattern = regexp.MustCompile(`\$\{steps\.([a-zA-Z0-9_\-]+)\.([^\}]+)\}`) + +func resolveStepWith(with map[string]any, prior []StepResult) (map[string]any, error) { + if with == nil { + return nil, nil + } + resolved := make(map[string]any, len(with)) + for k, v := range with { + out, err := resolveAny(v, prior) + if err != nil { + return nil, err + } + resolved[k] = out + } + return resolved, nil +} + +func resolveAny(v any, prior []StepResult) (any, error) { + switch t := v.(type) { + case string: + return resolveStringRefs(t, prior) + case map[string]any: + out := make(map[string]any, len(t)) + for k, inner := range t { + r, err := resolveAny(inner, prior) + if err != nil { + return nil, err + } + out[k] = r + } + return out, nil + case []any: + out := make([]any, 0, len(t)) + for _, inner := range t { + r, err := resolveAny(inner, prior) + if err != nil { + return nil, err + } + out = append(out, r) + } + return out, nil + default: + return v, nil + } +} + +func resolveStringRefs(s string, prior []StepResult) (any, error) { + matches := stepRefPattern.FindAllStringSubmatchIndex(s, -1) + if len(matches) == 0 { + return s, nil + } + if len(matches) == 1 && matches[0][0] == 0 && matches[0][1] == len(s) { + stepID := s[matches[0][2]:matches[0][3]] + path := s[matches[0][4]:matches[0][5]] + return lookupStepRef(prior, stepID, path) + } + + var b strings.Builder + last := 0 + for _, m := range matches { + b.WriteString(s[last:m[0]]) + stepID := s[m[2]:m[3]] + path := s[m[4]:m[5]] + val, err := lookupStepRef(prior, stepID, path) + if err != nil { + return nil, err + } + b.WriteString(fmt.Sprint(val)) + last = m[1] + } + b.WriteString(s[last:]) + return b.String(), nil +} + +func lookupStepRef(prior []StepResult, stepID string, path string) (any, error) { + var step *StepResult + for i := range prior { + if prior[i].ID == stepID { + step = &prior[i] + break + } + } + if step == nil { + return nil, fmt.Errorf("reference step %q not found", stepID) + } + if !step.OK { + return nil, fmt.Errorf("reference step %q did not succeed", stepID) + } + parts := strings.Split(path, ".") + var cur any = step + for _, p := range parts { + if p == "" { + return nil, fmt.Errorf("reference steps.%s.%s: empty path segment", stepID, path) + } + next, ok := descend(cur, p) + if !ok { + return nil, fmt.Errorf("reference steps.%s.%s not found", stepID, path) + } + cur = next + } + return cur, nil +} + +func descend(v any, key string) (any, bool) { + if v == nil { + return nil, false + } + rv := reflect.ValueOf(v) + for rv.Kind() == reflect.Pointer { + if rv.IsNil() { + return nil, false + } + rv = rv.Elem() + } + switch rv.Kind() { + case reflect.Map: + if rv.Type().Key().Kind() != reflect.String { + return nil, false + } + mv := rv.MapIndex(reflect.ValueOf(key)) + if mv.IsValid() { + return mv.Interface(), true + } + it := rv.MapRange() + for it.Next() { + k := it.Key().String() + if strings.EqualFold(k, key) { + return it.Value().Interface(), true + } + } + return nil, false + case reflect.Struct: + fv := rv.FieldByNameFunc(func(name string) bool { return strings.EqualFold(name, key) }) + if !fv.IsValid() || !fv.CanInterface() { + return nil, false + } + return fv.Interface(), true + default: + return nil, false + } +} diff --git a/internal/workflow/resolve_test.go b/internal/workflow/resolve_test.go new file mode 100644 index 0000000..8ad611d --- /dev/null +++ b/internal/workflow/resolve_test.go @@ -0,0 +1,70 @@ +package workflow + +import ( + "testing" + + wallbitrates "github.com/jeremyjsx/wallbit-go/services/rates" +) + +func TestResolveStepWithRatesDataPath(t *testing.T) { + prior := []StepResult{ + { + ID: "fx_base", + OK: true, + Data: &wallbitrates.GetResponse{ + Data: wallbitrates.ExchangeRate{ + SourceCurrency: "USD", + DestCurrency: "EUR", + }, + }, + }, + } + with := map[string]any{ + "source": "${steps.fx_base.data.Data.DestCurrency}", + "dest": "${steps.fx_base.data.Data.SourceCurrency}", + } + resolved, err := resolveStepWith(with, prior) + if err != nil { + t.Fatalf("resolveStepWith: %v", err) + } + if resolved["source"] != "EUR" { + t.Fatalf("source = %q want EUR", resolved["source"]) + } + if resolved["dest"] != "USD" { + t.Fatalf("dest = %q want USD", resolved["dest"]) + } +} + +func TestResolveStepRefMissingStep(t *testing.T) { + _, err := resolveStepWith(map[string]any{ + "x": "${steps.nope.data.Data.SourceCurrency}", + }, []StepResult{}) + if err == nil { + t.Fatal("expected error for missing step") + } +} + +func TestResolveStepRefFailedStep(t *testing.T) { + prior := []StepResult{ + {ID: "fx_base", OK: false, Error: &StepError{Message: "boom"}}, + } + _, err := resolveStepWith(map[string]any{ + "x": "${steps.fx_base.data.Data.SourceCurrency}", + }, prior) + if err == nil { + t.Fatal("expected error when referenced step failed") + } +} + +func TestResolveStringPartialInterpolation(t *testing.T) { + prior := []StepResult{ + {ID: "s1", OK: true, Data: map[string]any{"value": "X"}}, + } + out, err := resolveAny(`prefix-${steps.s1.data.value}-suffix`, prior) + if err != nil { + t.Fatal(err) + } + if out != "prefix-X-suffix" { + t.Fatalf("got %q", out) + } +} diff --git a/internal/workflow/runner.go b/internal/workflow/runner.go index adb674b..4530561 100644 --- a/internal/workflow/runner.go +++ b/internal/workflow/runner.go @@ -37,7 +37,25 @@ func Run(ctx context.Context, spec *Spec, svc *services.Services) *RunResult { continue } - data, err := handler(ctx, svc, step.With) + withResolved, err := resolveStepWith(step.With, out.Steps) + if err != nil { + r := StepResult{ + ID: step.ID, + Run: step.Run, + OK: false, + Error: &StepError{Message: err.Error()}, + DurationMS: time.Since(stepStart).Milliseconds(), + } + out.Steps = append(out.Steps, r) + out.OK = false + out.FailedStepID = step.ID + if spec.OnError == OnErrorFailFast { + break + } + continue + } + + data, err := handler(ctx, svc, withResolved) if err != nil { r := StepResult{ ID: step.ID, diff --git a/internal/workflow/runner_test.go b/internal/workflow/runner_test.go new file mode 100644 index 0000000..c9da0ad --- /dev/null +++ b/internal/workflow/runner_test.go @@ -0,0 +1,159 @@ +package workflow + +import ( + "context" + "errors" + "testing" + + "github.com/jeremyjsx/wallbit-cli/internal/services" +) + +func TestRunFailFastStopsAfterFirstError(t *testing.T) { + orig := Registry + t.Cleanup(func() { Registry = orig }) + + Registry = map[string]StepHandler{ + "ok.step": func(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + return map[string]any{"ok": true}, nil + }, + "bad.step": func(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + return nil, errors.New("boom") + }, + } + + spec := &Spec{ + Version: 1, + Name: "runner-fail-fast", + OnError: OnErrorFailFast, + Steps: []Step{ + {ID: "s1", Run: "ok.step"}, + {ID: "s2", Run: "bad.step"}, + {ID: "s3", Run: "ok.step"}, + }, + } + + out := Run(context.Background(), spec, nil) + if out.OK { + t.Fatalf("expected overall failure") + } + if out.FailedStepID != "s2" { + t.Fatalf("expected failed step s2, got %q", out.FailedStepID) + } + if len(out.Steps) != 2 { + t.Fatalf("expected 2 executed steps in fail-fast mode, got %d", len(out.Steps)) + } +} + +func TestRunContinueExecutesRemainingSteps(t *testing.T) { + orig := Registry + t.Cleanup(func() { Registry = orig }) + + Registry = map[string]StepHandler{ + "ok.step": func(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + return map[string]any{"ok": true}, nil + }, + "bad.step": func(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + return nil, errors.New("boom") + }, + } + + spec := &Spec{ + Version: 1, + Name: "runner-continue", + OnError: OnErrorContinue, + Steps: []Step{ + {ID: "s1", Run: "bad.step"}, + {ID: "s2", Run: "ok.step"}, + }, + } + + out := Run(context.Background(), spec, nil) + if out.OK { + t.Fatalf("expected overall failure due to one failed step") + } + if len(out.Steps) != 2 { + t.Fatalf("expected 2 executed steps in continue mode, got %d", len(out.Steps)) + } + if !out.Steps[1].OK { + t.Fatalf("expected second step to run and pass") + } +} + +func TestRunResolvesStepReferences(t *testing.T) { + orig := Registry + t.Cleanup(func() { Registry = orig }) + + Registry = map[string]StepHandler{ + "produce.step": func(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + return map[string]any{ + "value": "AAPL", + }, nil + }, + "consume.step": func(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + got, _ := with["symbol"].(string) + return map[string]any{"symbol": got}, nil + }, + } + + spec := &Spec{ + Version: 1, + Name: "runner-refs", + OnError: OnErrorFailFast, + Steps: []Step{ + {ID: "s1", Run: "produce.step"}, + { + ID: "s2", + Run: "consume.step", + With: map[string]any{ + "symbol": "${steps.s1.data.value}", + }, + }, + }, + } + + out := Run(context.Background(), spec, nil) + if !out.OK { + t.Fatalf("expected success, got failure: %+v", out) + } + if len(out.Steps) != 2 { + t.Fatalf("expected 2 steps, got %d", len(out.Steps)) + } + data, _ := out.Steps[1].Data.(map[string]any) + if got := data["symbol"]; got != "AAPL" { + t.Fatalf("expected resolved symbol AAPL, got %#v", got) + } +} + +func TestRunReferenceMissingStepFails(t *testing.T) { + orig := Registry + t.Cleanup(func() { Registry = orig }) + + Registry = map[string]StepHandler{ + "consume.step": func(ctx context.Context, svc *services.Services, with map[string]any) (any, error) { + return map[string]any{"ok": true}, nil + }, + } + + spec := &Spec{ + Version: 1, + Name: "runner-missing-ref", + OnError: OnErrorFailFast, + Steps: []Step{ + { + ID: "s1", + Run: "consume.step", + With: map[string]any{ + "symbol": "${steps.unknown.data.value}", + }, + }, + }, + } + + out := Run(context.Background(), spec, nil) + if out.OK { + t.Fatalf("expected failure for missing reference") + } + if out.FailedStepID != "s1" { + t.Fatalf("expected failed step s1, got %q", out.FailedStepID) + } +} diff --git a/internal/workflow/schema.go b/internal/workflow/schema.go index 672a235..02d3c6e 100644 --- a/internal/workflow/schema.go +++ b/internal/workflow/schema.go @@ -64,3 +64,25 @@ func (s *Spec) Validate() error { } return nil } + +func ValidateSupportedRuns(s *Spec) error { + for i, step := range s.Steps { + if _, ok := Registry[step.Run]; !ok { + return fmt.Errorf("steps[%d].run %q is not supported", i, step.Run) + } + } + return nil +} + +func ValidateStepInputs(s *Spec) error { + for i, step := range s.Steps { + validator, ok := InputValidators[step.Run] + if !ok { + continue + } + if err := validator(step.With); err != nil { + return fmt.Errorf("steps[%d] (%s): %w", i, step.Run, err) + } + } + return nil +} diff --git a/internal/workflow/schema_test.go b/internal/workflow/schema_test.go new file mode 100644 index 0000000..dcfd9ef --- /dev/null +++ b/internal/workflow/schema_test.go @@ -0,0 +1,68 @@ +package workflow + +import "testing" + +func TestParseSpecDefaultsOnError(t *testing.T) { + spec, err := ParseSpec([]byte(` +version: 1 +name: test +steps: + - id: s1 + run: balance.get_checking +`)) + if err != nil { + t.Fatalf("ParseSpec() error = %v", err) + } + if spec.OnError != OnErrorFailFast { + t.Fatalf("expected default on_error %q, got %q", OnErrorFailFast, spec.OnError) + } +} + +func TestValidateSupportedRuns(t *testing.T) { + spec := &Spec{ + Version: 1, + Name: "test", + OnError: OnErrorFailFast, + Steps: []Step{ + {ID: "s1", Run: "balance.get_checking"}, + {ID: "s2", Run: "unknown.run"}, + }, + } + if err := ValidateSupportedRuns(spec); err == nil { + t.Fatalf("expected unsupported run validation error") + } +} + +func TestValidateStepInputsTradesCreateRequiresExactlyOneAmountOrShares(t *testing.T) { + spec := &Spec{ + Version: 1, + Name: "test", + OnError: OnErrorFailFast, + Steps: []Step{ + { + ID: "trade", + Run: "trades.create", + With: map[string]any{ + "symbol": "AAPL", + "direction": "BUY", + "currency": "USD", + "order_type": "MARKET", + }, + }, + }, + } + if err := ValidateStepInputs(spec); err == nil { + t.Fatalf("expected trade input validation error when amount/shares missing") + } + + spec.Steps[0].With["amount"] = 10.0 + spec.Steps[0].With["shares"] = 1.0 + if err := ValidateStepInputs(spec); err == nil { + t.Fatalf("expected trade input validation error when both amount/shares present") + } + + delete(spec.Steps[0].With, "shares") + if err := ValidateStepInputs(spec); err != nil { + t.Fatalf("expected valid input, got error: %v", err) + } +} diff --git a/web/.gitignore b/web/.gitignore new file mode 100644 index 0000000..5ef6a52 --- /dev/null +++ b/web/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/web/AGENTS.md b/web/AGENTS.md new file mode 100644 index 0000000..8bd0e39 --- /dev/null +++ b/web/AGENTS.md @@ -0,0 +1,5 @@ + +# This is NOT the Next.js you know + +This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices. + diff --git a/web/CLAUDE.md b/web/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/web/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/web/README.md b/web/README.md new file mode 100644 index 0000000..e215bc4 --- /dev/null +++ b/web/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/web/app/docs/docs-sidebar.tsx b/web/app/docs/docs-sidebar.tsx new file mode 100644 index 0000000..4490204 --- /dev/null +++ b/web/app/docs/docs-sidebar.tsx @@ -0,0 +1,118 @@ +"use client"; + +import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react"; +import { DOCS_NAV_SECTIONS, docsNavIdsInOrder } from "./nav-config"; + +/** Viewport line (px from top) used by scrollspy. Slightly below sticky header for stable section matching. */ +const ACTIVE_LINE_PX = 120; + +function computeActiveId(): string { + const ids = docsNavIdsInOrder(); + const entries = ids + .map((id) => { + const el = document.getElementById(id); + return el ? { id, top: el.getBoundingClientRect().top } : null; + }) + .filter((e): e is { id: string; top: number } => Boolean(e)); + + if (entries.length === 0) return ids[0] || ""; + + // If the URL hash is already near the active line, prefer it to avoid "previous item still highlighted". + const hashId = window.location.hash.slice(1); + if (hashId) { + const hashEntry = entries.find((e) => e.id === hashId); + if (hashEntry && hashEntry.top <= ACTIVE_LINE_PX + 220 && hashEntry.top >= ACTIVE_LINE_PX - 80) { + return hashEntry.id; + } + } + + // Primary rule: last heading that has crossed the active line. + const passed = entries.filter((e) => e.top <= ACTIVE_LINE_PX + 4); + if (passed.length > 0) { + return passed[passed.length - 1]!.id; + } + + // Fallback near top: first upcoming heading. + return entries[0]!.id; +} + +export function DocsSidebar() { + const [activeId, setActiveId] = useState(""); + const linkRefs = useRef>(new Map()); + + const sync = useCallback(() => { + setActiveId(computeActiveId()); + }, []); + + useLayoutEffect(() => { + if (!activeId) return; + const el = linkRefs.current.get(activeId); + el?.scrollIntoView({ block: "nearest", behavior: "instant" }); + }, [activeId]); + + useEffect(() => { + const t0 = window.setTimeout(() => sync(), 0); + const onScroll = () => sync(); + window.addEventListener("scroll", onScroll, { passive: true }); + window.addEventListener("resize", onScroll); + window.addEventListener("hashchange", sync); + const t = window.setTimeout(sync, 200); + return () => { + window.clearTimeout(t0); + window.removeEventListener("scroll", onScroll); + window.removeEventListener("resize", onScroll); + window.removeEventListener("hashchange", sync); + window.clearTimeout(t); + }; + }, [sync]); + + return ( + + ); +} diff --git a/web/app/docs/layout.tsx b/web/app/docs/layout.tsx new file mode 100644 index 0000000..91d4697 --- /dev/null +++ b/web/app/docs/layout.tsx @@ -0,0 +1,11 @@ +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Documentation | Wallbit CLI", + description: + "Install Wallbit CLI, configure API keys, use every command, and author YAML workflows with validate and run.", +}; + +export default function DocsLayout({ children }: { children: React.ReactNode }) { + return children; +} diff --git a/web/app/docs/nav-config.ts b/web/app/docs/nav-config.ts new file mode 100644 index 0000000..3677cc1 --- /dev/null +++ b/web/app/docs/nav-config.ts @@ -0,0 +1,43 @@ +export type DocsNavItem = { href: string; label: string }; +export type DocsNavSection = { title: string; items: DocsNavItem[] }; + +/** Single source of truth for docs anchors — must match `id` on headings in `page.tsx`. */ +export const DOCS_NAV_SECTIONS: DocsNavSection[] = [ + { + title: "Getting started", + items: [ + { href: "#prerequisites", label: "Prerequisites" }, + { href: "#installation", label: "Installation" }, + { href: "#authentication", label: "Authentication" }, + { href: "#global-flags", label: "Global flags" }, + ], + }, + { + title: "Command reference", + items: [ + { href: "#cmd-auth", label: "auth" }, + { href: "#cmd-overview", label: "Command overview" }, + { href: "#cmd-trades", label: "trades (detailed)" }, + { href: "#environment", label: "Environment" }, + ], + }, + { + title: "Workflows", + items: [ + { href: "#workflow-quickstart", label: "First workflow in 5 min" }, + { href: "#workflow-language", label: "Workflow language" }, + { href: "#workflow-patterns", label: "Patterns cookbook" }, + { href: "#workflow-ai-prompts", label: "AI prompt templates" }, + { href: "#workflow-spec", label: "YAML specification" }, + { href: "#workflow-validate-run", label: "Validate, Run & Output" }, + { href: "#cmd-workflow", label: "workflow" }, + { href: "#output", label: "Output format" }, + { href: "#workflow-step-refs", label: "Step output references" }, + { href: "#workflow-catalog", label: "Run catalog" }, + ], + }, +]; + +export function docsNavIdsInOrder(): string[] { + return DOCS_NAV_SECTIONS.flatMap((s) => s.items.map((i) => i.href.slice(1))); +} diff --git a/web/app/docs/page.tsx b/web/app/docs/page.tsx new file mode 100644 index 0000000..eab50f2 --- /dev/null +++ b/web/app/docs/page.tsx @@ -0,0 +1,563 @@ +import Link from "next/link"; +import { Fragment } from "react"; +import { WallbitMark } from "../../components/site/wallbit-mark"; +import { DocsSidebar } from "./docs-sidebar"; + +const GITHUB = "https://github.com/jeremyjsx/wallbit-cli"; + +function CodeBlock({ children }: { children: string }) { + return ( +
+      {children}
+    
+ ); +} + +function H2({ id, children }: { id: string; children: React.ReactNode }) { + return ( +

+ {children} +

+ ); +} + +function H3({ id, children }: { id?: string; children: React.ReactNode }) { + return ( +

+ {children} +

+ ); +} + +function Table({ + headers, + rows, +}: { + headers: string[]; + rows: React.ReactNode[][]; +}) { + return ( +
+ + + + {headers.map((h) => ( + + ))} + + + + {rows.map((cells, i) => ( + + {cells.map((c, j) => ( + + ))} + + ))} + +
+ {h} +
+ {c} +
+
+ ); +} + +export default function DocsPage() { + return ( +
+
+
+
+ + + wallbit-cli + + / + Documentation +
+
+ + Home + + + Source + +
+
+
+ +
+ + +
+

+ Documentation +

+

+ wallbit-cli is built workflow-first: define flows in YAML, validate before execution, and run repeatable + financial automations from your terminal. +

+ +
+

Prerequisites

+
    +
  • Go toolchain (to install with go install)
  • +
  • A Wallbit API key
  • +
  • Network access to your Wallbit API host (default in this build is the dev API base URL unless you override it)
  • +
+ +

Installation

+

+ Install the wallbit binary from the repository module path: +

+ {`go install github.com/jeremyjsx/wallbit-cli/cmd/wallbit@latest`} +

+ Ensure $(go env GOPATH)/bin (or your chosen install location) is on your{" "} + PATH. +

+ +

Authentication

+

+ The CLI resolves an API key in this order: --api-key flag, then{" "} + WALLBIT_API_KEY, then the local credentials file written by{" "} + wallbit auth login. +

+ wallbit auth login, + "Prompts for an API key (unless --api-key is set) and saves it to the local store.", + ], + [ + wallbit auth status, + "Shows whether env/file/flag is configured. Never prints the key.", + ], + [ + wallbit auth logout, + "Removes the locally stored API key.", + ], + ]} + /> + +

Global flags

+

These flags are available on the root command and inherited by subcommands.

+
--api-key, + "Wallbit API key (overrides env and stored credentials).", + ], + [ + --base-url, + "Wallbit API base URL. Default matches the CLI build (currently the dev API URL unless you change the code).", + ], + [ + --timeout, + "HTTP client timeout (default 30s).", + ], + ]} + /> + +

CLI reference

+

+ All successful commands write JSON to stdout unless noted. Errors are printed to stderr and exit non-zero. +

+ +

auth

+

See Authentication above. Subcommands: login,{" "} + status, logout.

+ +

Command overview

+

+ Most commands are thin wrappers over one API domain. Use this table as a fast map, then jump to workflows + when you need multi-step execution. +

+
wallbit balance checking], + ["rates", "Currency exchange quotes", wallbit rates get --source USD --dest EUR], + ["wallets", "Wallet discovery/filtering", wallbit wallets get --currency USDC], + ["assets", "Asset listing and details", wallbit assets list --limit 5], + ["transactions", "Transaction feeds and filters", wallbit transactions list --limit 10], + ["cards", "List, block, unblock card operations", wallbit cards block <card-uuid>], + ["roboadvisor", "Portfolio balance, deposit, withdraw", wallbit roboadvisor balance], + ["fees / apikey", "Fee lookup and key revocation", wallbit fees get --type TRADE], + ]} + /> + +

trades

+

+ wallbit trades create — Required:{" "} + --symbol, --direction (BUY or SELL),{" "} + --order-type (MARKET, LIMIT, STOP, STOP_LIMIT). Exactly one of{" "} + --amount or --shares. Optional:{" "} + --currency (default USD), --stop-price,{" "} + --limit-price, --time-in-force (DAY or GTC for LIMIT). +

+

+ LIMIT requires --limit-price and --time-in-force. STOP requires{" "} + --stop-price. STOP_LIMIT requires both stop and limit prices. +

+ +

+ For the remaining groups (roboadvisor, fees,{" "} + apikey), prefer workflow handlers when available and use direct + commands for operational one-offs. +

+ +

Environment

+
WALLBIT_API_KEY, + "API key used when no --api-key flag and no saved credentials (or as configured by the credentials package).", + ], + ]} + /> + +

First workflow in 5 minutes

+

+ Your fastest path is: create a YAML file, validate it, then run it. Use this as a copy-paste baseline: +

+ {`version: 1 +name: quickstart-fx +steps: + - id: fx + run: rates.get + with: + source: USD + dest: EUR + - id: wallets + run: wallets.get + with: + currency: USDC + network: polygon`} + {`wallbit workflow validate ./quickstart.yaml +wallbit workflow run ./quickstart.yaml`} + +

Workflow language

+

+ Workflows are plain YAML with ordered steps. Each step has an{" "} + id, a run key, and optional{" "} + with inputs. Use step references to build multi-step logic: + {"${steps..}"} . +

+
version, "yes", "Workflow schema version (currently 1)."], + [name, "optional", "Human-readable run name."], + [on_error, "optional", "fail_fast (default) or continue."], + [steps, "yes", "Non-empty list of executable steps."], + ]} + /> + +

Patterns cookbook

+

Pattern 1 - FX check plus reverse confirmation

+ {`version: 1 +name: fx-roundtrip +steps: + - id: base_fx + run: rates.get + with: + source: USD + dest: EUR + - id: reverse_fx + run: rates.get + with: + source: \${steps.base_fx.data.Data.DestCurrency} + dest: \${steps.base_fx.data.Data.SourceCurrency}`} + +

Pattern 2 - Portfolio context plus transaction scan

+ {`version: 1 +name: portfolio-scan +steps: + - id: wallets + run: wallets.get + with: + currency: USDC + network: polygon + - id: tx + run: transactions.list + with: + page: 1 + limit: 10 + currency: USD`} + +

Pattern 3 - Multi-domain snapshot

+ {`version: 1 +name: morning-snapshot +steps: + - id: assets + run: assets.list + with: + page: 1 + limit: 5 + category: TECHNOLOGY + - id: cards + run: cards.list`} + +

AI prompt templates

+

+ Give your copilot strict prompts so it emits runnable YAML instead of vague prose. +

+ {`Generate a wallbit-cli workflow YAML (version 1) with: +- 3 steps +- one rates.get step (USD -> EUR) +- one wallets.get step (USDC on polygon) +- one transactions.list step (limit 10) +Return only valid YAML, no markdown, no explanations.`} + + {`Refactor this workflow to use step references where possible. +Keep run keys valid for wallbit-cli. +Return only YAML. + +`} + +

YAML workflow specification

+

Top-level fields:

+
version, + "yes", + "Must be 1.", + ], + [ + name, + "optional", + "Workflow display name (included in validate JSON).", + ], + [ + on_error, + "optional", + <> + fail_fast (default) stops after the first failed step;{" "} + continue runs subsequent steps. + , + ], + [ + steps, + "yes", + "Non-empty array of steps.", + ], + ]} + /> +

Each step:

+
id, + "yes", + "Unique identifier within the workflow. Used for output references.", + ], + [ + run, + "yes", + "Handler key (see Step catalog).", + ], + [ + with, + "optional", + "Map of inputs for the handler (snake_case keys as documented per step).", + ], + ]} + /> + {`version: 1 +name: example +on_error: fail_fast +steps: + - id: usd_eur + run: rates.get + with: + source: USD + dest: EUR + - id: list_tx + run: transactions.list + with: + limit: 20`} + +

Validate, Run & Output

+

+ Both commands parse YAML, run structural validation (version, unique{" "} + id, non-empty run, valid{" "} + on_error), then ValidateSupportedRuns and{" "} + ValidateStepInputs. run additionally executes each step in order. +

+ +

workflow

+

YAML workflow runner.

+
    +
  • + wallbit workflow validate <file.yaml> — Parse YAML, ensure{" "} + version and structure, check every run{" "} + is supported, validate with for steps that have validators. Prints a small JSON summary on success. +
  • +
  • + wallbit workflow run <file.yaml> — Same validation as above, then executes steps in order and prints JSON{" "} + RunResult (see{" "} + + Output format + + ). +
  • +
+ +

Output format

+

+ Commands that call the API print indented JSON. workflow run prints a{" "} + RunResult: workflow, ok,{" "} + started_at, finished_at, optional{" "} + failed_step_id, and steps. Each step has{" "} + id, run, ok, optional{" "} + data (API payload), optional error with message, and{" "} + duration_ms. +

+ +

Step output references

+

+ In with values you can interpolate prior step results using{" "} + {"${steps..}"}. The path walks struct fields (case-insensitive) or map keys. If the entire{" "} + with value is a single reference, the resolved type is preserved; otherwise references are stringified into the template. +

+

+ Only steps that completed successfully before the current step are visible; references must match a prior id. +

+ +

Workflow step catalog

+

+ Each row is a run key. Fields listed under with use workflow YAML naming (snake_case). +

+
rates.get, + + source, dest (required) + , + "Both strings (currency codes).", + ], + [ + balance.get_checking, + "—", + "No inputs.", + ], + [ + balance.get_stocks, + "—", + "No inputs.", + ], + [ + wallets.get, + + optional currency, network + , + "Workflow runner lowercases network for the API request.", + ], + [ + assets.list, + + optional category, search, page,{" "} + limit + , + "Use category values accepted by your Wallbit environment.", + ], + [ + assets.get, + symbol, + "Required.", + ], + [ + account_details.get, + + optional country, currency + , + "—", + ], + [ + transactions.list, + + optional status, type, currency,{" "} + page, limit + , + "API may restrict allowed limit values.", + ], + [ + cards.list, + "—", + "No inputs.", + ], + [ + cards.block, + card_uuid, + "Required.", + ], + [ + cards.unblock, + card_uuid, + "Required.", + ], + [ + trades.create, + + symbol, direction, currency,{" "} + order_type; exactly one of amount or shares; optional{" "} + stop_price, limit_price, time_in_force + , + "Same rules as the CLI trade validator.", + ], + [ + roboadvisor.deposit, + + robo_advisor_id, amount, from (DEFAULT or INVESTMENT) + , + "Mutation.", + ], + [ + roboadvisor.withdraw, + + robo_advisor_id, amount, to (DEFAULT or INVESTMENT) + , + "Mutation.", + ], + [ + apikey.revoke, + "—", + "Revokes the current API key. Dangerous in automation.", + ], + ]} + /> + +

+ Want more workflow recipes, integrations, or step patterns? Open an issue and share your use case so we can prioritize it in the docs and examples. You can also explore the{" "} + + repository + {" "} + and create a request directly in{" "} + + issues + + . +

+ + + + + ); +} diff --git a/web/app/favicon.ico b/web/app/favicon.ico new file mode 100644 index 0000000..718d6fe Binary files /dev/null and b/web/app/favicon.ico differ diff --git a/web/app/globals.css b/web/app/globals.css new file mode 100644 index 0000000..fdb3b85 --- /dev/null +++ b/web/app/globals.css @@ -0,0 +1,274 @@ +@import "tailwindcss"; + +/* + * Wallbit brand — primary matches CLI logo (internal/cli/logo.go): rgb(13, 153, 255) + */ +:root { + --background: #070708; + --foreground: #f4f4f5; + --muted: #a1a1aa; + --border: #27272a; + --accent: #0d99ff; + --accent-muted: color-mix(in srgb, var(--accent) 22%, transparent); + --accent-dim: color-mix(in srgb, var(--accent) 12%, transparent); + --panel: #0f0f12; +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + + /* Wallbit scale — 500 = logo blue */ + --color-wallbit-50: #eff8ff; + --color-wallbit-100: #d9efff; + --color-wallbit-200: #b3dfff; + --color-wallbit-300: #7fc8ff; + --color-wallbit-400: #47b0ff; + --color-wallbit-500: #0d99ff; + --color-wallbit-600: #0a7fd4; + --color-wallbit-700: #0866aa; + --color-wallbit-800: #064d80; + --color-wallbit-900: #043353; + --color-wallbit-950: #021a2a; + + /* Semantic aliases */ + --color-brand: var(--color-wallbit-500); + --color-brand-hover: var(--color-wallbit-400); + --color-brand-muted: var(--color-wallbit-300); + --color-brand-foreground: #ffffff; + + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); +} + +html { + scroll-behavior: smooth; + color-scheme: dark; +} + +body { + background: var(--background); + color: var(--foreground); + font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; +} + +/* Block-caret keyframe used by the Quickstart terminal's trailing caret. */ +@keyframes hero-caret-blink { + 0%, 49% { opacity: 1; } + 50%, 100% { opacity: 0; } +} + +/* + * Announcement bar shimmer — a translucent brand-tinted sweep that + * rides across the strip every few seconds. Provides motion without + * forcing users into a scrolling marquee. + */ +.announcement-shimmer { + background: linear-gradient( + 100deg, + transparent 0%, + transparent 35%, + rgba(13, 153, 255, 0.22) 50%, + transparent 65%, + transparent 100% + ); + filter: blur(2px); + transform: translateX(-100%); + animation: announcement-sweep 7s ease-in-out infinite; +} + +@keyframes announcement-sweep { + 0% { transform: translateX(-100%); opacity: 0; } + 8% { opacity: 1; } + 55% { transform: translateX(220%); opacity: 1; } + 56%, 100% { transform: translateX(220%); opacity: 0; } +} + +/* Typewriter sequence used by the Quickstart terminal. Each line uses + * --tw-len (chars, scales duration) + --tw-delay (s, sequence offset). + * steps() requires a literal int, so we approximate per-character feel + * with a fine-grained step count and let duration ride on --tw-len. */ +.tw-line { + display: block; + clip-path: inset(0 100% 0 0); + animation: tw-reveal calc(var(--tw-len, 30) * 32ms) steps(60, end) var(--tw-delay, 0s) forwards; +} + +@keyframes tw-reveal { + to { clip-path: inset(0 0 0 0); } +} + +/* Trailing block-caret that fades in after the last line and blinks forever. */ +.tw-caret { + display: inline-block; + width: 0.55em; + height: 1em; + margin-left: 0.15em; + background: currentColor; + vertical-align: -0.1em; + opacity: 0; + animation: + tw-caret-fade-in 0.2s linear var(--tw-delay, 0s) forwards, + hero-caret-blink 1s steps(2, end) var(--tw-delay, 0s) infinite; +} + +@keyframes tw-caret-fade-in { + to { opacity: 1; } +} + +section[id], +h2[id], +h3[id] { + scroll-margin-top: 96px; +} + +/* Hero grid */ +.hero-grid { + background-image: + linear-gradient(rgba(13, 153, 255, 0.04) 1px, transparent 1px), + linear-gradient(90deg, rgba(13, 153, 255, 0.04) 1px, transparent 1px); + background-size: 64px 64px; + mask-image: radial-gradient(ellipse 80% 70% at 50% 0%, black 20%, transparent 70%); +} + +/* + * Features: two-layer card. + * The outer wrapper paints an animated conic gradient "trace" on hover; + * the inner wrapper is the actual card surface. + */ +.feature-card { + isolation: isolate; +} + +.feature-card-borderbox { + position: absolute; + inset: 0; + border-radius: inherit; + overflow: hidden; + z-index: 0; + pointer-events: none; +} + +.feature-card-ring { + position: absolute; + inset: -45%; + opacity: 0; + background: conic-gradient(from 0turn, + transparent 0turn, + transparent 0.82turn, + rgba(13, 153, 255, 0.95) 0.875turn, + rgba(127, 200, 255, 0.98) 0.92turn, + rgba(13, 153, 255, 0.95) 0.965turn, + transparent 1turn); + transform: rotate(0turn); + will-change: transform; + pointer-events: none; +} + +.feature-card:hover .feature-card-ring, +.feature-card:focus-within .feature-card-ring { + opacity: 1; + animation: arch-border-run 1.9s linear infinite; +} + +.feature-card-inner { + border-radius: calc(1rem - 1px); + background-clip: padding-box; +} + +@keyframes arch-border-run { + from { + transform: rotate(0turn); + } + + to { + transform: rotate(1turn); + } +} + +@keyframes flow-stage-progress { + from { + width: 0%; + } + + to { + width: 100%; + } +} + +.flow-stage-progress { + animation: flow-stage-progress 5.5s linear forwards; +} + +.flow-stage-card { + isolation: isolate; +} + +.flow-stage-borderbox { + position: absolute; + inset: 0; + border-radius: inherit; + overflow: hidden; + z-index: 0; + pointer-events: none; +} + +@property --flow-progress { + syntax: ""; + inherits: false; + initial-value: 0turn; +} + +@keyframes flow-stage-grow { + from { + --flow-progress: 0turn; + } + + to { + --flow-progress: 1turn; + } +} + +.flow-stage-grow { + position: absolute; + inset: 0; + padding: 1px; + border-radius: inherit; + background: conic-gradient(from -90deg, + transparent 0turn, + rgba(71, 176, 255, 0.95) 0turn var(--flow-progress), + transparent var(--flow-progress), + transparent 1turn); + will-change: background; + animation: flow-stage-grow 5.5s linear forwards; +} + +@media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } + + .feature-card:hover .feature-card-ring, + .feature-card:focus-within .feature-card-ring { + animation: none; + } + + .tw-line { + animation: none; + clip-path: none; + } + + .tw-caret { + animation: none; + opacity: 1; + } + + .announcement-shimmer { + animation: none; + opacity: 0; + } +} + +.docs-scrollbar-hidden::-webkit-scrollbar { + display: none; +} \ No newline at end of file diff --git a/web/app/layout.tsx b/web/app/layout.tsx new file mode 100644 index 0000000..f952bd3 --- /dev/null +++ b/web/app/layout.tsx @@ -0,0 +1,48 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import { AnnouncementBar } from "../components/site/announcement-bar"; +import { GlobalFooter } from "../components/site/global-footer"; +import "./globals.css"; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "Wallbit CLI", + description: "YAML-first Wallbit CLI. Plan workflows, validate, and run from the terminal.", + openGraph: { + title: "Wallbit CLI", + description: "Plan in YAML. Run from the terminal.", + }, +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + + Skip to content + + +
+ {children} +
+ + + + ); +} diff --git a/web/app/page.tsx b/web/app/page.tsx new file mode 100644 index 0000000..e4ef848 --- /dev/null +++ b/web/app/page.tsx @@ -0,0 +1,27 @@ +import { ArchitectureHub } from "../components/architecture/architecture-hub"; +import { FeaturesSection } from "../components/home/features-section"; +import { GetStartedSection } from "../components/home/get-started-section"; +import { HeroSection } from "../components/home/hero-section"; +import { HomeCtaSection } from "../components/home/home-cta-section"; +import { HomeHeader } from "../components/home/home-header"; +import { ProductSection } from "../components/home/product-section"; + +const GITHUB = "https://github.com/jeremyjsx/wallbit-cli"; + +export default function Home() { + return ( +
+ + +
+ + + + + + + +
+
+ ); +} diff --git a/web/bun.lock b/web/bun.lock new file mode 100644 index 0000000..ae2c678 --- /dev/null +++ b/web/bun.lock @@ -0,0 +1,897 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "web", + "dependencies": { + "next": "16.2.4", + "react": "19.2.4", + "react-dom": "19.2.4", + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.2.4", + "tailwindcss": "^4", + "typescript": "^5", + }, + }, + }, + "trustedDependencies": [ + "sharp", + "unrs-resolver", + ], + "packages": { + "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], + + "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], + + "@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="], + + "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="], + + "@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="], + + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="], + + "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], + + "@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="], + + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="], + + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], + + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], + + "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], + + "@babel/helpers": ["@babel/helpers@7.29.2", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.29.0" } }, "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw=="], + + "@babel/parser": ["@babel/parser@7.29.2", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA=="], + + "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="], + + "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="], + + "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], + + "@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], + + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], + + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="], + + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], + + "@eslint/config-array": ["@eslint/config-array@0.21.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.5" } }, "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw=="], + + "@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="], + + "@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="], + + "@eslint/eslintrc": ["@eslint/eslintrc@3.3.5", "", { "dependencies": { "ajv": "^6.14.0", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" } }, "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg=="], + + "@eslint/js": ["@eslint/js@9.39.4", "", {}, "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw=="], + + "@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="], + + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="], + + "@humanfs/core": ["@humanfs/core@0.19.2", "", { "dependencies": { "@humanfs/types": "^0.15.0" } }, "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA=="], + + "@humanfs/node": ["@humanfs/node@0.16.8", "", { "dependencies": { "@humanfs/core": "^0.19.2", "@humanfs/types": "^0.15.0", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ=="], + + "@humanfs/types": ["@humanfs/types@0.15.0", "", {}, "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q=="], + + "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], + + "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], + + "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="], + + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="], + + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="], + + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="], + + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="], + + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="], + + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="], + + "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA=="], + + "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.2.4", "", { "os": "linux", "cpu": "none" }, "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA=="], + + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ=="], + + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="], + + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="], + + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="], + + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="], + + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="], + + "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.4" }, "os": "linux", "cpu": "ppc64" }, "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA=="], + + "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.2.4" }, "os": "linux", "cpu": "none" }, "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw=="], + + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.4" }, "os": "linux", "cpu": "s390x" }, "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg=="], + + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="], + + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="], + + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="], + + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "", { "dependencies": { "@emnapi/runtime": "^1.7.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="], + + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="], + + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="], + + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], + + "@next/env": ["@next/env@16.2.4", "", {}, "sha512-dKkkOzOSwFYe5RX6y26fZgkSpVAlIOJKQHIiydQcrWH6y/97+RceSOAdjZ14Qa3zLduVUy0TXcn+EiM6t4rPgw=="], + + "@next/eslint-plugin-next": ["@next/eslint-plugin-next@16.2.4", "", { "dependencies": { "fast-glob": "3.3.1" } }, "sha512-tOX826JJ96gYK/go18sPUgMq9FK1tqxBFfUCEufJb5XIkWFFmpgU7mahJANKGkHs7F41ir3tReJ3Lv5La0RvhA=="], + + "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-OXTFFox5EKN1Ym08vfrz+OXxmCcEjT4SFMbNRsWZE99dMqt2Kcusl5MqPXcW232RYkMLQTy0hqgAMEsfEd/l2A=="], + + "@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-XhpVnUfmYWvD3YrXu55XdcAkQtOnvaI6wtQa8fuF5fGoKoxIUZ0kWPtcOfqJEWngFF/lOS9l3+O9CcownhiQxQ=="], + + "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-Mx/tjlNA3G8kg14QvuGAJ4xBwPk1tUHq56JxZ8CXnZwz1Etz714soCEzGQQzVMz4bEnGPowzkV6Xrp6wAkEWOQ=="], + + "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-iVMMp14514u7Nup2umQS03nT/bN9HurK8ufylC3FZNykrwjtx7V1A7+4kvhbDSCeonTVqV3Txnv0Lu+m2oDXNg=="], + + "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-EZOvm1aQWgnI/N/xcWOlnS3RQBk0VtVav5Zo7n4p0A7UKyTDx047k8opDbXgBpHl4CulRqRfbw3QrX2w5UOXMQ=="], + + "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-h9FxsngCm9cTBf71AR4fGznDEDx1hS7+kSEiIRjq5kO1oXWm07DxVGZjCvk0SGx7TSjlUqhI8oOyz7NfwAdPoA=="], + + "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.2.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-3NdJV5OXMSOeJYijX+bjaLge3mJBlh4ybydbT4GFoB/2hAojWHtMhl3CYlYoMrjPuodp0nzFVi4Tj2+WaMg+Ow=="], + + "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.2.4", "", { "os": "win32", "cpu": "x64" }, "sha512-kMVGgsqhO5YTYODD9IPGGhA6iprWidQckK3LmPeW08PIFENRmgfb4MjXHO+p//d+ts2rpjvK5gXWzXSMrPl9cw=="], + + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + + "@nolyfill/is-core-module": ["@nolyfill/is-core-module@1.0.39", "", {}, "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA=="], + + "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], + + "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], + + "@tailwindcss/node": ["@tailwindcss/node@4.2.4", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.4" } }, "sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA=="], + + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.4", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.4", "@tailwindcss/oxide-darwin-arm64": "4.2.4", "@tailwindcss/oxide-darwin-x64": "4.2.4", "@tailwindcss/oxide-freebsd-x64": "4.2.4", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.4", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.4", "@tailwindcss/oxide-linux-arm64-musl": "4.2.4", "@tailwindcss/oxide-linux-x64-gnu": "4.2.4", "@tailwindcss/oxide-linux-x64-musl": "4.2.4", "@tailwindcss/oxide-wasm32-wasi": "4.2.4", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.4", "@tailwindcss/oxide-win32-x64-msvc": "4.2.4" } }, "sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q=="], + + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.2.4", "", { "os": "android", "cpu": "arm64" }, "sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g=="], + + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg=="], + + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg=="], + + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.2.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw=="], + + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA=="], + + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw=="], + + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-bBADEGAbo4ASnppIziaQJelekCxdMaxisrk+fB7Thit72IBnALp9K6ffA2G4ruj90G9XRS2VQ6q2bCKbfFV82g=="], + + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-7Mx25E4WTfnht0TVRTyC00j3i0M+EeFe7wguMDTlX4mRxafznw0CA8WJkFjWYH5BlgELd1kSjuU2JiPnNZbJDA=="], + + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-2wwJRF7nyhOR0hhHoChc04xngV3iS+akccHTGtz965FwF0up4b2lOdo6kI1EbDaEXKgvcrFBYcYQQ/rrnWFVfA=="], + + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.2.4", "", { "dependencies": { "@emnapi/core": "^1.8.1", "@emnapi/runtime": "^1.8.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.1", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-FQsqApeor8Fo6gUEklzmaa9994orJZZDBAlQpK2Mq+DslRKFJeD6AjHpBQ0kZFQohVr8o85PPh8eOy86VlSCmw=="], + + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.2.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-L9BXqxC4ToVgwMFqj3pmZRqyHEztulpUJzCxUtLjobMCzTPsGt1Fa9enKbOpY2iIyVtaHNeNvAK8ERP/64sqGQ=="], + + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.4", "", { "os": "win32", "cpu": "x64" }, "sha512-ESlKG0EpVJQwRjXDDa9rLvhEAh0mhP1sF7sap9dNZT0yyl9SAG6T7gdP09EH0vIv0UNTlo6jPWyujD6559fZvw=="], + + "@tailwindcss/postcss": ["@tailwindcss/postcss@4.2.4", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.2.4", "@tailwindcss/oxide": "4.2.4", "postcss": "^8.5.6", "tailwindcss": "4.2.4" } }, "sha512-wgAVj6nUWAolAu8YFvzT2cTBIElWHkjZwFYovF+xsqKsW2ADxM/X2opxj5NsF/qVccAOjRNe8X2IdPzMsWyHTg=="], + + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], + + "@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="], + + "@types/node": ["@types/node@20.19.39", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw=="], + + "@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="], + + "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], + + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.59.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.59.0", "@typescript-eslint/type-utils": "8.59.0", "@typescript-eslint/utils": "8.59.0", "@typescript-eslint/visitor-keys": "8.59.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.59.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-HyAZtpdkgZwpq8Sz3FSUvCR4c+ScbuWa9AksK2Jweub7w4M3yTz4O11AqVJzLYjy/B9ZWPyc81I+mOdJU/bDQw=="], + + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.59.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.59.0", "@typescript-eslint/types": "8.59.0", "@typescript-eslint/typescript-estree": "8.59.0", "@typescript-eslint/visitor-keys": "8.59.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-TI1XGwKbDpo9tRW8UDIXCOeLk55qe9ZFGs8MTKU6/M08HWTw52DD/IYhfQtOEhEdPhLMT26Ka/x7p70nd3dzDg=="], + + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.59.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.59.0", "@typescript-eslint/types": "^8.59.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-Lw5ITrR5s5TbC19YSvlr63ZfLaJoU6vtKTHyB0GQOpX0W7d5/Ir6vUahWi/8Sps/nOukZQ0IB3SmlxZnjaKVnw=="], + + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.59.0", "", { "dependencies": { "@typescript-eslint/types": "8.59.0", "@typescript-eslint/visitor-keys": "8.59.0" } }, "sha512-UzR16Ut8IpA3Mc4DbgAShlPPkVm8xXMWafXxB0BocaVRHs8ZGakAxGRskF7FId3sdk9lgGD73GSFaWmWFDE4dg=="], + + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.59.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-91Sbl3s4Kb3SybliIY6muFBmHVv+pYXfybC4Oolp3dvk8BvIE3wOPc+403CWIT7mJNkfQRGtdqghzs2+Z91Tqg=="], + + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.59.0", "", { "dependencies": { "@typescript-eslint/types": "8.59.0", "@typescript-eslint/typescript-estree": "8.59.0", "@typescript-eslint/utils": "8.59.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-3TRiZaQSltGqGeNrJzzr1+8YcEobKH9rHnqIp/1psfKFmhRQDNMGP5hBufanYTGznwShzVLs3Mz+gDN7HkWfXg=="], + + "@typescript-eslint/types": ["@typescript-eslint/types@8.59.0", "", {}, "sha512-nLzdsT1gdOgFxxxwrlNVUBzSNBEEHJ86bblmk4QAS6stfig7rcJzWKqCyxFy3YRRHXDWEkb2NralA1nOYkkm/A=="], + + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.59.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.59.0", "@typescript-eslint/tsconfig-utils": "8.59.0", "@typescript-eslint/types": "8.59.0", "@typescript-eslint/visitor-keys": "8.59.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-O9Re9P1BmBLFJyikRbQpLku/QA3/AueZNO9WePLBwQrvkixTmDe8u76B6CYUAITRl/rHawggEqUGn5QIkVRLMw=="], + + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.59.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.59.0", "@typescript-eslint/types": "8.59.0", "@typescript-eslint/typescript-estree": "8.59.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-I1R/K7V07XsMJ12Oaxg/O9GfrysGTmCRhvZJBv0RE0NcULMzjqVpR5kRRQjHsz3J/bElU7HwCO7zkqL+MSUz+g=="], + + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.59.0", "", { "dependencies": { "@typescript-eslint/types": "8.59.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-/uejZt4dSere1bx12WLlPfv8GktzcaDtuJ7s42/HEZ5zGj9oxRaD4bj7qwSunXkf+pbAhFt2zjpHYUiT5lHf0Q=="], + + "@unrs/resolver-binding-android-arm-eabi": ["@unrs/resolver-binding-android-arm-eabi@1.11.1", "", { "os": "android", "cpu": "arm" }, "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw=="], + + "@unrs/resolver-binding-android-arm64": ["@unrs/resolver-binding-android-arm64@1.11.1", "", { "os": "android", "cpu": "arm64" }, "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g=="], + + "@unrs/resolver-binding-darwin-arm64": ["@unrs/resolver-binding-darwin-arm64@1.11.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g=="], + + "@unrs/resolver-binding-darwin-x64": ["@unrs/resolver-binding-darwin-x64@1.11.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ=="], + + "@unrs/resolver-binding-freebsd-x64": ["@unrs/resolver-binding-freebsd-x64@1.11.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw=="], + + "@unrs/resolver-binding-linux-arm-gnueabihf": ["@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1", "", { "os": "linux", "cpu": "arm" }, "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw=="], + + "@unrs/resolver-binding-linux-arm-musleabihf": ["@unrs/resolver-binding-linux-arm-musleabihf@1.11.1", "", { "os": "linux", "cpu": "arm" }, "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw=="], + + "@unrs/resolver-binding-linux-arm64-gnu": ["@unrs/resolver-binding-linux-arm64-gnu@1.11.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ=="], + + "@unrs/resolver-binding-linux-arm64-musl": ["@unrs/resolver-binding-linux-arm64-musl@1.11.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w=="], + + "@unrs/resolver-binding-linux-ppc64-gnu": ["@unrs/resolver-binding-linux-ppc64-gnu@1.11.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA=="], + + "@unrs/resolver-binding-linux-riscv64-gnu": ["@unrs/resolver-binding-linux-riscv64-gnu@1.11.1", "", { "os": "linux", "cpu": "none" }, "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ=="], + + "@unrs/resolver-binding-linux-riscv64-musl": ["@unrs/resolver-binding-linux-riscv64-musl@1.11.1", "", { "os": "linux", "cpu": "none" }, "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew=="], + + "@unrs/resolver-binding-linux-s390x-gnu": ["@unrs/resolver-binding-linux-s390x-gnu@1.11.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg=="], + + "@unrs/resolver-binding-linux-x64-gnu": ["@unrs/resolver-binding-linux-x64-gnu@1.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w=="], + + "@unrs/resolver-binding-linux-x64-musl": ["@unrs/resolver-binding-linux-x64-musl@1.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA=="], + + "@unrs/resolver-binding-wasm32-wasi": ["@unrs/resolver-binding-wasm32-wasi@1.11.1", "", { "dependencies": { "@napi-rs/wasm-runtime": "^0.2.11" }, "cpu": "none" }, "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ=="], + + "@unrs/resolver-binding-win32-arm64-msvc": ["@unrs/resolver-binding-win32-arm64-msvc@1.11.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw=="], + + "@unrs/resolver-binding-win32-ia32-msvc": ["@unrs/resolver-binding-win32-ia32-msvc@1.11.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ=="], + + "@unrs/resolver-binding-win32-x64-msvc": ["@unrs/resolver-binding-win32-x64-msvc@1.11.1", "", { "os": "win32", "cpu": "x64" }, "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g=="], + + "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], + + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], + + "ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], + + "array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="], + + "array-includes": ["array-includes@3.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.0", "es-object-atoms": "^1.1.1", "get-intrinsic": "^1.3.0", "is-string": "^1.1.1", "math-intrinsics": "^1.1.0" } }, "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ=="], + + "array.prototype.findlast": ["array.prototype.findlast@1.2.5", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ=="], + + "array.prototype.findlastindex": ["array.prototype.findlastindex@1.2.6", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-shim-unscopables": "^1.1.0" } }, "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ=="], + + "array.prototype.flat": ["array.prototype.flat@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg=="], + + "array.prototype.flatmap": ["array.prototype.flatmap@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg=="], + + "array.prototype.tosorted": ["array.prototype.tosorted@1.1.4", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.3", "es-errors": "^1.3.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA=="], + + "arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="], + + "ast-types-flow": ["ast-types-flow@0.0.8", "", {}, "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ=="], + + "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], + + "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], + + "axe-core": ["axe-core@4.11.3", "", {}, "sha512-zBQouZixDTbo3jMGqHKyePxYxr1e5W8UdTmBQ7sNtaA9M2bE32daxxPLS/jojhKOHxQ7LWwPjfiwf/fhaJWzlg=="], + + "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "baseline-browser-mapping": ["baseline-browser-mapping@2.10.20", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-1AaXxEPfXT+GvTBJFuy4yXVHWJBXa4OdbIebGN/wX5DlsIkU0+wzGnd2lOzokSk51d5LUmqjgBLRLlypLUqInQ=="], + + "brace-expansion": ["brace-expansion@1.1.14", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g=="], + + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + + "browserslist": ["browserslist@4.28.2", "", { "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", "electron-to-chromium": "^1.5.328", "node-releases": "^2.0.36", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="], + + "call-bind": ["call-bind@1.0.9", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "get-intrinsic": "^1.3.0", "set-function-length": "^1.2.2" } }, "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001788", "", {}, "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ=="], + + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + + "damerau-levenshtein": ["damerau-levenshtein@1.0.8", "", {}, "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="], + + "data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="], + + "data-view-byte-length": ["data-view-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ=="], + + "data-view-byte-offset": ["data-view-byte-offset@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" } }, "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], + + "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], + + "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], + + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "electron-to-chromium": ["electron-to-chromium@1.5.342", "", {}, "sha512-GTuy59SdGxYgz+HN8KwOjFAVF2gfoKEmv0PFholcvVtbI9GPDND0m6ynGX3gAKOavcHRLrcfNy0QMbHbAemYdw=="], + + "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "enhanced-resolve": ["enhanced-resolve@5.20.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA=="], + + "es-abstract": ["es-abstract@1.24.2", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-iterator-helpers": ["es-iterator-helpers@1.3.2", "", { "dependencies": { "call-bind": "^1.0.9", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.2", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.1.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.3.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.5", "math-intrinsics": "^1.1.0" } }, "sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], + + "es-shim-unscopables": ["es-shim-unscopables@1.1.0", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw=="], + + "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + + "eslint": ["eslint@9.39.4", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.5", "@eslint/js": "9.39.4", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ=="], + + "eslint-config-next": ["eslint-config-next@16.2.4", "", { "dependencies": { "@next/eslint-plugin-next": "16.2.4", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", "eslint-plugin-jsx-a11y": "^6.10.0", "eslint-plugin-react": "^7.37.0", "eslint-plugin-react-hooks": "^7.0.0", "globals": "16.4.0", "typescript-eslint": "^8.46.0" }, "peerDependencies": { "eslint": ">=9.0.0", "typescript": ">=3.3.1" }, "optionalPeers": ["typescript"] }, "sha512-A6ekXYFj/YQxBPMl45g3e+U8zJo+X2+ZQwcz34pPKjpc/3S4roBA2Rd9xWB4FKuSxhofo1/95WjzmUY+wHrOhg=="], + + "eslint-import-resolver-node": ["eslint-import-resolver-node@0.3.10", "", { "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.16.1", "resolve": "^2.0.0-next.6" } }, "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ=="], + + "eslint-import-resolver-typescript": ["eslint-import-resolver-typescript@3.10.1", "", { "dependencies": { "@nolyfill/is-core-module": "1.0.39", "debug": "^4.4.0", "get-tsconfig": "^4.10.0", "is-bun-module": "^2.0.0", "stable-hash": "^0.0.5", "tinyglobby": "^0.2.13", "unrs-resolver": "^1.6.2" }, "peerDependencies": { "eslint": "*", "eslint-plugin-import": "*", "eslint-plugin-import-x": "*" }, "optionalPeers": ["eslint-plugin-import", "eslint-plugin-import-x"] }, "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ=="], + + "eslint-module-utils": ["eslint-module-utils@2.12.1", "", { "dependencies": { "debug": "^3.2.7" } }, "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw=="], + + "eslint-plugin-import": ["eslint-plugin-import@2.32.0", "", { "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", "array.prototype.findlastindex": "^1.2.6", "array.prototype.flat": "^1.3.3", "array.prototype.flatmap": "^1.3.3", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", "eslint-module-utils": "^2.12.1", "hasown": "^2.0.2", "is-core-module": "^2.16.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "object.groupby": "^1.0.3", "object.values": "^1.2.1", "semver": "^6.3.1", "string.prototype.trimend": "^1.0.9", "tsconfig-paths": "^3.15.0" }, "peerDependencies": { "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA=="], + + "eslint-plugin-jsx-a11y": ["eslint-plugin-jsx-a11y@6.10.2", "", { "dependencies": { "aria-query": "^5.3.2", "array-includes": "^3.1.8", "array.prototype.flatmap": "^1.3.2", "ast-types-flow": "^0.0.8", "axe-core": "^4.10.0", "axobject-query": "^4.1.0", "damerau-levenshtein": "^1.0.8", "emoji-regex": "^9.2.2", "hasown": "^2.0.2", "jsx-ast-utils": "^3.3.5", "language-tags": "^1.0.9", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "safe-regex-test": "^1.0.3", "string.prototype.includes": "^2.0.1" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" } }, "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q=="], + + "eslint-plugin-react": ["eslint-plugin-react@7.37.5", "", { "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA=="], + + "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@7.1.1", "", { "dependencies": { "@babel/core": "^7.24.4", "@babel/parser": "^7.24.4", "hermes-parser": "^0.25.1", "zod": "^3.25.0 || ^4.0.0", "zod-validation-error": "^3.5.0 || ^4.0.0" }, "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" } }, "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g=="], + + "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], + + "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], + + "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], + + "esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="], + + "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], + + "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], + + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-glob": ["fast-glob@3.3.1", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg=="], + + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + + "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], + + "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], + + "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], + + "flatted": ["flatted@3.4.2", "", {}, "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA=="], + + "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "function.prototype.name": ["function.prototype.name@1.1.8", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "functions-have-names": "^1.2.3", "hasown": "^2.0.2", "is-callable": "^1.2.7" } }, "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q=="], + + "functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="], + + "generator-function": ["generator-function@2.0.1", "", {}, "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g=="], + + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], + + "get-tsconfig": ["get-tsconfig@4.14.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA=="], + + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + + "globals": ["globals@16.4.0", "", {}, "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw=="], + + "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], + + "has-proto": ["has-proto@1.2.0", "", { "dependencies": { "dunder-proto": "^1.0.0" } }, "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + + "hasown": ["hasown@2.0.3", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg=="], + + "hermes-estree": ["hermes-estree@0.25.1", "", {}, "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw=="], + + "hermes-parser": ["hermes-parser@0.25.1", "", { "dependencies": { "hermes-estree": "0.25.1" } }, "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA=="], + + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + + "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], + + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], + + "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], + + "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="], + + "is-async-function": ["is-async-function@2.1.1", "", { "dependencies": { "async-function": "^1.0.0", "call-bound": "^1.0.3", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ=="], + + "is-bigint": ["is-bigint@1.1.0", "", { "dependencies": { "has-bigints": "^1.0.2" } }, "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ=="], + + "is-boolean-object": ["is-boolean-object@1.2.2", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A=="], + + "is-bun-module": ["is-bun-module@2.0.0", "", { "dependencies": { "semver": "^7.7.1" } }, "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ=="], + + "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="], + + "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], + + "is-data-view": ["is-data-view@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "is-typed-array": "^1.1.13" } }, "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw=="], + + "is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="], + + "is-generator-function": ["is-generator-function@1.1.2", "", { "dependencies": { "call-bound": "^1.0.4", "generator-function": "^2.0.0", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="], + + "is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="], + + "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], + + "is-set": ["is-set@2.0.3", "", {}, "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg=="], + + "is-shared-array-buffer": ["is-shared-array-buffer@1.0.4", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A=="], + + "is-string": ["is-string@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA=="], + + "is-symbol": ["is-symbol@1.1.1", "", { "dependencies": { "call-bound": "^1.0.2", "has-symbols": "^1.1.0", "safe-regex-test": "^1.1.0" } }, "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w=="], + + "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="], + + "is-weakmap": ["is-weakmap@2.0.2", "", {}, "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w=="], + + "is-weakref": ["is-weakref@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew=="], + + "is-weakset": ["is-weakset@2.0.4", "", { "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ=="], + + "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "iterator.prototype": ["iterator.prototype@1.1.5", "", { "dependencies": { "define-data-property": "^1.1.4", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "get-proto": "^1.0.0", "has-symbols": "^1.1.0", "set-function-name": "^2.0.2" } }, "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g=="], + + "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + + "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], + + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + + "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], + + "json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="], + + "jsx-ast-utils": ["jsx-ast-utils@3.3.5", "", { "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", "object.assign": "^4.1.4", "object.values": "^1.1.6" } }, "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ=="], + + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], + + "language-subtag-registry": ["language-subtag-registry@0.3.23", "", {}, "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ=="], + + "language-tags": ["language-tags@1.0.9", "", { "dependencies": { "language-subtag-registry": "^0.3.20" } }, "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA=="], + + "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], + + "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], + + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], + + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="], + + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="], + + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="], + + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="], + + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="], + + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="], + + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="], + + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="], + + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="], + + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], + + "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], + + "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], + + "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], + + "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + + "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=="], + + "napi-postinstall": ["napi-postinstall@0.3.4", "", { "bin": { "napi-postinstall": "lib/cli.js" } }, "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ=="], + + "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], + + "next": ["next@16.2.4", "", { "dependencies": { "@next/env": "16.2.4", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.2.4", "@next/swc-darwin-x64": "16.2.4", "@next/swc-linux-arm64-gnu": "16.2.4", "@next/swc-linux-arm64-musl": "16.2.4", "@next/swc-linux-x64-gnu": "16.2.4", "@next/swc-linux-x64-musl": "16.2.4", "@next/swc-win32-arm64-msvc": "16.2.4", "@next/swc-win32-x64-msvc": "16.2.4", "sharp": "^0.34.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-kPvz56wF5frc+FxlHI5qnklCzbq53HTwORaWBGdT0vNoKh1Aya9XC8aPauH4NJxqtzbWsS5mAbctm4cr+EkQ2Q=="], + + "node-exports-info": ["node-exports-info@1.6.0", "", { "dependencies": { "array.prototype.flatmap": "^1.3.3", "es-errors": "^1.3.0", "object.entries": "^1.1.9", "semver": "^6.3.1" } }, "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw=="], + + "node-releases": ["node-releases@2.0.37", "", {}, "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg=="], + + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + + "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], + + "object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="], + + "object.entries": ["object.entries@1.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-object-atoms": "^1.1.1" } }, "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw=="], + + "object.fromentries": ["object.fromentries@2.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-object-atoms": "^1.0.0" } }, "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ=="], + + "object.groupby": ["object.groupby@1.0.3", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2" } }, "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ=="], + + "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], + + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], + + "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], + + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + + "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], + + "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], + + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + + "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], + + "postcss": ["postcss@8.5.10", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ=="], + + "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], + + "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + + "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], + + "react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="], + + "react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], + + "regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", "get-proto": "^1.0.1", "gopd": "^1.2.0", "set-function-name": "^2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="], + + "resolve": ["resolve@2.0.0-next.6", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "node-exports-info": "^1.6.0", "object-keys": "^1.1.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA=="], + + "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], + + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + + "safe-array-concat": ["safe-array-concat@1.1.4", "", { "dependencies": { "call-bind": "^1.0.9", "call-bound": "^1.0.4", "get-intrinsic": "^1.3.0", "has-symbols": "^1.1.0", "isarray": "^2.0.5" } }, "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg=="], + + "safe-push-apply": ["safe-push-apply@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "isarray": "^2.0.5" } }, "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA=="], + + "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], + + "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], + + "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], + + "set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="], + + "set-proto": ["set-proto@1.0.0", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0" } }, "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw=="], + + "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], + + "side-channel-list": ["side-channel-list@1.0.1", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.4" } }, "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w=="], + + "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], + + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "stable-hash": ["stable-hash@0.0.5", "", {}, "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA=="], + + "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], + + "string.prototype.includes": ["string.prototype.includes@2.0.1", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.3" } }, "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg=="], + + "string.prototype.matchall": ["string.prototype.matchall@4.0.12", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "regexp.prototype.flags": "^1.5.3", "set-function-name": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA=="], + + "string.prototype.repeat": ["string.prototype.repeat@1.0.0", "", { "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" } }, "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w=="], + + "string.prototype.trim": ["string.prototype.trim@1.2.10", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-data-property": "^1.1.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-object-atoms": "^1.0.0", "has-property-descriptors": "^1.0.2" } }, "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA=="], + + "string.prototype.trimend": ["string.prototype.trimend@1.0.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ=="], + + "string.prototype.trimstart": ["string.prototype.trimstart@1.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg=="], + + "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="], + + "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + + "styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="], + + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], + + "tailwindcss": ["tailwindcss@4.2.4", "", {}, "sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA=="], + + "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], + + "tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "ts-api-utils": ["ts-api-utils@2.5.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA=="], + + "tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], + + "typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="], + + "typed-array-byte-length": ["typed-array-byte-length@1.0.3", "", { "dependencies": { "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.14" } }, "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg=="], + + "typed-array-byte-offset": ["typed-array-byte-offset@1.0.4", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.15", "reflect.getprototypeof": "^1.0.9" } }, "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ=="], + + "typed-array-length": ["typed-array-length@1.0.7", "", { "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", "is-typed-array": "^1.1.13", "possible-typed-array-names": "^1.0.0", "reflect.getprototypeof": "^1.0.6" } }, "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "typescript-eslint": ["typescript-eslint@8.59.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.59.0", "@typescript-eslint/parser": "8.59.0", "@typescript-eslint/typescript-estree": "8.59.0", "@typescript-eslint/utils": "8.59.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-BU3ONW9X+v90EcCH9ZS6LMackcVtxRLlI3XrYyqZIwVSHIk7Qf7bFw1z0M9Q0IUxhTMZCf8piY9hTYaNEIASrw=="], + + "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], + + "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + + "unrs-resolver": ["unrs-resolver@1.11.1", "", { "dependencies": { "napi-postinstall": "^0.3.0" }, "optionalDependencies": { "@unrs/resolver-binding-android-arm-eabi": "1.11.1", "@unrs/resolver-binding-android-arm64": "1.11.1", "@unrs/resolver-binding-darwin-arm64": "1.11.1", "@unrs/resolver-binding-darwin-x64": "1.11.1", "@unrs/resolver-binding-freebsd-x64": "1.11.1", "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-musl": "1.11.1", "@unrs/resolver-binding-wasm32-wasi": "1.11.1", "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg=="], + + "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], + + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="], + + "which-builtin-type": ["which-builtin-type@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.1.0", "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", "is-regex": "^1.2.1", "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.1.0", "which-collection": "^1.0.2", "which-typed-array": "^1.1.16" } }, "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q=="], + + "which-collection": ["which-collection@1.0.2", "", { "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", "is-weakmap": "^2.0.2", "is-weakset": "^2.0.3" } }, "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw=="], + + "which-typed-array": ["which-typed-array@1.1.20", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg=="], + + "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], + + "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], + + "zod-validation-error": ["zod-validation-error@4.0.2", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ=="], + + "@babel/core/json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], + + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], + + "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], + + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" }, "bundled": true }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], + + "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + + "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + + "@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "@typescript-eslint/typescript-estree/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], + + "@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], + + "eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "is-bun-module/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], + + "micromatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], + + "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], + + "sharp/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], + + "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.5", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ=="], + + "@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + } +} diff --git a/web/components/architecture/architecture-hub.tsx b/web/components/architecture/architecture-hub.tsx new file mode 100644 index 0000000..e2b0cf1 --- /dev/null +++ b/web/components/architecture/architecture-hub.tsx @@ -0,0 +1,263 @@ +"use client"; + +import { useState } from "react"; + +const pillars = [ + { + id: "define", + title: "DEFINE STEPS", + subtitle: "YAML engine", + description: "Shape rebalance intent in ordered YAML steps.", + accent: "from-wallbit-400/70 via-wallbit-500/25 to-transparent", + Icon: IconBlueprint, + featured: false, + }, + { + id: "validate", + title: "CHECK INPUTS", + subtitle: "Validation layer", + description: "Verify structure, handlers, and step references before run.", + accent: "from-wallbit-300/60 via-wallbit-500/20 to-transparent", + Icon: IconShieldCheck, + featured: false, + }, + { + id: "execute", + title: "EXECUTE FLOW", + subtitle: "Command runtime", + description: "Run the validated plan and consume deterministic JSON output.", + accent: "from-wallbit-500/70 via-wallbit-600/20 to-transparent", + Icon: IconPlayResults, + featured: false, + }, + { + id: "automate", + title: "AGENT AUTOMATION", + subtitle: "Autonomous orchestration", + description: "Let agents trigger validated workflows with guardrails and predictable outputs.", + accent: "from-wallbit-200/80 via-wallbit-500/30 to-transparent", + Icon: IconAgentSpark, + featured: true, + }, +] as const; + +const flowSteps = [ + { + id: "define", + button: "DEFINE STEPS", + tag: "STEP 1", + title: "Model the rebalance intent in YAML", + description: + "Define the portfolio check as ordered steps so you and your agents share the same plan before execution.", + example: `version: 1 +name: rebalance-check +steps: + - id: checking + run: balance.get_checking + - id: stocks + run: balance.get_stocks + - id: fx + run: rates.get + with: + source: USD + dest: EUR`, + chips: ["Human-readable plan", "Composable steps", "Reusable file"], + }, + { + id: "validate", + button: "CHECK INPUTS", + tag: "STEP 2", + title: "Validate structure and inputs before money moves", + description: + "Catch unsupported runs, missing fields, and bad references early so runs stay reliable across environments.", + example: `$ wallbit workflow validate ./rebalance.yaml +{ + "ok": true, + "workflow": "rebalance-check", + "steps": 3 +}`, + chips: ["Contract checks", "Reference checks", "Fast feedback"], + }, + { + id: "execute", + button: "EXECUTE FLOW", + tag: "STEP 3", + title: "Run and review deterministic output", + description: + "Execute the exact validated flow and consume RunResult JSON for automation, monitoring, or decision layers.", + example: `$ wallbit workflow run ./rebalance.yaml +{ + "ok": true, + "started_at": "...", + "finished_at": "...", + "steps": [{ "id": "fx", "ok": true }] +}`, + chips: ["Stable exits", "Structured JSON", "Agent-ready output"], + }, + { + id: "automate", + button: "AGENT AUTOMATION", + tag: "STEP 4", + title: "Automate rebalance decisions with your agent", + description: + "Once the workflow is validated, your copilot can trigger runs on schedule or based on signals, while preserving the same deterministic contract.", + example: `# agent loop (pseudo) +signal: "stocks_weight > 60%" +action: + run: wallbit workflow run ./rebalance.yaml +expect: + ok: true + output: RunResult`, + chips: ["Scheduled or event-driven", "Same validated YAML", "Safe-by-default automation"], + }, +] as const; + +function IconBlueprint() { + return ( + + + + + + ); +} + +function IconShieldCheck() { + return ( + + + + + ); +} + +function IconPlayResults() { + return ( + + + + + + ); +} + +function IconAgentSpark() { + return ( + + + + + + + + ); +} + +const focusRing = + "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-wallbit-500/90 focus-visible:ring-offset-2 focus-visible:ring-offset-black"; + +export function ArchitectureHub() { + const [activeStepId, setActiveStepId] = useState<(typeof flowSteps)[number]["id"]>("define"); + const [progressCycle, setProgressCycle] = useState(0); + const activeStep = flowSteps.find((step) => step.id === activeStepId) ?? flowSteps[0]; + const handleSelectStep = (stepId: (typeof flowSteps)[number]["id"]) => { + setActiveStepId(stepId); + setProgressCycle((prev) => prev + 1); + }; + const handleAdvanceStep = () => { + window.setTimeout(() => { + const currentIndex = pillars.findIndex((p) => p.id === activeStepId); + const nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % pillars.length; + setActiveStepId(pillars[nextIndex].id); + setProgressCycle((prev) => prev + 1); + }, 160); + }; + + return ( +
+
+

+ Built on a foundation of fast,{" "} + production-grade tooling +

+
+
+

Common Portfolio Flow

+ +
+

{activeStep.tag}

+

{activeStep.title}

+

{activeStep.description}

+ +
+                {activeStep.example}
+              
+ +
+ {activeStep.chips.map((chip) => ( + + {chip} + + ))} +
+
+
+ +
+

Select a stage

+
    + {pillars.map((p) => { + const IconCmp = p.Icon; + const isActive = p.id === activeStep.id; + return ( +
  • +
    +
    + {isActive ? ( + + ) : null} +
    + +
    +
  • + ); + })} +
+
+
+
+
+ ); +} diff --git a/web/components/home/features-section.tsx b/web/components/home/features-section.tsx new file mode 100644 index 0000000..1486be0 --- /dev/null +++ b/web/components/home/features-section.tsx @@ -0,0 +1,89 @@ +import Link from "next/link"; + +const featureBlocks = [ + { + tag: "BINARY", + title: "Built for humans and agents", + body: + "One interface for exploratory commands and repeatable workflows. You and your agent operate on the same contract.", + href: "/docs#cmd-overview", + cta: "See Command Overview", + }, + { + tag: "WORKFLOWS", + title: "YAML that executes, not just documents", + body: + "Turn intent into executable plans with `${steps..}`. Compose once, run many times, and keep shell glue out of mission-critical flows.", + href: "/docs#workflow-language", + cta: "See Workflow Language", + }, + { + tag: "VALIDATE", + title: "Validate before money moves", + body: + "`wallbit workflow validate` checks run keys and payload structure up front, so agents catch broken plans before execution.", + href: "/docs#workflow-validate-run", + cta: "See Validate & Run", + }, + { + tag: "JSON", + title: "Automation-ready output", + body: + "Structured JSON on success, strict non-zero exits on failure. Easy to pipe, test, monitor, and chain in automation pipelines.", + href: "/docs#output", + cta: "See Output Format", + }, + { + tag: "AUTH", + title: "Predictable auth resolution", + body: + "Clear credential precedence keeps runs deterministic across environments. See effective auth state instantly with `auth status`.", + href: "/docs#authentication", + cta: "See Authentication", + }, + { + tag: "SDK", + title: "Aligned with the public API", + body: + "Typed requests and domain-aware commands keep execution close to API behavior, with knobs for base URL and timeout when you need control.", + href: "/docs#cmd-overview", + cta: "See API Mapping", + }, +] as const; + +export function FeaturesSection() { + return ( +
+
+
+

Features

+

+ Why teams trust wallbit-cli +

+

+ From prompt to production run: design workflows with your favorite agent, validate them with the CLI, and execute with + confidence. +

+
+
    + {featureBlocks.map((f) => ( +
  • +
    + +
    + + {f.tag} +

    {f.title}

    +

    {f.body}

    + {f.cta} → + +
  • + ))} +
+
+
+ ); +} diff --git a/web/components/home/get-started-section.tsx b/web/components/home/get-started-section.tsx new file mode 100644 index 0000000..cffefe0 --- /dev/null +++ b/web/components/home/get-started-section.tsx @@ -0,0 +1,72 @@ +import type { CSSProperties } from "react"; + +type LineStyle = CSSProperties & { "--tw-len"?: number; "--tw-delay"?: string }; + +const lineStyle = (len: number, delay: number): LineStyle => ({ + ["--tw-len"]: len, + ["--tw-delay"]: `${delay}s`, +}); + +export function GetStartedSection() { + return ( +
+
+

Quickstart

+

Install, Validate, Execute

+

+ Run your first end-to-end workflow in minutes with the exact commands below. +

+
+ 1. Install + 2. Auth + 3. Validate + 4. Run +
+
+
+ + + + ~/wallbit · zsh +
+
+            
+              
+                $ 
+                go install github.com/jeremyjsx/wallbit-cli/cmd/wallbit@latest
+              
+              
+              
+                $ 
+                wallbit auth login
+              
+              
+                # paste key once → stored locally
+              
+              
+              
+                $ 
+                wallbit workflow validate ./workflow.yaml
+              
+              
+                > OK — steps and inputs look good
+              
+              
+              
+                $ 
+                wallbit workflow run ./workflow.yaml
+              
+              
+                > JSON run report on stdout
+                
+              
+            
+          
+
+
+
+ ); +} diff --git a/web/components/home/hero-section.tsx b/web/components/home/hero-section.tsx new file mode 100644 index 0000000..3abb34a --- /dev/null +++ b/web/components/home/hero-section.tsx @@ -0,0 +1,58 @@ +import Link from "next/link"; + +type HeroSectionProps = { + githubUrl: string; +}; + +export function HeroSection({ githubUrl }: HeroSectionProps) { + return ( +
+
+
+
+ + open source + + + powered by wallbit-go + +
+

+ Automate financial workflows + + from your terminal. + +

+

+ wallbit-cli turns AI plans into reliable execution: + define flows in YAML, run them with confidence, and keep every step observable. +

+

+ Built for builders and agents who want speed without chaos: deterministic outputs, validation before execution, + and composable workflows that scale from one-off runs to production automations. +

+
+ + Open Quickstart + + + View on GitHub + +
+
+
+ ); +} diff --git a/web/components/home/home-cta-section.tsx b/web/components/home/home-cta-section.tsx new file mode 100644 index 0000000..5bf00fa --- /dev/null +++ b/web/components/home/home-cta-section.tsx @@ -0,0 +1,41 @@ +import Link from "next/link"; + +type HomeCtaSectionProps = { + githubUrl: string; +}; + +export function HomeCtaSection({ githubUrl }: HomeCtaSectionProps) { + return ( +
+
+

+ [{" "} + ready to ship?{" "} + ] +

+

+ Ready to run your first real workflow? +

+

+ Start with the quickstart, adapt the YAML to your use case, and execute with deterministic output from the CLI. +

+
+ + Open Quickstart + + + View on GitHub + +
+
+
+ ); +} diff --git a/web/components/home/home-header.tsx b/web/components/home/home-header.tsx new file mode 100644 index 0000000..a58e7b6 --- /dev/null +++ b/web/components/home/home-header.tsx @@ -0,0 +1,70 @@ +import Link from "next/link"; +import { WallbitMark } from "../site/wallbit-mark"; + +function Logo() { + return ( + + + wallbit-cli + + ); +} + +export function HomeHeader() { + const navLinkClass = + "transition-colors hover:text-wallbit-400 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-wallbit-500/90 focus-visible:ring-offset-2 focus-visible:ring-offset-black rounded-sm"; + + return ( +
+
+ + +
+ + Docs + + + Quickstart + +
+
+ +
+ ); +} diff --git a/web/components/home/product-section.tsx b/web/components/home/product-section.tsx new file mode 100644 index 0000000..c88f865 --- /dev/null +++ b/web/components/home/product-section.tsx @@ -0,0 +1,56 @@ +export function ProductSection() { + return ( +
+
+

+ Product +

+

+ One CLI, two ways to win +

+

+ Move fast with direct commands, then lock in repeatability with YAML workflows you and your agents can run with + the same outcome every time. +

+
+
+
01
+

Direct commands

+

Ship outcomes in seconds

+

+ Query balances, rates, cards, trades, and more with explicit flags and clean JSON. Perfect for quick + decisions, scripts, and agent prompts. +

+
+              
+                $ 
+                wallbit balance checking
+                {"\n"}
+                $ 
+                wallbit rates get --source USD --dest EUR
+              
+            
+
+
+
02
+

YAML workflows

+

Scale execution like infrastructure

+

+ Define multi-step financial flows in YAML, validate before run, and execute the same plan across environments + with zero drift. +

+
+              
+                $ 
+                wallbit workflow validate ./payroll.yaml
+                {"\n"}
+                $ 
+                wallbit workflow run ./payroll.yaml
+              
+            
+
+
+
+
+ ); +} diff --git a/web/components/site/announcement-bar.tsx b/web/components/site/announcement-bar.tsx new file mode 100644 index 0000000..5120e17 --- /dev/null +++ b/web/components/site/announcement-bar.tsx @@ -0,0 +1,53 @@ +/** + * Site-wide announcement strip. Slightly taller than a standard top bar + * because the brand has a real release to announce. Uses three layered + * effects to draw the eye without screaming: + * 1. centered radial brand glow, + * 2. periodic shimmer sweep (CSS-only, see globals.css), + * 3. luminous brand bottom border. + */ +export function AnnouncementBar() { + return ( +
+
+ + + ); +} diff --git a/web/components/site/global-footer.tsx b/web/components/site/global-footer.tsx new file mode 100644 index 0000000..0c13b24 --- /dev/null +++ b/web/components/site/global-footer.tsx @@ -0,0 +1,33 @@ +import Link from "next/link"; + +const GITHUB_REPO = "jeremyjsx/wallbit-cli"; +const GITHUB_URL = `https://github.com/${GITHUB_REPO}`; + +export async function GlobalFooter() { + return ( +
+
+

+ © {new Date().getFullYear()} wallbit-cli by Jeremy. Independent tool + built on top of the Wallbit public API. +

+
+ + Quickstart + + + Docs + + + GitHub + +
+
+
+ ); +} diff --git a/web/components/site/wallbit-mark.tsx b/web/components/site/wallbit-mark.tsx new file mode 100644 index 0000000..aba412c --- /dev/null +++ b/web/components/site/wallbit-mark.tsx @@ -0,0 +1,61 @@ +type WallbitMarkProps = { + className?: string; + title?: string; +}; + +/** + * Wallbit brand mark. + * + * The source asset paints the OUTER rectangle and uses the "W" as + * negative space. Rendering it directly on a dark background paints + * the rectangle in `currentColor` and leaves the W dark — the opposite + * of what we want. + * + * Fix: use an SVG `` to invert the fill semantics. The mask + * starts white (= visible) and the original path is painted black + * (= hidden) over it. We then fill a full-canvas rect with + * `currentColor` through the mask, so only the negative space of the + * source path (the W shape) renders. + * + * Aspect is 94:112; size with `h-*` and `w-auto`. + */ +export function WallbitMark({ className, title }: WallbitMarkProps) { + const maskId = "wallbit-mark-cutout"; + const path = + "M0 560 l0 -560 470 0 470 0 0 135 0 136 -27 -15 c-16 -8 -68 -37 -118 -66 l-90 -52 -60 32 c-33 18 -65 38 -72 44 -9 8 -13 63 -13 185 l-2 173 64 39 c34 21 67 38 72 39 5 0 7 -75 4 -175 -3 -101 -2 -175 3 -175 5 0 27 11 48 24 38 24 38 24 44 108 4 45 7 163 7 261 0 97 3 177 6 177 3 0 35 -16 70 -36 l64 -36 0 161 0 161 -470 0 -470 0 0 -560z m592 433 l118 -67 0 -82 0 -82 -150 -86 c-82 -47 -155 -86 -162 -86 -7 1 -44 18 -82 39 l-68 39 103 55 c57 30 130 68 162 83 31 16 57 32 57 36 0 4 -23 19 -51 33 l-51 26 -186 -107 c-103 -59 -206 -119 -229 -132 l-43 -24 0 80 0 80 227 130 c126 71 230 130 232 131 3 1 58 -29 123 -66z m-282 -458 l149 -86 3 -84 c2 -47 1 -85 -1 -85 -2 0 -66 38 -141 85 -76 47 -145 88 -154 91 -13 5 -16 -2 -16 -48 l0 -55 215 -123 c118 -67 222 -128 230 -134 13 -9 5 -17 -49 -49 -36 -20 -69 -37 -73 -37 -4 0 -109 58 -233 129 l-225 128 -3 136 -3 135 73 41 c40 22 74 41 76 41 1 0 70 -38 152 -85z"; + + return ( + + {title ? {title} : null} + + + + + + + + + + + ); +} diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs new file mode 100644 index 0000000..05e726d --- /dev/null +++ b/web/eslint.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig, globalIgnores } from "eslint/config"; +import nextVitals from "eslint-config-next/core-web-vitals"; +import nextTs from "eslint-config-next/typescript"; + +const eslintConfig = defineConfig([ + ...nextVitals, + ...nextTs, + // Override default ignores of eslint-config-next. + globalIgnores([ + // Default ignores of eslint-config-next: + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ]), +]); + +export default eslintConfig; diff --git a/web/next.config.ts b/web/next.config.ts new file mode 100644 index 0000000..e9ffa30 --- /dev/null +++ b/web/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + /* config options here */ +}; + +export default nextConfig; diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..1dc873d --- /dev/null +++ b/web/package.json @@ -0,0 +1,34 @@ +{ + "name": "web", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "eslint" + }, + "dependencies": { + "next": "16.2.4", + "react": "19.2.4", + "react-dom": "19.2.4" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.2.4", + "tailwindcss": "^4", + "typescript": "^5" + }, + "ignoreScripts": [ + "sharp", + "unrs-resolver" + ], + "trustedDependencies": [ + "sharp", + "unrs-resolver" + ] +} diff --git a/web/postcss.config.mjs b/web/postcss.config.mjs new file mode 100644 index 0000000..61e3684 --- /dev/null +++ b/web/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; diff --git a/web/public/file.svg b/web/public/file.svg new file mode 100644 index 0000000..004145c --- /dev/null +++ b/web/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/public/globe.svg b/web/public/globe.svg new file mode 100644 index 0000000..567f17b --- /dev/null +++ b/web/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/public/next.svg b/web/public/next.svg new file mode 100644 index 0000000..5174b28 --- /dev/null +++ b/web/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/public/vercel.svg b/web/public/vercel.svg new file mode 100644 index 0000000..7705396 --- /dev/null +++ b/web/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/public/window.svg b/web/public/window.svg new file mode 100644 index 0000000..b2b2a44 --- /dev/null +++ b/web/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/tsconfig.json b/web/tsconfig.json new file mode 100644 index 0000000..3a13f90 --- /dev/null +++ b/web/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts", + "**/*.mts" + ], + "exclude": ["node_modules"] +}