From 3a01cffc6b17ed64f784c47692b85e0cdf1bb771 Mon Sep 17 00:00:00 2001 From: sudacode Date: Sat, 21 Mar 2026 23:37:42 -0700 Subject: [PATCH] feat(subtitle-sidebar): add sidebar config surface (#28) --- CHANGELOG.md | 16 + ...o-resume-position-on-first-resolved-cue.md | 37 + ...p-auto-open-option-for-subtitle-sidebar.md | 40 + ...deRabbit-follow-ups-on-subtitle-sidebar.md | 79 + ...rough-sync-between-subtitle-and-sidebar.md | 69 + bun.lock | 508 ++-- ...2026-03-19-incremental-known-word-cache.md | 4 - .../2026-03-19-known-jlpt-reading-fallback.md | 4 - .../2026-03-19-stats-ended-media-progress.md | 4 - ...03-19-stats-session-progress-checkpoint.md | 4 - ...026-03-19-texthooker-docs-bundle-update.md | 4 - ...tats-episode-progress-subtitle-fallback.md | 4 - changes/2026-03-22-subtitle-sidebar-config.md | 5 + config.example.jsonc | 24 + docs-site/changelog.md | 9 + docs-site/configuration.md | 42 + docs-site/public/config.example.jsonc | 24 + docs-site/shortcuts.md | 5 +- package.json | 31 +- scripts/patch-modernz.sh | 157 ++ scripts/patch-modernz.test.ts | 76 + src/config/definitions.ts | 3 +- src/config/definitions/defaults-subtitle.ts | 20 +- src/config/definitions/options-subtitle.ts | 97 + src/config/definitions/template-sections.ts | 6 + src/config/resolve/shared.ts | 40 + src/config/resolve/subtitle-domains.ts | 177 ++ src/config/resolve/subtitle-sidebar.test.ts | 93 + src/core/services/config-hot-reload.ts | 5 +- src/core/services/ipc.test.ts | 50 + src/core/services/ipc.ts | 11 + src/core/services/subtitle-cue-parser.test.ts | 2 +- src/core/services/subtitle-cue-parser.ts | 8 +- src/core/services/subtitle-prefetch.test.ts | 2 +- src/core/services/subtitle-prefetch.ts | 2 +- src/main.ts | 332 ++- src/main/dependencies.ts | 2 + .../runtime/config-hot-reload-handlers.ts | 1 + .../runtime/mpv-main-event-actions.test.ts | 33 +- src/main/runtime/mpv-main-event-actions.ts | 2 + .../runtime/mpv-main-event-bindings.test.ts | 3 + src/main/runtime/mpv-main-event-bindings.ts | 10 +- .../runtime/mpv-main-event-main-deps.test.ts | 5 +- src/main/runtime/mpv-main-event-main-deps.ts | 2 + .../runtime/subtitle-prefetch-init.test.ts | 124 +- src/main/runtime/subtitle-prefetch-init.ts | 24 +- .../runtime/subtitle-prefetch-source.test.ts | 45 + src/main/runtime/subtitle-prefetch-source.ts | 36 +- src/main/state.ts | 5 + src/preload.ts | 2 + src/release-workflow.test.ts | 15 + src/renderer/handlers/keyboard.ts | 27 + src/renderer/handlers/mouse.test.ts | 167 +- src/renderer/handlers/mouse.ts | 65 +- src/renderer/index.html | 12 + src/renderer/modals/subtitle-sidebar.test.ts | 2052 +++++++++++++++++ src/renderer/modals/subtitle-sidebar.ts | 599 +++++ src/renderer/overlay-mouse-ignore.ts | 42 + src/renderer/renderer.ts | 37 +- src/renderer/state.ts | 22 + src/renderer/style.css | 236 +- src/renderer/subtitle-render.test.ts | 43 + src/renderer/utils/dom.ts | 10 + src/shared/ipc/contracts.ts | 2 + src/types.ts | 48 +- vendor/texthooker-ui | 2 +- 66 files changed, 5241 insertions(+), 426 deletions(-) create mode 100644 backlog/tasks/task-214 - Jump-subtitle-sidebar-directly-to-resume-position-on-first-resolved-cue.md create mode 100644 backlog/tasks/task-215 - Add-startup-auto-open-option-for-subtitle-sidebar.md create mode 100644 backlog/tasks/task-216 - Address-PR-28-CodeRabbit-follow-ups-on-subtitle-sidebar.md create mode 100644 backlog/tasks/task-217 - Fix-embedded-overlay-passthrough-sync-between-subtitle-and-sidebar.md delete mode 100644 changes/2026-03-19-incremental-known-word-cache.md delete mode 100644 changes/2026-03-19-known-jlpt-reading-fallback.md delete mode 100644 changes/2026-03-19-stats-ended-media-progress.md delete mode 100644 changes/2026-03-19-stats-session-progress-checkpoint.md delete mode 100644 changes/2026-03-19-texthooker-docs-bundle-update.md delete mode 100644 changes/2026-03-20-stats-episode-progress-subtitle-fallback.md create mode 100644 changes/2026-03-22-subtitle-sidebar-config.md create mode 100755 scripts/patch-modernz.sh create mode 100644 scripts/patch-modernz.test.ts create mode 100644 src/config/resolve/subtitle-sidebar.test.ts create mode 100644 src/renderer/modals/subtitle-sidebar.test.ts create mode 100644 src/renderer/modals/subtitle-sidebar.ts create mode 100644 src/renderer/overlay-mouse-ignore.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index b56d34d..13528f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## v0.8.0 (2026-03-22) + +### Changed +- Docs: Refreshed the vendored Texthooker docs/index.html bundle to match the latest local build artifacts. + +### Fixed +- Anki: Known-word cache refreshes now reconcile Anki changes incrementally instead of wiping and rebuilding on startup, mined cards can append their word into the cache immediately through a new default-enabled config flag, and explicit refreshes now run through `subminer doctor --refresh-known-words`. +- Subtitle: Restored known-word coloring and JLPT underlines for subtitle tokens like `大体` when the subtitle token is kanji but the known-word cache only matches the kana reading. +- Stats: Episode progress in the anime page now uses the last ended playback position instead of cumulative active watch time, avoiding distorted percentages after rewatches or repeated sessions. +- Stats: Anime episode progress now keeps the latest known playback position through active-session checkpoints and stale-session recovery, so recently watched episodes no longer lose their progress percentage. +- Stats: Anime episode progress now falls back to the latest retained subtitle/event timing when a session is missing a persisted playback-position checkpoint, so older watch sessions no longer get stuck at `0%` progress. +- Overlay: Kept subtitle sidebar cue tracking stable across transitions by avoiding cue-line regression on subtitle timing edge cases and stale text updates. +- Overlay: Improved sidebar config by documenting and exposing layout mode and typography options (`layout`, `fontFamily`, `fontSize`) in the generated documentation flow. +- Overlay: Added `subtitleSidebar.autoOpen` (default `false`) to open the subtitle sidebar once during overlay startup when the sidebar feature is enabled. +- Overlay: Made subtitle sidebar resume/start positioning jump directly to the first resolved active cue instead of smooth-scrolling through the full list, while keeping smooth auto-follow for later cue changes. + ## v0.7.0 (2026-03-19) ### Added diff --git a/backlog/tasks/task-214 - Jump-subtitle-sidebar-directly-to-resume-position-on-first-resolved-cue.md b/backlog/tasks/task-214 - Jump-subtitle-sidebar-directly-to-resume-position-on-first-resolved-cue.md new file mode 100644 index 0000000..b44c1af --- /dev/null +++ b/backlog/tasks/task-214 - Jump-subtitle-sidebar-directly-to-resume-position-on-first-resolved-cue.md @@ -0,0 +1,37 @@ +--- +id: TASK-214 +title: Jump subtitle sidebar directly to resume position on first resolved cue +status: In Progress +assignee: [] +created_date: '2026-03-21 11:15' +updated_date: '2026-03-21 11:15' +labels: + - bug + - ux + - overlay + - subtitles +dependencies: [] +references: + - /Users/sudacode/projects/japanese/SubMiner/src/renderer/modals/subtitle-sidebar.ts + - /Users/sudacode/projects/japanese/SubMiner/src/renderer/modals/subtitle-sidebar.test.ts +priority: medium +--- + +## Description + + +When playback starts from a resumed timestamp while the subtitle sidebar is open, the sidebar currently smooth-scrolls from the top of the cue list to the resumed cue. Change the first resolved active-cue positioning to jump immediately to the resume location while preserving smooth auto-follow for later playback-driven cue advances. + + +## Acceptance Criteria + +- [x] #1 The first active cue resolved after open/resume uses an instant jump instead of smooth-scrolling through the list. +- [x] #2 Normal subtitle-sidebar auto-follow remains smooth after the first active cue has been positioned. +- [x] #3 Regression coverage distinguishes the initial jump behavior from later smooth auto-follow updates. + + +## Implementation Notes + + +2026-03-21: Fixed by treating the first auto-scroll from `previousActiveCueIndex < 0` as `behavior: 'auto'` in the subtitle sidebar scroll helper. Added renderer regression coverage for initial jump plus later smooth follow. + diff --git a/backlog/tasks/task-215 - Add-startup-auto-open-option-for-subtitle-sidebar.md b/backlog/tasks/task-215 - Add-startup-auto-open-option-for-subtitle-sidebar.md new file mode 100644 index 0000000..f3434ed --- /dev/null +++ b/backlog/tasks/task-215 - Add-startup-auto-open-option-for-subtitle-sidebar.md @@ -0,0 +1,40 @@ +--- +id: TASK-215 +title: Add startup auto-open option for subtitle sidebar +status: In Progress +assignee: [] +created_date: '2026-03-21 11:35' +updated_date: '2026-03-21 11:35' +labels: + - feature + - ux + - overlay + - subtitles +dependencies: [] +references: + - /Users/sudacode/projects/japanese/SubMiner/src/types.ts + - /Users/sudacode/projects/japanese/SubMiner/src/config/definitions/defaults-subtitle.ts + - /Users/sudacode/projects/japanese/SubMiner/src/config/resolve/subtitle-domains.ts + - /Users/sudacode/projects/japanese/SubMiner/src/renderer/modals/subtitle-sidebar.ts + - /Users/sudacode/projects/japanese/SubMiner/src/renderer/renderer.ts +priority: medium +--- + +## Description + + +Add a subtitle sidebar config option that auto-opens the sidebar once during overlay startup. The option should default to `false`, only apply when the sidebar feature is enabled, and should not force the sidebar back open later in the same session after manual close or later visibility changes. + + +## Acceptance Criteria + +- [x] #1 `subtitleSidebar.autoOpen` is available in config with default `false`. +- [x] #2 When enabled, overlay startup opens the subtitle sidebar once after initial sidebar config/snapshot load. +- [x] #3 Regression coverage covers config resolution and startup-only auto-open behavior. + + +## Implementation Notes + + +2026-03-21: Added `subtitleSidebar.autoOpen` to types/defaults/config registry and resolver. Renderer bootstrap now calls a startup-only subtitle sidebar helper after the initial snapshot refresh. Modal regression coverage verifies startup auto-open requires both `enabled` and `autoOpen`. + diff --git a/backlog/tasks/task-216 - Address-PR-28-CodeRabbit-follow-ups-on-subtitle-sidebar.md b/backlog/tasks/task-216 - Address-PR-28-CodeRabbit-follow-ups-on-subtitle-sidebar.md new file mode 100644 index 0000000..867dce0 --- /dev/null +++ b/backlog/tasks/task-216 - Address-PR-28-CodeRabbit-follow-ups-on-subtitle-sidebar.md @@ -0,0 +1,79 @@ +--- +id: TASK-216 +title: 'Address PR #28 CodeRabbit follow-ups on subtitle sidebar' +status: Completed +assignee: + - '@codex' +created_date: '2026-03-21 00:00' +updated_date: '2026-03-21 00:00' +labels: + - pr-review + - subtitle-sidebar + - renderer +dependencies: [] +references: + - src/main/runtime/subtitle-prefetch-init.ts + - src/main/runtime/subtitle-prefetch-init.test.ts + - src/renderer/handlers/mouse.ts + - src/renderer/handlers/mouse.test.ts + - src/renderer/modals/subtitle-sidebar.ts + - src/renderer/modals/subtitle-sidebar.test.ts + - src/renderer/style.css +priority: medium +--- + +## Description + + +Validate the CodeRabbit follow-ups on PR #28 for the subtitle sidebar workstream, implement the confirmed fixes, and verify the touched runtime and renderer paths. + + +## Acceptance Criteria + +- [x] #1 Review comments that described real regressions are fixed in code +- [x] #2 Focused regression coverage exists for the fixed behaviors +- [x] #3 Targeted typecheck and runtime-compat verification pass + + +## Implementation Notes + + +Completed follow-up fixes for PR #28: +- Cleared parsed subtitle cues on subtitle prefetch init failure so stale snapshot cache entries do not survive a failed refresh. +- Treated primary and secondary subtitle containers as one hover region so moving between them does not resume playback mid-transition. +- Kept the subtitle sidebar closed when disabled, serialized snapshot polling with timeouts, made cue rows keyboard-activatable, resolved stale cue selection fallback, and resumed hover-paused playback when the modal closes. + +Regression coverage added: +- `src/main/runtime/subtitle-prefetch-init.test.ts` +- `src/renderer/handlers/mouse.test.ts` +- `src/renderer/modals/subtitle-sidebar.test.ts` + +Verification: +- `bun test src/main/runtime/subtitle-prefetch-init.test.ts` +- `bun test src/renderer/handlers/mouse.test.ts` +- `bun test src/renderer/modals/subtitle-sidebar.test.ts` +- `bun run typecheck` +- `bun run test:runtime:compat` + +2026-03-21: Reopened to assess a newer CodeRabbit review pass on PR #28 and address any remaining valid action items before push/reply. + +2026-03-21: Addressed the latest CodeRabbit follow-up pass in commit d70c6448 after rebasing onto the updated remote branch tip. + +2026-03-21: Reopened for the latest CodeRabbit round on commit d70c6448; current actionable item is the invalid ctx.state.isOverSubtitleSidebar assignment in subtitle-sidebar.ts. + +2026-03-22: Addressed the live hover-state and startup mouse-ignore follow-ups from the latest CodeRabbit pass. `handleMouseLeave()` now clears `isOverSubtitle` and drops `secondary-sub-hover-active` when leaving the secondary subtitle container toward the primary container, and renderer startup now calls `syncOverlayMouseIgnoreState(ctx)` instead of forcing `setIgnoreMouseEvents(true, { forward: true })`. The sidebar IPC hover catch and CSS spacing comments were already satisfied in the current tree. + +2026-03-22: Regenerated `bun.lock` from a clean install so the `electron-builder-squirrel-windows` override now resolves at `26.8.2` in the lockfile alongside `app-builder-lib@26.8.2`. + +2026-03-21: Finished the remaining cleanup pass from the latest review. `subtitleSidebar.layout` now uses enum validation, `SubtitleCue` is re-exported from `src/types.ts` as the single public type path, and the subtitle sidebar resize listener now has unload cleanup wired through the renderer. + + +## Final Summary + + +Implemented the confirmed PR #28 CodeRabbit follow-ups for subtitle sidebar behavior and added regression coverage plus verification for the touched renderer and runtime paths. + +Handled the latest CodeRabbit review pass for PR #28: accepted zero sidebar opacity, closed/inerted the sidebar when refresh sees config disabled, moved poll rescheduling out of finally, caught hover pause IPC failures, and fixed the stylelint spacing issue. + +Verification: bun test src/config/resolve/subtitle-sidebar.test.ts; bun test src/renderer/modals/subtitle-sidebar.test.ts; bun test src/renderer/handlers/mouse.test.ts; bun run typecheck; bun run test:fast; bun run test:env; bun run build; SubMiner verifier lanes config + runtime-compat (including test:runtime:compat and test:smoke:dist). + diff --git a/backlog/tasks/task-217 - Fix-embedded-overlay-passthrough-sync-between-subtitle-and-sidebar.md b/backlog/tasks/task-217 - Fix-embedded-overlay-passthrough-sync-between-subtitle-and-sidebar.md new file mode 100644 index 0000000..287151c --- /dev/null +++ b/backlog/tasks/task-217 - Fix-embedded-overlay-passthrough-sync-between-subtitle-and-sidebar.md @@ -0,0 +1,69 @@ +--- +id: TASK-217 +title: Fix embedded overlay passthrough sync between subtitle and sidebar +status: Done +assignee: + - codex +created_date: '2026-03-21 23:16' +updated_date: '2026-03-21 23:28' +labels: + - bug + - overlay + - macos +dependencies: [] +references: + - src/renderer/handlers/mouse.ts + - src/renderer/modals/subtitle-sidebar.ts + - src/renderer/renderer.ts +documentation: + - docs/workflow/verification.md +priority: high +--- + +## Description + + +On macOS, when both the subtitle overlay and embedded subtitle sidebar are visible, mouse passthrough to mpv can remain stale until the user hovers the sidebar. After closing the sidebar, passthrough can likewise remain stale until the user hovers the subtitle again. Fix the overlay input-state synchronization so passthrough reflects the current hover/open state immediately instead of relying on the last hover target. + + +## Acceptance Criteria + +- [x] #1 When the embedded subtitle sidebar is open and the pointer is not over subtitle or sidebar content, the overlay returns to mouse passthrough immediately without requiring a sidebar hover cycle. +- [x] #2 When transitioning between subtitle hover and sidebar hover states on macOS embedded sidebar mode, mouse ignore state stays in sync with the currently interactive region. +- [x] #3 Closing the embedded subtitle sidebar restores the correct passthrough state based on remaining subtitle hover/modal state without requiring an additional hover. +- [x] #4 Regression tests cover the passthrough synchronization behavior. + + +## Implementation Plan + + +1. Add a shared renderer-side passthrough sync helper that derives whether the overlay should ignore mouse events from subtitle hover, embedded sidebar visibility/hover, popup visibility, and modal state. +2. Replace direct embedded-sidebar passthrough toggles in subtitle hover/sidebar handlers with calls to the shared sync helper so state is recomputed on every transition. +3. Add regression tests for macOS embedded sidebar mode covering sidebar-open idle passthrough, subtitle-to-sidebar transitions, and sidebar-close restore behavior. +4. Run targeted renderer tests for mouse/sidebar passthrough coverage, then summarize any residual risk. + + +## Implementation Notes + + +Added shared renderer overlay mouse-ignore recompute so subtitle hover, embedded sidebar hover/open/close, and popup idle transitions all derive passthrough from current state instead of last hover target. + +Added regression coverage for embedded sidebar idle passthrough on subtitle leave and for sidebar-close recompute behavior. + +Verification: `bun run typecheck` passed; `bun test src/renderer/handlers/mouse.test.ts` passed; `bun test src/renderer/modals/subtitle-sidebar.test.ts` passed; core verification wrapper artifact at `.tmp/skill-verification/subminer-verify-20260321-162743-XhSBxw` hit an unrelated `bun run test:fast` failure in `scripts/update-aur-package.test.ts` because macOS system bash lacks `mapfile`. + + +## Final Summary + + +Fixed stale embedded-sidebar passthrough sync on macOS by introducing a shared renderer mouse-ignore recompute path and tracking sidebar-hover state separately from subtitle hover. Subtitle hover leave, sidebar hover enter/leave, sidebar open, and sidebar close now all recompute passthrough from the current overlay state instead of waiting for a later hover event to repair it. Added regression tests covering subtitle-leave passthrough while the embedded sidebar is open but idle, plus sidebar-close restore behavior based on remaining subtitle hover state. + +Tests run: +- `bun run typecheck` +- `bun test src/renderer/handlers/mouse.test.ts` +- `bun test src/renderer/modals/subtitle-sidebar.test.ts` +- `bash .agents/skills/subminer-change-verification/scripts/classify_subminer_diff.sh src/renderer/state.ts src/renderer/overlay-mouse-ignore.ts src/renderer/handlers/mouse.ts src/renderer/handlers/mouse.test.ts src/renderer/modals/subtitle-sidebar.ts src/renderer/modals/subtitle-sidebar.test.ts` +- `bash .agents/skills/subminer-change-verification/scripts/verify_subminer_change.sh --lane core src/renderer/state.ts src/renderer/overlay-mouse-ignore.ts src/renderer/handlers/mouse.ts src/renderer/handlers/mouse.test.ts src/renderer/modals/subtitle-sidebar.ts src/renderer/modals/subtitle-sidebar.test.ts` (typecheck passed; `test:fast` blocked by unrelated `scripts/update-aur-package.test.ts` failure on macOS Bash 3.2 lacking `mapfile`) + +Risk: the classifier flagged this as a real-runtime candidate, so actual Electron/mpv macOS pointer behavior was not exercised in a live runtime during this turn. + diff --git a/bun.lock b/bun.lock index ae9b817..ec313d7 100644 --- a/bun.lock +++ b/bun.lock @@ -1,6 +1,6 @@ { "lockfileVersion": 1, - "configVersion": 0, + "configVersion": 1, "workspaces": { "": { "name": "subminer", @@ -20,33 +20,39 @@ "@types/node": "^25.3.0", "@types/ws": "^8.18.1", "electron": "^37.10.3", - "electron-builder": "^26.8.1", + "electron-builder": "26.8.2", "esbuild": "^0.25.12", "prettier": "^3.8.1", "typescript": "^5.9.3", }, }, }, + "overrides": { + "app-builder-lib": "26.8.2", + "electron-builder-squirrel-windows": "26.8.2", + "minimatch": "10.2.3", + "tar": "7.5.11", + }, "packages": { "7zip-bin": ["7zip-bin@5.2.0", "", {}, "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A=="], - "@develar/schema-utils": ["@develar/schema-utils@2.6.5", "", { "dependencies": { "ajv": "6.12.6", "ajv-keywords": "3.5.2" } }, "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig=="], + "@develar/schema-utils": ["@develar/schema-utils@2.6.5", "", { "dependencies": { "ajv": "^6.12.0", "ajv-keywords": "^3.4.1" } }, "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig=="], - "@electron/asar": ["@electron/asar@3.4.1", "", { "dependencies": { "commander": "5.1.0", "glob": "7.2.3", "minimatch": "3.1.2" }, "bin": { "asar": "bin/asar.js" } }, "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA=="], + "@electron/asar": ["@electron/asar@3.4.1", "", { "dependencies": { "commander": "^5.0.0", "glob": "^7.1.6", "minimatch": "^3.0.4" }, "bin": { "asar": "bin/asar.js" } }, "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA=="], - "@electron/fuses": ["@electron/fuses@1.8.0", "", { "dependencies": { "chalk": "4.1.2", "fs-extra": "9.1.0", "minimist": "1.2.8" }, "bin": { "electron-fuses": "dist/bin.js" } }, "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw=="], + "@electron/fuses": ["@electron/fuses@1.8.0", "", { "dependencies": { "chalk": "^4.1.1", "fs-extra": "^9.0.1", "minimist": "^1.2.5" }, "bin": { "electron-fuses": "dist/bin.js" } }, "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw=="], - "@electron/get": ["@electron/get@2.0.3", "", { "dependencies": { "debug": "4.4.3", "env-paths": "2.2.1", "fs-extra": "8.1.0", "got": "11.8.6", "progress": "2.0.3", "semver": "6.3.1", "sumchecker": "3.0.1" }, "optionalDependencies": { "global-agent": "3.0.0" } }, "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ=="], + "@electron/get": ["@electron/get@2.0.3", "", { "dependencies": { "debug": "^4.1.1", "env-paths": "^2.2.0", "fs-extra": "^8.1.0", "got": "^11.8.5", "progress": "^2.0.3", "semver": "^6.2.0", "sumchecker": "^3.0.1" }, "optionalDependencies": { "global-agent": "^3.0.0" } }, "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ=="], - "@electron/notarize": ["@electron/notarize@2.5.0", "", { "dependencies": { "debug": "4.4.3", "fs-extra": "9.1.0", "promise-retry": "2.0.1" } }, "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A=="], + "@electron/notarize": ["@electron/notarize@2.5.0", "", { "dependencies": { "debug": "^4.1.1", "fs-extra": "^9.0.1", "promise-retry": "^2.0.1" } }, "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A=="], - "@electron/osx-sign": ["@electron/osx-sign@1.3.3", "", { "dependencies": { "compare-version": "0.1.2", "debug": "4.4.3", "fs-extra": "10.1.0", "isbinaryfile": "4.0.10", "minimist": "1.2.8", "plist": "3.1.0" }, "bin": { "electron-osx-flat": "bin/electron-osx-flat.js", "electron-osx-sign": "bin/electron-osx-sign.js" } }, "sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg=="], + "@electron/osx-sign": ["@electron/osx-sign@1.3.3", "", { "dependencies": { "compare-version": "^0.1.2", "debug": "^4.3.4", "fs-extra": "^10.0.0", "isbinaryfile": "^4.0.8", "minimist": "^1.2.6", "plist": "^3.0.5" }, "bin": { "electron-osx-flat": "bin/electron-osx-flat.js", "electron-osx-sign": "bin/electron-osx-sign.js" } }, "sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg=="], - "@electron/rebuild": ["@electron/rebuild@4.0.3", "", { "dependencies": { "@malept/cross-spawn-promise": "2.0.0", "debug": "4.4.3", "detect-libc": "2.1.2", "got": "11.8.6", "graceful-fs": "4.2.11", "node-abi": "4.26.0", "node-api-version": "0.2.1", "node-gyp": "11.5.0", "ora": "5.4.1", "read-binary-file-arch": "1.0.6", "semver": "7.7.4", "tar": "7.5.9", "yargs": "17.7.2" }, "bin": { "electron-rebuild": "lib/cli.js" } }, "sha512-u9vpTHRMkOYCs/1FLiSVAFZ7FbjsXK+bQuzviJZa+lG7BHZl1nz52/IcGvwa3sk80/fc3llutBkbCq10Vh8WQA=="], + "@electron/rebuild": ["@electron/rebuild@4.0.3", "", { "dependencies": { "@malept/cross-spawn-promise": "^2.0.0", "debug": "^4.1.1", "detect-libc": "^2.0.1", "got": "^11.7.0", "graceful-fs": "^4.2.11", "node-abi": "^4.2.0", "node-api-version": "^0.2.1", "node-gyp": "^11.2.0", "ora": "^5.1.0", "read-binary-file-arch": "^1.0.6", "semver": "^7.3.5", "tar": "^7.5.6", "yargs": "^17.0.1" }, "bin": { "electron-rebuild": "lib/cli.js" } }, "sha512-u9vpTHRMkOYCs/1FLiSVAFZ7FbjsXK+bQuzviJZa+lG7BHZl1nz52/IcGvwa3sk80/fc3llutBkbCq10Vh8WQA=="], - "@electron/universal": ["@electron/universal@2.0.3", "", { "dependencies": { "@electron/asar": "3.4.1", "@malept/cross-spawn-promise": "2.0.0", "debug": "4.4.3", "dir-compare": "4.2.0", "fs-extra": "11.3.3", "minimatch": "9.0.5", "plist": "3.1.0" } }, "sha512-Wn9sPYIVFRFl5HmwMJkARCCf7rqK/EurkfQ/rJZ14mHP3iYTjZSIOSVonEAnhWeAXwtw7zOekGRlc6yTtZ0t+g=="], + "@electron/universal": ["@electron/universal@2.0.3", "", { "dependencies": { "@electron/asar": "^3.3.1", "@malept/cross-spawn-promise": "^2.0.0", "debug": "^4.3.1", "dir-compare": "^4.2.0", "fs-extra": "^11.1.1", "minimatch": "^9.0.3", "plist": "^3.1.0" } }, "sha512-Wn9sPYIVFRFl5HmwMJkARCCf7rqK/EurkfQ/rJZ14mHP3iYTjZSIOSVonEAnhWeAXwtw7zOekGRlc6yTtZ0t+g=="], - "@electron/windows-sign": ["@electron/windows-sign@1.2.2", "", { "dependencies": { "cross-dirname": "0.1.0", "debug": "4.4.3", "fs-extra": "11.3.3", "minimist": "1.2.8", "postject": "1.0.0-alpha.6" }, "bin": { "electron-windows-sign": "bin/electron-windows-sign.js" } }, "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ=="], + "@electron/windows-sign": ["@electron/windows-sign@1.2.2", "", { "dependencies": { "cross-dirname": "^0.1.0", "debug": "^4.3.4", "fs-extra": "^11.1.1", "minimist": "^1.2.8", "postject": "^1.0.0-alpha.6" }, "bin": { "electron-windows-sign": "bin/electron-windows-sign.js" } }, "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ=="], "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], @@ -106,67 +112,67 @@ "@hono/node-server": ["@hono/node-server@1.19.11", "", { "peerDependencies": { "hono": "^4" } }, "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g=="], - "@isaacs/cliui": ["@isaacs/cliui@9.0.0", "", {}, "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg=="], + "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], - "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "7.1.2" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], + "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], - "@libsql/darwin-arm64": ["@libsql/darwin-arm64@0.5.22", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4B8ZlX3nIDPndfct7GNe0nI3Yw6ibocEicWdC4fvQbSs/jdq/RC2oCsoJxJ4NzXkvktX70C1J4FcmmoBy069UA=="], + "@libsql/darwin-arm64": ["@libsql/darwin-arm64@0.5.28", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Lc/b8JXO2W2+H+5UXfw7PCHZCim1jlrB0CmLPsjfVmihMluBpdYafFImhjAHxHlWGfuZ32WzjVPUap5fGmkthw=="], - "@libsql/darwin-x64": ["@libsql/darwin-x64@0.5.22", "", { "os": "darwin", "cpu": "x64" }, "sha512-ny2HYWt6lFSIdNFzUFIJ04uiW6finXfMNJ7wypkAD8Pqdm6nAByO+Fdqu8t7sD0sqJGeUCiOg480icjyQ2/8VA=="], + "@libsql/darwin-x64": ["@libsql/darwin-x64@0.5.28", "", { "os": "darwin", "cpu": "x64" }, "sha512-m1hGkQm8A+CjZmR9D5G3zi36na7GXGJomsMbHwOFiCUYPjqRReD5KZ2HZ/qEAV6U/66xPdDDCuqDB8MzNhiwxA=="], - "@libsql/linux-arm-gnueabihf": ["@libsql/linux-arm-gnueabihf@0.5.22", "", { "os": "linux", "cpu": "arm" }, "sha512-3Uo3SoDPJe/zBnyZKosziRGtszXaEtv57raWrZIahtQDsjxBVjuzYQinCm9LRCJCUT5t2r5Z5nLDPJi2CwZVoA=="], + "@libsql/linux-arm-gnueabihf": ["@libsql/linux-arm-gnueabihf@0.5.28", "", { "os": "linux", "cpu": "arm" }, "sha512-D22yQotJkLcYxrwYP9ukoqbpA5hK7pHmho9jagCM/ij7UwjWJPAY2d2SmEndpJs/SueaGy1xuiUQFec4R7VebQ=="], - "@libsql/linux-arm-musleabihf": ["@libsql/linux-arm-musleabihf@0.5.22", "", { "os": "linux", "cpu": "arm" }, "sha512-LCsXh07jvSojTNJptT9CowOzwITznD+YFGGW+1XxUr7fS+7/ydUrpDfsMX7UqTqjm7xG17eq86VkWJgHJfvpNg=="], + "@libsql/linux-arm-musleabihf": ["@libsql/linux-arm-musleabihf@0.5.28", "", { "os": "linux", "cpu": "arm" }, "sha512-Z/aSb2WzZm7TYn/FEqefoN2sJoDhMtCjV8aHw55ibck6mdLLPGMYXxTyWn5U/OZbqD+wiM7eUgdsG20uEzxEoQ=="], - "@libsql/linux-arm64-gnu": ["@libsql/linux-arm64-gnu@0.5.22", "", { "os": "linux", "cpu": "arm64" }, "sha512-KSdnOMy88c9mpOFKUEzPskSaF3VLflfSUCBwas/pn1/sV3pEhtMF6H8VUCd2rsedwoukeeCSEONqX7LLnQwRMA=="], + "@libsql/linux-arm64-gnu": ["@libsql/linux-arm64-gnu@0.5.28", "", { "os": "linux", "cpu": "arm64" }, "sha512-gQGJgmUBdk3qm8rDwvFujzTWipLE4ZNP9fgcdVabVBFmD38wLOU5aZ4F3BHrL1ZWdvsrC8mrtnCTKEGuYHDZIw=="], - "@libsql/linux-arm64-musl": ["@libsql/linux-arm64-musl@0.5.22", "", { "os": "linux", "cpu": "arm64" }, "sha512-mCHSMAsDTLK5YH//lcV3eFEgiR23Ym0U9oEvgZA0667gqRZg/2px+7LshDvErEKv2XZ8ixzw3p1IrBzLQHGSsw=="], + "@libsql/linux-arm64-musl": ["@libsql/linux-arm64-musl@0.5.28", "", { "os": "linux", "cpu": "arm64" }, "sha512-zLlgKyG96DKJ4skFtubHbWuWRUW8YpcjHVyKyJJDIp2USPQKLXfB+rT06OSQIS90Bm3dbfU+9rAlNX0ua0cSvw=="], - "@libsql/linux-x64-gnu": ["@libsql/linux-x64-gnu@0.5.22", "", { "os": "linux", "cpu": "x64" }, "sha512-kNBHaIkSg78Y4BqAdgjcR2mBilZXs4HYkAmi58J+4GRwDQZh5fIUWbnQvB9f95DkWUIGVeenqLRFY2pcTmlsew=="], + "@libsql/linux-x64-gnu": ["@libsql/linux-x64-gnu@0.5.28", "", { "os": "linux", "cpu": "x64" }, "sha512-ra+fk6FmTl8ma4opxcTJ8JIt3KrSr+TrFCJtgccfg+7HDdGiE5Ys6jIJMqYuYG61Mv40z3lPZxRivBK5sP9o/w=="], - "@libsql/linux-x64-musl": ["@libsql/linux-x64-musl@0.5.22", "", { "os": "linux", "cpu": "x64" }, "sha512-UZ4Xdxm4pu3pQXjvfJiyCzZop/9j/eA2JjmhMaAhe3EVLH2g11Fy4fwyUp9sT1QJYR1kpc2JLuybPM0kuXv/Tg=="], + "@libsql/linux-x64-musl": ["@libsql/linux-x64-musl@0.5.28", "", { "os": "linux", "cpu": "x64" }, "sha512-XXl7lHsZEY8szhfMWoe0tFzKXv52nlDt0kckMmtYb97AkKB0bIcxbgx5zTHGyoXLMMhLvEo33OR7NHvjdDyvjw=="], - "@libsql/win32-x64-msvc": ["@libsql/win32-x64-msvc@0.5.22", "", { "os": "win32", "cpu": "x64" }, "sha512-Fj0j8RnBpo43tVZUVoNK6BV/9AtDUM5S7DF3LB4qTYg1LMSZqi3yeCneUTLJD6XomQJlZzbI4mst89yspVSAnA=="], + "@libsql/win32-x64-msvc": ["@libsql/win32-x64-msvc@0.5.28", "", { "os": "win32", "cpu": "x64" }, "sha512-KLB4TQKkRdki9Ugbz+X986a1F7IaZUZbPuTfPNFi7slTT+biSw0b/LPJ0tCk7EHyo5QmN8tZ1XLZwI7GgUBsfA=="], - "@malept/cross-spawn-promise": ["@malept/cross-spawn-promise@2.0.0", "", { "dependencies": { "cross-spawn": "7.0.6" } }, "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg=="], + "@malept/cross-spawn-promise": ["@malept/cross-spawn-promise@2.0.0", "", { "dependencies": { "cross-spawn": "^7.0.1" } }, "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg=="], - "@malept/flatpak-bundler": ["@malept/flatpak-bundler@0.4.0", "", { "dependencies": { "debug": "4.4.3", "fs-extra": "9.1.0", "lodash": "4.17.23", "tmp-promise": "3.0.3" } }, "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q=="], + "@malept/flatpak-bundler": ["@malept/flatpak-bundler@0.4.0", "", { "dependencies": { "debug": "^4.1.1", "fs-extra": "^9.0.0", "lodash": "^4.17.15", "tmp-promise": "^3.0.2" } }, "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q=="], "@neon-rs/load": ["@neon-rs/load@0.0.4", "", {}, "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw=="], - "@npmcli/agent": ["@npmcli/agent@3.0.0", "", { "dependencies": { "agent-base": "7.1.4", "http-proxy-agent": "7.0.2", "https-proxy-agent": "7.0.6", "lru-cache": "10.4.3", "socks-proxy-agent": "8.0.5" } }, "sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q=="], + "@npmcli/agent": ["@npmcli/agent@3.0.0", "", { "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^10.0.1", "socks-proxy-agent": "^8.0.3" } }, "sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q=="], - "@npmcli/fs": ["@npmcli/fs@4.0.0", "", { "dependencies": { "semver": "7.7.4" } }, "sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q=="], + "@npmcli/fs": ["@npmcli/fs@4.0.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q=="], "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], "@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="], - "@szmarczak/http-timer": ["@szmarczak/http-timer@4.0.6", "", { "dependencies": { "defer-to-connect": "2.0.1" } }, "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w=="], + "@szmarczak/http-timer": ["@szmarczak/http-timer@4.0.6", "", { "dependencies": { "defer-to-connect": "^2.0.0" } }, "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w=="], - "@types/cacheable-request": ["@types/cacheable-request@6.0.3", "", { "dependencies": { "@types/http-cache-semantics": "4.2.0", "@types/keyv": "3.1.4", "@types/node": "25.2.3", "@types/responselike": "1.0.3" } }, "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw=="], + "@types/cacheable-request": ["@types/cacheable-request@6.0.3", "", { "dependencies": { "@types/http-cache-semantics": "*", "@types/keyv": "^3.1.4", "@types/node": "*", "@types/responselike": "^1.0.0" } }, "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw=="], - "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "2.1.0" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], + "@types/debug": ["@types/debug@4.1.13", "", { "dependencies": { "@types/ms": "*" } }, "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw=="], - "@types/fs-extra": ["@types/fs-extra@9.0.13", "", { "dependencies": { "@types/node": "25.2.3" } }, "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA=="], + "@types/fs-extra": ["@types/fs-extra@9.0.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA=="], "@types/http-cache-semantics": ["@types/http-cache-semantics@4.2.0", "", {}, "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q=="], - "@types/keyv": ["@types/keyv@3.1.4", "", { "dependencies": { "@types/node": "25.2.3" } }, "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg=="], + "@types/keyv": ["@types/keyv@3.1.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg=="], "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], - "@types/node": ["@types/node@25.3.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A=="], + "@types/node": ["@types/node@25.5.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw=="], - "@types/plist": ["@types/plist@3.0.5", "", { "dependencies": { "@types/node": "25.2.3", "xmlbuilder": "15.1.1" } }, "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA=="], + "@types/plist": ["@types/plist@3.0.5", "", { "dependencies": { "@types/node": "*", "xmlbuilder": ">=11.0.1" } }, "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA=="], - "@types/responselike": ["@types/responselike@1.0.3", "", { "dependencies": { "@types/node": "25.2.3" } }, "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw=="], + "@types/responselike": ["@types/responselike@1.0.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw=="], "@types/verror": ["@types/verror@1.10.11", "", {}, "sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg=="], - "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "25.2.3" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], + "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], - "@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "25.2.3" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="], + "@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="], "@xmldom/xmldom": ["@xmldom/xmldom@0.8.11", "", {}, "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw=="], @@ -174,17 +180,17 @@ "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], - "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "3.1.3", "fast-json-stable-stringify": "2.1.0", "json-schema-traverse": "0.4.1", "uri-js": "4.4.1" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], + "ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], - "ajv-keywords": ["ajv-keywords@3.5.2", "", { "peerDependencies": { "ajv": "6.12.6" } }, "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="], + "ajv-keywords": ["ajv-keywords@3.5.2", "", { "peerDependencies": { "ajv": "^6.9.1" } }, "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="], "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "app-builder-bin": ["app-builder-bin@5.0.0-alpha.12", "", {}, "sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w=="], - "app-builder-lib": ["app-builder-lib@26.8.1", "", { "dependencies": { "@develar/schema-utils": "~2.6.5", "@electron/asar": "3.4.1", "@electron/fuses": "^1.8.0", "@electron/get": "^3.0.0", "@electron/notarize": "2.5.0", "@electron/osx-sign": "1.3.3", "@electron/rebuild": "^4.0.3", "@electron/universal": "2.0.3", "@malept/flatpak-bundler": "^0.4.0", "@types/fs-extra": "9.0.13", "async-exit-hook": "^2.0.1", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chromium-pickle-js": "^0.2.0", "ci-info": "4.3.1", "debug": "^4.3.4", "dotenv": "^16.4.5", "dotenv-expand": "^11.0.6", "ejs": "^3.1.8", "electron-publish": "26.8.1", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", "isbinaryfile": "^5.0.0", "jiti": "^2.4.2", "js-yaml": "^4.1.0", "json5": "^2.2.3", "lazy-val": "^1.0.5", "minimatch": "^10.0.3", "plist": "3.1.0", "proper-lockfile": "^4.1.2", "resedit": "^1.7.0", "semver": "~7.7.3", "tar": "^7.5.7", "temp-file": "^3.4.0", "tiny-async-pool": "1.3.0", "which": "^5.0.0" }, "peerDependencies": { "dmg-builder": "26.8.1", "electron-builder-squirrel-windows": "26.8.1" } }, "sha512-p0Im/Dx5C4tmz8QEE1Yn4MkuPC8PrnlRneMhWJj7BBXQfNTJUshM/bp3lusdEsDbvvfJZpXWnYesgSLvwtM2Zw=="], + "app-builder-lib": ["app-builder-lib@26.8.2", "", { "dependencies": { "@develar/schema-utils": "~2.6.5", "@electron/asar": "3.4.1", "@electron/fuses": "^1.8.0", "@electron/get": "^3.0.0", "@electron/notarize": "2.5.0", "@electron/osx-sign": "1.3.3", "@electron/rebuild": "^4.0.3", "@electron/universal": "2.0.3", "@malept/flatpak-bundler": "^0.4.0", "@types/fs-extra": "9.0.13", "async-exit-hook": "^2.0.1", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chromium-pickle-js": "^0.2.0", "ci-info": "4.3.1", "debug": "^4.3.4", "dotenv": "^16.4.5", "dotenv-expand": "^11.0.6", "ejs": "^3.1.8", "electron-publish": "26.8.1", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", "isbinaryfile": "^5.0.0", "jiti": "^2.4.2", "js-yaml": "^4.1.0", "json5": "^2.2.3", "lazy-val": "^1.0.5", "minimatch": "^10.0.3", "plist": "3.1.0", "proper-lockfile": "^4.1.2", "resedit": "^1.7.0", "semver": "~7.7.3", "tar": "^7.5.7", "temp-file": "^3.4.0", "tiny-async-pool": "1.3.0", "which": "^5.0.0" }, "peerDependencies": { "dmg-builder": "26.8.2", "electron-builder-squirrel-windows": "26.8.2" } }, "sha512-z3ptLzJwNl35fyR0wxv4qWOfZuU36VysYHnbs8PDtf8S0QzIl2OWimdDFVmCxYMkIV1k/RT9CeTgcP7oUznFOw=="], "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], @@ -200,21 +206,21 @@ "at-least-node": ["at-least-node@1.0.0", "", {}, "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="], - "axios": ["axios@1.13.5", "", { "dependencies": { "follow-redirects": "1.15.11", "form-data": "4.0.5", "proxy-from-env": "1.1.0" } }, "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q=="], + "axios": ["axios@1.13.6", "", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ=="], - "balanced-match": ["balanced-match@4.0.2", "", { "dependencies": { "jackspeak": "4.2.3" } }, "sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg=="], + "balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], "bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="], - "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "5.7.1", "inherits": "2.0.4", "readable-stream": "3.6.2" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], + "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], "boolean": ["boolean@3.2.0", "", {}, "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw=="], - "brace-expansion": ["brace-expansion@5.0.2", "", { "dependencies": { "balanced-match": "4.0.2" } }, "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw=="], + "brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="], - "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "1.5.1", "ieee754": "1.2.1" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], "buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="], @@ -222,17 +228,17 @@ "builder-util": ["builder-util@26.8.1", "", { "dependencies": { "7zip-bin": "~5.2.0", "@types/debug": "^4.1.6", "app-builder-bin": "5.0.0-alpha.12", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "cross-spawn": "^7.0.6", "debug": "^4.3.4", "fs-extra": "^10.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "js-yaml": "^4.1.0", "sanitize-filename": "^1.6.3", "source-map-support": "^0.5.19", "stat-mode": "^1.0.0", "temp-file": "^3.4.0", "tiny-async-pool": "1.3.0" } }, "sha512-pm1lTYbGyc90DHgCDO7eo8Rl4EqKLciayNbZqGziqnH9jrlKe8ZANGdityLZU+pJh16dfzjAx2xQq9McuIPEtw=="], - "builder-util-runtime": ["builder-util-runtime@9.5.1", "", { "dependencies": { "debug": "4.4.3", "sax": "1.4.4" } }, "sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ=="], + "builder-util-runtime": ["builder-util-runtime@9.5.1", "", { "dependencies": { "debug": "^4.3.4", "sax": "^1.2.4" } }, "sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ=="], - "cacache": ["cacache@19.0.1", "", { "dependencies": { "@npmcli/fs": "4.0.0", "fs-minipass": "3.0.3", "glob": "10.5.0", "lru-cache": "10.4.3", "minipass": "7.1.2", "minipass-collect": "2.0.1", "minipass-flush": "1.0.5", "minipass-pipeline": "1.2.4", "p-map": "7.0.4", "ssri": "12.0.0", "tar": "7.5.9", "unique-filename": "4.0.0" } }, "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ=="], + "cacache": ["cacache@19.0.1", "", { "dependencies": { "@npmcli/fs": "^4.0.0", "fs-minipass": "^3.0.0", "glob": "^10.2.2", "lru-cache": "^10.0.1", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^7.0.2", "ssri": "^12.0.0", "tar": "^7.4.3", "unique-filename": "^4.0.0" } }, "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ=="], "cacheable-lookup": ["cacheable-lookup@5.0.4", "", {}, "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA=="], - "cacheable-request": ["cacheable-request@7.0.4", "", { "dependencies": { "clone-response": "1.0.3", "get-stream": "5.2.0", "http-cache-semantics": "4.2.0", "keyv": "4.5.4", "lowercase-keys": "2.0.0", "normalize-url": "6.1.0", "responselike": "2.0.1" } }, "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg=="], + "cacheable-request": ["cacheable-request@7.0.4", "", { "dependencies": { "clone-response": "^1.0.2", "get-stream": "^5.1.0", "http-cache-semantics": "^4.0.0", "keyv": "^4.0.0", "lowercase-keys": "^2.0.0", "normalize-url": "^6.0.1", "responselike": "^2.0.0" } }, "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg=="], - "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "1.3.0", "function-bind": "1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], - "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "4.3.0", "supports-color": "7.2.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], @@ -240,49 +246,47 @@ "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], - "cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], + "cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="], - "cli-truncate": ["cli-truncate@2.1.0", "", { "dependencies": { "slice-ansi": "3.0.0", "string-width": "4.2.3" } }, "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg=="], + "cli-truncate": ["cli-truncate@2.1.0", "", { "dependencies": { "slice-ansi": "^3.0.0", "string-width": "^4.2.0" } }, "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg=="], - "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "4.2.3", "strip-ansi": "6.0.1", "wrap-ansi": "7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], "clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="], - "clone-response": ["clone-response@1.0.3", "", { "dependencies": { "mimic-response": "1.0.1" } }, "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA=="], + "clone-response": ["clone-response@1.0.3", "", { "dependencies": { "mimic-response": "^1.0.0" } }, "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA=="], - "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], + "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], "compare-version": ["compare-version@0.1.2", "", {}, "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A=="], - "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], - "core-util-is": ["core-util-is@1.0.2", "", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="], - "crc": ["crc@3.8.0", "", { "dependencies": { "buffer": "5.7.1" } }, "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ=="], + "crc": ["crc@3.8.0", "", { "dependencies": { "buffer": "^5.1.0" } }, "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ=="], "cross-dirname": ["cross-dirname@0.1.0", "", {}, "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q=="], - "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "3.1.1", "shebang-command": "2.0.0", "which": "2.0.2" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], - "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="], + "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="], - "defaults": ["defaults@1.0.4", "", { "dependencies": { "clone": "1.0.4" } }, "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A=="], + "defaults": ["defaults@1.0.4", "", { "dependencies": { "clone": "^1.0.2" } }, "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A=="], "defer-to-connect": ["defer-to-connect@2.0.1", "", {}, "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg=="], - "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "1.0.1", "es-errors": "1.3.0", "gopd": "1.2.0" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], + "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], - "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "1.1.4", "has-property-descriptors": "1.0.2", "object-keys": "1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], + "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], @@ -290,39 +294,39 @@ "detect-node": ["detect-node@2.1.0", "", {}, "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="], - "dir-compare": ["dir-compare@4.2.0", "", { "dependencies": { "minimatch": "3.1.2", "p-limit": "3.1.0" } }, "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ=="], + "dir-compare": ["dir-compare@4.2.0", "", { "dependencies": { "minimatch": "^3.0.5", "p-limit": "^3.1.0 " } }, "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ=="], "discord-rpc": ["discord-rpc@4.0.1", "", { "dependencies": { "node-fetch": "^2.6.1", "ws": "^7.3.1" }, "optionalDependencies": { "register-scheme": "github:devsnek/node-register-scheme" } }, "sha512-HOvHpbq5STRZJjQIBzwoKnQ0jHplbEWFWlPDwXXKm/bILh4nzjcg7mNqll0UY7RsjFoaXA7e/oYb/4lvpda2zA=="], - "dmg-builder": ["dmg-builder@26.8.1", "", { "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" }, "optionalDependencies": { "dmg-license": "^1.0.11" } }, "sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg=="], + "dmg-builder": ["dmg-builder@26.8.2", "", { "dependencies": { "app-builder-lib": "26.8.2", "builder-util": "26.8.1", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" }, "optionalDependencies": { "dmg-license": "^1.0.11" } }, "sha512-DaWI+p4DOqiFVZFMovdGYammBOyJAiHHFWUTQ0Z7gNc0twfdIN0LvyJ+vFsgZEDR1fjgbpCj690IVtbYIsZObQ=="], - "dmg-license": ["dmg-license@1.0.11", "", { "dependencies": { "@types/plist": "3.0.5", "@types/verror": "1.10.11", "ajv": "6.12.6", "crc": "3.8.0", "iconv-corefoundation": "1.1.7", "plist": "3.1.0", "smart-buffer": "4.2.0", "verror": "1.10.1" }, "os": "darwin", "bin": { "dmg-license": "bin/dmg-license.js" } }, "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q=="], + "dmg-license": ["dmg-license@1.0.11", "", { "dependencies": { "@types/plist": "^3.0.1", "@types/verror": "^1.10.3", "ajv": "^6.10.0", "crc": "^3.8.0", "iconv-corefoundation": "^1.1.7", "plist": "^3.0.4", "smart-buffer": "^4.0.2", "verror": "^1.10.0" }, "os": "darwin", "bin": { "dmg-license": "bin/dmg-license.js" } }, "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q=="], "dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], - "dotenv-expand": ["dotenv-expand@11.0.7", "", { "dependencies": { "dotenv": "16.6.1" } }, "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA=="], + "dotenv-expand": ["dotenv-expand@11.0.7", "", { "dependencies": { "dotenv": "^16.4.5" } }, "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA=="], - "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "1.0.2", "es-errors": "1.3.0", "gopd": "1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], - "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "10.9.4" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="], + "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="], - "electron": ["electron@37.10.3", "", { "dependencies": { "@electron/get": "2.0.3", "@types/node": "22.19.11", "extract-zip": "2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-3IjCGSjQmH50IbW2PFveaTzK+KwcFX9PEhE7KXb9v5IT8cLAiryAN7qezm/XzODhDRlLu0xKG1j8xWBtZ/bx/g=="], + "electron": ["electron@37.10.3", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^22.7.7", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-3IjCGSjQmH50IbW2PFveaTzK+KwcFX9PEhE7KXb9v5IT8cLAiryAN7qezm/XzODhDRlLu0xKG1j8xWBtZ/bx/g=="], - "electron-builder": ["electron-builder@26.8.1", "", { "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "ci-info": "^4.2.0", "dmg-builder": "26.8.1", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" }, "bin": { "electron-builder": "cli.js", "install-app-deps": "install-app-deps.js" } }, "sha512-uWhx1r74NGpCagG0ULs/P9Nqv2nsoo+7eo4fLUOB8L8MdWltq9odW/uuLXMFCDGnPafknYLZgjNX0ZIFRzOQAw=="], + "electron-builder": ["electron-builder@26.8.2", "", { "dependencies": { "app-builder-lib": "26.8.2", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "ci-info": "^4.2.0", "dmg-builder": "26.8.2", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" }, "bin": { "electron-builder": "cli.js", "install-app-deps": "install-app-deps.js" } }, "sha512-ieiiXPdgH3qrG6lcvy2mtnI5iEmAopmLuVRMSJ5j40weU0tgpNx0OAk9J5X5nnO0j9+KIkxHzwFZVUDk1U3aGw=="], - "electron-builder-squirrel-windows": ["electron-builder-squirrel-windows@26.7.0", "", { "dependencies": { "app-builder-lib": "26.7.0", "builder-util": "26.4.1", "electron-winstaller": "5.4.0" } }, "sha512-3EqkQK+q0kGshdPSKEPb2p5F75TENMKu6Fe5aTdeaPfdzFK4Yjp5L0d6S7K8iyvqIsGQ/ei4bnpyX9wt+kVCKQ=="], + "electron-builder-squirrel-windows": ["electron-builder-squirrel-windows@26.8.2", "", { "dependencies": { "app-builder-lib": "26.8.2", "builder-util": "26.8.1", "electron-winstaller": "5.4.0" } }, "sha512-kXhajX6DzdIQcTlctVTKoG1oO39JhWcTG0lH7ZEJ4FzPaKJy7KFNfNJUd5BoEmLjv5GlrRZpEOYnniD+LcwNJA=="], "electron-publish": ["electron-publish@26.8.1", "", { "dependencies": { "@types/fs-extra": "^9.0.11", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "form-data": "^4.0.5", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "mime": "^2.5.2" } }, "sha512-q+jrSTIh/Cv4eGZa7oVR+grEJo/FoLMYBAnSL5GCtqwUpr1T+VgKB/dn1pnzxIxqD8S/jP1yilT9VrwCqINR4w=="], - "electron-winstaller": ["electron-winstaller@5.4.0", "", { "dependencies": { "@electron/asar": "3.4.1", "debug": "4.4.3", "fs-extra": "7.0.1", "lodash": "4.17.23", "temp": "0.9.4" }, "optionalDependencies": { "@electron/windows-sign": "1.2.2" } }, "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg=="], + "electron-winstaller": ["electron-winstaller@5.4.0", "", { "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", "fs-extra": "^7.0.1", "lodash": "^4.17.21", "temp": "^0.9.0" }, "optionalDependencies": { "@electron/windows-sign": "^1.1.2" } }, "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg=="], "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - "encoding": ["encoding@0.1.13", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A=="], + "encoding": ["encoding@0.1.13", "", { "dependencies": { "iconv-lite": "^0.6.2" } }, "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A=="], - "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], + "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], @@ -332,9 +336,9 @@ "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], - "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], - "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "1.3.0", "get-intrinsic": "1.3.0", "has-tostringtag": "1.0.2", "hasown": "2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], + "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], "es6-error": ["es6-error@4.1.1", "", {}, "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg=="], @@ -346,7 +350,7 @@ "exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="], - "extract-zip": ["extract-zip@2.0.1", "", { "dependencies": { "debug": "4.4.3", "get-stream": "5.2.0", "yauzl": "2.10.0" }, "optionalDependencies": { "@types/yauzl": "2.10.3" }, "bin": { "extract-zip": "cli.js" } }, "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg=="], + "extract-zip": ["extract-zip@2.0.1", "", { "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", "yauzl": "^2.10.0" }, "optionalDependencies": { "@types/yauzl": "^2.9.1" }, "bin": { "extract-zip": "cli.js" } }, "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg=="], "extsprintf": ["extsprintf@1.4.1", "", {}, "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA=="], @@ -354,23 +358,23 @@ "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], - "fd-slicer": ["fd-slicer@1.1.0", "", { "dependencies": { "pend": "1.2.0" } }, "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g=="], + "fd-slicer": ["fd-slicer@1.1.0", "", { "dependencies": { "pend": "~1.2.0" } }, "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g=="], - "fdir": ["fdir@6.5.0", "", { "optionalDependencies": { "picomatch": "4.0.3" } }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], "file-uri-to-path": ["file-uri-to-path@1.0.0", "", {}, "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="], - "filelist": ["filelist@1.0.4", "", { "dependencies": { "minimatch": "5.1.6" } }, "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q=="], + "filelist": ["filelist@1.0.6", "", { "dependencies": { "minimatch": "^5.0.1" } }, "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA=="], "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], - "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "7.0.6", "signal-exit": "4.1.0" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], - "form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "0.4.0", "combined-stream": "1.0.8", "es-set-tostringtag": "2.1.0", "hasown": "2.0.2", "mime-types": "2.1.35" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], + "form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], - "fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "4.2.11", "jsonfile": "6.2.0", "universalify": "2.0.1" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], + "fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], - "fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "7.1.2" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="], + "fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="], "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], @@ -378,55 +382,55 @@ "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], - "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "1.0.2", "es-define-property": "1.0.1", "es-errors": "1.3.0", "es-object-atoms": "1.1.1", "function-bind": "1.1.2", "get-proto": "1.0.1", "gopd": "1.2.0", "has-symbols": "1.1.0", "hasown": "2.0.2", "math-intrinsics": "1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], - "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "1.0.1", "es-object-atoms": "1.1.1" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], - "get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "3.0.3" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="], + "get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="], - "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "1.0.0", "inflight": "1.0.6", "inherits": "2.0.4", "minimatch": "3.1.2", "once": "1.4.0", "path-is-absolute": "1.0.1" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], - "global-agent": ["global-agent@3.0.0", "", { "dependencies": { "boolean": "3.2.0", "es6-error": "4.1.1", "matcher": "3.0.0", "roarr": "2.15.4", "semver": "7.7.4", "serialize-error": "7.0.1" } }, "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q=="], + "global-agent": ["global-agent@3.0.0", "", { "dependencies": { "boolean": "^3.0.1", "es6-error": "^4.1.1", "matcher": "^3.0.0", "roarr": "^2.15.3", "semver": "^7.3.2", "serialize-error": "^7.0.1" } }, "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q=="], - "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "1.2.1", "gopd": "1.2.0" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], + "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], - "got": ["got@11.8.6", "", { "dependencies": { "@sindresorhus/is": "4.6.0", "@szmarczak/http-timer": "4.0.6", "@types/cacheable-request": "6.0.3", "@types/responselike": "1.0.3", "cacheable-lookup": "5.0.4", "cacheable-request": "7.0.4", "decompress-response": "6.0.0", "http2-wrapper": "1.0.3", "lowercase-keys": "2.0.0", "p-cancelable": "2.1.1", "responselike": "2.0.1" } }, "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g=="], + "got": ["got@11.8.6", "", { "dependencies": { "@sindresorhus/is": "^4.0.0", "@szmarczak/http-timer": "^4.0.5", "@types/cacheable-request": "^6.0.1", "@types/responselike": "^1.0.0", "cacheable-lookup": "^5.0.3", "cacheable-request": "^7.0.2", "decompress-response": "^6.0.0", "http2-wrapper": "^1.0.0-beta.5.2", "lowercase-keys": "^2.0.0", "p-cancelable": "^2.0.0", "responselike": "^2.0.0" } }, "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g=="], "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], - "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "1.0.1" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], + "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], - "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "1.1.0" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], - "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], - "hono": ["hono@4.12.7", "", {}, "sha512-jq9l1DM0zVIvsm3lv9Nw9nlJnMNPOcAtsbsgiUhWcFzPE99Gvo6yRTlszSLLYacMeQ6quHD6hMfId8crVHvexw=="], + "hono": ["hono@4.12.8", "", {}, "sha512-VJCEvtrezO1IAR+kqEYnxUOoStaQPGrCmX3j4wDTNOcD1uRPFpGlwQUIW8niPuvHXaTUxeOUl5MMDGrl+tmO9A=="], - "hosted-git-info": ["hosted-git-info@4.1.0", "", { "dependencies": { "lru-cache": "6.0.0" } }, "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA=="], + "hosted-git-info": ["hosted-git-info@4.1.0", "", { "dependencies": { "lru-cache": "^6.0.0" } }, "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA=="], "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="], - "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "7.1.4", "debug": "4.4.3" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], + "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], - "http2-wrapper": ["http2-wrapper@1.0.3", "", { "dependencies": { "quick-lru": "5.1.1", "resolve-alpn": "1.2.1" } }, "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg=="], + "http2-wrapper": ["http2-wrapper@1.0.3", "", { "dependencies": { "quick-lru": "^5.1.1", "resolve-alpn": "^1.0.0" } }, "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg=="], - "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "7.1.4", "debug": "4.4.3" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], + "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], - "iconv-corefoundation": ["iconv-corefoundation@1.1.7", "", { "dependencies": { "cli-truncate": "2.1.0", "node-addon-api": "1.7.2" }, "os": "darwin" }, "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ=="], + "iconv-corefoundation": ["iconv-corefoundation@1.1.7", "", { "dependencies": { "cli-truncate": "^2.1.0", "node-addon-api": "^1.6.3" }, "os": "darwin" }, "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ=="], - "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": "2.1.2" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], - "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "1.4.0", "wrappy": "1.0.2" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], + "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], @@ -442,13 +446,13 @@ "isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="], - "jackspeak": ["jackspeak@4.2.3", "", { "dependencies": { "@isaacs/cliui": "9.0.0" } }, "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg=="], + "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], - "jake": ["jake@10.9.4", "", { "dependencies": { "async": "3.2.6", "filelist": "1.0.4", "picocolors": "1.1.1" }, "bin": { "jake": "bin/cli.js" } }, "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA=="], + "jake": ["jake@10.9.4", "", { "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" } }, "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA=="], "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], - "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], @@ -460,25 +464,25 @@ "jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="], - "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "2.0.1" }, "optionalDependencies": { "graceful-fs": "4.2.11" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], "lazy-val": ["lazy-val@1.0.5", "", {}, "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q=="], - "libsql": ["libsql@0.5.22", "", { "dependencies": { "@neon-rs/load": "^0.0.4", "detect-libc": "2.0.2" }, "optionalDependencies": { "@libsql/darwin-arm64": "0.5.22", "@libsql/darwin-x64": "0.5.22", "@libsql/linux-arm-gnueabihf": "0.5.22", "@libsql/linux-arm-musleabihf": "0.5.22", "@libsql/linux-arm64-gnu": "0.5.22", "@libsql/linux-arm64-musl": "0.5.22", "@libsql/linux-x64-gnu": "0.5.22", "@libsql/linux-x64-musl": "0.5.22", "@libsql/win32-x64-msvc": "0.5.22" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "arm", "x64", "arm64", ] }, "sha512-NscWthMQt7fpU8lqd7LXMvT9pi+KhhmTHAJWUB/Lj6MWa0MKFv0F2V4C6WKKpjCVZl0VwcDz4nOI3CyaT1DDiA=="], + "libsql": ["libsql@0.5.28", "", { "dependencies": { "@neon-rs/load": "^0.0.4", "detect-libc": "2.0.2" }, "optionalDependencies": { "@libsql/darwin-arm64": "0.5.28", "@libsql/darwin-x64": "0.5.28", "@libsql/linux-arm-gnueabihf": "0.5.28", "@libsql/linux-arm-musleabihf": "0.5.28", "@libsql/linux-arm64-gnu": "0.5.28", "@libsql/linux-arm64-musl": "0.5.28", "@libsql/linux-x64-gnu": "0.5.28", "@libsql/linux-x64-musl": "0.5.28", "@libsql/win32-x64-msvc": "0.5.28" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "arm", "x64", "arm64", ] }, "sha512-wKqx9FgtPcKHdPfR/Kfm0gejsnbuf8zV+ESPmltFvsq5uXwdeN9fsWn611DmqrdXj1e94NkARcMA2f1syiAqOg=="], "lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], - "log-symbols": ["log-symbols@4.1.0", "", { "dependencies": { "chalk": "4.1.2", "is-unicode-supported": "0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="], + "log-symbols": ["log-symbols@4.1.0", "", { "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="], "lowercase-keys": ["lowercase-keys@2.0.0", "", {}, "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="], - "lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], + "lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], - "make-fetch-happen": ["make-fetch-happen@14.0.3", "", { "dependencies": { "@npmcli/agent": "3.0.0", "cacache": "19.0.1", "http-cache-semantics": "4.2.0", "minipass": "7.1.2", "minipass-fetch": "4.0.1", "minipass-flush": "1.0.5", "minipass-pipeline": "1.2.4", "negotiator": "1.0.0", "proc-log": "5.0.0", "promise-retry": "2.0.1", "ssri": "12.0.0" } }, "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ=="], + "make-fetch-happen": ["make-fetch-happen@14.0.3", "", { "dependencies": { "@npmcli/agent": "^3.0.0", "cacache": "^19.0.1", "http-cache-semantics": "^4.1.1", "minipass": "^7.0.2", "minipass-fetch": "^4.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^1.0.0", "proc-log": "^5.0.0", "promise-retry": "^2.0.1", "ssri": "^12.0.0" } }, "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ=="], - "matcher": ["matcher@3.0.0", "", { "dependencies": { "escape-string-regexp": "4.0.0" } }, "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng=="], + "matcher": ["matcher@3.0.0", "", { "dependencies": { "escape-string-regexp": "^4.0.0" } }, "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng=="], "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], @@ -492,55 +496,55 @@ "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], - "minimatch": ["minimatch@10.2.0", "", { "dependencies": { "brace-expansion": "5.0.2" } }, "sha512-ugkC31VaVg9cF0DFVoADH12k6061zNZkZON+aX8AWsR9GhPcErkcMBceb6znR8wLERM2AkkOxy2nWRLpT9Jq5w=="], + "minimatch": ["minimatch@10.2.3", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], - "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], - "minipass-collect": ["minipass-collect@2.0.1", "", { "dependencies": { "minipass": "7.1.2" } }, "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw=="], + "minipass-collect": ["minipass-collect@2.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw=="], - "minipass-fetch": ["minipass-fetch@4.0.1", "", { "dependencies": { "minipass": "7.1.2", "minipass-sized": "1.0.3", "minizlib": "3.1.0" }, "optionalDependencies": { "encoding": "0.1.13" } }, "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ=="], + "minipass-fetch": ["minipass-fetch@4.0.1", "", { "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", "minizlib": "^3.0.1" }, "optionalDependencies": { "encoding": "^0.1.13" } }, "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ=="], - "minipass-flush": ["minipass-flush@1.0.5", "", { "dependencies": { "minipass": "3.3.6" } }, "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw=="], + "minipass-flush": ["minipass-flush@1.0.5", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw=="], - "minipass-pipeline": ["minipass-pipeline@1.2.4", "", { "dependencies": { "minipass": "3.3.6" } }, "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A=="], + "minipass-pipeline": ["minipass-pipeline@1.2.4", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A=="], - "minipass-sized": ["minipass-sized@1.0.3", "", { "dependencies": { "minipass": "3.3.6" } }, "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g=="], + "minipass-sized": ["minipass-sized@1.0.3", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g=="], - "minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="], + "minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="], - "mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "1.2.8" }, "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="], + "mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="], "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], - "node-abi": ["node-abi@4.26.0", "", { "dependencies": { "semver": "7.7.4" } }, "sha512-8QwIZqikRvDIkXS2S93LjzhsSPJuIbfaMETWH+Bx8oOT9Sa9UsUtBFQlc3gBNd1+QINjaTloitXr1W3dQLi9Iw=="], + "node-abi": ["node-abi@4.28.0", "", { "dependencies": { "semver": "^7.6.3" } }, "sha512-Qfp5XZL1cJDOabOT8H5gnqMTmM4NjvYzHp4I/Kt/Sl76OVkOBBHRFlPspGV0hYvMoqQsypFjT/Yp7Km0beXW9g=="], "node-addon-api": ["node-addon-api@1.7.2", "", {}, "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg=="], - "node-api-version": ["node-api-version@0.2.1", "", { "dependencies": { "semver": "7.7.4" } }, "sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q=="], + "node-api-version": ["node-api-version@0.2.1", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q=="], "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], - "node-gyp": ["node-gyp@11.5.0", "", { "dependencies": { "env-paths": "2.2.1", "exponential-backoff": "3.1.3", "graceful-fs": "4.2.11", "make-fetch-happen": "14.0.3", "nopt": "8.1.0", "proc-log": "5.0.0", "semver": "7.7.4", "tar": "7.5.9", "tinyglobby": "0.2.15", "which": "5.0.0" }, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ=="], + "node-gyp": ["node-gyp@11.5.0", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "graceful-fs": "^4.2.6", "make-fetch-happen": "^14.0.3", "nopt": "^8.0.0", "proc-log": "^5.0.0", "semver": "^7.3.5", "tar": "^7.4.3", "tinyglobby": "^0.2.12", "which": "^5.0.0" }, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ=="], - "nopt": ["nopt@8.1.0", "", { "dependencies": { "abbrev": "3.0.1" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A=="], + "nopt": ["nopt@8.1.0", "", { "dependencies": { "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A=="], "normalize-url": ["normalize-url@6.1.0", "", {}, "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A=="], "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], - "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1.0.2" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], - "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], + "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], - "ora": ["ora@5.4.1", "", { "dependencies": { "bl": "4.1.0", "chalk": "4.1.2", "cli-cursor": "3.1.0", "cli-spinners": "2.9.2", "is-interactive": "1.0.0", "is-unicode-supported": "0.1.0", "log-symbols": "4.1.0", "strip-ansi": "6.0.1", "wcwidth": "1.0.1" } }, "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ=="], + "ora": ["ora@5.4.1", "", { "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", "cli-cursor": "^3.1.0", "cli-spinners": "^2.5.0", "is-interactive": "^1.0.0", "is-unicode-supported": "^0.1.0", "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" } }, "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ=="], "p-cancelable": ["p-cancelable@2.1.1", "", {}, "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg=="], - "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], "p-map": ["p-map@7.0.4", "", {}, "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ=="], @@ -550,7 +554,7 @@ "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], - "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "10.4.3", "minipass": "7.1.2" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], "pe-library": ["pe-library@0.4.1", "", {}, "sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw=="], @@ -560,9 +564,9 @@ "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "plist": ["plist@3.1.0", "", { "dependencies": { "@xmldom/xmldom": "0.8.11", "base64-js": "1.5.1", "xmlbuilder": "15.1.1" } }, "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ=="], + "plist": ["plist@3.1.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ=="], - "postject": ["postject@1.0.0-alpha.6", "", { "dependencies": { "commander": "9.5.0" }, "bin": { "postject": "dist/cli.js" } }, "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A=="], + "postject": ["postject@1.0.0-alpha.6", "", { "dependencies": { "commander": "^9.4.0" }, "bin": { "postject": "dist/cli.js" } }, "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A=="], "prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="], @@ -570,111 +574,111 @@ "progress": ["progress@2.0.3", "", {}, "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="], - "promise-retry": ["promise-retry@2.0.1", "", { "dependencies": { "err-code": "2.0.3", "retry": "0.12.0" } }, "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g=="], + "promise-retry": ["promise-retry@2.0.1", "", { "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" } }, "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g=="], - "proper-lockfile": ["proper-lockfile@4.1.2", "", { "dependencies": { "graceful-fs": "4.2.11", "retry": "0.12.0", "signal-exit": "3.0.7" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="], + "proper-lockfile": ["proper-lockfile@4.1.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", "signal-exit": "^3.0.2" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="], "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], - "pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "1.4.5", "once": "1.4.0" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="], + "pump": ["pump@3.0.4", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA=="], "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], "quick-lru": ["quick-lru@5.1.1", "", {}, "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="], - "read-binary-file-arch": ["read-binary-file-arch@1.0.6", "", { "dependencies": { "debug": "4.4.3" }, "bin": { "read-binary-file-arch": "cli.js" } }, "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg=="], + "read-binary-file-arch": ["read-binary-file-arch@1.0.6", "", { "dependencies": { "debug": "^4.3.4" }, "bin": { "read-binary-file-arch": "cli.js" } }, "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg=="], - "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "2.0.4", "string_decoder": "1.3.0", "util-deprecate": "1.0.2" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], - "register-scheme": ["register-scheme@github:devsnek/node-register-scheme#e7cc9a6", { "dependencies": { "bindings": "^1.3.0", "node-addon-api": "^1.3.0" } }, "devsnek-node-register-scheme-e7cc9a6"], + "register-scheme": ["register-scheme@github:devsnek/node-register-scheme#e7cc9a6", { "dependencies": { "bindings": "^1.3.0", "node-addon-api": "^1.3.0" } }, "devsnek-node-register-scheme-e7cc9a6", "sha512-VwUWN3aKIg/yn7T8axW20Y1+4wGALIQectBmkmwSJfLrCycpVepGP/+KHjXSL/Ga8N1SmewL49kESgIhW7HbWg=="], "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], - "resedit": ["resedit@1.7.2", "", { "dependencies": { "pe-library": "0.4.1" } }, "sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA=="], + "resedit": ["resedit@1.7.2", "", { "dependencies": { "pe-library": "^0.4.1" } }, "sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA=="], "resolve-alpn": ["resolve-alpn@1.2.1", "", {}, "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="], - "responselike": ["responselike@2.0.1", "", { "dependencies": { "lowercase-keys": "2.0.0" } }, "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw=="], + "responselike": ["responselike@2.0.1", "", { "dependencies": { "lowercase-keys": "^2.0.0" } }, "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw=="], - "restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "5.1.2", "signal-exit": "3.0.7" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], + "restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], "retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="], - "rimraf": ["rimraf@2.6.3", "", { "dependencies": { "glob": "7.2.3" }, "bin": { "rimraf": "./bin.js" } }, "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA=="], + "rimraf": ["rimraf@2.6.3", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "./bin.js" } }, "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA=="], - "roarr": ["roarr@2.15.4", "", { "dependencies": { "boolean": "3.2.0", "detect-node": "2.1.0", "globalthis": "1.0.4", "json-stringify-safe": "5.0.1", "semver-compare": "1.0.0", "sprintf-js": "1.1.3" } }, "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A=="], + "roarr": ["roarr@2.15.4", "", { "dependencies": { "boolean": "^3.0.1", "detect-node": "^2.0.4", "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", "semver-compare": "^1.0.0", "sprintf-js": "^1.1.2" } }, "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A=="], "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], - "sanitize-filename": ["sanitize-filename@1.6.3", "", { "dependencies": { "truncate-utf8-bytes": "1.0.2" } }, "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg=="], + "sanitize-filename": ["sanitize-filename@1.6.4", "", { "dependencies": { "truncate-utf8-bytes": "^1.0.0" } }, "sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg=="], - "sax": ["sax@1.4.4", "", {}, "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw=="], + "sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "semver-compare": ["semver-compare@1.0.0", "", {}, "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow=="], - "serialize-error": ["serialize-error@7.0.1", "", { "dependencies": { "type-fest": "0.13.1" } }, "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw=="], + "serialize-error": ["serialize-error@7.0.1", "", { "dependencies": { "type-fest": "^0.13.1" } }, "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw=="], - "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], - "simple-update-notifier": ["simple-update-notifier@2.0.0", "", { "dependencies": { "semver": "7.7.4" } }, "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w=="], + "simple-update-notifier": ["simple-update-notifier@2.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w=="], - "slice-ansi": ["slice-ansi@3.0.0", "", { "dependencies": { "ansi-styles": "4.3.0", "astral-regex": "2.0.0", "is-fullwidth-code-point": "3.0.0" } }, "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ=="], + "slice-ansi": ["slice-ansi@3.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" } }, "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ=="], "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], - "socks": ["socks@2.8.7", "", { "dependencies": { "ip-address": "10.1.0", "smart-buffer": "4.2.0" } }, "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A=="], + "socks": ["socks@2.8.7", "", { "dependencies": { "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" } }, "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A=="], - "socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "7.1.4", "debug": "4.4.3", "socks": "2.8.7" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="], + "socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="], "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], - "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "1.1.2", "source-map": "0.6.1" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], + "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], "sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="], - "ssri": ["ssri@12.0.0", "", { "dependencies": { "minipass": "7.1.2" } }, "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ=="], + "ssri": ["ssri@12.0.0", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ=="], "stat-mode": ["stat-mode@1.0.0", "", {}, "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg=="], - "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "8.0.0", "is-fullwidth-code-point": "3.0.0", "strip-ansi": "6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "8.0.0", "is-fullwidth-code-point": "3.0.0", "strip-ansi": "6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], - "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "sumchecker": ["sumchecker@3.0.1", "", { "dependencies": { "debug": "4.4.3" } }, "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg=="], + "sumchecker": ["sumchecker@3.0.1", "", { "dependencies": { "debug": "^4.1.0" } }, "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg=="], - "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - "tar": ["tar@7.5.9", "", { "dependencies": { "@isaacs/fs-minipass": "4.0.1", "chownr": "3.0.0", "minipass": "7.1.2", "minizlib": "3.1.0", "yallist": "5.0.0" } }, "sha512-BTLcK0xsDh2+PUe9F6c2TlRp4zOOBMTkoQHQIWSIzI0R7KG46uEwq4OPk2W7bZcprBMsuaeFsqwYr7pjh6CuHg=="], + "tar": ["tar@7.5.11", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ=="], - "temp": ["temp@0.9.4", "", { "dependencies": { "mkdirp": "0.5.6", "rimraf": "2.6.3" } }, "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA=="], + "temp": ["temp@0.9.4", "", { "dependencies": { "mkdirp": "^0.5.1", "rimraf": "~2.6.2" } }, "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA=="], - "temp-file": ["temp-file@3.4.0", "", { "dependencies": { "async-exit-hook": "2.0.1", "fs-extra": "10.1.0" } }, "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg=="], + "temp-file": ["temp-file@3.4.0", "", { "dependencies": { "async-exit-hook": "^2.0.1", "fs-extra": "^10.0.0" } }, "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg=="], - "tiny-async-pool": ["tiny-async-pool@1.3.0", "", { "dependencies": { "semver": "5.7.2" } }, "sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA=="], + "tiny-async-pool": ["tiny-async-pool@1.3.0", "", { "dependencies": { "semver": "^5.5.0" } }, "sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA=="], - "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "6.5.0", "picomatch": "4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], "tmp": ["tmp@0.2.5", "", {}, "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow=="], - "tmp-promise": ["tmp-promise@3.0.3", "", { "dependencies": { "tmp": "0.2.5" } }, "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ=="], + "tmp-promise": ["tmp-promise@3.0.3", "", { "dependencies": { "tmp": "^0.2.0" } }, "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ=="], "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], - "truncate-utf8-bytes": ["truncate-utf8-bytes@1.0.2", "", { "dependencies": { "utf8-byte-length": "1.0.5" } }, "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ=="], + "truncate-utf8-bytes": ["truncate-utf8-bytes@1.0.2", "", { "dependencies": { "utf8-byte-length": "^1.0.1" } }, "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ=="], "type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="], @@ -682,35 +686,35 @@ "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], - "unique-filename": ["unique-filename@4.0.0", "", { "dependencies": { "unique-slug": "5.0.0" } }, "sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ=="], + "unique-filename": ["unique-filename@4.0.0", "", { "dependencies": { "unique-slug": "^5.0.0" } }, "sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ=="], - "unique-slug": ["unique-slug@5.0.0", "", { "dependencies": { "imurmurhash": "0.1.4" } }, "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg=="], + "unique-slug": ["unique-slug@5.0.0", "", { "dependencies": { "imurmurhash": "^0.1.4" } }, "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg=="], "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], - "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "2.3.1" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], "utf8-byte-length": ["utf8-byte-length@1.0.5", "", {}, "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA=="], "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], - "verror": ["verror@1.10.1", "", { "dependencies": { "assert-plus": "1.0.0", "core-util-is": "1.0.2", "extsprintf": "1.4.1" } }, "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg=="], + "verror": ["verror@1.10.1", "", { "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg=="], - "wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "1.0.4" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="], + "wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="], "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], - "which": ["which@5.0.0", "", { "dependencies": { "isexe": "3.1.5" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], + "which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], - "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "4.3.0", "string-width": "4.2.3", "strip-ansi": "6.0.1" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "4.3.0", "string-width": "4.2.3", "strip-ansi": "6.0.1" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], - "ws": ["ws@8.19.0", "", {}, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], + "ws": ["ws@8.20.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA=="], "xmlbuilder": ["xmlbuilder@15.1.1", "", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="], @@ -718,97 +722,73 @@ "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], - "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "8.0.1", "escalade": "3.2.0", "get-caller-file": "2.0.5", "require-directory": "2.1.1", "string-width": "4.2.3", "y18n": "5.0.8", "yargs-parser": "21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], - "yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "0.2.13", "fd-slicer": "1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="], + "yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="], "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], "@electron/asar/commander": ["commander@5.1.0", "", {}, "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="], - "@electron/asar/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "1.1.12" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + "@electron/fuses/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], - "@electron/fuses/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "1.0.0", "graceful-fs": "4.2.11", "jsonfile": "6.2.0", "universalify": "2.0.1" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], + "@electron/get/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], - "@electron/get/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "4.2.11", "jsonfile": "4.0.0", "universalify": "0.1.2" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], - - "@electron/notarize/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "1.0.0", "graceful-fs": "4.2.11", "jsonfile": "6.2.0", "universalify": "2.0.1" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], + "@electron/notarize/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], "@electron/osx-sign/isbinaryfile": ["isbinaryfile@4.0.10", "", {}, "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw=="], - "@electron/rebuild/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], - "@electron/rebuild/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - "@electron/universal/fs-extra": ["fs-extra@11.3.3", "", { "dependencies": { "graceful-fs": "4.2.11", "jsonfile": "6.2.0", "universalify": "2.0.1" } }, "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg=="], + "@electron/universal/fs-extra": ["fs-extra@11.3.4", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA=="], - "@electron/universal/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "2.0.2" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "@electron/windows-sign/fs-extra": ["fs-extra@11.3.4", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA=="], - "@electron/windows-sign/fs-extra": ["fs-extra@11.3.3", "", { "dependencies": { "graceful-fs": "4.2.11", "jsonfile": "6.2.0", "universalify": "2.0.1" } }, "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg=="], + "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], - "@malept/flatpak-bundler/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "1.0.0", "graceful-fs": "4.2.11", "jsonfile": "6.2.0", "universalify": "2.0.1" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], + "@isaacs/cliui/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], + + "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + + "@malept/flatpak-bundler/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], "@npmcli/agent/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "@npmcli/fs/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - "@types/cacheable-request/@types/node": ["@types/node@25.2.3", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ=="], - - "@types/fs-extra/@types/node": ["@types/node@25.2.3", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ=="], - - "@types/keyv/@types/node": ["@types/node@25.2.3", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ=="], - - "@types/plist/@types/node": ["@types/node@25.2.3", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ=="], - - "@types/responselike/@types/node": ["@types/node@25.2.3", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ=="], - - "@types/ws/@types/node": ["@types/node@25.2.3", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ=="], - - "@types/yauzl/@types/node": ["@types/node@25.2.3", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ=="], - - "app-builder-lib/@electron/get": ["@electron/get@3.1.0", "", { "dependencies": { "debug": "4.4.3", "env-paths": "2.2.1", "fs-extra": "8.1.0", "got": "11.8.6", "progress": "2.0.3", "semver": "6.3.1", "sumchecker": "3.0.1" }, "optionalDependencies": { "global-agent": "3.0.0" } }, "sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ=="], + "app-builder-lib/@electron/get": ["@electron/get@3.1.0", "", { "dependencies": { "debug": "^4.1.1", "env-paths": "^2.2.0", "fs-extra": "^8.1.0", "got": "^11.8.5", "progress": "^2.0.3", "semver": "^6.2.0", "sumchecker": "^3.0.1" }, "optionalDependencies": { "global-agent": "^3.0.0" } }, "sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ=="], "app-builder-lib/ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="], "app-builder-lib/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - "cacache/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "3.3.1", "jackspeak": "3.4.3", "minimatch": "9.0.5", "minipass": "7.1.2", "package-json-from-dist": "1.0.1", "path-scurry": "1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], + "cacache/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], "cacache/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="], - "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], - - "dir-compare/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "1.1.12" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], "discord-rpc/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], - "electron/@types/node": ["@types/node@22.19.11", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w=="], + "electron/@types/node": ["@types/node@22.19.15", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg=="], - "electron-builder-squirrel-windows/app-builder-lib": ["app-builder-lib@26.7.0", "", { "dependencies": { "@develar/schema-utils": "2.6.5", "@electron/asar": "3.4.1", "@electron/fuses": "1.8.0", "@electron/get": "3.1.0", "@electron/notarize": "2.5.0", "@electron/osx-sign": "1.3.3", "@electron/rebuild": "4.0.3", "@electron/universal": "2.0.3", "@malept/flatpak-bundler": "0.4.0", "@types/fs-extra": "9.0.13", "async-exit-hook": "2.0.1", "builder-util": "26.4.1", "builder-util-runtime": "9.5.1", "chromium-pickle-js": "0.2.0", "ci-info": "4.3.1", "debug": "4.4.3", "dotenv": "16.6.1", "dotenv-expand": "11.0.7", "ejs": "3.1.10", "electron-publish": "26.6.0", "fs-extra": "10.1.0", "hosted-git-info": "4.1.0", "isbinaryfile": "5.0.7", "jiti": "2.6.1", "js-yaml": "4.1.1", "json5": "2.2.3", "lazy-val": "1.0.5", "minimatch": "10.2.0", "plist": "3.1.0", "proper-lockfile": "4.1.2", "resedit": "1.7.2", "semver": "7.7.4", "tar": "7.5.9", "temp-file": "3.4.0", "tiny-async-pool": "1.3.0", "which": "5.0.0" }, "peerDependencies": { "dmg-builder": "26.7.0", "electron-builder-squirrel-windows": "26.7.0" } }, "sha512-/UgCD8VrO79Wv8aBNpjMfsS1pIUfIPURoRn0Ik6tMe5avdZF+vQgl/juJgipcMmH3YS0BD573lCdCHyoi84USg=="], - - "electron-builder-squirrel-windows/builder-util": ["builder-util@26.4.1", "", { "dependencies": { "7zip-bin": "5.2.0", "@types/debug": "4.1.12", "app-builder-bin": "5.0.0-alpha.12", "builder-util-runtime": "9.5.1", "chalk": "4.1.2", "cross-spawn": "7.0.6", "debug": "4.4.3", "fs-extra": "10.1.0", "http-proxy-agent": "7.0.2", "https-proxy-agent": "7.0.6", "js-yaml": "4.1.1", "sanitize-filename": "1.6.3", "source-map-support": "0.5.21", "stat-mode": "1.0.0", "temp-file": "3.4.0", "tiny-async-pool": "1.3.0" } }, "sha512-FlgH43XZ50w3UtS1RVGDWOz8v9qMXPC7upMtKMtBEnYdt1OVoS61NYhKm/4x+cIaWqJTXua0+VVPI+fSPGXNIw=="], - - "electron-winstaller/fs-extra": ["fs-extra@7.0.1", "", { "dependencies": { "graceful-fs": "4.2.11", "jsonfile": "4.0.0", "universalify": "0.1.2" } }, "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw=="], - - "filelist/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "2.0.2" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], + "electron-winstaller/fs-extra": ["fs-extra@7.0.1", "", { "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw=="], "foreground-child/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - "glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "1.1.12" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], - "global-agent/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], "lru-cache/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], - "minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - "minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - "minipass-sized/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "minipass-sized/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], "node-abi/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], @@ -824,104 +804,36 @@ "tiny-async-pool/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], - "@electron/asar/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "1.0.2", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], - - "@electron/get/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "4.2.11" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], + "@electron/get/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], "@electron/get/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], - "@electron/universal/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "1.0.2" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], - "@types/cacheable-request/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], - "@types/fs-extra/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], - "@types/keyv/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], - - "@types/plist/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], - - "@types/responselike/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], - - "@types/ws/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], - - "@types/yauzl/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], - - "app-builder-lib/@electron/get/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "4.2.11", "jsonfile": "4.0.0", "universalify": "0.1.2" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], + "app-builder-lib/@electron/get/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], "app-builder-lib/@electron/get/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "cacache/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], - - "cacache/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "2.0.2" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - "cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - "dir-compare/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "1.0.2", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], - - "electron-builder-squirrel-windows/app-builder-lib/@electron/get": ["@electron/get@3.1.0", "", { "dependencies": { "debug": "4.4.3", "env-paths": "2.2.1", "fs-extra": "8.1.0", "got": "11.8.6", "progress": "2.0.3", "semver": "6.3.1", "sumchecker": "3.0.1" }, "optionalDependencies": { "global-agent": "3.0.0" } }, "sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ=="], - - "electron-builder-squirrel-windows/app-builder-lib/ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="], - - "electron-builder-squirrel-windows/app-builder-lib/dmg-builder": ["dmg-builder@26.7.0", "", { "dependencies": { "app-builder-lib": "26.7.0", "builder-util": "26.4.1", "fs-extra": "10.1.0", "iconv-lite": "0.6.3", "js-yaml": "4.1.1" }, "optionalDependencies": { "dmg-license": "1.0.11" } }, "sha512-uOOBA3f+kW3o4KpSoMQ6SNpdXU7WtxlJRb9vCZgOvqhTz4b3GjcoWKstdisizNZLsylhTMv8TLHFPFW0Uxsj/g=="], - - "electron-builder-squirrel-windows/app-builder-lib/electron-publish": ["electron-publish@26.6.0", "", { "dependencies": { "@types/fs-extra": "9.0.13", "builder-util": "26.4.1", "builder-util-runtime": "9.5.1", "chalk": "4.1.2", "form-data": "4.0.5", "fs-extra": "10.1.0", "lazy-val": "1.0.5", "mime": "2.6.0" } }, "sha512-LsyHMMqbvJ2vsOvuWJ19OezgF2ANdCiHpIucDHNiLhuI+/F3eW98ouzWSRmXXi82ZOPZXC07jnIravY4YYwCLQ=="], - - "electron-builder-squirrel-windows/app-builder-lib/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - - "electron-winstaller/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "4.2.11" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], + "electron-winstaller/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], "electron-winstaller/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], "electron/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], - "filelist/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "1.0.2" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - - "glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "1.0.2", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], - "minipass-flush/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], "minipass-pipeline/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], "minipass-sized/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], - "@electron/asar/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - - "@electron/universal/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - - "app-builder-lib/@electron/get/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "4.2.11" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], + "app-builder-lib/@electron/get/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], "app-builder-lib/@electron/get/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], - - "cacache/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "5.1.2", "string-width-cjs": "npm:string-width@4.2.3", "strip-ansi": "7.1.2", "strip-ansi-cjs": "npm:strip-ansi@6.0.1", "wrap-ansi": "8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], - - "cacache/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "1.0.2" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - - "dir-compare/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - - "electron-builder-squirrel-windows/app-builder-lib/@electron/get/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "4.2.11", "jsonfile": "4.0.0", "universalify": "0.1.2" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], - - "electron-builder-squirrel-windows/app-builder-lib/@electron/get/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "filelist/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - - "glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - - "cacache/glob/jackspeak/@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "0.2.0", "emoji-regex": "9.2.2", "strip-ansi": "7.1.2" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], - - "cacache/glob/jackspeak/@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "6.2.2" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], - - "cacache/glob/jackspeak/@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "6.2.3", "string-width": "5.1.2", "strip-ansi": "7.1.2" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], - - "cacache/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - - "electron-builder-squirrel-windows/app-builder-lib/@electron/get/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "4.2.11" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], - - "electron-builder-squirrel-windows/app-builder-lib/@electron/get/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], - - "cacache/glob/jackspeak/@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], - - "cacache/glob/jackspeak/@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], - - "cacache/glob/jackspeak/@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], } } diff --git a/changes/2026-03-19-incremental-known-word-cache.md b/changes/2026-03-19-incremental-known-word-cache.md deleted file mode 100644 index 85cfc07..0000000 --- a/changes/2026-03-19-incremental-known-word-cache.md +++ /dev/null @@ -1,4 +0,0 @@ -type: fixed -area: anki - -- Known-word cache refreshes now reconcile Anki changes incrementally instead of wiping and rebuilding on startup, mined cards can append their word into the cache immediately through a new default-enabled config flag, and explicit refreshes now run through `subminer doctor --refresh-known-words`. diff --git a/changes/2026-03-19-known-jlpt-reading-fallback.md b/changes/2026-03-19-known-jlpt-reading-fallback.md deleted file mode 100644 index 16e978b..0000000 --- a/changes/2026-03-19-known-jlpt-reading-fallback.md +++ /dev/null @@ -1,4 +0,0 @@ -type: fixed -area: subtitle - -- Restored known-word coloring and JLPT underlines for subtitle tokens like `大体` when the subtitle token is kanji but the known-word cache only matches the kana reading. diff --git a/changes/2026-03-19-stats-ended-media-progress.md b/changes/2026-03-19-stats-ended-media-progress.md deleted file mode 100644 index bf2829c..0000000 --- a/changes/2026-03-19-stats-ended-media-progress.md +++ /dev/null @@ -1,4 +0,0 @@ -type: fixed -area: stats - -- Episode progress in the anime page now uses the last ended playback position instead of cumulative active watch time, avoiding distorted percentages after rewatches or repeated sessions. diff --git a/changes/2026-03-19-stats-session-progress-checkpoint.md b/changes/2026-03-19-stats-session-progress-checkpoint.md deleted file mode 100644 index 832f65d..0000000 --- a/changes/2026-03-19-stats-session-progress-checkpoint.md +++ /dev/null @@ -1,4 +0,0 @@ -type: fixed -area: stats - -- Anime episode progress now keeps the latest known playback position through active-session checkpoints and stale-session recovery, so recently watched episodes no longer lose their progress percentage. diff --git a/changes/2026-03-19-texthooker-docs-bundle-update.md b/changes/2026-03-19-texthooker-docs-bundle-update.md deleted file mode 100644 index 55fedcb..0000000 --- a/changes/2026-03-19-texthooker-docs-bundle-update.md +++ /dev/null @@ -1,4 +0,0 @@ -type: changed -area: docs - -- Refreshed the vendored Texthooker docs/index.html bundle to match the latest local build artifacts. diff --git a/changes/2026-03-20-stats-episode-progress-subtitle-fallback.md b/changes/2026-03-20-stats-episode-progress-subtitle-fallback.md deleted file mode 100644 index 1bdb47f..0000000 --- a/changes/2026-03-20-stats-episode-progress-subtitle-fallback.md +++ /dev/null @@ -1,4 +0,0 @@ -type: fixed -area: stats - -- Anime episode progress now falls back to the latest retained subtitle/event timing when a session is missing a persisted playback-position checkpoint, so older watch sessions no longer get stuck at `0%` progress. diff --git a/changes/2026-03-22-subtitle-sidebar-config.md b/changes/2026-03-22-subtitle-sidebar-config.md new file mode 100644 index 0000000..89f18d9 --- /dev/null +++ b/changes/2026-03-22-subtitle-sidebar-config.md @@ -0,0 +1,5 @@ +type: changed +area: subtitle sidebar + +- Added subtitle sidebar state and behavior updates, including startup-auto-open controls and resume positioning improvements. +- Fixed subtitle prefetch and embedded overlay passthrough sync between sidebar and overlay subtitle rendering. diff --git a/config.example.jsonc b/config.example.jsonc index bf713e6..ab7af4a 100644 --- a/config.example.jsonc +++ b/config.example.jsonc @@ -284,6 +284,30 @@ } // Secondary setting. }, // Primary and secondary subtitle styling. + // ========================================== + // Subtitle Sidebar + // Parsed-subtitle sidebar cue list styling, behavior, and toggle key. + // Hot-reload: subtitle sidebar changes apply live without restarting SubMiner. + // ========================================== + "subtitleSidebar": { + "enabled": false, // Enable the subtitle sidebar feature for parsed subtitle sources. Values: true | false + "autoOpen": false, // Automatically open the subtitle sidebar once during overlay startup. Values: true | false + "layout": "overlay", // Render the subtitle sidebar as a floating overlay or reserve space inside mpv. Values: overlay | embedded + "toggleKey": "Backslash", // KeyboardEvent.code used to toggle the subtitle sidebar open and closed. + "pauseVideoOnHover": false, // Pause mpv while hovering the subtitle sidebar, then resume on leave. Values: true | false + "autoScroll": true, // Auto-scroll the active subtitle cue into view while playback advances. Values: true | false + "maxWidth": 420, // Maximum sidebar width in CSS pixels. + "opacity": 0.95, // Base opacity applied to the sidebar shell. + "backgroundColor": "rgba(73, 77, 100, 0.9)", // Background color for the subtitle sidebar shell. + "textColor": "#cad3f5", // Default cue text color in the subtitle sidebar. + "fontFamily": "\"M PLUS 1\", \"Noto Sans CJK JP\", sans-serif", // Font family used for subtitle sidebar cue text. + "fontSize": 16, // Base font size for subtitle sidebar cue text in CSS pixels. + "timestampColor": "#a5adcb", // Timestamp color in the subtitle sidebar. + "activeLineColor": "#f5bde6", // Text color for the active subtitle cue. + "activeLineBackgroundColor": "rgba(138, 173, 244, 0.22)", // Background color for the active subtitle cue. + "hoverLineBackgroundColor": "rgba(54, 58, 79, 0.84)" // Background color for hovered subtitle cues. + }, // Parsed-subtitle sidebar cue list styling, behavior, and toggle key. + // ========================================== // Shared AI Provider // Canonical OpenAI-compatible provider transport settings shared by Anki and YouTube subtitle fixing. diff --git a/docs-site/changelog.md b/docs-site/changelog.md index 9c8348d..53be971 100644 --- a/docs-site/changelog.md +++ b/docs-site/changelog.md @@ -1,5 +1,14 @@ # Changelog +## v0.8.0 (2026-03-22) +- Refreshed the vendored Texthooker docs/index.html bundle to match the latest local build artifacts. +- Added incremental known-word cache refresh behavior so mined cards can append cache entries immediately and `subminer doctor --refresh-known-words` is now the explicit full refresh path. +- Fixed known-word/JLPT subtitle styling so tokens like `大体` keep expected coloring even when only the kana reading is in cache. +- Fixed anime progress to use last ended playback position and keep latest known checkpoint across sessions, preventing stale or zero percent regressions. +- Kept subtitle sidebar cue tracking stable across transitions and improved sidebar configuration documentation for `layout`, `fontFamily`, and `fontSize`. +- Added `subtitleSidebar.autoOpen` to open the subtitle sidebar at startup when enabled. +- Improved sidebar resume/start behavior to jump directly to the active cue on resume while preserving auto-follow smooth motion. + ## v0.7.0 (2026-03-19) - Added a full local immersion dashboard release line with Overview, Library, Trends, Vocabulary, and Sessions drill-down views backed by SQLite tracking data. - Added browser-first stats workflows: `subminer stats`, background stats daemon controls (`-b` / `-s`), stats cleanup, and dashboard-side mining actions with media enrichment. diff --git a/docs-site/configuration.md b/docs-site/configuration.md index 5bde096..be38853 100644 --- a/docs-site/configuration.md +++ b/docs-site/configuration.md @@ -59,6 +59,7 @@ SubMiner watches the active config file (`config.jsonc` or `config.json`) while Hot-reloadable fields: - `subtitleStyle` +- `subtitleSidebar` - `keybindings` - `shortcuts` - `secondarySub.defaultMode` @@ -88,6 +89,7 @@ The configuration file includes several main sections: **Subtitle Display** - [**Subtitle Style**](#subtitle-style) - Appearance customization +- [**Subtitle Sidebar**](#subtitle-sidebar) - Parsed cue list sidebar modal - [**Subtitle Position**](#subtitle-position) - Overlay vertical positioning - [**Secondary Subtitles**](#secondary-subtitles) - Dual subtitle track support @@ -337,6 +339,46 @@ Secondary subtitle defaults: `fontFamily: "Inter, Noto Sans, Helvetica Neue, san **See `config.example.jsonc`** for the complete list of subtitle style configuration options. +### Subtitle Sidebar + +Configure the parsed-subtitle sidebar modal. + +```json +{ + "subtitleSidebar": { + "enabled": true, + "layout": "overlay", + "toggleKey": "Backslash", + "pauseVideoOnHover": false, + "autoScroll": true, + "fontFamily": "\"M PLUS 1\", \"Noto Sans CJK JP\", sans-serif", + "fontSize": 16 + } +} +``` + +| Option | Values | Description | +| --------------------------- | ---------------- | -------------------------------------------------------------------------------- | +| `enabled` | boolean | Enable subtitle sidebar support (`false` by default) | +| `layout` | string | `"overlay"` floats over mpv; `"embedded"` reserves right-side player space to mimic browser-like layout | +| `toggleKey` | string | `KeyboardEvent.code` used to open/close the sidebar (default: `"Backslash"`) | +| `pauseVideoOnHover` | boolean | Pause playback while hovering the sidebar cue list | +| `autoScroll` | boolean | Keep the active cue in view while playback advances | +| `maxWidth` | number | Maximum sidebar width in CSS pixels (default: `420`) | +| `opacity` | number | Sidebar opacity between `0` and `1` (default: `0.78`) | +| `backgroundColor` | string | Sidebar shell background color | +| `textColor` | hex color | Default cue text color | +| `fontFamily` | string | CSS `font-family` value applied to sidebar cue text | +| `fontSize` | number | Base sidebar cue font size in CSS pixels (default: `16`) | +| `timestampColor` | hex color | Cue timestamp color | +| `activeLineColor` | hex color | Active cue text color | +| `activeLineBackgroundColor` | string | Active cue background color | +| `hoverLineBackgroundColor` | string | Hovered cue background color | + +The sidebar is only available when the active subtitle source has been parsed into a cue list. Default colors use Catppuccin Macchiato with a semi-transparent shell so the panel stays readable without feeling like an opaque settings dialog. + +`embedded` layout is intended to act like a split-pane view: it reserves player space with a right-side video margin and keeps interaction in both the player area and sidebar. If you see unexpected offset behavior in your environment, switch back to `overlay` to isolate sidebar placement. + `jlptColors` keys are: | Key | Default | Description | diff --git a/docs-site/public/config.example.jsonc b/docs-site/public/config.example.jsonc index bf713e6..ab7af4a 100644 --- a/docs-site/public/config.example.jsonc +++ b/docs-site/public/config.example.jsonc @@ -284,6 +284,30 @@ } // Secondary setting. }, // Primary and secondary subtitle styling. + // ========================================== + // Subtitle Sidebar + // Parsed-subtitle sidebar cue list styling, behavior, and toggle key. + // Hot-reload: subtitle sidebar changes apply live without restarting SubMiner. + // ========================================== + "subtitleSidebar": { + "enabled": false, // Enable the subtitle sidebar feature for parsed subtitle sources. Values: true | false + "autoOpen": false, // Automatically open the subtitle sidebar once during overlay startup. Values: true | false + "layout": "overlay", // Render the subtitle sidebar as a floating overlay or reserve space inside mpv. Values: overlay | embedded + "toggleKey": "Backslash", // KeyboardEvent.code used to toggle the subtitle sidebar open and closed. + "pauseVideoOnHover": false, // Pause mpv while hovering the subtitle sidebar, then resume on leave. Values: true | false + "autoScroll": true, // Auto-scroll the active subtitle cue into view while playback advances. Values: true | false + "maxWidth": 420, // Maximum sidebar width in CSS pixels. + "opacity": 0.95, // Base opacity applied to the sidebar shell. + "backgroundColor": "rgba(73, 77, 100, 0.9)", // Background color for the subtitle sidebar shell. + "textColor": "#cad3f5", // Default cue text color in the subtitle sidebar. + "fontFamily": "\"M PLUS 1\", \"Noto Sans CJK JP\", sans-serif", // Font family used for subtitle sidebar cue text. + "fontSize": 16, // Base font size for subtitle sidebar cue text in CSS pixels. + "timestampColor": "#a5adcb", // Timestamp color in the subtitle sidebar. + "activeLineColor": "#f5bde6", // Text color for the active subtitle cue. + "activeLineBackgroundColor": "rgba(138, 173, 244, 0.22)", // Background color for the active subtitle cue. + "hoverLineBackgroundColor": "rgba(54, 58, 79, 0.84)" // Background color for hovered subtitle cues. + }, // Parsed-subtitle sidebar cue list styling, behavior, and toggle key. + // ========================================== // Shared AI Provider // Canonical OpenAI-compatible provider transport settings shared by Anki and YouTube subtitle fixing. diff --git a/docs-site/shortcuts.md b/docs-site/shortcuts.md index 3d4f9b1..503aa17 100644 --- a/docs-site/shortcuts.md +++ b/docs-site/shortcuts.md @@ -68,10 +68,13 @@ Mouse-hover playback behavior is configured separately from shortcuts: `subtitle | `Ctrl/Cmd+Shift+O` | Open runtime options palette | `shortcuts.openRuntimeOptions` | | `Ctrl+Shift+J` | Open Jimaku subtitle search modal | `shortcuts.openJimaku` | | `Ctrl+Alt+S` | Open subtitle sync (subsync) modal | `shortcuts.triggerSubsync` | +| `\` | Toggle subtitle sidebar | `subtitleSidebar.toggleKey` | | `` ` `` | Toggle stats overlay | `stats.toggleKey` | The stats toggle is handled inside the focused visible overlay window. It is configurable through the top-level `stats.toggleKey` setting and defaults to `Backquote`. +The subtitle sidebar toggle is overlay-local and only opens when SubMiner has a parsed cue list for the active subtitle source. + ## Controller Shortcuts These overlay-local shortcuts are fixed and open controller utilities for the Chrome Gamepad API integration. @@ -133,4 +136,4 @@ The `keybindings` array overrides or extends the overlay's built-in key handling } ``` -Both `shortcuts` and `keybindings` are [hot-reloadable](/configuration#hot-reload-behavior) — changes take effect without restarting SubMiner. +Both `shortcuts`, `keybindings`, and `subtitleSidebar` are [hot-reloadable](/configuration#hot-reload-behavior) — changes take effect without restarting SubMiner. diff --git a/package.json b/package.json index 3aa1ac0..43a8830 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "subminer", - "version": "0.7.1", + "version": "0.8.0", "description": "All-in-one sentence mining overlay with AnkiConnect and dictionary integration", "packageManager": "bun@1.3.5", "main": "dist/main-entry.js", @@ -77,6 +77,12 @@ "build:win": "bun run build && electron-builder --win nsis zip --publish never", "build:win:unsigned": "bun run build && node scripts/build-win-unsigned.mjs" }, + "overrides": { + "app-builder-lib": "26.8.2", + "electron-builder-squirrel-windows": "26.8.2", + "minimatch": "10.2.3", + "tar": "7.5.11" + }, "keywords": [ "anki", "ankiconnect", @@ -105,7 +111,7 @@ "@types/node": "^25.3.0", "@types/ws": "^8.18.1", "electron": "^37.10.3", - "electron-builder": "^26.8.1", + "electron-builder": "26.8.2", "esbuild": "^0.25.12", "prettier": "^3.8.1", "typescript": "^5.9.3" @@ -159,12 +165,21 @@ "include": "build/installer.nsh" }, "files": [ - "dist/**/*", - "stats/dist/**/*", - "vendor/texthooker-ui/docs/**/*", - "vendor/texthooker-ui/package.json", - "package.json", - "scripts/get-mpv-window-macos.swift" + "**/*", + "!src{,/**/*}", + "!launcher{,/**/*}", + "!stats/src{,/**/*}", + "!stats/index.html", + "!docs-site{,/**/*}", + "!changes{,/**/*}", + "!backlog{,/**/*}", + "!.tmp{,/**/*}", + "!release-*{,/**/*}", + "!vendor/subminer-yomitan{,/**/*}", + "!vendor/texthooker-ui/src{,/**/*}", + "!vendor/texthooker-ui/node_modules{,/**/*}", + "!vendor/texthooker-ui/.svelte-kit{,/**/*}", + "!vendor/texthooker-ui/package-lock.json" ], "extraResources": [ { diff --git a/scripts/patch-modernz.sh b/scripts/patch-modernz.sh new file mode 100755 index 0000000..12b7123 --- /dev/null +++ b/scripts/patch-modernz.sh @@ -0,0 +1,157 @@ +#!/bin/bash + +set -euo pipefail + +TARGET="${HOME}/.config/mpv/scripts/modernz.lua" + +usage() { + cat <<'EOF' +Usage: patch-modernz.sh [--target /path/to/modernz.lua] + +Applies the local ModernZ OSC sidebar-resize patch to an existing modernz.lua. +If the target file does not exist, the script exits without changing anything. +EOF +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --target) + if [[ $# -lt 2 || -z "${2:-}" || "$2" == -* ]]; then + echo "patch-modernz: --target requires a non-empty file path" >&2 + usage >&2 + exit 1 + fi + TARGET="$2" + shift 2 + ;; + --help|-h) + usage + exit 0 + ;; + *) + echo "Unknown argument: $1" >&2 + exit 1 + ;; + esac +done + +if [[ ! -f "$TARGET" ]]; then + echo "patch-modernz: target missing, skipped: $TARGET" + exit 0 +fi + +if grep -q 'get_external_video_margin_ratio' "$TARGET" \ + && grep -q 'observe_cached("video-margin-ratio-right"' "$TARGET"; then + echo "patch-modernz: already patched: $TARGET" + exit 0 +fi + +if ! patch --forward --quiet "$TARGET" <<'PATCH' +--- a/modernz.lua ++++ b/modernz.lua +@@ -931,6 +931,26 @@ local function reset_margins() + set_margin_offset("osd-margin-y", 0) + end + ++local function get_external_video_margin_ratio(prop) ++ local value = mp.get_property_number(prop, 0) or 0 ++ if value < 0 then return 0 end ++ if value > 0.95 then return 0.95 end ++ return value ++end ++ ++local function get_layout_horizontal_bounds() ++ local margin_l = get_external_video_margin_ratio("video-margin-ratio-left") ++ local margin_r = get_external_video_margin_ratio("video-margin-ratio-right") ++ local width_ratio = math.max(0.05, 1 - margin_l - margin_r) ++ local pos_x = osc_param.playresx * margin_l ++ local width = osc_param.playresx * width_ratio ++ ++ osc_param.video_margins.l = margin_l ++ osc_param.video_margins.r = margin_r ++ ++ return pos_x, width ++end ++ + local function update_margins() + local use_margins = get_hidetimeout() < 0 or user_opts.dynamic_margins + local top_vis = state.wc_visible +@@ -1965,8 +1985,9 @@ layouts["modern"] = function () + local chapter_index = user_opts.show_chapter_title and mp.get_property_number("chapter", -1) >= 0 + local osc_height_offset = (no_title and user_opts.notitle_osc_h_offset or 0) + ((no_chapter or not chapter_index) and user_opts.nochapter_osc_h_offset or 0) + ++ local posX, layout_width = get_layout_horizontal_bounds() + local osc_geo = { +- w = osc_param.playresx, ++ w = layout_width, + h = user_opts.osc_height - osc_height_offset + } + +@@ -1974,7 +1995,6 @@ layouts["modern"] = function () + osc_param.video_margins.b = math.max(user_opts.osc_height, user_opts.fade_alpha) / osc_param.playresy + + -- origin of the controllers, left/bottom corner +- local posX = 0 + local posY = osc_param.playresy + + osc_param.areas = {} -- delete areas +@@ -2191,8 +2211,9 @@ layouts["modern-compact"] = function () + ((user_opts.title_mbtn_left_command == "" and user_opts.title_mbtn_right_command == "") and 25 or 0) + + (((user_opts.chapter_title_mbtn_left_command == "" and user_opts.chapter_title_mbtn_right_command == "") or not chapter_index) and 10 or 0) + ++ local posX, layout_width = get_layout_horizontal_bounds() + local osc_geo = { +- w = osc_param.playresx, ++ w = layout_width, + h = 145 - osc_height_offset + } + +@@ -2200,7 +2221,6 @@ layouts["modern-compact"] = function () + osc_param.video_margins.b = math.max(osc_geo.h, user_opts.fade_alpha) / osc_param.playresy + + -- origin of the controllers, left/bottom corner +- local posX = 0 + local posY = osc_param.playresy + + osc_param.areas = {} -- delete areas +@@ -2370,8 +2390,9 @@ layouts["modern-compact"] = function () + end + + layouts["modern-image"] = function () ++ local posX, layout_width = get_layout_horizontal_bounds() + local osc_geo = { +- w = osc_param.playresx, ++ w = layout_width, + h = 50 + } + +@@ -2379,7 +2400,6 @@ layouts["modern-image"] = function () + osc_param.video_margins.b = math.max(50, user_opts.fade_alpha) / osc_param.playresy + + -- origin of the controllers, left/bottom corner +- local posX = 0 + local posY = osc_param.playresy + + osc_param.areas = {} -- delete areas +@@ -3718,6 +3738,14 @@ observe_cached("border", request_init_resize) + observe_cached("title-bar", request_init_resize) + observe_cached("window-maximized", request_init_resize) + observe_cached("idle-active", request_tick) ++observe_cached("video-margin-ratio-left", function () ++ state.marginsREQ = true ++ request_init_resize() ++end) ++observe_cached("video-margin-ratio-right", function () ++ state.marginsREQ = true ++ request_init_resize() ++end) + mp.observe_property("user-data/mpv/console/open", "bool", function(_, val) + if val and user_opts.visibility == "auto" and not user_opts.showonselect then + osc_visible(false) +PATCH +then + echo "patch-modernz: failed to apply patch to $TARGET" >&2 + exit 1 +fi + +echo "patch-modernz: patched $TARGET" diff --git a/scripts/patch-modernz.test.ts b/scripts/patch-modernz.test.ts new file mode 100644 index 0000000..7ceadf4 --- /dev/null +++ b/scripts/patch-modernz.test.ts @@ -0,0 +1,76 @@ +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { spawnSync } from 'node:child_process'; +import test from 'node:test'; + +function withTempDir(fn: (dir: string) => T): T { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-patch-modernz-test-')); + try { + return fn(dir); + } finally { + fs.rmSync(dir, { recursive: true, force: true }); + } +} + +function writeExecutable(filePath: string, contents: string): void { + fs.writeFileSync(filePath, contents, 'utf8'); + fs.chmodSync(filePath, 0o755); +} + +test('patch-modernz rejects a missing --target value', () => { + withTempDir((root) => { + const result = spawnSync('bash', ['scripts/patch-modernz.sh', '--target'], { + cwd: process.cwd(), + encoding: 'utf8', + env: { + ...process.env, + HOME: path.join(root, 'home'), + }, + }); + + assert.equal(result.status, 1, result.stderr || result.stdout); + assert.match(result.stderr, /--target requires a non-empty file path/); + assert.match(result.stderr, /Usage: patch-modernz\.sh/); + }); +}); + +test('patch-modernz reports patch failures explicitly', () => { + withTempDir((root) => { + const binDir = path.join(root, 'bin'); + const target = path.join(root, 'modernz.lua'); + const patchLog = path.join(root, 'patch.log'); + + fs.mkdirSync(binDir, { recursive: true }); + fs.mkdirSync(path.dirname(target), { recursive: true }); + fs.writeFileSync(target, 'original', 'utf8'); + + writeExecutable( + path.join(binDir, 'patch'), + `#!/usr/bin/env bash +set -euo pipefail +cat > "${patchLog}" +exit 1 +`, + ); + + const result = spawnSync( + 'bash', + ['scripts/patch-modernz.sh', '--target', target], + { + cwd: process.cwd(), + encoding: 'utf8', + env: { + ...process.env, + HOME: path.join(root, 'home'), + PATH: `${binDir}:${process.env.PATH || ''}`, + }, + }, + ); + + assert.equal(result.status, 1, result.stderr || result.stdout); + assert.match(result.stderr, /failed to apply patch to/); + assert.equal(fs.readFileSync(patchLog, 'utf8').includes('modernz.lua'), true); + }); +}); diff --git a/src/config/definitions.ts b/src/config/definitions.ts index 396bada..59c4f99 100644 --- a/src/config/definitions.ts +++ b/src/config/definitions.ts @@ -36,7 +36,7 @@ const { } = CORE_DEFAULT_CONFIG; const { ankiConnect, jimaku, anilist, yomitan, jellyfin, discordPresence, ai, youtubeSubgen } = INTEGRATIONS_DEFAULT_CONFIG; -const { subtitleStyle } = SUBTITLE_DEFAULT_CONFIG; +const { subtitleStyle, subtitleSidebar } = SUBTITLE_DEFAULT_CONFIG; const { immersionTracking } = IMMERSION_DEFAULT_CONFIG; const { stats } = STATS_DEFAULT_CONFIG; @@ -54,6 +54,7 @@ export const DEFAULT_CONFIG: ResolvedConfig = { subsync, startupWarmups, subtitleStyle, + subtitleSidebar, auto_start_overlay, jimaku, anilist, diff --git a/src/config/definitions/defaults-subtitle.ts b/src/config/definitions/defaults-subtitle.ts index 6798d3d..25bbd0f 100644 --- a/src/config/definitions/defaults-subtitle.ts +++ b/src/config/definitions/defaults-subtitle.ts @@ -1,6 +1,6 @@ import { ResolvedConfig } from '../../types'; -export const SUBTITLE_DEFAULT_CONFIG: Pick = { +export const SUBTITLE_DEFAULT_CONFIG: Pick = { subtitleStyle: { enableJlpt: false, preserveLineBreaks: false, @@ -57,4 +57,22 @@ export const SUBTITLE_DEFAULT_CONFIG: Pick = { fontStyle: 'normal', }, }, + subtitleSidebar: { + enabled: false, + autoOpen: false, + layout: 'overlay', + toggleKey: 'Backslash', + pauseVideoOnHover: false, + autoScroll: true, + maxWidth: 420, + opacity: 0.95, + backgroundColor: 'rgba(73, 77, 100, 0.9)', + textColor: '#cad3f5', + fontFamily: '"M PLUS 1", "Noto Sans CJK JP", sans-serif', + fontSize: 16, + timestampColor: '#a5adcb', + activeLineColor: '#f5bde6', + activeLineBackgroundColor: 'rgba(138, 173, 244, 0.22)', + hoverLineBackgroundColor: 'rgba(54, 58, 79, 0.84)', + }, }; diff --git a/src/config/definitions/options-subtitle.ts b/src/config/definitions/options-subtitle.ts index 72c3ec4..9b2d294 100644 --- a/src/config/definitions/options-subtitle.ts +++ b/src/config/definitions/options-subtitle.ts @@ -110,5 +110,102 @@ export function buildSubtitleConfigOptionRegistry( description: 'Five colors used for rank bands when mode is `banded` (from most common to least within topX).', }, + { + path: 'subtitleSidebar.enabled', + kind: 'boolean', + defaultValue: defaultConfig.subtitleSidebar.enabled, + description: 'Enable the subtitle sidebar feature for parsed subtitle sources.', + }, + { + path: 'subtitleSidebar.autoOpen', + kind: 'boolean', + defaultValue: defaultConfig.subtitleSidebar.autoOpen, + description: 'Automatically open the subtitle sidebar once during overlay startup.', + }, + { + path: 'subtitleSidebar.layout', + kind: 'enum', + enumValues: ['overlay', 'embedded'], + defaultValue: defaultConfig.subtitleSidebar.layout, + description: 'Render the subtitle sidebar as a floating overlay or reserve space inside mpv.', + }, + { + path: 'subtitleSidebar.toggleKey', + kind: 'string', + defaultValue: defaultConfig.subtitleSidebar.toggleKey, + description: 'KeyboardEvent.code used to toggle the subtitle sidebar open and closed.', + }, + { + path: 'subtitleSidebar.pauseVideoOnHover', + kind: 'boolean', + defaultValue: defaultConfig.subtitleSidebar.pauseVideoOnHover, + description: 'Pause mpv while hovering the subtitle sidebar, then resume on leave.', + }, + { + path: 'subtitleSidebar.autoScroll', + kind: 'boolean', + defaultValue: defaultConfig.subtitleSidebar.autoScroll, + description: 'Auto-scroll the active subtitle cue into view while playback advances.', + }, + { + path: 'subtitleSidebar.maxWidth', + kind: 'number', + defaultValue: defaultConfig.subtitleSidebar.maxWidth, + description: 'Maximum sidebar width in CSS pixels.', + }, + { + path: 'subtitleSidebar.opacity', + kind: 'number', + defaultValue: defaultConfig.subtitleSidebar.opacity, + description: 'Base opacity applied to the sidebar shell.', + }, + { + path: 'subtitleSidebar.backgroundColor', + kind: 'string', + defaultValue: defaultConfig.subtitleSidebar.backgroundColor, + description: 'Background color for the subtitle sidebar shell.', + }, + { + path: 'subtitleSidebar.textColor', + kind: 'string', + defaultValue: defaultConfig.subtitleSidebar.textColor, + description: 'Default cue text color in the subtitle sidebar.', + }, + { + path: 'subtitleSidebar.fontFamily', + kind: 'string', + defaultValue: defaultConfig.subtitleSidebar.fontFamily, + description: 'Font family used for subtitle sidebar cue text.', + }, + { + path: 'subtitleSidebar.fontSize', + kind: 'number', + defaultValue: defaultConfig.subtitleSidebar.fontSize, + description: 'Base font size for subtitle sidebar cue text in CSS pixels.', + }, + { + path: 'subtitleSidebar.timestampColor', + kind: 'string', + defaultValue: defaultConfig.subtitleSidebar.timestampColor, + description: 'Timestamp color in the subtitle sidebar.', + }, + { + path: 'subtitleSidebar.activeLineColor', + kind: 'string', + defaultValue: defaultConfig.subtitleSidebar.activeLineColor, + description: 'Text color for the active subtitle cue.', + }, + { + path: 'subtitleSidebar.activeLineBackgroundColor', + kind: 'string', + defaultValue: defaultConfig.subtitleSidebar.activeLineBackgroundColor, + description: 'Background color for the active subtitle cue.', + }, + { + path: 'subtitleSidebar.hoverLineBackgroundColor', + kind: 'string', + defaultValue: defaultConfig.subtitleSidebar.hoverLineBackgroundColor, + description: 'Background color for hovered subtitle cues.', + }, ]; } diff --git a/src/config/definitions/template-sections.ts b/src/config/definitions/template-sections.ts index c2ae9d8..d988402 100644 --- a/src/config/definitions/template-sections.ts +++ b/src/config/definitions/template-sections.ts @@ -98,6 +98,12 @@ const SUBTITLE_TEMPLATE_SECTIONS: ConfigTemplateSection[] = [ notes: ['Hot-reload: subtitle style changes apply live without restarting SubMiner.'], key: 'subtitleStyle', }, + { + title: 'Subtitle Sidebar', + description: ['Parsed-subtitle sidebar cue list styling, behavior, and toggle key.'], + notes: ['Hot-reload: subtitle sidebar changes apply live without restarting SubMiner.'], + key: 'subtitleSidebar', + }, ]; const INTEGRATION_TEMPLATE_SECTIONS: ConfigTemplateSection[] = [ diff --git a/src/config/resolve/shared.ts b/src/config/resolve/shared.ts index 2490f91..4981eeb 100644 --- a/src/config/resolve/shared.ts +++ b/src/config/resolve/shared.ts @@ -15,6 +15,22 @@ export function asBoolean(value: unknown): boolean | undefined { } const hexColorPattern = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/; +const cssColorKeywords = new Set([ + 'transparent', + 'currentcolor', + 'inherit', + 'initial', + 'unset', + 'revert', + 'revert-layer', +]); +const cssColorFunctionPattern = /^(?:rgba?|hsla?)\(\s*[^()]+?\s*\)$/i; + +function supportsCssColor(text: string): boolean { + const css = (globalThis as { CSS?: { supports?: (property: string, value: string) => boolean } }) + .CSS; + return css?.supports?.('color', text) ?? false; +} export function asColor(value: unknown): string | undefined { if (typeof value !== 'string') return undefined; @@ -22,6 +38,30 @@ export function asColor(value: unknown): string | undefined { return hexColorPattern.test(text) ? text : undefined; } +export function asCssColor(value: unknown): string | undefined { + if (typeof value !== 'string') return undefined; + + const text = value.trim(); + if (text.length === 0) { + return undefined; + } + + if (supportsCssColor(text)) { + return text; + } + + const normalized = text.toLowerCase(); + if ( + hexColorPattern.test(text) || + cssColorKeywords.has(normalized) || + cssColorFunctionPattern.test(text) + ) { + return text; + } + + return undefined; +} + export function asFrequencyBandedColors( value: unknown, ): [string, string, string, string, string] | undefined { diff --git a/src/config/resolve/subtitle-domains.ts b/src/config/resolve/subtitle-domains.ts index 1d906c5..2d88bb6 100644 --- a/src/config/resolve/subtitle-domains.ts +++ b/src/config/resolve/subtitle-domains.ts @@ -3,6 +3,7 @@ import { ResolveContext } from './context'; import { asBoolean, asColor, + asCssColor, asFrequencyBandedColors, asNumber, asString, @@ -418,4 +419,180 @@ export function applySubtitleDomainConfig(context: ResolveContext): void { ); } } + + if (isObject(src.subtitleSidebar)) { + const fallback = { ...resolved.subtitleSidebar }; + resolved.subtitleSidebar = { + ...resolved.subtitleSidebar, + ...(src.subtitleSidebar as ResolvedConfig['subtitleSidebar']), + }; + + const enabled = asBoolean((src.subtitleSidebar as { enabled?: unknown }).enabled); + if (enabled !== undefined) { + resolved.subtitleSidebar.enabled = enabled; + } else if ((src.subtitleSidebar as { enabled?: unknown }).enabled !== undefined) { + resolved.subtitleSidebar.enabled = fallback.enabled; + warn( + 'subtitleSidebar.enabled', + (src.subtitleSidebar as { enabled?: unknown }).enabled, + resolved.subtitleSidebar.enabled, + 'Expected boolean.', + ); + } + + const autoOpen = asBoolean((src.subtitleSidebar as { autoOpen?: unknown }).autoOpen); + if (autoOpen !== undefined) { + resolved.subtitleSidebar.autoOpen = autoOpen; + } else if ((src.subtitleSidebar as { autoOpen?: unknown }).autoOpen !== undefined) { + resolved.subtitleSidebar.autoOpen = fallback.autoOpen; + warn( + 'subtitleSidebar.autoOpen', + (src.subtitleSidebar as { autoOpen?: unknown }).autoOpen, + resolved.subtitleSidebar.autoOpen, + 'Expected boolean.', + ); + } + + const layout = asString((src.subtitleSidebar as { layout?: unknown }).layout); + if (layout === 'overlay' || layout === 'embedded') { + resolved.subtitleSidebar.layout = layout; + } else if ((src.subtitleSidebar as { layout?: unknown }).layout !== undefined) { + resolved.subtitleSidebar.layout = fallback.layout; + warn( + 'subtitleSidebar.layout', + (src.subtitleSidebar as { layout?: unknown }).layout, + resolved.subtitleSidebar.layout, + 'Expected "overlay" or "embedded".', + ); + } + + const pauseVideoOnHover = asBoolean( + (src.subtitleSidebar as { pauseVideoOnHover?: unknown }).pauseVideoOnHover, + ); + if (pauseVideoOnHover !== undefined) { + resolved.subtitleSidebar.pauseVideoOnHover = pauseVideoOnHover; + } else if ((src.subtitleSidebar as { pauseVideoOnHover?: unknown }).pauseVideoOnHover !== undefined) { + resolved.subtitleSidebar.pauseVideoOnHover = fallback.pauseVideoOnHover; + warn( + 'subtitleSidebar.pauseVideoOnHover', + (src.subtitleSidebar as { pauseVideoOnHover?: unknown }).pauseVideoOnHover, + resolved.subtitleSidebar.pauseVideoOnHover, + 'Expected boolean.', + ); + } + + const autoScroll = asBoolean((src.subtitleSidebar as { autoScroll?: unknown }).autoScroll); + if (autoScroll !== undefined) { + resolved.subtitleSidebar.autoScroll = autoScroll; + } else if ((src.subtitleSidebar as { autoScroll?: unknown }).autoScroll !== undefined) { + resolved.subtitleSidebar.autoScroll = fallback.autoScroll; + warn( + 'subtitleSidebar.autoScroll', + (src.subtitleSidebar as { autoScroll?: unknown }).autoScroll, + resolved.subtitleSidebar.autoScroll, + 'Expected boolean.', + ); + } + + const toggleKey = asString((src.subtitleSidebar as { toggleKey?: unknown }).toggleKey); + if (toggleKey !== undefined) { + resolved.subtitleSidebar.toggleKey = toggleKey; + } else if ((src.subtitleSidebar as { toggleKey?: unknown }).toggleKey !== undefined) { + resolved.subtitleSidebar.toggleKey = fallback.toggleKey; + warn( + 'subtitleSidebar.toggleKey', + (src.subtitleSidebar as { toggleKey?: unknown }).toggleKey, + resolved.subtitleSidebar.toggleKey, + 'Expected string.', + ); + } + + const maxWidth = asNumber((src.subtitleSidebar as { maxWidth?: unknown }).maxWidth); + if (maxWidth !== undefined && maxWidth > 0) { + resolved.subtitleSidebar.maxWidth = Math.floor(maxWidth); + } else if ((src.subtitleSidebar as { maxWidth?: unknown }).maxWidth !== undefined) { + resolved.subtitleSidebar.maxWidth = fallback.maxWidth; + warn( + 'subtitleSidebar.maxWidth', + (src.subtitleSidebar as { maxWidth?: unknown }).maxWidth, + resolved.subtitleSidebar.maxWidth, + 'Expected positive number.', + ); + } + + const opacity = asNumber((src.subtitleSidebar as { opacity?: unknown }).opacity); + if (opacity !== undefined && opacity >= 0 && opacity <= 1) { + resolved.subtitleSidebar.opacity = opacity; + } else if ((src.subtitleSidebar as { opacity?: unknown }).opacity !== undefined) { + resolved.subtitleSidebar.opacity = fallback.opacity; + warn( + 'subtitleSidebar.opacity', + (src.subtitleSidebar as { opacity?: unknown }).opacity, + resolved.subtitleSidebar.opacity, + 'Expected number between 0 and 1.', + ); + } + + const hexColorFields = ['textColor', 'timestampColor', 'activeLineColor'] as const; + for (const field of hexColorFields) { + const value = asColor((src.subtitleSidebar as Record)[field]); + if (value !== undefined) { + resolved.subtitleSidebar[field] = value; + } else if ((src.subtitleSidebar as Record)[field] !== undefined) { + resolved.subtitleSidebar[field] = fallback[field]; + warn( + `subtitleSidebar.${field}`, + (src.subtitleSidebar as Record)[field], + resolved.subtitleSidebar[field], + 'Expected hex color.', + ); + } + } + + const cssColorFields = [ + 'backgroundColor', + 'activeLineBackgroundColor', + 'hoverLineBackgroundColor', + ] as const; + for (const field of cssColorFields) { + const value = asCssColor((src.subtitleSidebar as Record)[field]); + if (value !== undefined) { + resolved.subtitleSidebar[field] = value; + } else if ((src.subtitleSidebar as Record)[field] !== undefined) { + resolved.subtitleSidebar[field] = fallback[field]; + warn( + `subtitleSidebar.${field}`, + (src.subtitleSidebar as Record)[field], + resolved.subtitleSidebar[field], + 'Expected valid CSS color.', + ); + } + } + + const fontFamily = asString((src.subtitleSidebar as { fontFamily?: unknown }).fontFamily); + if (fontFamily !== undefined && fontFamily.trim().length > 0) { + resolved.subtitleSidebar.fontFamily = fontFamily.trim(); + } else if ((src.subtitleSidebar as { fontFamily?: unknown }).fontFamily !== undefined) { + resolved.subtitleSidebar.fontFamily = fallback.fontFamily; + warn( + 'subtitleSidebar.fontFamily', + (src.subtitleSidebar as { fontFamily?: unknown }).fontFamily, + resolved.subtitleSidebar.fontFamily, + 'Expected non-empty string.', + ); + } + + const fontSize = asNumber((src.subtitleSidebar as { fontSize?: unknown }).fontSize); + if (fontSize !== undefined && fontSize > 0) { + resolved.subtitleSidebar.fontSize = fontSize; + } else if ((src.subtitleSidebar as { fontSize?: unknown }).fontSize !== undefined) { + resolved.subtitleSidebar.fontSize = fallback.fontSize; + warn( + 'subtitleSidebar.fontSize', + (src.subtitleSidebar as { fontSize?: unknown }).fontSize, + resolved.subtitleSidebar.fontSize, + 'Expected positive number.', + ); + } + } } diff --git a/src/config/resolve/subtitle-sidebar.test.ts b/src/config/resolve/subtitle-sidebar.test.ts new file mode 100644 index 0000000..7c23247 --- /dev/null +++ b/src/config/resolve/subtitle-sidebar.test.ts @@ -0,0 +1,93 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { createResolveContext } from './context'; +import { applySubtitleDomainConfig } from './subtitle-domains'; + +test('subtitleSidebar resolves valid values and preserves dedicated defaults', () => { + const { context } = createResolveContext({ + subtitleSidebar: { + enabled: true, + autoOpen: true, + layout: 'embedded', + toggleKey: 'KeyB', + pauseVideoOnHover: true, + autoScroll: false, + maxWidth: 540, + opacity: 0.72, + backgroundColor: 'rgba(36, 39, 58, 0.72)', + textColor: '#cad3f5', + fontFamily: '"Iosevka Aile", sans-serif', + fontSize: 17, + timestampColor: '#a5adcb', + activeLineColor: '#f5bde6', + activeLineBackgroundColor: 'rgba(138, 173, 244, 0.22)', + hoverLineBackgroundColor: 'rgba(54, 58, 79, 0.84)', + }, + }); + + applySubtitleDomainConfig(context); + + assert.equal(context.resolved.subtitleSidebar.enabled, true); + assert.equal(context.resolved.subtitleSidebar.autoOpen, true); + assert.equal(context.resolved.subtitleSidebar.layout, 'embedded'); + assert.equal(context.resolved.subtitleSidebar.toggleKey, 'KeyB'); + assert.equal(context.resolved.subtitleSidebar.pauseVideoOnHover, true); + assert.equal(context.resolved.subtitleSidebar.autoScroll, false); + assert.equal(context.resolved.subtitleSidebar.maxWidth, 540); + assert.equal(context.resolved.subtitleSidebar.opacity, 0.72); + assert.equal(context.resolved.subtitleSidebar.fontFamily, '"Iosevka Aile", sans-serif'); + assert.equal(context.resolved.subtitleSidebar.fontSize, 17); +}); + +test('subtitleSidebar accepts zero opacity', () => { + const { context, warnings } = createResolveContext({ + subtitleSidebar: { + opacity: 0, + }, + }); + + applySubtitleDomainConfig(context); + + assert.equal(context.resolved.subtitleSidebar.opacity, 0); + assert.equal(warnings.some((warning) => warning.path === 'subtitleSidebar.opacity'), false); +}); + +test('subtitleSidebar falls back and warns on invalid values', () => { + const { context, warnings } = createResolveContext({ + subtitleSidebar: { + enabled: 'yes' as never, + autoOpen: 'yes' as never, + layout: 'floating' as never, + maxWidth: -1, + opacity: 5, + fontSize: 0, + textColor: 'blue', + backgroundColor: 'not-a-color', + }, + }); + + applySubtitleDomainConfig(context); + + assert.equal(context.resolved.subtitleSidebar.enabled, false); + assert.equal(context.resolved.subtitleSidebar.autoOpen, false); + assert.equal(context.resolved.subtitleSidebar.layout, 'overlay'); + assert.equal(context.resolved.subtitleSidebar.maxWidth, 420); + assert.equal(context.resolved.subtitleSidebar.opacity, 0.95); + assert.equal(context.resolved.subtitleSidebar.fontSize, 16); + assert.equal(context.resolved.subtitleSidebar.textColor, '#cad3f5'); + assert.equal(context.resolved.subtitleSidebar.backgroundColor, 'rgba(73, 77, 100, 0.9)'); + assert.ok(warnings.some((warning) => warning.path === 'subtitleSidebar.enabled')); + assert.ok(warnings.some((warning) => warning.path === 'subtitleSidebar.autoOpen')); + assert.ok(warnings.some((warning) => warning.path === 'subtitleSidebar.layout')); + assert.ok(warnings.some((warning) => warning.path === 'subtitleSidebar.maxWidth')); + assert.ok(warnings.some((warning) => warning.path === 'subtitleSidebar.opacity')); + assert.ok(warnings.some((warning) => warning.path === 'subtitleSidebar.fontSize')); + assert.ok(warnings.some((warning) => warning.path === 'subtitleSidebar.textColor')); + assert.ok( + warnings.some( + (warning) => + warning.path === 'subtitleSidebar.backgroundColor' && + warning.message === 'Expected valid CSS color.', + ), + ); +}); diff --git a/src/core/services/config-hot-reload.ts b/src/core/services/config-hot-reload.ts index 3e751f2..5a405f3 100644 --- a/src/core/services/config-hot-reload.ts +++ b/src/core/services/config-hot-reload.ts @@ -42,6 +42,9 @@ function classifyDiff(prev: ResolvedConfig, next: ResolvedConfig): ConfigHotRelo if (!isEqual(prev.shortcuts, next.shortcuts)) { hotReloadFields.push('shortcuts'); } + if (!isEqual(prev.subtitleSidebar, next.subtitleSidebar)) { + hotReloadFields.push('subtitleSidebar'); + } if (prev.secondarySub.defaultMode !== next.secondarySub.defaultMode) { hotReloadFields.push('secondarySub.defaultMode'); } @@ -55,7 +58,7 @@ function classifyDiff(prev: ResolvedConfig, next: ResolvedConfig): ConfigHotRelo ]); for (const key of keys) { - if (key === 'subtitleStyle' || key === 'keybindings' || key === 'shortcuts') { + if (key === 'subtitleStyle' || key === 'keybindings' || key === 'shortcuts' || key === 'subtitleSidebar') { continue; } diff --git a/src/core/services/ipc.test.ts b/src/core/services/ipc.test.ts index b92473d..de8595f 100644 --- a/src/core/services/ipc.test.ts +++ b/src/core/services/ipc.test.ts @@ -3,6 +3,7 @@ import assert from 'node:assert/strict'; import { createIpcDepsRuntime, registerIpcHandlers, type IpcServiceDeps } from './ipc'; import { IPC_CHANNELS } from '../../shared/ipc/contracts'; +import type { SubtitleSidebarSnapshot } from '../../types'; interface FakeIpcRegistrar { on: Map void>; @@ -77,6 +78,31 @@ function createControllerConfigFixture() { }; } +function createSubtitleSidebarSnapshotFixture(): SubtitleSidebarSnapshot { + return { + cues: [], + currentSubtitle: { text: '', startTime: null, endTime: null }, + config: { + enabled: false, + autoOpen: false, + layout: 'overlay', + toggleKey: 'Backslash', + pauseVideoOnHover: false, + autoScroll: true, + maxWidth: 420, + opacity: 0.92, + backgroundColor: 'rgba(54, 58, 79, 0.88)', + textColor: '#cad3f5', + fontFamily: '"M PLUS 1", "Noto Sans CJK JP", sans-serif', + fontSize: 16, + timestampColor: '#a5adcb', + activeLineColor: '#f5bde6', + activeLineBackgroundColor: 'rgba(138, 173, 244, 0.22)', + hoverLineBackgroundColor: 'rgba(54, 58, 79, 0.84)', + }, + }; +} + function createRegisterIpcDeps(overrides: Partial = {}): IpcServiceDeps { return { onOverlayModalClosed: () => {}, @@ -88,6 +114,7 @@ function createRegisterIpcDeps(overrides: Partial = {}): IpcServ tokenizeCurrentSubtitle: async () => null, getCurrentSubtitleRaw: () => '', getCurrentSubtitleAss: () => '', + getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(), getPlaybackPaused: () => false, getSubtitlePosition: () => null, getSubtitleStyle: () => null, @@ -173,6 +200,7 @@ test('createIpcDepsRuntime wires AniList handlers', async () => { tokenizeCurrentSubtitle: async () => null, getCurrentSubtitleRaw: () => '', getCurrentSubtitleAss: () => '', + getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(), getPlaybackPaused: () => true, getSubtitlePosition: () => null, getSubtitleStyle: () => null, @@ -269,6 +297,7 @@ test('registerIpcHandlers rejects malformed runtime-option payloads', async () = cycles.push({ id, direction }); return { ok: true }; }, + getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(), reportOverlayContentBounds: () => {}, getAnilistStatus: () => ({}), clearAnilistToken: () => {}, @@ -320,6 +349,24 @@ test('registerIpcHandlers rejects malformed runtime-option payloads', async () = ); }); +test('registerIpcHandlers exposes subtitle sidebar snapshot request', async () => { + const { registrar, handlers } = createFakeIpcRegistrar(); + const snapshot = createSubtitleSidebarSnapshotFixture(); + snapshot.cues = [{ startTime: 1, endTime: 2, text: 'line-1' }]; + snapshot.config.enabled = true; + + registerIpcHandlers( + createRegisterIpcDeps({ + getSubtitleSidebarSnapshot: async () => snapshot, + }), + registrar, + ); + + const handler = handlers.handle.get(IPC_CHANNELS.request.getSubtitleSidebarSnapshot); + assert.ok(handler); + assert.deepEqual(await handler!({}), snapshot); +}); + test('registerIpcHandlers forwards yomitan lookup tracking commands to immersion tracker', () => { const { registrar, handlers } = createFakeIpcRegistrar(); const calls: string[] = []; @@ -530,6 +577,7 @@ test('registerIpcHandlers ignores malformed fire-and-forget payloads', () => { tokenizeCurrentSubtitle: async () => null, getCurrentSubtitleRaw: () => '', getCurrentSubtitleAss: () => '', + getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(), getPlaybackPaused: () => false, getSubtitlePosition: () => null, getSubtitleStyle: () => null, @@ -596,6 +644,7 @@ test('registerIpcHandlers awaits saveControllerPreference through request-respon tokenizeCurrentSubtitle: async () => null, getCurrentSubtitleRaw: () => '', getCurrentSubtitleAss: () => '', + getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(), getPlaybackPaused: () => false, getSubtitlePosition: () => null, getSubtitleStyle: () => null, @@ -667,6 +716,7 @@ test('registerIpcHandlers rejects malformed controller preference payloads', asy tokenizeCurrentSubtitle: async () => null, getCurrentSubtitleRaw: () => '', getCurrentSubtitleAss: () => '', + getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(), getPlaybackPaused: () => false, getSubtitlePosition: () => null, getSubtitleStyle: () => null, diff --git a/src/core/services/ipc.ts b/src/core/services/ipc.ts index 8ca671e..a8a4612 100644 --- a/src/core/services/ipc.ts +++ b/src/core/services/ipc.ts @@ -6,6 +6,7 @@ import type { ResolvedControllerConfig, RuntimeOptionId, RuntimeOptionValue, + SubtitleSidebarSnapshot, SubtitlePosition, SubsyncManualRunRequest, SubsyncResult, @@ -37,6 +38,7 @@ export interface IpcServiceDeps { tokenizeCurrentSubtitle: () => Promise; getCurrentSubtitleRaw: () => string; getCurrentSubtitleAss: () => string; + getSubtitleSidebarSnapshot?: () => Promise; getPlaybackPaused: () => boolean | null; getSubtitlePosition: () => unknown; getSubtitleStyle: () => unknown; @@ -143,6 +145,7 @@ export interface IpcDepsRuntimeOptions { tokenizeCurrentSubtitle: () => Promise; getCurrentSubtitleRaw: () => string; getCurrentSubtitleAss: () => string; + getSubtitleSidebarSnapshot?: () => Promise; getPlaybackPaused: () => boolean | null; getSubtitlePosition: () => unknown; getSubtitleStyle: () => unknown; @@ -190,6 +193,7 @@ export function createIpcDepsRuntime(options: IpcDepsRuntimeOptions): IpcService tokenizeCurrentSubtitle: options.tokenizeCurrentSubtitle, getCurrentSubtitleRaw: options.getCurrentSubtitleRaw, getCurrentSubtitleAss: options.getCurrentSubtitleAss, + getSubtitleSidebarSnapshot: options.getSubtitleSidebarSnapshot, getPlaybackPaused: options.getPlaybackPaused, getSubtitlePosition: options.getSubtitlePosition, getSubtitleStyle: options.getSubtitleStyle, @@ -321,6 +325,13 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar return deps.getCurrentSubtitleAss(); }); + ipc.handle(IPC_CHANNELS.request.getSubtitleSidebarSnapshot, async () => { + if (!deps.getSubtitleSidebarSnapshot) { + throw new Error('Subtitle sidebar snapshot is unavailable.'); + } + return await deps.getSubtitleSidebarSnapshot(); + }); + ipc.handle(IPC_CHANNELS.request.getPlaybackPaused, () => { return deps.getPlaybackPaused(); }); diff --git a/src/core/services/subtitle-cue-parser.test.ts b/src/core/services/subtitle-cue-parser.test.ts index 6a656b7..5c59e62 100644 --- a/src/core/services/subtitle-cue-parser.test.ts +++ b/src/core/services/subtitle-cue-parser.test.ts @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import test from 'node:test'; import { parseSrtCues, parseAssCues, parseSubtitleCues } from './subtitle-cue-parser'; -import type { SubtitleCue } from './subtitle-cue-parser'; +import type { SubtitleCue } from '../../types'; test('parseSrtCues parses basic SRT content', () => { const content = [ diff --git a/src/core/services/subtitle-cue-parser.ts b/src/core/services/subtitle-cue-parser.ts index 6314cb6..760bba3 100644 --- a/src/core/services/subtitle-cue-parser.ts +++ b/src/core/services/subtitle-cue-parser.ts @@ -183,7 +183,13 @@ export function parseSubtitleCues(content: string, filename: string): SubtitleCu cues = parseAssCues(content); break; default: - return []; + cues = []; + } + + if (cues.length === 0) { + const assCues = parseAssCues(content); + const srtCues = parseSrtCues(content); + cues = assCues.length >= srtCues.length ? assCues : srtCues; } cues.sort((a, b) => a.startTime - b.startTime); diff --git a/src/core/services/subtitle-prefetch.test.ts b/src/core/services/subtitle-prefetch.test.ts index 57f7df3..d053056 100644 --- a/src/core/services/subtitle-prefetch.test.ts +++ b/src/core/services/subtitle-prefetch.test.ts @@ -1,8 +1,8 @@ import assert from 'node:assert/strict'; import test from 'node:test'; import { computePriorityWindow, createSubtitlePrefetchService } from './subtitle-prefetch'; -import type { SubtitleCue } from './subtitle-cue-parser'; import type { SubtitleData } from '../../types'; +import type { SubtitleCue } from '../../types'; function makeCues(count: number, startOffset = 0): SubtitleCue[] { return Array.from({ length: count }, (_, i) => ({ diff --git a/src/core/services/subtitle-prefetch.ts b/src/core/services/subtitle-prefetch.ts index eb0eb9a..9641b35 100644 --- a/src/core/services/subtitle-prefetch.ts +++ b/src/core/services/subtitle-prefetch.ts @@ -1,5 +1,5 @@ -import type { SubtitleCue } from './subtitle-cue-parser'; import type { SubtitleData } from '../../types'; +import type { SubtitleCue } from '../../types'; export interface SubtitlePrefetchServiceDeps { cues: SubtitleCue[]; diff --git a/src/main.ts b/src/main.ts index f2e9dff..be30496 100644 --- a/src/main.ts +++ b/src/main.ts @@ -438,10 +438,11 @@ import { parseSubtitleCues } from './core/services/subtitle-cue-parser'; import { createSubtitlePrefetchService } from './core/services/subtitle-prefetch'; import type { SubtitlePrefetchService } from './core/services/subtitle-prefetch'; import { - getActiveExternalSubtitleSource, + buildSubtitleSidebarSourceKey, resolveSubtitleSourcePath, } from './main/runtime/subtitle-prefetch-source'; import { createSubtitlePrefetchInitController } from './main/runtime/subtitle-prefetch-init'; +import { codecToExtension } from './subsync/utils'; if (process.platform === 'linux') { app.commandLine.appendSwitch('enable-features', 'GlobalShortcutsPortal'); @@ -1142,15 +1143,23 @@ function maybeSignalPluginAutoplayReady( let appTray: Tray | null = null; let tokenizeSubtitleDeferred: ((text: string) => Promise) | null = null; +function withCurrentSubtitleTiming(payload: SubtitleData): SubtitleData { + return { + ...payload, + startTime: appState.mpvClient?.currentSubStart ?? null, + endTime: appState.mpvClient?.currentSubEnd ?? null, + }; +} function emitSubtitlePayload(payload: SubtitleData): void { - appState.currentSubtitleData = payload; - broadcastToOverlayWindows('subtitle:set', payload); - subtitleWsService.broadcast(payload, { + const timedPayload = withCurrentSubtitleTiming(payload); + appState.currentSubtitleData = timedPayload; + broadcastToOverlayWindows('subtitle:set', timedPayload); + subtitleWsService.broadcast(timedPayload, { enabled: getResolvedConfig().subtitleStyle.frequencyDictionary.enabled, topX: getResolvedConfig().subtitleStyle.frequencyDictionary.topX, mode: getResolvedConfig().subtitleStyle.frequencyDictionary.mode, }); - annotationSubtitleWsService.broadcast(payload, { + annotationSubtitleWsService.broadcast(timedPayload, { enabled: getResolvedConfig().subtitleStyle.frequencyDictionary.enabled, topX: getResolvedConfig().subtitleStyle.frequencyDictionary.topX, mode: getResolvedConfig().subtitleStyle.frequencyDictionary.mode, @@ -1200,6 +1209,10 @@ const subtitlePrefetchInitController = createSubtitlePrefetchInitController({ isCacheFull: () => subtitleProcessingController.isCacheFull(), logInfo: (message) => logger.info(message), logWarn: (message) => logger.warn(message), + onParsedSubtitleCuesChanged: (cues, sourceKey) => { + appState.activeParsedSubtitleCues = cues ?? []; + appState.activeParsedSubtitleSource = sourceKey; + }, }); async function refreshSubtitlePrefetchFromActiveTrack(): Promise { @@ -1209,19 +1222,40 @@ async function refreshSubtitlePrefetchFromActiveTrack(): Promise { } try { - const [trackListRaw, sidRaw] = await Promise.all([ + const [currentExternalFilenameRaw, currentTrackRaw, trackListRaw, sidRaw, videoPathRaw] = + await Promise.all([ + client.requestProperty('current-tracks/sub/external-filename').catch(() => null), + client.requestProperty('current-tracks/sub').catch(() => null), client.requestProperty('track-list'), client.requestProperty('sid'), - ]); - const externalFilename = getActiveExternalSubtitleSource(trackListRaw, sidRaw); - if (!externalFilename) { + client.requestProperty('path'), + ]); + const videoPath = typeof videoPathRaw === 'string' ? videoPathRaw : ''; + if (!videoPath) { subtitlePrefetchInitController.cancelPendingInit(); return; } - await subtitlePrefetchInitController.initSubtitlePrefetch( - externalFilename, - lastObservedTimePos, + + const resolvedSource = await resolveActiveSubtitleSidebarSource( + currentExternalFilenameRaw, + currentTrackRaw, + trackListRaw, + sidRaw, + videoPath, ); + if (!resolvedSource) { + subtitlePrefetchInitController.cancelPendingInit(); + return; + } + try { + await subtitlePrefetchInitController.initSubtitlePrefetch( + resolvedSource.path, + lastObservedTimePos, + resolvedSource.sourceKey, + ); + } finally { + await resolvedSource.cleanup?.(); + } } catch { // Track list query failed; skip subtitle prefetch refresh. } @@ -2965,6 +2999,8 @@ const { appReadyRuntimeRunner } = composeAppReadyRuntime({ ? { text: appState.currentSubText, tokens: null, + startTime: appState.mpvClient?.currentSubStart ?? null, + endTime: appState.mpvClient?.currentSubEnd ?? null, } : null), () => ({ @@ -2983,6 +3019,8 @@ const { appReadyRuntimeRunner } = composeAppReadyRuntime({ ? { text: appState.currentSubText, tokens: null, + startTime: appState.mpvClient?.currentSubStart ?? null, + endTime: appState.mpvClient?.currentSubEnd ?? null, } : null), () => ({ @@ -3257,6 +3295,9 @@ const { restoreMpvSubVisibility: () => { restoreOverlayMpvSubtitles(); }, + resetSubtitleSidebarEmbeddedLayout: () => { + resetSubtitleSidebarEmbeddedLayoutRuntime(); + }, getCurrentAnilistMediaKey: () => getCurrentAnilistMediaKey(), resetAnilistMediaTracking: (mediaKey) => { resetAnilistMediaTracking(mediaKey); @@ -3475,6 +3516,11 @@ function createMpvClientRuntimeService(): MpvIpcClient { return createMpvClientRuntimeServiceHandler() as MpvIpcClient; } +function resetSubtitleSidebarEmbeddedLayoutRuntime(): void { + sendMpvCommandRuntime(appState.mpvClient, ['set_property', 'video-margin-ratio-right', 0]); + sendMpvCommandRuntime(appState.mpvClient, ['set_property', 'video-pan-x', 0]); +} + function updateMpvSubtitleRenderMetrics(patch: Partial): void { updateMpvSubtitleRenderMetricsHandler(patch); } @@ -3919,6 +3965,176 @@ async function loadSubtitleSourceText(source: string): Promise { return fs.promises.readFile(filePath, 'utf8'); } +type MpvSubtitleTrackLike = { + type?: unknown; + id?: unknown; + selected?: unknown; + external?: unknown; + codec?: unknown; + 'ff-index'?: unknown; + 'external-filename'?: unknown; +}; + +function parseTrackId(value: unknown): number | null { + if (typeof value === 'number' && Number.isInteger(value)) { + return value; + } + if (typeof value === 'string') { + const parsed = Number(value.trim()); + return Number.isInteger(parsed) ? parsed : null; + } + return null; +} + +function getActiveSubtitleTrack( + currentTrackRaw: unknown, + trackListRaw: unknown, + sidRaw: unknown, +): MpvSubtitleTrackLike | null { + if (currentTrackRaw && typeof currentTrackRaw === 'object') { + const track = currentTrackRaw as MpvSubtitleTrackLike; + if (track.type === undefined || track.type === 'sub') { + return track; + } + } + + const sid = parseTrackId(sidRaw); + if (!Array.isArray(trackListRaw)) { + return null; + } + + const bySid = + sid === null + ? null + : ((trackListRaw.find((entry: unknown) => { + if (!entry || typeof entry !== 'object') { + return false; + } + const track = entry as MpvSubtitleTrackLike; + return track.type === 'sub' && parseTrackId(track.id) === sid; + }) as MpvSubtitleTrackLike | undefined) ?? null); + if (bySid) { + return bySid; + } + + return ( + (trackListRaw.find((entry: unknown) => { + if (!entry || typeof entry !== 'object') { + return false; + } + const track = entry as MpvSubtitleTrackLike; + return track.type === 'sub' && track.selected === true; + }) as MpvSubtitleTrackLike | undefined) ?? null + ); +} + +function buildFfmpegSubtitleExtractionArgs( + videoPath: string, + ffIndex: number, + outputPath: string, +): string[] { + return [ + '-hide_banner', + '-nostdin', + '-y', + '-loglevel', + 'error', + '-an', + '-vn', + '-i', + videoPath, + '-map', + `0:${ffIndex}`, + '-f', + path.extname(outputPath).slice(1), + outputPath, + ]; +} + +async function extractInternalSubtitleTrackToTempFile( + ffmpegPath: string, + videoPath: string, + track: MpvSubtitleTrackLike, +): Promise<{ path: string; cleanup: () => Promise } | null> { + const ffIndex = parseTrackId(track['ff-index']); + const codec = typeof track.codec === 'string' ? track.codec : null; + const extension = codecToExtension(codec ?? undefined); + if (ffIndex === null || extension === null) { + return null; + } + + const tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'subminer-sidebar-')); + const outputPath = path.join(tempDir, `track_${ffIndex}.${extension}`); + + try { + await new Promise((resolve, reject) => { + const child = spawn( + ffmpegPath, + buildFfmpegSubtitleExtractionArgs(videoPath, ffIndex, outputPath), + ); + let stderr = ''; + child.stderr.on('data', (chunk: Buffer) => { + stderr += chunk.toString(); + }); + child.on('error', (error) => { + reject(error); + }); + child.on('close', (code) => { + if (code === 0) { + resolve(); + return; + } + reject(new Error(stderr.trim() || `ffmpeg exited with code ${code ?? 'unknown'}`)); + }); + }); + } catch (error) { + await fs.promises.rm(tempDir, { recursive: true, force: true }).catch(() => undefined); + throw error; + } + + return { + path: outputPath, + cleanup: async () => { + await fs.promises.rm(tempDir, { recursive: true, force: true }); + }, + }; +} + +async function resolveActiveSubtitleSidebarSource( + currentExternalFilenameRaw: unknown, + currentTrackRaw: unknown, + trackListRaw: unknown, + sidRaw: unknown, + videoPath: string, +): Promise<{ path: string; sourceKey: string; cleanup?: () => Promise } | null> { + const currentExternalFilename = + typeof currentExternalFilenameRaw === 'string' ? currentExternalFilenameRaw.trim() : ''; + if (currentExternalFilename) { + return { path: currentExternalFilename, sourceKey: currentExternalFilename }; + } + + const track = getActiveSubtitleTrack(currentTrackRaw, trackListRaw, sidRaw); + if (!track) { + return null; + } + + const externalFilename = + typeof track['external-filename'] === 'string' ? track['external-filename'].trim() : ''; + if (externalFilename) { + return { path: externalFilename, sourceKey: externalFilename }; + } + + const ffmpegPath = getResolvedConfig().subsync.ffmpeg_path.trim() || 'ffmpeg'; + const extracted = await extractInternalSubtitleTrackToTempFile(ffmpegPath, videoPath, track); + if (!extracted) { + return null; + } + return { + ...extracted, + sourceKey: buildSubtitleSidebarSourceKey(videoPath, track, extracted.path), + }; +} + const shiftSubtitleDelayToAdjacentCueHandler = createShiftSubtitleDelayToAdjacentCueHandler({ getMpvClient: () => appState.mpvClient, loadSubtitleSourceText, @@ -3976,9 +4192,99 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({ openYomitanSettings: () => openYomitanSettings(), quitApp: () => requestAppQuit(), toggleVisibleOverlay: () => toggleVisibleOverlay(), - tokenizeCurrentSubtitle: () => tokenizeSubtitle(appState.currentSubText), + tokenizeCurrentSubtitle: async () => withCurrentSubtitleTiming(await tokenizeSubtitle(appState.currentSubText)), getCurrentSubtitleRaw: () => appState.currentSubText, getCurrentSubtitleAss: () => appState.currentSubAssText, + getSubtitleSidebarSnapshot: async () => { + const currentSubtitle = { + text: appState.currentSubText, + startTime: appState.mpvClient?.currentSubStart ?? null, + endTime: appState.mpvClient?.currentSubEnd ?? null, + }; + const currentTimeSec = appState.mpvClient?.currentTimePos ?? null; + const config = getResolvedConfig().subtitleSidebar; + const client = appState.mpvClient; + if (!client?.connected) { + return { + cues: appState.activeParsedSubtitleCues, + currentTimeSec, + currentSubtitle, + config, + }; + } + + try { + const [ + currentExternalFilenameRaw, + currentTrackRaw, + trackListRaw, + sidRaw, + videoPathRaw, + ] = await Promise.all([ + client.requestProperty('current-tracks/sub/external-filename').catch(() => null), + client.requestProperty('current-tracks/sub').catch(() => null), + client.requestProperty('track-list'), + client.requestProperty('sid'), + client.requestProperty('path'), + ]); + const videoPath = typeof videoPathRaw === 'string' ? videoPathRaw : ''; + if (!videoPath) { + return { + cues: appState.activeParsedSubtitleCues, + currentTimeSec, + currentSubtitle, + config, + }; + } + + const resolvedSource = await resolveActiveSubtitleSidebarSource( + currentExternalFilenameRaw, + currentTrackRaw, + trackListRaw, + sidRaw, + videoPath, + ); + if (!resolvedSource) { + return { + cues: appState.activeParsedSubtitleCues, + currentTimeSec, + currentSubtitle, + config, + }; + } + + if (appState.activeParsedSubtitleSource === resolvedSource.sourceKey) { + return { + cues: appState.activeParsedSubtitleCues, + currentTimeSec, + currentSubtitle, + config, + }; + } + + try { + const content = await loadSubtitleSourceText(resolvedSource.path); + const cues = parseSubtitleCues(content, resolvedSource.path); + appState.activeParsedSubtitleCues = cues; + appState.activeParsedSubtitleSource = resolvedSource.sourceKey; + return { + cues, + currentTimeSec, + currentSubtitle, + config, + }; + } finally { + await resolvedSource.cleanup?.(); + } + } catch { + return { + cues: appState.activeParsedSubtitleCues, + currentTimeSec, + currentSubtitle, + config, + }; + } + }, getPlaybackPaused: () => appState.playbackPaused, getSubtitlePosition: () => loadSubtitlePosition(), getSubtitleStyle: () => { diff --git a/src/main/dependencies.ts b/src/main/dependencies.ts index 1ae07d0..debb8b9 100644 --- a/src/main/dependencies.ts +++ b/src/main/dependencies.ts @@ -63,6 +63,7 @@ export interface MainIpcRuntimeServiceDepsParams { tokenizeCurrentSubtitle: IpcDepsRuntimeOptions['tokenizeCurrentSubtitle']; getCurrentSubtitleRaw: IpcDepsRuntimeOptions['getCurrentSubtitleRaw']; getCurrentSubtitleAss: IpcDepsRuntimeOptions['getCurrentSubtitleAss']; + getSubtitleSidebarSnapshot?: IpcDepsRuntimeOptions['getSubtitleSidebarSnapshot']; getPlaybackPaused: IpcDepsRuntimeOptions['getPlaybackPaused']; focusMainWindow?: IpcDepsRuntimeOptions['focusMainWindow']; getSubtitlePosition: IpcDepsRuntimeOptions['getSubtitlePosition']; @@ -212,6 +213,7 @@ export function createMainIpcRuntimeServiceDeps( tokenizeCurrentSubtitle: params.tokenizeCurrentSubtitle, getCurrentSubtitleRaw: params.getCurrentSubtitleRaw, getCurrentSubtitleAss: params.getCurrentSubtitleAss, + getSubtitleSidebarSnapshot: params.getSubtitleSidebarSnapshot, getPlaybackPaused: params.getPlaybackPaused, getSubtitlePosition: params.getSubtitlePosition, getSubtitleStyle: params.getSubtitleStyle, diff --git a/src/main/runtime/config-hot-reload-handlers.ts b/src/main/runtime/config-hot-reload-handlers.ts index 602be3c..cf4f9c6 100644 --- a/src/main/runtime/config-hot-reload-handlers.ts +++ b/src/main/runtime/config-hot-reload-handlers.ts @@ -36,6 +36,7 @@ export function buildConfigHotReloadPayload(config: ResolvedConfig): ConfigHotRe return { keybindings: resolveKeybindings(config, DEFAULT_KEYBINDINGS), subtitleStyle: resolveSubtitleStyleForRenderer(config), + subtitleSidebar: config.subtitleSidebar, secondarySubMode: config.secondarySub.defaultMode, }; } diff --git a/src/main/runtime/mpv-main-event-actions.test.ts b/src/main/runtime/mpv-main-event-actions.test.ts index eb0b4a7..dd32261 100644 --- a/src/main/runtime/mpv-main-event-actions.test.ts +++ b/src/main/runtime/mpv-main-event-actions.test.ts @@ -82,6 +82,7 @@ test('media path change handler reports stop for empty path and probes media key updateCurrentMediaPath: (path) => calls.push(`path:${path}`), reportJellyfinRemoteStopped: () => calls.push('stopped'), restoreMpvSubVisibility: () => calls.push('restore-mpv-sub'), + resetSubtitleSidebarEmbeddedLayout: () => calls.push('reset-sidebar-layout'), getCurrentAnilistMediaKey: () => 'show:1', resetAnilistMediaTracking: (mediaKey) => calls.push(`reset:${String(mediaKey)}`), maybeProbeAnilistDuration: (mediaKey) => calls.push(`probe:${mediaKey}`), @@ -97,6 +98,7 @@ test('media path change handler reports stop for empty path and probes media key assert.deepEqual(calls, [ 'flush-playback', 'path:', + 'reset-sidebar-layout', 'stopped', 'restore-mpv-sub', 'reset:show:1', @@ -113,6 +115,7 @@ test('media path change handler signals autoplay-ready fast path for warm non-em updateCurrentMediaPath: (path) => calls.push(`path:${path}`), reportJellyfinRemoteStopped: () => calls.push('stopped'), restoreMpvSubVisibility: () => calls.push('restore-mpv-sub'), + resetSubtitleSidebarEmbeddedLayout: () => calls.push('reset-sidebar-layout'), getCurrentAnilistMediaKey: () => null, resetAnilistMediaTracking: (mediaKey) => calls.push(`reset:${String(mediaKey)}`), maybeProbeAnilistDuration: (mediaKey) => calls.push(`probe:${mediaKey}`), @@ -128,35 +131,7 @@ test('media path change handler signals autoplay-ready fast path for warm non-em assert.deepEqual(calls, [ 'path:/tmp/video.mkv', - 'reset:null', - 'sync', - 'dict-sync', - 'autoplay:/tmp/video.mkv', - 'presence', - ]); -}); - -test('media path change handler ignores playback flush for non-empty path', () => { - const calls: string[] = []; - const handler = createHandleMpvMediaPathChangeHandler({ - updateCurrentMediaPath: (path) => calls.push(`path:${path}`), - reportJellyfinRemoteStopped: () => calls.push('stopped'), - restoreMpvSubVisibility: () => calls.push('restore-mpv-sub'), - getCurrentAnilistMediaKey: () => null, - resetAnilistMediaTracking: (mediaKey) => calls.push(`reset:${String(mediaKey)}`), - maybeProbeAnilistDuration: (mediaKey) => calls.push(`probe:${mediaKey}`), - ensureAnilistMediaGuess: (mediaKey) => calls.push(`guess:${mediaKey}`), - syncImmersionMediaState: () => calls.push('sync'), - flushPlaybackPositionOnMediaPathClear: () => calls.push('flush-playback'), - scheduleCharacterDictionarySync: () => calls.push('dict-sync'), - signalAutoplayReadyIfWarm: (path) => calls.push(`autoplay:${path}`), - refreshDiscordPresence: () => calls.push('presence'), - }); - - handler({ path: '/tmp/video.mkv' }); - assert.ok(!calls.includes('flush-playback')); - assert.deepEqual(calls, [ - 'path:/tmp/video.mkv', + 'reset-sidebar-layout', 'reset:null', 'sync', 'dict-sync', diff --git a/src/main/runtime/mpv-main-event-actions.ts b/src/main/runtime/mpv-main-event-actions.ts index 77f9daa..2fd43ea 100644 --- a/src/main/runtime/mpv-main-event-actions.ts +++ b/src/main/runtime/mpv-main-event-actions.ts @@ -46,6 +46,7 @@ export function createHandleMpvMediaPathChangeHandler(deps: { updateCurrentMediaPath: (path: string) => void; reportJellyfinRemoteStopped: () => void; restoreMpvSubVisibility: () => void; + resetSubtitleSidebarEmbeddedLayout: () => void; getCurrentAnilistMediaKey: () => string | null; resetAnilistMediaTracking: (mediaKey: string | null) => void; maybeProbeAnilistDuration: (mediaKey: string) => void; @@ -62,6 +63,7 @@ export function createHandleMpvMediaPathChangeHandler(deps: { deps.flushPlaybackPositionOnMediaPathClear?.(normalizedPath); } deps.updateCurrentMediaPath(normalizedPath); + deps.resetSubtitleSidebarEmbeddedLayout(); if (!normalizedPath) { deps.reportJellyfinRemoteStopped(); deps.restoreMpvSubVisibility(); diff --git a/src/main/runtime/mpv-main-event-bindings.test.ts b/src/main/runtime/mpv-main-event-bindings.test.ts index fd4c9f5..a3910e9 100644 --- a/src/main/runtime/mpv-main-event-bindings.test.ts +++ b/src/main/runtime/mpv-main-event-bindings.test.ts @@ -9,6 +9,7 @@ test('main mpv event binder wires callbacks through to runtime deps', () => { const bind = createBindMpvMainEventHandlersHandler({ reportJellyfinRemoteStopped: () => calls.push('remote-stopped'), syncOverlayMpvSubtitleSuppression: () => calls.push('sync-overlay-mpv-sub'), + resetSubtitleSidebarEmbeddedLayout: () => calls.push('reset-sidebar-layout'), hasInitialJellyfinPlayArg: () => false, isOverlayRuntimeInitialized: () => false, isQuitOnDisconnectArmed: () => false, @@ -67,6 +68,7 @@ test('main mpv event binder wires callbacks through to runtime deps', () => { }, }); + handlers.get('connection-change')?.({ connected: true }); handlers.get('subtitle-change')?.({ text: 'line' }); handlers.get('subtitle-track-change')?.({ sid: 3 }); handlers.get('subtitle-track-list-change')?.({ trackList: [] }); @@ -76,6 +78,7 @@ test('main mpv event binder wires callbacks through to runtime deps', () => { handlers.get('pause-change')?.({ paused: true }); assert.ok(calls.includes('set-sub:line')); + assert.ok(calls.includes('reset-sidebar-layout')); assert.ok(calls.includes('broadcast-sub:line')); assert.ok(calls.includes('subtitle-change:line')); assert.ok(calls.includes('subtitle-track-change')); diff --git a/src/main/runtime/mpv-main-event-bindings.ts b/src/main/runtime/mpv-main-event-bindings.ts index 14266c6..7890818 100644 --- a/src/main/runtime/mpv-main-event-bindings.ts +++ b/src/main/runtime/mpv-main-event-bindings.ts @@ -21,6 +21,7 @@ type MpvEventClient = Parameters void; syncOverlayMpvSubtitleSuppression: () => void; + resetSubtitleSidebarEmbeddedLayout: () => void; scheduleCharacterDictionarySync?: () => void; hasInitialJellyfinPlayArg: () => boolean; isOverlayRuntimeInitialized: () => boolean; @@ -83,6 +84,12 @@ export function createBindMpvMainEventHandlersHandler(deps: { isMpvConnected: () => deps.isMpvConnected(), quitApp: () => deps.quitApp(), }); + const handleMpvConnectionChangeWithSidebarReset = ({ connected }: { connected: boolean }): void => { + if (connected) { + deps.resetSubtitleSidebarEmbeddedLayout(); + } + handleMpvConnectionChange({ connected }); + }; const handleMpvSubtitleTiming = createHandleMpvSubtitleTimingHandler({ recordImmersionSubtitleLine: (text, start, end) => deps.recordImmersionSubtitleLine(text, start, end), @@ -110,6 +117,7 @@ export function createBindMpvMainEventHandlersHandler(deps: { updateCurrentMediaPath: (path) => deps.updateCurrentMediaPath(path), reportJellyfinRemoteStopped: () => deps.reportJellyfinRemoteStopped(), restoreMpvSubVisibility: () => deps.restoreMpvSubVisibility(), + resetSubtitleSidebarEmbeddedLayout: () => deps.resetSubtitleSidebarEmbeddedLayout(), getCurrentAnilistMediaKey: () => deps.getCurrentAnilistMediaKey(), resetAnilistMediaTracking: (mediaKey) => deps.resetAnilistMediaTracking(mediaKey), maybeProbeAnilistDuration: (mediaKey) => deps.maybeProbeAnilistDuration(mediaKey), @@ -150,7 +158,7 @@ export function createBindMpvMainEventHandlersHandler(deps: { }); createBindMpvClientEventHandlers({ - onConnectionChange: handleMpvConnectionChange, + onConnectionChange: handleMpvConnectionChangeWithSidebarReset, onSubtitleChange: handleMpvSubtitleChange, onSubtitleAssChange: handleMpvSubtitleAssChange, onSecondarySubtitleChange: handleMpvSecondarySubtitleChange, diff --git a/src/main/runtime/mpv-main-event-main-deps.test.ts b/src/main/runtime/mpv-main-event-main-deps.test.ts index 5b8b77d..705d398 100644 --- a/src/main/runtime/mpv-main-event-main-deps.test.ts +++ b/src/main/runtime/mpv-main-event-main-deps.test.ts @@ -47,6 +47,7 @@ test('mpv main event main deps map app state updates and delegate callbacks', as ensureImmersionTrackerInitialized: () => calls.push('ensure-immersion'), updateCurrentMediaPath: (path) => calls.push(`path:${path}`), restoreMpvSubVisibility: () => calls.push('restore-mpv-sub'), + resetSubtitleSidebarEmbeddedLayout: () => calls.push('reset-sidebar-layout'), getCurrentAnilistMediaKey: () => 'media-key', resetAnilistMediaTracking: (mediaKey) => calls.push(`reset:${mediaKey}`), maybeProbeAnilistDuration: (mediaKey) => calls.push(`probe:${mediaKey}`), @@ -82,6 +83,7 @@ test('mpv main event main deps map app state updates and delegate callbacks', as deps.broadcastSecondarySubtitle('sec'); deps.updateCurrentMediaPath('/tmp/video'); deps.restoreMpvSubVisibility(); + deps.resetSubtitleSidebarEmbeddedLayout(); assert.equal(deps.getCurrentAnilistMediaKey(), 'media-key'); deps.resetAnilistMediaTracking('media-key'); deps.maybeProbeAnilistDuration('media-key'); @@ -112,6 +114,5 @@ test('mpv main event main deps map app state updates and delegate callbacks', as assert.ok(calls.includes('metrics')); assert.ok(calls.includes('presence-refresh')); assert.ok(calls.includes('restore-mpv-sub')); - assert.ok(calls.includes('immersion-time:12.25')); - assert.ok(calls.includes('immersion-time:18.75')); + assert.ok(calls.includes('reset-sidebar-layout')); }); diff --git a/src/main/runtime/mpv-main-event-main-deps.ts b/src/main/runtime/mpv-main-event-main-deps.ts index 5d4ac65..2523861 100644 --- a/src/main/runtime/mpv-main-event-main-deps.ts +++ b/src/main/runtime/mpv-main-event-main-deps.ts @@ -50,6 +50,7 @@ export function createBuildBindMpvMainEventHandlersMainDepsHandler(deps: { onSubtitleTrackListChange?: (trackList: unknown[] | null) => void; updateCurrentMediaPath: (path: string) => void; restoreMpvSubVisibility: () => void; + resetSubtitleSidebarEmbeddedLayout?: () => void; getCurrentAnilistMediaKey: () => string | null; resetAnilistMediaTracking: (mediaKey: string | null) => void; maybeProbeAnilistDuration: (mediaKey: string) => void; @@ -146,6 +147,7 @@ export function createBuildBindMpvMainEventHandlersMainDepsHandler(deps: { deps.broadcastToOverlayWindows('secondary-subtitle:set', text), updateCurrentMediaPath: (path: string) => deps.updateCurrentMediaPath(path), restoreMpvSubVisibility: () => deps.restoreMpvSubVisibility(), + resetSubtitleSidebarEmbeddedLayout: () => deps.resetSubtitleSidebarEmbeddedLayout?.(), getCurrentAnilistMediaKey: () => deps.getCurrentAnilistMediaKey(), resetAnilistMediaTracking: (mediaKey: string | null) => deps.resetAnilistMediaTracking(mediaKey), diff --git a/src/main/runtime/subtitle-prefetch-init.test.ts b/src/main/runtime/subtitle-prefetch-init.test.ts index e076d1c..162e85e 100644 --- a/src/main/runtime/subtitle-prefetch-init.test.ts +++ b/src/main/runtime/subtitle-prefetch-init.test.ts @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import type { SubtitleCue } from '../../core/services/subtitle-cue-parser'; import type { SubtitlePrefetchService } from '../../core/services/subtitle-prefetch'; +import type { SubtitleCue } from '../../types'; import { createSubtitlePrefetchInitController } from './subtitle-prefetch-init'; function createDeferred(): { @@ -112,3 +112,125 @@ test('cancelPendingInit prevents an in-flight load from attaching a stale servic assert.equal(currentService, null); assert.deepEqual(started, []); }); + +test('subtitle prefetch init publishes parsed cues and clears them on cancel', async () => { + const deferred = createDeferred(); + let currentService: SubtitlePrefetchService | null = null; + const cueUpdates: Array = []; + + const controller = createSubtitlePrefetchInitController({ + getCurrentService: () => currentService, + setCurrentService: (service) => { + currentService = service; + }, + loadSubtitleSourceText: async () => await deferred.promise, + parseSubtitleCues: () => [ + { startTime: 1, endTime: 2, text: 'first' }, + { startTime: 3, endTime: 4, text: 'second' }, + ], + createSubtitlePrefetchService: () => ({ + start: () => {}, + stop: () => {}, + onSeek: () => {}, + pause: () => {}, + resume: () => {}, + }), + tokenizeSubtitle: async () => null, + preCacheTokenization: () => {}, + isCacheFull: () => false, + logInfo: () => {}, + logWarn: () => {}, + onParsedSubtitleCuesChanged: (cues) => { + cueUpdates.push(cues); + }, + }); + + const initPromise = controller.initSubtitlePrefetch('episode.ass', 12); + deferred.resolve('content'); + await initPromise; + + controller.cancelPendingInit(); + + assert.deepEqual(cueUpdates, [ + [ + { startTime: 1, endTime: 2, text: 'first' }, + { startTime: 3, endTime: 4, text: 'second' }, + ], + null, + ]); +}); + +test('subtitle prefetch init publishes the provided stable source key instead of the load path', async () => { + const deferred = createDeferred(); + let currentService: SubtitlePrefetchService | null = null; + const sourceUpdates: Array = []; + + const controller = createSubtitlePrefetchInitController({ + getCurrentService: () => currentService, + setCurrentService: (service) => { + currentService = service; + }, + loadSubtitleSourceText: async () => await deferred.promise, + parseSubtitleCues: () => [{ startTime: 1, endTime: 2, text: 'first' }], + createSubtitlePrefetchService: () => ({ + start: () => {}, + stop: () => {}, + onSeek: () => {}, + pause: () => {}, + resume: () => {}, + }), + tokenizeSubtitle: async () => null, + preCacheTokenization: () => {}, + isCacheFull: () => false, + logInfo: () => {}, + logWarn: () => {}, + onParsedSubtitleCuesChanged: (_cues, source) => { + sourceUpdates.push(source); + }, + }); + + const initPromise = controller.initSubtitlePrefetch( + '/tmp/subminer-sidebar-123/track_7.ass', + 12, + 'internal:/media/episode01.mkv:track:3:ff:7', + ); + deferred.resolve('content'); + await initPromise; + + assert.deepEqual(sourceUpdates, ['internal:/media/episode01.mkv:track:3:ff:7']); +}); + +test('subtitle prefetch init clears parsed cues when initialization fails', async () => { + const cueUpdates: Array = []; + let currentService: SubtitlePrefetchService | null = null; + + const controller = createSubtitlePrefetchInitController({ + getCurrentService: () => currentService, + setCurrentService: (service) => { + currentService = service; + }, + loadSubtitleSourceText: async () => { + throw new Error('boom'); + }, + parseSubtitleCues: () => [{ startTime: 1, endTime: 2, text: 'first' }], + createSubtitlePrefetchService: () => ({ + start: () => {}, + stop: () => {}, + onSeek: () => {}, + pause: () => {}, + resume: () => {}, + }), + tokenizeSubtitle: async () => null, + preCacheTokenization: () => {}, + isCacheFull: () => false, + logInfo: () => {}, + logWarn: () => {}, + onParsedSubtitleCuesChanged: (cues) => { + cueUpdates.push(cues); + }, + }); + + await controller.initSubtitlePrefetch('episode.ass', 12); + + assert.deepEqual(cueUpdates, [null]); +}); diff --git a/src/main/runtime/subtitle-prefetch-init.ts b/src/main/runtime/subtitle-prefetch-init.ts index 5d11b30..42b717e 100644 --- a/src/main/runtime/subtitle-prefetch-init.ts +++ b/src/main/runtime/subtitle-prefetch-init.ts @@ -1,9 +1,9 @@ -import type { SubtitleCue } from '../../core/services/subtitle-cue-parser'; import type { SubtitlePrefetchService, SubtitlePrefetchServiceDeps, } from '../../core/services/subtitle-prefetch'; import type { SubtitleData } from '../../types'; +import type { SubtitleCue } from '../../types'; export interface SubtitlePrefetchInitControllerDeps { getCurrentService: () => SubtitlePrefetchService | null; @@ -16,11 +16,16 @@ export interface SubtitlePrefetchInitControllerDeps { isCacheFull: () => boolean; logInfo: (message: string) => void; logWarn: (message: string) => void; + onParsedSubtitleCuesChanged?: (cues: SubtitleCue[] | null, sourceKey: string | null) => void; } export interface SubtitlePrefetchInitController { cancelPendingInit: () => void; - initSubtitlePrefetch: (externalFilename: string, currentTimePos: number) => Promise; + initSubtitlePrefetch: ( + sourcePath: string, + currentTimePos: number, + sourceKey?: string, + ) => Promise; } export function createSubtitlePrefetchInitController( @@ -32,24 +37,29 @@ export function createSubtitlePrefetchInitController( initRevision += 1; deps.getCurrentService()?.stop(); deps.setCurrentService(null); + deps.onParsedSubtitleCuesChanged?.(null, null); }; const initSubtitlePrefetch = async ( - externalFilename: string, + sourcePath: string, currentTimePos: number, + sourceKey = sourcePath, ): Promise => { const revision = ++initRevision; deps.getCurrentService()?.stop(); deps.setCurrentService(null); try { - const content = await deps.loadSubtitleSourceText(externalFilename); + const content = await deps.loadSubtitleSourceText(sourcePath); if (revision !== initRevision) { return; } - const cues = deps.parseSubtitleCues(content, externalFilename); + const cues = deps.parseSubtitleCues(content, sourcePath); if (revision !== initRevision || cues.length === 0) { + if (revision === initRevision) { + deps.onParsedSubtitleCuesChanged?.(null, null); + } return; } @@ -65,12 +75,14 @@ export function createSubtitlePrefetchInitController( } deps.setCurrentService(nextService); + deps.onParsedSubtitleCuesChanged?.(cues, sourceKey); nextService.start(currentTimePos); deps.logInfo( - `[subtitle-prefetch] started prefetching ${cues.length} cues from ${externalFilename}`, + `[subtitle-prefetch] started prefetching ${cues.length} cues from ${sourcePath}`, ); } catch (error) { if (revision === initRevision) { + deps.onParsedSubtitleCuesChanged?.(null, null); deps.logWarn(`[subtitle-prefetch] failed to initialize: ${(error as Error).message}`); } } diff --git a/src/main/runtime/subtitle-prefetch-source.test.ts b/src/main/runtime/subtitle-prefetch-source.test.ts index e031437..6bb8183 100644 --- a/src/main/runtime/subtitle-prefetch-source.test.ts +++ b/src/main/runtime/subtitle-prefetch-source.test.ts @@ -1,6 +1,7 @@ import assert from 'node:assert/strict'; import test from 'node:test'; import { + buildSubtitleSidebarSourceKey, getActiveExternalSubtitleSource, resolveSubtitleSourcePath, } from './subtitle-prefetch-source'; @@ -17,6 +18,15 @@ test('getActiveExternalSubtitleSource returns the active external subtitle path' assert.equal(source, 'https://host/subs.ass'); }); +test('getActiveExternalSubtitleSource normalizes integer-like string track ids', () => { + const source = getActiveExternalSubtitleSource( + [{ type: 'sub', id: '2', external: true, 'external-filename': ' /tmp/subs.ass ' }], + '2', + ); + + assert.equal(source, '/tmp/subs.ass'); +}); + test('getActiveExternalSubtitleSource returns null when the selected track is not external', () => { const source = getActiveExternalSubtitleSource( [{ type: 'sub', id: 2, external: false, 'external-filename': '/tmp/subs.ass' }], @@ -48,3 +58,38 @@ test('resolveSubtitleSourcePath returns the original source for malformed file U assert.equal(resolveSubtitleSourcePath(source), source); }); + +test('buildSubtitleSidebarSourceKey uses a stable identifier for internal subtitle tracks', () => { + const firstKey = buildSubtitleSidebarSourceKey('/media/episode01.mkv', { + id: 3, + 'ff-index': 7, + title: 'English', + lang: 'eng', + codec: 'ass', + }); + const secondKey = buildSubtitleSidebarSourceKey('/media/episode01.mkv', { + id: 3, + 'ff-index': 7, + title: 'English', + lang: 'eng', + codec: 'ass', + }); + + assert.equal(firstKey, secondKey); + assert.equal(firstKey, 'internal:/media/episode01.mkv:track:3:ff:7'); +}); + +test('buildSubtitleSidebarSourceKey normalizes integer-like string track metadata', () => { + const key = buildSubtitleSidebarSourceKey('/media/episode01.mkv', { + id: '3', + 'ff-index': '7', + }); + + assert.equal(key, 'internal:/media/episode01.mkv:track:3:ff:7'); +}); + +test('buildSubtitleSidebarSourceKey falls back to source path when no track metadata is available', () => { + const key = buildSubtitleSidebarSourceKey('/media/episode01.mkv', null, '/tmp/subtitle.ass'); + + assert.equal(key, '/tmp/subtitle.ass'); +}); diff --git a/src/main/runtime/subtitle-prefetch-source.ts b/src/main/runtime/subtitle-prefetch-source.ts index b740ff6..688ad71 100644 --- a/src/main/runtime/subtitle-prefetch-source.ts +++ b/src/main/runtime/subtitle-prefetch-source.ts @@ -1,5 +1,16 @@ import { fileURLToPath } from 'node:url'; +function parseTrackId(value: unknown): number | null { + if (typeof value === 'number' && Number.isInteger(value)) { + return value; + } + if (typeof value === 'string') { + const parsed = Number(value.trim()); + return Number.isInteger(parsed) ? parsed : null; + } + return null; +} + export function getActiveExternalSubtitleSource( trackListRaw: unknown, sidRaw: unknown, @@ -8,9 +19,8 @@ export function getActiveExternalSubtitleSource( return null; } - const sid = - typeof sidRaw === 'number' ? sidRaw : typeof sidRaw === 'string' ? Number(sidRaw) : null; - if (sid == null || !Number.isFinite(sid)) { + const sid = parseTrackId(sidRaw); + if (sid === null) { return null; } @@ -19,7 +29,7 @@ export function getActiveExternalSubtitleSource( return false; } const track = entry as Record; - return track.type === 'sub' && track.id === sid && track.external === true; + return track.type === 'sub' && parseTrackId(track.id) === sid && track.external === true; }) as Record | undefined; const externalFilename = @@ -40,3 +50,21 @@ export function resolveSubtitleSourcePath(source: string): string { return source; } } + +export function buildSubtitleSidebarSourceKey( + videoPath: string, + track: unknown, + fallbackSourcePath?: string, +): string { + const normalizedVideoPath = videoPath.trim(); + if (track && typeof track === 'object' && normalizedVideoPath) { + const subtitleTrack = track as Record; + const trackId = parseTrackId(subtitleTrack.id); + const ffIndex = parseTrackId(subtitleTrack['ff-index']); + if (trackId !== null || ffIndex !== null) { + return `internal:${normalizedVideoPath}:track:${trackId ?? 'unknown'}:ff:${ffIndex ?? 'unknown'}`; + } + } + + return fallbackSourcePath ?? normalizedVideoPath; +} diff --git a/src/main/state.ts b/src/main/state.ts index d8c9081..16372dd 100644 --- a/src/main/state.ts +++ b/src/main/state.ts @@ -9,6 +9,7 @@ import type { KikuFieldGroupingChoice, JlptLevel, FrequencyDictionaryLookup, + SubtitleCue, } from '../types'; import type { CliArgs } from '../cli/args'; import type { SubtitleTimingTracker } from '../subtitle-timing-tracker'; @@ -158,6 +159,8 @@ export interface AppState { currentSubText: string; currentSubAssText: string; currentSubtitleData: SubtitleData | null; + activeParsedSubtitleCues: SubtitleCue[]; + activeParsedSubtitleSource: string | null; windowTracker: BaseWindowTracker | null; subtitlePosition: SubtitlePosition | null; currentMediaPath: string | null; @@ -238,6 +241,8 @@ export function createAppState(values: AppStateInitialValues): AppState { currentSubText: '', currentSubAssText: '', currentSubtitleData: null, + activeParsedSubtitleCues: [], + activeParsedSubtitleSource: null, windowTracker: null, subtitlePosition: null, currentMediaPath: null, diff --git a/src/preload.ts b/src/preload.ts index 55b3dd7..ba063ab 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -169,6 +169,8 @@ const electronAPI: ElectronAPI = { ipcRenderer.invoke(IPC_CHANNELS.request.getCurrentSubtitleRaw), getCurrentSubtitleAss: (): Promise => ipcRenderer.invoke(IPC_CHANNELS.request.getCurrentSubtitleAss), + getSubtitleSidebarSnapshot: () => + ipcRenderer.invoke(IPC_CHANNELS.request.getSubtitleSidebarSnapshot), getPlaybackPaused: (): Promise => ipcRenderer.invoke(IPC_CHANNELS.request.getPlaybackPaused), onSubtitleAss: (callback: (assText: string) => void) => { diff --git a/src/release-workflow.test.ts b/src/release-workflow.test.ts index 438085b..570e4dc 100644 --- a/src/release-workflow.test.ts +++ b/src/release-workflow.test.ts @@ -10,6 +10,9 @@ const makefile = readFileSync(makefilePath, 'utf8'); const packageJsonPath = resolve(__dirname, '../package.json'); const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as { scripts: Record; + build?: { + files?: string[]; + }; }; test('publish release leaves prerelease unset so gh creates a normal release', () => { @@ -65,6 +68,18 @@ test('release package scripts disable implicit electron-builder publishing', () assert.match(packageJson.scripts['build:win:unsigned'] ?? '', /build-win-unsigned\.mjs/); }); +test('release packaging keeps default file inclusion and excludes large source-only trees explicitly', () => { + const files = packageJson.build?.files ?? []; + assert.ok(files.includes('**/*')); + assert.ok(files.includes('!src{,/**/*}')); + assert.ok(files.includes('!launcher{,/**/*}')); + assert.ok(files.includes('!stats/src{,/**/*}')); + assert.ok(files.includes('!.tmp{,/**/*}')); + assert.ok(files.includes('!release-*{,/**/*}')); + assert.ok(files.includes('!vendor/subminer-yomitan{,/**/*}')); + assert.ok(files.includes('!vendor/texthooker-ui/src{,/**/*}')); +}); + test('config example generation runs directly from source without unrelated bundle prerequisites', () => { assert.equal( packageJson.scripts['generate:config-example'], diff --git a/src/renderer/handlers/keyboard.ts b/src/renderer/handlers/keyboard.ts index 853596a..0afb5ae 100644 --- a/src/renderer/handlers/keyboard.ts +++ b/src/renderer/handlers/keyboard.ts @@ -27,6 +27,7 @@ export function createKeyboardHandlers( getPlaybackPaused: () => Promise; openControllerSelectModal: () => void; openControllerDebugModal: () => void; + toggleSubtitleSidebarModal?: () => void; }, ) { // Timeout for the modal chord capture window (e.g. Y followed by H/K). @@ -181,6 +182,26 @@ export function createKeyboardHandlers( return !e.ctrlKey && !e.metaKey && e.altKey && !e.repeat && e.code === 'KeyC'; } + function isSubtitleSidebarToggle(e: KeyboardEvent): boolean { + const toggleKey = ctx.state.subtitleSidebarToggleKey; + if (!toggleKey) return false; + const isBackslashConfigured = toggleKey === 'Backslash' || toggleKey === '\\'; + const isBackslashLikeCode = ['Backslash', 'IntlBackslash', 'IntlYen'].includes(e.code); + const keyMatches = + toggleKey === e.code || + (isBackslashConfigured && isBackslashLikeCode) || + (isBackslashConfigured && e.key === '\\') || + (toggleKey.length === 1 && e.key === toggleKey); + + return ( + keyMatches && + !e.ctrlKey && + !e.altKey && + !e.metaKey && + !e.repeat + ); + } + function isStatsOverlayToggle(e: KeyboardEvent): boolean { return ( e.code === ctx.state.statsToggleKey && @@ -838,6 +859,12 @@ export function createKeyboardHandlers( return; } + if (isSubtitleSidebarToggle(e)) { + e.preventDefault(); + options.toggleSubtitleSidebarModal?.(); + return; + } + if ( (ctx.state.yomitanPopupVisible || isYomitanPopupVisible(document)) && !isControllerModalShortcut(e) diff --git a/src/renderer/handlers/mouse.test.ts b/src/renderer/handlers/mouse.test.ts index fd514a1..1966a08 100644 --- a/src/renderer/handlers/mouse.test.ts +++ b/src/renderer/handlers/mouse.test.ts @@ -1,6 +1,7 @@ import assert from 'node:assert/strict'; import test from 'node:test'; +import type { SubtitleSidebarConfig } from '../../types'; import { createMouseHandlers } from './mouse.js'; import { YOMITAN_POPUP_HIDDEN_EVENT, YOMITAN_POPUP_SHOWN_EVENT } from '../yomitan-popup.js'; @@ -39,6 +40,7 @@ function createMouseTestContext() { const overlayClassList = createClassList(); const subtitleRootClassList = createClassList(); const subtitleContainerClassList = createClassList(); + const secondarySubContainerClassList = createClassList(); const ctx = { dom: { @@ -54,6 +56,7 @@ function createMouseTestContext() { addEventListener: () => {}, }, secondarySubContainer: { + classList: secondarySubContainerClassList, addEventListener: () => {}, }, }, @@ -63,6 +66,9 @@ function createMouseTestContext() { }, state: { isOverSubtitle: false, + isOverSubtitleSidebar: false, + subtitleSidebarModalOpen: false, + subtitleSidebarConfig: null as SubtitleSidebarConfig | null, isDragging: false, dragStartY: 0, startYPercent: 0, @@ -72,7 +78,7 @@ function createMouseTestContext() { return ctx; } -test('auto-pause on subtitle hover pauses on enter and resumes on leave when enabled', async () => { +test('secondary hover pauses on enter, reveals secondary subtitle, and resumes on leave when enabled', async () => { const ctx = createMouseTestContext(); const mpvCommands: Array<(string | number)[]> = []; @@ -92,8 +98,10 @@ test('auto-pause on subtitle hover pauses on enter and resumes on leave when ena }, }); - await handlers.handleMouseEnter(); - await handlers.handleMouseLeave(); + await handlers.handleSecondaryMouseEnter(); + assert.equal(ctx.dom.secondarySubContainer.classList.contains('secondary-sub-hover-active'), true); + await handlers.handleSecondaryMouseLeave(); + assert.equal(ctx.dom.secondarySubContainer.classList.contains('secondary-sub-hover-active'), false); assert.deepEqual(mpvCommands, [ ['set_property', 'pause', 'yes'], @@ -101,6 +109,68 @@ test('auto-pause on subtitle hover pauses on enter and resumes on leave when ena ]); }); +test('moving between primary and secondary subtitle containers keeps the hover pause active', async () => { + const ctx = createMouseTestContext(); + const mpvCommands: Array<(string | number)[]> = []; + + const handlers = createMouseHandlers(ctx as never, { + modalStateReader: { + isAnySettingsModalOpen: () => false, + isAnyModalOpen: () => false, + }, + applyYPercent: () => {}, + getCurrentYPercent: () => 10, + persistSubtitlePositionPatch: () => {}, + getSubtitleHoverAutoPauseEnabled: () => true, + getYomitanPopupAutoPauseEnabled: () => false, + getPlaybackPaused: async () => false, + sendMpvCommand: (command) => { + mpvCommands.push(command); + }, + }); + + await handlers.handleSecondaryMouseEnter(); + await handlers.handleSecondaryMouseLeave({ + relatedTarget: ctx.dom.subtitleContainer, + } as unknown as MouseEvent); + await handlers.handlePrimaryMouseEnter({ + relatedTarget: ctx.dom.secondarySubContainer, + } as unknown as MouseEvent); + + assert.equal(ctx.state.isOverSubtitle, true); + assert.deepEqual(mpvCommands, [['set_property', 'pause', 'yes']]); +}); + +test('secondary leave toward primary subtitle container clears the secondary hover class', async () => { + const ctx = createMouseTestContext(); + const mpvCommands: Array<(string | number)[]> = []; + + const handlers = createMouseHandlers(ctx as never, { + modalStateReader: { + isAnySettingsModalOpen: () => false, + isAnyModalOpen: () => false, + }, + applyYPercent: () => {}, + getCurrentYPercent: () => 10, + persistSubtitlePositionPatch: () => {}, + getSubtitleHoverAutoPauseEnabled: () => true, + getYomitanPopupAutoPauseEnabled: () => false, + getPlaybackPaused: async () => false, + sendMpvCommand: (command) => { + mpvCommands.push(command); + }, + }); + + await handlers.handleSecondaryMouseEnter(); + await handlers.handleSecondaryMouseLeave({ + relatedTarget: ctx.dom.subtitleContainer, + } as unknown as MouseEvent); + + assert.equal(ctx.state.isOverSubtitle, false); + assert.equal(ctx.dom.secondarySubContainer.classList.contains('secondary-sub-hover-active'), false); + assert.deepEqual(mpvCommands, [['set_property', 'pause', 'yes']]); +}); + test('auto-pause on subtitle hover skips when playback is already paused', async () => { const ctx = createMouseTestContext(); const mpvCommands: Array<(string | number)[]> = []; @@ -127,6 +197,36 @@ test('auto-pause on subtitle hover skips when playback is already paused', async assert.deepEqual(mpvCommands, []); }); +test('primary hover pauses on enter without revealing secondary subtitle', async () => { + const ctx = createMouseTestContext(); + const mpvCommands: Array<(string | number)[]> = []; + + const handlers = createMouseHandlers(ctx as never, { + modalStateReader: { + isAnySettingsModalOpen: () => false, + isAnyModalOpen: () => false, + }, + applyYPercent: () => {}, + getCurrentYPercent: () => 10, + persistSubtitlePositionPatch: () => {}, + getSubtitleHoverAutoPauseEnabled: () => true, + getYomitanPopupAutoPauseEnabled: () => false, + getPlaybackPaused: async () => false, + sendMpvCommand: (command) => { + mpvCommands.push(command); + }, + }); + + await handlers.handlePrimaryMouseEnter(); + assert.equal(ctx.dom.secondarySubContainer.classList.contains('secondary-sub-hover-active'), false); + await handlers.handlePrimaryMouseLeave(); + + assert.deepEqual(mpvCommands, [ + ['set_property', 'pause', 'yes'], + ['set_property', 'pause', 'no'], + ]); +}); + test('auto-pause on subtitle hover is skipped when disabled in config', async () => { const ctx = createMouseTestContext(); const mpvCommands: Array<(string | number)[]> = []; @@ -153,6 +253,67 @@ test('auto-pause on subtitle hover is skipped when disabled in config', async () assert.deepEqual(mpvCommands, []); }); +test('subtitle leave restores passthrough while embedded sidebar is open but not hovered', async () => { + const ctx = createMouseTestContext(); + const ignoreMouseCalls: Array<[boolean, { forward?: boolean } | undefined]> = []; + const previousWindow = (globalThis as { window?: unknown }).window; + + ctx.platform.shouldToggleMouseIgnore = true; + ctx.state.isOverSubtitle = true; + ctx.state.subtitleSidebarModalOpen = true; + ctx.state.subtitleSidebarConfig = { + enabled: true, + autoOpen: false, + layout: 'embedded', + toggleKey: 'Backslash', + pauseVideoOnHover: false, + autoScroll: true, + maxWidth: 360, + opacity: 0.92, + backgroundColor: 'rgba(54, 58, 79, 0.88)', + textColor: '#cad3f5', + fontFamily: '"Iosevka Aile", sans-serif', + fontSize: 17, + timestampColor: '#a5adcb', + activeLineColor: '#f5bde6', + activeLineBackgroundColor: 'rgba(138, 173, 244, 0.22)', + hoverLineBackgroundColor: 'rgba(54, 58, 79, 0.84)', + }; + + Object.defineProperty(globalThis, 'window', { + configurable: true, + value: { + electronAPI: { + setIgnoreMouseEvents: (ignore: boolean, options?: { forward?: boolean }) => { + ignoreMouseCalls.push([ignore, options]); + }, + }, + }, + }); + + try { + const handlers = createMouseHandlers(ctx as never, { + modalStateReader: { + isAnySettingsModalOpen: () => false, + isAnyModalOpen: () => true, + }, + applyYPercent: () => {}, + getCurrentYPercent: () => 10, + persistSubtitlePositionPatch: () => {}, + getSubtitleHoverAutoPauseEnabled: () => false, + getYomitanPopupAutoPauseEnabled: () => false, + getPlaybackPaused: async () => false, + sendMpvCommand: () => {}, + }); + + await handlers.handlePrimaryMouseLeave(); + + assert.deepEqual(ignoreMouseCalls.at(-1), [true, { forward: true }]); + } finally { + Object.defineProperty(globalThis, 'window', { configurable: true, value: previousWindow }); + } +}); + test('pending hover pause check is ignored when mouse leaves before pause state resolves', async () => { const ctx = createMouseTestContext(); const mpvCommands: Array<(string | number)[]> = []; diff --git a/src/renderer/handlers/mouse.ts b/src/renderer/handlers/mouse.ts index 0d66d3a..43462bf 100644 --- a/src/renderer/handlers/mouse.ts +++ b/src/renderer/handlers/mouse.ts @@ -1,4 +1,5 @@ import type { ModalStateReader, RendererContext } from '../context'; +import { syncOverlayMouseIgnoreState } from '../overlay-mouse-ignore.js'; import { YOMITAN_POPUP_HIDDEN_EVENT, YOMITAN_POPUP_SHOWN_EVENT, @@ -25,6 +26,19 @@ export function createMouseHandlers( let pausedBySubtitleHover = false; let pausedByYomitanPopup = false; + function isWithinOtherSubtitleContainer( + relatedTarget: EventTarget | null, + otherContainer: HTMLElement, + ): boolean { + if (relatedTarget === otherContainer) { + return true; + } + if (typeof Node !== 'undefined' && relatedTarget instanceof Node) { + return otherContainer.contains(relatedTarget); + } + return false; + } + function maybeResumeHoverPause(): void { if (!pausedBySubtitleHover) return; if (pausedByYomitanPopup) return; @@ -80,10 +94,7 @@ export function createMouseHandlers( function enablePopupInteraction(): void { yomitanPopupVisible = true; ctx.state.yomitanPopupVisible = true; - ctx.dom.overlay.classList.add('interactive'); - if (ctx.platform.shouldToggleMouseIgnore) { - window.electronAPI.setIgnoreMouseEvents(false); - } + syncOverlayMouseIgnoreState(ctx); if (ctx.platform.isMacOSPlatform) { window.focus(); } @@ -101,20 +112,18 @@ export function createMouseHandlers( popupPauseRequestId += 1; maybeResumeYomitanPopupPause(); maybeResumeHoverPause(); - if (!ctx.state.isOverSubtitle && !options.modalStateReader.isAnyModalOpen()) { - ctx.dom.overlay.classList.remove('interactive'); - if (ctx.platform.shouldToggleMouseIgnore) { - window.electronAPI.setIgnoreMouseEvents(true, { forward: true }); - } - } + syncOverlayMouseIgnoreState(ctx); } - async function handleMouseEnter(): Promise { + async function handleMouseEnter( + _event?: MouseEvent, + showSecondaryHover = false, + ): Promise { ctx.state.isOverSubtitle = true; - ctx.dom.overlay.classList.add('interactive'); - if (ctx.platform.shouldToggleMouseIgnore) { - window.electronAPI.setIgnoreMouseEvents(false); + if (showSecondaryHover) { + ctx.dom.secondarySubContainer.classList.add('secondary-sub-hover-active'); } + syncOverlayMouseIgnoreState(ctx); if (yomitanPopupVisible && options.getYomitanPopupAutoPauseEnabled()) { return; @@ -124,6 +133,10 @@ export function createMouseHandlers( return; } + if (pausedBySubtitleHover) { + return; + } + const requestId = ++hoverPauseRequestId; let paused: boolean | null = null; try { @@ -141,8 +154,26 @@ export function createMouseHandlers( pausedBySubtitleHover = true; } - async function handleMouseLeave(): Promise { + async function handleMouseLeave( + _event?: MouseEvent, + hideSecondaryHover = false, + ): Promise { + const relatedTarget = _event?.relatedTarget ?? null; + const otherContainer = hideSecondaryHover + ? ctx.dom.subtitleContainer + : ctx.dom.secondarySubContainer; + if (relatedTarget && isWithinOtherSubtitleContainer(relatedTarget, otherContainer)) { + ctx.state.isOverSubtitle = false; + if (hideSecondaryHover) { + ctx.dom.secondarySubContainer.classList.remove('secondary-sub-hover-active'); + } + return; + } + ctx.state.isOverSubtitle = false; + if (hideSecondaryHover) { + ctx.dom.secondarySubContainer.classList.remove('secondary-sub-hover-active'); + } hoverPauseRequestId += 1; maybeResumeHoverPause(); if (yomitanPopupVisible) return; @@ -246,6 +277,10 @@ export function createMouseHandlers( } return { + handlePrimaryMouseEnter: (event?: MouseEvent) => handleMouseEnter(event, false), + handlePrimaryMouseLeave: (event?: MouseEvent) => handleMouseLeave(event, false), + handleSecondaryMouseEnter: (event?: MouseEvent) => handleMouseEnter(event, true), + handleSecondaryMouseLeave: (event?: MouseEvent) => handleMouseLeave(event, true), handleMouseEnter, handleMouseLeave, setupDragging, diff --git a/src/renderer/index.html b/src/renderer/index.html index 2eae08d..142512f 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -256,6 +256,18 @@ +