detached fe26fdd

Merge pull request #127 from bnema/chore/update-deps

chore: update dependencies and add dependabot auto-merge
commit
fe26fdd1ef5ae1c39c155d3fadd5baa9443f8703
author
bnema · · 2026-01-23 06:50 UTC
committer
GitHub · · 2026-01-23 06:50 UTC
merge of
2e6c485 + a3f5ef4 · diff against the first parent
signature
GPG UnverifiedB5690EEEBB952194 The key is unknown
26 files · +1417 -679
A .github/CODEOWNERS +2 -0
@@ -0,0 +1,2 @@
1+# Default owner for everything
2+* @bnema
@@ -0,0 +1,2 @@
1+# Default owner for everything
2+* @bnema
A .github/dependabot.yml +28 -0
@@ -0,0 +1,28 @@
1+version: 2
2+updates:
3+ - package-ecosystem: gomod
4+ directory: /
5+ schedule:
6+ interval: weekly
7+ groups:
8+ go-dependencies:
9+ patterns:
10+ - "*"
11+
12+ - package-ecosystem: npm
13+ directory: /webui
14+ schedule:
15+ interval: weekly
16+ groups:
17+ npm-dependencies:
18+ patterns:
19+ - "*"
20+
21+ - package-ecosystem: github-actions
22+ directory: /
23+ schedule:
24+ interval: weekly
25+ groups:
26+ github-actions:
27+ patterns:
28+ - "*"
@@ -0,0 +1,28 @@
1+version: 2
2+updates:
3+ - package-ecosystem: gomod
4+ directory: /
5+ schedule:
6+ interval: weekly
7+ groups:
8+ go-dependencies:
9+ patterns:
10+ - "*"
11+
12+ - package-ecosystem: npm
13+ directory: /webui
14+ schedule:
15+ interval: weekly
16+ groups:
17+ npm-dependencies:
18+ patterns:
19+ - "*"
20+
21+ - package-ecosystem: github-actions
22+ directory: /
23+ schedule:
24+ interval: weekly
25+ groups:
26+ github-actions:
27+ patterns:
28+ - "*"
A .github/workflows/dependabot-auto-merge.yml +25 -0
@@ -0,0 +1,25 @@
1+name: Dependabot auto-merge
2+
3+on: pull_request
4+
5+permissions:
6+ contents: write
7+ pull-requests: write
8+
9+jobs:
10+ dependabot:
11+ runs-on: ubuntu-latest
12+ if: github.actor == 'dependabot[bot]'
13+ steps:
14+ - name: Dependabot metadata
15+ id: metadata
16+ uses: dependabot/fetch-metadata@v2
17+ with:
18+ github-token: "${{ secrets.GITHUB_TOKEN }}"
19+
20+ - name: Auto-merge patch and minor updates
21+ if: steps.metadata.outputs.update-type == 'version-update:semver-patch' || steps.metadata.outputs.update-type == 'version-update:semver-minor'
22+ run: gh pr merge --auto --squash "$PR_URL"
23+ env:
24+ PR_URL: ${{ github.event.pull_request.html_url }}
25+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,25 @@
1+name: Dependabot auto-merge
2+
3+on: pull_request
4+
5+permissions:
6+ contents: write
7+ pull-requests: write
8+
9+jobs:
10+ dependabot:
11+ runs-on: ubuntu-latest
12+ if: github.actor == 'dependabot[bot]'
13+ steps:
14+ - name: Dependabot metadata
15+ id: metadata
16+ uses: dependabot/fetch-metadata@v2
17+ with:
18+ github-token: "${{ secrets.GITHUB_TOKEN }}"
19+
20+ - name: Auto-merge patch and minor updates
21+ if: steps.metadata.outputs.update-type == 'version-update:semver-patch' || steps.metadata.outputs.update-type == 'version-update:semver-minor'
22+ run: gh pr merge --auto --squash "$PR_URL"
23+ env:
24+ PR_URL: ${{ github.event.pull_request.html_url }}
25+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
M CHANGELOG.md +7 -0
@@ -2,6 +2,13 @@
22
33 All notable changes to this project will be documented in this file.
44
5+## [Unreleased]
6+
7+### Fixed
8+- **Session snapshot FK constraint**: Fixed SQLite foreign key constraint violation when snapshot service tried to save before session was persisted to database. Added ready flag and callback notification pattern.
9+- **Stacked pane index out of bounds**: Fixed crash when domain model and UI got out of sync during stacked pane operations. Added bounds checking and proper rollback when UI updates fail.
10+- **Noisy gesture navigation logs**: Mouse button back/forward navigation errors (expected when no history) now log at debug level instead of error level.
11+
512 ## [0.25.0] - 2026-01-08
613
714 ### Added
@@ -2,6 +2,13 @@
2 2
3 All notable changes to this project will be documented in this file.3 All notable changes to this project will be documented in this file.
4 4
5+## [Unreleased]
6+
7+### Fixed
8+- **Session snapshot FK constraint**: Fixed SQLite foreign key constraint violation when snapshot service tried to save before session was persisted to database. Added ready flag and callback notification pattern.
9+- **Stacked pane index out of bounds**: Fixed crash when domain model and UI got out of sync during stacked pane operations. Added bounds checking and proper rollback when UI updates fail.
10+- **Noisy gesture navigation logs**: Mouse button back/forward navigation errors (expected when no history) now log at debug level instead of error level.
11+
5 ## [0.25.0] - 2026-01-0812 ## [0.25.0] - 2026-01-08
6 13
7 ### Added14 ### Added
M cmd/dumber/main.go +96 -32
@@ -29,6 +29,7 @@ import (
2929 "github.com/bnema/dumber/internal/logging"
3030 "github.com/bnema/dumber/internal/ui"
3131 "github.com/bnema/dumber/internal/ui/theme"
32+ "github.com/rs/zerolog"
3233 )
3334
3435 // Build-time variables (set via ldflags).
@@ -75,17 +76,12 @@ func runGUI() int {
7576 cfg := initConfig()
7677 timer.Mark("config")
7778
78- ctx := initStartupContext(cfg)
79+ ctx := initStartupContextWithTrace(cfg)
7980 timer.Mark("logger")
8081 bootstrapLog := logging.FromContext(ctx)
8182
82- // Parallel phase: directories and theme setup
83- initResult, err := bootstrap.RunParallelInit(bootstrap.ParallelInitInput{
84- Ctx: ctx,
85- Config: cfg,
86- })
83+ initResult, err := runParallelInitPhase(ctx, cfg)
8784 if err != nil {
88- handleParallelInitError(ctx, err)
8985 return 1
9086 }
9187 timer.MarkDuration("parallel_phase", initResult.Duration)
@@ -101,44 +97,27 @@ func runGUI() int {
10197 }
10298 timer.Mark("db_webkit_parallel")
10399
104- browserSession, sessionCtx, err := bootstrap.StartBrowserSession(ctx, cfg, repos.session, !needsEagerDB)
105- if err != nil {
106- bootstrapLog.Fatal().Err(err).Msg("failed to start session")
107- }
108- if browserSession.LogCleanup != nil {
109- defer browserSession.LogCleanup()
110- }
111- defer func() { _ = browserSession.End(sessionCtx) }()
100+ ctx, browserSession, sessionCleanup := initBrowserSession(ctx, cfg, repos, bootstrapLog)
101+ defer sessionCleanup()
112102 timer.Mark("session")
113103
114- ctx = sessionCtx
115104 log := logging.FromContext(ctx)
105+ logging.Trace().UpdateLogger(log)
106+
116107 if stack.MessageRouter != nil {
117108 stack.MessageRouter.SetBaseContext(ctx)
118109 }
119110
120- // Repositories and use cases
121111 useCases := createUseCases(repos, cfg)
122112 if needsEagerDB {
123113 handleAutoRestore(ctx, cfg, useCases, browserSession.Session.ID)
124114 }
125115
126116 idleInhibitor := idle.NewPortalInhibitor(ctx)
127- defer func() {
128- if idleInhibitor != nil {
129- _ = idleInhibitor.Close()
130- }
131- }()
117+ defer closeIdleInhibitor(idleInhibitor)
132118 timer.Mark("use_cases")
133119
134- // Build UI
135- uiDeps := buildUIDependencies(
136- ctx, cfg, initResult.ThemeManager,
137- initResult.ColorResolver, initResult.AdwaitaDetector,
138- &stack, repos, useCases, idleInhibitor, browserSession.Session.ID,
139- )
140- configureDeferredInit(uiDeps, cfg, browserSession)
141- app, err := ui.New(uiDeps)
120+ app, err := buildAndConfigureApp(ctx, cfg, initResult, &stack, repos, useCases, idleInhibitor, browserSession)
142121 if err != nil {
143122 log.Error().Err(err).Msg("failed to create application")
144123 return 1
@@ -146,12 +125,83 @@ func runGUI() int {
146125 timer.Mark("ui_deps")
147126 timer.Log(ctx)
148127
149- // Signal handling
150128 setupSignalHandler(ctx, app)
151129
152130 return app.Run(ctx, os.Args)
153131 }
154132
133+func initStartupContextWithTrace(cfg *config.Config) context.Context {
134+ logging.InitStartupTrace(cfg.Logging.Level)
135+ logging.Trace().Mark("config_loaded")
136+
137+ ctx := initStartupContext(cfg)
138+ bootstrapLog := logging.FromContext(ctx)
139+
140+ logging.Trace().SetLogger(bootstrapLog)
141+ logging.Trace().Mark("logger_init")
142+
143+ return ctx
144+}
145+
146+func runParallelInitPhase(ctx context.Context, cfg *config.Config) (*bootstrap.ParallelInitResult, error) {
147+ logging.Trace().Mark("parallel_start")
148+ initResult, err := bootstrap.RunParallelInit(bootstrap.ParallelInitInput{
149+ Ctx: ctx,
150+ Config: cfg,
151+ })
152+ if err != nil {
153+ handleParallelInitError(ctx, err)
154+ return nil, err
155+ }
156+ logging.Trace().Mark("parallel_done")
157+ return initResult, nil
158+}
159+
160+func initBrowserSession(
161+ ctx context.Context,
162+ cfg *config.Config,
163+ repos *repositories,
164+ bootstrapLog *zerolog.Logger,
165+) (context.Context, *bootstrap.BrowserSession, func()) {
166+ deferPersist := restoreSessionID == "" && !cfg.Session.AutoRestore
167+ browserSession, sessionCtx, err := bootstrap.StartBrowserSession(ctx, cfg, repos.session, deferPersist)
168+ if err != nil {
169+ bootstrapLog.Fatal().Err(err).Msg("failed to start session")
170+ }
171+ cleanup := func() {
172+ if browserSession.LogCleanup != nil {
173+ browserSession.LogCleanup()
174+ }
175+ _ = browserSession.End(sessionCtx)
176+ }
177+ return sessionCtx, browserSession, cleanup
178+}
179+
180+func closeIdleInhibitor(inhibitor port.IdleInhibitor) {
181+ if inhibitor != nil {
182+ _ = inhibitor.Close()
183+ }
184+}
185+
186+func buildAndConfigureApp(
187+ ctx context.Context,
188+ cfg *config.Config,
189+ initResult *bootstrap.ParallelInitResult,
190+ stack *bootstrap.WebKitStack,
191+ repos *repositories,
192+ useCases *useCases,
193+ idleInhibitor port.IdleInhibitor,
194+ browserSession *bootstrap.BrowserSession,
195+) (*ui.App, error) {
196+ uiDeps := buildUIDependencies(
197+ ctx, cfg, initResult.ThemeManager,
198+ initResult.ColorResolver, initResult.AdwaitaDetector,
199+ stack, repos, useCases, idleInhibitor, browserSession.Session.ID,
200+ )
201+ configureDeferredInit(uiDeps, cfg, browserSession)
202+ return ui.New(uiDeps)
203+}
204+
155205 func initStartupContext(cfg *config.Config) context.Context {
156206 deps.ApplyPrefixEnv(cfg.Runtime.Prefix)
157207 bootstrapLogger := logging.NewFromConfigValuesWithTimeFormat(
@@ -217,6 +267,11 @@ func configureDeferredInit(
217267 if uiDeps == nil {
218268 return
219269 }
270+
271+ // If session was already persisted (not deferred), mark snapshot service ready immediately
272+ // via callback that will be set by the app after initialization
273+ sessionAlreadyPersisted := session == nil || session.Persist == nil
274+
220275 uiDeps.OnFirstWebViewShown = func(cbCtx context.Context) {
221276 logger := logging.FromContext(cbCtx)
222277 bgCtx := logging.WithContext(context.Background(), *logger)
@@ -227,10 +282,19 @@ func configureDeferredInit(
227282 })
228283 logDeferredInitResults(bgCtx, result)
229284 }()
230- if session != nil && session.Persist != nil {
285+
286+ if sessionAlreadyPersisted {
287+ // Session was persisted eagerly, notify immediately
288+ if uiDeps.OnSessionPersisted != nil {
289+ uiDeps.OnSessionPersisted()
290+ }
291+ } else if session.Persist != nil {
292+ // Session persist is deferred, notify after it completes
231293 go func() {
232294 if persistErr := session.Persist(bgCtx); persistErr != nil {
233295 logger.Error().Err(persistErr).Msg("deferred session persistence failed")
296+ } else if uiDeps.OnSessionPersisted != nil {
297+ uiDeps.OnSessionPersisted()
234298 }
235299 }()
236300 }
@@ -29,6 +29,7 @@ import (
29 "github.com/bnema/dumber/internal/logging"29 "github.com/bnema/dumber/internal/logging"
30 "github.com/bnema/dumber/internal/ui"30 "github.com/bnema/dumber/internal/ui"
31 "github.com/bnema/dumber/internal/ui/theme"31 "github.com/bnema/dumber/internal/ui/theme"
32+ "github.com/rs/zerolog"
32 )33 )
33 34
34 // Build-time variables (set via ldflags).35 // Build-time variables (set via ldflags).
@@ -75,17 +76,12 @@ func runGUI() int {
75 cfg := initConfig()76 cfg := initConfig()
76 timer.Mark("config")77 timer.Mark("config")
77 78
78- ctx := initStartupContext(cfg)79+ ctx := initStartupContextWithTrace(cfg)
79 timer.Mark("logger")80 timer.Mark("logger")
80 bootstrapLog := logging.FromContext(ctx)81 bootstrapLog := logging.FromContext(ctx)
81 82
82- // Parallel phase: directories and theme setup83+ initResult, err := runParallelInitPhase(ctx, cfg)
83- initResult, err := bootstrap.RunParallelInit(bootstrap.ParallelInitInput{
84- Ctx: ctx,
85- Config: cfg,
86- })
87 if err != nil {84 if err != nil {
88- handleParallelInitError(ctx, err)
89 return 185 return 1
90 }86 }
91 timer.MarkDuration("parallel_phase", initResult.Duration)87 timer.MarkDuration("parallel_phase", initResult.Duration)
@@ -101,44 +97,27 @@ func runGUI() int {
101 }97 }
102 timer.Mark("db_webkit_parallel")98 timer.Mark("db_webkit_parallel")
103 99
104- browserSession, sessionCtx, err := bootstrap.StartBrowserSession(ctx, cfg, repos.session, !needsEagerDB)100+ ctx, browserSession, sessionCleanup := initBrowserSession(ctx, cfg, repos, bootstrapLog)
105- if err != nil {101+ defer sessionCleanup()
106- bootstrapLog.Fatal().Err(err).Msg("failed to start session")
107- }
108- if browserSession.LogCleanup != nil {
109- defer browserSession.LogCleanup()
110- }
111- defer func() { _ = browserSession.End(sessionCtx) }()
112 timer.Mark("session")102 timer.Mark("session")
113 103
114- ctx = sessionCtx
115 log := logging.FromContext(ctx)104 log := logging.FromContext(ctx)
105+ logging.Trace().UpdateLogger(log)
106+
116 if stack.MessageRouter != nil {107 if stack.MessageRouter != nil {
117 stack.MessageRouter.SetBaseContext(ctx)108 stack.MessageRouter.SetBaseContext(ctx)
118 }109 }
119 110
120- // Repositories and use cases
121 useCases := createUseCases(repos, cfg)111 useCases := createUseCases(repos, cfg)
122 if needsEagerDB {112 if needsEagerDB {
123 handleAutoRestore(ctx, cfg, useCases, browserSession.Session.ID)113 handleAutoRestore(ctx, cfg, useCases, browserSession.Session.ID)
124 }114 }
125 115
126 idleInhibitor := idle.NewPortalInhibitor(ctx)116 idleInhibitor := idle.NewPortalInhibitor(ctx)
127- defer func() {117+ defer closeIdleInhibitor(idleInhibitor)
128- if idleInhibitor != nil {
129- _ = idleInhibitor.Close()
130- }
131- }()
132 timer.Mark("use_cases")118 timer.Mark("use_cases")
133 119
134- // Build UI120+ app, err := buildAndConfigureApp(ctx, cfg, initResult, &stack, repos, useCases, idleInhibitor, browserSession)
135- uiDeps := buildUIDependencies(
136- ctx, cfg, initResult.ThemeManager,
137- initResult.ColorResolver, initResult.AdwaitaDetector,
138- &stack, repos, useCases, idleInhibitor, browserSession.Session.ID,
139- )
140- configureDeferredInit(uiDeps, cfg, browserSession)
141- app, err := ui.New(uiDeps)
142 if err != nil {121 if err != nil {
143 log.Error().Err(err).Msg("failed to create application")122 log.Error().Err(err).Msg("failed to create application")
144 return 1123 return 1
@@ -146,12 +125,83 @@ func runGUI() int {
146 timer.Mark("ui_deps")125 timer.Mark("ui_deps")
147 timer.Log(ctx)126 timer.Log(ctx)
148 127
149- // Signal handling
150 setupSignalHandler(ctx, app)128 setupSignalHandler(ctx, app)
151 129
152 return app.Run(ctx, os.Args)130 return app.Run(ctx, os.Args)
153 }131 }
154 132
133+func initStartupContextWithTrace(cfg *config.Config) context.Context {
134+ logging.InitStartupTrace(cfg.Logging.Level)
135+ logging.Trace().Mark("config_loaded")
136+
137+ ctx := initStartupContext(cfg)
138+ bootstrapLog := logging.FromContext(ctx)
139+
140+ logging.Trace().SetLogger(bootstrapLog)
141+ logging.Trace().Mark("logger_init")
142+
143+ return ctx
144+}
145+
146+func runParallelInitPhase(ctx context.Context, cfg *config.Config) (*bootstrap.ParallelInitResult, error) {
147+ logging.Trace().Mark("parallel_start")
148+ initResult, err := bootstrap.RunParallelInit(bootstrap.ParallelInitInput{
149+ Ctx: ctx,
150+ Config: cfg,
151+ })
152+ if err != nil {
153+ handleParallelInitError(ctx, err)
154+ return nil, err
155+ }
156+ logging.Trace().Mark("parallel_done")
157+ return initResult, nil
158+}
159+
160+func initBrowserSession(
161+ ctx context.Context,
162+ cfg *config.Config,
163+ repos *repositories,
164+ bootstrapLog *zerolog.Logger,
165+) (context.Context, *bootstrap.BrowserSession, func()) {
166+ deferPersist := restoreSessionID == "" && !cfg.Session.AutoRestore
167+ browserSession, sessionCtx, err := bootstrap.StartBrowserSession(ctx, cfg, repos.session, deferPersist)
168+ if err != nil {
169+ bootstrapLog.Fatal().Err(err).Msg("failed to start session")
170+ }
171+ cleanup := func() {
172+ if browserSession.LogCleanup != nil {
173+ browserSession.LogCleanup()
174+ }
175+ _ = browserSession.End(sessionCtx)
176+ }
177+ return sessionCtx, browserSession, cleanup
178+}
179+
180+func closeIdleInhibitor(inhibitor port.IdleInhibitor) {
181+ if inhibitor != nil {
182+ _ = inhibitor.Close()
183+ }
184+}
185+
186+func buildAndConfigureApp(
187+ ctx context.Context,
188+ cfg *config.Config,
189+ initResult *bootstrap.ParallelInitResult,
190+ stack *bootstrap.WebKitStack,
191+ repos *repositories,
192+ useCases *useCases,
193+ idleInhibitor port.IdleInhibitor,
194+ browserSession *bootstrap.BrowserSession,
195+) (*ui.App, error) {
196+ uiDeps := buildUIDependencies(
197+ ctx, cfg, initResult.ThemeManager,
198+ initResult.ColorResolver, initResult.AdwaitaDetector,
199+ stack, repos, useCases, idleInhibitor, browserSession.Session.ID,
200+ )
201+ configureDeferredInit(uiDeps, cfg, browserSession)
202+ return ui.New(uiDeps)
203+}
204+
155 func initStartupContext(cfg *config.Config) context.Context {205 func initStartupContext(cfg *config.Config) context.Context {
156 deps.ApplyPrefixEnv(cfg.Runtime.Prefix)206 deps.ApplyPrefixEnv(cfg.Runtime.Prefix)
157 bootstrapLogger := logging.NewFromConfigValuesWithTimeFormat(207 bootstrapLogger := logging.NewFromConfigValuesWithTimeFormat(
@@ -217,6 +267,11 @@ func configureDeferredInit(
217 if uiDeps == nil {267 if uiDeps == nil {
218 return268 return
219 }269 }
270+
271+ // If session was already persisted (not deferred), mark snapshot service ready immediately
272+ // via callback that will be set by the app after initialization
273+ sessionAlreadyPersisted := session == nil || session.Persist == nil
274+
220 uiDeps.OnFirstWebViewShown = func(cbCtx context.Context) {275 uiDeps.OnFirstWebViewShown = func(cbCtx context.Context) {
221 logger := logging.FromContext(cbCtx)276 logger := logging.FromContext(cbCtx)
222 bgCtx := logging.WithContext(context.Background(), *logger)277 bgCtx := logging.WithContext(context.Background(), *logger)
@@ -227,10 +282,19 @@ func configureDeferredInit(
227 })282 })
228 logDeferredInitResults(bgCtx, result)283 logDeferredInitResults(bgCtx, result)
229 }()284 }()
230- if session != nil && session.Persist != nil {285+
286+ if sessionAlreadyPersisted {
287+ // Session was persisted eagerly, notify immediately
288+ if uiDeps.OnSessionPersisted != nil {
289+ uiDeps.OnSessionPersisted()
290+ }
291+ } else if session.Persist != nil {
292+ // Session persist is deferred, notify after it completes
231 go func() {293 go func() {
232 if persistErr := session.Persist(bgCtx); persistErr != nil {294 if persistErr := session.Persist(bgCtx); persistErr != nil {
233 logger.Error().Err(persistErr).Msg("deferred session persistence failed")295 logger.Error().Err(persistErr).Msg("deferred session persistence failed")
296+ } else if uiDeps.OnSessionPersisted != nil {
297+ uiDeps.OnSessionPersisted()
234 }298 }
235 }()299 }()
236 }300 }
M go.mod +23 -20
@@ -8,17 +8,17 @@ require (
88 github.com/charmbracelet/bubbletea v1.3.10
99 github.com/charmbracelet/lipgloss v1.1.0
1010 github.com/fsnotify/fsnotify v1.9.0
11- github.com/godbus/dbus/v5 v5.2.1
12- github.com/jwijenbergh/puregotk v0.0.0-20251222174431-73930527faa3
13- github.com/ncruces/go-sqlite3 v0.30.3
11+ github.com/godbus/dbus/v5 v5.2.2
12+ github.com/jwijenbergh/puregotk v0.0.0-20260115100645-c78e1521129b
13+ github.com/ncruces/go-sqlite3 v0.30.4
1414 github.com/pelletier/go-toml/v2 v2.2.4
1515 github.com/pressly/goose/v3 v3.26.0
16- github.com/rs/zerolog v1.33.0
16+ github.com/rs/zerolog v1.34.0
1717 github.com/spf13/cobra v1.10.2
1818 github.com/spf13/viper v1.21.0
1919 github.com/stretchr/testify v1.11.1
20- golang.org/x/image v0.34.0
21- golang.org/x/sys v0.38.0
20+ golang.org/x/image v0.35.0
21+ golang.org/x/sys v0.40.0
2222 gopkg.in/yaml.v3 v3.0.1
2323 )
2424
@@ -27,21 +27,24 @@ replace github.com/jwijenbergh/puregotk => github.com/bnema/puregotk v0.0.0-2025
2727 require (
2828 github.com/atotto/clipboard v0.1.4 // indirect
2929 github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
30- github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
31- github.com/charmbracelet/x/ansi v0.10.1 // indirect
32- github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
33- github.com/charmbracelet/x/term v0.2.1 // indirect
34- github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
30+ github.com/charmbracelet/colorprofile v0.4.1 // indirect
31+ github.com/charmbracelet/x/ansi v0.11.4 // indirect
32+ github.com/charmbracelet/x/cellbuf v0.0.14 // indirect
33+ github.com/charmbracelet/x/term v0.2.2 // indirect
34+ github.com/clipperhouse/displaywidth v0.7.0 // indirect
35+ github.com/clipperhouse/stringish v0.1.1 // indirect
36+ github.com/clipperhouse/uax29/v2 v2.3.1 // indirect
37+ github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
3538 github.com/davecgh/go-spew v1.1.1 // indirect
3639 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
37- github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
40+ github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
3841 github.com/inconshreveable/mousetrap v1.1.0 // indirect
3942 github.com/jwijenbergh/purego v0.0.0-20251017112123-b71757b9ba42 // indirect
40- github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
41- github.com/mattn/go-colorable v0.1.13 // indirect
43+ github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
44+ github.com/mattn/go-colorable v0.1.14 // indirect
4245 github.com/mattn/go-isatty v0.0.20 // indirect
4346 github.com/mattn/go-localereader v0.0.1 // indirect
44- github.com/mattn/go-runewidth v0.0.16 // indirect
47+ github.com/mattn/go-runewidth v0.0.19 // indirect
4548 github.com/mfridman/interpolate v0.0.2 // indirect
4649 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
4750 github.com/muesli/cancelreader v0.2.2 // indirect
@@ -50,19 +53,19 @@ require (
5053 github.com/pmezard/go-difflib v1.0.0 // indirect
5154 github.com/rivo/uniseg v0.4.7 // indirect
5255 github.com/russross/blackfriday/v2 v2.1.0 // indirect
53- github.com/sagikazarmark/locafero v0.11.0 // indirect
56+ github.com/sagikazarmark/locafero v0.12.0 // indirect
5457 github.com/sahilm/fuzzy v0.1.1 // indirect
5558 github.com/sethvargo/go-retry v0.3.0 // indirect
56- github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
5759 github.com/spf13/afero v1.15.0 // indirect
5860 github.com/spf13/cast v1.10.0 // indirect
5961 github.com/spf13/pflag v1.0.10 // indirect
60- github.com/stretchr/objx v0.5.2 // indirect
62+ github.com/stretchr/objx v0.5.3 // indirect
6163 github.com/subosito/gotenv v1.6.0 // indirect
62- github.com/tetratelabs/wazero v1.10.1 // indirect
64+ github.com/tetratelabs/wazero v1.11.0 // indirect
6365 github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
6466 go.uber.org/multierr v1.11.0 // indirect
6567 go.yaml.in/yaml/v3 v3.0.4 // indirect
6668 golang.org/x/sync v0.19.0 // indirect
67- golang.org/x/text v0.32.0 // indirect
69+ golang.org/x/text v0.33.0 // indirect
70+ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
6871 )
@@ -8,17 +8,17 @@ require (
8 github.com/charmbracelet/bubbletea v1.3.108 github.com/charmbracelet/bubbletea v1.3.10
9 github.com/charmbracelet/lipgloss v1.1.09 github.com/charmbracelet/lipgloss v1.1.0
10 github.com/fsnotify/fsnotify v1.9.010 github.com/fsnotify/fsnotify v1.9.0
11- github.com/godbus/dbus/v5 v5.2.111+ github.com/godbus/dbus/v5 v5.2.2
12- github.com/jwijenbergh/puregotk v0.0.0-20251222174431-73930527faa312+ github.com/jwijenbergh/puregotk v0.0.0-20260115100645-c78e1521129b
13- github.com/ncruces/go-sqlite3 v0.30.313+ github.com/ncruces/go-sqlite3 v0.30.4
14 github.com/pelletier/go-toml/v2 v2.2.414 github.com/pelletier/go-toml/v2 v2.2.4
15 github.com/pressly/goose/v3 v3.26.015 github.com/pressly/goose/v3 v3.26.0
16- github.com/rs/zerolog v1.33.016+ github.com/rs/zerolog v1.34.0
17 github.com/spf13/cobra v1.10.217 github.com/spf13/cobra v1.10.2
18 github.com/spf13/viper v1.21.018 github.com/spf13/viper v1.21.0
19 github.com/stretchr/testify v1.11.119 github.com/stretchr/testify v1.11.1
20- golang.org/x/image v0.34.020+ golang.org/x/image v0.35.0
21- golang.org/x/sys v0.38.021+ golang.org/x/sys v0.40.0
22 gopkg.in/yaml.v3 v3.0.122 gopkg.in/yaml.v3 v3.0.1
23 )23 )
24 24
@@ -27,21 +27,24 @@ replace github.com/jwijenbergh/puregotk => github.com/bnema/puregotk v0.0.0-2025
27 require (27 require (
28 github.com/atotto/clipboard v0.1.4 // indirect28 github.com/atotto/clipboard v0.1.4 // indirect
29 github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect29 github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
30- github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect30+ github.com/charmbracelet/colorprofile v0.4.1 // indirect
31- github.com/charmbracelet/x/ansi v0.10.1 // indirect31+ github.com/charmbracelet/x/ansi v0.11.4 // indirect
32- github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect32+ github.com/charmbracelet/x/cellbuf v0.0.14 // indirect
33- github.com/charmbracelet/x/term v0.2.1 // indirect33+ github.com/charmbracelet/x/term v0.2.2 // indirect
34- github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect34+ github.com/clipperhouse/displaywidth v0.7.0 // indirect
35+ github.com/clipperhouse/stringish v0.1.1 // indirect
36+ github.com/clipperhouse/uax29/v2 v2.3.1 // indirect
37+ github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
35 github.com/davecgh/go-spew v1.1.1 // indirect38 github.com/davecgh/go-spew v1.1.1 // indirect
36 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect39 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
37- github.com/go-viper/mapstructure/v2 v2.4.0 // indirect40+ github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
38 github.com/inconshreveable/mousetrap v1.1.0 // indirect41 github.com/inconshreveable/mousetrap v1.1.0 // indirect
39 github.com/jwijenbergh/purego v0.0.0-20251017112123-b71757b9ba42 // indirect42 github.com/jwijenbergh/purego v0.0.0-20251017112123-b71757b9ba42 // indirect
40- github.com/lucasb-eyer/go-colorful v1.2.0 // indirect43+ github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
41- github.com/mattn/go-colorable v0.1.13 // indirect44+ github.com/mattn/go-colorable v0.1.14 // indirect
42 github.com/mattn/go-isatty v0.0.20 // indirect45 github.com/mattn/go-isatty v0.0.20 // indirect
43 github.com/mattn/go-localereader v0.0.1 // indirect46 github.com/mattn/go-localereader v0.0.1 // indirect
44- github.com/mattn/go-runewidth v0.0.16 // indirect47+ github.com/mattn/go-runewidth v0.0.19 // indirect
45 github.com/mfridman/interpolate v0.0.2 // indirect48 github.com/mfridman/interpolate v0.0.2 // indirect
46 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect49 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
47 github.com/muesli/cancelreader v0.2.2 // indirect50 github.com/muesli/cancelreader v0.2.2 // indirect
@@ -50,19 +53,19 @@ require (
50 github.com/pmezard/go-difflib v1.0.0 // indirect53 github.com/pmezard/go-difflib v1.0.0 // indirect
51 github.com/rivo/uniseg v0.4.7 // indirect54 github.com/rivo/uniseg v0.4.7 // indirect
52 github.com/russross/blackfriday/v2 v2.1.0 // indirect55 github.com/russross/blackfriday/v2 v2.1.0 // indirect
53- github.com/sagikazarmark/locafero v0.11.0 // indirect56+ github.com/sagikazarmark/locafero v0.12.0 // indirect
54 github.com/sahilm/fuzzy v0.1.1 // indirect57 github.com/sahilm/fuzzy v0.1.1 // indirect
55 github.com/sethvargo/go-retry v0.3.0 // indirect58 github.com/sethvargo/go-retry v0.3.0 // indirect
56- github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
57 github.com/spf13/afero v1.15.0 // indirect59 github.com/spf13/afero v1.15.0 // indirect
58 github.com/spf13/cast v1.10.0 // indirect60 github.com/spf13/cast v1.10.0 // indirect
59 github.com/spf13/pflag v1.0.10 // indirect61 github.com/spf13/pflag v1.0.10 // indirect
60- github.com/stretchr/objx v0.5.2 // indirect62+ github.com/stretchr/objx v0.5.3 // indirect
61 github.com/subosito/gotenv v1.6.0 // indirect63 github.com/subosito/gotenv v1.6.0 // indirect
62- github.com/tetratelabs/wazero v1.10.1 // indirect64+ github.com/tetratelabs/wazero v1.11.0 // indirect
63 github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect65 github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
64 go.uber.org/multierr v1.11.0 // indirect66 go.uber.org/multierr v1.11.0 // indirect
65 go.yaml.in/yaml/v3 v3.0.4 // indirect67 go.yaml.in/yaml/v3 v3.0.4 // indirect
66 golang.org/x/sync v0.19.0 // indirect68 golang.org/x/sync v0.19.0 // indirect
67- golang.org/x/text v0.32.0 // indirect69+ golang.org/x/text v0.33.0 // indirect
70+ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
68 )71 )
M go.sum +43 -38 generated file: collapsed
M internal/application/usecase/navigate.go +5 -2
@@ -17,6 +17,9 @@ const (
1717 // historyQueueSize is the buffer size for the async history queue.
1818 // If the queue is full, new records are dropped with a warning.
1919 historyQueueSize = 100
20+
21+ // logURLMaxLen is the max length for URLs in log messages.
22+ logURLMaxLen = 60
2023 )
2124
2225 // historyRecord holds data for async history recording.
@@ -137,7 +140,7 @@ func (uc *NavigateUseCase) RecordHistory(ctx context.Context, url string) {
137140 // Non-blocking send to async queue
138141 select {
139142 case uc.historyQueue <- historyRecord{url: url, timestamp: now}:
140- log.Debug().Str("url", url).Msg("history record queued")
143+ log.Debug().Str("url", logging.TruncateURL(url, logURLMaxLen)).Msg("history record queued")
141144 default:
142145 // Queue full - log warning but don't block navigation
143146 log.Warn().Str("url", url).Msg("history queue full, dropping record")
@@ -205,7 +208,7 @@ func (uc *NavigateUseCase) UpdateHistoryTitle(ctx context.Context, url, title st
205208
206209 // Normalize URL to match storage (e.g., github.com/ -> github.com)
207210 url = normalizeURLForHistory(url)
208- log.Debug().Str("url", url).Str("title", title).Msg("updating history title")
211+ log.Debug().Str("url", logging.TruncateURL(url, logURLMaxLen)).Str("title", title).Msg("updating history title")
209212
210213 entry, err := uc.historyRepo.FindByURL(ctx, url)
211214 if err != nil {
@@ -17,6 +17,9 @@ const (
17 // historyQueueSize is the buffer size for the async history queue.17 // historyQueueSize is the buffer size for the async history queue.
18 // If the queue is full, new records are dropped with a warning.18 // If the queue is full, new records are dropped with a warning.
19 historyQueueSize = 10019 historyQueueSize = 100
20+
21+ // logURLMaxLen is the max length for URLs in log messages.
22+ logURLMaxLen = 60
20 )23 )
21 24
22 // historyRecord holds data for async history recording.25 // historyRecord holds data for async history recording.
@@ -137,7 +140,7 @@ func (uc *NavigateUseCase) RecordHistory(ctx context.Context, url string) {
137 // Non-blocking send to async queue140 // Non-blocking send to async queue
138 select {141 select {
139 case uc.historyQueue <- historyRecord{url: url, timestamp: now}:142 case uc.historyQueue <- historyRecord{url: url, timestamp: now}:
140- log.Debug().Str("url", url).Msg("history record queued")143+ log.Debug().Str("url", logging.TruncateURL(url, logURLMaxLen)).Msg("history record queued")
141 default:144 default:
142 // Queue full - log warning but don't block navigation145 // Queue full - log warning but don't block navigation
143 log.Warn().Str("url", url).Msg("history queue full, dropping record")146 log.Warn().Str("url", url).Msg("history queue full, dropping record")
@@ -205,7 +208,7 @@ func (uc *NavigateUseCase) UpdateHistoryTitle(ctx context.Context, url, title st
205 208
206 // Normalize URL to match storage (e.g., github.com/ -> github.com)209 // Normalize URL to match storage (e.g., github.com/ -> github.com)
207 url = normalizeURLForHistory(url)210 url = normalizeURLForHistory(url)
208- log.Debug().Str("url", url).Str("title", title).Msg("updating history title")211+ log.Debug().Str("url", logging.TruncateURL(url, logURLMaxLen)).Str("title", title).Msg("updating history title")
209 212
210 entry, err := uc.historyRepo.FindByURL(ctx, url)213 entry, err := uc.historyRepo.FindByURL(ctx, url)
211 if err != nil {214 if err != nil {
M internal/bootstrap/webkit_stack.go +84 -39
@@ -11,6 +11,7 @@ import (
1111 "github.com/bnema/dumber/internal/infrastructure/env"
1212 "github.com/bnema/dumber/internal/infrastructure/filtering"
1313 "github.com/bnema/dumber/internal/infrastructure/webkit"
14+ "github.com/bnema/dumber/internal/logging"
1415 "github.com/bnema/dumber/internal/ui/theme"
1516 "github.com/rs/zerolog"
1617 )
@@ -38,14 +39,44 @@ type WebKitStack struct {
3839 func BuildWebKitStack(input WebKitStackInput) WebKitStack {
3940 ctx := input.Ctx
4041 cfg := input.Config
41- dataDir := input.DataDir
42- cacheDir := input.CacheDir
43- themeManager := input.ThemeManager
44- colorResolver := input.ColorResolver
4542 logger := input.Logger
46- // Detect hardware for performance profile scaling
43+
44+ perfSettings := surveyHardwareAndResolveProfile(ctx, cfg, logger)
45+
46+ configureRenderingEnvironment(ctx, cfg, &perfSettings, logger)
47+ logging.Trace().Mark("render_env")
48+
49+ wkOpts := buildWebKitContextOptions(input.DataDir, input.CacheDir, &perfSettings)
50+ wkCtx, err := webkit.NewWebKitContextWithOptions(ctx, wkOpts)
51+ if err != nil {
52+ logger.Fatal().Err(err).Msg("failed to initialize WebKit context")
53+ }
54+ logging.Trace().Mark("webkit_context")
55+
56+ filterManager := initFilterManager(ctx, cfg, input.DataDir, logger)
57+
58+ schemeHandler := webkit.NewDumbSchemeHandler(ctx)
59+ schemeHandler.SetAssets(assets.WebUIAssets)
60+ schemeHandler.RegisterWithContext(wkCtx)
61+
62+ settings, injector, messageRouter := initWebKitComponents(ctx, cfg, input.ThemeManager, input.ColorResolver, logger)
63+
64+ pool := initWebViewPool(ctx, wkCtx, settings, injector, messageRouter, input.ThemeManager, filterManager, &perfSettings, logger)
65+
66+ return WebKitStack{
67+ Context: wkCtx,
68+ Settings: settings,
69+ Injector: injector,
70+ MessageRouter: messageRouter,
71+ Pool: pool,
72+ FilterManager: filterManager,
73+ }
74+}
75+
76+func surveyHardwareAndResolveProfile(ctx context.Context, cfg *config.Config, logger zerolog.Logger) config.ResolvedPerformanceSettings {
4777 hwSurveyor := env.NewHardwareSurveyor()
4878 hwInfo := hwSurveyor.Survey(ctx)
79+ logging.Trace().Mark("hardware_survey")
4980 logger.Info().
5081 Int("cpu_cores", hwInfo.CPUCores).
5182 Int("cpu_threads", hwInfo.CPUThreads).
@@ -54,8 +85,8 @@ func BuildWebKitStack(input WebKitStackInput) WebKitStack {
5485 Uint64("vram_mb", hwInfo.VRAM/(1024*1024)).
5586 Msg("hardware survey completed")
5687
57- // Resolve performance profile to get actual settings
5888 perfSettings := config.ResolvePerformanceProfile(&cfg.Performance, &hwInfo)
89+ logging.Trace().Mark("performance_profile")
5990 logger.Info().
6091 Str("profile", string(cfg.Performance.Profile)).
6192 Int("skia_cpu_threads", perfSettings.SkiaCPUPaintingThreads).
@@ -63,17 +94,16 @@ func BuildWebKitStack(input WebKitStackInput) WebKitStack {
6394 Int("webview_pool_prewarm", perfSettings.WebViewPoolPrewarmCount).
6495 Msg("resolved performance profile")
6596
66- // Configure rendering environment (must happen before WebKit/GTK init)
67- configureRenderingEnvironment(ctx, cfg, &perfSettings, logger)
97+ return perfSettings
98+}
6899
69- // Build WebKitContext options with memory pressure settings
100+func buildWebKitContextOptions(dataDir, cacheDir string, perfSettings *config.ResolvedPerformanceSettings) port.WebKitContextOptions {
70101 wkOpts := port.WebKitContextOptions{
71102 DataDir: dataDir,
72103 CacheDir: cacheDir,
73104 }
74105
75- // Configure web process memory pressure if any setting is configured
76- if hasWebProcessMemoryConfig(&perfSettings) {
106+ if hasWebProcessMemoryConfig(perfSettings) {
77107 wkOpts.WebProcessMemory = &port.MemoryPressureConfig{
78108 MemoryLimitMB: perfSettings.WebProcessMemoryLimitMB,
79109 PollIntervalSec: perfSettings.WebProcessMemoryPollIntervalSec,
@@ -82,8 +112,7 @@ func BuildWebKitStack(input WebKitStackInput) WebKitStack {
82112 }
83113 }
84114
85- // Configure network process memory pressure if any setting is configured
86- if hasNetworkProcessMemoryConfig(&perfSettings) {
115+ if hasNetworkProcessMemoryConfig(perfSettings) {
87116 wkOpts.NetworkProcessMemory = &port.MemoryPressureConfig{
88117 MemoryLimitMB: perfSettings.NetworkProcessMemoryLimitMB,
89118 PollIntervalSec: perfSettings.NetworkProcessMemoryPollIntervalSec,
@@ -92,11 +121,10 @@ func BuildWebKitStack(input WebKitStackInput) WebKitStack {
92121 }
93122 }
94123
95- wkCtx, err := webkit.NewWebKitContextWithOptions(ctx, wkOpts)
96- if err != nil {
97- logger.Fatal().Err(err).Msg("failed to initialize WebKit context")
98- }
124+ return wkOpts
125+}
99126
127+func initFilterManager(ctx context.Context, cfg *config.Config, dataDir string, logger zerolog.Logger) *filtering.Manager {
100128 filterStoreDir := filepath.Join(dataDir, "filters", "store")
101129 filterJSONDir := filepath.Join(dataDir, "filters", "json")
102130 filterManager, err := filtering.NewManager(filtering.ManagerConfig{
@@ -107,20 +135,25 @@ func BuildWebKitStack(input WebKitStackInput) WebKitStack {
107135 })
108136 if err != nil {
109137 logger.Warn().Err(err).Msg("failed to create filter manager, continuing without content filtering")
110- } else {
111- if err := filterManager.Initialize(ctx); err != nil {
112- logger.Warn().Err(err).Msg("failed to initialize filters, will load async")
113- }
138+ return nil
114139 }
140+ if err := filterManager.Initialize(ctx); err != nil {
141+ logger.Warn().Err(err).Msg("failed to initialize filters, will load async")
142+ }
143+ logging.Trace().Mark("filter_manager")
144+ return filterManager
145+}
115146
116- schemeHandler := webkit.NewDumbSchemeHandler(ctx)
117- schemeHandler.SetAssets(assets.WebUIAssets)
118- schemeHandler.RegisterWithContext(wkCtx)
119-
147+func initWebKitComponents(
148+ ctx context.Context,
149+ cfg *config.Config,
150+ themeManager *theme.Manager,
151+ colorResolver port.ColorSchemeResolver,
152+ logger zerolog.Logger,
153+) (*webkit.SettingsManager, *webkit.ContentInjector, *webkit.MessageRouter) {
120154 settings := webkit.NewSettingsManager(ctx, cfg)
121155 injector := webkit.NewContentInjector(colorResolver)
122156
123- // Set up auto-copy on selection config getter
124157 injector.SetAutoCopyConfigGetter(func() bool {
125158 return config.Get().Clipboard.AutoCopyOnSelection
126159 })
@@ -132,13 +165,28 @@ func BuildWebKitStack(input WebKitStackInput) WebKitStack {
132165 }
133166
134167 messageRouter := webkit.NewMessageRouter(ctx)
168+ logging.Trace().Mark("settings_manager")
169+
170+ return settings, injector, messageRouter
171+}
172+
173+func initWebViewPool(
174+ ctx context.Context,
175+ wkCtx *webkit.WebKitContext,
176+ settings *webkit.SettingsManager,
177+ injector *webkit.ContentInjector,
178+ messageRouter *webkit.MessageRouter,
179+ themeManager *theme.Manager,
180+ filterManager *filtering.Manager,
181+ perfSettings *config.ResolvedPerformanceSettings,
182+ logger zerolog.Logger,
183+) *webkit.WebViewPool {
135184 poolCfg := webkit.DefaultPoolConfig()
136- // Override prewarm count from resolved profile settings
137185 if perfSettings.WebViewPoolPrewarmCount > 0 {
138186 poolCfg.PrewarmCount = perfSettings.WebViewPoolPrewarmCount
139187 }
140188 pool := webkit.NewWebViewPool(ctx, wkCtx, settings, poolCfg, injector, messageRouter)
141- // Ensure prewarmed WebViews pick up the theme background color.
189+
142190 bgR, bgG, bgB, bgA := themeManager.GetBackgroundRGBA()
143191 pool.SetBackgroundColor(bgR, bgG, bgB, bgA)
144192
@@ -146,21 +194,12 @@ func BuildWebKitStack(input WebKitStackInput) WebKitStack {
146194 pool.SetFilterApplier(filterManager)
147195 }
148196
149- // Pre-create ONE WebView synchronously for instant first navigation.
150- // This is the heaviest operation but happens before window is shown,
151- // so users perceive it as part of the normal "loading" phase.
152197 if err := pool.PrewarmFirst(ctx); err != nil {
153198 logger.Warn().Err(err).Msg("failed to prewarm first webview, first tab may be slower")
154199 }
200+ logging.Trace().Mark("pool_prewarm_first")
155201
156- return WebKitStack{
157- Context: wkCtx,
158- Settings: settings,
159- Injector: injector,
160- MessageRouter: messageRouter,
161- Pool: pool,
162- FilterManager: filterManager,
163- }
202+ return pool
164203 }
165204
166205 // hasWebProcessMemoryConfig returns true if any web process memory setting is configured.
@@ -187,6 +226,12 @@ func configureRenderingEnvironment(
187226 perfSettings *config.ResolvedPerformanceSettings,
188227 logger zerolog.Logger,
189228 ) {
229+ // Install GLib log handler FIRST if configured (must be before any GTK/GLib calls)
230+ if cfg.Logging.CaptureGTKLogs {
231+ enableDebug := cfg.Logging.Level == "debug" || cfg.Logging.Level == "trace"
232+ logging.InstallGLibLogHandler(ctx, logger, enableDebug)
233+ }
234+
190235 renderEnv := env.NewManager()
191236 gpuVendor := renderEnv.DetectGPUVendor(ctx)
192237 renderSettings := port.RenderingEnvSettings{
@@ -11,6 +11,7 @@ import (
11 "github.com/bnema/dumber/internal/infrastructure/env"11 "github.com/bnema/dumber/internal/infrastructure/env"
12 "github.com/bnema/dumber/internal/infrastructure/filtering"12 "github.com/bnema/dumber/internal/infrastructure/filtering"
13 "github.com/bnema/dumber/internal/infrastructure/webkit"13 "github.com/bnema/dumber/internal/infrastructure/webkit"
14+ "github.com/bnema/dumber/internal/logging"
14 "github.com/bnema/dumber/internal/ui/theme"15 "github.com/bnema/dumber/internal/ui/theme"
15 "github.com/rs/zerolog"16 "github.com/rs/zerolog"
16 )17 )
@@ -38,14 +39,44 @@ type WebKitStack struct {
38 func BuildWebKitStack(input WebKitStackInput) WebKitStack {39 func BuildWebKitStack(input WebKitStackInput) WebKitStack {
39 ctx := input.Ctx40 ctx := input.Ctx
40 cfg := input.Config41 cfg := input.Config
41- dataDir := input.DataDir
42- cacheDir := input.CacheDir
43- themeManager := input.ThemeManager
44- colorResolver := input.ColorResolver
45 logger := input.Logger42 logger := input.Logger
46- // Detect hardware for performance profile scaling43+
44+ perfSettings := surveyHardwareAndResolveProfile(ctx, cfg, logger)
45+
46+ configureRenderingEnvironment(ctx, cfg, &perfSettings, logger)
47+ logging.Trace().Mark("render_env")
48+
49+ wkOpts := buildWebKitContextOptions(input.DataDir, input.CacheDir, &perfSettings)
50+ wkCtx, err := webkit.NewWebKitContextWithOptions(ctx, wkOpts)
51+ if err != nil {
52+ logger.Fatal().Err(err).Msg("failed to initialize WebKit context")
53+ }
54+ logging.Trace().Mark("webkit_context")
55+
56+ filterManager := initFilterManager(ctx, cfg, input.DataDir, logger)
57+
58+ schemeHandler := webkit.NewDumbSchemeHandler(ctx)
59+ schemeHandler.SetAssets(assets.WebUIAssets)
60+ schemeHandler.RegisterWithContext(wkCtx)
61+
62+ settings, injector, messageRouter := initWebKitComponents(ctx, cfg, input.ThemeManager, input.ColorResolver, logger)
63+
64+ pool := initWebViewPool(ctx, wkCtx, settings, injector, messageRouter, input.ThemeManager, filterManager, &perfSettings, logger)
65+
66+ return WebKitStack{
67+ Context: wkCtx,
68+ Settings: settings,
69+ Injector: injector,
70+ MessageRouter: messageRouter,
71+ Pool: pool,
72+ FilterManager: filterManager,
73+ }
74+}
75+
76+func surveyHardwareAndResolveProfile(ctx context.Context, cfg *config.Config, logger zerolog.Logger) config.ResolvedPerformanceSettings {
47 hwSurveyor := env.NewHardwareSurveyor()77 hwSurveyor := env.NewHardwareSurveyor()
48 hwInfo := hwSurveyor.Survey(ctx)78 hwInfo := hwSurveyor.Survey(ctx)
79+ logging.Trace().Mark("hardware_survey")
49 logger.Info().80 logger.Info().
50 Int("cpu_cores", hwInfo.CPUCores).81 Int("cpu_cores", hwInfo.CPUCores).
51 Int("cpu_threads", hwInfo.CPUThreads).82 Int("cpu_threads", hwInfo.CPUThreads).
@@ -54,8 +85,8 @@ func BuildWebKitStack(input WebKitStackInput) WebKitStack {
54 Uint64("vram_mb", hwInfo.VRAM/(1024*1024)).85 Uint64("vram_mb", hwInfo.VRAM/(1024*1024)).
55 Msg("hardware survey completed")86 Msg("hardware survey completed")
56 87
57- // Resolve performance profile to get actual settings
58 perfSettings := config.ResolvePerformanceProfile(&cfg.Performance, &hwInfo)88 perfSettings := config.ResolvePerformanceProfile(&cfg.Performance, &hwInfo)
89+ logging.Trace().Mark("performance_profile")
59 logger.Info().90 logger.Info().
60 Str("profile", string(cfg.Performance.Profile)).91 Str("profile", string(cfg.Performance.Profile)).
61 Int("skia_cpu_threads", perfSettings.SkiaCPUPaintingThreads).92 Int("skia_cpu_threads", perfSettings.SkiaCPUPaintingThreads).
@@ -63,17 +94,16 @@ func BuildWebKitStack(input WebKitStackInput) WebKitStack {
63 Int("webview_pool_prewarm", perfSettings.WebViewPoolPrewarmCount).94 Int("webview_pool_prewarm", perfSettings.WebViewPoolPrewarmCount).
64 Msg("resolved performance profile")95 Msg("resolved performance profile")
65 96
66- // Configure rendering environment (must happen before WebKit/GTK init)97+ return perfSettings
67- configureRenderingEnvironment(ctx, cfg, &perfSettings, logger)98+}
68 99
69- // Build WebKitContext options with memory pressure settings100+func buildWebKitContextOptions(dataDir, cacheDir string, perfSettings *config.ResolvedPerformanceSettings) port.WebKitContextOptions {
70 wkOpts := port.WebKitContextOptions{101 wkOpts := port.WebKitContextOptions{
71 DataDir: dataDir,102 DataDir: dataDir,
72 CacheDir: cacheDir,103 CacheDir: cacheDir,
73 }104 }
74 105
75- // Configure web process memory pressure if any setting is configured106+ if hasWebProcessMemoryConfig(perfSettings) {
76- if hasWebProcessMemoryConfig(&perfSettings) {
77 wkOpts.WebProcessMemory = &port.MemoryPressureConfig{107 wkOpts.WebProcessMemory = &port.MemoryPressureConfig{
78 MemoryLimitMB: perfSettings.WebProcessMemoryLimitMB,108 MemoryLimitMB: perfSettings.WebProcessMemoryLimitMB,
79 PollIntervalSec: perfSettings.WebProcessMemoryPollIntervalSec,109 PollIntervalSec: perfSettings.WebProcessMemoryPollIntervalSec,
@@ -82,8 +112,7 @@ func BuildWebKitStack(input WebKitStackInput) WebKitStack {
82 }112 }
83 }113 }
84 114
85- // Configure network process memory pressure if any setting is configured115+ if hasNetworkProcessMemoryConfig(perfSettings) {
86- if hasNetworkProcessMemoryConfig(&perfSettings) {
87 wkOpts.NetworkProcessMemory = &port.MemoryPressureConfig{116 wkOpts.NetworkProcessMemory = &port.MemoryPressureConfig{
88 MemoryLimitMB: perfSettings.NetworkProcessMemoryLimitMB,117 MemoryLimitMB: perfSettings.NetworkProcessMemoryLimitMB,
89 PollIntervalSec: perfSettings.NetworkProcessMemoryPollIntervalSec,118 PollIntervalSec: perfSettings.NetworkProcessMemoryPollIntervalSec,
@@ -92,11 +121,10 @@ func BuildWebKitStack(input WebKitStackInput) WebKitStack {
92 }121 }
93 }122 }
94 123
95- wkCtx, err := webkit.NewWebKitContextWithOptions(ctx, wkOpts)124+ return wkOpts
96- if err != nil {125+}
97- logger.Fatal().Err(err).Msg("failed to initialize WebKit context")
98- }
99 126
127+func initFilterManager(ctx context.Context, cfg *config.Config, dataDir string, logger zerolog.Logger) *filtering.Manager {
100 filterStoreDir := filepath.Join(dataDir, "filters", "store")128 filterStoreDir := filepath.Join(dataDir, "filters", "store")
101 filterJSONDir := filepath.Join(dataDir, "filters", "json")129 filterJSONDir := filepath.Join(dataDir, "filters", "json")
102 filterManager, err := filtering.NewManager(filtering.ManagerConfig{130 filterManager, err := filtering.NewManager(filtering.ManagerConfig{
@@ -107,20 +135,25 @@ func BuildWebKitStack(input WebKitStackInput) WebKitStack {
107 })135 })
108 if err != nil {136 if err != nil {
109 logger.Warn().Err(err).Msg("failed to create filter manager, continuing without content filtering")137 logger.Warn().Err(err).Msg("failed to create filter manager, continuing without content filtering")
110- } else {138+ return nil
111- if err := filterManager.Initialize(ctx); err != nil {
112- logger.Warn().Err(err).Msg("failed to initialize filters, will load async")
113- }
114 }139 }
140+ if err := filterManager.Initialize(ctx); err != nil {
141+ logger.Warn().Err(err).Msg("failed to initialize filters, will load async")
142+ }
143+ logging.Trace().Mark("filter_manager")
144+ return filterManager
145+}
115 146
116- schemeHandler := webkit.NewDumbSchemeHandler(ctx)147+func initWebKitComponents(
117- schemeHandler.SetAssets(assets.WebUIAssets)148+ ctx context.Context,
118- schemeHandler.RegisterWithContext(wkCtx)149+ cfg *config.Config,
119-150+ themeManager *theme.Manager,
151+ colorResolver port.ColorSchemeResolver,
152+ logger zerolog.Logger,
153+) (*webkit.SettingsManager, *webkit.ContentInjector, *webkit.MessageRouter) {
120 settings := webkit.NewSettingsManager(ctx, cfg)154 settings := webkit.NewSettingsManager(ctx, cfg)
121 injector := webkit.NewContentInjector(colorResolver)155 injector := webkit.NewContentInjector(colorResolver)
122 156
123- // Set up auto-copy on selection config getter
124 injector.SetAutoCopyConfigGetter(func() bool {157 injector.SetAutoCopyConfigGetter(func() bool {
125 return config.Get().Clipboard.AutoCopyOnSelection158 return config.Get().Clipboard.AutoCopyOnSelection
126 })159 })
@@ -132,13 +165,28 @@ func BuildWebKitStack(input WebKitStackInput) WebKitStack {
132 }165 }
133 166
134 messageRouter := webkit.NewMessageRouter(ctx)167 messageRouter := webkit.NewMessageRouter(ctx)
168+ logging.Trace().Mark("settings_manager")
169+
170+ return settings, injector, messageRouter
171+}
172+
173+func initWebViewPool(
174+ ctx context.Context,
175+ wkCtx *webkit.WebKitContext,
176+ settings *webkit.SettingsManager,
177+ injector *webkit.ContentInjector,
178+ messageRouter *webkit.MessageRouter,
179+ themeManager *theme.Manager,
180+ filterManager *filtering.Manager,
181+ perfSettings *config.ResolvedPerformanceSettings,
182+ logger zerolog.Logger,
183+) *webkit.WebViewPool {
135 poolCfg := webkit.DefaultPoolConfig()184 poolCfg := webkit.DefaultPoolConfig()
136- // Override prewarm count from resolved profile settings
137 if perfSettings.WebViewPoolPrewarmCount > 0 {185 if perfSettings.WebViewPoolPrewarmCount > 0 {
138 poolCfg.PrewarmCount = perfSettings.WebViewPoolPrewarmCount186 poolCfg.PrewarmCount = perfSettings.WebViewPoolPrewarmCount
139 }187 }
140 pool := webkit.NewWebViewPool(ctx, wkCtx, settings, poolCfg, injector, messageRouter)188 pool := webkit.NewWebViewPool(ctx, wkCtx, settings, poolCfg, injector, messageRouter)
141- // Ensure prewarmed WebViews pick up the theme background color.189+
142 bgR, bgG, bgB, bgA := themeManager.GetBackgroundRGBA()190 bgR, bgG, bgB, bgA := themeManager.GetBackgroundRGBA()
143 pool.SetBackgroundColor(bgR, bgG, bgB, bgA)191 pool.SetBackgroundColor(bgR, bgG, bgB, bgA)
144 192
@@ -146,21 +194,12 @@ func BuildWebKitStack(input WebKitStackInput) WebKitStack {
146 pool.SetFilterApplier(filterManager)194 pool.SetFilterApplier(filterManager)
147 }195 }
148 196
149- // Pre-create ONE WebView synchronously for instant first navigation.
150- // This is the heaviest operation but happens before window is shown,
151- // so users perceive it as part of the normal "loading" phase.
152 if err := pool.PrewarmFirst(ctx); err != nil {197 if err := pool.PrewarmFirst(ctx); err != nil {
153 logger.Warn().Err(err).Msg("failed to prewarm first webview, first tab may be slower")198 logger.Warn().Err(err).Msg("failed to prewarm first webview, first tab may be slower")
154 }199 }
200+ logging.Trace().Mark("pool_prewarm_first")
155 201
156- return WebKitStack{202+ return pool
157- Context: wkCtx,
158- Settings: settings,
159- Injector: injector,
160- MessageRouter: messageRouter,
161- Pool: pool,
162- FilterManager: filterManager,
163- }
164 }203 }
165 204
166 // hasWebProcessMemoryConfig returns true if any web process memory setting is configured.205 // hasWebProcessMemoryConfig returns true if any web process memory setting is configured.
@@ -187,6 +226,12 @@ func configureRenderingEnvironment(
187 perfSettings *config.ResolvedPerformanceSettings,226 perfSettings *config.ResolvedPerformanceSettings,
188 logger zerolog.Logger,227 logger zerolog.Logger,
189 ) {228 ) {
229+ // Install GLib log handler FIRST if configured (must be before any GTK/GLib calls)
230+ if cfg.Logging.CaptureGTKLogs {
231+ enableDebug := cfg.Logging.Level == "debug" || cfg.Logging.Level == "trace"
232+ logging.InstallGLibLogHandler(ctx, logger, enableDebug)
233+ }
234+
190 renderEnv := env.NewManager()235 renderEnv := env.NewManager()
191 gpuVendor := renderEnv.DetectGPUVendor(ctx)236 gpuVendor := renderEnv.DetectGPUVendor(ctx)
192 renderSettings := port.RenderingEnvSettings{237 renderSettings := port.RenderingEnvSettings{
M internal/infrastructure/config/defaults.go +1 -0
@@ -110,6 +110,7 @@ func DefaultConfig() *Config {
110110 LogDir: getDefaultLogDir(),
111111 EnableFileLog: true,
112112 CaptureConsole: false, // Disabled by default
113+ CaptureGTKLogs: false, // Disabled by default
113114 },
114115 Appearance: AppearanceConfig{
115116 SansFont: "Fira Sans",
@@ -110,6 +110,7 @@ func DefaultConfig() *Config {
110 LogDir: getDefaultLogDir(),110 LogDir: getDefaultLogDir(),
111 EnableFileLog: true,111 EnableFileLog: true,
112 CaptureConsole: false, // Disabled by default112 CaptureConsole: false, // Disabled by default
113+ CaptureGTKLogs: false, // Disabled by default
113 },114 },
114 Appearance: AppearanceConfig{115 Appearance: AppearanceConfig{
115 SansFont: "Fira Sans",116 SansFont: "Fira Sans",
M internal/infrastructure/config/loader.go +1 -0
@@ -397,6 +397,7 @@ func (m *Manager) setLoggingDefaults(defaults *Config) {
397397 m.viper.SetDefault("logging.log_dir", defaults.Logging.LogDir)
398398 m.viper.SetDefault("logging.enable_file_log", defaults.Logging.EnableFileLog)
399399 m.viper.SetDefault("logging.capture_console", defaults.Logging.CaptureConsole)
400+ m.viper.SetDefault("logging.capture_gtk_logs", defaults.Logging.CaptureGTKLogs)
400401 }
401402
402403 func (m *Manager) setDebugDefaults(defaults *Config) {
@@ -397,6 +397,7 @@ func (m *Manager) setLoggingDefaults(defaults *Config) {
397 m.viper.SetDefault("logging.log_dir", defaults.Logging.LogDir)397 m.viper.SetDefault("logging.log_dir", defaults.Logging.LogDir)
398 m.viper.SetDefault("logging.enable_file_log", defaults.Logging.EnableFileLog)398 m.viper.SetDefault("logging.enable_file_log", defaults.Logging.EnableFileLog)
399 m.viper.SetDefault("logging.capture_console", defaults.Logging.CaptureConsole)399 m.viper.SetDefault("logging.capture_console", defaults.Logging.CaptureConsole)
400+ m.viper.SetDefault("logging.capture_gtk_logs", defaults.Logging.CaptureGTKLogs)
400 }401 }
401 402
402 func (m *Manager) setDebugDefaults(defaults *Config) {403 func (m *Manager) setDebugDefaults(defaults *Config) {
M internal/infrastructure/config/schema.go +3 -0
@@ -298,6 +298,9 @@ type LoggingConfig struct {
298298
299299 // Capture browser console to logs
300300 CaptureConsole bool `mapstructure:"capture_console" yaml:"capture_console" toml:"capture_console" json:"capture_console"`
301+
302+ // Capture GTK4/WebKitGTK6 messages to session logs
303+ CaptureGTKLogs bool `mapstructure:"capture_gtk_logs" yaml:"capture_gtk_logs" toml:"capture_gtk_logs" json:"capture_gtk_logs"`
301304 }
302305
303306 // AppearanceConfig holds UI/rendering preferences.
@@ -298,6 +298,9 @@ type LoggingConfig struct {
298 298
299 // Capture browser console to logs299 // Capture browser console to logs
300 CaptureConsole bool `mapstructure:"capture_console" yaml:"capture_console" toml:"capture_console" json:"capture_console"`300 CaptureConsole bool `mapstructure:"capture_console" yaml:"capture_console" toml:"capture_console" json:"capture_console"`
301+
302+ // Capture GTK4/WebKitGTK6 messages to session logs
303+ CaptureGTKLogs bool `mapstructure:"capture_gtk_logs" yaml:"capture_gtk_logs" toml:"capture_gtk_logs" json:"capture_gtk_logs"`
301 }304 }
302 305
303 // AppearanceConfig holds UI/rendering preferences.306 // AppearanceConfig holds UI/rendering preferences.
M internal/infrastructure/persistence/sqlite/history_repo.go +3 -1
@@ -14,6 +14,8 @@ import (
1414 "github.com/bnema/dumber/internal/logging"
1515 )
1616
17+const logURLMaxLen = 60
18+
1719 type historyRepo struct {
1820 queries *sqlc.Queries
1921 }
@@ -25,7 +27,7 @@ func NewHistoryRepository(db *sql.DB) repository.HistoryRepository {
2527
2628 func (r *historyRepo) Save(ctx context.Context, entry *entity.HistoryEntry) error {
2729 log := logging.FromContext(ctx)
28- log.Debug().Str("url", entry.URL).Msg("saving history entry")
30+ log.Debug().Str("url", logging.TruncateURL(entry.URL, logURLMaxLen)).Msg("saving history entry")
2931
3032 return r.queries.UpsertHistory(ctx, sqlc.UpsertHistoryParams{
3133 Url: entry.URL,
@@ -14,6 +14,8 @@ import (
14 "github.com/bnema/dumber/internal/logging"14 "github.com/bnema/dumber/internal/logging"
15 )15 )
16 16
17+const logURLMaxLen = 60
18+
17 type historyRepo struct {19 type historyRepo struct {
18 queries *sqlc.Queries20 queries *sqlc.Queries
19 }21 }
@@ -25,7 +27,7 @@ func NewHistoryRepository(db *sql.DB) repository.HistoryRepository {
25 27
26 func (r *historyRepo) Save(ctx context.Context, entry *entity.HistoryEntry) error {28 func (r *historyRepo) Save(ctx context.Context, entry *entity.HistoryEntry) error {
27 log := logging.FromContext(ctx)29 log := logging.FromContext(ctx)
28- log.Debug().Str("url", entry.URL).Msg("saving history entry")30+ log.Debug().Str("url", logging.TruncateURL(entry.URL, logURLMaxLen)).Msg("saving history entry")
29 31
30 return r.queries.UpsertHistory(ctx, sqlc.UpsertHistoryParams{32 return r.queries.UpsertHistory(ctx, sqlc.UpsertHistoryParams{
31 Url: entry.URL,33 Url: entry.URL,
M internal/infrastructure/snapshot/service.go +17 -0
@@ -19,6 +19,7 @@ type Service struct {
1919 mu sync.Mutex
2020 timer *time.Timer
2121 dirty bool
22+ ready bool // true when session is persisted to DB and snapshots can be saved
2223 ctx context.Context
2324 cancel context.CancelFunc
2425 }
@@ -48,6 +49,15 @@ func (s *Service) Start(ctx context.Context) {
4849 logging.FromContext(ctx).Debug().Dur("interval", s.interval).Msg("snapshot service started")
4950 }
5051
52+// SetReady marks the service as ready to save snapshots.
53+// Call this after the session has been persisted to the database
54+// to avoid FK constraint violations.
55+func (s *Service) SetReady() {
56+ s.mu.Lock()
57+ defer s.mu.Unlock()
58+ s.ready = true
59+}
60+
5161 // Stop stops the service and saves final state.
5262 func (s *Service) Stop(ctx context.Context) error {
5363 s.mu.Lock()
@@ -111,6 +121,13 @@ func (s *Service) SaveNow(ctx context.Context) error {
111121
112122 func (s *Service) saveSnapshot(ctx context.Context) error {
113123 s.mu.Lock()
124+ ready := s.ready
125+ if !ready {
126+ // Don't clear dirty if not ready - keep pending snapshot for later
127+ s.mu.Unlock()
128+ return nil
129+ }
130+ // Only clear dirty when we're actually going to save
114131 s.dirty = false
115132 s.mu.Unlock()
116133
@@ -19,6 +19,7 @@ type Service struct {
19 mu sync.Mutex19 mu sync.Mutex
20 timer *time.Timer20 timer *time.Timer
21 dirty bool21 dirty bool
22+ ready bool // true when session is persisted to DB and snapshots can be saved
22 ctx context.Context23 ctx context.Context
23 cancel context.CancelFunc24 cancel context.CancelFunc
24 }25 }
@@ -48,6 +49,15 @@ func (s *Service) Start(ctx context.Context) {
48 logging.FromContext(ctx).Debug().Dur("interval", s.interval).Msg("snapshot service started")49 logging.FromContext(ctx).Debug().Dur("interval", s.interval).Msg("snapshot service started")
49 }50 }
50 51
52+// SetReady marks the service as ready to save snapshots.
53+// Call this after the session has been persisted to the database
54+// to avoid FK constraint violations.
55+func (s *Service) SetReady() {
56+ s.mu.Lock()
57+ defer s.mu.Unlock()
58+ s.ready = true
59+}
60+
51 // Stop stops the service and saves final state.61 // Stop stops the service and saves final state.
52 func (s *Service) Stop(ctx context.Context) error {62 func (s *Service) Stop(ctx context.Context) error {
53 s.mu.Lock()63 s.mu.Lock()
@@ -111,6 +121,13 @@ func (s *Service) SaveNow(ctx context.Context) error {
111 121
112 func (s *Service) saveSnapshot(ctx context.Context) error {122 func (s *Service) saveSnapshot(ctx context.Context) error {
113 s.mu.Lock()123 s.mu.Lock()
124+ ready := s.ready
125+ if !ready {
126+ // Don't clear dirty if not ready - keep pending snapshot for later
127+ s.mu.Unlock()
128+ return nil
129+ }
130+ // Only clear dirty when we're actually going to save
114 s.dirty = false131 s.dirty = false
115 s.mu.Unlock()132 s.mu.Unlock()
116 133
M internal/infrastructure/webkit/pool.go +2 -1
@@ -312,7 +312,8 @@ func (p *WebViewPool) PrewarmAsync(ctx context.Context, count int) {
312312 schedule()
313313 return false
314314 })
315- glib.IdleAdd(&cb, 0)
315+ // Use LOW priority so initial navigation and other high-priority work runs first
316+ glib.IdleAddFull(glib.PRIORITY_LOW, &cb, 0, nil)
316317 }
317318
318319 schedule()
@@ -312,7 +312,8 @@ func (p *WebViewPool) PrewarmAsync(ctx context.Context, count int) {
312 schedule()312 schedule()
313 return false313 return false
314 })314 })
315- glib.IdleAdd(&cb, 0)315+ // Use LOW priority so initial navigation and other high-priority work runs first
316+ glib.IdleAddFull(glib.PRIORITY_LOW, &cb, 0, nil)
316 }317 }
317 318
318 schedule()319 schedule()
M internal/infrastructure/webkit/webview.go +25 -0
@@ -327,11 +327,20 @@ func NewWebViewWithRelated(ctx context.Context, parent *WebView, settings *Setti
327327 return nil, fmt.Errorf("parent webview %d is destroyed", parent.id)
328328 }
329329
330+ log.Debug().
331+ Uint64("parent_ptr", uint64(parent.inner.GoPointer())).
332+ Msg("creating related webview with parent pointer")
333+
330334 inner := webkit.NewWebViewWithRelatedView(parent.inner)
331335 if inner == nil {
332336 return nil, fmt.Errorf("failed to create related webkit webview")
333337 }
334338
339+ log.Debug().
340+ Uint64("new_ptr", uint64(inner.GoPointer())).
341+ Uint64("new_widget_ptr", uint64(inner.Widget.GoPointer())).
342+ Msg("related webview created, checking pointers")
343+
335344 wv := &WebView{
336345 inner: inner,
337346 isRelated: true, // Shares web process with parent - must not terminate process on destroy
@@ -441,11 +450,18 @@ func (wv *WebView) connectCreateSignal() {
441450 ParentID: wv.id,
442451 }
443452
453+ wv.logger.Debug().Msg("create signal: invoking OnCreate handler")
444454 newWV := wv.OnCreate(popupReq)
455+ wv.logger.Debug().Bool("nil", newWV == nil).Msg("create signal: OnCreate returned")
445456 if newWV == nil {
446457 return gtk.Widget{} // Block popup
447458 }
448459
460+ wv.logger.Debug().
461+ Uint64("parent_id", uint64(wv.id)).
462+ Uint64("popup_id", uint64(newWV.id)).
463+ Msg("create signal: returning webview widget to WebKit")
464+
449465 return newWV.inner.Widget
450466 }
451467 sigID := wv.inner.ConnectCreate(&createCb)
@@ -889,6 +905,15 @@ func (wv *WebView) SetBackgroundColor(r, g, b, a float32) {
889905 wv.inner.SetBackgroundColor(rgba)
890906 }
891907
908+// Show makes the WebView widget visible.
909+// This should be called after the WebView is ready to be displayed.
910+func (wv *WebView) Show() {
911+ if wv.destroyed.Load() {
912+ return
913+ }
914+ wv.inner.SetVisible(true)
915+}
916+
892917 // State returns the current WebView state as a snapshot.
893918 func (wv *WebView) State() port.WebViewState {
894919 return port.WebViewState{
@@ -327,11 +327,20 @@ func NewWebViewWithRelated(ctx context.Context, parent *WebView, settings *Setti
327 return nil, fmt.Errorf("parent webview %d is destroyed", parent.id)327 return nil, fmt.Errorf("parent webview %d is destroyed", parent.id)
328 }328 }
329 329
330+ log.Debug().
331+ Uint64("parent_ptr", uint64(parent.inner.GoPointer())).
332+ Msg("creating related webview with parent pointer")
333+
330 inner := webkit.NewWebViewWithRelatedView(parent.inner)334 inner := webkit.NewWebViewWithRelatedView(parent.inner)
331 if inner == nil {335 if inner == nil {
332 return nil, fmt.Errorf("failed to create related webkit webview")336 return nil, fmt.Errorf("failed to create related webkit webview")
333 }337 }
334 338
339+ log.Debug().
340+ Uint64("new_ptr", uint64(inner.GoPointer())).
341+ Uint64("new_widget_ptr", uint64(inner.Widget.GoPointer())).
342+ Msg("related webview created, checking pointers")
343+
335 wv := &WebView{344 wv := &WebView{
336 inner: inner,345 inner: inner,
337 isRelated: true, // Shares web process with parent - must not terminate process on destroy346 isRelated: true, // Shares web process with parent - must not terminate process on destroy
@@ -441,11 +450,18 @@ func (wv *WebView) connectCreateSignal() {
441 ParentID: wv.id,450 ParentID: wv.id,
442 }451 }
443 452
453+ wv.logger.Debug().Msg("create signal: invoking OnCreate handler")
444 newWV := wv.OnCreate(popupReq)454 newWV := wv.OnCreate(popupReq)
455+ wv.logger.Debug().Bool("nil", newWV == nil).Msg("create signal: OnCreate returned")
445 if newWV == nil {456 if newWV == nil {
446 return gtk.Widget{} // Block popup457 return gtk.Widget{} // Block popup
447 }458 }
448 459
460+ wv.logger.Debug().
461+ Uint64("parent_id", uint64(wv.id)).
462+ Uint64("popup_id", uint64(newWV.id)).
463+ Msg("create signal: returning webview widget to WebKit")
464+
449 return newWV.inner.Widget465 return newWV.inner.Widget
450 }466 }
451 sigID := wv.inner.ConnectCreate(&createCb)467 sigID := wv.inner.ConnectCreate(&createCb)
@@ -889,6 +905,15 @@ func (wv *WebView) SetBackgroundColor(r, g, b, a float32) {
889 wv.inner.SetBackgroundColor(rgba)905 wv.inner.SetBackgroundColor(rgba)
890 }906 }
891 907
908+// Show makes the WebView widget visible.
909+// This should be called after the WebView is ready to be displayed.
910+func (wv *WebView) Show() {
911+ if wv.destroyed.Load() {
912+ return
913+ }
914+ wv.inner.SetVisible(true)
915+}
916+
892 // State returns the current WebView state as a snapshot.917 // State returns the current WebView state as a snapshot.
893 func (wv *WebView) State() port.WebViewState {918 func (wv *WebView) State() port.WebViewState {
894 return port.WebViewState{919 return port.WebViewState{
A internal/logging/glib.go +70 -0
@@ -0,0 +1,70 @@
1+package logging
2+
3+import (
4+ "context"
5+ "sync"
6+
7+ "github.com/jwijenbergh/puregotk/v4/glib"
8+ "github.com/rs/zerolog"
9+)
10+
11+// glibLogger holds the logger for the GLib handler.
12+// We need this because the GLib callback doesn't support passing Go pointers directly.
13+var (
14+ glibLogger zerolog.Logger
15+ glibLoggerOnce sync.Once
16+)
17+
18+// InstallGLibLogHandler installs a custom GLib log handler that routes
19+// GTK4/WebKitGTK6/GLib messages to the provided zerolog logger.
20+// This must be called before GTK/WebKit initialization.
21+// The handler captures messages from all GLib-based libraries (GTK, GDK, WebKit, etc.)
22+// If enableDebug is true, GLib debug messages will also be captured (useful when log level is debug/trace).
23+func InstallGLibLogHandler(ctx context.Context, logger zerolog.Logger, enableDebug bool) {
24+ log := FromContext(ctx)
25+
26+ glibLoggerOnce.Do(func() {
27+ glibLogger = logger
28+
29+ // Only enable GLib debug messages if requested (matches app log level)
30+ if enableDebug {
31+ glib.LogSetDebugEnabled(true)
32+ }
33+
34+ // Install our custom handler for all log messages
35+ handler := glib.LogFunc(glibLogHandler)
36+ glib.LogSetDefaultHandler(&handler, 0)
37+
38+ log.Info().Bool("debug_enabled", enableDebug).Msg("GLib log handler installed")
39+ })
40+}
41+
42+// glibLogHandler is the callback invoked by GLib for all log messages.
43+func glibLogHandler(domain string, level glib.LogLevelFlags, message string, _ uintptr) {
44+ // Map GLib log levels to zerolog levels
45+ var event *zerolog.Event
46+
47+ switch {
48+ case level&glib.GLogLevelErrorValue != 0:
49+ event = glibLogger.Error()
50+ case level&glib.GLogLevelCriticalValue != 0:
51+ event = glibLogger.Error()
52+ case level&glib.GLogLevelWarningValue != 0:
53+ event = glibLogger.Warn()
54+ case level&glib.GLogLevelMessageValue != 0:
55+ event = glibLogger.Info()
56+ case level&glib.GLogLevelInfoValue != 0:
57+ event = glibLogger.Info()
58+ case level&glib.GLogLevelDebugValue != 0:
59+ event = glibLogger.Debug()
60+ default:
61+ event = glibLogger.Debug()
62+ }
63+
64+ // Add domain if present
65+ if domain != "" {
66+ event = event.Str("glib_domain", domain)
67+ }
68+
69+ event.Msg(message)
70+}
@@ -0,0 +1,70 @@
1+package logging
2+
3+import (
4+ "context"
5+ "sync"
6+
7+ "github.com/jwijenbergh/puregotk/v4/glib"
8+ "github.com/rs/zerolog"
9+)
10+
11+// glibLogger holds the logger for the GLib handler.
12+// We need this because the GLib callback doesn't support passing Go pointers directly.
13+var (
14+ glibLogger zerolog.Logger
15+ glibLoggerOnce sync.Once
16+)
17+
18+// InstallGLibLogHandler installs a custom GLib log handler that routes
19+// GTK4/WebKitGTK6/GLib messages to the provided zerolog logger.
20+// This must be called before GTK/WebKit initialization.
21+// The handler captures messages from all GLib-based libraries (GTK, GDK, WebKit, etc.)
22+// If enableDebug is true, GLib debug messages will also be captured (useful when log level is debug/trace).
23+func InstallGLibLogHandler(ctx context.Context, logger zerolog.Logger, enableDebug bool) {
24+ log := FromContext(ctx)
25+
26+ glibLoggerOnce.Do(func() {
27+ glibLogger = logger
28+
29+ // Only enable GLib debug messages if requested (matches app log level)
30+ if enableDebug {
31+ glib.LogSetDebugEnabled(true)
32+ }
33+
34+ // Install our custom handler for all log messages
35+ handler := glib.LogFunc(glibLogHandler)
36+ glib.LogSetDefaultHandler(&handler, 0)
37+
38+ log.Info().Bool("debug_enabled", enableDebug).Msg("GLib log handler installed")
39+ })
40+}
41+
42+// glibLogHandler is the callback invoked by GLib for all log messages.
43+func glibLogHandler(domain string, level glib.LogLevelFlags, message string, _ uintptr) {
44+ // Map GLib log levels to zerolog levels
45+ var event *zerolog.Event
46+
47+ switch {
48+ case level&glib.GLogLevelErrorValue != 0:
49+ event = glibLogger.Error()
50+ case level&glib.GLogLevelCriticalValue != 0:
51+ event = glibLogger.Error()
52+ case level&glib.GLogLevelWarningValue != 0:
53+ event = glibLogger.Warn()
54+ case level&glib.GLogLevelMessageValue != 0:
55+ event = glibLogger.Info()
56+ case level&glib.GLogLevelInfoValue != 0:
57+ event = glibLogger.Info()
58+ case level&glib.GLogLevelDebugValue != 0:
59+ event = glibLogger.Debug()
60+ default:
61+ event = glibLogger.Debug()
62+ }
63+
64+ // Add domain if present
65+ if domain != "" {
66+ event = event.Str("glib_domain", domain)
67+ }
68+
69+ event.Msg(message)
70+}
M internal/logging/logger.go +8 -0
@@ -189,3 +189,11 @@ func ParseLevel(level string) zerolog.Level {
189189 return zerolog.InfoLevel
190190 }
191191 }
192+
193+// TruncateURL truncates a URL to maxLen characters for logging.
194+func TruncateURL(url string, maxLen int) string {
195+ if len(url) <= maxLen {
196+ return url
197+ }
198+ return url[:maxLen] + "..."
199+}
@@ -189,3 +189,11 @@ func ParseLevel(level string) zerolog.Level {
189 return zerolog.InfoLevel189 return zerolog.InfoLevel
190 }190 }
191 }191 }
192+
193+// TruncateURL truncates a URL to maxLen characters for logging.
194+func TruncateURL(url string, maxLen int) string {
195+ if len(url) <= maxLen {
196+ return url
197+ }
198+ return url[:maxLen] + "..."
199+}
A internal/logging/startup_trace.go +220 -0
@@ -0,0 +1,220 @@
1+package logging
2+
3+import (
4+ "fmt"
5+ "strings"
6+ "sync"
7+ "time"
8+
9+ "github.com/rs/zerolog"
10+)
11+
12+// StartupTrace tracks cold start milestones from process launch to first paint.
13+// Thread-safe for use across goroutines.
14+// Enabled only when log level is debug or trace.
15+type StartupTrace struct {
16+ mu sync.Mutex
17+ t0 time.Time
18+ milestones []Milestone
19+ enabled bool
20+ logger *zerolog.Logger
21+ buffered []Milestone // milestones recorded before logger is set
22+ finished bool
23+}
24+
25+// Milestone represents a timing checkpoint during startup.
26+type Milestone struct {
27+ Name string
28+ Elapsed time.Duration // time since t0
29+ Delta time.Duration // time since previous milestone
30+}
31+
32+var (
33+ globalTrace *StartupTrace
34+ globalTraceMu sync.Mutex
35+ globalTraceOnce sync.Once
36+)
37+
38+// InitStartupTrace initializes the global startup trace.
39+// Call this as early as possible in main() to capture T0.
40+// The trace is enabled only if the given log level is debug or trace.
41+func InitStartupTrace(logLevel string) {
42+ globalTraceOnce.Do(func() {
43+ enabled := logLevel == "debug" || logLevel == "trace"
44+ globalTraceMu.Lock()
45+ globalTrace = &StartupTrace{
46+ t0: time.Now(),
47+ milestones: make([]Milestone, 0, 32),
48+ enabled: enabled,
49+ buffered: make([]Milestone, 0, 8),
50+ }
51+ globalTraceMu.Unlock()
52+
53+ if enabled {
54+ // Record process_start as first milestone
55+ globalTrace.Mark("process_start")
56+ }
57+ })
58+}
59+
60+// Trace returns the global startup trace instance.
61+// Returns a no-op trace if not initialized or disabled.
62+func Trace() *StartupTrace {
63+ globalTraceMu.Lock()
64+ defer globalTraceMu.Unlock()
65+ if globalTrace == nil {
66+ // Return a disabled no-op trace
67+ return &StartupTrace{enabled: false}
68+ }
69+ return globalTrace
70+}
71+
72+// SetLogger sets the logger for emitting milestone logs.
73+// Flushes any buffered milestones that were recorded before the logger was set.
74+func (st *StartupTrace) SetLogger(logger *zerolog.Logger) {
75+ if st == nil || !st.enabled {
76+ return
77+ }
78+
79+ st.mu.Lock()
80+ defer st.mu.Unlock()
81+
82+ st.logger = logger
83+
84+ // Flush buffered milestones
85+ for _, m := range st.buffered {
86+ st.emitMilestone(m)
87+ }
88+ st.buffered = nil
89+}
90+
91+// UpdateLogger updates the logger and re-emits all milestones to the new logger.
92+// Call this after the session file logger is available to capture milestones in the log file.
93+func (st *StartupTrace) UpdateLogger(logger *zerolog.Logger) {
94+ if st == nil || !st.enabled {
95+ return
96+ }
97+
98+ st.mu.Lock()
99+ defer st.mu.Unlock()
100+
101+ st.logger = logger
102+
103+ // Re-emit all milestones to the new logger
104+ for _, m := range st.milestones {
105+ st.emitMilestone(m)
106+ }
107+}
108+
109+// Mark records a milestone with the given name.
110+// Emits a debug log line showing elapsed time and delta from previous milestone.
111+func (st *StartupTrace) Mark(name string) {
112+ if st == nil || !st.enabled {
113+ return
114+ }
115+
116+ st.mu.Lock()
117+ defer st.mu.Unlock()
118+
119+ if st.finished {
120+ return
121+ }
122+
123+ now := time.Now()
124+ elapsed := now.Sub(st.t0)
125+
126+ var delta time.Duration
127+ if len(st.milestones) > 0 {
128+ delta = elapsed - st.milestones[len(st.milestones)-1].Elapsed
129+ }
130+
131+ m := Milestone{
132+ Name: name,
133+ Elapsed: elapsed,
134+ Delta: delta,
135+ }
136+ st.milestones = append(st.milestones, m)
137+
138+ if st.logger != nil {
139+ st.emitMilestone(m)
140+ } else {
141+ // Buffer until logger is set
142+ st.buffered = append(st.buffered, m)
143+ }
144+}
145+
146+// emitMilestone logs a single milestone. Caller must hold mutex.
147+func (st *StartupTrace) emitMilestone(m Milestone) {
148+ if st.logger == nil {
149+ return
150+ }
151+
152+ elapsedMs := m.Elapsed.Milliseconds()
153+
154+ event := st.logger.Debug().
155+ Str("milestone", m.Name).
156+ Int64("t_ms", elapsedMs)
157+
158+ if m.Delta > 0 {
159+ event = event.Int64("delta_ms", m.Delta.Milliseconds())
160+ }
161+
162+ // Format: startup_trace: milestone_name (T+123ms, +45ms)
163+ if m.Delta > 0 {
164+ event.Msgf("startup_trace: %s (T+%dms, +%dms)", m.Name, elapsedMs, m.Delta.Milliseconds())
165+ } else {
166+ event.Msgf("startup_trace: %s (T+%dms)", m.Name, elapsedMs)
167+ }
168+}
169+
170+// Finish marks the startup trace as complete and emits a summary.
171+// Called on first_paint milestone.
172+func (st *StartupTrace) Finish() {
173+ if st == nil || !st.enabled {
174+ return
175+ }
176+
177+ st.mu.Lock()
178+ defer st.mu.Unlock()
179+
180+ if st.finished {
181+ return
182+ }
183+ st.finished = true
184+
185+ if st.logger == nil {
186+ return
187+ }
188+
189+ // Build summary string
190+ total := time.Since(st.t0)
191+ var parts []string
192+ for _, m := range st.milestones {
193+ parts = append(parts, fmt.Sprintf("%s:%d", m.Name, m.Elapsed.Milliseconds()))
194+ }
195+ summary := strings.Join(parts, ",")
196+
197+ st.logger.Info().
198+ Int64("total_ms", total.Milliseconds()).
199+ Str("milestones", summary).
200+ Msg("startup_trace: cold start complete")
201+}
202+
203+// Enabled returns whether the trace is active.
204+func (st *StartupTrace) Enabled() bool {
205+ if st == nil {
206+ return false
207+ }
208+ return st.enabled
209+}
210+
211+// TotalElapsed returns the total time since T0.
212+func (st *StartupTrace) TotalElapsed() time.Duration {
213+ if st == nil || !st.enabled {
214+ return 0
215+ }
216+
217+ st.mu.Lock()
218+ defer st.mu.Unlock()
219+ return time.Since(st.t0)
220+}
@@ -0,0 +1,220 @@
1+package logging
2+
3+import (
4+ "fmt"
5+ "strings"
6+ "sync"
7+ "time"
8+
9+ "github.com/rs/zerolog"
10+)
11+
12+// StartupTrace tracks cold start milestones from process launch to first paint.
13+// Thread-safe for use across goroutines.
14+// Enabled only when log level is debug or trace.
15+type StartupTrace struct {
16+ mu sync.Mutex
17+ t0 time.Time
18+ milestones []Milestone
19+ enabled bool
20+ logger *zerolog.Logger
21+ buffered []Milestone // milestones recorded before logger is set
22+ finished bool
23+}
24+
25+// Milestone represents a timing checkpoint during startup.
26+type Milestone struct {
27+ Name string
28+ Elapsed time.Duration // time since t0
29+ Delta time.Duration // time since previous milestone
30+}
31+
32+var (
33+ globalTrace *StartupTrace
34+ globalTraceMu sync.Mutex
35+ globalTraceOnce sync.Once
36+)
37+
38+// InitStartupTrace initializes the global startup trace.
39+// Call this as early as possible in main() to capture T0.
40+// The trace is enabled only if the given log level is debug or trace.
41+func InitStartupTrace(logLevel string) {
42+ globalTraceOnce.Do(func() {
43+ enabled := logLevel == "debug" || logLevel == "trace"
44+ globalTraceMu.Lock()
45+ globalTrace = &StartupTrace{
46+ t0: time.Now(),
47+ milestones: make([]Milestone, 0, 32),
48+ enabled: enabled,
49+ buffered: make([]Milestone, 0, 8),
50+ }
51+ globalTraceMu.Unlock()
52+
53+ if enabled {
54+ // Record process_start as first milestone
55+ globalTrace.Mark("process_start")
56+ }
57+ })
58+}
59+
60+// Trace returns the global startup trace instance.
61+// Returns a no-op trace if not initialized or disabled.
62+func Trace() *StartupTrace {
63+ globalTraceMu.Lock()
64+ defer globalTraceMu.Unlock()
65+ if globalTrace == nil {
66+ // Return a disabled no-op trace
67+ return &StartupTrace{enabled: false}
68+ }
69+ return globalTrace
70+}
71+
72+// SetLogger sets the logger for emitting milestone logs.
73+// Flushes any buffered milestones that were recorded before the logger was set.
74+func (st *StartupTrace) SetLogger(logger *zerolog.Logger) {
75+ if st == nil || !st.enabled {
76+ return
77+ }
78+
79+ st.mu.Lock()
80+ defer st.mu.Unlock()
81+
82+ st.logger = logger
83+
84+ // Flush buffered milestones
85+ for _, m := range st.buffered {
86+ st.emitMilestone(m)
87+ }
88+ st.buffered = nil
89+}
90+
91+// UpdateLogger updates the logger and re-emits all milestones to the new logger.
92+// Call this after the session file logger is available to capture milestones in the log file.
93+func (st *StartupTrace) UpdateLogger(logger *zerolog.Logger) {
94+ if st == nil || !st.enabled {
95+ return
96+ }
97+
98+ st.mu.Lock()
99+ defer st.mu.Unlock()
100+
101+ st.logger = logger
102+
103+ // Re-emit all milestones to the new logger
104+ for _, m := range st.milestones {
105+ st.emitMilestone(m)
106+ }
107+}
108+
109+// Mark records a milestone with the given name.
110+// Emits a debug log line showing elapsed time and delta from previous milestone.
111+func (st *StartupTrace) Mark(name string) {
112+ if st == nil || !st.enabled {
113+ return
114+ }
115+
116+ st.mu.Lock()
117+ defer st.mu.Unlock()
118+
119+ if st.finished {
120+ return
121+ }
122+
123+ now := time.Now()
124+ elapsed := now.Sub(st.t0)
125+
126+ var delta time.Duration
127+ if len(st.milestones) > 0 {
128+ delta = elapsed - st.milestones[len(st.milestones)-1].Elapsed
129+ }
130+
131+ m := Milestone{
132+ Name: name,
133+ Elapsed: elapsed,
134+ Delta: delta,
135+ }
136+ st.milestones = append(st.milestones, m)
137+
138+ if st.logger != nil {
139+ st.emitMilestone(m)
140+ } else {
141+ // Buffer until logger is set
142+ st.buffered = append(st.buffered, m)
143+ }
144+}
145+
146+// emitMilestone logs a single milestone. Caller must hold mutex.
147+func (st *StartupTrace) emitMilestone(m Milestone) {
148+ if st.logger == nil {
149+ return
150+ }
151+
152+ elapsedMs := m.Elapsed.Milliseconds()
153+
154+ event := st.logger.Debug().
155+ Str("milestone", m.Name).
156+ Int64("t_ms", elapsedMs)
157+
158+ if m.Delta > 0 {
159+ event = event.Int64("delta_ms", m.Delta.Milliseconds())
160+ }
161+
162+ // Format: startup_trace: milestone_name (T+123ms, +45ms)
163+ if m.Delta > 0 {
164+ event.Msgf("startup_trace: %s (T+%dms, +%dms)", m.Name, elapsedMs, m.Delta.Milliseconds())
165+ } else {
166+ event.Msgf("startup_trace: %s (T+%dms)", m.Name, elapsedMs)
167+ }
168+}
169+
170+// Finish marks the startup trace as complete and emits a summary.
171+// Called on first_paint milestone.
172+func (st *StartupTrace) Finish() {
173+ if st == nil || !st.enabled {
174+ return
175+ }
176+
177+ st.mu.Lock()
178+ defer st.mu.Unlock()
179+
180+ if st.finished {
181+ return
182+ }
183+ st.finished = true
184+
185+ if st.logger == nil {
186+ return
187+ }
188+
189+ // Build summary string
190+ total := time.Since(st.t0)
191+ var parts []string
192+ for _, m := range st.milestones {
193+ parts = append(parts, fmt.Sprintf("%s:%d", m.Name, m.Elapsed.Milliseconds()))
194+ }
195+ summary := strings.Join(parts, ",")
196+
197+ st.logger.Info().
198+ Int64("total_ms", total.Milliseconds()).
199+ Str("milestones", summary).
200+ Msg("startup_trace: cold start complete")
201+}
202+
203+// Enabled returns whether the trace is active.
204+func (st *StartupTrace) Enabled() bool {
205+ if st == nil {
206+ return false
207+ }
208+ return st.enabled
209+}
210+
211+// TotalElapsed returns the total time since T0.
212+func (st *StartupTrace) TotalElapsed() time.Duration {
213+ if st == nil || !st.enabled {
214+ return 0
215+ }
216+
217+ st.mu.Lock()
218+ defer st.mu.Unlock()
219+ return time.Since(st.t0)
220+}
M internal/ui/app.go +52 -14
@@ -115,6 +115,10 @@ type App struct {
115115 insertAccentUC *usecase.InsertAccentUseCase
116116 accentFocusProvider *textinput.FocusProvider
117117
118+ // Deferred initialization - runs after first load_started to avoid blocking initial navigation
119+ deferredInitOnce sync.Once
120+ deferredInitFn func()
121+
118122 // lifecycle
119123 cancel context.CancelCauseFunc
120124 }
@@ -182,6 +186,7 @@ func (a *App) Run(ctx context.Context, args []string) int {
182186 // Initialize libadwaita once (required before using StyleManager).
183187 // This also initializes GTK implicitly.
184188 adw.Init()
189+ logging.Trace().Mark("gtk_init")
185190
186191 // Mark adwaita detector as available now that adw.Init() is complete.
187192 // This enables the highest-priority color scheme detector.
@@ -203,6 +208,7 @@ func (a *App) Run(ctx context.Context, args []string) int {
203208 return 1
204209 }
205210 defer a.gtkApp.Unref()
211+ logging.Trace().Mark("gtk_app_created")
206212
207213 // Connect activate signal
208214 activateCb := func(_ gio.Application) {
@@ -236,6 +242,7 @@ func (a *App) onActivate(ctx context.Context) {
236242 log.Error().Err(err).Msg("failed to create main window")
237243 return
238244 }
245+ logging.Trace().Mark("window_created")
239246
240247 a.initLayoutInfrastructure()
241248 a.initAppToasterOverlay()
@@ -244,6 +251,7 @@ func (a *App) onActivate(ctx context.Context) {
244251 a.initDownloadHandler(ctx)
245252
246253 a.initCoordinators(ctx)
254+ logging.Trace().Mark("coordinators_init")
247255 a.initKeyboardHandler(ctx)
248256 a.initOmniboxConfig(ctx)
249257 a.initFindBarConfig()
@@ -252,8 +260,6 @@ func (a *App) onActivate(ctx context.Context) {
252260 a.initSnapshotService(ctx)
253261 a.initUpdateCoordinator(ctx)
254262 a.createInitialTab(ctx)
255- // Prewarm the remaining WebViews after the initial tab starts loading.
256- a.prewarmWebViewPoolAsync(ctx)
257263 a.finalizeActivation(ctx)
258264 }
259265
@@ -1016,6 +1022,11 @@ func (a *App) initSnapshotService(ctx context.Context) {
10161022 a.snapshotService = snapshot.NewService(a.deps.SnapshotUC, a, intervalMs)
10171023 a.snapshotService.Start(ctx)
10181024
1025+ // Set up callback for main.go to notify when session is persisted
1026+ a.deps.OnSessionPersisted = func() {
1027+ a.snapshotService.SetReady()
1028+ }
1029+
10191030 log.Debug().Int("interval_ms", intervalMs).Msg("snapshot service started")
10201031 }
10211032
@@ -1149,26 +1160,48 @@ func (a *App) restoreSession(ctx context.Context, sessionID entity.SessionID) er
11491160 func (a *App) finalizeActivation(ctx context.Context) {
11501161 log := logging.FromContext(ctx)
11511162
1152- // Show the window.
1163+ // Show the window
11531164 if a.mainWindow != nil {
11541165 a.mainWindow.Show()
11551166 }
11561167 log.Info().Msg("main window displayed")
11571168
1158- // Start watching config for appearance changes.
1159- a.initConfigWatcher(ctx)
1169+ // Defer non-critical initialization until after first navigation starts.
1170+ // This keeps pool prewarm, config watcher, and filter loading from
1171+ // competing with the initial page load.
1172+ a.runAfterFirstLoadStarted(func() {
1173+ a.prewarmWebViewPoolAsync(ctx)
1174+ a.initConfigWatcher(ctx)
1175+ a.initFilteringAsync(ctx)
1176+ a.checkConfigMigration(ctx)
1177+ })
1178+}
11601179
1161- // Ensure the current appearance config is applied once at startup.
1162- // This avoids the WebUI showing default tokens until the first config change event.
1163- if a.deps != nil {
1164- a.applyAppearanceConfig(ctx, a.deps.Config)
1165- }
1180+// runAfterFirstLoadStarted schedules work to run after the first navigation starts.
1181+// This keeps the GTK main loop free to process the initial load_uri() quickly,
1182+// reducing the gap between webview_attached and load_started.
1183+func (a *App) runAfterFirstLoadStarted(fn func()) {
1184+ a.deferredInitFn = fn
1185+}
11661186
1167- // Start async filter loading after window is visible.
1168- a.initFilteringAsync(ctx)
1187+// triggerDeferredInit is called from ContentCoordinator on first load_started.
1188+// It runs deferred initialization at LOW priority so navigation continues unblocked.
1189+func (a *App) triggerDeferredInit(ctx context.Context) {
1190+ a.deferredInitOnce.Do(func() {
1191+ if a.deferredInitFn == nil {
1192+ return
1193+ }
1194+ log := logging.FromContext(ctx)
1195+ log.Debug().Msg("triggering deferred initialization")
11691196
1170- // Check for config migration after window is visible.
1171- a.checkConfigMigration(ctx)
1197+ fn := a.deferredInitFn
1198+ cb := glib.SourceFunc(func(_ uintptr) bool {
1199+ fn()
1200+ return false
1201+ })
1202+ // Use LOW priority so navigation processing continues first
1203+ glib.IdleAddFull(glib.PRIORITY_LOW, &cb, 0, nil)
1204+ })
11721205 }
11731206
11741207 // onShutdown is called when the GTK application is shutting down.
@@ -1242,6 +1275,11 @@ func (a *App) initCoordinators(ctx context.Context) {
12421275 a.contentCoord.SetIdleInhibitor(a.deps.IdleInhibitor)
12431276 }
12441277
1278+ // Wire deferred init trigger - runs after first navigation starts
1279+ a.contentCoord.SetOnFirstLoadStarted(func() {
1280+ a.triggerDeferredInit(ctx)
1281+ })
1282+
12451283 // 2. Tab Coordinator
12461284 a.tabCoord = coordinator.NewTabCoordinator(ctx, coordinator.TabCoordinatorConfig{
12471285 TabsUC: a.tabsUC,
@@ -115,6 +115,10 @@ type App struct {
115 insertAccentUC *usecase.InsertAccentUseCase115 insertAccentUC *usecase.InsertAccentUseCase
116 accentFocusProvider *textinput.FocusProvider116 accentFocusProvider *textinput.FocusProvider
117 117
118+ // Deferred initialization - runs after first load_started to avoid blocking initial navigation
119+ deferredInitOnce sync.Once
120+ deferredInitFn func()
121+
118 // lifecycle122 // lifecycle
119 cancel context.CancelCauseFunc123 cancel context.CancelCauseFunc
120 }124 }
@@ -182,6 +186,7 @@ func (a *App) Run(ctx context.Context, args []string) int {
182 // Initialize libadwaita once (required before using StyleManager).186 // Initialize libadwaita once (required before using StyleManager).
183 // This also initializes GTK implicitly.187 // This also initializes GTK implicitly.
184 adw.Init()188 adw.Init()
189+ logging.Trace().Mark("gtk_init")
185 190
186 // Mark adwaita detector as available now that adw.Init() is complete.191 // Mark adwaita detector as available now that adw.Init() is complete.
187 // This enables the highest-priority color scheme detector.192 // This enables the highest-priority color scheme detector.
@@ -203,6 +208,7 @@ func (a *App) Run(ctx context.Context, args []string) int {
203 return 1208 return 1
204 }209 }
205 defer a.gtkApp.Unref()210 defer a.gtkApp.Unref()
211+ logging.Trace().Mark("gtk_app_created")
206 212
207 // Connect activate signal213 // Connect activate signal
208 activateCb := func(_ gio.Application) {214 activateCb := func(_ gio.Application) {
@@ -236,6 +242,7 @@ func (a *App) onActivate(ctx context.Context) {
236 log.Error().Err(err).Msg("failed to create main window")242 log.Error().Err(err).Msg("failed to create main window")
237 return243 return
238 }244 }
245+ logging.Trace().Mark("window_created")
239 246
240 a.initLayoutInfrastructure()247 a.initLayoutInfrastructure()
241 a.initAppToasterOverlay()248 a.initAppToasterOverlay()
@@ -244,6 +251,7 @@ func (a *App) onActivate(ctx context.Context) {
244 a.initDownloadHandler(ctx)251 a.initDownloadHandler(ctx)
245 252
246 a.initCoordinators(ctx)253 a.initCoordinators(ctx)
254+ logging.Trace().Mark("coordinators_init")
247 a.initKeyboardHandler(ctx)255 a.initKeyboardHandler(ctx)
248 a.initOmniboxConfig(ctx)256 a.initOmniboxConfig(ctx)
249 a.initFindBarConfig()257 a.initFindBarConfig()
@@ -252,8 +260,6 @@ func (a *App) onActivate(ctx context.Context) {
252 a.initSnapshotService(ctx)260 a.initSnapshotService(ctx)
253 a.initUpdateCoordinator(ctx)261 a.initUpdateCoordinator(ctx)
254 a.createInitialTab(ctx)262 a.createInitialTab(ctx)
255- // Prewarm the remaining WebViews after the initial tab starts loading.
256- a.prewarmWebViewPoolAsync(ctx)
257 a.finalizeActivation(ctx)263 a.finalizeActivation(ctx)
258 }264 }
259 265
@@ -1016,6 +1022,11 @@ func (a *App) initSnapshotService(ctx context.Context) {
1016 a.snapshotService = snapshot.NewService(a.deps.SnapshotUC, a, intervalMs)1022 a.snapshotService = snapshot.NewService(a.deps.SnapshotUC, a, intervalMs)
1017 a.snapshotService.Start(ctx)1023 a.snapshotService.Start(ctx)
1018 1024
1025+ // Set up callback for main.go to notify when session is persisted
1026+ a.deps.OnSessionPersisted = func() {
1027+ a.snapshotService.SetReady()
1028+ }
1029+
1019 log.Debug().Int("interval_ms", intervalMs).Msg("snapshot service started")1030 log.Debug().Int("interval_ms", intervalMs).Msg("snapshot service started")
1020 }1031 }
1021 1032
@@ -1149,26 +1160,48 @@ func (a *App) restoreSession(ctx context.Context, sessionID entity.SessionID) er
1149 func (a *App) finalizeActivation(ctx context.Context) {1160 func (a *App) finalizeActivation(ctx context.Context) {
1150 log := logging.FromContext(ctx)1161 log := logging.FromContext(ctx)
1151 1162
1152- // Show the window.1163+ // Show the window
1153 if a.mainWindow != nil {1164 if a.mainWindow != nil {
1154 a.mainWindow.Show()1165 a.mainWindow.Show()
1155 }1166 }
1156 log.Info().Msg("main window displayed")1167 log.Info().Msg("main window displayed")
1157 1168
1158- // Start watching config for appearance changes.1169+ // Defer non-critical initialization until after first navigation starts.
1159- a.initConfigWatcher(ctx)1170+ // This keeps pool prewarm, config watcher, and filter loading from
1171+ // competing with the initial page load.
1172+ a.runAfterFirstLoadStarted(func() {
1173+ a.prewarmWebViewPoolAsync(ctx)
1174+ a.initConfigWatcher(ctx)
1175+ a.initFilteringAsync(ctx)
1176+ a.checkConfigMigration(ctx)
1177+ })
1178+}
1160 1179
1161- // Ensure the current appearance config is applied once at startup.1180+// runAfterFirstLoadStarted schedules work to run after the first navigation starts.
1162- // This avoids the WebUI showing default tokens until the first config change event.1181+// This keeps the GTK main loop free to process the initial load_uri() quickly,
1163- if a.deps != nil {1182+// reducing the gap between webview_attached and load_started.
1164- a.applyAppearanceConfig(ctx, a.deps.Config)1183+func (a *App) runAfterFirstLoadStarted(fn func()) {
1165- }1184+ a.deferredInitFn = fn
1185+}
1166 1186
1167- // Start async filter loading after window is visible.1187+// triggerDeferredInit is called from ContentCoordinator on first load_started.
1168- a.initFilteringAsync(ctx)1188+// It runs deferred initialization at LOW priority so navigation continues unblocked.
1189+func (a *App) triggerDeferredInit(ctx context.Context) {
1190+ a.deferredInitOnce.Do(func() {
1191+ if a.deferredInitFn == nil {
1192+ return
1193+ }
1194+ log := logging.FromContext(ctx)
1195+ log.Debug().Msg("triggering deferred initialization")
1169 1196
1170- // Check for config migration after window is visible.1197+ fn := a.deferredInitFn
1171- a.checkConfigMigration(ctx)1198+ cb := glib.SourceFunc(func(_ uintptr) bool {
1199+ fn()
1200+ return false
1201+ })
1202+ // Use LOW priority so navigation processing continues first
1203+ glib.IdleAddFull(glib.PRIORITY_LOW, &cb, 0, nil)
1204+ })
1172 }1205 }
1173 1206
1174 // onShutdown is called when the GTK application is shutting down.1207 // onShutdown is called when the GTK application is shutting down.
@@ -1242,6 +1275,11 @@ func (a *App) initCoordinators(ctx context.Context) {
1242 a.contentCoord.SetIdleInhibitor(a.deps.IdleInhibitor)1275 a.contentCoord.SetIdleInhibitor(a.deps.IdleInhibitor)
1243 }1276 }
1244 1277
1278+ // Wire deferred init trigger - runs after first navigation starts
1279+ a.contentCoord.SetOnFirstLoadStarted(func() {
1280+ a.triggerDeferredInit(ctx)
1281+ })
1282+
1245 // 2. Tab Coordinator1283 // 2. Tab Coordinator
1246 a.tabCoord = coordinator.NewTabCoordinator(ctx, coordinator.TabCoordinatorConfig{1284 a.tabCoord = coordinator.NewTabCoordinator(ctx, coordinator.TabCoordinatorConfig{
1247 TabsUC: a.tabsUC,1285 TabsUC: a.tabsUC,
M internal/ui/coordinator/content.go +185 -79
@@ -21,7 +21,10 @@ import (
2121 "github.com/jwijenbergh/puregotk/v4/gdk"
2222 )
2323
24-const aboutBlankURI = "about:blank"
24+const (
25+ aboutBlankURI = "about:blank"
26+ logURLMaxLen = 80
27+)
2528
2629 // ContentCoordinator manages WebView lifecycle, title tracking, and content attachment.
2730 type ContentCoordinator struct {
@@ -95,6 +98,10 @@ type ContentCoordinator struct {
9598
9699 // Callback when WebView gains focus (for accent picker text input targeting)
97100 onWebViewFocused func(paneID entity.PaneID, wv *webkit.WebView)
101+
102+ // Callback for first load_started event (triggers deferred initialization)
103+ onFirstLoadStarted func()
104+ loadStartedOnce sync.Once
98105 }
99106
100107 type pendingThemeUpdate struct {
@@ -173,6 +180,13 @@ func (c *ContentCoordinator) SetOnWebViewFocused(fn func(paneID entity.PaneID, w
173180 c.onWebViewFocused = fn
174181 }
175182
183+// SetOnFirstLoadStarted sets the callback for when the first navigation starts.
184+// This is used to trigger deferred initialization after the initial load_uri()
185+// has been processed by the GTK main loop.
186+func (c *ContentCoordinator) SetOnFirstLoadStarted(fn func()) {
187+ c.onFirstLoadStarted = fn
188+}
189+
176190 // EnsureWebView acquires or reuses a WebView for the given pane.
177191 func (c *ContentCoordinator) EnsureWebView(ctx context.Context, paneID entity.PaneID) (*webkit.WebView, error) {
178192 log := logging.FromContext(ctx)
@@ -185,10 +199,16 @@ func (c *ContentCoordinator) EnsureWebView(ctx context.Context, paneID entity.Pa
185199 return nil, fmt.Errorf("webview pool not configured")
186200 }
187201
202+ // Mark tab_created on first webview (first tab)
203+ if len(c.webViews) == 0 {
204+ logging.Trace().Mark("tab_created")
205+ }
206+
188207 wv, err := c.pool.Acquire(ctx)
189208 if err != nil {
190209 return nil, err
191210 }
211+ logging.Trace().Mark("webview_acquired")
192212
193213 c.webViews[paneID] = wv
194214
@@ -331,6 +351,7 @@ func (c *ContentCoordinator) AttachToWorkspace(ctx context.Context, ws *entity.W
331351 if err := wsView.SetWebViewWidget(pane.ID, widget); err != nil {
332352 log.Warn().Err(err).Str("pane_id", string(pane.ID)).Msg("failed to attach webview widget")
333353 }
354+ logging.Trace().Mark("webview_attached")
334355 }
335356 }
336357
@@ -908,6 +929,7 @@ func (c *ContentCoordinator) PreloadCachedFavicon(ctx context.Context, paneID en
908929 // Also shows the WebView widget (it's hidden during creation to avoid white flash).
909930 func (c *ContentCoordinator) onLoadCommitted(ctx context.Context, paneID entity.PaneID, wv *webkit.WebView) {
910931 log := logging.FromContext(ctx)
932+ logging.Trace().Mark("load_committed")
911933
912934 url := wv.URI()
913935 if url == "" {
@@ -1020,6 +1042,16 @@ func (c *ContentCoordinator) updatePaneURI(paneID entity.PaneID, url string) {
10201042
10211043 // onLoadStarted shows the progress bar when page loading begins.
10221044 func (c *ContentCoordinator) onLoadStarted(paneID entity.PaneID) {
1045+ logging.Trace().Mark("load_started")
1046+
1047+ // Trigger deferred initialization on first load_started.
1048+ // This ensures non-critical init runs after initial navigation starts.
1049+ c.loadStartedOnce.Do(func() {
1050+ if c.onFirstLoadStarted != nil {
1051+ c.onFirstLoadStarted()
1052+ }
1053+ })
1054+
10231055 _, wsView := c.getActiveWS()
10241056 if wsView == nil {
10251057 return
@@ -1106,6 +1138,11 @@ func (c *ContentCoordinator) revealIfPending(ctx context.Context, paneID entity.
11061138 Str("reason", reason).
11071139 Msg("webview revealed")
11081140 }
1141+
1142+ // Mark first_paint and finish startup trace
1143+ logging.Trace().Mark("first_paint")
1144+ logging.Trace().Finish()
1145+
11091146 if c.onWebViewShown != nil {
11101147 c.onWebViewShown(paneID)
11111148 }
@@ -1170,8 +1207,34 @@ func (c *ContentCoordinator) SetupPopupHandling(ctx context.Context, paneID enti
11701207 log.Debug().Str("pane_id", string(paneID)).Msg("popup handling configured for webview")
11711208 }
11721209
1210+// createPopupPane creates a new pane entity for a popup window.
1211+func (c *ContentCoordinator) createPopupPane(
1212+ popupID port.WebViewID,
1213+ parentPaneID entity.PaneID,
1214+ targetURI string,
1215+) (entity.PaneID, *entity.Pane) {
1216+ var paneID entity.PaneID
1217+ if c.generateID != nil {
1218+ paneID = entity.PaneID(c.generateID())
1219+ } else {
1220+ paneID = entity.PaneID(fmt.Sprintf("popup_%d", popupID))
1221+ }
1222+
1223+ popupPane := entity.NewPane(paneID)
1224+ popupPane.WindowType = entity.WindowPopup
1225+ popupPane.IsRelated = true
1226+ popupPane.ParentPaneID = &parentPaneID
1227+ popupPane.URI = targetURI
1228+
1229+ return paneID, popupPane
1230+}
1231+
11731232 // handlePopupCreate handles the WebKit "create" signal for popup windows.
11741233 // Returns a new related WebView if popup is allowed, nil to block.
1234+//
1235+// IMPORTANT: The WebView MUST be added to a GtkWindow hierarchy BEFORE this
1236+// signal handler returns. Otherwise WebKit won't establish window.opener.
1237+// The WebView stays hidden until ready-to-show signal is received.
11751238 func (c *ContentCoordinator) handlePopupCreate(
11761239 ctx context.Context,
11771240 parentPaneID entity.PaneID,
@@ -1199,7 +1262,7 @@ func (c *ContentCoordinator) handlePopupCreate(
11991262 return nil
12001263 }
12011264
1202- // Create related WebView for session sharing
1265+ // Create related WebView for session sharing (created hidden)
12031266 parentID := parentWV.ID()
12041267 popupWV, err := c.factory.CreateRelated(ctx, parentID)
12051268 if err != nil {
@@ -1209,9 +1272,63 @@ func (c *ContentCoordinator) handlePopupCreate(
12091272
12101273 // Detect popup type
12111274 popupType := DetectPopupType(req.FrameName)
1212-
1213- // Store pending popup for ready-to-show handling
12141275 popupID := popupWV.ID()
1276+
1277+ // Determine behavior from config
1278+ behavior := GetBehavior(popupType, c.popupConfig)
1279+ placement := "right"
1280+ if c.popupConfig != nil {
1281+ placement = c.popupConfig.Placement
1282+ }
1283+
1284+ // Create popup pane entity
1285+ paneID, popupPane := c.createPopupPane(popupID, parentPaneID, req.TargetURI)
1286+
1287+ // Check OAuth configuration
1288+ hasConfig := c.popupConfig != nil
1289+ oauthEnabled := hasConfig && c.popupConfig.OAuthAutoClose
1290+ isOAuth := IsOAuthURL(req.TargetURI)
1291+ log.Debug().
1292+ Bool("has_config", hasConfig).
1293+ Bool("oauth_enabled", oauthEnabled).
1294+ Bool("is_oauth", isOAuth).
1295+ Str("uri", logging.TruncateURL(req.TargetURI, logURLMaxLen)).
1296+ Msg("popup OAuth check")
1297+
1298+ // Insert into workspace IMMEDIATELY (WebView stays hidden)
1299+ // This is required for WebKit to establish window.opener relationship
1300+ if c.onInsertPopup != nil {
1301+ popupInput := InsertPopupInput{
1302+ ParentPaneID: parentPaneID,
1303+ PopupPane: popupPane,
1304+ WebView: popupWV,
1305+ Behavior: behavior,
1306+ Placement: placement,
1307+ PopupType: popupType,
1308+ TargetURI: req.TargetURI,
1309+ }
1310+
1311+ if err := c.onInsertPopup(ctx, popupInput); err != nil {
1312+ log.Error().Err(err).Msg("failed to insert popup into workspace")
1313+ popupWV.Destroy()
1314+ return nil
1315+ }
1316+ }
1317+
1318+ // Register WebView in our map (after successful insertion)
1319+ c.webViews[paneID] = popupWV
1320+
1321+ // Setup standard callbacks (after successful insertion to avoid leak)
1322+ c.setupWebViewCallbacks(ctx, paneID, popupWV)
1323+
1324+ // Setup OAuth auto-close if configured
1325+ if hasConfig && oauthEnabled && isOAuth {
1326+ popupPane.AutoClose = true
1327+ c.setupOAuthAutoClose(ctx, paneID, popupWV)
1328+ log.Debug().Str("pane_id", string(paneID)).Msg("OAuth auto-close enabled for popup")
1329+ }
1330+
1331+ // Store pending popup for ready-to-show handling (just visibility now)
12151332 pending := &PendingPopup{
12161333 WebView: popupWV,
12171334 ParentPaneID: parentPaneID,
@@ -1227,7 +1344,7 @@ func (c *ContentCoordinator) handlePopupCreate(
12271344 c.pendingPopups[popupID] = pending
12281345 c.popupMu.Unlock()
12291346
1230- // Wire ready-to-show and close signals
1347+ // Wire ready-to-show (now just for visibility) and close signals
12311348 popupWV.OnReadyToShow = func() {
12321349 c.handlePopupReadyToShow(ctx, popupID)
12331350 }
@@ -1237,15 +1354,17 @@ func (c *ContentCoordinator) handlePopupCreate(
12371354
12381355 log.Info().
12391356 Uint64("popup_id", uint64(popupID)).
1357+ Str("pane_id", string(paneID)).
12401358 Str("popup_type", popupType.String()).
1241- Str("target_uri", req.TargetURI).
1242- Msg("popup created, awaiting ready-to-show")
1359+ Str("target_uri", logging.TruncateURL(req.TargetURI, logURLMaxLen)).
1360+ Msg("popup inserted (hidden), awaiting ready-to-show for visibility")
12431361
12441362 return popupWV
12451363 }
12461364
12471365 // handlePopupReadyToShow handles the WebKit "ready-to-show" signal.
1248-// This is called when the popup is configured and ready to be displayed.
1366+// The popup WebView was already inserted into the workspace (hidden) during
1367+// the create signal. This handler just makes it visible.
12491368 func (c *ContentCoordinator) handlePopupReadyToShow(ctx context.Context, popupID port.WebViewID) {
12501369 log := logging.FromContext(ctx)
12511370
@@ -1265,67 +1384,17 @@ func (c *ContentCoordinator) handlePopupReadyToShow(ctx context.Context, popupID
12651384 log.Debug().
12661385 Uint64("popup_id", uint64(popupID)).
12671386 Str("popup_type", pending.PopupType.String()).
1268- Msg("popup ready to show")
1269-
1270- // Determine behavior from config
1271- behavior := GetBehavior(pending.PopupType, c.popupConfig)
1272- placement := "right"
1273- if c.popupConfig != nil {
1274- placement = c.popupConfig.Placement
1275- }
1276-
1277- // Create popup pane entity
1278- var paneID entity.PaneID
1279- if c.generateID != nil {
1280- paneID = entity.PaneID(c.generateID())
1281- } else {
1282- paneID = entity.PaneID(fmt.Sprintf("popup_%d", popupID))
1283- }
1387+ Msg("popup ready to show - making visible")
12841388
1285- popupPane := entity.NewPane(paneID)
1286- popupPane.WindowType = entity.WindowPopup
1287- popupPane.IsRelated = true
1288- popupPane.ParentPaneID = &pending.ParentPaneID
1289- popupPane.URI = pending.TargetURI
1290-
1291- // Enable OAuth auto-close if configured
1292- if c.popupConfig != nil && c.popupConfig.OAuthAutoClose && IsOAuthURL(pending.TargetURI) {
1293- popupPane.AutoClose = true
1294- c.setupOAuthAutoClose(ctx, paneID, pending.WebView)
1295- }
1296-
1297- // Register WebView in our map
1298- c.webViews[paneID] = pending.WebView
1299-
1300- // Setup standard callbacks
1301- c.setupWebViewCallbacks(ctx, paneID, pending.WebView)
1302-
1303- // Request insertion into workspace
1304- if c.onInsertPopup != nil {
1305- popupInput := InsertPopupInput{
1306- ParentPaneID: pending.ParentPaneID,
1307- PopupPane: popupPane,
1308- WebView: pending.WebView,
1309- Behavior: behavior,
1310- Placement: placement,
1311- PopupType: pending.PopupType,
1312- TargetURI: pending.TargetURI,
1313- }
1314-
1315- if err := c.onInsertPopup(ctx, popupInput); err != nil {
1316- log.Error().Err(err).Msg("failed to insert popup into workspace")
1317- // Clean up on failure
1318- delete(c.webViews, paneID)
1319- pending.WebView.Destroy()
1320- return
1321- }
1389+ // Make the WebView visible now that it's ready
1390+ if pending.WebView != nil {
1391+ pending.WebView.Show()
13221392 }
13231393
13241394 log.Info().
1325- Str("pane_id", string(paneID)).
1326- Str("behavior", string(behavior)).
1327- Str("placement", placement).
1328- Msg("popup inserted into workspace")
1395+ Uint64("popup_id", uint64(popupID)).
1396+ Str("target_uri", logging.TruncateURL(pending.TargetURI, logURLMaxLen)).
1397+ Msg("popup now visible")
13291398 }
13301399
13311400 // handlePopupClose handles the WebKit "close" signal for popup windows.
@@ -1426,9 +1495,44 @@ func (c *ContentCoordinator) setupWebViewCallbacks(ctx context.Context, paneID e
14261495 }
14271496
14281497 // setupOAuthAutoClose monitors the popup for OAuth callback URLs and auto-closes.
1498+// It uses URL pattern detection for standard OAuth callbacks (code=, access_token=, etc.)
1499+// For providers using postMessage (like Google Sign-In), we rely on the provider calling
1500+// window.close() which triggers WebKit's close signal.
1501+// A long safety timeout (30s) catches popups that get stuck.
14291502 func (c *ContentCoordinator) setupOAuthAutoClose(ctx context.Context, paneID entity.PaneID, wv *webkit.WebView) {
14301503 log := logging.FromContext(ctx)
14311504
1505+ // Safety timeout - only triggers if popup gets stuck (provider should close via window.close)
1506+ var safetyTimer *time.Timer
1507+ var safetyTimerMu sync.Mutex
1508+ const oauthSafetyTimeout = 30 * time.Second
1509+
1510+ startSafetyTimer := func() {
1511+ safetyTimerMu.Lock()
1512+ defer safetyTimerMu.Unlock()
1513+ if safetyTimer != nil {
1514+ safetyTimer.Stop()
1515+ }
1516+ safetyTimer = time.AfterFunc(oauthSafetyTimeout, func() {
1517+ if wv != nil && !wv.IsDestroyed() {
1518+ log.Warn().Str("pane", string(paneID)).Msg("oauth safety timeout, closing stuck popup")
1519+ wv.Close()
1520+ }
1521+ })
1522+ }
1523+
1524+ cancelSafetyTimer := func() {
1525+ safetyTimerMu.Lock()
1526+ defer safetyTimerMu.Unlock()
1527+ if safetyTimer != nil {
1528+ safetyTimer.Stop()
1529+ safetyTimer = nil
1530+ }
1531+ }
1532+
1533+ // Start safety timer immediately
1534+ startSafetyTimer()
1535+
14321536 // Wrap the existing OnURIChanged to also check for OAuth callbacks
14331537 originalURIChanged := wv.OnURIChanged
14341538 wv.OnURIChanged = func(uri string) {
@@ -1437,39 +1541,32 @@ func (c *ContentCoordinator) setupOAuthAutoClose(ctx context.Context, paneID ent
14371541 originalURIChanged(uri)
14381542 }
14391543
1440- // Check for OAuth callback
1544+ // Check for OAuth callback (URL-based detection)
14411545 if ShouldAutoClose(uri) {
1442- log.Info().
1443- Str("pane_id", string(paneID)).
1444- Str("uri", uri).
1445- Msg("OAuth callback detected, auto-closing popup")
1446-
1447- // Trigger close after a short delay to let the page process
1546+ cancelSafetyTimer()
1547+ log.Info().Str("pane", string(paneID)).Msg("oauth callback detected, closing")
14481548 go func() {
14491549 time.Sleep(500 * time.Millisecond)
14501550 if wv != nil && !wv.IsDestroyed() {
1451- // This will trigger handlePopupClose
14521551 wv.Close()
14531552 }
14541553 }()
14551554 }
14561555 }
14571556
1458- // Also check on load committed for immediate redirects
1557+ // Monitor load events for URL-based detection
14591558 originalLoadChanged := wv.OnLoadChanged
14601559 wv.OnLoadChanged = func(event webkit.LoadEvent) {
14611560 if originalLoadChanged != nil {
14621561 originalLoadChanged(event)
14631562 }
14641563
1564+ // Check URL on commit for immediate detection
14651565 if event == webkit.LoadCommitted {
14661566 uri := wv.URI()
14671567 if ShouldAutoClose(uri) {
1468- log.Info().
1469- Str("pane_id", string(paneID)).
1470- Str("uri", uri).
1471- Msg("OAuth callback detected on load, auto-closing popup")
1472-
1568+ cancelSafetyTimer()
1569+ log.Info().Str("pane", string(paneID)).Msg("oauth callback on load, closing")
14731570 go func() {
14741571 time.Sleep(500 * time.Millisecond)
14751572 if wv != nil && !wv.IsDestroyed() {
@@ -1479,6 +1576,15 @@ func (c *ContentCoordinator) setupOAuthAutoClose(ctx context.Context, paneID ent
14791576 }
14801577 }
14811578 }
1579+
1580+ // Wrap OnClose to cancel safety timer when popup closes normally
1581+ originalOnClose := wv.OnClose
1582+ wv.OnClose = func() {
1583+ cancelSafetyTimer()
1584+ if originalOnClose != nil {
1585+ originalOnClose()
1586+ }
1587+ }
14821588 }
14831589
14841590 // handleLinkMiddleClick handles middle-click / Ctrl+click on links.
@@ -21,7 +21,10 @@ import (
21 "github.com/jwijenbergh/puregotk/v4/gdk"21 "github.com/jwijenbergh/puregotk/v4/gdk"
22 )22 )
23 23
24-const aboutBlankURI = "about:blank"24+const (
25+ aboutBlankURI = "about:blank"
26+ logURLMaxLen = 80
27+)
25 28
26 // ContentCoordinator manages WebView lifecycle, title tracking, and content attachment.29 // ContentCoordinator manages WebView lifecycle, title tracking, and content attachment.
27 type ContentCoordinator struct {30 type ContentCoordinator struct {
@@ -95,6 +98,10 @@ type ContentCoordinator struct {
95 98
96 // Callback when WebView gains focus (for accent picker text input targeting)99 // Callback when WebView gains focus (for accent picker text input targeting)
97 onWebViewFocused func(paneID entity.PaneID, wv *webkit.WebView)100 onWebViewFocused func(paneID entity.PaneID, wv *webkit.WebView)
101+
102+ // Callback for first load_started event (triggers deferred initialization)
103+ onFirstLoadStarted func()
104+ loadStartedOnce sync.Once
98 }105 }
99 106
100 type pendingThemeUpdate struct {107 type pendingThemeUpdate struct {
@@ -173,6 +180,13 @@ func (c *ContentCoordinator) SetOnWebViewFocused(fn func(paneID entity.PaneID, w
173 c.onWebViewFocused = fn180 c.onWebViewFocused = fn
174 }181 }
175 182
183+// SetOnFirstLoadStarted sets the callback for when the first navigation starts.
184+// This is used to trigger deferred initialization after the initial load_uri()
185+// has been processed by the GTK main loop.
186+func (c *ContentCoordinator) SetOnFirstLoadStarted(fn func()) {
187+ c.onFirstLoadStarted = fn
188+}
189+
176 // EnsureWebView acquires or reuses a WebView for the given pane.190 // EnsureWebView acquires or reuses a WebView for the given pane.
177 func (c *ContentCoordinator) EnsureWebView(ctx context.Context, paneID entity.PaneID) (*webkit.WebView, error) {191 func (c *ContentCoordinator) EnsureWebView(ctx context.Context, paneID entity.PaneID) (*webkit.WebView, error) {
178 log := logging.FromContext(ctx)192 log := logging.FromContext(ctx)
@@ -185,10 +199,16 @@ func (c *ContentCoordinator) EnsureWebView(ctx context.Context, paneID entity.Pa
185 return nil, fmt.Errorf("webview pool not configured")199 return nil, fmt.Errorf("webview pool not configured")
186 }200 }
187 201
202+ // Mark tab_created on first webview (first tab)
203+ if len(c.webViews) == 0 {
204+ logging.Trace().Mark("tab_created")
205+ }
206+
188 wv, err := c.pool.Acquire(ctx)207 wv, err := c.pool.Acquire(ctx)
189 if err != nil {208 if err != nil {
190 return nil, err209 return nil, err
191 }210 }
211+ logging.Trace().Mark("webview_acquired")
192 212
193 c.webViews[paneID] = wv213 c.webViews[paneID] = wv
194 214
@@ -331,6 +351,7 @@ func (c *ContentCoordinator) AttachToWorkspace(ctx context.Context, ws *entity.W
331 if err := wsView.SetWebViewWidget(pane.ID, widget); err != nil {351 if err := wsView.SetWebViewWidget(pane.ID, widget); err != nil {
332 log.Warn().Err(err).Str("pane_id", string(pane.ID)).Msg("failed to attach webview widget")352 log.Warn().Err(err).Str("pane_id", string(pane.ID)).Msg("failed to attach webview widget")
333 }353 }
354+ logging.Trace().Mark("webview_attached")
334 }355 }
335 }356 }
336 357
@@ -908,6 +929,7 @@ func (c *ContentCoordinator) PreloadCachedFavicon(ctx context.Context, paneID en
908 // Also shows the WebView widget (it's hidden during creation to avoid white flash).929 // Also shows the WebView widget (it's hidden during creation to avoid white flash).
909 func (c *ContentCoordinator) onLoadCommitted(ctx context.Context, paneID entity.PaneID, wv *webkit.WebView) {930 func (c *ContentCoordinator) onLoadCommitted(ctx context.Context, paneID entity.PaneID, wv *webkit.WebView) {
910 log := logging.FromContext(ctx)931 log := logging.FromContext(ctx)
932+ logging.Trace().Mark("load_committed")
911 933
912 url := wv.URI()934 url := wv.URI()
913 if url == "" {935 if url == "" {
@@ -1020,6 +1042,16 @@ func (c *ContentCoordinator) updatePaneURI(paneID entity.PaneID, url string) {
1020 1042
1021 // onLoadStarted shows the progress bar when page loading begins.1043 // onLoadStarted shows the progress bar when page loading begins.
1022 func (c *ContentCoordinator) onLoadStarted(paneID entity.PaneID) {1044 func (c *ContentCoordinator) onLoadStarted(paneID entity.PaneID) {
1045+ logging.Trace().Mark("load_started")
1046+
1047+ // Trigger deferred initialization on first load_started.
1048+ // This ensures non-critical init runs after initial navigation starts.
1049+ c.loadStartedOnce.Do(func() {
1050+ if c.onFirstLoadStarted != nil {
1051+ c.onFirstLoadStarted()
1052+ }
1053+ })
1054+
1023 _, wsView := c.getActiveWS()1055 _, wsView := c.getActiveWS()
1024 if wsView == nil {1056 if wsView == nil {
1025 return1057 return
@@ -1106,6 +1138,11 @@ func (c *ContentCoordinator) revealIfPending(ctx context.Context, paneID entity.
1106 Str("reason", reason).1138 Str("reason", reason).
1107 Msg("webview revealed")1139 Msg("webview revealed")
1108 }1140 }
1141+
1142+ // Mark first_paint and finish startup trace
1143+ logging.Trace().Mark("first_paint")
1144+ logging.Trace().Finish()
1145+
1109 if c.onWebViewShown != nil {1146 if c.onWebViewShown != nil {
1110 c.onWebViewShown(paneID)1147 c.onWebViewShown(paneID)
1111 }1148 }
@@ -1170,8 +1207,34 @@ func (c *ContentCoordinator) SetupPopupHandling(ctx context.Context, paneID enti
1170 log.Debug().Str("pane_id", string(paneID)).Msg("popup handling configured for webview")1207 log.Debug().Str("pane_id", string(paneID)).Msg("popup handling configured for webview")
1171 }1208 }
1172 1209
1210+// createPopupPane creates a new pane entity for a popup window.
1211+func (c *ContentCoordinator) createPopupPane(
1212+ popupID port.WebViewID,
1213+ parentPaneID entity.PaneID,
1214+ targetURI string,
1215+) (entity.PaneID, *entity.Pane) {
1216+ var paneID entity.PaneID
1217+ if c.generateID != nil {
1218+ paneID = entity.PaneID(c.generateID())
1219+ } else {
1220+ paneID = entity.PaneID(fmt.Sprintf("popup_%d", popupID))
1221+ }
1222+
1223+ popupPane := entity.NewPane(paneID)
1224+ popupPane.WindowType = entity.WindowPopup
1225+ popupPane.IsRelated = true
1226+ popupPane.ParentPaneID = &parentPaneID
1227+ popupPane.URI = targetURI
1228+
1229+ return paneID, popupPane
1230+}
1231+
1173 // handlePopupCreate handles the WebKit "create" signal for popup windows.1232 // handlePopupCreate handles the WebKit "create" signal for popup windows.
1174 // Returns a new related WebView if popup is allowed, nil to block.1233 // Returns a new related WebView if popup is allowed, nil to block.
1234+//
1235+// IMPORTANT: The WebView MUST be added to a GtkWindow hierarchy BEFORE this
1236+// signal handler returns. Otherwise WebKit won't establish window.opener.
1237+// The WebView stays hidden until ready-to-show signal is received.
1175 func (c *ContentCoordinator) handlePopupCreate(1238 func (c *ContentCoordinator) handlePopupCreate(
1176 ctx context.Context,1239 ctx context.Context,
1177 parentPaneID entity.PaneID,1240 parentPaneID entity.PaneID,
@@ -1199,7 +1262,7 @@ func (c *ContentCoordinator) handlePopupCreate(
1199 return nil1262 return nil
1200 }1263 }
1201 1264
1202- // Create related WebView for session sharing1265+ // Create related WebView for session sharing (created hidden)
1203 parentID := parentWV.ID()1266 parentID := parentWV.ID()
1204 popupWV, err := c.factory.CreateRelated(ctx, parentID)1267 popupWV, err := c.factory.CreateRelated(ctx, parentID)
1205 if err != nil {1268 if err != nil {
@@ -1209,9 +1272,63 @@ func (c *ContentCoordinator) handlePopupCreate(
1209 1272
1210 // Detect popup type1273 // Detect popup type
1211 popupType := DetectPopupType(req.FrameName)1274 popupType := DetectPopupType(req.FrameName)
1212-
1213- // Store pending popup for ready-to-show handling
1214 popupID := popupWV.ID()1275 popupID := popupWV.ID()
1276+
1277+ // Determine behavior from config
1278+ behavior := GetBehavior(popupType, c.popupConfig)
1279+ placement := "right"
1280+ if c.popupConfig != nil {
1281+ placement = c.popupConfig.Placement
1282+ }
1283+
1284+ // Create popup pane entity
1285+ paneID, popupPane := c.createPopupPane(popupID, parentPaneID, req.TargetURI)
1286+
1287+ // Check OAuth configuration
1288+ hasConfig := c.popupConfig != nil
1289+ oauthEnabled := hasConfig && c.popupConfig.OAuthAutoClose
1290+ isOAuth := IsOAuthURL(req.TargetURI)
1291+ log.Debug().
1292+ Bool("has_config", hasConfig).
1293+ Bool("oauth_enabled", oauthEnabled).
1294+ Bool("is_oauth", isOAuth).
1295+ Str("uri", logging.TruncateURL(req.TargetURI, logURLMaxLen)).
1296+ Msg("popup OAuth check")
1297+
1298+ // Insert into workspace IMMEDIATELY (WebView stays hidden)
1299+ // This is required for WebKit to establish window.opener relationship
1300+ if c.onInsertPopup != nil {
1301+ popupInput := InsertPopupInput{
1302+ ParentPaneID: parentPaneID,
1303+ PopupPane: popupPane,
1304+ WebView: popupWV,
1305+ Behavior: behavior,
1306+ Placement: placement,
1307+ PopupType: popupType,
1308+ TargetURI: req.TargetURI,
1309+ }
1310+
1311+ if err := c.onInsertPopup(ctx, popupInput); err != nil {
1312+ log.Error().Err(err).Msg("failed to insert popup into workspace")
1313+ popupWV.Destroy()
1314+ return nil
1315+ }
1316+ }
1317+
1318+ // Register WebView in our map (after successful insertion)
1319+ c.webViews[paneID] = popupWV
1320+
1321+ // Setup standard callbacks (after successful insertion to avoid leak)
1322+ c.setupWebViewCallbacks(ctx, paneID, popupWV)
1323+
1324+ // Setup OAuth auto-close if configured
1325+ if hasConfig && oauthEnabled && isOAuth {
1326+ popupPane.AutoClose = true
1327+ c.setupOAuthAutoClose(ctx, paneID, popupWV)
1328+ log.Debug().Str("pane_id", string(paneID)).Msg("OAuth auto-close enabled for popup")
1329+ }
1330+
1331+ // Store pending popup for ready-to-show handling (just visibility now)
1215 pending := &PendingPopup{1332 pending := &PendingPopup{
1216 WebView: popupWV,1333 WebView: popupWV,
1217 ParentPaneID: parentPaneID,1334 ParentPaneID: parentPaneID,
@@ -1227,7 +1344,7 @@ func (c *ContentCoordinator) handlePopupCreate(
1227 c.pendingPopups[popupID] = pending1344 c.pendingPopups[popupID] = pending
1228 c.popupMu.Unlock()1345 c.popupMu.Unlock()
1229 1346
1230- // Wire ready-to-show and close signals1347+ // Wire ready-to-show (now just for visibility) and close signals
1231 popupWV.OnReadyToShow = func() {1348 popupWV.OnReadyToShow = func() {
1232 c.handlePopupReadyToShow(ctx, popupID)1349 c.handlePopupReadyToShow(ctx, popupID)
1233 }1350 }
@@ -1237,15 +1354,17 @@ func (c *ContentCoordinator) handlePopupCreate(
1237 1354
1238 log.Info().1355 log.Info().
1239 Uint64("popup_id", uint64(popupID)).1356 Uint64("popup_id", uint64(popupID)).
1357+ Str("pane_id", string(paneID)).
1240 Str("popup_type", popupType.String()).1358 Str("popup_type", popupType.String()).
1241- Str("target_uri", req.TargetURI).1359+ Str("target_uri", logging.TruncateURL(req.TargetURI, logURLMaxLen)).
1242- Msg("popup created, awaiting ready-to-show")1360+ Msg("popup inserted (hidden), awaiting ready-to-show for visibility")
1243 1361
1244 return popupWV1362 return popupWV
1245 }1363 }
1246 1364
1247 // handlePopupReadyToShow handles the WebKit "ready-to-show" signal.1365 // handlePopupReadyToShow handles the WebKit "ready-to-show" signal.
1248-// This is called when the popup is configured and ready to be displayed.1366+// The popup WebView was already inserted into the workspace (hidden) during
1367+// the create signal. This handler just makes it visible.
1249 func (c *ContentCoordinator) handlePopupReadyToShow(ctx context.Context, popupID port.WebViewID) {1368 func (c *ContentCoordinator) handlePopupReadyToShow(ctx context.Context, popupID port.WebViewID) {
1250 log := logging.FromContext(ctx)1369 log := logging.FromContext(ctx)
1251 1370
@@ -1265,67 +1384,17 @@ func (c *ContentCoordinator) handlePopupReadyToShow(ctx context.Context, popupID
1265 log.Debug().1384 log.Debug().
1266 Uint64("popup_id", uint64(popupID)).1385 Uint64("popup_id", uint64(popupID)).
1267 Str("popup_type", pending.PopupType.String()).1386 Str("popup_type", pending.PopupType.String()).
1268- Msg("popup ready to show")1387+ Msg("popup ready to show - making visible")
1269-
1270- // Determine behavior from config
1271- behavior := GetBehavior(pending.PopupType, c.popupConfig)
1272- placement := "right"
1273- if c.popupConfig != nil {
1274- placement = c.popupConfig.Placement
1275- }
1276-
1277- // Create popup pane entity
1278- var paneID entity.PaneID
1279- if c.generateID != nil {
1280- paneID = entity.PaneID(c.generateID())
1281- } else {
1282- paneID = entity.PaneID(fmt.Sprintf("popup_%d", popupID))
1283- }
1284 1388
1285- popupPane := entity.NewPane(paneID)1389+ // Make the WebView visible now that it's ready
1286- popupPane.WindowType = entity.WindowPopup1390+ if pending.WebView != nil {
1287- popupPane.IsRelated = true1391+ pending.WebView.Show()
1288- popupPane.ParentPaneID = &pending.ParentPaneID
1289- popupPane.URI = pending.TargetURI
1290-
1291- // Enable OAuth auto-close if configured
1292- if c.popupConfig != nil && c.popupConfig.OAuthAutoClose && IsOAuthURL(pending.TargetURI) {
1293- popupPane.AutoClose = true
1294- c.setupOAuthAutoClose(ctx, paneID, pending.WebView)
1295- }
1296-
1297- // Register WebView in our map
1298- c.webViews[paneID] = pending.WebView
1299-
1300- // Setup standard callbacks
1301- c.setupWebViewCallbacks(ctx, paneID, pending.WebView)
1302-
1303- // Request insertion into workspace
1304- if c.onInsertPopup != nil {
1305- popupInput := InsertPopupInput{
1306- ParentPaneID: pending.ParentPaneID,
1307- PopupPane: popupPane,
1308- WebView: pending.WebView,
1309- Behavior: behavior,
1310- Placement: placement,
1311- PopupType: pending.PopupType,
1312- TargetURI: pending.TargetURI,
1313- }
1314-
1315- if err := c.onInsertPopup(ctx, popupInput); err != nil {
1316- log.Error().Err(err).Msg("failed to insert popup into workspace")
1317- // Clean up on failure
1318- delete(c.webViews, paneID)
1319- pending.WebView.Destroy()
1320- return
1321- }
1322 }1392 }
1323 1393
1324 log.Info().1394 log.Info().
1325- Str("pane_id", string(paneID)).1395+ Uint64("popup_id", uint64(popupID)).
1326- Str("behavior", string(behavior)).1396+ Str("target_uri", logging.TruncateURL(pending.TargetURI, logURLMaxLen)).
1327- Str("placement", placement).1397+ Msg("popup now visible")
1328- Msg("popup inserted into workspace")
1329 }1398 }
1330 1399
1331 // handlePopupClose handles the WebKit "close" signal for popup windows.1400 // handlePopupClose handles the WebKit "close" signal for popup windows.
@@ -1426,9 +1495,44 @@ func (c *ContentCoordinator) setupWebViewCallbacks(ctx context.Context, paneID e
1426 }1495 }
1427 1496
1428 // setupOAuthAutoClose monitors the popup for OAuth callback URLs and auto-closes.1497 // setupOAuthAutoClose monitors the popup for OAuth callback URLs and auto-closes.
1498+// It uses URL pattern detection for standard OAuth callbacks (code=, access_token=, etc.)
1499+// For providers using postMessage (like Google Sign-In), we rely on the provider calling
1500+// window.close() which triggers WebKit's close signal.
1501+// A long safety timeout (30s) catches popups that get stuck.
1429 func (c *ContentCoordinator) setupOAuthAutoClose(ctx context.Context, paneID entity.PaneID, wv *webkit.WebView) {1502 func (c *ContentCoordinator) setupOAuthAutoClose(ctx context.Context, paneID entity.PaneID, wv *webkit.WebView) {
1430 log := logging.FromContext(ctx)1503 log := logging.FromContext(ctx)
1431 1504
1505+ // Safety timeout - only triggers if popup gets stuck (provider should close via window.close)
1506+ var safetyTimer *time.Timer
1507+ var safetyTimerMu sync.Mutex
1508+ const oauthSafetyTimeout = 30 * time.Second
1509+
1510+ startSafetyTimer := func() {
1511+ safetyTimerMu.Lock()
1512+ defer safetyTimerMu.Unlock()
1513+ if safetyTimer != nil {
1514+ safetyTimer.Stop()
1515+ }
1516+ safetyTimer = time.AfterFunc(oauthSafetyTimeout, func() {
1517+ if wv != nil && !wv.IsDestroyed() {
1518+ log.Warn().Str("pane", string(paneID)).Msg("oauth safety timeout, closing stuck popup")
1519+ wv.Close()
1520+ }
1521+ })
1522+ }
1523+
1524+ cancelSafetyTimer := func() {
1525+ safetyTimerMu.Lock()
1526+ defer safetyTimerMu.Unlock()
1527+ if safetyTimer != nil {
1528+ safetyTimer.Stop()
1529+ safetyTimer = nil
1530+ }
1531+ }
1532+
1533+ // Start safety timer immediately
1534+ startSafetyTimer()
1535+
1432 // Wrap the existing OnURIChanged to also check for OAuth callbacks1536 // Wrap the existing OnURIChanged to also check for OAuth callbacks
1433 originalURIChanged := wv.OnURIChanged1537 originalURIChanged := wv.OnURIChanged
1434 wv.OnURIChanged = func(uri string) {1538 wv.OnURIChanged = func(uri string) {
@@ -1437,39 +1541,32 @@ func (c *ContentCoordinator) setupOAuthAutoClose(ctx context.Context, paneID ent
1437 originalURIChanged(uri)1541 originalURIChanged(uri)
1438 }1542 }
1439 1543
1440- // Check for OAuth callback1544+ // Check for OAuth callback (URL-based detection)
1441 if ShouldAutoClose(uri) {1545 if ShouldAutoClose(uri) {
1442- log.Info().1546+ cancelSafetyTimer()
1443- Str("pane_id", string(paneID)).1547+ log.Info().Str("pane", string(paneID)).Msg("oauth callback detected, closing")
1444- Str("uri", uri).
1445- Msg("OAuth callback detected, auto-closing popup")
1446-
1447- // Trigger close after a short delay to let the page process
1448 go func() {1548 go func() {
1449 time.Sleep(500 * time.Millisecond)1549 time.Sleep(500 * time.Millisecond)
1450 if wv != nil && !wv.IsDestroyed() {1550 if wv != nil && !wv.IsDestroyed() {
1451- // This will trigger handlePopupClose
1452 wv.Close()1551 wv.Close()
1453 }1552 }
1454 }()1553 }()
1455 }1554 }
1456 }1555 }
1457 1556
1458- // Also check on load committed for immediate redirects1557+ // Monitor load events for URL-based detection
1459 originalLoadChanged := wv.OnLoadChanged1558 originalLoadChanged := wv.OnLoadChanged
1460 wv.OnLoadChanged = func(event webkit.LoadEvent) {1559 wv.OnLoadChanged = func(event webkit.LoadEvent) {
1461 if originalLoadChanged != nil {1560 if originalLoadChanged != nil {
1462 originalLoadChanged(event)1561 originalLoadChanged(event)
1463 }1562 }
1464 1563
1564+ // Check URL on commit for immediate detection
1465 if event == webkit.LoadCommitted {1565 if event == webkit.LoadCommitted {
1466 uri := wv.URI()1566 uri := wv.URI()
1467 if ShouldAutoClose(uri) {1567 if ShouldAutoClose(uri) {
1468- log.Info().1568+ cancelSafetyTimer()
1469- Str("pane_id", string(paneID)).1569+ log.Info().Str("pane", string(paneID)).Msg("oauth callback on load, closing")
1470- Str("uri", uri).
1471- Msg("OAuth callback detected on load, auto-closing popup")
1472-
1473 go func() {1570 go func() {
1474 time.Sleep(500 * time.Millisecond)1571 time.Sleep(500 * time.Millisecond)
1475 if wv != nil && !wv.IsDestroyed() {1572 if wv != nil && !wv.IsDestroyed() {
@@ -1479,6 +1576,15 @@ func (c *ContentCoordinator) setupOAuthAutoClose(ctx context.Context, paneID ent
1479 }1576 }
1480 }1577 }
1481 }1578 }
1579+
1580+ // Wrap OnClose to cancel safety timer when popup closes normally
1581+ originalOnClose := wv.OnClose
1582+ wv.OnClose = func() {
1583+ cancelSafetyTimer()
1584+ if originalOnClose != nil {
1585+ originalOnClose()
1586+ }
1587+ }
1482 }1588 }
1483 1589
1484 // handleLinkMiddleClick handles middle-click / Ctrl+click on links.1590 // handleLinkMiddleClick handles middle-click / Ctrl+click on links.
M internal/ui/coordinator/oauth.go +0 -1
@@ -101,7 +101,6 @@ func IsOAuthCallback(url string) bool {
101101 // - Errors: error=, error_description=
102102 // - Various OAuth providers (Google, GitHub, Auth0, etc.)
103103 func ShouldAutoClose(url string) bool {
104- // Only auto-close on callback URLs that have OAuth response params
105104 return IsOAuthCallback(url)
106105 }
107106
@@ -101,7 +101,6 @@ func IsOAuthCallback(url string) bool {
101 // - Errors: error=, error_description=101 // - Errors: error=, error_description=
102 // - Various OAuth providers (Google, GitHub, Auth0, etc.)102 // - Various OAuth providers (Google, GitHub, Auth0, etc.)
103 func ShouldAutoClose(url string) bool {103 func ShouldAutoClose(url string) bool {
104- // Only auto-close on callback URLs that have OAuth response params
105 return IsOAuthCallback(url)104 return IsOAuthCallback(url)
106 }105 }
107 106
M internal/ui/coordinator/workspace.go +57 -6
@@ -1135,11 +1135,24 @@ func (c *WorkspaceCoordinator) syncStackedPaneTitles(ctx context.Context, stacke
11351135 return
11361136 }
11371137
1138+ // Get UI pane count to avoid index out of bounds when domain and UI are out of sync
1139+ uiPaneCount := stackedView.Count()
1140+
11381141 for i, child := range stackNode.Children {
11391142 if child.Pane == nil {
11401143 continue
11411144 }
11421145
1146+ // Skip if index exceeds UI pane count (domain/UI desync)
1147+ if i >= uiPaneCount {
1148+ log.Debug().
1149+ Int("index", i).
1150+ Int("ui_count", uiPaneCount).
1151+ Str("pane_id", string(child.Pane.ID)).
1152+ Msg("skipping title sync: index exceeds UI pane count")
1153+ continue
1154+ }
1155+
11431156 title := c.contentCoord.GetTitle(child.Pane.ID)
11441157 if title == "" {
11451158 title = child.Pane.Title
@@ -1798,11 +1811,13 @@ func (c *WorkspaceCoordinator) insertPopupStacked(ctx context.Context, input Ins
17981811 return fmt.Errorf("parent pane not found: %s", input.ParentPaneID)
17991812 }
18001813
1801- // Resolve or create stack node
1802- stackNode := c.resolveOrCreateStackNode(ctx, parentNode, input.ParentPaneID)
1814+ // Resolve or create stack node (track conversion for potential rollback)
1815+ stackNode, conversionInfo := c.resolveOrCreateStackNode(ctx, parentNode, input.ParentPaneID)
18031816
18041817 // Add popup pane to stack using use case
18051818 if _, err := c.panesUC.AddToStack(ctx, ws, stackNode, input.PopupPane); err != nil {
1819+ // Rollback stack conversion if we created a new stack
1820+ conversionInfo.revert()
18061821 return fmt.Errorf("failed to add popup to stack: %w", err)
18071822 }
18081823
@@ -1812,6 +1827,17 @@ func (c *WorkspaceCoordinator) insertPopupStacked(ctx context.Context, input Ins
18121827 }
18131828
18141829 if err := c.attachPopupPaneView(ctx, input, wsView, stackNode, log); err != nil {
1830+ // UI update failed - rollback domain changes to maintain consistency
1831+ log.Warn().Err(err).Msg("rolling back domain changes due to UI failure")
1832+
1833+ // Remove popup pane from stack
1834+ if removeErr := c.panesUC.RemoveFromStack(ctx, stackNode, input.PopupPane.ID); removeErr != nil {
1835+ log.Error().Err(removeErr).Msg("failed to rollback popup pane addition")
1836+ }
1837+
1838+ // Revert stack conversion if we created a new stack
1839+ conversionInfo.revert()
1840+
18151841 return err
18161842 }
18171843
@@ -1823,14 +1849,35 @@ func (c *WorkspaceCoordinator) insertPopupStacked(ctx context.Context, input Ins
18231849 return nil
18241850 }
18251851
1852+// stackConversionInfo holds state needed to revert a leaf-to-stack conversion.
1853+type stackConversionInfo struct {
1854+ wasConverted bool // true if resolveOrCreateStackNode converted a leaf to a stack
1855+ originalPane *entity.Pane // the pane that was in the node before conversion
1856+ node *entity.PaneNode // the node that was converted
1857+}
1858+
1859+// revert undoes a leaf-to-stack conversion.
1860+func (info *stackConversionInfo) revert() {
1861+ if !info.wasConverted || info.node == nil {
1862+ return
1863+ }
1864+
1865+ // Restore node to leaf state
1866+ info.node.Pane = info.originalPane
1867+ info.node.IsStacked = false
1868+ info.node.ActiveStackIndex = 0
1869+ info.node.Children = nil
1870+}
1871+
18261872 // resolveOrCreateStackNode finds an existing stack or creates one for popup insertion.
18271873 // Note: For popups, we can't use CreateStack use case since it creates a new pane,
18281874 // but we already have the popup pane. This conversion is a special case.
1875+// Returns the stack node and conversion info for potential rollback.
18291876 func (c *WorkspaceCoordinator) resolveOrCreateStackNode(
18301877 ctx context.Context,
18311878 parentNode *entity.PaneNode,
18321879 parentPaneID entity.PaneID,
1833-) *entity.PaneNode {
1880+) (*entity.PaneNode, stackConversionInfo) {
18341881 log := logging.FromContext(ctx)
18351882
18361883 // Check if parent is already in a stack
@@ -1838,7 +1885,7 @@ func (c *WorkspaceCoordinator) resolveOrCreateStackNode(
18381885 log.Debug().
18391886 Str("stack_id", parentNode.Parent.ID).
18401887 Msg("using existing parent stack for popup")
1841- return parentNode.Parent
1888+ return parentNode.Parent, stackConversionInfo{}
18421889 }
18431890
18441891 // Check if parent is already a stack container
@@ -1846,7 +1893,7 @@ func (c *WorkspaceCoordinator) resolveOrCreateStackNode(
18461893 log.Debug().
18471894 Str("stack_id", parentNode.ID).
18481895 Msg("parent is already a stack container")
1849- return parentNode
1896+ return parentNode, stackConversionInfo{}
18501897 }
18511898
18521899 // Need to convert leaf to stack for popup insertion.
@@ -1880,7 +1927,11 @@ func (c *WorkspaceCoordinator) resolveOrCreateStackNode(
18801927 Str("original_pane", string(originalPane.ID)).
18811928 Msg("converted leaf to stacked node for popup")
18821929
1883- return parentNode
1930+ return parentNode, stackConversionInfo{
1931+ wasConverted: true,
1932+ originalPane: originalPane,
1933+ node: parentNode,
1934+ }
18841935 }
18851936
18861937 func (c *WorkspaceCoordinator) attachPopupPaneView(
@@ -1135,11 +1135,24 @@ func (c *WorkspaceCoordinator) syncStackedPaneTitles(ctx context.Context, stacke
1135 return1135 return
1136 }1136 }
1137 1137
1138+ // Get UI pane count to avoid index out of bounds when domain and UI are out of sync
1139+ uiPaneCount := stackedView.Count()
1140+
1138 for i, child := range stackNode.Children {1141 for i, child := range stackNode.Children {
1139 if child.Pane == nil {1142 if child.Pane == nil {
1140 continue1143 continue
1141 }1144 }
1142 1145
1146+ // Skip if index exceeds UI pane count (domain/UI desync)
1147+ if i >= uiPaneCount {
1148+ log.Debug().
1149+ Int("index", i).
1150+ Int("ui_count", uiPaneCount).
1151+ Str("pane_id", string(child.Pane.ID)).
1152+ Msg("skipping title sync: index exceeds UI pane count")
1153+ continue
1154+ }
1155+
1143 title := c.contentCoord.GetTitle(child.Pane.ID)1156 title := c.contentCoord.GetTitle(child.Pane.ID)
1144 if title == "" {1157 if title == "" {
1145 title = child.Pane.Title1158 title = child.Pane.Title
@@ -1798,11 +1811,13 @@ func (c *WorkspaceCoordinator) insertPopupStacked(ctx context.Context, input Ins
1798 return fmt.Errorf("parent pane not found: %s", input.ParentPaneID)1811 return fmt.Errorf("parent pane not found: %s", input.ParentPaneID)
1799 }1812 }
1800 1813
1801- // Resolve or create stack node1814+ // Resolve or create stack node (track conversion for potential rollback)
1802- stackNode := c.resolveOrCreateStackNode(ctx, parentNode, input.ParentPaneID)1815+ stackNode, conversionInfo := c.resolveOrCreateStackNode(ctx, parentNode, input.ParentPaneID)
1803 1816
1804 // Add popup pane to stack using use case1817 // Add popup pane to stack using use case
1805 if _, err := c.panesUC.AddToStack(ctx, ws, stackNode, input.PopupPane); err != nil {1818 if _, err := c.panesUC.AddToStack(ctx, ws, stackNode, input.PopupPane); err != nil {
1819+ // Rollback stack conversion if we created a new stack
1820+ conversionInfo.revert()
1806 return fmt.Errorf("failed to add popup to stack: %w", err)1821 return fmt.Errorf("failed to add popup to stack: %w", err)
1807 }1822 }
1808 1823
@@ -1812,6 +1827,17 @@ func (c *WorkspaceCoordinator) insertPopupStacked(ctx context.Context, input Ins
1812 }1827 }
1813 1828
1814 if err := c.attachPopupPaneView(ctx, input, wsView, stackNode, log); err != nil {1829 if err := c.attachPopupPaneView(ctx, input, wsView, stackNode, log); err != nil {
1830+ // UI update failed - rollback domain changes to maintain consistency
1831+ log.Warn().Err(err).Msg("rolling back domain changes due to UI failure")
1832+
1833+ // Remove popup pane from stack
1834+ if removeErr := c.panesUC.RemoveFromStack(ctx, stackNode, input.PopupPane.ID); removeErr != nil {
1835+ log.Error().Err(removeErr).Msg("failed to rollback popup pane addition")
1836+ }
1837+
1838+ // Revert stack conversion if we created a new stack
1839+ conversionInfo.revert()
1840+
1815 return err1841 return err
1816 }1842 }
1817 1843
@@ -1823,14 +1849,35 @@ func (c *WorkspaceCoordinator) insertPopupStacked(ctx context.Context, input Ins
1823 return nil1849 return nil
1824 }1850 }
1825 1851
1852+// stackConversionInfo holds state needed to revert a leaf-to-stack conversion.
1853+type stackConversionInfo struct {
1854+ wasConverted bool // true if resolveOrCreateStackNode converted a leaf to a stack
1855+ originalPane *entity.Pane // the pane that was in the node before conversion
1856+ node *entity.PaneNode // the node that was converted
1857+}
1858+
1859+// revert undoes a leaf-to-stack conversion.
1860+func (info *stackConversionInfo) revert() {
1861+ if !info.wasConverted || info.node == nil {
1862+ return
1863+ }
1864+
1865+ // Restore node to leaf state
1866+ info.node.Pane = info.originalPane
1867+ info.node.IsStacked = false
1868+ info.node.ActiveStackIndex = 0
1869+ info.node.Children = nil
1870+}
1871+
1826 // resolveOrCreateStackNode finds an existing stack or creates one for popup insertion.1872 // resolveOrCreateStackNode finds an existing stack or creates one for popup insertion.
1827 // Note: For popups, we can't use CreateStack use case since it creates a new pane,1873 // Note: For popups, we can't use CreateStack use case since it creates a new pane,
1828 // but we already have the popup pane. This conversion is a special case.1874 // but we already have the popup pane. This conversion is a special case.
1875+// Returns the stack node and conversion info for potential rollback.
1829 func (c *WorkspaceCoordinator) resolveOrCreateStackNode(1876 func (c *WorkspaceCoordinator) resolveOrCreateStackNode(
1830 ctx context.Context,1877 ctx context.Context,
1831 parentNode *entity.PaneNode,1878 parentNode *entity.PaneNode,
1832 parentPaneID entity.PaneID,1879 parentPaneID entity.PaneID,
1833-) *entity.PaneNode {1880+) (*entity.PaneNode, stackConversionInfo) {
1834 log := logging.FromContext(ctx)1881 log := logging.FromContext(ctx)
1835 1882
1836 // Check if parent is already in a stack1883 // Check if parent is already in a stack
@@ -1838,7 +1885,7 @@ func (c *WorkspaceCoordinator) resolveOrCreateStackNode(
1838 log.Debug().1885 log.Debug().
1839 Str("stack_id", parentNode.Parent.ID).1886 Str("stack_id", parentNode.Parent.ID).
1840 Msg("using existing parent stack for popup")1887 Msg("using existing parent stack for popup")
1841- return parentNode.Parent1888+ return parentNode.Parent, stackConversionInfo{}
1842 }1889 }
1843 1890
1844 // Check if parent is already a stack container1891 // Check if parent is already a stack container
@@ -1846,7 +1893,7 @@ func (c *WorkspaceCoordinator) resolveOrCreateStackNode(
1846 log.Debug().1893 log.Debug().
1847 Str("stack_id", parentNode.ID).1894 Str("stack_id", parentNode.ID).
1848 Msg("parent is already a stack container")1895 Msg("parent is already a stack container")
1849- return parentNode1896+ return parentNode, stackConversionInfo{}
1850 }1897 }
1851 1898
1852 // Need to convert leaf to stack for popup insertion.1899 // Need to convert leaf to stack for popup insertion.
@@ -1880,7 +1927,11 @@ func (c *WorkspaceCoordinator) resolveOrCreateStackNode(
1880 Str("original_pane", string(originalPane.ID)).1927 Str("original_pane", string(originalPane.ID)).
1881 Msg("converted leaf to stacked node for popup")1928 Msg("converted leaf to stacked node for popup")
1882 1929
1883- return parentNode1930+ return parentNode, stackConversionInfo{
1931+ wasConverted: true,
1932+ originalPane: originalPane,
1933+ node: parentNode,
1934+ }
1884 }1935 }
1885 1936
1886 func (c *WorkspaceCoordinator) attachPopupPaneView(1937 func (c *WorkspaceCoordinator) attachPopupPaneView(
M internal/ui/deps.go +1 -0
@@ -25,6 +25,7 @@ type Dependencies struct {
2525 InitialURL string // URL to open on startup (optional)
2626 RestoreSessionID string // Session ID to restore on startup (optional)
2727 OnFirstWebViewShown func(context.Context)
28+ OnSessionPersisted func() // Called by main after session is persisted to DB
2829
2930 // Theme and color scheme management
3031 Theme *theme.Manager
@@ -25,6 +25,7 @@ type Dependencies struct {
25 InitialURL string // URL to open on startup (optional)25 InitialURL string // URL to open on startup (optional)
26 RestoreSessionID string // Session ID to restore on startup (optional)26 RestoreSessionID string // Session ID to restore on startup (optional)
27 OnFirstWebViewShown func(context.Context)27 OnFirstWebViewShown func(context.Context)
28+ OnSessionPersisted func() // Called by main after session is persisted to DB
28 29
29 // Theme and color scheme management30 // Theme and color scheme management
30 Theme *theme.Manager31 Theme *theme.Manager
M internal/ui/input/gesture.go +14 -5
@@ -107,11 +107,20 @@ func (h *GestureHandler) handlePressed(nPress int) {
107107 if handler != nil {
108108 if err := handler(h.ctx, action); err != nil {
109109 log := logging.FromContext(h.ctx)
110- log.Error().
111- Err(err).
112- Str("action", string(action)).
113- Uint("button", button).
114- Msg("gesture action handler error")
110+ // Navigation errors are expected (e.g., no back/forward history)
111+ if action == ActionGoBack || action == ActionGoForward {
112+ log.Debug().
113+ Err(err).
114+ Str("action", string(action)).
115+ Uint("button", button).
116+ Msg("gesture navigation not available")
117+ } else {
118+ log.Error().
119+ Err(err).
120+ Str("action", string(action)).
121+ Uint("button", button).
122+ Msg("gesture action handler error")
123+ }
115124 }
116125 }
117126 }
@@ -107,11 +107,20 @@ func (h *GestureHandler) handlePressed(nPress int) {
107 if handler != nil {107 if handler != nil {
108 if err := handler(h.ctx, action); err != nil {108 if err := handler(h.ctx, action); err != nil {
109 log := logging.FromContext(h.ctx)109 log := logging.FromContext(h.ctx)
110- log.Error().110+ // Navigation errors are expected (e.g., no back/forward history)
111- Err(err).111+ if action == ActionGoBack || action == ActionGoForward {
112- Str("action", string(action)).112+ log.Debug().
113- Uint("button", button).113+ Err(err).
114- Msg("gesture action handler error")114+ Str("action", string(action)).
115+ Uint("button", button).
116+ Msg("gesture navigation not available")
117+ } else {
118+ log.Error().
119+ Err(err).
120+ Str("action", string(action)).
121+ Uint("button", button).
122+ Msg("gesture action handler error")
123+ }
115 }124 }
116 }125 }
117 }126 }
M webui/package-lock.json +445 -441
@@ -442,9 +442,9 @@
442442 }
443443 },
444444 "node_modules/@eslint-community/eslint-utils": {
445- "version": "4.9.0",
446- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
447- "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
445+ "version": "4.9.1",
446+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
447+ "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
448448 "dev": true,
449449 "license": "MIT",
450450 "dependencies": {
@@ -719,17 +719,17 @@
719719 }
720720 },
721721 "node_modules/@parcel/watcher": {
722- "version": "2.5.1",
723- "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
724- "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
722+ "version": "2.5.4",
723+ "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.4.tgz",
724+ "integrity": "sha512-WYa2tUVV5HiArWPB3ydlOc4R2ivq0IDrlqhMi3l7mVsFEXNcTfxYFPIHXHXIh/ca/y/V5N4E1zecyxdIBjYnkQ==",
725725 "dev": true,
726726 "hasInstallScript": true,
727727 "license": "MIT",
728728 "dependencies": {
729- "detect-libc": "^1.0.3",
729+ "detect-libc": "^2.0.3",
730730 "is-glob": "^4.0.3",
731- "micromatch": "^4.0.5",
732- "node-addon-api": "^7.0.0"
731+ "node-addon-api": "^7.0.0",
732+ "picomatch": "^4.0.3"
733733 },
734734 "engines": {
735735 "node": ">= 10.0.0"
@@ -739,25 +739,25 @@
739739 "url": "https://opencollective.com/parcel"
740740 },
741741 "optionalDependencies": {
742- "@parcel/watcher-android-arm64": "2.5.1",
743- "@parcel/watcher-darwin-arm64": "2.5.1",
744- "@parcel/watcher-darwin-x64": "2.5.1",
745- "@parcel/watcher-freebsd-x64": "2.5.1",
746- "@parcel/watcher-linux-arm-glibc": "2.5.1",
747- "@parcel/watcher-linux-arm-musl": "2.5.1",
748- "@parcel/watcher-linux-arm64-glibc": "2.5.1",
749- "@parcel/watcher-linux-arm64-musl": "2.5.1",
750- "@parcel/watcher-linux-x64-glibc": "2.5.1",
751- "@parcel/watcher-linux-x64-musl": "2.5.1",
752- "@parcel/watcher-win32-arm64": "2.5.1",
753- "@parcel/watcher-win32-ia32": "2.5.1",
754- "@parcel/watcher-win32-x64": "2.5.1"
742+ "@parcel/watcher-android-arm64": "2.5.4",
743+ "@parcel/watcher-darwin-arm64": "2.5.4",
744+ "@parcel/watcher-darwin-x64": "2.5.4",
745+ "@parcel/watcher-freebsd-x64": "2.5.4",
746+ "@parcel/watcher-linux-arm-glibc": "2.5.4",
747+ "@parcel/watcher-linux-arm-musl": "2.5.4",
748+ "@parcel/watcher-linux-arm64-glibc": "2.5.4",
749+ "@parcel/watcher-linux-arm64-musl": "2.5.4",
750+ "@parcel/watcher-linux-x64-glibc": "2.5.4",
751+ "@parcel/watcher-linux-x64-musl": "2.5.4",
752+ "@parcel/watcher-win32-arm64": "2.5.4",
753+ "@parcel/watcher-win32-ia32": "2.5.4",
754+ "@parcel/watcher-win32-x64": "2.5.4"
755755 }
756756 },
757757 "node_modules/@parcel/watcher-android-arm64": {
758- "version": "2.5.1",
759- "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",
760- "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",
758+ "version": "2.5.4",
759+ "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.4.tgz",
760+ "integrity": "sha512-hoh0vx4v+b3BNI7Cjoy2/B0ARqcwVNrzN/n7DLq9ZB4I3lrsvhrkCViJyfTj/Qi5xM9YFiH4AmHGK6pgH1ss7g==",
761761 "cpu": [
762762 "arm64"
763763 ],
@@ -776,9 +776,9 @@
776776 }
777777 },
778778 "node_modules/@parcel/watcher-darwin-arm64": {
779- "version": "2.5.1",
780- "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",
781- "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",
779+ "version": "2.5.4",
780+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.4.tgz",
781+ "integrity": "sha512-kphKy377pZiWpAOyTgQYPE5/XEKVMaj6VUjKT5VkNyUJlr2qZAn8gIc7CPzx+kbhvqHDT9d7EqdOqRXT6vk0zw==",
782782 "cpu": [
783783 "arm64"
784784 ],
@@ -797,9 +797,9 @@
797797 }
798798 },
799799 "node_modules/@parcel/watcher-darwin-x64": {
800- "version": "2.5.1",
801- "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",
802- "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",
800+ "version": "2.5.4",
801+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.4.tgz",
802+ "integrity": "sha512-UKaQFhCtNJW1A9YyVz3Ju7ydf6QgrpNQfRZ35wNKUhTQ3dxJ/3MULXN5JN/0Z80V/KUBDGa3RZaKq1EQT2a2gg==",
803803 "cpu": [
804804 "x64"
805805 ],
@@ -818,9 +818,9 @@
818818 }
819819 },
820820 "node_modules/@parcel/watcher-freebsd-x64": {
821- "version": "2.5.1",
822- "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",
823- "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",
821+ "version": "2.5.4",
822+ "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.4.tgz",
823+ "integrity": "sha512-Dib0Wv3Ow/m2/ttvLdeI2DBXloO7t3Z0oCp4bAb2aqyqOjKPPGrg10pMJJAQ7tt8P4V2rwYwywkDhUia/FgS+Q==",
824824 "cpu": [
825825 "x64"
826826 ],
@@ -839,9 +839,9 @@
839839 }
840840 },
841841 "node_modules/@parcel/watcher-linux-arm-glibc": {
842- "version": "2.5.1",
843- "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",
844- "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",
842+ "version": "2.5.4",
843+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.4.tgz",
844+ "integrity": "sha512-I5Vb769pdf7Q7Sf4KNy8Pogl/URRCKu9ImMmnVKYayhynuyGYMzuI4UOWnegQNa2sGpsPSbzDsqbHNMyeyPCgw==",
845845 "cpu": [
846846 "arm"
847847 ],
@@ -860,9 +860,9 @@
860860 }
861861 },
862862 "node_modules/@parcel/watcher-linux-arm-musl": {
863- "version": "2.5.1",
864- "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",
865- "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",
863+ "version": "2.5.4",
864+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.4.tgz",
865+ "integrity": "sha512-kGO8RPvVrcAotV4QcWh8kZuHr9bXi9a3bSZw7kFarYR0+fGliU7hd/zevhjw8fnvIKG3J9EO5G6sXNGCSNMYPQ==",
866866 "cpu": [
867867 "arm"
868868 ],
@@ -881,9 +881,9 @@
881881 }
882882 },
883883 "node_modules/@parcel/watcher-linux-arm64-glibc": {
884- "version": "2.5.1",
885- "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",
886- "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",
884+ "version": "2.5.4",
885+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.4.tgz",
886+ "integrity": "sha512-KU75aooXhqGFY2W5/p8DYYHt4hrjHZod8AhcGAmhzPn/etTa+lYCDB2b1sJy3sWJ8ahFVTdy+EbqSBvMx3iFlw==",
887887 "cpu": [
888888 "arm64"
889889 ],
@@ -902,9 +902,9 @@
902902 }
903903 },
904904 "node_modules/@parcel/watcher-linux-arm64-musl": {
905- "version": "2.5.1",
906- "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",
907- "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",
905+ "version": "2.5.4",
906+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.4.tgz",
907+ "integrity": "sha512-Qx8uNiIekVutnzbVdrgSanM+cbpDD3boB1f8vMtnuG5Zau4/bdDbXyKwIn0ToqFhIuob73bcxV9NwRm04/hzHQ==",
908908 "cpu": [
909909 "arm64"
910910 ],
@@ -923,9 +923,9 @@
923923 }
924924 },
925925 "node_modules/@parcel/watcher-linux-x64-glibc": {
926- "version": "2.5.1",
927- "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
928- "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
926+ "version": "2.5.4",
927+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.4.tgz",
928+ "integrity": "sha512-UYBQvhYmgAv61LNUn24qGQdjtycFBKSK3EXr72DbJqX9aaLbtCOO8+1SkKhD/GNiJ97ExgcHBrukcYhVjrnogA==",
929929 "cpu": [
930930 "x64"
931931 ],
@@ -944,9 +944,9 @@
944944 }
945945 },
946946 "node_modules/@parcel/watcher-linux-x64-musl": {
947- "version": "2.5.1",
948- "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
949- "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
947+ "version": "2.5.4",
948+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.4.tgz",
949+ "integrity": "sha512-YoRWCVgxv8akZrMhdyVi6/TyoeeMkQ0PGGOf2E4omODrvd1wxniXP+DBynKoHryStks7l+fDAMUBRzqNHrVOpg==",
950950 "cpu": [
951951 "x64"
952952 ],
@@ -965,9 +965,9 @@
965965 }
966966 },
967967 "node_modules/@parcel/watcher-win32-arm64": {
968- "version": "2.5.1",
969- "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",
970- "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",
968+ "version": "2.5.4",
969+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.4.tgz",
970+ "integrity": "sha512-iby+D/YNXWkiQNYcIhg8P5hSjzXEHaQrk2SLrWOUD7VeC4Ohu0WQvmV+HDJokZVJ2UjJ4AGXW3bx7Lls9Ln4TQ==",
971971 "cpu": [
972972 "arm64"
973973 ],
@@ -986,9 +986,9 @@
986986 }
987987 },
988988 "node_modules/@parcel/watcher-win32-ia32": {
989- "version": "2.5.1",
990- "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",
991- "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",
989+ "version": "2.5.4",
990+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.4.tgz",
991+ "integrity": "sha512-vQN+KIReG0a2ZDpVv8cgddlf67J8hk1WfZMMP7sMeZmJRSmEax5xNDNWKdgqSe2brOKTQQAs3aCCUal2qBHAyg==",
992992 "cpu": [
993993 "ia32"
994994 ],
@@ -1007,9 +1007,9 @@
10071007 }
10081008 },
10091009 "node_modules/@parcel/watcher-win32-x64": {
1010- "version": "2.5.1",
1011- "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",
1012- "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",
1010+ "version": "2.5.4",
1011+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.4.tgz",
1012+ "integrity": "sha512-3A6efb6BOKwyw7yk9ro2vus2YTt2nvcd56AuzxdMiVOxL9umDyN5PKkKfZ/gZ9row41SjVmTVQNWQhaRRGpOKw==",
10131013 "cpu": [
10141014 "x64"
10151015 ],
@@ -1028,9 +1028,9 @@
10281028 }
10291029 },
10301030 "node_modules/@rollup/rollup-android-arm-eabi": {
1031- "version": "4.53.3",
1032- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz",
1033- "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==",
1031+ "version": "4.56.0",
1032+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.56.0.tgz",
1033+ "integrity": "sha512-LNKIPA5k8PF1+jAFomGe3qN3bbIgJe/IlpDBwuVjrDKrJhVWywgnJvflMt/zkbVNLFtF1+94SljYQS6e99klnw==",
10341034 "cpu": [
10351035 "arm"
10361036 ],
@@ -1042,9 +1042,9 @@
10421042 ]
10431043 },
10441044 "node_modules/@rollup/rollup-android-arm64": {
1045- "version": "4.53.3",
1046- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz",
1047- "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==",
1045+ "version": "4.56.0",
1046+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.56.0.tgz",
1047+ "integrity": "sha512-lfbVUbelYqXlYiU/HApNMJzT1E87UPGvzveGg2h0ktUNlOCxKlWuJ9jtfvs1sKHdwU4fzY7Pl8sAl49/XaEk6Q==",
10481048 "cpu": [
10491049 "arm64"
10501050 ],
@@ -1056,9 +1056,9 @@
10561056 ]
10571057 },
10581058 "node_modules/@rollup/rollup-darwin-arm64": {
1059- "version": "4.53.3",
1060- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz",
1061- "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==",
1059+ "version": "4.56.0",
1060+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.56.0.tgz",
1061+ "integrity": "sha512-EgxD1ocWfhoD6xSOeEEwyE7tDvwTgZc8Bss7wCWe+uc7wO8G34HHCUH+Q6cHqJubxIAnQzAsyUsClt0yFLu06w==",
10621062 "cpu": [
10631063 "arm64"
10641064 ],
@@ -1070,9 +1070,9 @@
10701070 ]
10711071 },
10721072 "node_modules/@rollup/rollup-darwin-x64": {
1073- "version": "4.53.3",
1074- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz",
1075- "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==",
1073+ "version": "4.56.0",
1074+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.56.0.tgz",
1075+ "integrity": "sha512-1vXe1vcMOssb/hOF8iv52A7feWW2xnu+c8BV4t1F//m9QVLTfNVpEdja5ia762j/UEJe2Z1jAmEqZAK42tVW3g==",
10761076 "cpu": [
10771077 "x64"
10781078 ],
@@ -1084,9 +1084,9 @@
10841084 ]
10851085 },
10861086 "node_modules/@rollup/rollup-freebsd-arm64": {
1087- "version": "4.53.3",
1088- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz",
1089- "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==",
1087+ "version": "4.56.0",
1088+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.56.0.tgz",
1089+ "integrity": "sha512-bof7fbIlvqsyv/DtaXSck4VYQ9lPtoWNFCB/JY4snlFuJREXfZnm+Ej6yaCHfQvofJDXLDMTVxWscVSuQvVWUQ==",
10901090 "cpu": [
10911091 "arm64"
10921092 ],
@@ -1098,9 +1098,9 @@
10981098 ]
10991099 },
11001100 "node_modules/@rollup/rollup-freebsd-x64": {
1101- "version": "4.53.3",
1102- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz",
1103- "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==",
1101+ "version": "4.56.0",
1102+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.56.0.tgz",
1103+ "integrity": "sha512-KNa6lYHloW+7lTEkYGa37fpvPq+NKG/EHKM8+G/g9WDU7ls4sMqbVRV78J6LdNuVaeeK5WB9/9VAFbKxcbXKYg==",
11041104 "cpu": [
11051105 "x64"
11061106 ],
@@ -1112,9 +1112,9 @@
11121112 ]
11131113 },
11141114 "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
1115- "version": "4.53.3",
1116- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz",
1117- "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==",
1115+ "version": "4.56.0",
1116+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.56.0.tgz",
1117+ "integrity": "sha512-E8jKK87uOvLrrLN28jnAAAChNq5LeCd2mGgZF+fGF5D507WlG/Noct3lP/QzQ6MrqJ5BCKNwI9ipADB6jyiq2A==",
11181118 "cpu": [
11191119 "arm"
11201120 ],
@@ -1126,9 +1126,9 @@
11261126 ]
11271127 },
11281128 "node_modules/@rollup/rollup-linux-arm-musleabihf": {
1129- "version": "4.53.3",
1130- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz",
1131- "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==",
1129+ "version": "4.56.0",
1130+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.56.0.tgz",
1131+ "integrity": "sha512-jQosa5FMYF5Z6prEpTCCmzCXz6eKr/tCBssSmQGEeozA9tkRUty/5Vx06ibaOP9RCrW1Pvb8yp3gvZhHwTDsJw==",
11321132 "cpu": [
11331133 "arm"
11341134 ],
@@ -1140,9 +1140,9 @@
11401140 ]
11411141 },
11421142 "node_modules/@rollup/rollup-linux-arm64-gnu": {
1143- "version": "4.53.3",
1144- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz",
1145- "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==",
1143+ "version": "4.56.0",
1144+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.56.0.tgz",
1145+ "integrity": "sha512-uQVoKkrC1KGEV6udrdVahASIsaF8h7iLG0U0W+Xn14ucFwi6uS539PsAr24IEF9/FoDtzMeeJXJIBo5RkbNWvQ==",
11461146 "cpu": [
11471147 "arm64"
11481148 ],
@@ -1154,9 +1154,9 @@
11541154 ]
11551155 },
11561156 "node_modules/@rollup/rollup-linux-arm64-musl": {
1157- "version": "4.53.3",
1158- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz",
1159- "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==",
1157+ "version": "4.56.0",
1158+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.56.0.tgz",
1159+ "integrity": "sha512-vLZ1yJKLxhQLFKTs42RwTwa6zkGln+bnXc8ueFGMYmBTLfNu58sl5/eXyxRa2RarTkJbXl8TKPgfS6V5ijNqEA==",
11601160 "cpu": [
11611161 "arm64"
11621162 ],
@@ -1168,9 +1168,23 @@
11681168 ]
11691169 },
11701170 "node_modules/@rollup/rollup-linux-loong64-gnu": {
1171- "version": "4.53.3",
1172- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz",
1173- "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==",
1171+ "version": "4.56.0",
1172+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.56.0.tgz",
1173+ "integrity": "sha512-FWfHOCub564kSE3xJQLLIC/hbKqHSVxy8vY75/YHHzWvbJL7aYJkdgwD/xGfUlL5UV2SB7otapLrcCj2xnF1dg==",
1174+ "cpu": [
1175+ "loong64"
1176+ ],
1177+ "dev": true,
1178+ "license": "MIT",
1179+ "optional": true,
1180+ "os": [
1181+ "linux"
1182+ ]
1183+ },
1184+ "node_modules/@rollup/rollup-linux-loong64-musl": {
1185+ "version": "4.56.0",
1186+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.56.0.tgz",
1187+ "integrity": "sha512-z1EkujxIh7nbrKL1lmIpqFTc/sr0u8Uk0zK/qIEFldbt6EDKWFk/pxFq3gYj4Bjn3aa9eEhYRlL3H8ZbPT1xvA==",
11741188 "cpu": [
11751189 "loong64"
11761190 ],
@@ -1182,9 +1196,23 @@
11821196 ]
11831197 },
11841198 "node_modules/@rollup/rollup-linux-ppc64-gnu": {
1185- "version": "4.53.3",
1186- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz",
1187- "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==",
1199+ "version": "4.56.0",
1200+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.56.0.tgz",
1201+ "integrity": "sha512-iNFTluqgdoQC7AIE8Q34R3AuPrJGJirj5wMUErxj22deOcY7XwZRaqYmB6ZKFHoVGqRcRd0mqO+845jAibKCkw==",
1202+ "cpu": [
1203+ "ppc64"
1204+ ],
1205+ "dev": true,
1206+ "license": "MIT",
1207+ "optional": true,
1208+ "os": [
1209+ "linux"
1210+ ]
1211+ },
1212+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
1213+ "version": "4.56.0",
1214+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.56.0.tgz",
1215+ "integrity": "sha512-MtMeFVlD2LIKjp2sE2xM2slq3Zxf9zwVuw0jemsxvh1QOpHSsSzfNOTH9uYW9i1MXFxUSMmLpeVeUzoNOKBaWg==",
11881216 "cpu": [
11891217 "ppc64"
11901218 ],
@@ -1196,9 +1224,9 @@
11961224 ]
11971225 },
11981226 "node_modules/@rollup/rollup-linux-riscv64-gnu": {
1199- "version": "4.53.3",
1200- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz",
1201- "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==",
1227+ "version": "4.56.0",
1228+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.56.0.tgz",
1229+ "integrity": "sha512-in+v6wiHdzzVhYKXIk5U74dEZHdKN9KH0Q4ANHOTvyXPG41bajYRsy7a8TPKbYPl34hU7PP7hMVHRvv/5aCSew==",
12021230 "cpu": [
12031231 "riscv64"
12041232 ],
@@ -1210,9 +1238,9 @@
12101238 ]
12111239 },
12121240 "node_modules/@rollup/rollup-linux-riscv64-musl": {
1213- "version": "4.53.3",
1214- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz",
1215- "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==",
1241+ "version": "4.56.0",
1242+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.56.0.tgz",
1243+ "integrity": "sha512-yni2raKHB8m9NQpI9fPVwN754mn6dHQSbDTwxdr9SE0ks38DTjLMMBjrwvB5+mXrX+C0npX0CVeCUcvvvD8CNQ==",
12161244 "cpu": [
12171245 "riscv64"
12181246 ],
@@ -1224,9 +1252,9 @@
12241252 ]
12251253 },
12261254 "node_modules/@rollup/rollup-linux-s390x-gnu": {
1227- "version": "4.53.3",
1228- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz",
1229- "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==",
1255+ "version": "4.56.0",
1256+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.56.0.tgz",
1257+ "integrity": "sha512-zhLLJx9nQPu7wezbxt2ut+CI4YlXi68ndEve16tPc/iwoylWS9B3FxpLS2PkmfYgDQtosah07Mj9E0khc3Y+vQ==",
12301258 "cpu": [
12311259 "s390x"
12321260 ],
@@ -1238,9 +1266,9 @@
12381266 ]
12391267 },
12401268 "node_modules/@rollup/rollup-linux-x64-gnu": {
1241- "version": "4.53.3",
1242- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz",
1243- "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==",
1269+ "version": "4.56.0",
1270+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.56.0.tgz",
1271+ "integrity": "sha512-MVC6UDp16ZSH7x4rtuJPAEoE1RwS8N4oK9DLHy3FTEdFoUTCFVzMfJl/BVJ330C+hx8FfprA5Wqx4FhZXkj2Kw==",
12441272 "cpu": [
12451273 "x64"
12461274 ],
@@ -1252,9 +1280,9 @@
12521280 ]
12531281 },
12541282 "node_modules/@rollup/rollup-linux-x64-musl": {
1255- "version": "4.53.3",
1256- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz",
1257- "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==",
1283+ "version": "4.56.0",
1284+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.56.0.tgz",
1285+ "integrity": "sha512-ZhGH1eA4Qv0lxaV00azCIS1ChedK0V32952Md3FtnxSqZTBTd6tgil4nZT5cU8B+SIw3PFYkvyR4FKo2oyZIHA==",
12581286 "cpu": [
12591287 "x64"
12601288 ],
@@ -1265,10 +1293,24 @@
12651293 "linux"
12661294 ]
12671295 },
1296+ "node_modules/@rollup/rollup-openbsd-x64": {
1297+ "version": "4.56.0",
1298+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.56.0.tgz",
1299+ "integrity": "sha512-O16XcmyDeFI9879pEcmtWvD/2nyxR9mF7Gs44lf1vGGx8Vg2DRNx11aVXBEqOQhWb92WN4z7fW/q4+2NYzCbBA==",
1300+ "cpu": [
1301+ "x64"
1302+ ],
1303+ "dev": true,
1304+ "license": "MIT",
1305+ "optional": true,
1306+ "os": [
1307+ "openbsd"
1308+ ]
1309+ },
12681310 "node_modules/@rollup/rollup-openharmony-arm64": {
1269- "version": "4.53.3",
1270- "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz",
1271- "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==",
1311+ "version": "4.56.0",
1312+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.56.0.tgz",
1313+ "integrity": "sha512-LhN/Reh+7F3RCgQIRbgw8ZMwUwyqJM+8pXNT6IIJAqm2IdKkzpCh/V9EdgOMBKuebIrzswqy4ATlrDgiOwbRcQ==",
12721314 "cpu": [
12731315 "arm64"
12741316 ],
@@ -1280,9 +1322,9 @@
12801322 ]
12811323 },
12821324 "node_modules/@rollup/rollup-win32-arm64-msvc": {
1283- "version": "4.53.3",
1284- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz",
1285- "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==",
1325+ "version": "4.56.0",
1326+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.56.0.tgz",
1327+ "integrity": "sha512-kbFsOObXp3LBULg1d3JIUQMa9Kv4UitDmpS+k0tinPBz3watcUiV2/LUDMMucA6pZO3WGE27P7DsfaN54l9ing==",
12861328 "cpu": [
12871329 "arm64"
12881330 ],
@@ -1294,9 +1336,9 @@
12941336 ]
12951337 },
12961338 "node_modules/@rollup/rollup-win32-ia32-msvc": {
1297- "version": "4.53.3",
1298- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz",
1299- "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==",
1339+ "version": "4.56.0",
1340+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.56.0.tgz",
1341+ "integrity": "sha512-vSSgny54D6P4vf2izbtFm/TcWYedw7f8eBrOiGGecyHyQB9q4Kqentjaj8hToe+995nob/Wv48pDqL5a62EWtg==",
13001342 "cpu": [
13011343 "ia32"
13021344 ],
@@ -1308,9 +1350,9 @@
13081350 ]
13091351 },
13101352 "node_modules/@rollup/rollup-win32-x64-gnu": {
1311- "version": "4.53.3",
1312- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz",
1313- "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==",
1353+ "version": "4.56.0",
1354+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.56.0.tgz",
1355+ "integrity": "sha512-FeCnkPCTHQJFbiGG49KjV5YGW/8b9rrXAM2Mz2kiIoktq2qsJxRD5giEMEOD2lPdgs72upzefaUvS+nc8E3UzQ==",
13141356 "cpu": [
13151357 "x64"
13161358 ],
@@ -1322,9 +1364,9 @@
13221364 ]
13231365 },
13241366 "node_modules/@rollup/rollup-win32-x64-msvc": {
1325- "version": "4.53.3",
1326- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz",
1327- "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==",
1367+ "version": "4.56.0",
1368+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.56.0.tgz",
1369+ "integrity": "sha512-H8AE9Ur/t0+1VXujj90w0HrSOuv0Nq9r1vSZF2t5km20NTfosQsGGUXDaKdQZzwuLts7IyL1fYT4hM95TI9c4g==",
13281370 "cpu": [
13291371 "x64"
13301372 ],
@@ -1386,37 +1428,37 @@
13861428 }
13871429 },
13881430 "node_modules/@swc/helpers": {
1389- "version": "0.5.17",
1390- "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz",
1391- "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==",
1431+ "version": "0.5.18",
1432+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.18.tgz",
1433+ "integrity": "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==",
13921434 "license": "Apache-2.0",
13931435 "dependencies": {
13941436 "tslib": "^2.8.0"
13951437 }
13961438 },
13971439 "node_modules/@tailwindcss/cli": {
1398- "version": "4.1.17",
1399- "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.1.17.tgz",
1400- "integrity": "sha512-jUIxcyUNlCC2aNPnyPEWU/L2/ik3pB4fF3auKGXr8AvN3T3OFESVctFKOBoPZQaZJIeUpPn1uCLp0MRxuek8gg==",
1440+ "version": "4.1.18",
1441+ "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.1.18.tgz",
1442+ "integrity": "sha512-sMZ+lZbDyxwjD2E0L7oRUjJ01Ffjtme5OtjvvnC+cV4CEDcbqzbp25TCpxHj6kWLU9+DlqJOiNgSOgctC2aZmg==",
14011443 "dev": true,
14021444 "license": "MIT",
14031445 "dependencies": {
14041446 "@parcel/watcher": "^2.5.1",
1405- "@tailwindcss/node": "4.1.17",
1406- "@tailwindcss/oxide": "4.1.17",
1447+ "@tailwindcss/node": "4.1.18",
1448+ "@tailwindcss/oxide": "4.1.18",
14071449 "enhanced-resolve": "^5.18.3",
14081450 "mri": "^1.2.0",
14091451 "picocolors": "^1.1.1",
1410- "tailwindcss": "4.1.17"
1452+ "tailwindcss": "4.1.18"
14111453 },
14121454 "bin": {
14131455 "tailwindcss": "dist/index.mjs"
14141456 }
14151457 },
14161458 "node_modules/@tailwindcss/node": {
1417- "version": "4.1.17",
1418- "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.17.tgz",
1419- "integrity": "sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==",
1459+ "version": "4.1.18",
1460+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz",
1461+ "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==",
14201462 "dev": true,
14211463 "license": "MIT",
14221464 "dependencies": {
@@ -1426,37 +1468,37 @@
14261468 "lightningcss": "1.30.2",
14271469 "magic-string": "^0.30.21",
14281470 "source-map-js": "^1.2.1",
1429- "tailwindcss": "4.1.17"
1471+ "tailwindcss": "4.1.18"
14301472 }
14311473 },
14321474 "node_modules/@tailwindcss/oxide": {
1433- "version": "4.1.17",
1434- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.17.tgz",
1435- "integrity": "sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==",
1475+ "version": "4.1.18",
1476+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz",
1477+ "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==",
14361478 "dev": true,
14371479 "license": "MIT",
14381480 "engines": {
14391481 "node": ">= 10"
14401482 },
14411483 "optionalDependencies": {
1442- "@tailwindcss/oxide-android-arm64": "4.1.17",
1443- "@tailwindcss/oxide-darwin-arm64": "4.1.17",
1444- "@tailwindcss/oxide-darwin-x64": "4.1.17",
1445- "@tailwindcss/oxide-freebsd-x64": "4.1.17",
1446- "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.17",
1447- "@tailwindcss/oxide-linux-arm64-gnu": "4.1.17",
1448- "@tailwindcss/oxide-linux-arm64-musl": "4.1.17",
1449- "@tailwindcss/oxide-linux-x64-gnu": "4.1.17",
1450- "@tailwindcss/oxide-linux-x64-musl": "4.1.17",
1451- "@tailwindcss/oxide-wasm32-wasi": "4.1.17",
1452- "@tailwindcss/oxide-win32-arm64-msvc": "4.1.17",
1453- "@tailwindcss/oxide-win32-x64-msvc": "4.1.17"
1484+ "@tailwindcss/oxide-android-arm64": "4.1.18",
1485+ "@tailwindcss/oxide-darwin-arm64": "4.1.18",
1486+ "@tailwindcss/oxide-darwin-x64": "4.1.18",
1487+ "@tailwindcss/oxide-freebsd-x64": "4.1.18",
1488+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18",
1489+ "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18",
1490+ "@tailwindcss/oxide-linux-arm64-musl": "4.1.18",
1491+ "@tailwindcss/oxide-linux-x64-gnu": "4.1.18",
1492+ "@tailwindcss/oxide-linux-x64-musl": "4.1.18",
1493+ "@tailwindcss/oxide-wasm32-wasi": "4.1.18",
1494+ "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18",
1495+ "@tailwindcss/oxide-win32-x64-msvc": "4.1.18"
14541496 }
14551497 },
14561498 "node_modules/@tailwindcss/oxide-android-arm64": {
1457- "version": "4.1.17",
1458- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.17.tgz",
1459- "integrity": "sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==",
1499+ "version": "4.1.18",
1500+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz",
1501+ "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==",
14601502 "cpu": [
14611503 "arm64"
14621504 ],
@@ -1471,9 +1513,9 @@
14711513 }
14721514 },
14731515 "node_modules/@tailwindcss/oxide-darwin-arm64": {
1474- "version": "4.1.17",
1475- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.17.tgz",
1476- "integrity": "sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==",
1516+ "version": "4.1.18",
1517+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz",
1518+ "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==",
14771519 "cpu": [
14781520 "arm64"
14791521 ],
@@ -1488,9 +1530,9 @@
14881530 }
14891531 },
14901532 "node_modules/@tailwindcss/oxide-darwin-x64": {
1491- "version": "4.1.17",
1492- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.17.tgz",
1493- "integrity": "sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==",
1533+ "version": "4.1.18",
1534+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz",
1535+ "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==",
14941536 "cpu": [
14951537 "x64"
14961538 ],
@@ -1505,9 +1547,9 @@
15051547 }
15061548 },
15071549 "node_modules/@tailwindcss/oxide-freebsd-x64": {
1508- "version": "4.1.17",
1509- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.17.tgz",
1510- "integrity": "sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==",
1550+ "version": "4.1.18",
1551+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz",
1552+ "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==",
15111553 "cpu": [
15121554 "x64"
15131555 ],
@@ -1522,9 +1564,9 @@
15221564 }
15231565 },
15241566 "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
1525- "version": "4.1.17",
1526- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.17.tgz",
1527- "integrity": "sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==",
1567+ "version": "4.1.18",
1568+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz",
1569+ "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==",
15281570 "cpu": [
15291571 "arm"
15301572 ],
@@ -1539,9 +1581,9 @@
15391581 }
15401582 },
15411583 "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
1542- "version": "4.1.17",
1543- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.17.tgz",
1544- "integrity": "sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==",
1584+ "version": "4.1.18",
1585+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz",
1586+ "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==",
15451587 "cpu": [
15461588 "arm64"
15471589 ],
@@ -1556,9 +1598,9 @@
15561598 }
15571599 },
15581600 "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
1559- "version": "4.1.17",
1560- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.17.tgz",
1561- "integrity": "sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==",
1601+ "version": "4.1.18",
1602+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz",
1603+ "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==",
15621604 "cpu": [
15631605 "arm64"
15641606 ],
@@ -1573,9 +1615,9 @@
15731615 }
15741616 },
15751617 "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
1576- "version": "4.1.17",
1577- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.17.tgz",
1578- "integrity": "sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==",
1618+ "version": "4.1.18",
1619+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz",
1620+ "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==",
15791621 "cpu": [
15801622 "x64"
15811623 ],
@@ -1590,9 +1632,9 @@
15901632 }
15911633 },
15921634 "node_modules/@tailwindcss/oxide-linux-x64-musl": {
1593- "version": "4.1.17",
1594- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.17.tgz",
1595- "integrity": "sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==",
1635+ "version": "4.1.18",
1636+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz",
1637+ "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==",
15961638 "cpu": [
15971639 "x64"
15981640 ],
@@ -1607,9 +1649,9 @@
16071649 }
16081650 },
16091651 "node_modules/@tailwindcss/oxide-wasm32-wasi": {
1610- "version": "4.1.17",
1611- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.17.tgz",
1612- "integrity": "sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==",
1652+ "version": "4.1.18",
1653+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz",
1654+ "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==",
16131655 "bundleDependencies": [
16141656 "@napi-rs/wasm-runtime",
16151657 "@emnapi/core",
@@ -1625,10 +1667,10 @@
16251667 "license": "MIT",
16261668 "optional": true,
16271669 "dependencies": {
1628- "@emnapi/core": "^1.6.0",
1629- "@emnapi/runtime": "^1.6.0",
1670+ "@emnapi/core": "^1.7.1",
1671+ "@emnapi/runtime": "^1.7.1",
16301672 "@emnapi/wasi-threads": "^1.1.0",
1631- "@napi-rs/wasm-runtime": "^1.0.7",
1673+ "@napi-rs/wasm-runtime": "^1.1.0",
16321674 "@tybys/wasm-util": "^0.10.1",
16331675 "tslib": "^2.4.0"
16341676 },
@@ -1637,9 +1679,9 @@
16371679 }
16381680 },
16391681 "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
1640- "version": "4.1.17",
1641- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.17.tgz",
1642- "integrity": "sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==",
1682+ "version": "4.1.18",
1683+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz",
1684+ "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==",
16431685 "cpu": [
16441686 "arm64"
16451687 ],
@@ -1654,9 +1696,9 @@
16541696 }
16551697 },
16561698 "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
1657- "version": "4.1.17",
1658- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.17.tgz",
1659- "integrity": "sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==",
1699+ "version": "4.1.18",
1700+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz",
1701+ "integrity": "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==",
16601702 "cpu": [
16611703 "x64"
16621704 ],
@@ -1671,17 +1713,17 @@
16711713 }
16721714 },
16731715 "node_modules/@tailwindcss/postcss": {
1674- "version": "4.1.17",
1675- "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.17.tgz",
1676- "integrity": "sha512-+nKl9N9mN5uJ+M7dBOOCzINw94MPstNR/GtIhz1fpZysxL/4a+No64jCBD6CPN+bIHWFx3KWuu8XJRrj/572Dw==",
1716+ "version": "4.1.18",
1717+ "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.18.tgz",
1718+ "integrity": "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==",
16771719 "dev": true,
16781720 "license": "MIT",
16791721 "dependencies": {
16801722 "@alloc/quick-lru": "^5.2.0",
1681- "@tailwindcss/node": "4.1.17",
1682- "@tailwindcss/oxide": "4.1.17",
1723+ "@tailwindcss/node": "4.1.18",
1724+ "@tailwindcss/oxide": "4.1.18",
16831725 "postcss": "^8.4.41",
1684- "tailwindcss": "4.1.17"
1726+ "tailwindcss": "4.1.18"
16851727 }
16861728 },
16871729 "node_modules/@types/estree": {
@@ -1691,9 +1733,9 @@
16911733 "license": "MIT"
16921734 },
16931735 "node_modules/@types/node": {
1694- "version": "20.19.25",
1695- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.25.tgz",
1696- "integrity": "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==",
1736+ "version": "20.19.30",
1737+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz",
1738+ "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==",
16971739 "dev": true,
16981740 "license": "MIT",
16991741 "peer": true,
@@ -1766,15 +1808,15 @@
17661808 }
17671809 },
17681810 "node_modules/@typescript-eslint/project-service": {
1769- "version": "8.48.1",
1770- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.1.tgz",
1771- "integrity": "sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==",
1811+ "version": "8.53.1",
1812+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.53.1.tgz",
1813+ "integrity": "sha512-WYC4FB5Ra0xidsmlPb+1SsnaSKPmS3gsjIARwbEkHkoWloQmuzcfypljaJcR78uyLA1h8sHdWWPHSLDI+MtNog==",
17721814 "dev": true,
17731815 "license": "MIT",
17741816 "dependencies": {
1775- "@typescript-eslint/tsconfig-utils": "^8.48.1",
1776- "@typescript-eslint/types": "^8.48.1",
1777- "debug": "^4.3.4"
1817+ "@typescript-eslint/tsconfig-utils": "^8.53.1",
1818+ "@typescript-eslint/types": "^8.53.1",
1819+ "debug": "^4.4.3"
17781820 },
17791821 "engines": {
17801822 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1788,9 +1830,9 @@
17881830 }
17891831 },
17901832 "node_modules/@typescript-eslint/project-service/node_modules/@typescript-eslint/types": {
1791- "version": "8.48.1",
1792- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.1.tgz",
1793- "integrity": "sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==",
1833+ "version": "8.53.1",
1834+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.53.1.tgz",
1835+ "integrity": "sha512-jr/swrr2aRmUAUjW5/zQHbMaui//vQlsZcJKijZf3M26bnmLj8LyZUpj8/Rd6uzaek06OWsqdofN/Thenm5O8A==",
17941836 "dev": true,
17951837 "license": "MIT",
17961838 "engines": {
@@ -1820,9 +1862,9 @@
18201862 }
18211863 },
18221864 "node_modules/@typescript-eslint/tsconfig-utils": {
1823- "version": "8.48.1",
1824- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.1.tgz",
1825- "integrity": "sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==",
1865+ "version": "8.53.1",
1866+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.53.1.tgz",
1867+ "integrity": "sha512-qfvLXS6F6b1y43pnf0pPbXJ+YoXIC7HKg0UGZ27uMIemKMKA6XH2DTxsEDdpdN29D+vHV07x/pnlPNVLhdhWiA==",
18261868 "dev": true,
18271869 "license": "MIT",
18281870 "engines": {
@@ -2048,9 +2090,9 @@
20482090 }
20492091 },
20502092 "node_modules/autoprefixer": {
2051- "version": "10.4.22",
2052- "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.22.tgz",
2053- "integrity": "sha512-ARe0v/t9gO28Bznv6GgqARmVqcWOV3mfgUPn9becPHMiD3o9BwlRgaeccZnwTpZ7Zwqrm+c1sUSsMxIzQzc8Xg==",
2093+ "version": "10.4.23",
2094+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.23.tgz",
2095+ "integrity": "sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==",
20542096 "dev": true,
20552097 "funding": [
20562098 {
@@ -2068,10 +2110,9 @@
20682110 ],
20692111 "license": "MIT",
20702112 "dependencies": {
2071- "browserslist": "^4.27.0",
2072- "caniuse-lite": "^1.0.30001754",
2113+ "browserslist": "^4.28.1",
2114+ "caniuse-lite": "^1.0.30001760",
20732115 "fraction.js": "^5.3.4",
2074- "normalize-range": "^0.1.2",
20752116 "picocolors": "^1.1.1",
20762117 "postcss-value-parser": "^4.2.0"
20772118 },
@@ -2102,9 +2143,9 @@
21022143 "license": "MIT"
21032144 },
21042145 "node_modules/baseline-browser-mapping": {
2105- "version": "2.9.3",
2106- "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.3.tgz",
2107- "integrity": "sha512-8QdH6czo+G7uBsNo0GiUfouPN1lRzKdJTGnKXwe12gkFbnnOUaUKGN55dMkfy+mnxmvjwl9zcI4VncczcVXDhA==",
2146+ "version": "2.9.17",
2147+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.17.tgz",
2148+ "integrity": "sha512-agD0MgJFUP/4nvjqzIB29zRPUuCF7Ge6mEv9s8dHrtYD7QWXRcx75rOADE/d5ah1NI+0vkDl0yorDd5U852IQQ==",
21082149 "dev": true,
21092150 "license": "Apache-2.0",
21102151 "bin": {
@@ -2112,9 +2153,9 @@
21122153 }
21132154 },
21142155 "node_modules/bits-ui": {
2115- "version": "2.14.4",
2116- "resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-2.14.4.tgz",
2117- "integrity": "sha512-W6kenhnbd/YVvur+DKkaVJ6GldE53eLewur5AhUCqslYQ0vjZr8eWlOfwZnMiPB+PF5HMVqf61vXBvmyrAmPWg==",
2156+ "version": "2.15.4",
2157+ "resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-2.15.4.tgz",
2158+ "integrity": "sha512-7H9YUfp03KOk1LVDh8wPYSRPxlZgG/GRWLNSA8QC73/8Z8ytun+DWJhIuibyFyz7A0cP/RANVcB4iDrbY8q+Og==",
21182159 "license": "MIT",
21192160 "dependencies": {
21202161 "@floating-ui/core": "^1.7.1",
@@ -2204,9 +2245,9 @@
22042245 }
22052246 },
22062247 "node_modules/caniuse-lite": {
2207- "version": "1.0.30001759",
2208- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001759.tgz",
2209- "integrity": "sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==",
2248+ "version": "1.0.30001766",
2249+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz",
2250+ "integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==",
22102251 "dev": true,
22112252 "funding": [
22122253 {
@@ -2360,22 +2401,19 @@
23602401 }
23612402 },
23622403 "node_modules/detect-libc": {
2363- "version": "1.0.3",
2364- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
2365- "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
2404+ "version": "2.1.2",
2405+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
2406+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
23662407 "dev": true,
23672408 "license": "Apache-2.0",
2368- "bin": {
2369- "detect-libc": "bin/detect-libc.js"
2370- },
23712409 "engines": {
2372- "node": ">=0.10"
2410+ "node": ">=8"
23732411 }
23742412 },
23752413 "node_modules/devalue": {
2376- "version": "5.5.0",
2377- "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.5.0.tgz",
2378- "integrity": "sha512-69sM5yrHfFLJt0AZ9QqZXGCPfJ7fQjvpln3Rq5+PS03LD32Ost1Q9N+eEnaQwGRIriKkMImXD56ocjQmfjbV3w==",
2414+ "version": "5.6.2",
2415+ "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.2.tgz",
2416+ "integrity": "sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==",
23792417 "license": "MIT"
23802418 },
23812419 "node_modules/dir-glob": {
@@ -2405,16 +2443,16 @@
24052443 }
24062444 },
24072445 "node_modules/electron-to-chromium": {
2408- "version": "1.5.266",
2409- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.266.tgz",
2410- "integrity": "sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg==",
2446+ "version": "1.5.277",
2447+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.277.tgz",
2448+ "integrity": "sha512-wKXFZw4erWmmOz5N/grBoJ2XrNJGDFMu2+W5ACHza5rHtvsqrK4gb6rnLC7XxKB9WlJ+RmyQatuEXmtm86xbnw==",
24112449 "dev": true,
24122450 "license": "ISC"
24132451 },
24142452 "node_modules/enhanced-resolve": {
2415- "version": "5.18.3",
2416- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
2417- "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
2453+ "version": "5.18.4",
2454+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz",
2455+ "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==",
24182456 "dev": true,
24192457 "license": "MIT",
24202458 "dependencies": {
@@ -2624,9 +2662,9 @@
26242662 }
26252663 },
26262664 "node_modules/esquery": {
2627- "version": "1.6.0",
2628- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
2629- "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
2665+ "version": "1.7.0",
2666+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
2667+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
26302668 "dev": true,
26312669 "license": "BSD-3-Clause",
26322670 "dependencies": {
@@ -2637,9 +2675,9 @@
26372675 }
26382676 },
26392677 "node_modules/esrap": {
2640- "version": "2.2.1",
2641- "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.1.tgz",
2642- "integrity": "sha512-GiYWG34AN/4CUyaWAgunGt0Rxvr1PTMlGC0vvEov/uOQYWne2bpN03Um+k8jT+q3op33mKouP2zeJ6OlM+qeUg==",
2678+ "version": "2.2.2",
2679+ "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.2.tgz",
2680+ "integrity": "sha512-zA6497ha+qKvoWIK+WM9NAh5ni17sKZKhbS5B3PoYbBvaYHZWoS33zmFybmyqpn07RLUxSmn+RCls2/XF+d0oQ==",
26432681 "license": "MIT",
26442682 "dependencies": {
26452683 "@jridgewell/sourcemap-codec": "^1.4.15"
@@ -2730,15 +2768,33 @@
27302768 "license": "MIT"
27312769 },
27322770 "node_modules/fastq": {
2733- "version": "1.19.1",
2734- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
2735- "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
2771+ "version": "1.20.1",
2772+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
2773+ "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
27362774 "dev": true,
27372775 "license": "ISC",
27382776 "dependencies": {
27392777 "reusify": "^1.0.4"
27402778 }
27412779 },
2780+ "node_modules/fdir": {
2781+ "version": "6.5.0",
2782+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
2783+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
2784+ "dev": true,
2785+ "license": "MIT",
2786+ "engines": {
2787+ "node": ">=12.0.0"
2788+ },
2789+ "peerDependencies": {
2790+ "picomatch": "^3 || ^4"
2791+ },
2792+ "peerDependenciesMeta": {
2793+ "picomatch": {
2794+ "optional": true
2795+ }
2796+ }
2797+ },
27422798 "node_modules/file-entry-cache": {
27432799 "version": "6.0.1",
27442800 "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -3426,16 +3482,6 @@
34263482 "url": "https://opencollective.com/parcel"
34273483 }
34283484 },
3429- "node_modules/lightningcss/node_modules/detect-libc": {
3430- "version": "2.1.2",
3431- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
3432- "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
3433- "dev": true,
3434- "license": "Apache-2.0",
3435- "engines": {
3436- "node": ">=8"
3437- }
3438- },
34393485 "node_modules/locate-character": {
34403486 "version": "3.0.0",
34413487 "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
@@ -3507,6 +3553,19 @@
35073553 "node": ">=8.6"
35083554 }
35093555 },
3556+ "node_modules/micromatch/node_modules/picomatch": {
3557+ "version": "2.3.1",
3558+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
3559+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
3560+ "dev": true,
3561+ "license": "MIT",
3562+ "engines": {
3563+ "node": ">=8.6"
3564+ },
3565+ "funding": {
3566+ "url": "https://github.com/sponsors/jonschlinkert"
3567+ }
3568+ },
35103569 "node_modules/minimatch": {
35113570 "version": "9.0.5",
35123571 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
@@ -3643,16 +3702,6 @@
36433702 "dev": true,
36443703 "license": "MIT"
36453704 },
3646- "node_modules/normalize-range": {
3647- "version": "0.1.2",
3648- "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
3649- "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
3650- "dev": true,
3651- "license": "MIT",
3652- "engines": {
3653- "node": ">=0.10.0"
3654- }
3655- },
36563705 "node_modules/once": {
36573706 "version": "1.4.0",
36583707 "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -3774,13 +3823,13 @@
37743823 "license": "ISC"
37753824 },
37763825 "node_modules/picomatch": {
3777- "version": "2.3.1",
3778- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
3779- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
3826+ "version": "4.0.3",
3827+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
3828+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
37803829 "dev": true,
37813830 "license": "MIT",
37823831 "engines": {
3783- "node": ">=8.6"
3832+ "node": ">=12"
37843833 },
37853834 "funding": {
37863835 "url": "https://github.com/sponsors/jonschlinkert"
@@ -3917,9 +3966,9 @@
39173966 }
39183967 },
39193968 "node_modules/rollup": {
3920- "version": "4.53.3",
3921- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz",
3922- "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==",
3969+ "version": "4.56.0",
3970+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.56.0.tgz",
3971+ "integrity": "sha512-9FwVqlgUHzbXtDg9RCMgodF3Ua4Na6Gau+Sdt9vyCN4RhHfVKX2DCHy3BjMLTDd47ITDhYAnTwGulWTblJSDLg==",
39233972 "dev": true,
39243973 "license": "MIT",
39253974 "dependencies": {
@@ -3933,28 +3982,31 @@
39333982 "npm": ">=8.0.0"
39343983 },
39353984 "optionalDependencies": {
3936- "@rollup/rollup-android-arm-eabi": "4.53.3",
3937- "@rollup/rollup-android-arm64": "4.53.3",
3938- "@rollup/rollup-darwin-arm64": "4.53.3",
3939- "@rollup/rollup-darwin-x64": "4.53.3",
3940- "@rollup/rollup-freebsd-arm64": "4.53.3",
3941- "@rollup/rollup-freebsd-x64": "4.53.3",
3942- "@rollup/rollup-linux-arm-gnueabihf": "4.53.3",
3943- "@rollup/rollup-linux-arm-musleabihf": "4.53.3",
3944- "@rollup/rollup-linux-arm64-gnu": "4.53.3",
3945- "@rollup/rollup-linux-arm64-musl": "4.53.3",
3946- "@rollup/rollup-linux-loong64-gnu": "4.53.3",
3947- "@rollup/rollup-linux-ppc64-gnu": "4.53.3",
3948- "@rollup/rollup-linux-riscv64-gnu": "4.53.3",
3949- "@rollup/rollup-linux-riscv64-musl": "4.53.3",
3950- "@rollup/rollup-linux-s390x-gnu": "4.53.3",
3951- "@rollup/rollup-linux-x64-gnu": "4.53.3",
3952- "@rollup/rollup-linux-x64-musl": "4.53.3",
3953- "@rollup/rollup-openharmony-arm64": "4.53.3",
3954- "@rollup/rollup-win32-arm64-msvc": "4.53.3",
3955- "@rollup/rollup-win32-ia32-msvc": "4.53.3",
3956- "@rollup/rollup-win32-x64-gnu": "4.53.3",
3957- "@rollup/rollup-win32-x64-msvc": "4.53.3",
3985+ "@rollup/rollup-android-arm-eabi": "4.56.0",
3986+ "@rollup/rollup-android-arm64": "4.56.0",
3987+ "@rollup/rollup-darwin-arm64": "4.56.0",
3988+ "@rollup/rollup-darwin-x64": "4.56.0",
3989+ "@rollup/rollup-freebsd-arm64": "4.56.0",
3990+ "@rollup/rollup-freebsd-x64": "4.56.0",
3991+ "@rollup/rollup-linux-arm-gnueabihf": "4.56.0",
3992+ "@rollup/rollup-linux-arm-musleabihf": "4.56.0",
3993+ "@rollup/rollup-linux-arm64-gnu": "4.56.0",
3994+ "@rollup/rollup-linux-arm64-musl": "4.56.0",
3995+ "@rollup/rollup-linux-loong64-gnu": "4.56.0",
3996+ "@rollup/rollup-linux-loong64-musl": "4.56.0",
3997+ "@rollup/rollup-linux-ppc64-gnu": "4.56.0",
3998+ "@rollup/rollup-linux-ppc64-musl": "4.56.0",
3999+ "@rollup/rollup-linux-riscv64-gnu": "4.56.0",
4000+ "@rollup/rollup-linux-riscv64-musl": "4.56.0",
4001+ "@rollup/rollup-linux-s390x-gnu": "4.56.0",
4002+ "@rollup/rollup-linux-x64-gnu": "4.56.0",
4003+ "@rollup/rollup-linux-x64-musl": "4.56.0",
4004+ "@rollup/rollup-openbsd-x64": "4.56.0",
4005+ "@rollup/rollup-openharmony-arm64": "4.56.0",
4006+ "@rollup/rollup-win32-arm64-msvc": "4.56.0",
4007+ "@rollup/rollup-win32-ia32-msvc": "4.56.0",
4008+ "@rollup/rollup-win32-x64-gnu": "4.56.0",
4009+ "@rollup/rollup-win32-x64-msvc": "4.56.0",
39584010 "fsevents": "~2.3.2"
39594011 }
39604012 },
@@ -4124,9 +4176,9 @@
41244176 }
41254177 },
41264178 "node_modules/svelte": {
4127- "version": "5.45.5",
4128- "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.45.5.tgz",
4129- "integrity": "sha512-2074U+vObO5Zs8/qhxtBwdi6ZXNIhEBTzNmUFjiZexLxTdt9vq96D/0pnQELl6YcpLMD7pZ2dhXKByfGS8SAdg==",
4179+ "version": "5.48.0",
4180+ "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.48.0.tgz",
4181+ "integrity": "sha512-+NUe82VoFP1RQViZI/esojx70eazGF4u0O/9ucqZ4rPcOZD+n5EVp17uYsqwdzjUjZyTpGKunHbDziW6AIAVkQ==",
41304182 "license": "MIT",
41314183 "peer": true,
41324184 "dependencies": {
@@ -4138,7 +4190,7 @@
41384190 "aria-query": "^5.3.1",
41394191 "axobject-query": "^4.1.0",
41404192 "clsx": "^2.1.1",
4141- "devalue": "^5.5.0",
4193+ "devalue": "^5.6.2",
41424194 "esm-env": "^1.2.1",
41434195 "esrap": "^2.2.1",
41444196 "is-reference": "^3.0.3",
@@ -4151,15 +4203,18 @@
41514203 }
41524204 },
41534205 "node_modules/svelte-awesome-color-picker": {
4154- "version": "4.1.0",
4155- "resolved": "https://registry.npmjs.org/svelte-awesome-color-picker/-/svelte-awesome-color-picker-4.1.0.tgz",
4156- "integrity": "sha512-afiSB3eTBlqu96f4+rjBvqG3eCaLwuneNYHe587Wr4Ien6yQWeztGZunPT0FmiI7wFFBVNUlJQLYutII8LfQUg==",
4206+ "version": "4.1.1",
4207+ "resolved": "https://registry.npmjs.org/svelte-awesome-color-picker/-/svelte-awesome-color-picker-4.1.1.tgz",
4208+ "integrity": "sha512-k4APFGBFN8EpvUS0UJfdlqj8xDekMbqGBwnDYBK1QCY8kcTXSO8c7SitEk70MkiYOIByOgXlHcjaipy6H7dpAw==",
41574209 "dev": true,
41584210 "license": "MIT",
41594211 "dependencies": {
41604212 "colord": "^2.9.3",
41614213 "svelte-awesome-slider": "2.0.0"
41624214 },
4215+ "engines": {
4216+ "node": ">=24"
4217+ },
41634218 "peerDependencies": {
41644219 "svelte": "^5.0.0"
41654220 }
@@ -4175,9 +4230,9 @@
41754230 }
41764231 },
41774232 "node_modules/svelte-check": {
4178- "version": "4.3.4",
4179- "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.3.4.tgz",
4180- "integrity": "sha512-DVWvxhBrDsd+0hHWKfjP99lsSXASeOhHJYyuKOFYJcP7ThfSCKgjVarE8XfuMWpS5JV3AlDf+iK1YGGo2TACdw==",
4233+ "version": "4.3.5",
4234+ "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.3.5.tgz",
4235+ "integrity": "sha512-e4VWZETyXaKGhpkxOXP+B/d0Fp/zKViZoJmneZWe/05Y2aqSKj3YN2nLfYPJBQ87WEiY4BQCQ9hWGu9mPT1a1Q==",
41814236 "dev": true,
41824237 "license": "MIT",
41834238 "dependencies": {
@@ -4198,24 +4253,6 @@
41984253 "typescript": ">=5.0.0"
41994254 }
42004255 },
4201- "node_modules/svelte-check/node_modules/fdir": {
4202- "version": "6.5.0",
4203- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
4204- "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
4205- "dev": true,
4206- "license": "MIT",
4207- "engines": {
4208- "node": ">=12.0.0"
4209- },
4210- "peerDependencies": {
4211- "picomatch": "^3 || ^4"
4212- },
4213- "peerDependenciesMeta": {
4214- "picomatch": {
4215- "optional": true
4216- }
4217- }
4218- },
42194256 "node_modules/svelte-toolbelt": {
42204257 "version": "0.10.6",
42214258 "resolved": "https://registry.npmjs.org/svelte-toolbelt/-/svelte-toolbelt-0.10.6.tgz",
@@ -4237,9 +4274,9 @@
42374274 }
42384275 },
42394276 "node_modules/tabbable": {
4240- "version": "6.3.0",
4241- "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.3.0.tgz",
4242- "integrity": "sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==",
4277+ "version": "6.4.0",
4278+ "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz",
4279+ "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==",
42434280 "license": "MIT"
42444281 },
42454282 "node_modules/tailwind-merge": {
@@ -4274,9 +4311,9 @@
42744311 }
42754312 },
42764313 "node_modules/tailwindcss": {
4277- "version": "4.1.17",
4278- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz",
4279- "integrity": "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==",
4314+ "version": "4.1.18",
4315+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
4316+ "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
42804317 "dev": true,
42814318 "license": "MIT",
42824319 "peer": true
@@ -4319,38 +4356,6 @@
43194356 "url": "https://github.com/sponsors/SuperchupuDev"
43204357 }
43214358 },
4322- "node_modules/tinyglobby/node_modules/fdir": {
4323- "version": "6.5.0",
4324- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
4325- "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
4326- "dev": true,
4327- "license": "MIT",
4328- "engines": {
4329- "node": ">=12.0.0"
4330- },
4331- "peerDependencies": {
4332- "picomatch": "^3 || ^4"
4333- },
4334- "peerDependenciesMeta": {
4335- "picomatch": {
4336- "optional": true
4337- }
4338- }
4339- },
4340- "node_modules/tinyglobby/node_modules/picomatch": {
4341- "version": "4.0.3",
4342- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
4343- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
4344- "dev": true,
4345- "license": "MIT",
4346- "peer": true,
4347- "engines": {
4348- "node": ">=12"
4349- },
4350- "funding": {
4351- "url": "https://github.com/sponsors/jonschlinkert"
4352- }
4353- },
43544359 "node_modules/to-regex-range": {
43554360 "version": "5.0.1",
43564361 "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -4435,16 +4440,16 @@
44354440 }
44364441 },
44374442 "node_modules/typescript-eslint": {
4438- "version": "8.48.1",
4439- "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.48.1.tgz",
4440- "integrity": "sha512-FbOKN1fqNoXp1hIl5KYpObVrp0mCn+CLgn479nmu2IsRMrx2vyv74MmsBLVlhg8qVwNFGbXSp8fh1zp8pEoC2A==",
4443+ "version": "8.53.1",
4444+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.53.1.tgz",
4445+ "integrity": "sha512-gB+EVQfP5RDElh9ittfXlhZJdjSU4jUSTyE2+ia8CYyNvet4ElfaLlAIqDvQV9JPknKx0jQH1racTYe/4LaLSg==",
44414446 "dev": true,
44424447 "license": "MIT",
44434448 "dependencies": {
4444- "@typescript-eslint/eslint-plugin": "8.48.1",
4445- "@typescript-eslint/parser": "8.48.1",
4446- "@typescript-eslint/typescript-estree": "8.48.1",
4447- "@typescript-eslint/utils": "8.48.1"
4449+ "@typescript-eslint/eslint-plugin": "8.53.1",
4450+ "@typescript-eslint/parser": "8.53.1",
4451+ "@typescript-eslint/typescript-estree": "8.53.1",
4452+ "@typescript-eslint/utils": "8.53.1"
44484453 },
44494454 "engines": {
44504455 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4459,21 +4464,20 @@
44594464 }
44604465 },
44614466 "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": {
4462- "version": "8.48.1",
4463- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.1.tgz",
4464- "integrity": "sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==",
4467+ "version": "8.53.1",
4468+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.1.tgz",
4469+ "integrity": "sha512-cFYYFZ+oQFi6hUnBTbLRXfTJiaQtYE3t4O692agbBl+2Zy+eqSKWtPjhPXJu1G7j4RLjKgeJPDdq3EqOwmX5Ag==",
44654470 "dev": true,
44664471 "license": "MIT",
44674472 "dependencies": {
4468- "@eslint-community/regexpp": "^4.10.0",
4469- "@typescript-eslint/scope-manager": "8.48.1",
4470- "@typescript-eslint/type-utils": "8.48.1",
4471- "@typescript-eslint/utils": "8.48.1",
4472- "@typescript-eslint/visitor-keys": "8.48.1",
4473- "graphemer": "^1.4.0",
4474- "ignore": "^7.0.0",
4473+ "@eslint-community/regexpp": "^4.12.2",
4474+ "@typescript-eslint/scope-manager": "8.53.1",
4475+ "@typescript-eslint/type-utils": "8.53.1",
4476+ "@typescript-eslint/utils": "8.53.1",
4477+ "@typescript-eslint/visitor-keys": "8.53.1",
4478+ "ignore": "^7.0.5",
44754479 "natural-compare": "^1.4.0",
4476- "ts-api-utils": "^2.1.0"
4480+ "ts-api-utils": "^2.4.0"
44774481 },
44784482 "engines": {
44794483 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4483,24 +4487,24 @@
44834487 "url": "https://opencollective.com/typescript-eslint"
44844488 },
44854489 "peerDependencies": {
4486- "@typescript-eslint/parser": "^8.48.1",
4490+ "@typescript-eslint/parser": "^8.53.1",
44874491 "eslint": "^8.57.0 || ^9.0.0",
44884492 "typescript": ">=4.8.4 <6.0.0"
44894493 }
44904494 },
44914495 "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": {
4492- "version": "8.48.1",
4493- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.1.tgz",
4494- "integrity": "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==",
4496+ "version": "8.53.1",
4497+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.53.1.tgz",
4498+ "integrity": "sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==",
44954499 "dev": true,
44964500 "license": "MIT",
44974501 "peer": true,
44984502 "dependencies": {
4499- "@typescript-eslint/scope-manager": "8.48.1",
4500- "@typescript-eslint/types": "8.48.1",
4501- "@typescript-eslint/typescript-estree": "8.48.1",
4502- "@typescript-eslint/visitor-keys": "8.48.1",
4503- "debug": "^4.3.4"
4503+ "@typescript-eslint/scope-manager": "8.53.1",
4504+ "@typescript-eslint/types": "8.53.1",
4505+ "@typescript-eslint/typescript-estree": "8.53.1",
4506+ "@typescript-eslint/visitor-keys": "8.53.1",
4507+ "debug": "^4.4.3"
45044508 },
45054509 "engines": {
45064510 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4515,14 +4519,14 @@
45154519 }
45164520 },
45174521 "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": {
4518- "version": "8.48.1",
4519- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.1.tgz",
4520- "integrity": "sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==",
4522+ "version": "8.53.1",
4523+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.53.1.tgz",
4524+ "integrity": "sha512-Lu23yw1uJMFY8cUeq7JlrizAgeQvWugNQzJp8C3x8Eo5Jw5Q2ykMdiiTB9vBVOOUBysMzmRRmUfwFrZuI2C4SQ==",
45214525 "dev": true,
45224526 "license": "MIT",
45234527 "dependencies": {
4524- "@typescript-eslint/types": "8.48.1",
4525- "@typescript-eslint/visitor-keys": "8.48.1"
4528+ "@typescript-eslint/types": "8.53.1",
4529+ "@typescript-eslint/visitor-keys": "8.53.1"
45264530 },
45274531 "engines": {
45284532 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4533,17 +4537,17 @@
45334537 }
45344538 },
45354539 "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": {
4536- "version": "8.48.1",
4537- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.1.tgz",
4538- "integrity": "sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==",
4540+ "version": "8.53.1",
4541+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.53.1.tgz",
4542+ "integrity": "sha512-MOrdtNvyhy0rHyv0ENzub1d4wQYKb2NmIqG7qEqPWFW7Mpy2jzFC3pQ2yKDvirZB7jypm5uGjF2Qqs6OIqu47w==",
45394543 "dev": true,
45404544 "license": "MIT",
45414545 "dependencies": {
4542- "@typescript-eslint/types": "8.48.1",
4543- "@typescript-eslint/typescript-estree": "8.48.1",
4544- "@typescript-eslint/utils": "8.48.1",
4545- "debug": "^4.3.4",
4546- "ts-api-utils": "^2.1.0"
4546+ "@typescript-eslint/types": "8.53.1",
4547+ "@typescript-eslint/typescript-estree": "8.53.1",
4548+ "@typescript-eslint/utils": "8.53.1",
4549+ "debug": "^4.4.3",
4550+ "ts-api-utils": "^2.4.0"
45474551 },
45484552 "engines": {
45494553 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4558,9 +4562,9 @@
45584562 }
45594563 },
45604564 "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": {
4561- "version": "8.48.1",
4562- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.1.tgz",
4563- "integrity": "sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==",
4565+ "version": "8.53.1",
4566+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.53.1.tgz",
4567+ "integrity": "sha512-jr/swrr2aRmUAUjW5/zQHbMaui//vQlsZcJKijZf3M26bnmLj8LyZUpj8/Rd6uzaek06OWsqdofN/Thenm5O8A==",
45644568 "dev": true,
45654569 "license": "MIT",
45664570 "engines": {
@@ -4572,21 +4576,21 @@
45724576 }
45734577 },
45744578 "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": {
4575- "version": "8.48.1",
4576- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.1.tgz",
4577- "integrity": "sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==",
4579+ "version": "8.53.1",
4580+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.53.1.tgz",
4581+ "integrity": "sha512-RGlVipGhQAG4GxV1s34O91cxQ/vWiHJTDHbXRr0li2q/BGg3RR/7NM8QDWgkEgrwQYCvmJV9ichIwyoKCQ+DTg==",
45784582 "dev": true,
45794583 "license": "MIT",
45804584 "dependencies": {
4581- "@typescript-eslint/project-service": "8.48.1",
4582- "@typescript-eslint/tsconfig-utils": "8.48.1",
4583- "@typescript-eslint/types": "8.48.1",
4584- "@typescript-eslint/visitor-keys": "8.48.1",
4585- "debug": "^4.3.4",
4586- "minimatch": "^9.0.4",
4587- "semver": "^7.6.0",
4585+ "@typescript-eslint/project-service": "8.53.1",
4586+ "@typescript-eslint/tsconfig-utils": "8.53.1",
4587+ "@typescript-eslint/types": "8.53.1",
4588+ "@typescript-eslint/visitor-keys": "8.53.1",
4589+ "debug": "^4.4.3",
4590+ "minimatch": "^9.0.5",
4591+ "semver": "^7.7.3",
45884592 "tinyglobby": "^0.2.15",
4589- "ts-api-utils": "^2.1.0"
4593+ "ts-api-utils": "^2.4.0"
45904594 },
45914595 "engines": {
45924596 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4600,16 +4604,16 @@
46004604 }
46014605 },
46024606 "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": {
4603- "version": "8.48.1",
4604- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.1.tgz",
4605- "integrity": "sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==",
4607+ "version": "8.53.1",
4608+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.53.1.tgz",
4609+ "integrity": "sha512-c4bMvGVWW4hv6JmDUEG7fSYlWOl3II2I4ylt0NM+seinYQlZMQIaKaXIIVJWt9Ofh6whrpM+EdDQXKXjNovvrg==",
46064610 "dev": true,
46074611 "license": "MIT",
46084612 "dependencies": {
4609- "@eslint-community/eslint-utils": "^4.7.0",
4610- "@typescript-eslint/scope-manager": "8.48.1",
4611- "@typescript-eslint/types": "8.48.1",
4612- "@typescript-eslint/typescript-estree": "8.48.1"
4613+ "@eslint-community/eslint-utils": "^4.9.1",
4614+ "@typescript-eslint/scope-manager": "8.53.1",
4615+ "@typescript-eslint/types": "8.53.1",
4616+ "@typescript-eslint/typescript-estree": "8.53.1"
46134617 },
46144618 "engines": {
46154619 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4624,13 +4628,13 @@
46244628 }
46254629 },
46264630 "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": {
4627- "version": "8.48.1",
4628- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.1.tgz",
4629- "integrity": "sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==",
4631+ "version": "8.53.1",
4632+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.53.1.tgz",
4633+ "integrity": "sha512-oy+wV7xDKFPRyNggmXuZQSBzvoLnpmJs+GhzRhPjrxl2b/jIlyjVokzm47CZCDUdXKr2zd7ZLodPfOBpOPyPlg==",
46304634 "dev": true,
46314635 "license": "MIT",
46324636 "dependencies": {
4633- "@typescript-eslint/types": "8.48.1",
4637+ "@typescript-eslint/types": "8.53.1",
46344638 "eslint-visitor-keys": "^4.2.1"
46354639 },
46364640 "engines": {
@@ -4665,9 +4669,9 @@
46654669 }
46664670 },
46674671 "node_modules/typescript-eslint/node_modules/ts-api-utils": {
4668- "version": "2.1.0",
4669- "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
4670- "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
4672+ "version": "2.4.0",
4673+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz",
4674+ "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==",
46714675 "dev": true,
46724676 "license": "MIT",
46734677 "engines": {
@@ -4685,9 +4689,9 @@
46854689 "license": "MIT"
46864690 },
46874691 "node_modules/update-browserslist-db": {
4688- "version": "1.2.2",
4689- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz",
4690- "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==",
4692+ "version": "1.2.3",
4693+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
4694+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
46914695 "dev": true,
46924696 "funding": [
46934697 {
@@ -442,9 +442,9 @@
442 }442 }
443 },443 },
444 "node_modules/@eslint-community/eslint-utils": {444 "node_modules/@eslint-community/eslint-utils": {
445- "version": "4.9.0",445+ "version": "4.9.1",
446- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",446+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
447- "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",447+ "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
448 "dev": true,448 "dev": true,
449 "license": "MIT",449 "license": "MIT",
450 "dependencies": {450 "dependencies": {
@@ -719,17 +719,17 @@
719 }719 }
720 },720 },
721 "node_modules/@parcel/watcher": {721 "node_modules/@parcel/watcher": {
722- "version": "2.5.1",722+ "version": "2.5.4",
723- "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",723+ "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.4.tgz",
724- "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",724+ "integrity": "sha512-WYa2tUVV5HiArWPB3ydlOc4R2ivq0IDrlqhMi3l7mVsFEXNcTfxYFPIHXHXIh/ca/y/V5N4E1zecyxdIBjYnkQ==",
725 "dev": true,725 "dev": true,
726 "hasInstallScript": true,726 "hasInstallScript": true,
727 "license": "MIT",727 "license": "MIT",
728 "dependencies": {728 "dependencies": {
729- "detect-libc": "^1.0.3",729+ "detect-libc": "^2.0.3",
730 "is-glob": "^4.0.3",730 "is-glob": "^4.0.3",
731- "micromatch": "^4.0.5",731+ "node-addon-api": "^7.0.0",
732- "node-addon-api": "^7.0.0"732+ "picomatch": "^4.0.3"
733 },733 },
734 "engines": {734 "engines": {
735 "node": ">= 10.0.0"735 "node": ">= 10.0.0"
@@ -739,25 +739,25 @@
739 "url": "https://opencollective.com/parcel"739 "url": "https://opencollective.com/parcel"
740 },740 },
741 "optionalDependencies": {741 "optionalDependencies": {
742- "@parcel/watcher-android-arm64": "2.5.1",742+ "@parcel/watcher-android-arm64": "2.5.4",
743- "@parcel/watcher-darwin-arm64": "2.5.1",743+ "@parcel/watcher-darwin-arm64": "2.5.4",
744- "@parcel/watcher-darwin-x64": "2.5.1",744+ "@parcel/watcher-darwin-x64": "2.5.4",
745- "@parcel/watcher-freebsd-x64": "2.5.1",745+ "@parcel/watcher-freebsd-x64": "2.5.4",
746- "@parcel/watcher-linux-arm-glibc": "2.5.1",746+ "@parcel/watcher-linux-arm-glibc": "2.5.4",
747- "@parcel/watcher-linux-arm-musl": "2.5.1",747+ "@parcel/watcher-linux-arm-musl": "2.5.4",
748- "@parcel/watcher-linux-arm64-glibc": "2.5.1",748+ "@parcel/watcher-linux-arm64-glibc": "2.5.4",
749- "@parcel/watcher-linux-arm64-musl": "2.5.1",749+ "@parcel/watcher-linux-arm64-musl": "2.5.4",
750- "@parcel/watcher-linux-x64-glibc": "2.5.1",750+ "@parcel/watcher-linux-x64-glibc": "2.5.4",
751- "@parcel/watcher-linux-x64-musl": "2.5.1",751+ "@parcel/watcher-linux-x64-musl": "2.5.4",
752- "@parcel/watcher-win32-arm64": "2.5.1",752+ "@parcel/watcher-win32-arm64": "2.5.4",
753- "@parcel/watcher-win32-ia32": "2.5.1",753+ "@parcel/watcher-win32-ia32": "2.5.4",
754- "@parcel/watcher-win32-x64": "2.5.1"754+ "@parcel/watcher-win32-x64": "2.5.4"
755 }755 }
756 },756 },
757 "node_modules/@parcel/watcher-android-arm64": {757 "node_modules/@parcel/watcher-android-arm64": {
758- "version": "2.5.1",758+ "version": "2.5.4",
759- "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",759+ "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.4.tgz",
760- "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",760+ "integrity": "sha512-hoh0vx4v+b3BNI7Cjoy2/B0ARqcwVNrzN/n7DLq9ZB4I3lrsvhrkCViJyfTj/Qi5xM9YFiH4AmHGK6pgH1ss7g==",
761 "cpu": [761 "cpu": [
762 "arm64"762 "arm64"
763 ],763 ],
@@ -776,9 +776,9 @@
776 }776 }
777 },777 },
778 "node_modules/@parcel/watcher-darwin-arm64": {778 "node_modules/@parcel/watcher-darwin-arm64": {
779- "version": "2.5.1",779+ "version": "2.5.4",
780- "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",780+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.4.tgz",
781- "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",781+ "integrity": "sha512-kphKy377pZiWpAOyTgQYPE5/XEKVMaj6VUjKT5VkNyUJlr2qZAn8gIc7CPzx+kbhvqHDT9d7EqdOqRXT6vk0zw==",
782 "cpu": [782 "cpu": [
783 "arm64"783 "arm64"
784 ],784 ],
@@ -797,9 +797,9 @@
797 }797 }
798 },798 },
799 "node_modules/@parcel/watcher-darwin-x64": {799 "node_modules/@parcel/watcher-darwin-x64": {
800- "version": "2.5.1",800+ "version": "2.5.4",
801- "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",801+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.4.tgz",
802- "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",802+ "integrity": "sha512-UKaQFhCtNJW1A9YyVz3Ju7ydf6QgrpNQfRZ35wNKUhTQ3dxJ/3MULXN5JN/0Z80V/KUBDGa3RZaKq1EQT2a2gg==",
803 "cpu": [803 "cpu": [
804 "x64"804 "x64"
805 ],805 ],
@@ -818,9 +818,9 @@
818 }818 }
819 },819 },
820 "node_modules/@parcel/watcher-freebsd-x64": {820 "node_modules/@parcel/watcher-freebsd-x64": {
821- "version": "2.5.1",821+ "version": "2.5.4",
822- "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",822+ "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.4.tgz",
823- "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",823+ "integrity": "sha512-Dib0Wv3Ow/m2/ttvLdeI2DBXloO7t3Z0oCp4bAb2aqyqOjKPPGrg10pMJJAQ7tt8P4V2rwYwywkDhUia/FgS+Q==",
824 "cpu": [824 "cpu": [
825 "x64"825 "x64"
826 ],826 ],
@@ -839,9 +839,9 @@
839 }839 }
840 },840 },
841 "node_modules/@parcel/watcher-linux-arm-glibc": {841 "node_modules/@parcel/watcher-linux-arm-glibc": {
842- "version": "2.5.1",842+ "version": "2.5.4",
843- "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",843+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.4.tgz",
844- "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",844+ "integrity": "sha512-I5Vb769pdf7Q7Sf4KNy8Pogl/URRCKu9ImMmnVKYayhynuyGYMzuI4UOWnegQNa2sGpsPSbzDsqbHNMyeyPCgw==",
845 "cpu": [845 "cpu": [
846 "arm"846 "arm"
847 ],847 ],
@@ -860,9 +860,9 @@
860 }860 }
861 },861 },
862 "node_modules/@parcel/watcher-linux-arm-musl": {862 "node_modules/@parcel/watcher-linux-arm-musl": {
863- "version": "2.5.1",863+ "version": "2.5.4",
864- "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",864+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.4.tgz",
865- "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",865+ "integrity": "sha512-kGO8RPvVrcAotV4QcWh8kZuHr9bXi9a3bSZw7kFarYR0+fGliU7hd/zevhjw8fnvIKG3J9EO5G6sXNGCSNMYPQ==",
866 "cpu": [866 "cpu": [
867 "arm"867 "arm"
868 ],868 ],
@@ -881,9 +881,9 @@
881 }881 }
882 },882 },
883 "node_modules/@parcel/watcher-linux-arm64-glibc": {883 "node_modules/@parcel/watcher-linux-arm64-glibc": {
884- "version": "2.5.1",884+ "version": "2.5.4",
885- "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",885+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.4.tgz",
886- "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",886+ "integrity": "sha512-KU75aooXhqGFY2W5/p8DYYHt4hrjHZod8AhcGAmhzPn/etTa+lYCDB2b1sJy3sWJ8ahFVTdy+EbqSBvMx3iFlw==",
887 "cpu": [887 "cpu": [
888 "arm64"888 "arm64"
889 ],889 ],
@@ -902,9 +902,9 @@
902 }902 }
903 },903 },
904 "node_modules/@parcel/watcher-linux-arm64-musl": {904 "node_modules/@parcel/watcher-linux-arm64-musl": {
905- "version": "2.5.1",905+ "version": "2.5.4",
906- "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",906+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.4.tgz",
907- "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",907+ "integrity": "sha512-Qx8uNiIekVutnzbVdrgSanM+cbpDD3boB1f8vMtnuG5Zau4/bdDbXyKwIn0ToqFhIuob73bcxV9NwRm04/hzHQ==",
908 "cpu": [908 "cpu": [
909 "arm64"909 "arm64"
910 ],910 ],
@@ -923,9 +923,9 @@
923 }923 }
924 },924 },
925 "node_modules/@parcel/watcher-linux-x64-glibc": {925 "node_modules/@parcel/watcher-linux-x64-glibc": {
926- "version": "2.5.1",926+ "version": "2.5.4",
927- "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",927+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.4.tgz",
928- "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",928+ "integrity": "sha512-UYBQvhYmgAv61LNUn24qGQdjtycFBKSK3EXr72DbJqX9aaLbtCOO8+1SkKhD/GNiJ97ExgcHBrukcYhVjrnogA==",
929 "cpu": [929 "cpu": [
930 "x64"930 "x64"
931 ],931 ],
@@ -944,9 +944,9 @@
944 }944 }
945 },945 },
946 "node_modules/@parcel/watcher-linux-x64-musl": {946 "node_modules/@parcel/watcher-linux-x64-musl": {
947- "version": "2.5.1",947+ "version": "2.5.4",
948- "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",948+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.4.tgz",
949- "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",949+ "integrity": "sha512-YoRWCVgxv8akZrMhdyVi6/TyoeeMkQ0PGGOf2E4omODrvd1wxniXP+DBynKoHryStks7l+fDAMUBRzqNHrVOpg==",
950 "cpu": [950 "cpu": [
951 "x64"951 "x64"
952 ],952 ],
@@ -965,9 +965,9 @@
965 }965 }
966 },966 },
967 "node_modules/@parcel/watcher-win32-arm64": {967 "node_modules/@parcel/watcher-win32-arm64": {
968- "version": "2.5.1",968+ "version": "2.5.4",
969- "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",969+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.4.tgz",
970- "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",970+ "integrity": "sha512-iby+D/YNXWkiQNYcIhg8P5hSjzXEHaQrk2SLrWOUD7VeC4Ohu0WQvmV+HDJokZVJ2UjJ4AGXW3bx7Lls9Ln4TQ==",
971 "cpu": [971 "cpu": [
972 "arm64"972 "arm64"
973 ],973 ],
@@ -986,9 +986,9 @@
986 }986 }
987 },987 },
988 "node_modules/@parcel/watcher-win32-ia32": {988 "node_modules/@parcel/watcher-win32-ia32": {
989- "version": "2.5.1",989+ "version": "2.5.4",
990- "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",990+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.4.tgz",
991- "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",991+ "integrity": "sha512-vQN+KIReG0a2ZDpVv8cgddlf67J8hk1WfZMMP7sMeZmJRSmEax5xNDNWKdgqSe2brOKTQQAs3aCCUal2qBHAyg==",
992 "cpu": [992 "cpu": [
993 "ia32"993 "ia32"
994 ],994 ],
@@ -1007,9 +1007,9 @@
1007 }1007 }
1008 },1008 },
1009 "node_modules/@parcel/watcher-win32-x64": {1009 "node_modules/@parcel/watcher-win32-x64": {
1010- "version": "2.5.1",1010+ "version": "2.5.4",
1011- "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",1011+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.4.tgz",
1012- "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",1012+ "integrity": "sha512-3A6efb6BOKwyw7yk9ro2vus2YTt2nvcd56AuzxdMiVOxL9umDyN5PKkKfZ/gZ9row41SjVmTVQNWQhaRRGpOKw==",
1013 "cpu": [1013 "cpu": [
1014 "x64"1014 "x64"
1015 ],1015 ],
@@ -1028,9 +1028,9 @@
1028 }1028 }
1029 },1029 },
1030 "node_modules/@rollup/rollup-android-arm-eabi": {1030 "node_modules/@rollup/rollup-android-arm-eabi": {
1031- "version": "4.53.3",1031+ "version": "4.56.0",
1032- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz",1032+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.56.0.tgz",
1033- "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==",1033+ "integrity": "sha512-LNKIPA5k8PF1+jAFomGe3qN3bbIgJe/IlpDBwuVjrDKrJhVWywgnJvflMt/zkbVNLFtF1+94SljYQS6e99klnw==",
1034 "cpu": [1034 "cpu": [
1035 "arm"1035 "arm"
1036 ],1036 ],
@@ -1042,9 +1042,9 @@
1042 ]1042 ]
1043 },1043 },
1044 "node_modules/@rollup/rollup-android-arm64": {1044 "node_modules/@rollup/rollup-android-arm64": {
1045- "version": "4.53.3",1045+ "version": "4.56.0",
1046- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz",1046+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.56.0.tgz",
1047- "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==",1047+ "integrity": "sha512-lfbVUbelYqXlYiU/HApNMJzT1E87UPGvzveGg2h0ktUNlOCxKlWuJ9jtfvs1sKHdwU4fzY7Pl8sAl49/XaEk6Q==",
1048 "cpu": [1048 "cpu": [
1049 "arm64"1049 "arm64"
1050 ],1050 ],
@@ -1056,9 +1056,9 @@
1056 ]1056 ]
1057 },1057 },
1058 "node_modules/@rollup/rollup-darwin-arm64": {1058 "node_modules/@rollup/rollup-darwin-arm64": {
1059- "version": "4.53.3",1059+ "version": "4.56.0",
1060- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz",1060+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.56.0.tgz",
1061- "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==",1061+ "integrity": "sha512-EgxD1ocWfhoD6xSOeEEwyE7tDvwTgZc8Bss7wCWe+uc7wO8G34HHCUH+Q6cHqJubxIAnQzAsyUsClt0yFLu06w==",
1062 "cpu": [1062 "cpu": [
1063 "arm64"1063 "arm64"
1064 ],1064 ],
@@ -1070,9 +1070,9 @@
1070 ]1070 ]
1071 },1071 },
1072 "node_modules/@rollup/rollup-darwin-x64": {1072 "node_modules/@rollup/rollup-darwin-x64": {
1073- "version": "4.53.3",1073+ "version": "4.56.0",
1074- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz",1074+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.56.0.tgz",
1075- "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==",1075+ "integrity": "sha512-1vXe1vcMOssb/hOF8iv52A7feWW2xnu+c8BV4t1F//m9QVLTfNVpEdja5ia762j/UEJe2Z1jAmEqZAK42tVW3g==",
1076 "cpu": [1076 "cpu": [
1077 "x64"1077 "x64"
1078 ],1078 ],
@@ -1084,9 +1084,9 @@
1084 ]1084 ]
1085 },1085 },
1086 "node_modules/@rollup/rollup-freebsd-arm64": {1086 "node_modules/@rollup/rollup-freebsd-arm64": {
1087- "version": "4.53.3",1087+ "version": "4.56.0",
1088- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz",1088+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.56.0.tgz",
1089- "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==",1089+ "integrity": "sha512-bof7fbIlvqsyv/DtaXSck4VYQ9lPtoWNFCB/JY4snlFuJREXfZnm+Ej6yaCHfQvofJDXLDMTVxWscVSuQvVWUQ==",
1090 "cpu": [1090 "cpu": [
1091 "arm64"1091 "arm64"
1092 ],1092 ],
@@ -1098,9 +1098,9 @@
1098 ]1098 ]
1099 },1099 },
1100 "node_modules/@rollup/rollup-freebsd-x64": {1100 "node_modules/@rollup/rollup-freebsd-x64": {
1101- "version": "4.53.3",1101+ "version": "4.56.0",
1102- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz",1102+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.56.0.tgz",
1103- "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==",1103+ "integrity": "sha512-KNa6lYHloW+7lTEkYGa37fpvPq+NKG/EHKM8+G/g9WDU7ls4sMqbVRV78J6LdNuVaeeK5WB9/9VAFbKxcbXKYg==",
1104 "cpu": [1104 "cpu": [
1105 "x64"1105 "x64"
1106 ],1106 ],
@@ -1112,9 +1112,9 @@
1112 ]1112 ]
1113 },1113 },
1114 "node_modules/@rollup/rollup-linux-arm-gnueabihf": {1114 "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
1115- "version": "4.53.3",1115+ "version": "4.56.0",
1116- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz",1116+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.56.0.tgz",
1117- "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==",1117+ "integrity": "sha512-E8jKK87uOvLrrLN28jnAAAChNq5LeCd2mGgZF+fGF5D507WlG/Noct3lP/QzQ6MrqJ5BCKNwI9ipADB6jyiq2A==",
1118 "cpu": [1118 "cpu": [
1119 "arm"1119 "arm"
1120 ],1120 ],
@@ -1126,9 +1126,9 @@
1126 ]1126 ]
1127 },1127 },
1128 "node_modules/@rollup/rollup-linux-arm-musleabihf": {1128 "node_modules/@rollup/rollup-linux-arm-musleabihf": {
1129- "version": "4.53.3",1129+ "version": "4.56.0",
1130- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz",1130+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.56.0.tgz",
1131- "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==",1131+ "integrity": "sha512-jQosa5FMYF5Z6prEpTCCmzCXz6eKr/tCBssSmQGEeozA9tkRUty/5Vx06ibaOP9RCrW1Pvb8yp3gvZhHwTDsJw==",
1132 "cpu": [1132 "cpu": [
1133 "arm"1133 "arm"
1134 ],1134 ],
@@ -1140,9 +1140,9 @@
1140 ]1140 ]
1141 },1141 },
1142 "node_modules/@rollup/rollup-linux-arm64-gnu": {1142 "node_modules/@rollup/rollup-linux-arm64-gnu": {
1143- "version": "4.53.3",1143+ "version": "4.56.0",
1144- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz",1144+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.56.0.tgz",
1145- "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==",1145+ "integrity": "sha512-uQVoKkrC1KGEV6udrdVahASIsaF8h7iLG0U0W+Xn14ucFwi6uS539PsAr24IEF9/FoDtzMeeJXJIBo5RkbNWvQ==",
1146 "cpu": [1146 "cpu": [
1147 "arm64"1147 "arm64"
1148 ],1148 ],
@@ -1154,9 +1154,9 @@
1154 ]1154 ]
1155 },1155 },
1156 "node_modules/@rollup/rollup-linux-arm64-musl": {1156 "node_modules/@rollup/rollup-linux-arm64-musl": {
1157- "version": "4.53.3",1157+ "version": "4.56.0",
1158- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz",1158+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.56.0.tgz",
1159- "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==",1159+ "integrity": "sha512-vLZ1yJKLxhQLFKTs42RwTwa6zkGln+bnXc8ueFGMYmBTLfNu58sl5/eXyxRa2RarTkJbXl8TKPgfS6V5ijNqEA==",
1160 "cpu": [1160 "cpu": [
1161 "arm64"1161 "arm64"
1162 ],1162 ],
@@ -1168,9 +1168,23 @@
1168 ]1168 ]
1169 },1169 },
1170 "node_modules/@rollup/rollup-linux-loong64-gnu": {1170 "node_modules/@rollup/rollup-linux-loong64-gnu": {
1171- "version": "4.53.3",1171+ "version": "4.56.0",
1172- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz",1172+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.56.0.tgz",
1173- "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==",1173+ "integrity": "sha512-FWfHOCub564kSE3xJQLLIC/hbKqHSVxy8vY75/YHHzWvbJL7aYJkdgwD/xGfUlL5UV2SB7otapLrcCj2xnF1dg==",
1174+ "cpu": [
1175+ "loong64"
1176+ ],
1177+ "dev": true,
1178+ "license": "MIT",
1179+ "optional": true,
1180+ "os": [
1181+ "linux"
1182+ ]
1183+ },
1184+ "node_modules/@rollup/rollup-linux-loong64-musl": {
1185+ "version": "4.56.0",
1186+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.56.0.tgz",
1187+ "integrity": "sha512-z1EkujxIh7nbrKL1lmIpqFTc/sr0u8Uk0zK/qIEFldbt6EDKWFk/pxFq3gYj4Bjn3aa9eEhYRlL3H8ZbPT1xvA==",
1174 "cpu": [1188 "cpu": [
1175 "loong64"1189 "loong64"
1176 ],1190 ],
@@ -1182,9 +1196,23 @@
1182 ]1196 ]
1183 },1197 },
1184 "node_modules/@rollup/rollup-linux-ppc64-gnu": {1198 "node_modules/@rollup/rollup-linux-ppc64-gnu": {
1185- "version": "4.53.3",1199+ "version": "4.56.0",
1186- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz",1200+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.56.0.tgz",
1187- "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==",1201+ "integrity": "sha512-iNFTluqgdoQC7AIE8Q34R3AuPrJGJirj5wMUErxj22deOcY7XwZRaqYmB6ZKFHoVGqRcRd0mqO+845jAibKCkw==",
1202+ "cpu": [
1203+ "ppc64"
1204+ ],
1205+ "dev": true,
1206+ "license": "MIT",
1207+ "optional": true,
1208+ "os": [
1209+ "linux"
1210+ ]
1211+ },
1212+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
1213+ "version": "4.56.0",
1214+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.56.0.tgz",
1215+ "integrity": "sha512-MtMeFVlD2LIKjp2sE2xM2slq3Zxf9zwVuw0jemsxvh1QOpHSsSzfNOTH9uYW9i1MXFxUSMmLpeVeUzoNOKBaWg==",
1188 "cpu": [1216 "cpu": [
1189 "ppc64"1217 "ppc64"
1190 ],1218 ],
@@ -1196,9 +1224,9 @@
1196 ]1224 ]
1197 },1225 },
1198 "node_modules/@rollup/rollup-linux-riscv64-gnu": {1226 "node_modules/@rollup/rollup-linux-riscv64-gnu": {
1199- "version": "4.53.3",1227+ "version": "4.56.0",
1200- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz",1228+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.56.0.tgz",
1201- "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==",1229+ "integrity": "sha512-in+v6wiHdzzVhYKXIk5U74dEZHdKN9KH0Q4ANHOTvyXPG41bajYRsy7a8TPKbYPl34hU7PP7hMVHRvv/5aCSew==",
1202 "cpu": [1230 "cpu": [
1203 "riscv64"1231 "riscv64"
1204 ],1232 ],
@@ -1210,9 +1238,9 @@
1210 ]1238 ]
1211 },1239 },
1212 "node_modules/@rollup/rollup-linux-riscv64-musl": {1240 "node_modules/@rollup/rollup-linux-riscv64-musl": {
1213- "version": "4.53.3",1241+ "version": "4.56.0",
1214- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz",1242+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.56.0.tgz",
1215- "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==",1243+ "integrity": "sha512-yni2raKHB8m9NQpI9fPVwN754mn6dHQSbDTwxdr9SE0ks38DTjLMMBjrwvB5+mXrX+C0npX0CVeCUcvvvD8CNQ==",
1216 "cpu": [1244 "cpu": [
1217 "riscv64"1245 "riscv64"
1218 ],1246 ],
@@ -1224,9 +1252,9 @@
1224 ]1252 ]
1225 },1253 },
1226 "node_modules/@rollup/rollup-linux-s390x-gnu": {1254 "node_modules/@rollup/rollup-linux-s390x-gnu": {
1227- "version": "4.53.3",1255+ "version": "4.56.0",
1228- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz",1256+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.56.0.tgz",
1229- "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==",1257+ "integrity": "sha512-zhLLJx9nQPu7wezbxt2ut+CI4YlXi68ndEve16tPc/iwoylWS9B3FxpLS2PkmfYgDQtosah07Mj9E0khc3Y+vQ==",
1230 "cpu": [1258 "cpu": [
1231 "s390x"1259 "s390x"
1232 ],1260 ],
@@ -1238,9 +1266,9 @@
1238 ]1266 ]
1239 },1267 },
1240 "node_modules/@rollup/rollup-linux-x64-gnu": {1268 "node_modules/@rollup/rollup-linux-x64-gnu": {
1241- "version": "4.53.3",1269+ "version": "4.56.0",
1242- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz",1270+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.56.0.tgz",
1243- "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==",1271+ "integrity": "sha512-MVC6UDp16ZSH7x4rtuJPAEoE1RwS8N4oK9DLHy3FTEdFoUTCFVzMfJl/BVJ330C+hx8FfprA5Wqx4FhZXkj2Kw==",
1244 "cpu": [1272 "cpu": [
1245 "x64"1273 "x64"
1246 ],1274 ],
@@ -1252,9 +1280,9 @@
1252 ]1280 ]
1253 },1281 },
1254 "node_modules/@rollup/rollup-linux-x64-musl": {1282 "node_modules/@rollup/rollup-linux-x64-musl": {
1255- "version": "4.53.3",1283+ "version": "4.56.0",
1256- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz",1284+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.56.0.tgz",
1257- "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==",1285+ "integrity": "sha512-ZhGH1eA4Qv0lxaV00azCIS1ChedK0V32952Md3FtnxSqZTBTd6tgil4nZT5cU8B+SIw3PFYkvyR4FKo2oyZIHA==",
1258 "cpu": [1286 "cpu": [
1259 "x64"1287 "x64"
1260 ],1288 ],
@@ -1265,10 +1293,24 @@
1265 "linux"1293 "linux"
1266 ]1294 ]
1267 },1295 },
1296+ "node_modules/@rollup/rollup-openbsd-x64": {
1297+ "version": "4.56.0",
1298+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.56.0.tgz",
1299+ "integrity": "sha512-O16XcmyDeFI9879pEcmtWvD/2nyxR9mF7Gs44lf1vGGx8Vg2DRNx11aVXBEqOQhWb92WN4z7fW/q4+2NYzCbBA==",
1300+ "cpu": [
1301+ "x64"
1302+ ],
1303+ "dev": true,
1304+ "license": "MIT",
1305+ "optional": true,
1306+ "os": [
1307+ "openbsd"
1308+ ]
1309+ },
1268 "node_modules/@rollup/rollup-openharmony-arm64": {1310 "node_modules/@rollup/rollup-openharmony-arm64": {
1269- "version": "4.53.3",1311+ "version": "4.56.0",
1270- "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz",1312+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.56.0.tgz",
1271- "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==",1313+ "integrity": "sha512-LhN/Reh+7F3RCgQIRbgw8ZMwUwyqJM+8pXNT6IIJAqm2IdKkzpCh/V9EdgOMBKuebIrzswqy4ATlrDgiOwbRcQ==",
1272 "cpu": [1314 "cpu": [
1273 "arm64"1315 "arm64"
1274 ],1316 ],
@@ -1280,9 +1322,9 @@
1280 ]1322 ]
1281 },1323 },
1282 "node_modules/@rollup/rollup-win32-arm64-msvc": {1324 "node_modules/@rollup/rollup-win32-arm64-msvc": {
1283- "version": "4.53.3",1325+ "version": "4.56.0",
1284- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz",1326+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.56.0.tgz",
1285- "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==",1327+ "integrity": "sha512-kbFsOObXp3LBULg1d3JIUQMa9Kv4UitDmpS+k0tinPBz3watcUiV2/LUDMMucA6pZO3WGE27P7DsfaN54l9ing==",
1286 "cpu": [1328 "cpu": [
1287 "arm64"1329 "arm64"
1288 ],1330 ],
@@ -1294,9 +1336,9 @@
1294 ]1336 ]
1295 },1337 },
1296 "node_modules/@rollup/rollup-win32-ia32-msvc": {1338 "node_modules/@rollup/rollup-win32-ia32-msvc": {
1297- "version": "4.53.3",1339+ "version": "4.56.0",
1298- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz",1340+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.56.0.tgz",
1299- "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==",1341+ "integrity": "sha512-vSSgny54D6P4vf2izbtFm/TcWYedw7f8eBrOiGGecyHyQB9q4Kqentjaj8hToe+995nob/Wv48pDqL5a62EWtg==",
1300 "cpu": [1342 "cpu": [
1301 "ia32"1343 "ia32"
1302 ],1344 ],
@@ -1308,9 +1350,9 @@
1308 ]1350 ]
1309 },1351 },
1310 "node_modules/@rollup/rollup-win32-x64-gnu": {1352 "node_modules/@rollup/rollup-win32-x64-gnu": {
1311- "version": "4.53.3",1353+ "version": "4.56.0",
1312- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz",1354+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.56.0.tgz",
1313- "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==",1355+ "integrity": "sha512-FeCnkPCTHQJFbiGG49KjV5YGW/8b9rrXAM2Mz2kiIoktq2qsJxRD5giEMEOD2lPdgs72upzefaUvS+nc8E3UzQ==",
1314 "cpu": [1356 "cpu": [
1315 "x64"1357 "x64"
1316 ],1358 ],
@@ -1322,9 +1364,9 @@
1322 ]1364 ]
1323 },1365 },
1324 "node_modules/@rollup/rollup-win32-x64-msvc": {1366 "node_modules/@rollup/rollup-win32-x64-msvc": {
1325- "version": "4.53.3",1367+ "version": "4.56.0",
1326- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz",1368+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.56.0.tgz",
1327- "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==",1369+ "integrity": "sha512-H8AE9Ur/t0+1VXujj90w0HrSOuv0Nq9r1vSZF2t5km20NTfosQsGGUXDaKdQZzwuLts7IyL1fYT4hM95TI9c4g==",
1328 "cpu": [1370 "cpu": [
1329 "x64"1371 "x64"
1330 ],1372 ],
@@ -1386,37 +1428,37 @@
1386 }1428 }
1387 },1429 },
1388 "node_modules/@swc/helpers": {1430 "node_modules/@swc/helpers": {
1389- "version": "0.5.17",1431+ "version": "0.5.18",
1390- "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz",1432+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.18.tgz",
1391- "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==",1433+ "integrity": "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==",
1392 "license": "Apache-2.0",1434 "license": "Apache-2.0",
1393 "dependencies": {1435 "dependencies": {
1394 "tslib": "^2.8.0"1436 "tslib": "^2.8.0"
1395 }1437 }
1396 },1438 },
1397 "node_modules/@tailwindcss/cli": {1439 "node_modules/@tailwindcss/cli": {
1398- "version": "4.1.17",1440+ "version": "4.1.18",
1399- "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.1.17.tgz",1441+ "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.1.18.tgz",
1400- "integrity": "sha512-jUIxcyUNlCC2aNPnyPEWU/L2/ik3pB4fF3auKGXr8AvN3T3OFESVctFKOBoPZQaZJIeUpPn1uCLp0MRxuek8gg==",1442+ "integrity": "sha512-sMZ+lZbDyxwjD2E0L7oRUjJ01Ffjtme5OtjvvnC+cV4CEDcbqzbp25TCpxHj6kWLU9+DlqJOiNgSOgctC2aZmg==",
1401 "dev": true,1443 "dev": true,
1402 "license": "MIT",1444 "license": "MIT",
1403 "dependencies": {1445 "dependencies": {
1404 "@parcel/watcher": "^2.5.1",1446 "@parcel/watcher": "^2.5.1",
1405- "@tailwindcss/node": "4.1.17",1447+ "@tailwindcss/node": "4.1.18",
1406- "@tailwindcss/oxide": "4.1.17",1448+ "@tailwindcss/oxide": "4.1.18",
1407 "enhanced-resolve": "^5.18.3",1449 "enhanced-resolve": "^5.18.3",
1408 "mri": "^1.2.0",1450 "mri": "^1.2.0",
1409 "picocolors": "^1.1.1",1451 "picocolors": "^1.1.1",
1410- "tailwindcss": "4.1.17"1452+ "tailwindcss": "4.1.18"
1411 },1453 },
1412 "bin": {1454 "bin": {
1413 "tailwindcss": "dist/index.mjs"1455 "tailwindcss": "dist/index.mjs"
1414 }1456 }
1415 },1457 },
1416 "node_modules/@tailwindcss/node": {1458 "node_modules/@tailwindcss/node": {
1417- "version": "4.1.17",1459+ "version": "4.1.18",
1418- "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.17.tgz",1460+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz",
1419- "integrity": "sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==",1461+ "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==",
1420 "dev": true,1462 "dev": true,
1421 "license": "MIT",1463 "license": "MIT",
1422 "dependencies": {1464 "dependencies": {
@@ -1426,37 +1468,37 @@
1426 "lightningcss": "1.30.2",1468 "lightningcss": "1.30.2",
1427 "magic-string": "^0.30.21",1469 "magic-string": "^0.30.21",
1428 "source-map-js": "^1.2.1",1470 "source-map-js": "^1.2.1",
1429- "tailwindcss": "4.1.17"1471+ "tailwindcss": "4.1.18"
1430 }1472 }
1431 },1473 },
1432 "node_modules/@tailwindcss/oxide": {1474 "node_modules/@tailwindcss/oxide": {
1433- "version": "4.1.17",1475+ "version": "4.1.18",
1434- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.17.tgz",1476+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz",
1435- "integrity": "sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==",1477+ "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==",
1436 "dev": true,1478 "dev": true,
1437 "license": "MIT",1479 "license": "MIT",
1438 "engines": {1480 "engines": {
1439 "node": ">= 10"1481 "node": ">= 10"
1440 },1482 },
1441 "optionalDependencies": {1483 "optionalDependencies": {
1442- "@tailwindcss/oxide-android-arm64": "4.1.17",1484+ "@tailwindcss/oxide-android-arm64": "4.1.18",
1443- "@tailwindcss/oxide-darwin-arm64": "4.1.17",1485+ "@tailwindcss/oxide-darwin-arm64": "4.1.18",
1444- "@tailwindcss/oxide-darwin-x64": "4.1.17",1486+ "@tailwindcss/oxide-darwin-x64": "4.1.18",
1445- "@tailwindcss/oxide-freebsd-x64": "4.1.17",1487+ "@tailwindcss/oxide-freebsd-x64": "4.1.18",
1446- "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.17",1488+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18",
1447- "@tailwindcss/oxide-linux-arm64-gnu": "4.1.17",1489+ "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18",
1448- "@tailwindcss/oxide-linux-arm64-musl": "4.1.17",1490+ "@tailwindcss/oxide-linux-arm64-musl": "4.1.18",
1449- "@tailwindcss/oxide-linux-x64-gnu": "4.1.17",1491+ "@tailwindcss/oxide-linux-x64-gnu": "4.1.18",
1450- "@tailwindcss/oxide-linux-x64-musl": "4.1.17",1492+ "@tailwindcss/oxide-linux-x64-musl": "4.1.18",
1451- "@tailwindcss/oxide-wasm32-wasi": "4.1.17",1493+ "@tailwindcss/oxide-wasm32-wasi": "4.1.18",
1452- "@tailwindcss/oxide-win32-arm64-msvc": "4.1.17",1494+ "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18",
1453- "@tailwindcss/oxide-win32-x64-msvc": "4.1.17"1495+ "@tailwindcss/oxide-win32-x64-msvc": "4.1.18"
1454 }1496 }
1455 },1497 },
1456 "node_modules/@tailwindcss/oxide-android-arm64": {1498 "node_modules/@tailwindcss/oxide-android-arm64": {
1457- "version": "4.1.17",1499+ "version": "4.1.18",
1458- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.17.tgz",1500+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz",
1459- "integrity": "sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==",1501+ "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==",
1460 "cpu": [1502 "cpu": [
1461 "arm64"1503 "arm64"
1462 ],1504 ],
@@ -1471,9 +1513,9 @@
1471 }1513 }
1472 },1514 },
1473 "node_modules/@tailwindcss/oxide-darwin-arm64": {1515 "node_modules/@tailwindcss/oxide-darwin-arm64": {
1474- "version": "4.1.17",1516+ "version": "4.1.18",
1475- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.17.tgz",1517+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz",
1476- "integrity": "sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==",1518+ "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==",
1477 "cpu": [1519 "cpu": [
1478 "arm64"1520 "arm64"
1479 ],1521 ],
@@ -1488,9 +1530,9 @@
1488 }1530 }
1489 },1531 },
1490 "node_modules/@tailwindcss/oxide-darwin-x64": {1532 "node_modules/@tailwindcss/oxide-darwin-x64": {
1491- "version": "4.1.17",1533+ "version": "4.1.18",
1492- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.17.tgz",1534+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz",
1493- "integrity": "sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==",1535+ "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==",
1494 "cpu": [1536 "cpu": [
1495 "x64"1537 "x64"
1496 ],1538 ],
@@ -1505,9 +1547,9 @@
1505 }1547 }
1506 },1548 },
1507 "node_modules/@tailwindcss/oxide-freebsd-x64": {1549 "node_modules/@tailwindcss/oxide-freebsd-x64": {
1508- "version": "4.1.17",1550+ "version": "4.1.18",
1509- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.17.tgz",1551+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz",
1510- "integrity": "sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==",1552+ "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==",
1511 "cpu": [1553 "cpu": [
1512 "x64"1554 "x64"
1513 ],1555 ],
@@ -1522,9 +1564,9 @@
1522 }1564 }
1523 },1565 },
1524 "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {1566 "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
1525- "version": "4.1.17",1567+ "version": "4.1.18",
1526- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.17.tgz",1568+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz",
1527- "integrity": "sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==",1569+ "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==",
1528 "cpu": [1570 "cpu": [
1529 "arm"1571 "arm"
1530 ],1572 ],
@@ -1539,9 +1581,9 @@
1539 }1581 }
1540 },1582 },
1541 "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {1583 "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
1542- "version": "4.1.17",1584+ "version": "4.1.18",
1543- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.17.tgz",1585+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz",
1544- "integrity": "sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==",1586+ "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==",
1545 "cpu": [1587 "cpu": [
1546 "arm64"1588 "arm64"
1547 ],1589 ],
@@ -1556,9 +1598,9 @@
1556 }1598 }
1557 },1599 },
1558 "node_modules/@tailwindcss/oxide-linux-arm64-musl": {1600 "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
1559- "version": "4.1.17",1601+ "version": "4.1.18",
1560- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.17.tgz",1602+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz",
1561- "integrity": "sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==",1603+ "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==",
1562 "cpu": [1604 "cpu": [
1563 "arm64"1605 "arm64"
1564 ],1606 ],
@@ -1573,9 +1615,9 @@
1573 }1615 }
1574 },1616 },
1575 "node_modules/@tailwindcss/oxide-linux-x64-gnu": {1617 "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
1576- "version": "4.1.17",1618+ "version": "4.1.18",
1577- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.17.tgz",1619+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz",
1578- "integrity": "sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==",1620+ "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==",
1579 "cpu": [1621 "cpu": [
1580 "x64"1622 "x64"
1581 ],1623 ],
@@ -1590,9 +1632,9 @@
1590 }1632 }
1591 },1633 },
1592 "node_modules/@tailwindcss/oxide-linux-x64-musl": {1634 "node_modules/@tailwindcss/oxide-linux-x64-musl": {
1593- "version": "4.1.17",1635+ "version": "4.1.18",
1594- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.17.tgz",1636+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz",
1595- "integrity": "sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==",1637+ "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==",
1596 "cpu": [1638 "cpu": [
1597 "x64"1639 "x64"
1598 ],1640 ],
@@ -1607,9 +1649,9 @@
1607 }1649 }
1608 },1650 },
1609 "node_modules/@tailwindcss/oxide-wasm32-wasi": {1651 "node_modules/@tailwindcss/oxide-wasm32-wasi": {
1610- "version": "4.1.17",1652+ "version": "4.1.18",
1611- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.17.tgz",1653+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz",
1612- "integrity": "sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==",1654+ "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==",
1613 "bundleDependencies": [1655 "bundleDependencies": [
1614 "@napi-rs/wasm-runtime",1656 "@napi-rs/wasm-runtime",
1615 "@emnapi/core",1657 "@emnapi/core",
@@ -1625,10 +1667,10 @@
1625 "license": "MIT",1667 "license": "MIT",
1626 "optional": true,1668 "optional": true,
1627 "dependencies": {1669 "dependencies": {
1628- "@emnapi/core": "^1.6.0",1670+ "@emnapi/core": "^1.7.1",
1629- "@emnapi/runtime": "^1.6.0",1671+ "@emnapi/runtime": "^1.7.1",
1630 "@emnapi/wasi-threads": "^1.1.0",1672 "@emnapi/wasi-threads": "^1.1.0",
1631- "@napi-rs/wasm-runtime": "^1.0.7",1673+ "@napi-rs/wasm-runtime": "^1.1.0",
1632 "@tybys/wasm-util": "^0.10.1",1674 "@tybys/wasm-util": "^0.10.1",
1633 "tslib": "^2.4.0"1675 "tslib": "^2.4.0"
1634 },1676 },
@@ -1637,9 +1679,9 @@
1637 }1679 }
1638 },1680 },
1639 "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {1681 "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
1640- "version": "4.1.17",1682+ "version": "4.1.18",
1641- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.17.tgz",1683+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz",
1642- "integrity": "sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==",1684+ "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==",
1643 "cpu": [1685 "cpu": [
1644 "arm64"1686 "arm64"
1645 ],1687 ],
@@ -1654,9 +1696,9 @@
1654 }1696 }
1655 },1697 },
1656 "node_modules/@tailwindcss/oxide-win32-x64-msvc": {1698 "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
1657- "version": "4.1.17",1699+ "version": "4.1.18",
1658- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.17.tgz",1700+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz",
1659- "integrity": "sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==",1701+ "integrity": "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==",
1660 "cpu": [1702 "cpu": [
1661 "x64"1703 "x64"
1662 ],1704 ],
@@ -1671,17 +1713,17 @@
1671 }1713 }
1672 },1714 },
1673 "node_modules/@tailwindcss/postcss": {1715 "node_modules/@tailwindcss/postcss": {
1674- "version": "4.1.17",1716+ "version": "4.1.18",
1675- "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.17.tgz",1717+ "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.18.tgz",
1676- "integrity": "sha512-+nKl9N9mN5uJ+M7dBOOCzINw94MPstNR/GtIhz1fpZysxL/4a+No64jCBD6CPN+bIHWFx3KWuu8XJRrj/572Dw==",1718+ "integrity": "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==",
1677 "dev": true,1719 "dev": true,
1678 "license": "MIT",1720 "license": "MIT",
1679 "dependencies": {1721 "dependencies": {
1680 "@alloc/quick-lru": "^5.2.0",1722 "@alloc/quick-lru": "^5.2.0",
1681- "@tailwindcss/node": "4.1.17",1723+ "@tailwindcss/node": "4.1.18",
1682- "@tailwindcss/oxide": "4.1.17",1724+ "@tailwindcss/oxide": "4.1.18",
1683 "postcss": "^8.4.41",1725 "postcss": "^8.4.41",
1684- "tailwindcss": "4.1.17"1726+ "tailwindcss": "4.1.18"
1685 }1727 }
1686 },1728 },
1687 "node_modules/@types/estree": {1729 "node_modules/@types/estree": {
@@ -1691,9 +1733,9 @@
1691 "license": "MIT"1733 "license": "MIT"
1692 },1734 },
1693 "node_modules/@types/node": {1735 "node_modules/@types/node": {
1694- "version": "20.19.25",1736+ "version": "20.19.30",
1695- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.25.tgz",1737+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz",
1696- "integrity": "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==",1738+ "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==",
1697 "dev": true,1739 "dev": true,
1698 "license": "MIT",1740 "license": "MIT",
1699 "peer": true,1741 "peer": true,
@@ -1766,15 +1808,15 @@
1766 }1808 }
1767 },1809 },
1768 "node_modules/@typescript-eslint/project-service": {1810 "node_modules/@typescript-eslint/project-service": {
1769- "version": "8.48.1",1811+ "version": "8.53.1",
1770- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.1.tgz",1812+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.53.1.tgz",
1771- "integrity": "sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==",1813+ "integrity": "sha512-WYC4FB5Ra0xidsmlPb+1SsnaSKPmS3gsjIARwbEkHkoWloQmuzcfypljaJcR78uyLA1h8sHdWWPHSLDI+MtNog==",
1772 "dev": true,1814 "dev": true,
1773 "license": "MIT",1815 "license": "MIT",
1774 "dependencies": {1816 "dependencies": {
1775- "@typescript-eslint/tsconfig-utils": "^8.48.1",1817+ "@typescript-eslint/tsconfig-utils": "^8.53.1",
1776- "@typescript-eslint/types": "^8.48.1",1818+ "@typescript-eslint/types": "^8.53.1",
1777- "debug": "^4.3.4"1819+ "debug": "^4.4.3"
1778 },1820 },
1779 "engines": {1821 "engines": {
1780 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"1822 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1788,9 +1830,9 @@
1788 }1830 }
1789 },1831 },
1790 "node_modules/@typescript-eslint/project-service/node_modules/@typescript-eslint/types": {1832 "node_modules/@typescript-eslint/project-service/node_modules/@typescript-eslint/types": {
1791- "version": "8.48.1",1833+ "version": "8.53.1",
1792- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.1.tgz",1834+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.53.1.tgz",
1793- "integrity": "sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==",1835+ "integrity": "sha512-jr/swrr2aRmUAUjW5/zQHbMaui//vQlsZcJKijZf3M26bnmLj8LyZUpj8/Rd6uzaek06OWsqdofN/Thenm5O8A==",
1794 "dev": true,1836 "dev": true,
1795 "license": "MIT",1837 "license": "MIT",
1796 "engines": {1838 "engines": {
@@ -1820,9 +1862,9 @@
1820 }1862 }
1821 },1863 },
1822 "node_modules/@typescript-eslint/tsconfig-utils": {1864 "node_modules/@typescript-eslint/tsconfig-utils": {
1823- "version": "8.48.1",1865+ "version": "8.53.1",
1824- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.1.tgz",1866+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.53.1.tgz",
1825- "integrity": "sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==",1867+ "integrity": "sha512-qfvLXS6F6b1y43pnf0pPbXJ+YoXIC7HKg0UGZ27uMIemKMKA6XH2DTxsEDdpdN29D+vHV07x/pnlPNVLhdhWiA==",
1826 "dev": true,1868 "dev": true,
1827 "license": "MIT",1869 "license": "MIT",
1828 "engines": {1870 "engines": {
@@ -2048,9 +2090,9 @@
2048 }2090 }
2049 },2091 },
2050 "node_modules/autoprefixer": {2092 "node_modules/autoprefixer": {
2051- "version": "10.4.22",2093+ "version": "10.4.23",
2052- "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.22.tgz",2094+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.23.tgz",
2053- "integrity": "sha512-ARe0v/t9gO28Bznv6GgqARmVqcWOV3mfgUPn9becPHMiD3o9BwlRgaeccZnwTpZ7Zwqrm+c1sUSsMxIzQzc8Xg==",2095+ "integrity": "sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==",
2054 "dev": true,2096 "dev": true,
2055 "funding": [2097 "funding": [
2056 {2098 {
@@ -2068,10 +2110,9 @@
2068 ],2110 ],
2069 "license": "MIT",2111 "license": "MIT",
2070 "dependencies": {2112 "dependencies": {
2071- "browserslist": "^4.27.0",2113+ "browserslist": "^4.28.1",
2072- "caniuse-lite": "^1.0.30001754",2114+ "caniuse-lite": "^1.0.30001760",
2073 "fraction.js": "^5.3.4",2115 "fraction.js": "^5.3.4",
2074- "normalize-range": "^0.1.2",
2075 "picocolors": "^1.1.1",2116 "picocolors": "^1.1.1",
2076 "postcss-value-parser": "^4.2.0"2117 "postcss-value-parser": "^4.2.0"
2077 },2118 },
@@ -2102,9 +2143,9 @@
2102 "license": "MIT"2143 "license": "MIT"
2103 },2144 },
2104 "node_modules/baseline-browser-mapping": {2145 "node_modules/baseline-browser-mapping": {
2105- "version": "2.9.3",2146+ "version": "2.9.17",
2106- "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.3.tgz",2147+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.17.tgz",
2107- "integrity": "sha512-8QdH6czo+G7uBsNo0GiUfouPN1lRzKdJTGnKXwe12gkFbnnOUaUKGN55dMkfy+mnxmvjwl9zcI4VncczcVXDhA==",2148+ "integrity": "sha512-agD0MgJFUP/4nvjqzIB29zRPUuCF7Ge6mEv9s8dHrtYD7QWXRcx75rOADE/d5ah1NI+0vkDl0yorDd5U852IQQ==",
2108 "dev": true,2149 "dev": true,
2109 "license": "Apache-2.0",2150 "license": "Apache-2.0",
2110 "bin": {2151 "bin": {
@@ -2112,9 +2153,9 @@
2112 }2153 }
2113 },2154 },
2114 "node_modules/bits-ui": {2155 "node_modules/bits-ui": {
2115- "version": "2.14.4",2156+ "version": "2.15.4",
2116- "resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-2.14.4.tgz",2157+ "resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-2.15.4.tgz",
2117- "integrity": "sha512-W6kenhnbd/YVvur+DKkaVJ6GldE53eLewur5AhUCqslYQ0vjZr8eWlOfwZnMiPB+PF5HMVqf61vXBvmyrAmPWg==",2158+ "integrity": "sha512-7H9YUfp03KOk1LVDh8wPYSRPxlZgG/GRWLNSA8QC73/8Z8ytun+DWJhIuibyFyz7A0cP/RANVcB4iDrbY8q+Og==",
2118 "license": "MIT",2159 "license": "MIT",
2119 "dependencies": {2160 "dependencies": {
2120 "@floating-ui/core": "^1.7.1",2161 "@floating-ui/core": "^1.7.1",
@@ -2204,9 +2245,9 @@
2204 }2245 }
2205 },2246 },
2206 "node_modules/caniuse-lite": {2247 "node_modules/caniuse-lite": {
2207- "version": "1.0.30001759",2248+ "version": "1.0.30001766",
2208- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001759.tgz",2249+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz",
2209- "integrity": "sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==",2250+ "integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==",
2210 "dev": true,2251 "dev": true,
2211 "funding": [2252 "funding": [
2212 {2253 {
@@ -2360,22 +2401,19 @@
2360 }2401 }
2361 },2402 },
2362 "node_modules/detect-libc": {2403 "node_modules/detect-libc": {
2363- "version": "1.0.3",2404+ "version": "2.1.2",
2364- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",2405+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
2365- "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",2406+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
2366 "dev": true,2407 "dev": true,
2367 "license": "Apache-2.0",2408 "license": "Apache-2.0",
2368- "bin": {
2369- "detect-libc": "bin/detect-libc.js"
2370- },
2371 "engines": {2409 "engines": {
2372- "node": ">=0.10"2410+ "node": ">=8"
2373 }2411 }
2374 },2412 },
2375 "node_modules/devalue": {2413 "node_modules/devalue": {
2376- "version": "5.5.0",2414+ "version": "5.6.2",
2377- "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.5.0.tgz",2415+ "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.2.tgz",
2378- "integrity": "sha512-69sM5yrHfFLJt0AZ9QqZXGCPfJ7fQjvpln3Rq5+PS03LD32Ost1Q9N+eEnaQwGRIriKkMImXD56ocjQmfjbV3w==",2416+ "integrity": "sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==",
2379 "license": "MIT"2417 "license": "MIT"
2380 },2418 },
2381 "node_modules/dir-glob": {2419 "node_modules/dir-glob": {
@@ -2405,16 +2443,16 @@
2405 }2443 }
2406 },2444 },
2407 "node_modules/electron-to-chromium": {2445 "node_modules/electron-to-chromium": {
2408- "version": "1.5.266",2446+ "version": "1.5.277",
2409- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.266.tgz",2447+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.277.tgz",
2410- "integrity": "sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg==",2448+ "integrity": "sha512-wKXFZw4erWmmOz5N/grBoJ2XrNJGDFMu2+W5ACHza5rHtvsqrK4gb6rnLC7XxKB9WlJ+RmyQatuEXmtm86xbnw==",
2411 "dev": true,2449 "dev": true,
2412 "license": "ISC"2450 "license": "ISC"
2413 },2451 },
2414 "node_modules/enhanced-resolve": {2452 "node_modules/enhanced-resolve": {
2415- "version": "5.18.3",2453+ "version": "5.18.4",
2416- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",2454+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz",
2417- "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",2455+ "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==",
2418 "dev": true,2456 "dev": true,
2419 "license": "MIT",2457 "license": "MIT",
2420 "dependencies": {2458 "dependencies": {
@@ -2624,9 +2662,9 @@
2624 }2662 }
2625 },2663 },
2626 "node_modules/esquery": {2664 "node_modules/esquery": {
2627- "version": "1.6.0",2665+ "version": "1.7.0",
2628- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",2666+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
2629- "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",2667+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
2630 "dev": true,2668 "dev": true,
2631 "license": "BSD-3-Clause",2669 "license": "BSD-3-Clause",
2632 "dependencies": {2670 "dependencies": {
@@ -2637,9 +2675,9 @@
2637 }2675 }
2638 },2676 },
2639 "node_modules/esrap": {2677 "node_modules/esrap": {
2640- "version": "2.2.1",2678+ "version": "2.2.2",
2641- "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.1.tgz",2679+ "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.2.tgz",
2642- "integrity": "sha512-GiYWG34AN/4CUyaWAgunGt0Rxvr1PTMlGC0vvEov/uOQYWne2bpN03Um+k8jT+q3op33mKouP2zeJ6OlM+qeUg==",2680+ "integrity": "sha512-zA6497ha+qKvoWIK+WM9NAh5ni17sKZKhbS5B3PoYbBvaYHZWoS33zmFybmyqpn07RLUxSmn+RCls2/XF+d0oQ==",
2643 "license": "MIT",2681 "license": "MIT",
2644 "dependencies": {2682 "dependencies": {
2645 "@jridgewell/sourcemap-codec": "^1.4.15"2683 "@jridgewell/sourcemap-codec": "^1.4.15"
@@ -2730,15 +2768,33 @@
2730 "license": "MIT"2768 "license": "MIT"
2731 },2769 },
2732 "node_modules/fastq": {2770 "node_modules/fastq": {
2733- "version": "1.19.1",2771+ "version": "1.20.1",
2734- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",2772+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
2735- "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",2773+ "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
2736 "dev": true,2774 "dev": true,
2737 "license": "ISC",2775 "license": "ISC",
2738 "dependencies": {2776 "dependencies": {
2739 "reusify": "^1.0.4"2777 "reusify": "^1.0.4"
2740 }2778 }
2741 },2779 },
2780+ "node_modules/fdir": {
2781+ "version": "6.5.0",
2782+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
2783+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
2784+ "dev": true,
2785+ "license": "MIT",
2786+ "engines": {
2787+ "node": ">=12.0.0"
2788+ },
2789+ "peerDependencies": {
2790+ "picomatch": "^3 || ^4"
2791+ },
2792+ "peerDependenciesMeta": {
2793+ "picomatch": {
2794+ "optional": true
2795+ }
2796+ }
2797+ },
2742 "node_modules/file-entry-cache": {2798 "node_modules/file-entry-cache": {
2743 "version": "6.0.1",2799 "version": "6.0.1",
2744 "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",2800 "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -3426,16 +3482,6 @@
3426 "url": "https://opencollective.com/parcel"3482 "url": "https://opencollective.com/parcel"
3427 }3483 }
3428 },3484 },
3429- "node_modules/lightningcss/node_modules/detect-libc": {
3430- "version": "2.1.2",
3431- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
3432- "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
3433- "dev": true,
3434- "license": "Apache-2.0",
3435- "engines": {
3436- "node": ">=8"
3437- }
3438- },
3439 "node_modules/locate-character": {3485 "node_modules/locate-character": {
3440 "version": "3.0.0",3486 "version": "3.0.0",
3441 "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",3487 "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
@@ -3507,6 +3553,19 @@
3507 "node": ">=8.6"3553 "node": ">=8.6"
3508 }3554 }
3509 },3555 },
3556+ "node_modules/micromatch/node_modules/picomatch": {
3557+ "version": "2.3.1",
3558+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
3559+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
3560+ "dev": true,
3561+ "license": "MIT",
3562+ "engines": {
3563+ "node": ">=8.6"
3564+ },
3565+ "funding": {
3566+ "url": "https://github.com/sponsors/jonschlinkert"
3567+ }
3568+ },
3510 "node_modules/minimatch": {3569 "node_modules/minimatch": {
3511 "version": "9.0.5",3570 "version": "9.0.5",
3512 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",3571 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
@@ -3643,16 +3702,6 @@
3643 "dev": true,3702 "dev": true,
3644 "license": "MIT"3703 "license": "MIT"
3645 },3704 },
3646- "node_modules/normalize-range": {
3647- "version": "0.1.2",
3648- "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
3649- "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
3650- "dev": true,
3651- "license": "MIT",
3652- "engines": {
3653- "node": ">=0.10.0"
3654- }
3655- },
3656 "node_modules/once": {3705 "node_modules/once": {
3657 "version": "1.4.0",3706 "version": "1.4.0",
3658 "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",3707 "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -3774,13 +3823,13 @@
3774 "license": "ISC"3823 "license": "ISC"
3775 },3824 },
3776 "node_modules/picomatch": {3825 "node_modules/picomatch": {
3777- "version": "2.3.1",3826+ "version": "4.0.3",
3778- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",3827+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
3779- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",3828+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
3780 "dev": true,3829 "dev": true,
3781 "license": "MIT",3830 "license": "MIT",
3782 "engines": {3831 "engines": {
3783- "node": ">=8.6"3832+ "node": ">=12"
3784 },3833 },
3785 "funding": {3834 "funding": {
3786 "url": "https://github.com/sponsors/jonschlinkert"3835 "url": "https://github.com/sponsors/jonschlinkert"
@@ -3917,9 +3966,9 @@
3917 }3966 }
3918 },3967 },
3919 "node_modules/rollup": {3968 "node_modules/rollup": {
3920- "version": "4.53.3",3969+ "version": "4.56.0",
3921- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz",3970+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.56.0.tgz",
3922- "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==",3971+ "integrity": "sha512-9FwVqlgUHzbXtDg9RCMgodF3Ua4Na6Gau+Sdt9vyCN4RhHfVKX2DCHy3BjMLTDd47ITDhYAnTwGulWTblJSDLg==",
3923 "dev": true,3972 "dev": true,
3924 "license": "MIT",3973 "license": "MIT",
3925 "dependencies": {3974 "dependencies": {
@@ -3933,28 +3982,31 @@
3933 "npm": ">=8.0.0"3982 "npm": ">=8.0.0"
3934 },3983 },
3935 "optionalDependencies": {3984 "optionalDependencies": {
3936- "@rollup/rollup-android-arm-eabi": "4.53.3",3985+ "@rollup/rollup-android-arm-eabi": "4.56.0",
3937- "@rollup/rollup-android-arm64": "4.53.3",3986+ "@rollup/rollup-android-arm64": "4.56.0",
3938- "@rollup/rollup-darwin-arm64": "4.53.3",3987+ "@rollup/rollup-darwin-arm64": "4.56.0",
3939- "@rollup/rollup-darwin-x64": "4.53.3",3988+ "@rollup/rollup-darwin-x64": "4.56.0",
3940- "@rollup/rollup-freebsd-arm64": "4.53.3",3989+ "@rollup/rollup-freebsd-arm64": "4.56.0",
3941- "@rollup/rollup-freebsd-x64": "4.53.3",3990+ "@rollup/rollup-freebsd-x64": "4.56.0",
3942- "@rollup/rollup-linux-arm-gnueabihf": "4.53.3",3991+ "@rollup/rollup-linux-arm-gnueabihf": "4.56.0",
3943- "@rollup/rollup-linux-arm-musleabihf": "4.53.3",3992+ "@rollup/rollup-linux-arm-musleabihf": "4.56.0",
3944- "@rollup/rollup-linux-arm64-gnu": "4.53.3",3993+ "@rollup/rollup-linux-arm64-gnu": "4.56.0",
3945- "@rollup/rollup-linux-arm64-musl": "4.53.3",3994+ "@rollup/rollup-linux-arm64-musl": "4.56.0",
3946- "@rollup/rollup-linux-loong64-gnu": "4.53.3",3995+ "@rollup/rollup-linux-loong64-gnu": "4.56.0",
3947- "@rollup/rollup-linux-ppc64-gnu": "4.53.3",3996+ "@rollup/rollup-linux-loong64-musl": "4.56.0",
3948- "@rollup/rollup-linux-riscv64-gnu": "4.53.3",3997+ "@rollup/rollup-linux-ppc64-gnu": "4.56.0",
3949- "@rollup/rollup-linux-riscv64-musl": "4.53.3",3998+ "@rollup/rollup-linux-ppc64-musl": "4.56.0",
3950- "@rollup/rollup-linux-s390x-gnu": "4.53.3",3999+ "@rollup/rollup-linux-riscv64-gnu": "4.56.0",
3951- "@rollup/rollup-linux-x64-gnu": "4.53.3",4000+ "@rollup/rollup-linux-riscv64-musl": "4.56.0",
3952- "@rollup/rollup-linux-x64-musl": "4.53.3",4001+ "@rollup/rollup-linux-s390x-gnu": "4.56.0",
3953- "@rollup/rollup-openharmony-arm64": "4.53.3",4002+ "@rollup/rollup-linux-x64-gnu": "4.56.0",
3954- "@rollup/rollup-win32-arm64-msvc": "4.53.3",4003+ "@rollup/rollup-linux-x64-musl": "4.56.0",
3955- "@rollup/rollup-win32-ia32-msvc": "4.53.3",4004+ "@rollup/rollup-openbsd-x64": "4.56.0",
3956- "@rollup/rollup-win32-x64-gnu": "4.53.3",4005+ "@rollup/rollup-openharmony-arm64": "4.56.0",
3957- "@rollup/rollup-win32-x64-msvc": "4.53.3",4006+ "@rollup/rollup-win32-arm64-msvc": "4.56.0",
4007+ "@rollup/rollup-win32-ia32-msvc": "4.56.0",
4008+ "@rollup/rollup-win32-x64-gnu": "4.56.0",
4009+ "@rollup/rollup-win32-x64-msvc": "4.56.0",
3958 "fsevents": "~2.3.2"4010 "fsevents": "~2.3.2"
3959 }4011 }
3960 },4012 },
@@ -4124,9 +4176,9 @@
4124 }4176 }
4125 },4177 },
4126 "node_modules/svelte": {4178 "node_modules/svelte": {
4127- "version": "5.45.5",4179+ "version": "5.48.0",
4128- "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.45.5.tgz",4180+ "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.48.0.tgz",
4129- "integrity": "sha512-2074U+vObO5Zs8/qhxtBwdi6ZXNIhEBTzNmUFjiZexLxTdt9vq96D/0pnQELl6YcpLMD7pZ2dhXKByfGS8SAdg==",4181+ "integrity": "sha512-+NUe82VoFP1RQViZI/esojx70eazGF4u0O/9ucqZ4rPcOZD+n5EVp17uYsqwdzjUjZyTpGKunHbDziW6AIAVkQ==",
4130 "license": "MIT",4182 "license": "MIT",
4131 "peer": true,4183 "peer": true,
4132 "dependencies": {4184 "dependencies": {
@@ -4138,7 +4190,7 @@
4138 "aria-query": "^5.3.1",4190 "aria-query": "^5.3.1",
4139 "axobject-query": "^4.1.0",4191 "axobject-query": "^4.1.0",
4140 "clsx": "^2.1.1",4192 "clsx": "^2.1.1",
4141- "devalue": "^5.5.0",4193+ "devalue": "^5.6.2",
4142 "esm-env": "^1.2.1",4194 "esm-env": "^1.2.1",
4143 "esrap": "^2.2.1",4195 "esrap": "^2.2.1",
4144 "is-reference": "^3.0.3",4196 "is-reference": "^3.0.3",
@@ -4151,15 +4203,18 @@
4151 }4203 }
4152 },4204 },
4153 "node_modules/svelte-awesome-color-picker": {4205 "node_modules/svelte-awesome-color-picker": {
4154- "version": "4.1.0",4206+ "version": "4.1.1",
4155- "resolved": "https://registry.npmjs.org/svelte-awesome-color-picker/-/svelte-awesome-color-picker-4.1.0.tgz",4207+ "resolved": "https://registry.npmjs.org/svelte-awesome-color-picker/-/svelte-awesome-color-picker-4.1.1.tgz",
4156- "integrity": "sha512-afiSB3eTBlqu96f4+rjBvqG3eCaLwuneNYHe587Wr4Ien6yQWeztGZunPT0FmiI7wFFBVNUlJQLYutII8LfQUg==",4208+ "integrity": "sha512-k4APFGBFN8EpvUS0UJfdlqj8xDekMbqGBwnDYBK1QCY8kcTXSO8c7SitEk70MkiYOIByOgXlHcjaipy6H7dpAw==",
4157 "dev": true,4209 "dev": true,
4158 "license": "MIT",4210 "license": "MIT",
4159 "dependencies": {4211 "dependencies": {
4160 "colord": "^2.9.3",4212 "colord": "^2.9.3",
4161 "svelte-awesome-slider": "2.0.0"4213 "svelte-awesome-slider": "2.0.0"
4162 },4214 },
4215+ "engines": {
4216+ "node": ">=24"
4217+ },
4163 "peerDependencies": {4218 "peerDependencies": {
4164 "svelte": "^5.0.0"4219 "svelte": "^5.0.0"
4165 }4220 }
@@ -4175,9 +4230,9 @@
4175 }4230 }
4176 },4231 },
4177 "node_modules/svelte-check": {4232 "node_modules/svelte-check": {
4178- "version": "4.3.4",4233+ "version": "4.3.5",
4179- "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.3.4.tgz",4234+ "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.3.5.tgz",
4180- "integrity": "sha512-DVWvxhBrDsd+0hHWKfjP99lsSXASeOhHJYyuKOFYJcP7ThfSCKgjVarE8XfuMWpS5JV3AlDf+iK1YGGo2TACdw==",4235+ "integrity": "sha512-e4VWZETyXaKGhpkxOXP+B/d0Fp/zKViZoJmneZWe/05Y2aqSKj3YN2nLfYPJBQ87WEiY4BQCQ9hWGu9mPT1a1Q==",
4181 "dev": true,4236 "dev": true,
4182 "license": "MIT",4237 "license": "MIT",
4183 "dependencies": {4238 "dependencies": {
@@ -4198,24 +4253,6 @@
4198 "typescript": ">=5.0.0"4253 "typescript": ">=5.0.0"
4199 }4254 }
4200 },4255 },
4201- "node_modules/svelte-check/node_modules/fdir": {
4202- "version": "6.5.0",
4203- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
4204- "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
4205- "dev": true,
4206- "license": "MIT",
4207- "engines": {
4208- "node": ">=12.0.0"
4209- },
4210- "peerDependencies": {
4211- "picomatch": "^3 || ^4"
4212- },
4213- "peerDependenciesMeta": {
4214- "picomatch": {
4215- "optional": true
4216- }
4217- }
4218- },
4219 "node_modules/svelte-toolbelt": {4256 "node_modules/svelte-toolbelt": {
4220 "version": "0.10.6",4257 "version": "0.10.6",
4221 "resolved": "https://registry.npmjs.org/svelte-toolbelt/-/svelte-toolbelt-0.10.6.tgz",4258 "resolved": "https://registry.npmjs.org/svelte-toolbelt/-/svelte-toolbelt-0.10.6.tgz",
@@ -4237,9 +4274,9 @@
4237 }4274 }
4238 },4275 },
4239 "node_modules/tabbable": {4276 "node_modules/tabbable": {
4240- "version": "6.3.0",4277+ "version": "6.4.0",
4241- "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.3.0.tgz",4278+ "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz",
4242- "integrity": "sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==",4279+ "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==",
4243 "license": "MIT"4280 "license": "MIT"
4244 },4281 },
4245 "node_modules/tailwind-merge": {4282 "node_modules/tailwind-merge": {
@@ -4274,9 +4311,9 @@
4274 }4311 }
4275 },4312 },
4276 "node_modules/tailwindcss": {4313 "node_modules/tailwindcss": {
4277- "version": "4.1.17",4314+ "version": "4.1.18",
4278- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz",4315+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
4279- "integrity": "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==",4316+ "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
4280 "dev": true,4317 "dev": true,
4281 "license": "MIT",4318 "license": "MIT",
4282 "peer": true4319 "peer": true
@@ -4319,38 +4356,6 @@
4319 "url": "https://github.com/sponsors/SuperchupuDev"4356 "url": "https://github.com/sponsors/SuperchupuDev"
4320 }4357 }
4321 },4358 },
4322- "node_modules/tinyglobby/node_modules/fdir": {
4323- "version": "6.5.0",
4324- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
4325- "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
4326- "dev": true,
4327- "license": "MIT",
4328- "engines": {
4329- "node": ">=12.0.0"
4330- },
4331- "peerDependencies": {
4332- "picomatch": "^3 || ^4"
4333- },
4334- "peerDependenciesMeta": {
4335- "picomatch": {
4336- "optional": true
4337- }
4338- }
4339- },
4340- "node_modules/tinyglobby/node_modules/picomatch": {
4341- "version": "4.0.3",
4342- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
4343- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
4344- "dev": true,
4345- "license": "MIT",
4346- "peer": true,
4347- "engines": {
4348- "node": ">=12"
4349- },
4350- "funding": {
4351- "url": "https://github.com/sponsors/jonschlinkert"
4352- }
4353- },
4354 "node_modules/to-regex-range": {4359 "node_modules/to-regex-range": {
4355 "version": "5.0.1",4360 "version": "5.0.1",
4356 "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",4361 "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -4435,16 +4440,16 @@
4435 }4440 }
4436 },4441 },
4437 "node_modules/typescript-eslint": {4442 "node_modules/typescript-eslint": {
4438- "version": "8.48.1",4443+ "version": "8.53.1",
4439- "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.48.1.tgz",4444+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.53.1.tgz",
4440- "integrity": "sha512-FbOKN1fqNoXp1hIl5KYpObVrp0mCn+CLgn479nmu2IsRMrx2vyv74MmsBLVlhg8qVwNFGbXSp8fh1zp8pEoC2A==",4445+ "integrity": "sha512-gB+EVQfP5RDElh9ittfXlhZJdjSU4jUSTyE2+ia8CYyNvet4ElfaLlAIqDvQV9JPknKx0jQH1racTYe/4LaLSg==",
4441 "dev": true,4446 "dev": true,
4442 "license": "MIT",4447 "license": "MIT",
4443 "dependencies": {4448 "dependencies": {
4444- "@typescript-eslint/eslint-plugin": "8.48.1",4449+ "@typescript-eslint/eslint-plugin": "8.53.1",
4445- "@typescript-eslint/parser": "8.48.1",4450+ "@typescript-eslint/parser": "8.53.1",
4446- "@typescript-eslint/typescript-estree": "8.48.1",4451+ "@typescript-eslint/typescript-estree": "8.53.1",
4447- "@typescript-eslint/utils": "8.48.1"4452+ "@typescript-eslint/utils": "8.53.1"
4448 },4453 },
4449 "engines": {4454 "engines": {
4450 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"4455 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4459,21 +4464,20 @@
4459 }4464 }
4460 },4465 },
4461 "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": {4466 "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": {
4462- "version": "8.48.1",4467+ "version": "8.53.1",
4463- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.1.tgz",4468+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.1.tgz",
4464- "integrity": "sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==",4469+ "integrity": "sha512-cFYYFZ+oQFi6hUnBTbLRXfTJiaQtYE3t4O692agbBl+2Zy+eqSKWtPjhPXJu1G7j4RLjKgeJPDdq3EqOwmX5Ag==",
4465 "dev": true,4470 "dev": true,
4466 "license": "MIT",4471 "license": "MIT",
4467 "dependencies": {4472 "dependencies": {
4468- "@eslint-community/regexpp": "^4.10.0",4473+ "@eslint-community/regexpp": "^4.12.2",
4469- "@typescript-eslint/scope-manager": "8.48.1",4474+ "@typescript-eslint/scope-manager": "8.53.1",
4470- "@typescript-eslint/type-utils": "8.48.1",4475+ "@typescript-eslint/type-utils": "8.53.1",
4471- "@typescript-eslint/utils": "8.48.1",4476+ "@typescript-eslint/utils": "8.53.1",
4472- "@typescript-eslint/visitor-keys": "8.48.1",4477+ "@typescript-eslint/visitor-keys": "8.53.1",
4473- "graphemer": "^1.4.0",4478+ "ignore": "^7.0.5",
4474- "ignore": "^7.0.0",
4475 "natural-compare": "^1.4.0",4479 "natural-compare": "^1.4.0",
4476- "ts-api-utils": "^2.1.0"4480+ "ts-api-utils": "^2.4.0"
4477 },4481 },
4478 "engines": {4482 "engines": {
4479 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"4483 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4483,24 +4487,24 @@
4483 "url": "https://opencollective.com/typescript-eslint"4487 "url": "https://opencollective.com/typescript-eslint"
4484 },4488 },
4485 "peerDependencies": {4489 "peerDependencies": {
4486- "@typescript-eslint/parser": "^8.48.1",4490+ "@typescript-eslint/parser": "^8.53.1",
4487 "eslint": "^8.57.0 || ^9.0.0",4491 "eslint": "^8.57.0 || ^9.0.0",
4488 "typescript": ">=4.8.4 <6.0.0"4492 "typescript": ">=4.8.4 <6.0.0"
4489 }4493 }
4490 },4494 },
4491 "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": {4495 "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": {
4492- "version": "8.48.1",4496+ "version": "8.53.1",
4493- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.1.tgz",4497+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.53.1.tgz",
4494- "integrity": "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==",4498+ "integrity": "sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==",
4495 "dev": true,4499 "dev": true,
4496 "license": "MIT",4500 "license": "MIT",
4497 "peer": true,4501 "peer": true,
4498 "dependencies": {4502 "dependencies": {
4499- "@typescript-eslint/scope-manager": "8.48.1",4503+ "@typescript-eslint/scope-manager": "8.53.1",
4500- "@typescript-eslint/types": "8.48.1",4504+ "@typescript-eslint/types": "8.53.1",
4501- "@typescript-eslint/typescript-estree": "8.48.1",4505+ "@typescript-eslint/typescript-estree": "8.53.1",
4502- "@typescript-eslint/visitor-keys": "8.48.1",4506+ "@typescript-eslint/visitor-keys": "8.53.1",
4503- "debug": "^4.3.4"4507+ "debug": "^4.4.3"
4504 },4508 },
4505 "engines": {4509 "engines": {
4506 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"4510 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4515,14 +4519,14 @@
4515 }4519 }
4516 },4520 },
4517 "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": {4521 "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": {
4518- "version": "8.48.1",4522+ "version": "8.53.1",
4519- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.1.tgz",4523+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.53.1.tgz",
4520- "integrity": "sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==",4524+ "integrity": "sha512-Lu23yw1uJMFY8cUeq7JlrizAgeQvWugNQzJp8C3x8Eo5Jw5Q2ykMdiiTB9vBVOOUBysMzmRRmUfwFrZuI2C4SQ==",
4521 "dev": true,4525 "dev": true,
4522 "license": "MIT",4526 "license": "MIT",
4523 "dependencies": {4527 "dependencies": {
4524- "@typescript-eslint/types": "8.48.1",4528+ "@typescript-eslint/types": "8.53.1",
4525- "@typescript-eslint/visitor-keys": "8.48.1"4529+ "@typescript-eslint/visitor-keys": "8.53.1"
4526 },4530 },
4527 "engines": {4531 "engines": {
4528 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"4532 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4533,17 +4537,17 @@
4533 }4537 }
4534 },4538 },
4535 "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": {4539 "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": {
4536- "version": "8.48.1",4540+ "version": "8.53.1",
4537- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.1.tgz",4541+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.53.1.tgz",
4538- "integrity": "sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==",4542+ "integrity": "sha512-MOrdtNvyhy0rHyv0ENzub1d4wQYKb2NmIqG7qEqPWFW7Mpy2jzFC3pQ2yKDvirZB7jypm5uGjF2Qqs6OIqu47w==",
4539 "dev": true,4543 "dev": true,
4540 "license": "MIT",4544 "license": "MIT",
4541 "dependencies": {4545 "dependencies": {
4542- "@typescript-eslint/types": "8.48.1",4546+ "@typescript-eslint/types": "8.53.1",
4543- "@typescript-eslint/typescript-estree": "8.48.1",4547+ "@typescript-eslint/typescript-estree": "8.53.1",
4544- "@typescript-eslint/utils": "8.48.1",4548+ "@typescript-eslint/utils": "8.53.1",
4545- "debug": "^4.3.4",4549+ "debug": "^4.4.3",
4546- "ts-api-utils": "^2.1.0"4550+ "ts-api-utils": "^2.4.0"
4547 },4551 },
4548 "engines": {4552 "engines": {
4549 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"4553 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4558,9 +4562,9 @@
4558 }4562 }
4559 },4563 },
4560 "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": {4564 "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": {
4561- "version": "8.48.1",4565+ "version": "8.53.1",
4562- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.1.tgz",4566+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.53.1.tgz",
4563- "integrity": "sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==",4567+ "integrity": "sha512-jr/swrr2aRmUAUjW5/zQHbMaui//vQlsZcJKijZf3M26bnmLj8LyZUpj8/Rd6uzaek06OWsqdofN/Thenm5O8A==",
4564 "dev": true,4568 "dev": true,
4565 "license": "MIT",4569 "license": "MIT",
4566 "engines": {4570 "engines": {
@@ -4572,21 +4576,21 @@
4572 }4576 }
4573 },4577 },
4574 "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": {4578 "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": {
4575- "version": "8.48.1",4579+ "version": "8.53.1",
4576- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.1.tgz",4580+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.53.1.tgz",
4577- "integrity": "sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==",4581+ "integrity": "sha512-RGlVipGhQAG4GxV1s34O91cxQ/vWiHJTDHbXRr0li2q/BGg3RR/7NM8QDWgkEgrwQYCvmJV9ichIwyoKCQ+DTg==",
4578 "dev": true,4582 "dev": true,
4579 "license": "MIT",4583 "license": "MIT",
4580 "dependencies": {4584 "dependencies": {
4581- "@typescript-eslint/project-service": "8.48.1",4585+ "@typescript-eslint/project-service": "8.53.1",
4582- "@typescript-eslint/tsconfig-utils": "8.48.1",4586+ "@typescript-eslint/tsconfig-utils": "8.53.1",
4583- "@typescript-eslint/types": "8.48.1",4587+ "@typescript-eslint/types": "8.53.1",
4584- "@typescript-eslint/visitor-keys": "8.48.1",4588+ "@typescript-eslint/visitor-keys": "8.53.1",
4585- "debug": "^4.3.4",4589+ "debug": "^4.4.3",
4586- "minimatch": "^9.0.4",4590+ "minimatch": "^9.0.5",
4587- "semver": "^7.6.0",4591+ "semver": "^7.7.3",
4588 "tinyglobby": "^0.2.15",4592 "tinyglobby": "^0.2.15",
4589- "ts-api-utils": "^2.1.0"4593+ "ts-api-utils": "^2.4.0"
4590 },4594 },
4591 "engines": {4595 "engines": {
4592 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"4596 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4600,16 +4604,16 @@
4600 }4604 }
4601 },4605 },
4602 "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": {4606 "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": {
4603- "version": "8.48.1",4607+ "version": "8.53.1",
4604- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.1.tgz",4608+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.53.1.tgz",
4605- "integrity": "sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==",4609+ "integrity": "sha512-c4bMvGVWW4hv6JmDUEG7fSYlWOl3II2I4ylt0NM+seinYQlZMQIaKaXIIVJWt9Ofh6whrpM+EdDQXKXjNovvrg==",
4606 "dev": true,4610 "dev": true,
4607 "license": "MIT",4611 "license": "MIT",
4608 "dependencies": {4612 "dependencies": {
4609- "@eslint-community/eslint-utils": "^4.7.0",4613+ "@eslint-community/eslint-utils": "^4.9.1",
4610- "@typescript-eslint/scope-manager": "8.48.1",4614+ "@typescript-eslint/scope-manager": "8.53.1",
4611- "@typescript-eslint/types": "8.48.1",4615+ "@typescript-eslint/types": "8.53.1",
4612- "@typescript-eslint/typescript-estree": "8.48.1"4616+ "@typescript-eslint/typescript-estree": "8.53.1"
4613 },4617 },
4614 "engines": {4618 "engines": {
4615 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"4619 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4624,13 +4628,13 @@
4624 }4628 }
4625 },4629 },
4626 "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": {4630 "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": {
4627- "version": "8.48.1",4631+ "version": "8.53.1",
4628- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.1.tgz",4632+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.53.1.tgz",
4629- "integrity": "sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==",4633+ "integrity": "sha512-oy+wV7xDKFPRyNggmXuZQSBzvoLnpmJs+GhzRhPjrxl2b/jIlyjVokzm47CZCDUdXKr2zd7ZLodPfOBpOPyPlg==",
4630 "dev": true,4634 "dev": true,
4631 "license": "MIT",4635 "license": "MIT",
4632 "dependencies": {4636 "dependencies": {
4633- "@typescript-eslint/types": "8.48.1",4637+ "@typescript-eslint/types": "8.53.1",
4634 "eslint-visitor-keys": "^4.2.1"4638 "eslint-visitor-keys": "^4.2.1"
4635 },4639 },
4636 "engines": {4640 "engines": {
@@ -4665,9 +4669,9 @@
4665 }4669 }
4666 },4670 },
4667 "node_modules/typescript-eslint/node_modules/ts-api-utils": {4671 "node_modules/typescript-eslint/node_modules/ts-api-utils": {
4668- "version": "2.1.0",4672+ "version": "2.4.0",
4669- "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",4673+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz",
4670- "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",4674+ "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==",
4671 "dev": true,4675 "dev": true,
4672 "license": "MIT",4676 "license": "MIT",
4673 "engines": {4677 "engines": {
@@ -4685,9 +4689,9 @@
4685 "license": "MIT"4689 "license": "MIT"
4686 },4690 },
4687 "node_modules/update-browserslist-db": {4691 "node_modules/update-browserslist-db": {
4688- "version": "1.2.2",4692+ "version": "1.2.3",
4689- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz",4693+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
4690- "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==",4694+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
4691 "dev": true,4695 "dev": true,
4692 "funding": [4696 "funding": [
4693 {4697 {

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close