mirror of
https://github.com/debpalash/VoiceStudio.git
synced 2026-10-02 01:26:35 +08:00
refactor: move shared UI under Electron
This commit is contained in:
@@ -211,11 +211,11 @@ one. The rules:
|
||||
Anything over 500 lines must be split. (The cap does **not** apply to
|
||||
`src/index.css` — it is the single, intentional styling foundation and the
|
||||
only app stylesheet; see the CSS rule above.)
|
||||
- **Pages are thin orchestrators.** A file in `frontend/src/pages/` is just
|
||||
- **Pages are thin orchestrators.** A file in `electron/src/shared/pages/` is just
|
||||
layout + routing + state wiring that composes feature components — no inline
|
||||
sub-component over ~50 lines.
|
||||
- **One component per file.** Co-locate `Foo.jsx` + `Foo.test.jsx` together in a
|
||||
per-page feature folder under `frontend/src/components/` (e.g.
|
||||
per-page feature folder under `electron/src/shared/components/` (e.g.
|
||||
`components/settings/`, `components/dub/`). Styling is **not** co-located —
|
||||
it's utilities + shadcn, with any irreducible rules in `src/index.css`.
|
||||
- **Shared bits go in a `primitives/` folder** inside the feature folder
|
||||
@@ -309,7 +309,7 @@ hard rules from the first prompt.
|
||||
var, or CLI flag).
|
||||
- **i18n — all 21 locales (hard rule):** every user-facing string goes through
|
||||
`t('...')` and the key must exist in **all 21** files under
|
||||
`frontend/src/i18n/locales/`. Translate; don't copy English into non-English
|
||||
`electron/src/shared/i18n/locales/`. Translate; don't copy English into non-English
|
||||
locales. CI fails on hardcoded CJK outside the allowlist in
|
||||
`tests/test_no_hardcoded_cjk.py` (extend `_ALLOWED_FILES` with a
|
||||
justification for legitimate functional CJK).
|
||||
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
cache-dependency-glob: "uv.lock"
|
||||
|
||||
# Node 22 is needed for --experimental-strip-types so node:test can
|
||||
# import .ts files directly from frontend/src/api/*.
|
||||
# import .ts files directly from electron/src/shared/api/*.
|
||||
- name: Setup Node 22
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Electron (`electron/`) is the only desktop and web UI. The Tauri shell and legacy
|
||||
UI entrypoints are removed; do not restore build, runtime, release, or CI paths for
|
||||
them. Triage reports from final Tauri installations toward the migration guide and
|
||||
preserve their immutable updater feeds. Some modules under `frontend/src/` remain
|
||||
preserve their immutable updater feeds. Some modules under `electron/src/shared/` remain
|
||||
temporarily shared by Electron; they are not a runnable app. New UI, IPC, setup
|
||||
instructions, tests, and browser assets belong in Electron; validate Electron on
|
||||
macOS, Windows and Linux.
|
||||
@@ -37,7 +37,7 @@ Binding for every AI agent (Claude, Codex, Cursor, review bots, …). CLAUDE.md
|
||||
- Root-cause the class, not the instance; fail-before/pass-after regression test; smallest correct change.
|
||||
- Default behavior identical on macOS/Windows/Linux; platform-only features go behind explicit opt-in. Divergent default = P0.
|
||||
- Local-first: no new required network calls; any HF download gated on installed-ness or explicit user action; all synthetic audio through the `mark_synthetic` chokepoint.
|
||||
- Every user-facing string via i18n, present in ALL 21 `frontend/src/i18n/locales/*.json` with real translations.
|
||||
- Every user-facing string via i18n, present in ALL 21 `electron/src/shared/i18n/locales/*.json` with real translations.
|
||||
- Docs-sync in the same PR. CHANGELOG Unreleased: quiet one-liners ending `(#N)` + `— thanks @user!` for community work, under a short `**Highlights**` list.
|
||||
- Tagged release announcements lead with the biggest user-visible change; redesigns need real UI screenshots and migrations need installer links and steps. Verify all contributor credits from the tag comparison and included PRs; list authors and bug reporters separately (see `docs/RELEASING.md`).
|
||||
- Versioning: root `package.json` is the single source of truth; never bump without the owner asking.
|
||||
@@ -46,7 +46,7 @@ Binding for every AI agent (Claude, Codex, Cursor, review bots, …). CLAUDE.md
|
||||
|
||||
## Shared select controls
|
||||
|
||||
- Use `frontend/src/components/SearchableSelect.jsx` for all new or redesigned select boxes. Reuse `VoiceSelector` for voice choices. Do not introduce native `<select>` controls.
|
||||
- Use `electron/src/shared/components/SearchableSelect.jsx` for all new or redesigned select boxes. Reuse `VoiceSelector` for voice choices. Do not introduce native `<select>` controls.
|
||||
- Provide a localized `ariaLabel`; use `menuPortal` inside scrolling or clipping containers. Preserve keyboard selection and disabled states.
|
||||
|
||||
## Agent skills
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Electron (`electron/`) is the only desktop and web UI. The Tauri shell and legacy
|
||||
UI entrypoints are removed; do not restore build, runtime, release, or CI paths for
|
||||
them. Triage reports from final Tauri installations toward the migration guide and
|
||||
preserve their immutable updater feeds. Some modules under `frontend/src/` remain
|
||||
preserve their immutable updater feeds. Some modules under `electron/src/shared/` remain
|
||||
temporarily shared by Electron; they are not a runnable app. New UI, IPC, setup
|
||||
instructions, tests, and browser assets belong in Electron; validate Electron on
|
||||
macOS, Windows and Linux.
|
||||
@@ -34,7 +34,7 @@ Everything else (new engines, fancy features) is downstream of "the thing instal
|
||||
|
||||
The May-2026 stack research that used to live here served five capabilities that have all since shipped (HF-token Settings panel, prefilled-URL bug reporting, uv mirror fallback for restricted networks, the Supertonic-3 engine, in-repo Markdown docs). Follow the patterns in the code itself; the durable *don'ts* that research established:
|
||||
|
||||
- **No third-party endpoints for bug reporting or crash dumps** (`sentry-tauri` was evaluated and rejected) — bug reporting stays opt-in via prefilled GitHub-issue URLs, submitted from the user's own browser. The one sanctioned third-party endpoint is the opt-in PostHog US product analytics and error tracking (owner-set 2026-07-16; migrated 2026-09-26; sanitized renderer errors approved 2026-09-26), which is consent-gated behind the first-run prompt and ships allowlisted content-free metadata only. Raw exception, DOM, and session autocapture stay disabled; manually captured renderer exceptions must replace messages and scrub stack paths before transmission. Its publishable write-only project token is committed in-repo (owner reversal 2026-07-20, #1193 — source builds get the same consent-gated analytics as installers; env/baked token overrides), allowed by `tests/test_no_committed_analytics_token.py` in exactly `backend/core/analytics.py` + `frontend/src/utils/analytics.ts`.
|
||||
- **No third-party endpoints for bug reporting or crash dumps** (`sentry-tauri` was evaluated and rejected) — bug reporting stays opt-in via prefilled GitHub-issue URLs, submitted from the user's own browser. The one sanctioned third-party endpoint is the opt-in PostHog US product analytics and error tracking (owner-set 2026-07-16; migrated 2026-09-26; sanitized renderer errors approved 2026-09-26), which is consent-gated behind the first-run prompt and ships allowlisted content-free metadata only. Raw exception, DOM, and session autocapture stay disabled; manually captured renderer exceptions must replace messages and scrub stack paths before transmission. Its publishable write-only project token is committed in-repo (owner reversal 2026-07-20, #1193 — source builds get the same consent-gated analytics as installers; env/baked token overrides), allowed by `tests/test_no_committed_analytics_token.py` in exactly `backend/core/analytics.py` + `electron/src/shared/utils/analytics.ts`.
|
||||
- **No PAT/token-based GitHub posting from the app** — the user submits from their own browser.
|
||||
- **Don't recommend `setx` for env vars on Windows** (silent truncation, no current-shell propagation) — use the in-app Settings panel or PowerShell `[Environment]::SetEnvironmentVariable`.
|
||||
- **Don't adopt Material for MkDocs** for any future docs site (maintenance mode since Nov 2025) — Astro Starlight is the precedent if docs ever outgrow the repo.
|
||||
@@ -58,7 +58,7 @@ For anything new: prefer what's already pinned in `pyproject.toml` / `electron/p
|
||||
|
||||
**Release presentation and credits (owner-set 2026-09-17):** Tagged release announcements lead with the biggest user-visible change; redesigns need real UI screenshots and migrations need installer links and steps. Verify all contributor credits from the tag comparison and included PRs; list authors and bug reporters separately (see `docs/RELEASING.md`). Keep Highlights to 3–5 bullets; the release introduction can include prose, images, and a download table before the concise change entries.
|
||||
|
||||
**Localization (hard rule):** No hardcoded non-English (CJK) **user-facing text** anywhere in the codebase except the translation layer (`frontend/src/i18n/`). All UI strings go through i18n (`t('...')` keys in `locales/*.json`); native language names live in `i18n/index.ts` (`LANGUAGES`). Functional CJK is allowed and tracked via the allowlist in `tests/test_no_hardcoded_cjk.py` — text-processing regexes, model/engine vocabulary & identifiers (e.g. CosyVoice speaker IDs), localized error matching, demo/eval data, and test fixtures. CI fails on any hardcoded CJK outside the allowlist; to add legitimate functional CJK, extend `_ALLOWED_FILES` there with a justification.
|
||||
**Localization (hard rule):** No hardcoded non-English (CJK) **user-facing text** anywhere in the codebase except the translation layer (`electron/src/shared/i18n/`). All UI strings go through i18n (`t('...')` keys in `locales/*.json`); native language names live in `i18n/index.ts` (`LANGUAGES`). Functional CJK is allowed and tracked via the allowlist in `tests/test_no_hardcoded_cjk.py` — text-processing regexes, model/engine vocabulary & identifiers (e.g. CosyVoice speaker IDs), localized error matching, demo/eval data, and test fixtures. CI fails on any hardcoded CJK outside the allowlist; to add legitimate functional CJK, extend `_ALLOWED_FILES` there with a justification.
|
||||
|
||||
**Release deployment channels (hard rule, owner-set 2026-07-16):** a version bump is not "released" until **every** maintained channel ships it — the full checklist lives in `docs/RELEASING.md`. The channels are the four-platform Electron GitHub Release, GHCR and Docker Hub in CUDA and ROCm flavors, and the Docker Hub overview page synced from `deploy/dockerhub-overview.md`. The final Tauri feeds are immutable compatibility assets copied into releases for old clients; they are never rebuilt. Verify all channels after tagging. Preview/RC builds always source from `main`; never cut a side-branch build.
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ _OFF_VALUES = {"1", "true", "yes", "on"}
|
||||
#: A `POSTHOG_PROJECT_TOKEN` env var (release builds bake one in via the
|
||||
#: desktop shell; developers can point at their own project) always wins.
|
||||
#: Committed-token guard: tests/test_no_committed_analytics_token.py allows a
|
||||
#: `phc_` literal in exactly this file and frontend/src/utils/analytics.ts.
|
||||
#: `phc_` literal in exactly this file and electron/src/shared/utils/analytics.ts.
|
||||
_PUBLIC_PROJECT_TOKEN = "phc_kJK9nFqtwFmB4CYWS4bMDTY7z9P4KCRyiRT7CzJTXm9f" # gitleaks:allow — publishable write-only key (#1193)
|
||||
_DEFAULT_HOST = "https://us.i.posthog.com"
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ _DIALECTS_SORTED = sorted(_CAT[5]) # 12 Chinese dialects
|
||||
|
||||
# ── Use-case categories (replaces the named-real-person buckets) ──────────────
|
||||
# `icon` values are lucide-react component names; the frontend maps them to SVG
|
||||
# components (see frontend/src/utils/archetypeIcons.jsx). No emoji — they render
|
||||
# components (see electron/src/shared/utils/archetypeIcons.jsx). No emoji — they render
|
||||
# inconsistently across OSes.
|
||||
USE_CASES = [
|
||||
{"id": "narration", "name": "Narration & Story", "icon": "BookOpen"},
|
||||
@@ -323,7 +323,7 @@ def _make_featured():
|
||||
# gender/age/pitch axes keeps every instruct inside the validator's vocabulary —
|
||||
# ``test_archetypes.py`` enforces this independently.
|
||||
#
|
||||
# Each ``language`` label must match an entry in ``frontend/src/languages.json``
|
||||
# Each ``language`` label must match an entry in ``electron/src/shared/languages.json``
|
||||
# verbatim, because the string flows straight into ``model.generate(language=…)``
|
||||
# with no normalization. ("Arabic" is intentionally omitted — it is not in that
|
||||
# list.) ``_ML_SAMPLES`` is functional demo/eval text (like ``_ZH_SAMPLE``); the
|
||||
|
||||
@@ -31,7 +31,7 @@ Design notes
|
||||
|
||||
Localization note (CLAUDE.md): the only hardcoded CJK here is
|
||||
``DIALECT_PINYIN`` — a functional pinyin → Chinese-dialect-token mapping
|
||||
(model vocabulary, like ``frontend/src/utils/constants.js``). Registered in
|
||||
(model vocabulary, like ``electron/src/shared/utils/constants.js``). Registered in
|
||||
``tests/test_no_hardcoded_cjk.py``'s allowlist with this justification.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Error class → docs URL mapping for the in-app deeplink button.
|
||||
|
||||
Used by the React ErrorBoundary's "Open docs for this error" button (via the
|
||||
TypeScript mirror at `frontend/src/utils/errorDocsMap.ts`) and by the Phase 5
|
||||
TypeScript mirror at `electron/src/shared/utils/errorDocsMap.ts`) and by the Phase 5
|
||||
bug-reporter for "this error has a docs page" links.
|
||||
|
||||
The error taxonomy below is the contract — Phase 5 reporter consumes it,
|
||||
@@ -10,7 +10,7 @@ locks the key set. To add a new class:
|
||||
|
||||
1. Pick a stable ALL_CAPS key (the API will live forever).
|
||||
2. Add the entry here.
|
||||
3. Mirror it in `frontend/src/utils/errorDocsMap.ts`.
|
||||
3. Mirror it in `electron/src/shared/utils/errorDocsMap.ts`.
|
||||
4. Update the `test_keys_match_taxonomy` set and the TS-side keys-sync test.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Everything VoiceStudio renders into a bug report or diagnostic dump goes
|
||||
through ``scrub_text()`` before it can reach a prefilled GitHub Issues URL
|
||||
(the only outbound path — see CLAUDE.md Capability 2). The scrubber is the
|
||||
backend twin of ``frontend/src/utils/bugReport.js``'s ``scrubText`` and
|
||||
backend twin of ``electron/src/shared/utils/bugReport.js``'s ``scrubText`` and
|
||||
must stay at least as strict:
|
||||
|
||||
- home directories → ``~`` (macOS ``/Users/<name>``, Linux ``/home/<name>``,
|
||||
|
||||
@@ -34,7 +34,7 @@ _TOKEN_BYTES = 32
|
||||
_ENCODED_TOKEN_LENGTH = 43
|
||||
_TOKEN_BODY_RE = re.compile(rf"^[A-Za-z0-9_-]{{{_ENCODED_TOKEN_LENGTH}}}$")
|
||||
# Every ticketed WebSocket route. The first-party mirror is ``ALLOWED_WS_PATHS``
|
||||
# in frontend/src/api/authSession.ts — a route missing here mints a 422 and the
|
||||
# in electron/src/shared/api/authSession.ts — a route missing here mints a 422 and the
|
||||
# UI consumer fails silently (#1769 added /ws/tts for the live dub preview).
|
||||
_ALLOWED_WS_PATHS = frozenset(
|
||||
{"/ws/events", "/ws/transcribe", "/ws/tts", "/v1/audio/transcriptions/stream"}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
The longform marker dialect (``# heading``, ``[voice:NAME]``, ``[pause …]``,
|
||||
``[slow]/[fast]/[emphasis]/[spell]``) was parsed by three independent code
|
||||
paths that disagreed (client/server/regex-level). This module is the one
|
||||
canonical Python parser; ``frontend/src/utils/longformParser.js`` is its
|
||||
canonical Python parser; ``electron/src/shared/utils/longformParser.js`` is its
|
||||
mechanically-mirrored JS twin, and ``tests/fixtures/longform_parser_cases.json``
|
||||
is the shared golden corpus asserted byte-for-byte against both.
|
||||
|
||||
|
||||
@@ -226,7 +226,7 @@ _WEBVTT_TAG_RE = re.compile(r"<[^<>\n]*>")
|
||||
# SubRip has no escaping, so `a<b and c>d` is dialogue. Only exact tag
|
||||
# shapes are markup: `<i>`/`<b.x>`/`</u>`, `<c.colorE5E5E5>`, `<v Roger>`,
|
||||
# `<font color=...>` and karaoke timestamps. Mirrored in
|
||||
# frontend/src/utils/importStory.js (CUE_MARKUP); keep the two in step.
|
||||
# electron/src/shared/utils/importStory.js (CUE_MARKUP); keep the two in step.
|
||||
_SRT_MARKUP_RE = re.compile(
|
||||
r"</?(?:[biu]|c|ruby|rt)(?:\.[^\s.<>]+)*>"
|
||||
r"|<(?:v|lang)(?:\.[^\s.<>]+)*[ \t][^<>\n]*>|</(?:v|lang)>"
|
||||
|
||||
@@ -19,7 +19,7 @@ Design rules (load-bearing):
|
||||
pass through a pipeline is harmless.
|
||||
* **Per-language.** Numbers go through ``num2words`` only for languages it
|
||||
supports (``_NUM2WORDS_LANGS``; the request's ``language`` is a full
|
||||
display name from frontend/src/languages.json or an ISO-ish code — both
|
||||
display name from electron/src/shared/languages.json or an ISO-ish code — both
|
||||
resolve via :func:`_num2words_lang`), or through a hand-written native
|
||||
verbalizer for languages num2words lacks (``_NATIVE_VERBALIZERS``, e.g.
|
||||
Malayalam). Everything else keeps its digits.
|
||||
@@ -75,7 +75,7 @@ PREF_KEY = "text_normalization_enabled"
|
||||
# ── Language resolution ───────────────────────────────────────────────────────
|
||||
#
|
||||
# The `language` kwarg across the app is normally a full display name from
|
||||
# frontend/src/languages.json ("English", "German", …) — see
|
||||
# electron/src/shared/languages.json ("English", "German", …) — see
|
||||
# resolve_kokoro_lang_code in services/tts_backend.py — but ISO-ish codes
|
||||
# ("en", "pt-BR") also flow through dub/API callers. Map both to a num2words
|
||||
# locale; anything unmapped keeps its digits (false negatives are fine).
|
||||
|
||||
@@ -2230,7 +2230,7 @@ class KittenTTSBackend(TTSBackend):
|
||||
# #977: Kokoro's own ALIASES table (mlx_audio.tts.models.kokoro.pipeline) only
|
||||
# recognizes ISO-ish tokens ("en", "es", "fr-fr", "pt-br", …) — it has no idea
|
||||
# what a full language name is. OmniVoice's `language` kwarg is normally a
|
||||
# full display name from frontend/src/languages.json (e.g. "Dutch",
|
||||
# full display name from electron/src/shared/languages.json (e.g. "Dutch",
|
||||
# "Spanish"), forwarded verbatim by the frontend and by
|
||||
# `OmniVoiceBackend.generate()`. Translate the subset Kokoro actually
|
||||
# supports to the ISO token its own ALIASES expects; a caller that already
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "omnivoice-studio-monorepo",
|
||||
"dependencies": {
|
||||
"posthog-js": "^1.434.14",
|
||||
},
|
||||
"devDependencies": {
|
||||
"concurrently": "^10",
|
||||
"playwright": "^1.63.0",
|
||||
@@ -24,37 +21,57 @@
|
||||
"@electron-toolkit/preload": "^3.0.2",
|
||||
"@electron-toolkit/utils": "^4.0.0",
|
||||
"@fontsource-variable/inter": "^5.3.0",
|
||||
"@fontsource-variable/source-serif-4": "^5.3.0",
|
||||
"@fontsource/ibm-plex-mono": "^5.3.0",
|
||||
"@lobehub/icons-static-svg": "^1.95.0",
|
||||
"@radix-ui/react-dialog": "^1.1.23",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.24",
|
||||
"@radix-ui/react-progress": "^1.1.16",
|
||||
"@radix-ui/react-select": "^2.3.7",
|
||||
"@radix-ui/react-slider": "^1.4.7",
|
||||
"@radix-ui/react-slot": "^1.3.3",
|
||||
"@radix-ui/react-tabs": "^1.1.21",
|
||||
"@radix-ui/react-toggle": "^1.1.18",
|
||||
"@radix-ui/react-toggle-group": "^1.1.19",
|
||||
"@radix-ui/react-tooltip": "^1.2.16",
|
||||
"@scalar/api-reference-react": "^0.9.67",
|
||||
"@tanstack/react-form": "^1.33.5",
|
||||
"@tanstack/react-pacer": "^0.23.0",
|
||||
"@tanstack/react-query": "^5.102.8",
|
||||
"@tanstack/react-router": "^1.170.36",
|
||||
"@tanstack/react-store": "^0.11.1",
|
||||
"@tanstack/react-table": "^8.21.3",
|
||||
"@tanstack/react-virtual": "^3.14.13",
|
||||
"@tanstack/store": "^0.11.1",
|
||||
"@vidstack/react": "1.15.6",
|
||||
"@xyflow/react": "^12.12.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cn": "^0.3.0",
|
||||
"country-flag-icons": "^1.6.20",
|
||||
"dashjs": "^5.2.1",
|
||||
"electron-updater": "^6.8.9",
|
||||
"hls.js": "^1.7.3",
|
||||
"html-entities": "^2.6.0",
|
||||
"i18next": "^26.4.2",
|
||||
"i18next-browser-languagedetector": "^8.2.1",
|
||||
"lucide-react": "^1.46.0",
|
||||
"posthog-js": "^1.434.14",
|
||||
"proxy-agent": "6.5.0",
|
||||
"qrcode": "^1.5.4",
|
||||
"react": "^19.3.0",
|
||||
"react-dom": "^19.3.0",
|
||||
"react-hot-toast": "^2.6.0",
|
||||
"react-i18next": "^17.0.14",
|
||||
"react-window": "^2.3.1",
|
||||
"remotion": "4.0.524",
|
||||
"shadcn": "^4.21.0",
|
||||
"sonner": "^2.0.8",
|
||||
"tailwind-merge": "^3.6.0",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"wavesurfer.js": "^7.12.12",
|
||||
"word-extractor": "1.0.4",
|
||||
"zustand": "^5.0.15",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/vite": "^4.3.3",
|
||||
@@ -297,6 +314,8 @@
|
||||
|
||||
"@fontsource-variable/inter": ["@fontsource-variable/inter@5.3.0", "", {}, "sha512-OupL48va4JNofb97w6NYeF9S7W/kHNKM0Er8Dem5nqi4jeOLrVJDoE8tZEpnMJmtkvNbB1EIPPwHcdkF6b1oUA=="],
|
||||
|
||||
"@fontsource-variable/source-serif-4": ["@fontsource-variable/source-serif-4@5.3.0", "", {}, "sha512-9vch9WqxjaaA+1o9Ur8pOgIGbCYLjRReOUel23A6lOpD1syptgjtkORevvNmldJ5kGXQL29onQUqI5Ltz0s3bQ=="],
|
||||
|
||||
"@fontsource/ibm-plex-mono": ["@fontsource/ibm-plex-mono@5.3.0", "", {}, "sha512-eTgnZjZEGk1QtD3ZstF+Vclo2HLAni8YMy34/DxllwZvyz1lR/1RF/xTiAquOBO7MvqBx8D2Ig2WCPMVfdZu7Q=="],
|
||||
|
||||
"@hapi/address": ["@hapi/address@5.1.1", "", { "dependencies": { "@hapi/hoek": "^11.0.2" } }, "sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA=="],
|
||||
@@ -487,6 +506,80 @@
|
||||
|
||||
"@quansync/fs": ["@quansync/fs@1.0.0", "", { "dependencies": { "quansync": "^1.0.0" } }, "sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ=="],
|
||||
|
||||
"@radix-ui/number": ["@radix-ui/number@1.1.3", "", {}, "sha512-Road2bidD0uu/1BGDOWNdPI06g0lIRy6IF9GZcIrDK2KGItfor8IQwQa+yM2ERgHM1MmHxaxpTzk0/Jp42lNfA=="],
|
||||
|
||||
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.7", "", {}, "sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q=="],
|
||||
|
||||
"@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.15", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.10" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-v4zggRcjadnI+ClKDuijlQEW4tw3NoaeHc/PwpKnLoLLKNUG4InLegkstooLcRIUWCs+8L22dGURCVuFfOKfnA=="],
|
||||
|
||||
"@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.15", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-slot": "1.3.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9W+B9NPF0NaaPh/1NJd3+KqsnlLqU9H7T2rvww+fp+T/evVXdNAyYcnfRQZFOjkR1ajQp3yORlqnI8soawLvNA=="],
|
||||
|
||||
"@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.5", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA=="],
|
||||
|
||||
"@radix-ui/react-context": ["@radix-ui/react-context@1.2.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RHCUGwKHDr0hDGg4X7ma4JG4/+12qxw8rkh5QKdDldlCvtja6nUx1Ef/8HVrJze81lEsgLQlqjzjGNHantgnQA=="],
|
||||
|
||||
"@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.23", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-focus-guards": "1.1.6", "@radix-ui/react-focus-scope": "1.1.16", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-portal": "1.1.17", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-slot": "1.3.3", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-layout-effect": "1.1.4", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Ksw4WeROkO4rC9k/onilX/Ao2Cr1ku1unMNH+XSCcP4jSXYu7HDsg9n4ojMjVb22XpYjAQ9qfrFlVbru1vXDUA=="],
|
||||
|
||||
"@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-5pzg4FGQNpExhnhT2zlrP1wZFaYCd1K0nYWoFAdcYoYK868IEigqMX3B3f8yIoRlAhAeDWciLI6ZdCKHF9P4Vg=="],
|
||||
|
||||
"@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.19", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-effect-event": "0.0.5" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w=="],
|
||||
|
||||
"@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.24", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-menu": "2.1.24", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-controllable-state": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-geq8l2rJkxvkXsT9RMgtUE3P8pITFpTsvYpbySi1IH4fZEABD/Gp85myayFgxk0ktljGMJnCbeFkyTusvSvv7g=="],
|
||||
|
||||
"@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.6", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RNOJjfZMTyBM6xYmV3IVGXkPjIhcBAuv48POevAXwrGJhkWZ9p1rFoIS1JFooPuT193AZmRsCPhpoVJxx6OPoQ=="],
|
||||
|
||||
"@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.16", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ=="],
|
||||
|
||||
"@radix-ui/react-id": ["@radix-ui/react-id@1.1.4", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA=="],
|
||||
|
||||
"@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.24", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-focus-guards": "1.1.6", "@radix-ui/react-focus-scope": "1.1.16", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-popper": "1.3.7", "@radix-ui/react-portal": "1.1.17", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-roving-focus": "1.1.19", "@radix-ui/react-slot": "1.3.3", "@radix-ui/react-use-callback-ref": "1.1.4", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-uW7RVuU6Lp/ZtfeY4b3kL32zccgEWvPv1+cf17ubYzHa9cL8AHokmk36cG/XEiH/smbQvumnieXX9j/e9RqJWA=="],
|
||||
|
||||
"@radix-ui/react-popper": ["@radix-ui/react-popper@1.3.7", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-layout-effect": "1.1.4", "@radix-ui/react-use-rect": "1.1.4", "@radix-ui/react-use-size": "1.1.4", "@radix-ui/rect": "1.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-UsJrrd7w4wuKKTdvd/DNERVlwSlUcyXzjhyDwBk+3aPOsCjOY6ZSbxuw8E6lZTjjfP8Cpd0J8VVkrYUWyGYXyg=="],
|
||||
|
||||
"@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.17", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vKQLcWypUnwZVvfV7UkGahH2g6ySe8M8R+zYBwPrv5byZ9QAW6cQVvNKo7GgmD+p8aYb6D9JBuvy8/WhOno2wQ=="],
|
||||
|
||||
"@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.10", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3wyzCQ6+ubRA+D4uv9m95JYLXxmOHp05qjrkjeA7uKHHtjpPggQzc6DAb0URl7j67oR0K2foO4ip27TiX037Bw=="],
|
||||
|
||||
"@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.10", "", { "dependencies": { "@radix-ui/react-slot": "1.3.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-MucOnzh6hR5mid6VpkbglRAMYMjKLqRnGBbjXkzjK52fuQDd1qbkx78a5P40mkcnVXJdEVxm26E9OPAiUq7nBg=="],
|
||||
|
||||
"@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.16", "", { "dependencies": { "@radix-ui/react-context": "1.2.2", "@radix-ui/react-primitive": "2.1.10" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-5XnomAsoZZCY+KNTxbIghpGqPruZvKFNlvcAljVAOdDRDsH4/OZQxhtwo5wdtoDM5R6MhJBb2sPnDuRFep3lzg=="],
|
||||
|
||||
"@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.19", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-is-hydrated": "0.1.3", "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-V9jI6hDjT7l3jsCQD9bLNvDLM3tH/gdbOTp7Tefp3hbbgCGQoK7tUvrWiRlcoBHIZ809ElXwNQwVo0B98LuTXQ=="],
|
||||
|
||||
"@radix-ui/react-select": ["@radix-ui/react-select@2.3.7", "", { "dependencies": { "@radix-ui/number": "1.1.3", "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-focus-guards": "1.1.6", "@radix-ui/react-focus-scope": "1.1.16", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-popper": "1.3.7", "@radix-ui/react-portal": "1.1.17", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-slot": "1.3.3", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-layout-effect": "1.1.4", "@radix-ui/react-use-previous": "1.1.4", "@radix-ui/react-visually-hidden": "1.2.11", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-WFGImkmbzcfxeIwq/+4HvRN0pizBwbwQUED4I13ezQsDdfl38ZntN6TmR8XaSzPBqoCToe8rF75j6NPNDSzhbg=="],
|
||||
|
||||
"@radix-ui/react-slider": ["@radix-ui/react-slider@1.4.7", "", { "dependencies": { "@radix-ui/number": "1.1.3", "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-layout-effect": "1.1.4", "@radix-ui/react-use-previous": "1.1.4", "@radix-ui/react-use-size": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-mTSLf1GC/C0moWjTbvCM6Qn/gBjvlFt1azuWF2v7MN5C3Zq2U2J2lN3ZEYkpujuOU5Ro7A28wkviSxaKnG0BYg=="],
|
||||
|
||||
"@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.5" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-qx7oqnYbxnK9kYI9m317qmFmEgo6ywqWvbTogdj7cL9p3/yx4M48p7Rnw5z3H890cL/ow/EeWJsuTykeZVXP5Q=="],
|
||||
|
||||
"@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.21", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-roving-focus": "1.1.19", "@radix-ui/react-use-controllable-state": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-UKxJlZid7FVtsk/WTxj4i4uSEgj2Au+KBbS7SQyTlzMhhn+86Cz3tISZdTa87bfEfcuvZezf2ZsxD4xuEKtkog=="],
|
||||
|
||||
"@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.1.18", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-controllable-state": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7lonPlKfSacd20GlOBx2ltuVKz9oqWYZz+oMQyOltw6t1y2nyftj2ZmwwUHYn49kqfDWcp8dNZm5NgV+5Z+mug=="],
|
||||
|
||||
"@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.1.19", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-roving-focus": "1.1.19", "@radix-ui/react-toggle": "1.1.18", "@radix-ui/react-use-controllable-state": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-OtnwuSVjd1Ofi+AdnvhsjQdyuhCDwYs1w9RyB5BN/OavXOVQo42SYqQjwUnbPnaiPFBpQ9aX70dWeee+v2oBLA=="],
|
||||
|
||||
"@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-popper": "1.3.7", "@radix-ui/react-portal": "1.1.17", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-slot": "1.3.3", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-layout-effect": "1.1.4", "@radix-ui/react-visually-hidden": "1.2.11" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-6EamKFRRnlpdadndbZ6LMwycfwkwPte1B42hs6QA0gYhjaOKqW4PZ4pjaW9UrlDX5eVt/OjncE7BFTPL5nmZhg=="],
|
||||
|
||||
"@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ=="],
|
||||
|
||||
"@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-use-effect-event": "0.0.5", "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ=="],
|
||||
|
||||
"@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.5", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg=="],
|
||||
|
||||
"@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-umO/aJ+82CpOnhDZUTbILCQf7kU/g0iv+oGs/Q8jw7IkhWBzaEP4sA268PhFAJTFetbwp3ICc6ktpI4TqtxcIw=="],
|
||||
|
||||
"@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw=="],
|
||||
|
||||
"@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-XoSLhbRbqxFtgJoi2fNHA3C6pDlY34x508vUpUGoFZfvePfHXHbE1lC4FYFMnJWgiCRroSTw6fOsXQoVS9RwZg=="],
|
||||
|
||||
"@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.4", "", { "dependencies": { "@radix-ui/rect": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-cSOCh6JlkmfjLyNcLiu2nB4v+nm+dkZ+Q5KHWk/soo4U7ZLiEQFKHK9/YmtBHjfCEaU43IBKQOc4/uJmCaiCTQ=="],
|
||||
|
||||
"@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.4", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-D3anSY15EJoxrihpsXI6SMrmmonnQtR2ni7arO+Lfdg3O95b9hNXxONk8jA5C8ANdF/h5HMAxejgs8PWJ6rlhw=="],
|
||||
|
||||
"@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.11", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.10" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-NFS86RYYZb4/exihaESBGOpMJFz8MGLAfu3mOBSGByVnVPC9JPASfYubxd/8KbkQK0sYAv8lVQDEQukDX/qXvQ=="],
|
||||
|
||||
"@radix-ui/rect": ["@radix-ui/rect@1.1.3", "", {}, "sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw=="],
|
||||
|
||||
"@replit/codemirror-css-color-picker": ["@replit/codemirror-css-color-picker@6.3.0", "", { "peerDependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0" } }, "sha512-19biDANghUm7Fz7L1SNMIhK48tagaWuCOHj4oPPxc7hxPGkTVY2lU/jVZ8tsbTKQPVG7BO2CBDzs7CBwb20t4A=="],
|
||||
|
||||
"@rolldown/binding-android-arm-eabi": ["@rolldown/binding-android-arm-eabi@1.2.7", "", { "os": "android", "cpu": "arm" }, "sha512-EypzgnYCwyVY4NDHKzGmNJT5b+XaQEBniHxsMdeIQLB/tcCzZnhqrzHpZFbX9iaxx+5RiB8caATBtfvZP7zVxQ=="],
|
||||
@@ -661,6 +754,8 @@
|
||||
|
||||
"@tanstack/react-store": ["@tanstack/react-store@0.11.1", "", { "dependencies": { "@tanstack/store": "0.11.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-HaIGKI3YLmjBYIvy5DFDY23oNaYZIsTZfngey07Uh5iLVJgM3bIGCnZeOFOqzjFld9JHWcaHJnasD/bKoGKwJQ=="],
|
||||
|
||||
"@tanstack/react-table": ["@tanstack/react-table@8.21.3", "", { "dependencies": { "@tanstack/table-core": "8.21.3" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww=="],
|
||||
|
||||
"@tanstack/react-virtual": ["@tanstack/react-virtual@3.14.13", "", { "dependencies": { "@tanstack/virtual-core": "3.17.11" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-JbDTAwtzZ99aOeCrAfW5EsE5KSq5RWh6Af2dtFwyLIIk48Ja7vm6n4axu/43T3vfjFnEGJalxJ1wyYjSQD6bSg=="],
|
||||
|
||||
"@tanstack/router-core": ["@tanstack/router-core@1.171.30", "", { "dependencies": { "@tanstack/history": "1.162.4", "cookie-es": "^3.0.0", "seroval": "^1.6.2", "seroval-plugins": "^1.6.2" } }, "sha512-wtS1yCAb/k5CJBauvrCyqf2n4/kRc3aiz81tFBJ1QXH4Utsu81xFTMq15AdmNWgWmt2UstUSMfWi4Ua7ph2F+w=="],
|
||||
@@ -669,6 +764,8 @@
|
||||
|
||||
"@tanstack/store": ["@tanstack/store@0.11.1", "", {}, "sha512-mzTOBhypOuDJAy/D8n2MfUZ1HFkXnmSETviRyhqEC8LUE7/IZQExOTxMANj3KjTofYTkFNpBY67qaVrT41YccA=="],
|
||||
|
||||
"@tanstack/table-core": ["@tanstack/table-core@8.21.3", "", {}, "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg=="],
|
||||
|
||||
"@tanstack/virtual-core": ["@tanstack/virtual-core@3.17.11", "", {}, "sha512-+ILjvtHup6Y2hzQ6YzwMgX1Q+oQpxEGOXCEsCNaPoIP0VxMbizIBTmYTDtkerkIQS8/CbP1BRuyt8V/8BCsy1g=="],
|
||||
|
||||
"@tanstack/vue-virtual": ["@tanstack/vue-virtual@3.13.36", "", { "dependencies": { "@tanstack/virtual-core": "3.17.8" }, "peerDependencies": { "vue": "^2.7.0 || ^3.0.0" } }, "sha512-gKpExv4RbB9luVG+SucTXoqPZv/gzu/Yvz6BNO+8kpNxJ2x+I/ulryzl5W9BRciahZGp5Tls3Dp5XP1ztVGbMw=="],
|
||||
@@ -1097,6 +1194,8 @@
|
||||
|
||||
"cosmiconfig": ["cosmiconfig@9.0.2", "", { "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", "parse-json": "^5.2.0" }, "peerDependencies": { "typescript": ">=4.9.5" }, "optionalPeers": ["typescript"] }, "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg=="],
|
||||
|
||||
"country-flag-icons": ["country-flag-icons@1.6.20", "", {}, "sha512-py8JiEKzjhYw6HPJ0L7SxLgCYim36UPRTZX43/kqGueUCZLSvnrqAiwW8HtQibur7mdkFQUkjOgdK+o/9FBtaw=="],
|
||||
|
||||
"crelt": ["crelt@1.0.7", "", {}, "sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA=="],
|
||||
|
||||
"cross-dirname": ["cross-dirname@0.1.0", "", {}, "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q=="],
|
||||
@@ -1181,6 +1280,8 @@
|
||||
|
||||
"detect-node": ["detect-node@2.1.0", "", {}, "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="],
|
||||
|
||||
"detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="],
|
||||
|
||||
"devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="],
|
||||
|
||||
"diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="],
|
||||
@@ -1351,6 +1452,8 @@
|
||||
|
||||
"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-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="],
|
||||
|
||||
"get-own-enumerable-keys": ["get-own-enumerable-keys@1.0.0", "", {}, "sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA=="],
|
||||
|
||||
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
|
||||
@@ -1455,6 +1558,8 @@
|
||||
|
||||
"i18next": ["i18next@26.4.2", "", { "peerDependencies": { "typescript": "^5 || ^6 || ^7" }, "optionalPeers": ["typescript"] }, "sha512-RX+R0VLg13IbvRuJSxnqykUFS9vQZTl8wYpWPCIUDWVrSGjsQywB5Y+pjzrkboxGAuYfJZVH1InFTdgBdxq6ug=="],
|
||||
|
||||
"i18next-browser-languagedetector": ["i18next-browser-languagedetector@8.2.1", "", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-bZg8+4bdmaOiApD7N7BPT9W8MLZG+nPTOFlLiJiT8uzKXFjhxw4v2ierCXOwB5sFDMtuA5G4kgYZ0AznZxQ/cw=="],
|
||||
|
||||
"iconv-lite": ["iconv-lite@0.7.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ=="],
|
||||
|
||||
"identifier-regex": ["identifier-regex@1.1.0", "", { "dependencies": { "reserved-identifiers": "^1.0.0" } }, "sha512-SLX4H/vtcYlYnL7XqnuJKHU7Z8517TgsW9nmQiGOgMCjQ8V/deLYu6bEmbGoXe7WMMhc9+EUGyFFneHja8KabA=="],
|
||||
@@ -1935,10 +2040,20 @@
|
||||
|
||||
"react-dom": ["react-dom@19.3.0", "", { "dependencies": { "scheduler": "^0.28.0" }, "peerDependencies": { "react": "^19.3.0" } }, "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q=="],
|
||||
|
||||
"react-hot-toast": ["react-hot-toast@2.6.1", "", { "dependencies": { "csstype": "^3.1.3", "goober": "^2.1.16" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": ">=16", "react-dom": ">=16" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-gjFsf05dxcku0FkyMtFH+XmYFdA2odXfBVknEr/IZ+XpUjwsgvtY2616sOpUynK+l9ykQDRNpaJ1hYfuximUiA=="],
|
||||
|
||||
"react-i18next": ["react-i18next@17.0.14", "", { "dependencies": { "@babel/runtime": "^7.29.7", "html-parse-stringify": "^4.0.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "i18next": ">= 26.2.0", "react": ">= 16.8.0", "react-dom": "*", "react-native": "*", "typescript": "^5 || ^6 || ^7" }, "optionalPeers": ["react-dom", "react-native", "typescript"] }, "sha512-ZpMBfJL3BiXPuYHj5QMY1GwvKJNhE1vCxOJQ8BoMBdHP5XONTfi/Qss1nuRlnFdIl72PKo2jPmw+fxuLjRFgaQ=="],
|
||||
|
||||
"react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="],
|
||||
|
||||
"react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="],
|
||||
|
||||
"react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="],
|
||||
|
||||
"react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
|
||||
|
||||
"react-window": ["react-window@2.3.3", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-uu/dTwysXp+YL+i5GW/cC/3JrqyE7oE6DYXYVlTeMaDSDgCI+UGo+XCKwXfS8uoFPih8TJYTnikqjAnbDvn75Q=="],
|
||||
|
||||
"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@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
|
||||
@@ -2131,7 +2246,7 @@
|
||||
|
||||
"tagged-tag": ["tagged-tag@1.0.0", "", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="],
|
||||
|
||||
"tailwind-merge": ["tailwind-merge@3.5.0", "", {}, "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A=="],
|
||||
"tailwind-merge": ["tailwind-merge@3.7.0", "", {}, "sha512-XPPUyAc+cvspz3lHTcR/QgPfW2A0lv/xQNIjX3HGhLR+Nq2lHaLq5MtTesHn8GUr3W3DguT2KT5x3NVgRtYwmA=="],
|
||||
|
||||
"tailwindcss": ["tailwindcss@4.3.3", "", {}, "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ=="],
|
||||
|
||||
@@ -2243,6 +2358,10 @@
|
||||
|
||||
"update-browserslist-db": ["update-browserslist-db@1.3.2", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw=="],
|
||||
|
||||
"use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="],
|
||||
|
||||
"use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="],
|
||||
|
||||
"use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
|
||||
|
||||
"utf8-byte-length": ["utf8-byte-length@1.0.5", "", {}, "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA=="],
|
||||
@@ -2351,7 +2470,7 @@
|
||||
|
||||
"zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="],
|
||||
|
||||
"zustand": ["zustand@4.5.7", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw=="],
|
||||
"zustand": ["zustand@5.0.15", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-MpSEjRiBkA9crSYeOUH32rJC7SVqAbm0Fqcqge/bUi2PPoLcBWKOsG+C8mevmpr8TwXHBVkChbbJiyvkE+i/3A=="],
|
||||
|
||||
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
|
||||
|
||||
@@ -2419,6 +2538,8 @@
|
||||
|
||||
"@scalar/types/zod": ["zod@4.5.4", "", {}, "sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA=="],
|
||||
|
||||
"@scalar/use-hooks/tailwind-merge": ["tailwind-merge@3.5.0", "", {}, "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A=="],
|
||||
|
||||
"@tailwindcss/node/lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.11.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ=="],
|
||||
@@ -2457,6 +2578,8 @@
|
||||
|
||||
"@vue/compiler-sfc/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
||||
|
||||
"@xyflow/react/zustand": ["zustand@4.5.7", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw=="],
|
||||
|
||||
"accepts/mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="],
|
||||
|
||||
"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=="],
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ COPY electron/package.json ./electron/
|
||||
|
||||
RUN bun install --frozen-lockfile
|
||||
|
||||
# Build the maintained Electron renderer as the browser UI. `frontend/src`
|
||||
# Build the maintained Electron renderer as the browser UI. `electron/src/shared`
|
||||
# contains transitional shared modules only; it has no app entry point.
|
||||
COPY frontend/ ./frontend/
|
||||
COPY electron/ ./electron/
|
||||
|
||||
@@ -53,7 +53,7 @@ Live dictation uses a WebSocket, which cannot pass through the app protocol HTTP
|
||||
`apiJson<T>(path, init?)`; `audioUrl(filename)` → `/api/audio/<filename>`;
|
||||
`profileAudioUrl(id)` → `/api/profiles/<id>/audio`.
|
||||
- `@/lib/api/generate.ts`: `generateClone(input: CloneGenerateInput, opts?: { signal?: AbortSignal; onProgress?: (pct: number|null) => void }): Promise<GenerateResult>`;
|
||||
`sanitizeInstruct(free: string): { instruct: string; unsupported: string[]; duplicates: string[]; conflicts: string[] }` (port of frontend/src/utils/voiceInstruct.js buildDesignInstruct with empty vdStates);
|
||||
`sanitizeInstruct(free: string): { instruct: string; unsupported: string[]; duplicates: string[]; conflicts: string[] }` (port of electron/src/shared/utils/voiceInstruct.js buildDesignInstruct with empty vdStates);
|
||||
`CLONE_MAX_SECONDS = 15`, `REF_HARD_MAX_SECONDS = 75`.
|
||||
- `@/lib/api/profiles.ts`: `listProfiles()`, `createCloneProfile({ name, refAudio, refAudioName, refText, instruct, language })`, `deleteProfile(id)`.
|
||||
- `@/lib/api/history.ts`: `listHistory()`, `clearHistory()`, `deleteHistoryItem(id)`, `setHistoryStarred(id, starred)`.
|
||||
|
||||
@@ -75,6 +75,7 @@ export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve(__dirname, 'src/renderer/src'),
|
||||
'@shared': resolve(__dirname, 'src/shared'),
|
||||
// Scalar's optional AI client reaches a CommonJS browser entry that
|
||||
// native ESM cannot import by name. Mirror its browser API as real ESM.
|
||||
'@vercel/oidc': resolve(__dirname, 'src/renderer/src/lib/vercel-oidc-browser.ts'),
|
||||
|
||||
+21
-1
@@ -39,12 +39,24 @@
|
||||
"@electron-toolkit/preload": "^3.0.2",
|
||||
"@electron-toolkit/utils": "^4.0.0",
|
||||
"@fontsource-variable/inter": "^5.3.0",
|
||||
"@fontsource-variable/source-serif-4": "^5.3.0",
|
||||
"@fontsource/ibm-plex-mono": "^5.3.0",
|
||||
"@lobehub/icons-static-svg": "^1.95.0",
|
||||
"@radix-ui/react-dialog": "^1.1.23",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.24",
|
||||
"@radix-ui/react-progress": "^1.1.16",
|
||||
"@radix-ui/react-select": "^2.3.7",
|
||||
"@radix-ui/react-slider": "^1.4.7",
|
||||
"@radix-ui/react-slot": "^1.3.3",
|
||||
"@radix-ui/react-tabs": "^1.1.21",
|
||||
"@radix-ui/react-toggle": "^1.1.18",
|
||||
"@radix-ui/react-toggle-group": "^1.1.19",
|
||||
"@radix-ui/react-tooltip": "^1.2.16",
|
||||
"@scalar/api-reference-react": "^0.9.67",
|
||||
"@tanstack/react-form": "^1.33.5",
|
||||
"@tanstack/react-pacer": "^0.23.0",
|
||||
"@tanstack/react-query": "^5.102.8",
|
||||
"@tanstack/react-table": "^8.21.3",
|
||||
"@tanstack/react-router": "^1.170.36",
|
||||
"@tanstack/react-store": "^0.11.1",
|
||||
"@tanstack/react-virtual": "^3.14.13",
|
||||
@@ -52,24 +64,32 @@
|
||||
"@vidstack/react": "1.15.6",
|
||||
"@xyflow/react": "^12.12.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cn": "^0.3.0",
|
||||
"country-flag-icons": "^1.6.20",
|
||||
"dashjs": "^5.2.1",
|
||||
"electron-updater": "^6.8.9",
|
||||
"hls.js": "^1.7.3",
|
||||
"html-entities": "^2.6.0",
|
||||
"i18next": "^26.4.2",
|
||||
"i18next-browser-languagedetector": "^8.2.1",
|
||||
"lucide-react": "^1.46.0",
|
||||
"posthog-js": "^1.434.14",
|
||||
"proxy-agent": "6.5.0",
|
||||
"qrcode": "^1.5.4",
|
||||
"react": "^19.3.0",
|
||||
"react-dom": "^19.3.0",
|
||||
"react-hot-toast": "^2.6.0",
|
||||
"react-i18next": "^17.0.14",
|
||||
"react-window": "^2.3.1",
|
||||
"remotion": "4.0.524",
|
||||
"shadcn": "^4.21.0",
|
||||
"sonner": "^2.0.8",
|
||||
"tailwind-merge": "^3.6.0",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"wavesurfer.js": "^7.12.12",
|
||||
"word-extractor": "1.0.4"
|
||||
"word-extractor": "1.0.4",
|
||||
"zustand": "^5.0.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/vite": "^4.3.3",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { readFileSync, writeFileSync, renameSync } from 'node:fs';
|
||||
import type { NativeCrashRecord } from '../preload/index.d';
|
||||
import { nativeCrashExcerpt } from '../../../frontend/src/utils/crashReport';
|
||||
import { scrubText } from '../../../frontend/src/utils/scrub';
|
||||
import { nativeCrashExcerpt } from '../shared/utils/crashReport';
|
||||
import { scrubText } from '../shared/utils/scrub';
|
||||
|
||||
/** Small version-scoped local journal. Read failures must never block startup. */
|
||||
export class CrashJournal {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @vitest-environment node
|
||||
import { expect, it } from 'vitest';
|
||||
import { clampCrashTail } from '../../../frontend/src/utils/crashReport';
|
||||
import { clampCrashTail } from '../shared/utils/crashReport';
|
||||
|
||||
it.each(['Fatal Python error: Segmentation fault', 'Windows fatal exception: access violation'])(
|
||||
'preserves native fault frames under the report character limit: %s',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
||||
import { dirname } from 'node:path';
|
||||
import { scrubText } from '../../../frontend/src/utils/scrub';
|
||||
import { scrubText } from '../shared/utils/scrub';
|
||||
|
||||
const MAX_RECORDS = 20;
|
||||
const MAX_DETAIL = 20_000;
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
capturePageview,
|
||||
disableAnalytics,
|
||||
enableAnalytics,
|
||||
} from '../../../../../frontend/src/utils/analytics';
|
||||
} from '@shared/utils/analytics';
|
||||
import { routeBreadcrumb } from '@/lib/report-breadcrumb';
|
||||
|
||||
interface AnalyticsState {
|
||||
|
||||
@@ -27,7 +27,7 @@ import { getBridge } from '@/components/bridge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { getFrontendLogs } from '../../../../../../frontend/src/utils/consoleBuffer';
|
||||
import { getFrontendLogs } from '@shared/utils/consoleBuffer';
|
||||
import { useBackendStatus } from '@/hooks/use-backend-status';
|
||||
import type {
|
||||
RepairAgentId,
|
||||
|
||||
@@ -34,7 +34,7 @@ import { ComputeVendorIcon, formatComputeRuntime } from '@/components/compute-ve
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/popover';
|
||||
import { ComputeTargetChoices } from '@/components/compute-target-choices';
|
||||
import { useComputeRuntime, useComputeTarget } from '@/hooks/use-compute-target';
|
||||
import type { BatchJob } from '../../../../../../frontend/src/api/batch-types';
|
||||
import type { BatchJob } from '@shared/api/batch-types';
|
||||
import {
|
||||
IDLE_STATUS_POLL_MS,
|
||||
batchStatusPollMs,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useBackendStatus } from '@/hooks/use-backend-status';
|
||||
import { scrubText } from '../../../../../frontend/src/utils/scrub';
|
||||
import { describeExitCode } from '../../../../../frontend/src/utils/nativeExit';
|
||||
import { scrubText } from '@shared/utils/scrub';
|
||||
import { describeExitCode } from '@shared/utils/nativeExit';
|
||||
import { ReportBug } from './report-bug';
|
||||
import { getBridge } from './bridge';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { DICTATION_SCRIPTS } from '../../../../../frontend/src/utils/dictationScripts';
|
||||
import { DICTATION_SCRIPTS } from '@shared/utils/dictationScripts';
|
||||
import { apiFetch, apiJson, apiPath, ApiError } from '@/lib/api/client';
|
||||
import { Button } from './ui/button';
|
||||
import { AudioPreviewButton } from './audio-preview-button';
|
||||
|
||||
@@ -2,17 +2,17 @@ import {
|
||||
classifyError,
|
||||
urlFor,
|
||||
type ErrorClass,
|
||||
} from '../../../../../frontend/src/utils/errorDocsMap';
|
||||
} from '@shared/utils/errorDocsMap';
|
||||
import { ExternalLink } from './external-link';
|
||||
import { buildIssueSearchUrl } from '../../../../../frontend/src/utils/bugReportDocument';
|
||||
import { buildIssueSearchUrl } from '@shared/utils/bugReportDocument';
|
||||
import { Component, useEffect, type ReactNode, type ErrorInfo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { BotIcon, CircleAlertIcon } from 'lucide-react';
|
||||
import { scrubText } from '../../../../../frontend/src/utils/scrub';
|
||||
import { scrubText } from '@shared/utils/scrub';
|
||||
import { ReportBug } from './report-bug';
|
||||
import { Button } from './ui/button';
|
||||
import { openRepairAgent } from '@/lib/repair-agent-events';
|
||||
import { captureException } from '../../../../../frontend/src/utils/analytics';
|
||||
import { captureException } from '@shared/utils/analytics';
|
||||
|
||||
const MODULE_RETRY_PREFIX = 'voicestudio.moduleRetry:';
|
||||
const reloadRenderer = () => window.location.reload();
|
||||
|
||||
@@ -3,12 +3,12 @@ import { useTranslation } from 'react-i18next';
|
||||
import { useGenerateClone } from '@/hooks/use-generate';
|
||||
import { router } from '@/router';
|
||||
import { writeDraft } from '@/features/design/design-draft';
|
||||
import defaults from '../../../../../frontend/src/utils/firstSound.json';
|
||||
import defaults from '@shared/utils/firstSound.json';
|
||||
import {
|
||||
instructToVdStates,
|
||||
mergeDescribedAttrs,
|
||||
} from '../../../../../frontend/src/utils/voiceInstruct';
|
||||
import { pickDesignSeed } from '../../../../../frontend/src/utils/seed';
|
||||
} from '@shared/utils/voiceInstruct';
|
||||
import { pickDesignSeed } from '@shared/utils/seed';
|
||||
import { FIRST_SOUND_EVENT } from '@/lib/first-sound';
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
inlineSegments,
|
||||
parseBlocks,
|
||||
type MarkdownBlock,
|
||||
} from '../../../../../frontend/src/utils/markdownLite';
|
||||
} from '@shared/utils/markdownLite';
|
||||
|
||||
function InlineMarkdown({ text }: { text: string }) {
|
||||
return inlineSegments(text).map((segment, index) => {
|
||||
|
||||
@@ -17,7 +17,7 @@ import { RemotionProviderLoader } from '@vidstack/react/player/remotion';
|
||||
import { useEffect, useMemo, useRef, type RefObject } from 'react';
|
||||
import { claimPlayback } from '@/lib/audio/playback';
|
||||
import { useAecEnabled } from '@/lib/store/dictation-settings';
|
||||
import { attachPlaybackTap } from '../../../../../frontend/src/utils/aec/playbackTap';
|
||||
import { attachPlaybackTap } from '@shared/utils/aec/playbackTap';
|
||||
|
||||
export type { MediaPlayerInstance };
|
||||
export { useMediaState } from '@vidstack/react';
|
||||
|
||||
@@ -2,7 +2,7 @@ import { AlertCircleIcon, CopyIcon, XIcon } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import type { ReactNode } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { urlFor } from '../../../../../frontend/src/utils/errorDocsMap';
|
||||
import { urlFor } from '@shared/utils/errorDocsMap';
|
||||
import type { PublicFailure } from '@/lib/api/failure';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { ExternalLink } from './external-link';
|
||||
|
||||
@@ -14,11 +14,11 @@ vi.mock('@/hooks/use-backend-status', () => ({
|
||||
}));
|
||||
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import { afterEach, beforeEach, expect, it, vi } from 'vitest';
|
||||
import { addBreadcrumb, clearBreadcrumbs } from '../../../../../frontend/src/utils/breadcrumbs';
|
||||
import { addBreadcrumb, clearBreadcrumbs } from '@shared/utils/breadcrumbs';
|
||||
import {
|
||||
_resetBackendContactForTests,
|
||||
recordBackendContact,
|
||||
} from '../../../../../frontend/src/utils/backendContact';
|
||||
} from '@shared/utils/backendContact';
|
||||
const mock = vi.hoisted(() => ({
|
||||
crashed: false,
|
||||
native: true,
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { composeBugReportUrl } from '../../../../../frontend/src/utils/bugReportDocument';
|
||||
import { formatBreadcrumbs } from '../../../../../frontend/src/utils/breadcrumbs';
|
||||
import { contactAge, lastBackendContact } from '../../../../../frontend/src/utils/backendContact';
|
||||
import { clampCrashTail } from '../../../../../frontend/src/utils/crashReport';
|
||||
import { scrubText } from '../../../../../frontend/src/utils/scrub';
|
||||
import { describeExitCode, isNativeFaultExit } from '../../../../../frontend/src/utils/nativeExit';
|
||||
import { composeBugReportUrl } from '@shared/utils/bugReportDocument';
|
||||
import { formatBreadcrumbs } from '@shared/utils/breadcrumbs';
|
||||
import { contactAge, lastBackendContact } from '@shared/utils/backendContact';
|
||||
import { clampCrashTail } from '@shared/utils/crashReport';
|
||||
import { scrubText } from '@shared/utils/scrub';
|
||||
import { describeExitCode, isNativeFaultExit } from '@shared/utils/nativeExit';
|
||||
import {
|
||||
_adaptLastRunCrash,
|
||||
type LastRunCrashRecord,
|
||||
} from '../../../../../frontend/src/utils/runCrashRecord';
|
||||
} from '@shared/utils/runCrashRecord';
|
||||
import { getBackendStatusSnapshot } from '@/hooks/use-backend-status';
|
||||
import { apiJson } from '@/lib/api/client';
|
||||
import { router } from '@/router';
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { apiJson } from '@/lib/api/client';
|
||||
import type { PreflightReport } from '../../../../../frontend/src/api/setup-types';
|
||||
import type { PreflightReport } from '@shared/api/setup-types';
|
||||
import { SystemPreflight } from '@/features/settings/system-preflight';
|
||||
import { PermissionsSettings } from '@/features/settings/permissions-settings';
|
||||
import { SetupMediaEngine } from '@/features/settings/media-tools';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useRef, useState, type FormEvent, type ReactNode } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { KeyRoundIcon } from 'lucide-react';
|
||||
import { exchangeApiKey } from '../../../../../frontend/src/api/authSession';
|
||||
import { exchangeApiKey } from '@shared/api/authSession';
|
||||
import { absoluteApiBase, ApiError, apiFetch } from '@/lib/api/client';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
|
||||
@@ -32,10 +32,10 @@ import { useTtsReadiness } from '@/hooks/use-tts-readiness';
|
||||
import { getBridge } from '@/components/bridge';
|
||||
import { apiJson, apiPath, describeError } from '@/lib/api/client';
|
||||
import { saveExport } from '@/lib/export-history';
|
||||
import { LANG_CODES } from '../../../../../../frontend/src/utils/languages';
|
||||
import { PRESETS } from '../../../../../../frontend/src/utils/constants';
|
||||
import type { BatchJob } from '../../../../../../frontend/src/api/batch-types';
|
||||
import { generationFailureMessage } from '../../../../../../frontend/src/utils/generationFailureMessage';
|
||||
import { LANG_CODES } from '@shared/utils/languages';
|
||||
import { PRESETS } from '@shared/utils/constants';
|
||||
import type { BatchJob } from '@shared/api/batch-types';
|
||||
import { generationFailureMessage } from '@shared/utils/generationFailureMessage';
|
||||
import { enqueueVideos } from './enqueue';
|
||||
import { useTranslationEngines } from '@/features/settings/translation-settings';
|
||||
const languageOptions = LANG_CODES.map((item) => item.label);
|
||||
|
||||
@@ -8,7 +8,7 @@ import { describeError } from '@/lib/api/client';
|
||||
import {
|
||||
createIngestTracker,
|
||||
WATCH_POLL_MS,
|
||||
} from '../../../../../../frontend/src/utils/watchFolderTracker';
|
||||
} from '@shared/utils/watchFolderTracker';
|
||||
import type { WatchSelection } from '../../../../preload/index.d';
|
||||
|
||||
export function WatchFolder({
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { useNavigate } from '@tanstack/react-router';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FolderOpenIcon } from 'lucide-react';
|
||||
import type { ProfileUsage } from '../../../../../../frontend/src/api/types';
|
||||
import type { ProfileUsage } from '@shared/api/types';
|
||||
import { apiJson, describeError } from '@/lib/api/client';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { PipelineFailure } from '@/components/pipeline-failure';
|
||||
|
||||
@@ -2,8 +2,8 @@ import type { HistoryItem, Profile } from '@/lib/api/types';
|
||||
import {
|
||||
instructToVdStates,
|
||||
mergeDescribedAttrs,
|
||||
} from '../../../../../../frontend/src/utils/voiceInstruct';
|
||||
import { pickDesignSeed } from '../../../../../../frontend/src/utils/seed';
|
||||
} from '@shared/utils/voiceInstruct';
|
||||
import { pickDesignSeed } from '@shared/utils/seed';
|
||||
export const STORAGE = 'voicestudio.design.v1';
|
||||
export const DESIGN_DRAFT_EVENT = 'voicestudio:design-draft';
|
||||
|
||||
|
||||
@@ -50,13 +50,13 @@ import { queryKeys } from '@/lib/query';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { cloneSettingsStore } from '@/lib/store/clone-settings';
|
||||
import type { Profile } from '@/lib/api/types';
|
||||
import { CATEGORIES, PRESETS } from '../../../../../../frontend/src/utils/constants';
|
||||
import { CATEGORIES, PRESETS } from '@shared/utils/constants';
|
||||
import {
|
||||
applyVdState,
|
||||
buildDesignInstruct,
|
||||
mergeDescribedAttrs,
|
||||
} from '../../../../../../frontend/src/utils/voiceInstruct';
|
||||
import { pickDesignSeed } from '../../../../../../frontend/src/utils/seed';
|
||||
} from '@shared/utils/voiceInstruct';
|
||||
import { pickDesignSeed } from '@shared/utils/seed';
|
||||
export function DesignPage() {
|
||||
const { t } = useTranslation();
|
||||
const selectedTake = useSelectedTake();
|
||||
|
||||
@@ -12,7 +12,7 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { apiJson } from '@/lib/api/client';
|
||||
import { instructToVdStates } from '../../../../../../frontend/src/utils/voiceInstruct';
|
||||
import { instructToVdStates } from '@shared/utils/voiceInstruct';
|
||||
|
||||
interface Personality {
|
||||
id: string;
|
||||
|
||||
@@ -15,12 +15,12 @@ import {
|
||||
import { ProfileAvatar } from '@/components/profile-avatar';
|
||||
import type { Profile } from '@/lib/api/types';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { PRESETS } from '../../../../../../frontend/src/utils/constants';
|
||||
import { PRESETS } from '@shared/utils/constants';
|
||||
import {
|
||||
autoProfileId,
|
||||
castParts,
|
||||
castSpeakers,
|
||||
} from '../../../../../../frontend/src/utils/segments';
|
||||
} from '@shared/utils/segments';
|
||||
import type { DubSegment } from './dub-session';
|
||||
|
||||
const DEFAULT_VOICE = '__default__';
|
||||
|
||||
@@ -7,18 +7,18 @@ import { AgentFixButton } from '@/components/agent-fix-button';
|
||||
import { getBridge } from '@/components/bridge';
|
||||
import { WorkspaceHeader } from '@/components/app-shell/workspace-header';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { MAX_COOKIE_EXPORT_BYTES } from '../../../../../../frontend/src/utils/cookieExport';
|
||||
import { MAX_COOKIE_EXPORT_BYTES } from '@shared/utils/cookieExport';
|
||||
import {
|
||||
hasCompleteTranslation,
|
||||
multiLangTargets,
|
||||
} from '../../../../../../frontend/src/utils/multiLang';
|
||||
import { segmentGenInputs } from '../../../../../../frontend/src/utils/segments';
|
||||
import { clampSegmentEdit } from '../../../../../../frontend/src/utils/timeline';
|
||||
} from '@shared/utils/multiLang';
|
||||
import { segmentGenInputs } from '@shared/utils/segments';
|
||||
import { clampSegmentEdit } from '@shared/utils/timeline';
|
||||
import {
|
||||
dialectLabel,
|
||||
dialectMatchesLang,
|
||||
dialectOptionsFor,
|
||||
} from '../../../../../../frontend/src/api/dialects';
|
||||
} from '@shared/api/dialects';
|
||||
import { DubExportPanel } from './dub-export-panel';
|
||||
import { DubTimeline } from './dub-timeline';
|
||||
import { PasteTranslation } from './paste-translation';
|
||||
@@ -97,7 +97,7 @@ import { apiFetch, apiJson, apiPath, describeError, isAbortError } from '@/lib/a
|
||||
import { createObjectUrl, revokeObjectUrl } from '@/lib/audio/object-url';
|
||||
import { requestPlaybackSeek } from '@/lib/audio/playback-clock';
|
||||
import { beginAppActivity } from '@/lib/app-activity';
|
||||
import { LANG_CODES } from '../../../../../../frontend/src/utils/languages';
|
||||
import { LANG_CODES } from '@shared/utils/languages';
|
||||
import { cn } from '@/lib/utils';
|
||||
import {
|
||||
useDubSession,
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { DubExportPreferences } from './dub-export';
|
||||
import {
|
||||
MAX_COOKIE_EXPORT_BYTES,
|
||||
_cookieTransportAllowed,
|
||||
} from '../../../../../../frontend/src/utils/cookieExport';
|
||||
} from '@shared/utils/cookieExport';
|
||||
import { projectSession, type DubProject } from '../projects/project-format';
|
||||
import { DUB_DRAFT_KEY, restoreDubDraft } from './dub-draft';
|
||||
import { Store } from '@tanstack/store';
|
||||
@@ -22,8 +22,8 @@ import {
|
||||
settleCueSources,
|
||||
withOriginalCueSource,
|
||||
withoutCueSource,
|
||||
} from '../../../../../../frontend/src/utils/segments';
|
||||
import { hasCompleteTranslation } from '../../../../../../frontend/src/utils/multiLang';
|
||||
} from '@shared/utils/segments';
|
||||
import { hasCompleteTranslation } from '@shared/utils/multiLang';
|
||||
import {
|
||||
ATTRIBUTION_FIELDS,
|
||||
applyAttribution,
|
||||
@@ -36,9 +36,9 @@ import {
|
||||
nextSegmentId,
|
||||
partsFor,
|
||||
type SegmentPart,
|
||||
} from '../../../../../../frontend/src/utils/segmentParts';
|
||||
import { commitMoveResize } from '../../../../../../frontend/src/utils/timeline';
|
||||
import type { PasteTranslationRow } from '../../../../../../frontend/src/utils/pasteTranslations';
|
||||
} from '@shared/utils/segmentParts';
|
||||
import { commitMoveResize } from '@shared/utils/timeline';
|
||||
import type { PasteTranslationRow } from '@shared/utils/pasteTranslations';
|
||||
import type {
|
||||
DubAgentTranslationRequest,
|
||||
DubAgentTranslationResult,
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
nearestOnset,
|
||||
snapCandidates,
|
||||
snapTime,
|
||||
} from '../../../../../../frontend/src/utils/timeline';
|
||||
} from '@shared/utils/timeline';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { cn } from '@/lib/utils';
|
||||
import {
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
* Carrying a finished dub into the Stories editor.
|
||||
*
|
||||
* The transform itself is shared with the browser app
|
||||
* (`frontend/src/utils/dubToStory`); this is the Electron wiring around it, kept
|
||||
* (`electron/src/shared/utils/dubToStory`); this is the Electron wiring around it, kept
|
||||
* out of `dub-page.tsx` so the rules that decide whether the action is offered,
|
||||
* and what it overwrites, can be tested without mounting the page.
|
||||
*/
|
||||
import { dubToStory } from '../../../../../../frontend/src/utils/dubToStory';
|
||||
import { dubToStory } from '@shared/utils/dubToStory';
|
||||
import {
|
||||
editLongform,
|
||||
longformSession,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { readTextFile } from '../../../../../../frontend/src/utils/readTextFile';
|
||||
import { readTextFile } from '@shared/utils/readTextFile';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { AlertTriangleIcon, ClipboardPasteIcon, FileTextIcon, XIcon } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
detectPasteMode,
|
||||
type PasteTranslationCue,
|
||||
type PasteTranslationRow,
|
||||
} from '../../../../../../frontend/src/utils/pasteTranslations';
|
||||
} from '@shared/utils/pasteTranslations';
|
||||
import type { DubSegment } from './dub-session';
|
||||
|
||||
const PREVIEW_LIMIT = 120;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { createStreamingPreview, supportsStreamingPreview } from '@/lib/audio/st
|
||||
import { backendWebSocketUrl } from '@/lib/api/websocket';
|
||||
import { beginAppActivity } from '@/lib/app-activity';
|
||||
import { acquireSynthesis } from '@/lib/synthesis-lock';
|
||||
import { segmentGenInputs } from '../../../../../../frontend/src/utils/segments';
|
||||
import { segmentGenInputs } from '@shared/utils/segments';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
@@ -15,11 +15,11 @@ import { STORAGE, readDraft } from '@/features/design/design-draft';
|
||||
import {
|
||||
instructToVdStates,
|
||||
mergeDescribedAttrs,
|
||||
} from '../../../../../../frontend/src/utils/voiceInstruct';
|
||||
} from '@shared/utils/voiceInstruct';
|
||||
import type {
|
||||
CommunityItem,
|
||||
CommunityPage,
|
||||
} from '../../../../../../frontend/src/api/community-types';
|
||||
} from '@shared/api/community-types';
|
||||
import type { Profile } from '@/lib/api/types';
|
||||
import type { Mode } from '@/features/longform/longform-session';
|
||||
import { placeLongformVoice } from './place-voice';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { apiJson } from '@/lib/api/client';
|
||||
import type { ArchetypePage } from '../../../../../../frontend/src/api/archetypes-types';
|
||||
import type { ArchetypePage } from '@shared/api/archetypes-types';
|
||||
export const FAVORITES_KEY = 'voicestudio.gallery.favorites.v1';
|
||||
export function readFavorites(): string[] {
|
||||
try {
|
||||
|
||||
@@ -16,7 +16,7 @@ import { VoiceDestinations } from './voice-destinations';
|
||||
import { placeLongformVoice } from './place-voice';
|
||||
import type { Mode } from '@/features/longform/longform-session';
|
||||
import { ImportsView } from './imports-view';
|
||||
import { FACETS } from '../../../../../../frontend/src/components/gallery/facets';
|
||||
import { FACETS } from '@shared/components/gallery/facets';
|
||||
import { FAVORITES_KEY, readFavorites, favoriteCatalogue } from './favorites';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useNavigate } from '@tanstack/react-router';
|
||||
@@ -33,8 +33,8 @@ import type { Profile } from '@/lib/api/types';
|
||||
import type {
|
||||
ArchetypePage,
|
||||
ArchetypeCategory,
|
||||
} from '../../../../../../frontend/src/api/archetypes-types';
|
||||
import { mergeDescribedAttrs } from '../../../../../../frontend/src/utils/voiceInstruct';
|
||||
} from '@shared/api/archetypes-types';
|
||||
import { mergeDescribedAttrs } from '@shared/utils/voiceInstruct';
|
||||
import { STORAGE, readDraft } from '@/features/design/design-draft';
|
||||
import { setCloneSetting } from '@/lib/store/clone-settings';
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ import type {
|
||||
DownloadParams,
|
||||
GalleryVoice,
|
||||
YoutubeSearchResult,
|
||||
} from '../../../../../../frontend/src/api/gallery-types';
|
||||
import type { PersonaImportResult } from '../../../../../../frontend/src/api/types';
|
||||
} from '@shared/api/gallery-types';
|
||||
import type { PersonaImportResult } from '@shared/api/types';
|
||||
export type { GalleryVoice, YoutubeSearchResult };
|
||||
export const importsApi = {
|
||||
list: (signal?: AbortSignal) => apiJson<GalleryVoice[]>('/gallery/voices', { signal }),
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
decodeToMonoLowRate,
|
||||
sliceToMono,
|
||||
encodeWav,
|
||||
} from '../../../../../../frontend/src/utils/audioTrim';
|
||||
} from '@shared/utils/audioTrim';
|
||||
|
||||
const MAX_TRIM_SECONDS = 60;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import '@/i18n';
|
||||
import { IntegrationDetailPage } from './integration-detail-page';
|
||||
import { INTEGRATION_SETUPS } from './setup-registry';
|
||||
import en from '@/i18n/locales/en.json';
|
||||
vi.mock('../../../../../../frontend/src/config/sponsors', () => ({
|
||||
vi.mock('@shared/config/sponsors', () => ({
|
||||
SPONSORS: [
|
||||
{ name: 'Example sponsor', url: 'https://example.org', logoUrl: '/example.svg', tier: 'gold' },
|
||||
],
|
||||
|
||||
@@ -22,8 +22,8 @@ import {
|
||||
getIntegrationBySlug,
|
||||
integrationSlug,
|
||||
type IntegrationCatalogEntry,
|
||||
} from '../../../../../../frontend/src/config/integration-catalog';
|
||||
import { SPONSORS } from '../../../../../../frontend/src/config/sponsors';
|
||||
} from '@shared/config/integration-catalog';
|
||||
import { SPONSORS } from '@shared/config/sponsors';
|
||||
import './integrations-page.css';
|
||||
|
||||
/** Catalog entries and featured sponsors both have an in-app page. */
|
||||
|
||||
@@ -18,7 +18,7 @@ vi.mock('@/components/app-shell/workspace-header', () => ({
|
||||
vi.mock('@/hooks/use-backend-status', () => ({
|
||||
useBackendStatus: () => ({ baseUrl: 'http://127.0.0.1:3912' }),
|
||||
}));
|
||||
vi.mock('../../../../../../frontend/src/config/sponsors', () => ({
|
||||
vi.mock('@shared/config/sponsors', () => ({
|
||||
SPONSORS: [
|
||||
{ name: 'Acme Voice', logoUrl: 'acme.svg', url: 'https://acme.example', tier: 'gold' },
|
||||
],
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
INTEGRATION_CATALOG,
|
||||
integrationSlug,
|
||||
getIntegrationBySlug,
|
||||
} from '../../../../../../frontend/src/config/integration-catalog';
|
||||
} from '@shared/config/integration-catalog';
|
||||
import {
|
||||
INTEGRATION_CATEGORIES,
|
||||
integrationCategoryKey,
|
||||
|
||||
@@ -8,8 +8,8 @@ import { Input } from '@/components/ui/input';
|
||||
import {
|
||||
INTEGRATION_CATALOG,
|
||||
integrationSlug,
|
||||
} from '../../../../../../frontend/src/config/integration-catalog';
|
||||
import { SPONSORS } from '../../../../../../frontend/src/config/sponsors';
|
||||
} from '@shared/config/integration-catalog';
|
||||
import { SPONSORS } from '@shared/config/sponsors';
|
||||
import { integrationSetup } from './setup-registry';
|
||||
import { INTEGRATION_CATEGORIES, integrationCategoryKey } from './integration-categories';
|
||||
import './integrations-page.css';
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
} from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, buttonVariants } from '@/components/ui/button';
|
||||
import { TAGS } from '../../../../../../frontend/src/utils/constants';
|
||||
import { TAGS } from '@shared/utils/constants';
|
||||
|
||||
export function AudiobookMarkupToolbar({
|
||||
textareaRef,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { expect, it } from 'vitest';
|
||||
import { buildAutoCast } from '../../../../../../frontend/src/utils/autoCast';
|
||||
import { buildAutoCast } from '@shared/utils/autoCast';
|
||||
it('preserves assigned character voices and appends only new speakers', () => {
|
||||
const cast = [{ id: 'existing', name: 'Mara', profileId: 'actor' }];
|
||||
const result = buildAutoCast('[Mara] Hello.\n[Guest] Welcome.', cast, [{ id: 'narrator' }]);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* occupies no time in the finished file. Give it a cue and every later
|
||||
* timestamp is wrong by that chapter's would-be duration.
|
||||
*
|
||||
* The timecode maths lives in `frontend/src/utils/storyExport` and is tested
|
||||
* The timecode maths lives in `electron/src/shared/utils/storyExport` and is tested
|
||||
* there; this pins the part that is specific to a render — which chapters
|
||||
* count, and when there is nothing worth downloading.
|
||||
*/
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
buildCueSheet,
|
||||
cueSheetFilename,
|
||||
cuesFromChapters,
|
||||
} from '../../../../../../frontend/src/utils/storyExport';
|
||||
} from '@shared/utils/storyExport';
|
||||
import type { AudiobookRenderChapter } from './longform-session';
|
||||
|
||||
const RENDERED: ReadonlySet<string> = new Set(['done', 'cached']);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { readTextFile } from '../../../../../../frontend/src/utils/readTextFile';
|
||||
import { readTextFile } from '@shared/utils/readTextFile';
|
||||
import { ProfileAvatar } from '@/components/profile-avatar';
|
||||
import {
|
||||
BookOpenTextIcon,
|
||||
@@ -12,7 +12,7 @@ import { AudioLinesIcon } from 'lucide-react';
|
||||
import { SecondarySidebar } from '@/components/workspace-sidebar';
|
||||
import { WorkspaceHeader } from '@/components/app-shell/workspace-header';
|
||||
import { PipelineFailure } from '@/components/pipeline-failure';
|
||||
import { importToText } from '../../../../../../frontend/src/utils/importStory';
|
||||
import { importToText } from '@shared/utils/importStory';
|
||||
import { cueSheetFor } from './cue-sheet';
|
||||
import { saveLocalFile } from '@/lib/local-export';
|
||||
import { StoryCast, StoryEditor } from './story-editor';
|
||||
@@ -31,7 +31,7 @@ import {
|
||||
scriptStats,
|
||||
formatRuntimeClock,
|
||||
validateScript,
|
||||
} from '../../../../../../frontend/src/utils/audiobookScript';
|
||||
} from '@shared/utils/audiobookScript';
|
||||
import { BookSettings } from './book-settings';
|
||||
import { duplicateWords } from './book-options';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
@@ -52,7 +52,7 @@ import { useProfiles } from '@/hooks/use-profiles';
|
||||
import { apiJson, apiPath, describeError } from '@/lib/api/client';
|
||||
import { saveExport } from '@/lib/export-history';
|
||||
import { EngineLanguagePicker } from '@/features/clone/engine-language-picker';
|
||||
import { LANG_CODES } from '../../../../../../frontend/src/utils/languages';
|
||||
import { LANG_CODES } from '@shared/utils/languages';
|
||||
import {
|
||||
editLongform,
|
||||
dismissLongformError,
|
||||
@@ -62,7 +62,7 @@ import {
|
||||
storiesImportEpoch,
|
||||
type Mode,
|
||||
} from './longform-session';
|
||||
import { SAMPLE_AUDIOBOOK_SCRIPT } from '../../../../../../frontend/src/data/sampleAudiobook';
|
||||
import { SAMPLE_AUDIOBOOK_SCRIPT } from '@shared/data/sampleAudiobook';
|
||||
import { useTtsReadiness } from '@/hooks/use-tts-readiness';
|
||||
interface Recovery {
|
||||
job_id: string;
|
||||
|
||||
@@ -2,16 +2,16 @@ import {
|
||||
DEFAULT_OVERRIDES,
|
||||
overridesToRequest,
|
||||
type Overrides,
|
||||
} from '../../../../../../frontend/src/utils/longformOverrides';
|
||||
} from '@shared/utils/longformOverrides';
|
||||
import { castVoice } from './cast-map';
|
||||
import { parseCastNames } from '../../../../../../frontend/src/utils/audiobookScript';
|
||||
import { parseCastNames } from '@shared/utils/audiobookScript';
|
||||
import { restoreBookOptions, lexiconMap, type BookOptions } from './book-options';
|
||||
import { createCoalescedJsonStorage } from '../../../../../../frontend/src/utils/coalescedJsonStorage';
|
||||
import { createCoalescedJsonStorage } from '@shared/utils/coalescedJsonStorage';
|
||||
import { Store } from '@tanstack/store';
|
||||
import { useStore } from '@tanstack/react-store';
|
||||
import { apiFetch } from '@/lib/api/client';
|
||||
import { consumeLongformStream } from '../../../../../../frontend/src/utils/longformStream';
|
||||
import { storyToSpans } from '../../../../../../frontend/src/utils/storyToSpans';
|
||||
import { consumeLongformStream } from '@shared/utils/longformStream';
|
||||
import { storyToSpans } from '@shared/utils/storyToSpans';
|
||||
import { beginAppActivity } from '@/lib/app-activity';
|
||||
import { publicFailureFromEvent, type PublicFailure } from '@/lib/api/failure';
|
||||
export type Mode = 'stories' | 'audiobook';
|
||||
|
||||
@@ -5,7 +5,7 @@ import i18n from '@/i18n';
|
||||
import {
|
||||
DEFAULT_OVERRIDES,
|
||||
overridesToRequest,
|
||||
} from '../../../../../../frontend/src/utils/longformOverrides';
|
||||
} from '@shared/utils/longformOverrides';
|
||||
import { ProductionSettings } from './production-settings';
|
||||
it('shows effective legacy joins for untouched and reset drafts', () => {
|
||||
render(
|
||||
|
||||
@@ -8,7 +8,7 @@ import { apiJson } from '@/lib/api/client';
|
||||
import {
|
||||
DEFAULT_OVERRIDES,
|
||||
type Overrides,
|
||||
} from '../../../../../../frontend/src/utils/longformOverrides';
|
||||
} from '@shared/utils/longformOverrides';
|
||||
const knobs = [
|
||||
{ key: 'numStep', label: 'steps', min: 8, max: 64, step: 1, value: 32 },
|
||||
{ key: 'guidanceScale', label: 'cfg', min: 0, max: 4, step: 0.1, value: 2 },
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { expect, it } from 'vitest';
|
||||
import { createProjectLibrary } from './project-library';
|
||||
import { blankLongformDraft } from './longform-session';
|
||||
import type { DurableLongformRecord } from '../../../../../../frontend/src/utils/indexedDbLongformStore';
|
||||
import type { DurableLongformRecord } from '@shared/utils/indexedDbLongformStore';
|
||||
it('serializes simultaneous saves without losing a project and snapshots inputs', async () => {
|
||||
let record: DurableLongformRecord | null = null;
|
||||
const library = createProjectLibrary({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
createIndexedDbLongformStore,
|
||||
type LongformDurableStore,
|
||||
} from '../../../../../../frontend/src/utils/indexedDbLongformStore';
|
||||
} from '@shared/utils/indexedDbLongformStore';
|
||||
import type { Draft, Mode } from './longform-session';
|
||||
export interface LongformProject {
|
||||
id: string;
|
||||
|
||||
@@ -7,14 +7,14 @@ import {
|
||||
SPLIT_MODES,
|
||||
splitStoryText,
|
||||
type SplitMode,
|
||||
} from '../../../../../../frontend/src/utils/splitStoryText';
|
||||
} from '@shared/utils/splitStoryText';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { buildAutoCast } from '../../../../../../frontend/src/utils/autoCast';
|
||||
import { buildAutoCast } from '@shared/utils/autoCast';
|
||||
import {
|
||||
SAMPLE_STORY_CAST,
|
||||
SAMPLE_STORY_LINES,
|
||||
SAMPLE_STORY_NAME,
|
||||
} from '../../../../../../frontend/src/data/sampleStory';
|
||||
} from '@shared/data/sampleStory';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
ArrowDownIcon,
|
||||
@@ -46,7 +46,7 @@ import {
|
||||
} from '@/components/ui/select';
|
||||
import { PipelineFailure } from '@/components/pipeline-failure';
|
||||
import { describeError } from '@/lib/api/client';
|
||||
import { reorder } from '../../../../../../frontend/src/utils/storyReorder';
|
||||
import { reorder } from '@shared/utils/storyReorder';
|
||||
import type { Draft } from './longform-session';
|
||||
interface Props {
|
||||
draft: Draft;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { expect, it } from 'vitest';
|
||||
import { importToText } from '../../../../../../frontend/src/utils/importStory';
|
||||
import { importToText } from '@shared/utils/importStory';
|
||||
import {
|
||||
splitIntoChunks,
|
||||
splitStoryText,
|
||||
} from '../../../../../../frontend/src/utils/splitStoryText';
|
||||
} from '@shared/utils/splitStoryText';
|
||||
it('removes SRT metadata and retains spoken lines', () => {
|
||||
expect(
|
||||
importToText(
|
||||
@@ -43,7 +43,7 @@ it('split presets give one line per paragraph or per chapter, headings kept sepa
|
||||
});
|
||||
|
||||
it('decodes a UTF-16 manuscript before extracting subtitle speech', async () => {
|
||||
const { readTextFile } = await import('../../../../../../frontend/src/utils/readTextFile');
|
||||
const { readTextFile } = await import('@shared/utils/readTextFile');
|
||||
const text = '1\n00:00:01,000 --> 00:00:02,000\nCafé — hello';
|
||||
const bytes = new Uint8Array(2 + text.length * 2);
|
||||
bytes.set([0xff, 0xfe]);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { storyToSpans } from '../../../../../../frontend/src/utils/storyToSpans';
|
||||
import { storyToSpans } from '@shared/utils/storyToSpans';
|
||||
import { castVoice } from './cast-map';
|
||||
import type { Draft } from './longform-session';
|
||||
export function storyVoicesReady(draft: Draft, profiles: { id: string }[]) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { afterEach, expect, it, vi } from 'vitest';
|
||||
import { exportStoryAudio } from '../../../../../../frontend/src/utils/storyExport';
|
||||
import { exportStoryAudio } from '@shared/utils/storyExport';
|
||||
import { storyChunkBody } from './story-preview';
|
||||
import { blankLongformDraft } from './longform-session';
|
||||
afterEach(() => vi.unstubAllGlobals());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { apiFetch } from '@/lib/api/client';
|
||||
import { exportStoryAudio, exportStems } from '../../../../../../frontend/src/utils/storyExport';
|
||||
import { overridesToRequest } from '../../../../../../frontend/src/utils/longformOverrides';
|
||||
import { exportStoryAudio, exportStems } from '@shared/utils/storyExport';
|
||||
import { overridesToRequest } from '@shared/utils/longformOverrides';
|
||||
import { resolveStoryVoice } from './story-inputs';
|
||||
import type { Draft, Line } from './longform-session';
|
||||
import { beginAppActivity } from '@/lib/app-activity';
|
||||
|
||||
@@ -15,7 +15,7 @@ import { cn } from '@/lib/utils';
|
||||
import {
|
||||
activeWordIndex,
|
||||
buildLyricsTimeline,
|
||||
} from '../../../../../../frontend/src/utils/audiobookLyrics';
|
||||
} from '@shared/utils/audiobookLyrics';
|
||||
import type { AudiobookRenderChapter } from './longform-session';
|
||||
|
||||
interface TimelineWord {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { LANG_CODES } from '../../../../../../frontend/src/utils/languages';
|
||||
import { LANG_CODES } from '@shared/utils/languages';
|
||||
import { restoreDubDraft } from '../dub/dub-draft';
|
||||
import type { DubSession } from '../dub/dub-session';
|
||||
export interface DubProject {
|
||||
|
||||
@@ -57,8 +57,8 @@ import {
|
||||
removeTranscription,
|
||||
subscribeTranscriptions,
|
||||
type TranscriptEntry,
|
||||
} from '../../../../../../frontend/src/utils/transcriptionsStore';
|
||||
import { preferredTranscript } from '../../../../../../frontend/src/utils/transcriptionFormat';
|
||||
} from '@shared/utils/transcriptionsStore';
|
||||
import { preferredTranscript } from '@shared/utils/transcriptionFormat';
|
||||
import {
|
||||
useDubSession,
|
||||
openDubProject,
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
removeTranscription,
|
||||
subscribeTranscriptions,
|
||||
TRANSCRIPTIONS_KEY,
|
||||
} from '../../../../../../frontend/src/utils/transcriptionsStore';
|
||||
} from '@shared/utils/transcriptionsStore';
|
||||
beforeEach(() => localStorage.clear());
|
||||
afterEach(() => vi.restoreAllMocks());
|
||||
it('deletes from fresh storage and notifies mounted library subscribers', () => {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Switch } from '@/components/ui/switch';
|
||||
import { apiJson } from '@/lib/api/client';
|
||||
import { SettingsSection, SettingsRow } from './settings-layout';
|
||||
import { useSettingsAction } from './use-settings-action';
|
||||
import { PROVIDER_FIELDS } from '../../../../../../frontend/src/utils/translationProviderFields';
|
||||
import { PROVIDER_FIELDS } from '@shared/utils/translationProviderFields';
|
||||
interface TokenState {
|
||||
active: string | null;
|
||||
sources: {
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
} from '@/components/ui/dialog';
|
||||
import { apiJson, describeError } from '@/lib/api/client';
|
||||
import type { DataDirectorySelection, DataRelocationStage } from '../../../../preload/index.d';
|
||||
import { fmtBytes } from '../../../../../../frontend/src/components/settings/models/format';
|
||||
import { fmtBytes } from '@shared/components/settings/models/format';
|
||||
import { SettingsRow, SettingsSection } from './settings-layout';
|
||||
|
||||
function relocationError(t: (key: string) => string, error: unknown): string {
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
progressPct,
|
||||
isGoalMet,
|
||||
formatMoney,
|
||||
} from '../../../../../../frontend/src/api/donation';
|
||||
} from '@shared/api/donation';
|
||||
import snapshotUrl from '../../../../../public/donation_progress.json?url';
|
||||
|
||||
export function DonationGoal() {
|
||||
|
||||
@@ -14,7 +14,7 @@ import { cn } from '@/lib/utils';
|
||||
import {
|
||||
getFrontendLogs,
|
||||
clearFrontendLogs,
|
||||
} from '../../../../../../frontend/src/utils/consoleBuffer';
|
||||
} from '@shared/utils/consoleBuffer';
|
||||
interface LogResponse {
|
||||
lines: string[];
|
||||
path?: string;
|
||||
|
||||
@@ -37,7 +37,7 @@ import { SettingsSection, SettingsRow } from './settings-layout';
|
||||
import { familyIcons, type ModelFamily } from './model-family';
|
||||
import { useModelCatalogue, type CatalogueModel } from './model-catalogue-query';
|
||||
import { resolvePerformanceModelPack } from './performance-model-packs';
|
||||
import { fmtBytes } from '../../../../../../frontend/src/components/settings/models/format';
|
||||
import { fmtBytes } from '@shared/components/settings/models/format';
|
||||
import {
|
||||
engineSelectionFeedback,
|
||||
type EngineSelectionResult,
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Input } from '@/components/ui/input';
|
||||
import { apiJson } from '@/lib/api/client';
|
||||
import { SettingsSection, SettingsRow } from './settings-layout';
|
||||
import { useSettingsAction } from './use-settings-action';
|
||||
import { saveProxyPreference } from '../../../../../../frontend/src/utils/networkPreferences';
|
||||
import { saveProxyPreference } from '@shared/utils/networkPreferences';
|
||||
export function NetworkSettings() {
|
||||
const { t } = useTranslation();
|
||||
const client = useQueryClient();
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Switch } from '@/components/ui/switch';
|
||||
import { apiJson } from '@/lib/api/client';
|
||||
import { SettingsSection, SettingsRow } from './settings-layout';
|
||||
import { useSettingsAction } from './use-settings-action';
|
||||
import { translatorPrivacy } from '../../../../../../frontend/src/utils/translatorPrivacy';
|
||||
import { translatorPrivacy } from '@shared/utils/translatorPrivacy';
|
||||
export function PrivacySettings({ showAnalytics = true }: { showAnalytics?: boolean } = {}) {
|
||||
const { t } = useTranslation();
|
||||
const info = useQuery({
|
||||
|
||||
@@ -6,7 +6,7 @@ import { apiJson } from '@/lib/api/client';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { SettingsSection, SettingsRow } from './settings-layout';
|
||||
import { refineFailureNoteKey } from '../../../../../../frontend/src/components/settings/refineStatus';
|
||||
import { refineFailureNoteKey } from '@shared/components/settings/refineStatus';
|
||||
const flags = ['auto', 'smart_cleanup', 'self_correction', 'preserve_technical'] as const;
|
||||
type Config = Record<(typeof flags)[number], boolean> & {
|
||||
llm_ready: boolean;
|
||||
|
||||
@@ -32,7 +32,7 @@ import { apiFetch, describeError } from '@/lib/api/client';
|
||||
import { projectLibrary } from '@/features/longform/project-library';
|
||||
import { clearLongformDraftForReset } from '@/features/longform/longform-session';
|
||||
import { clearDubDraftForReset } from '@/features/dub/dub-session';
|
||||
import { fmtBytes } from '../../../../../../frontend/src/components/settings/models/format';
|
||||
import { fmtBytes } from '@shared/components/settings/models/format';
|
||||
import { SettingsSection } from './settings-layout';
|
||||
import { forgetSetupProgress } from '@/lib/setup-progress';
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
import {
|
||||
keyEventToAccelerator,
|
||||
isPureModifierEvent,
|
||||
} from '../../../../../../frontend/src/utils/shortcutAccelerator';
|
||||
} from '@shared/utils/shortcutAccelerator';
|
||||
import { SettingsSection, SettingsRow } from './settings-layout';
|
||||
|
||||
export function ShortcutSettings() {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { getBridge } from '@/components/bridge';
|
||||
import { SettingsSection } from './settings-layout';
|
||||
import { HistoryRetention } from './privacy-settings';
|
||||
import { useSettingsAction } from './use-settings-action';
|
||||
import { fmtBytes } from '../../../../../../frontend/src/components/settings/models/format';
|
||||
import { fmtBytes } from '@shared/components/settings/models/format';
|
||||
import { ModelsDirectorySettings } from './models-directory-settings';
|
||||
import { ResetSettings } from './reset-settings';
|
||||
import { DataDirectorySettings } from './data-directory-settings';
|
||||
@@ -18,7 +18,7 @@ import { UninstallSettings } from './uninstall-settings';
|
||||
import {
|
||||
warningText,
|
||||
type StorageWarning,
|
||||
} from '../../../../../../frontend/src/utils/storageWarnings';
|
||||
} from '@shared/utils/storageWarnings';
|
||||
interface Item {
|
||||
id: string;
|
||||
path?: string;
|
||||
|
||||
@@ -20,12 +20,12 @@ import { brandIcon } from '@/lib/brand';
|
||||
import { DonationGoal } from './donation-goal';
|
||||
import { ReportBug } from '@/components/report-bug';
|
||||
import { ExternalLink } from '@/components/external-link';
|
||||
import { KOFI_URL, PAYPAL_URL } from '../../../../../../frontend/src/utils/donateLinks';
|
||||
import { KOFI_URL, PAYPAL_URL } from '@shared/utils/donateLinks';
|
||||
import {
|
||||
SPONSORS,
|
||||
SPONSOR_TIERS,
|
||||
SPONSOR_CONTACT,
|
||||
} from '../../../../../../frontend/src/config/sponsors';
|
||||
} from '@shared/config/sponsors';
|
||||
import {
|
||||
ISSUES_URL,
|
||||
DISCORD_URL,
|
||||
@@ -33,7 +33,7 @@ import {
|
||||
EMAIL,
|
||||
WEBSITE_URL,
|
||||
X_URL,
|
||||
} from '../../../../../../frontend/src/utils/contactLinks';
|
||||
} from '@shared/utils/contactLinks';
|
||||
import './support-settings.css';
|
||||
|
||||
export function SupportSettings() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { CheckCircleIcon, TriangleAlertIcon, CircleXIcon, ScanSearchIcon } from 'lucide-react';
|
||||
import type { PreflightReport } from '../../../../../../frontend/src/api/setup-types';
|
||||
import type { PreflightReport } from '@shared/api/setup-types';
|
||||
import { apiJson } from '@/lib/api/client';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { SettingsRow, SettingsSection } from './settings-layout';
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { describeError } from '@/lib/api/client';
|
||||
import type { UninstallTarget } from '../../../../preload/index.d';
|
||||
import { fmtBytes } from '../../../../../../frontend/src/components/settings/models/format';
|
||||
import { fmtBytes } from '@shared/components/settings/models/format';
|
||||
import { SettingsSection } from './settings-layout';
|
||||
|
||||
const ICONS: Record<UninstallTarget['key'], LucideIcon> = {
|
||||
|
||||
@@ -13,7 +13,7 @@ import { cloneSettingsStore } from '@/lib/store/clone-settings';
|
||||
import { acquireSynthesis } from '@/lib/synthesis-lock';
|
||||
import { queryKeys } from '@/lib/query';
|
||||
import { describeError } from '@/lib/api/client';
|
||||
import { PRESETS } from '../../../../../../frontend/src/utils/constants';
|
||||
import { PRESETS } from '@shared/utils/constants';
|
||||
import { beginAppActivity } from '@/lib/app-activity';
|
||||
import { useTtsReadiness } from '@/hooks/use-tts-readiness';
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import { Input } from '@/components/ui/input';
|
||||
import { PipelineFailure } from '@/components/pipeline-failure';
|
||||
import { apiJson, describeError } from '@/lib/api/client';
|
||||
import { LanguagePicker } from '@/features/clone/language-picker';
|
||||
import { LANG_CODES } from '../../../../../../frontend/src/utils/languages';
|
||||
import { LANG_CODES } from '@shared/utils/languages';
|
||||
const options = LANG_CODES.map((item) => item.label);
|
||||
const tools = [
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ import { CopyIcon, MicIcon, PauseIcon, PlayIcon, SquareIcon, XIcon } from 'lucid
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useBackendStatus } from '@/hooks/use-backend-status';
|
||||
import { LiveDictation } from './live-dictation';
|
||||
import { addTranscription } from '../../../../../../frontend/src/utils/transcriptionsStore';
|
||||
import { addTranscription } from '@shared/utils/transcriptionsStore';
|
||||
|
||||
/** Native recorder stays separate from page navigation and the script editor. */
|
||||
export function CaptureWidget() {
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Button, buttonVariants } from '@/components/ui/button';
|
||||
import { AgentFixButton } from '@/components/agent-fix-button';
|
||||
import { Progress } from '@/components/ui/progress';
|
||||
import { apiJson, describeError } from '@/lib/api/client';
|
||||
import { fmtBytes } from '../../../../../../frontend/src/components/settings/models/format';
|
||||
import { fmtBytes } from '@shared/components/settings/models/format';
|
||||
|
||||
interface DictationModel {
|
||||
id: string;
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
loadTranscriptions,
|
||||
TRANSCRIPTIONS_KEY,
|
||||
TRANSCRIPTION_EVENT,
|
||||
} from '../../../../../../frontend/src/utils/transcriptionsStore';
|
||||
} from '@shared/utils/transcriptionsStore';
|
||||
beforeEach(() => localStorage.clear());
|
||||
it('preserves existing history and publishes a complete entry with nullable timings', () => {
|
||||
localStorage.setItem(TRANSCRIPTIONS_KEY, JSON.stringify([{ id: 1, text: 'Existing' }]));
|
||||
|
||||
@@ -5,7 +5,7 @@ vi.mock('@/hooks/use-backend-status', () => ({
|
||||
getBackendStatusSnapshot: () => ({ baseUrl: 'http://127.0.0.1:3900' }),
|
||||
}));
|
||||
vi.mock('@/components/bridge', () => ({ getBridge: () => mocks.bridge }));
|
||||
vi.mock('../../../../../../frontend/src/utils/aec/micCapture', () => ({
|
||||
vi.mock('@shared/utils/aec/micCapture', () => ({
|
||||
startMicCapture: mocks.capture,
|
||||
}));
|
||||
import { LiveDictation } from './live-dictation';
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { startMicCapture } from '../../../../../../frontend/src/utils/aec/micCapture';
|
||||
import { subscribeFarEnd } from '../../../../../../frontend/src/utils/aec/farEndBus';
|
||||
import { startMicCapture } from '@shared/utils/aec/micCapture';
|
||||
import { subscribeFarEnd } from '@shared/utils/aec/farEndBus';
|
||||
import {
|
||||
AEC_FAR,
|
||||
AEC_NEAR,
|
||||
floatToInt16,
|
||||
tagFrame,
|
||||
} from '../../../../../../frontend/src/utils/aec/pcm';
|
||||
} from '@shared/utils/aec/pcm';
|
||||
import {
|
||||
classifySherpaFinal,
|
||||
sherpaSummaryTail,
|
||||
} from '../../../../../../frontend/src/utils/captureProtocol';
|
||||
import type { TranscriptEntry } from '../../../../../../frontend/src/utils/transcriptionsStore';
|
||||
} from '@shared/utils/captureProtocol';
|
||||
import type { TranscriptEntry } from '@shared/utils/transcriptionsStore';
|
||||
import { apiJson } from '@/lib/api/client';
|
||||
import { backendWebSocketUrl } from '@/lib/api/websocket';
|
||||
import { beginAppActivity } from '@/lib/app-activity';
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
segTimeRange,
|
||||
formatTranscriptExport,
|
||||
preferredTranscript,
|
||||
} from '../../../../../../frontend/src/utils/transcriptionFormat';
|
||||
} from '@shared/utils/transcriptionFormat';
|
||||
import { RecordingInputs } from '@/components/recording-inputs';
|
||||
import { AgentFixButton } from '@/components/agent-fix-button';
|
||||
import { useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';
|
||||
@@ -52,14 +52,14 @@ import {
|
||||
TRANSCRIPTIONS_KEY,
|
||||
TRANSCRIPTION_EVENT,
|
||||
type TranscriptEntry,
|
||||
} from '../../../../../../frontend/src/utils/transcriptionsStore';
|
||||
} from '@shared/utils/transcriptionsStore';
|
||||
import { beginAppActivity } from '@/lib/app-activity';
|
||||
import { formatRelative } from '@/features/clone/format';
|
||||
import { useModelCatalogue } from '@/features/settings/model-catalogue-query';
|
||||
import { useNativeShortcut } from '@/hooks/use-native-dictation';
|
||||
import { recordActionBreadcrumb } from '@/lib/report-breadcrumb';
|
||||
import { saveLocalFile } from '@/lib/local-export';
|
||||
import { formatShortcut } from '../../../../../../frontend/src/utils/dictationShortcut';
|
||||
import { formatShortcut } from '@shared/utils/dictationShortcut';
|
||||
|
||||
type TranscriptionMode = 'fast' | 'accurate';
|
||||
const TRANSCRIPTION_MODE_KEY = 'voicestudio.transcription.mode';
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user