diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0f222ecd..846b08f8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -13,7 +13,7 @@ jobs: name: Lint Frontend runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: pnpm/action-setup@v4 with: package_json_file: "frontend/package.json" @@ -31,7 +31,7 @@ jobs: name: Lint Backend runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: go-version: "1.25.x" @@ -43,7 +43,7 @@ jobs: name: Test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: go-version: "1.25.x" @@ -53,7 +53,7 @@ jobs: name: Build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: fetch-depth: 0 - uses: actions/setup-go@v6 @@ -77,7 +77,7 @@ jobs: if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: fetch-depth: 0 - uses: actions/setup-go@v6 @@ -97,7 +97,7 @@ jobs: uses: docker/setup-buildx-action@v3 - name: Install Task uses: go-task/setup-task@v1 - - run: task build-frontend + - run: task build:frontend - name: Login to Docker Hub uses: docker/login-action@v3 with: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 8eec9747..1f64177c 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Install Task @@ -35,7 +35,7 @@ jobs: timeout-minutes: 5 steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Install Task diff --git a/.golangci.yml b/.golangci.yml index 32d944f3..8819f48b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -2,8 +2,13 @@ version: "2" linters: default: standard + enable: + - gocritic + - govet + - revive exclusions: presets: - std-error-handling + - comments paths: - frontend/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 2be8b2c8..49f40267 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,88 @@ All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines. +## [2.49.0](https://github.com/filebrowser/filebrowser/compare/v2.48.2...v2.49.0) (2025-11-22) + + +### Features + +* add "copy download link to clipboard" button to Share prompt ([#5173](https://github.com/filebrowser/filebrowser/issues/5173)) ([d48f566](https://github.com/filebrowser/filebrowser/commit/d48f5665d6975c4cbbdf9be20dc2e0106db02f01)) +* add Bulgarian language ([8db2411](https://github.com/filebrowser/filebrowser/commit/8db2411cd43a23ae3292a817e3524cfdb5ae9b86)) +* Updates for project File Browser ([#5566](https://github.com/filebrowser/filebrowser/issues/5566)) ([54306bd](https://github.com/filebrowser/filebrowser/commit/54306bdc8700fac489326ae81e28ac5db0580d13)) + + +### Bug Fixes + +* display friendly error message for password validation on signup ([#5563](https://github.com/filebrowser/filebrowser/issues/5563)) ([6d5aa35](https://github.com/filebrowser/filebrowser/commit/6d5aa355e433d613e5a3ae137f410c63baeddf0f)) + +## [2.48.2](https://github.com/filebrowser/filebrowser/compare/v2.48.1...v2.48.2) (2025-11-18) + + +### Bug Fixes + +* add transitionary support for FB_BASEURL ([984ea7b](https://github.com/filebrowser/filebrowser/commit/984ea7b569e3bd33b6f91ebdf63684a618d51e94)) + + +### Refactorings + +* rename python for clarification ([fd7b70c](https://github.com/filebrowser/filebrowser/commit/fd7b70cf38ac67c8c9ff79f2e7fde5e2ec45a1de)) + +## [2.48.1](https://github.com/filebrowser/filebrowser/compare/v2.48.0...v2.48.1) (2025-11-17) + + +### Bug Fixes + +* options should only override if set ([420adea](https://github.com/filebrowser/filebrowser/commit/420adea7e61a1c182cddd6fb2544a0752e5709f7)) + +## [2.48.0](https://github.com/filebrowser/filebrowser/compare/v2.47.0...v2.48.0) (2025-11-17) + + +### Features + +* consistent flags and environment variables ([#5549](https://github.com/filebrowser/filebrowser/issues/5549)) ([0a0cb80](https://github.com/filebrowser/filebrowser/commit/0a0cb8046fce52f1ff926171b34bcdb7cd39aab3)) + + +### Bug Fixes + +* add tokenExpirationTime to `config init` and troubleshoot docs ([#5546](https://github.com/filebrowser/filebrowser/issues/5546)) ([8c5dc76](https://github.com/filebrowser/filebrowser/commit/8c5dc7641e6f8aadd9e5d5d3b25a2ad9f1ec9a1e)) +* use all available flags in quick setup ([f41585f](https://github.com/filebrowser/filebrowser/commit/f41585f0392d65c08c01ab65b62d3eeb04c03b7d)) + + +### Refactorings + +* reuse logic for config init and set ([89be0b1](https://github.com/filebrowser/filebrowser/commit/89be0b1873527987dd2dddac746e93b8bc684d46)) + +## [2.47.0](https://github.com/filebrowser/filebrowser/compare/v2.46.1...v2.47.0) (2025-11-16) + + +### Features + +* add TUS settings to the command line ([#5556](https://github.com/filebrowser/filebrowser/issues/5556)) ([e24e1f1](https://github.com/filebrowser/filebrowser/commit/e24e1f1abae9e80add620c4ad65660ca1b575a49)) +* remove importer of v1 config ([#5550](https://github.com/filebrowser/filebrowser/issues/5550)) ([ceb5e72](https://github.com/filebrowser/filebrowser/commit/ceb5e723f3ee2c966bb561a804015246450280ca)) + + +### Bug Fixes + +* exit 0 when gracefully shutting down ([#5555](https://github.com/filebrowser/filebrowser/issues/5555)) ([5de4099](https://github.com/filebrowser/filebrowser/commit/5de4099cba2cf012d4a213c8eb29c412fc72c151)) + +## [2.46.1](https://github.com/filebrowser/filebrowser/compare/v2.46.0...v2.46.1) (2025-11-15) + + +### Bug Fixes + +* env key replacer and remove unused function ([#5547](https://github.com/filebrowser/filebrowser/issues/5547)) ([13814e1](https://github.com/filebrowser/filebrowser/commit/13814e11197ebd9101940883e3ca85998f86d442)) +* remove duplicated 'hide-defaults' flag (is 'hideDefaults') ([#5548](https://github.com/filebrowser/filebrowser/issues/5548)) ([ffc8504](https://github.com/filebrowser/filebrowser/commit/ffc850454e4cb8f10b970511681d6c627340afc7)) + +## [2.46.0](https://github.com/filebrowser/filebrowser/compare/v2.45.3...v2.46.0) (2025-11-14) + + +### Features + +* add 'hide-dotfiles' as command line parameter ([#3802](https://github.com/filebrowser/filebrowser/issues/3802)) ([0d973d3](https://github.com/filebrowser/filebrowser/commit/0d973d3aad70ceb88950f2cd9c297fc76e7955b1)) +* add context menu ([#3343](https://github.com/filebrowser/filebrowser/issues/3343)) ([1ace579](https://github.com/filebrowser/filebrowser/commit/1ace579a553486bb15af2d11f537414156606434)) +* add option to hide the login button from public-facing pages ([#3922](https://github.com/filebrowser/filebrowser/issues/3922)) ([ac7b49c](https://github.com/filebrowser/filebrowser/commit/ac7b49c1484b4e27a1149310542ccd1e90659ee2)) +* Updates for project File Browser ([#5544](https://github.com/filebrowser/filebrowser/issues/5544)) ([fb5d099](https://github.com/filebrowser/filebrowser/commit/fb5d099f8514516216f407be012d2e3f25de2441)) + ## [2.45.3](https://github.com/filebrowser/filebrowser/compare/v2.45.2...v2.45.3) (2025-11-13) This is a test release to ensure the updated workflow works. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d6e694f1..311a2fd7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -86,7 +86,7 @@ task docs To start a local server on port `8000` to view the built documentation: ```bash -task docs-serve +task docs:serve ``` ## Release diff --git a/README.md b/README.md index 33ecbde1..1e15d592 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ This project is a finished product which fulfills its goal: be a single binary w - It can take a while until someone gets back to you. Please be patient. - [Issues](https://github.com/filebrowser/filebrowser/issues) are meant to track bugs. Unrelated issues will be converted into [discussions](https://github.com/filebrowser/filebrowser/discussions). - No new features will be implemented by maintainers. Pull requests for new features will be reviewed on a case by case basis. -- The priority is triaging issues, addressing security issues, and fixing bug fixes. +- The priority is triaging issues, addressing security issues and reviewing pull requests meant to solve bugs. ## Contributing diff --git a/Taskfile.yml b/Taskfile.yml index 9721317f..378e3409 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -10,14 +10,14 @@ vars: -v ./CONTRIBUTING.md:/docs/docs/contributing.md tasks: - build-frontend: + build:frontend: desc: Build frontend assets dir: frontend cmds: - pnpm install --frozen-lockfile - pnpm run build - build-backend: + build:backend: desc: Build backend binary cmds: - go build -ldflags='-s -w -X "github.com/filebrowser/filebrowser/v2/version.Version={{.VERSION}}" -X "github.com/filebrowser/filebrowser/v2/version.CommitSHA={{.GIT_COMMIT}}"' -o filebrowser . @@ -30,16 +30,16 @@ tasks: build: desc: Build both frontend and backend cmds: - - task: build-frontend - - task: build-backend + - task: build:frontend + - task: build:backend - release-make: + release:make: internal: true prompt: Do you wish to proceed? cmds: - pnpm dlx commit-and-tag-version -s - release-dry-run: + release:dry-run: internal: true cmds: - pnpm dlx commit-and-tag-version --dry-run --skip @@ -47,10 +47,24 @@ tasks: release: desc: Create a new release cmds: - - task: release-dry-run - - task: release-make + - task: docs:cli:generate + - git add www/docs/cli + - | + if [[ `git status www/docs/cli --porcelain` ]]; then + git commit -m 'chore(docs): update CLI documentation' + fi + - task: release:dry-run + - task: release:make - docs-image-make: + docs:cli:generate: + cmds: + - rm -rf www/docs/cli + - mkdir -p www/docs/cli + - go run . docs + generates: + - www/docs/cli + + docs:docker:generate: internal: true cmds: - docker build -f www/Dockerfile --progress=plain -t filebrowser.site www @@ -59,11 +73,11 @@ tasks: desc: Generate documentation cmds: - rm -rf www/public - - task: docs-image-make + - task: docs:docker:generate - docker run --rm {{.SITE_DOCKER_FLAGS}} filebrowser.site build -d "public" - docs-serve: + docs:serve: desc: Serve documentation cmds: - - task: docs-image-make + - task: docs:docker:generate - docker run --rm -it -p 8000:8000 {{.SITE_DOCKER_FLAGS}} filebrowser.site diff --git a/auth/hook.go b/auth/hook.go index 2ecb12f3..ec3c5bfb 100644 --- a/auth/hook.go +++ b/auth/hook.go @@ -103,7 +103,7 @@ func (a *HookAuth) RunCommand() (string, error) { command[i] = os.Expand(arg, envMapping) } - cmd := exec.Command(command[0], command[1:]...) //nolint:gosec + cmd := exec.Command(command[0], command[1:]...) cmd.Env = append(os.Environ(), fmt.Sprintf("USERNAME=%s", a.Cred.Username)) cmd.Env = append(cmd.Env, fmt.Sprintf("PASSWORD=%s", a.Cred.Password)) out, err := cmd.Output() diff --git a/auth/json.go b/auth/json.go index 81f430b3..f779c476 100644 --- a/auth/json.go +++ b/auth/json.go @@ -40,7 +40,7 @@ func (a JSONAuth) Auth(r *http.Request, usr users.Store, _ *settings.Settings, s // If ReCaptcha is enabled, check the code. if a.ReCaptcha != nil && a.ReCaptcha.Secret != "" { - ok, err := a.ReCaptcha.Ok(cred.ReCaptcha) //nolint:govet + ok, err := a.ReCaptcha.Ok(cred.ReCaptcha) if err != nil { return nil, err diff --git a/cmd/cmd_test.go b/cmd/cmd_test.go new file mode 100644 index 00000000..e4b45c47 --- /dev/null +++ b/cmd/cmd_test.go @@ -0,0 +1,35 @@ +package cmd + +import ( + "testing" + + "github.com/samber/lo" + "github.com/spf13/cobra" +) + +// TestEnvCollisions ensures that there are no collisions in the produced environment +// variable names for all commands and their flags. +func TestEnvCollisions(t *testing.T) { + testEnvCollisions(t, rootCmd) +} + +func testEnvCollisions(t *testing.T, cmd *cobra.Command) { + for _, cmd := range cmd.Commands() { + testEnvCollisions(t, cmd) + } + + replacements := generateEnvKeyReplacements(cmd) + envVariables := []string{} + + for i := range replacements { + if i%2 != 0 { + envVariables = append(envVariables, replacements[i]) + } + } + + duplicates := lo.FindDuplicates(envVariables) + + if len(duplicates) > 0 { + t.Errorf("Found duplicate environment variable keys for command %q: %v", cmd.Name(), duplicates) + } +} diff --git a/cmd/cmds_add.go b/cmd/cmds_add.go index a4d17061..a209b83f 100644 --- a/cmd/cmds_add.go +++ b/cmd/cmds_add.go @@ -15,18 +15,18 @@ var cmdsAddCmd = &cobra.Command{ Short: "Add a command to run on a specific event", Long: `Add a command to run on a specific event.`, Args: cobra.MinimumNArgs(2), - RunE: python(func(_ *cobra.Command, args []string, d *pythonData) error { - s, err := d.store.Settings.Get() + RunE: withStore(func(_ *cobra.Command, args []string, st *store) error { + s, err := st.Settings.Get() if err != nil { return err } command := strings.Join(args[1:], " ") s.Commands[args[0]] = append(s.Commands[args[0]], command) - err = d.store.Settings.Save(s) + err = st.Settings.Save(s) if err != nil { return err } printEvents(s.Commands) return nil - }, pythonConfig{}), + }, storeOptions{}), } diff --git a/cmd/cmds_ls.go b/cmd/cmds_ls.go index fa901a56..694be178 100644 --- a/cmd/cmds_ls.go +++ b/cmd/cmds_ls.go @@ -14,12 +14,13 @@ var cmdsLsCmd = &cobra.Command{ Short: "List all commands for each event", Long: `List all commands for each event.`, Args: cobra.NoArgs, - RunE: python(func(cmd *cobra.Command, _ []string, d *pythonData) error { - s, err := d.store.Settings.Get() + RunE: withStore(func(cmd *cobra.Command, _ []string, st *store) error { + s, err := st.Settings.Get() if err != nil { return err } - evt, err := getString(cmd.Flags(), "event") + + evt, err := cmd.Flags().GetString("event") if err != nil { return err } @@ -32,6 +33,7 @@ var cmdsLsCmd = &cobra.Command{ show["after_"+evt] = s.Commands["after_"+evt] printEvents(show) } + return nil - }, pythonConfig{}), + }, storeOptions{}), } diff --git a/cmd/cmds_rm.go b/cmd/cmds_rm.go index 34089388..861f495f 100644 --- a/cmd/cmds_rm.go +++ b/cmd/cmds_rm.go @@ -35,8 +35,8 @@ including 'index_end'.`, return nil }, - RunE: python(func(_ *cobra.Command, args []string, d *pythonData) error { - s, err := d.store.Settings.Get() + RunE: withStore(func(_ *cobra.Command, args []string, st *store) error { + s, err := st.Settings.Get() if err != nil { return err } @@ -55,11 +55,11 @@ including 'index_end'.`, } s.Commands[evt] = append(s.Commands[evt][:i], s.Commands[evt][f+1:]...) - err = d.store.Settings.Save(s) + err = st.Settings.Save(s) if err != nil { return err } printEvents(s.Commands) return nil - }, pythonConfig{}), + }, storeOptions{}), } diff --git a/cmd/config.go b/cmd/config.go index 7b03f1fe..fb0dce34 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -30,12 +30,18 @@ var configCmd = &cobra.Command{ func addConfigFlags(flags *pflag.FlagSet) { addServerFlags(flags) addUserFlags(flags) + flags.BoolP("signup", "s", false, "allow users to signup") - flags.Bool("hide-login-button", false, "hide login button from public pages") - flags.Bool("create-user-dir", false, "generate user's home directory automatically") - flags.Uint("minimum-password-length", settings.DefaultMinimumPasswordLength, "minimum password length for new users") + flags.Bool("hideLoginButton", false, "hide login button from public pages") + flags.Bool("createUserDir", false, "generate user's home directory automatically") + flags.Uint("minimumPasswordLength", settings.DefaultMinimumPasswordLength, "minimum password length for new users") flags.String("shell", "", "shell command to which other commands should be appended") + // NB: these are string so they can be presented as octal in the help text + // as that's the conventional representation for modes in Unix. + flags.String("fileMode", fmt.Sprintf("%O", settings.DefaultFileMode), "mode bits that new files are created with") + flags.String("dirMode", fmt.Sprintf("%O", settings.DefaultDirMode), "mode bits that new directories are created with") + flags.String("auth.method", string(auth.MethodJSONAuth), "authentication type") flags.String("auth.header", "", "HTTP header for auth.method=proxy") flags.String("auth.command", "", "command for auth.method=hook") @@ -51,14 +57,13 @@ func addConfigFlags(flags *pflag.FlagSet) { flags.String("branding.files", "", "path to directory with images and custom styles") flags.Bool("branding.disableExternal", false, "disable external links such as GitHub links") flags.Bool("branding.disableUsedPercentage", false, "disable used disk percentage graph") - // NB: these are string so they can be presented as octal in the help text - // as that's the conventional representation for modes in Unix. - flags.String("file-mode", fmt.Sprintf("%O", settings.DefaultFileMode), "Mode bits that new files are created with") - flags.String("dir-mode", fmt.Sprintf("%O", settings.DefaultDirMode), "Mode bits that new directories are created with") + + flags.Uint64("tus.chunkSize", settings.DefaultTusChunkSize, "the tus chunk size") + flags.Uint16("tus.retryCount", settings.DefaultTusRetryCount, "the tus retry count") } func getAuthMethod(flags *pflag.FlagSet, defaults ...interface{}) (settings.AuthMethod, map[string]interface{}, error) { - methodStr, err := getString(flags, "auth.method") + methodStr, err := flags.GetString("auth.method") if err != nil { return "", nil, err } @@ -89,7 +94,7 @@ func getAuthMethod(flags *pflag.FlagSet, defaults ...interface{}) (settings.Auth } func getProxyAuth(flags *pflag.FlagSet, defaultAuther map[string]interface{}) (auth.Auther, error) { - header, err := getString(flags, "auth.header") + header, err := flags.GetString("auth.header") if err != nil { return nil, err } @@ -111,15 +116,17 @@ func getNoAuth() auth.Auther { func getJSONAuth(flags *pflag.FlagSet, defaultAuther map[string]interface{}) (auth.Auther, error) { jsonAuth := &auth.JSONAuth{} - host, err := getString(flags, "recaptcha.host") + host, err := flags.GetString("recaptcha.host") if err != nil { return nil, err } - key, err := getString(flags, "recaptcha.key") + + key, err := flags.GetString("recaptcha.key") if err != nil { return nil, err } - secret, err := getString(flags, "recaptcha.secret") + + secret, err := flags.GetString("recaptcha.secret") if err != nil { return nil, err } @@ -147,11 +154,10 @@ func getJSONAuth(flags *pflag.FlagSet, defaultAuther map[string]interface{}) (au } func getHookAuth(flags *pflag.FlagSet, defaultAuther map[string]interface{}) (auth.Auther, error) { - command, err := getString(flags, "auth.command") + command, err := flags.GetString("auth.command") if err != nil { return nil, err } - if command == "" { command = defaultAuther["command"].(string) } @@ -200,6 +206,7 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut fmt.Fprintf(w, "Minimum Password Length:\t%d\n", set.MinimumPasswordLength) fmt.Fprintf(w, "Auth Method:\t%s\n", set.AuthMethod) fmt.Fprintf(w, "Shell:\t%s\t\n", strings.Join(set.Shell, " ")) + fmt.Fprintln(w, "\nBranding:") fmt.Fprintf(w, "\tName:\t%s\n", set.Branding.Name) fmt.Fprintf(w, "\tFiles override:\t%s\n", set.Branding.Files) @@ -207,6 +214,7 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut fmt.Fprintf(w, "\tDisable used disk percentage graph:\t%t\n", set.Branding.DisableUsedPercentage) fmt.Fprintf(w, "\tColor:\t%s\n", set.Branding.Color) fmt.Fprintf(w, "\tTheme:\t%s\n", set.Branding.Theme) + fmt.Fprintln(w, "\nServer:") fmt.Fprintf(w, "\tLog:\t%s\n", ser.Log) fmt.Fprintf(w, "\tPort:\t%s\n", ser.Port) @@ -216,7 +224,16 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut fmt.Fprintf(w, "\tAddress:\t%s\n", ser.Address) fmt.Fprintf(w, "\tTLS Cert:\t%s\n", ser.TLSCert) fmt.Fprintf(w, "\tTLS Key:\t%s\n", ser.TLSKey) + fmt.Fprintf(w, "\tToken Expiration Time:\t%s\n", ser.TokenExpirationTime) fmt.Fprintf(w, "\tExec Enabled:\t%t\n", ser.EnableExec) + fmt.Fprintf(w, "\tThumbnails Enabled:\t%t\n", ser.EnableThumbnails) + fmt.Fprintf(w, "\tResize Preview:\t%t\n", ser.ResizePreview) + fmt.Fprintf(w, "\tType Detection by Header:\t%t\n", ser.TypeDetectionByHeader) + + fmt.Fprintln(w, "\nTUS:") + fmt.Fprintf(w, "\tChunk size:\t%d\n", set.Tus.ChunkSize) + fmt.Fprintf(w, "\tRetry count:\t%d\n", set.Tus.RetryCount) + fmt.Fprintln(w, "\nDefaults:") fmt.Fprintf(w, "\tScope:\t%s\n", set.Defaults.Scope) fmt.Fprintf(w, "\tHideDotfiles:\t%t\n", set.Defaults.HideDotfiles) @@ -227,9 +244,11 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut fmt.Fprintf(w, "\tDirectory Creation Mode:\t%O\n", set.DirMode) fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " ")) fmt.Fprintf(w, "\tAce editor syntax highlighting theme:\t%s\n", set.Defaults.AceEditorTheme) + fmt.Fprintf(w, "\tSorting:\n") fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By) fmt.Fprintf(w, "\t\tAsc:\t%t\n", set.Defaults.Sorting.Asc) + fmt.Fprintf(w, "\tPermissions:\n") fmt.Fprintf(w, "\t\tAdmin:\t%t\n", set.Defaults.Perm.Admin) fmt.Fprintf(w, "\t\tExecute:\t%t\n", set.Defaults.Perm.Execute) @@ -239,6 +258,7 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut fmt.Fprintf(w, "\t\tDelete:\t%t\n", set.Defaults.Perm.Delete) fmt.Fprintf(w, "\t\tShare:\t%t\n", set.Defaults.Perm.Share) fmt.Fprintf(w, "\t\tDownload:\t%t\n", set.Defaults.Perm.Download) + w.Flush() b, err := json.MarshalIndent(auther, "", " ") @@ -248,3 +268,120 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut fmt.Printf("\nAuther configuration (raw):\n\n%s\n\n", string(b)) return nil } + +func getSettings(flags *pflag.FlagSet, set *settings.Settings, ser *settings.Server, auther auth.Auther, all bool) (auth.Auther, error) { + errs := []error{} + hasAuth := false + + visit := func(flag *pflag.Flag) { + var err error + + switch flag.Name { + // Server flags from [addServerFlags] + case "address": + ser.Address, err = flags.GetString(flag.Name) + case "log": + ser.Log, err = flags.GetString(flag.Name) + case "port": + ser.Port, err = flags.GetString(flag.Name) + case "cert": + ser.TLSCert, err = flags.GetString(flag.Name) + case "key": + ser.TLSKey, err = flags.GetString(flag.Name) + case "root": + ser.Root, err = flags.GetString(flag.Name) + case "socket": + ser.Socket, err = flags.GetString(flag.Name) + case "baseURL": + ser.BaseURL, err = flags.GetString(flag.Name) + case "tokenExpirationTime": + ser.TokenExpirationTime, err = flags.GetString(flag.Name) + case "disableThumbnails": + ser.EnableThumbnails, err = flags.GetBool(flag.Name) + ser.EnableThumbnails = !ser.EnableThumbnails + case "disablePreviewResize": + ser.ResizePreview, err = flags.GetBool(flag.Name) + ser.ResizePreview = !ser.ResizePreview + case "disableExec": + ser.EnableExec, err = flags.GetBool(flag.Name) + ser.EnableExec = !ser.EnableExec + case "disableTypeDetectionByHeader": + ser.TypeDetectionByHeader, err = flags.GetBool(flag.Name) + ser.TypeDetectionByHeader = !ser.TypeDetectionByHeader + + // Settings flags from [addConfigFlags] + case "signup": + set.Signup, err = flags.GetBool(flag.Name) + case "hideLoginButton": + set.HideLoginButton, err = flags.GetBool(flag.Name) + case "createUserDir": + set.CreateUserDir, err = flags.GetBool(flag.Name) + case "minimumPasswordLength": + set.MinimumPasswordLength, err = flags.GetUint(flag.Name) + case "shell": + var shell string + shell, err = flags.GetString(flag.Name) + if err == nil { + set.Shell = convertCmdStrToCmdArray(shell) + } + case "fileMode": + set.FileMode, err = getAndParseFileMode(flags, flag.Name) + case "dirMode": + set.DirMode, err = getAndParseFileMode(flags, flag.Name) + case "auth.method": + hasAuth = true + case "auth.logoutPage": + set.LogoutPage, err = flags.GetString(flag.Name) + case "branding.name": + set.Branding.Name, err = flags.GetString(flag.Name) + case "branding.theme": + set.Branding.Theme, err = flags.GetString(flag.Name) + case "branding.color": + set.Branding.Color, err = flags.GetString(flag.Name) + case "branding.files": + set.Branding.Files, err = flags.GetString(flag.Name) + case "branding.disableExternal": + set.Branding.DisableExternal, err = flags.GetBool(flag.Name) + case "branding.disableUsedPercentage": + set.Branding.DisableUsedPercentage, err = flags.GetBool(flag.Name) + case "tus.chunkSize": + set.Tus.ChunkSize, err = flags.GetUint64(flag.Name) + case "tus.retryCount": + set.Tus.RetryCount, err = flags.GetUint16(flag.Name) + } + + if err != nil { + errs = append(errs, err) + } + } + + if all { + flags.VisitAll(visit) + } else { + flags.Visit(visit) + } + + err := nerrors.Join(errs...) + if err != nil { + return nil, err + } + + err = getUserDefaults(flags, &set.Defaults, all) + if err != nil { + return nil, err + } + + if all { + set.AuthMethod, auther, err = getAuthentication(flags) + if err != nil { + return nil, err + } + } else { + set.AuthMethod, auther, err = getAuthentication(flags, hasAuth, set, auther) + if err != nil { + return nil, err + } + } + + return auther, nil +} diff --git a/cmd/config_cat.go b/cmd/config_cat.go index 39b1f664..b8d2f48f 100644 --- a/cmd/config_cat.go +++ b/cmd/config_cat.go @@ -13,19 +13,19 @@ var configCatCmd = &cobra.Command{ Short: "Prints the configuration", Long: `Prints the configuration.`, Args: cobra.NoArgs, - RunE: python(func(_ *cobra.Command, _ []string, d *pythonData) error { - set, err := d.store.Settings.Get() + RunE: withStore(func(_ *cobra.Command, _ []string, st *store) error { + set, err := st.Settings.Get() if err != nil { return err } - ser, err := d.store.Settings.GetServer() + ser, err := st.Settings.GetServer() if err != nil { return err } - auther, err := d.store.Auth.Get(set.AuthMethod) + auther, err := st.Auth.Get(set.AuthMethod) if err != nil { return err } return printSettings(ser, set, auther) - }, pythonConfig{}), + }, storeOptions{}), } diff --git a/cmd/config_export.go b/cmd/config_export.go index 9877fb63..b19c10b6 100644 --- a/cmd/config_export.go +++ b/cmd/config_export.go @@ -15,18 +15,18 @@ var configExportCmd = &cobra.Command{ json or yaml file. This exported configuration can be changed, and imported again with 'config import' command.`, Args: jsonYamlArg, - RunE: python(func(_ *cobra.Command, args []string, d *pythonData) error { - settings, err := d.store.Settings.Get() + RunE: withStore(func(_ *cobra.Command, args []string, st *store) error { + settings, err := st.Settings.Get() if err != nil { return err } - server, err := d.store.Settings.GetServer() + server, err := st.Settings.GetServer() if err != nil { return err } - auther, err := d.store.Auth.Get(settings.AuthMethod) + auther, err := st.Auth.Get(settings.AuthMethod) if err != nil { return err } @@ -42,5 +42,5 @@ and imported again with 'config import' command.`, return err } return nil - }, pythonConfig{}), + }, storeOptions{}), } diff --git a/cmd/config_import.go b/cmd/config_import.go index 7763517d..4de34c9b 100644 --- a/cmd/config_import.go +++ b/cmd/config_import.go @@ -34,11 +34,11 @@ database. The path must be for a json or yaml file.`, Args: jsonYamlArg, - RunE: python(func(_ *cobra.Command, args []string, d *pythonData) error { + RunE: withStore(func(_ *cobra.Command, args []string, st *store) error { var key []byte var err error - if d.hadDB { - settings, settingErr := d.store.Settings.Get() + if st.databaseExisted { + settings, settingErr := st.Settings.Get() if settingErr != nil { return settingErr } @@ -54,12 +54,12 @@ The path must be for a json or yaml file.`, } file.Settings.Key = key - err = d.store.Settings.Save(file.Settings) + err = st.Settings.Save(file.Settings) if err != nil { return err } - err = d.store.Settings.SaveServer(file.Server) + err = st.Settings.SaveServer(file.Server) if err != nil { return err } @@ -98,13 +98,13 @@ The path must be for a json or yaml file.`, return autherErr } - err = d.store.Auth.Save(auther) + err = st.Auth.Save(auther) if err != nil { return err } return printSettings(file.Server, file.Settings, auther) - }, pythonConfig{allowNoDB: true}), + }, storeOptions{allowsNoDatabase: true}), } func getAuther(sample auth.Auther, data interface{}) (interface{}, error) { diff --git a/cmd/config_init.go b/cmd/config_init.go index 693b6ace..359d02a3 100644 --- a/cmd/config_init.go +++ b/cmd/config_init.go @@ -22,158 +22,31 @@ this options can be changed in the future with the command to the defaults when creating new users and you don't override the options.`, Args: cobra.NoArgs, - RunE: python(func(cmd *cobra.Command, _ []string, d *pythonData) error { - defaults := settings.UserDefaults{} + RunE: withStore(func(cmd *cobra.Command, _ []string, st *store) error { flags := cmd.Flags() - err := getUserDefaults(flags, &defaults, true) - if err != nil { - return err - } - authMethod, auther, err := getAuthentication(flags) + + // Initialize config + s := &settings.Settings{Key: generateKey()} + ser := &settings.Server{} + + // Fill config with options + auther, err := getSettings(flags, s, ser, nil, true) if err != nil { return err } - key := generateKey() - - signup, err := getBool(flags, "signup") + // Save updated config + err = st.Settings.Save(s) if err != nil { return err } - hideLoginButton, err := getBool(flags, "hide-login-button") + err = st.Settings.SaveServer(ser) if err != nil { return err } - createUserDir, err := getBool(flags, "create-user-dir") - if err != nil { - return err - } - - minLength, err := getUint(flags, "minimum-password-length") - if err != nil { - return err - } - - shell, err := getString(flags, "shell") - if err != nil { - return err - } - - brandingName, err := getString(flags, "branding.name") - if err != nil { - return err - } - - brandingDisableExternal, err := getBool(flags, "branding.disableExternal") - if err != nil { - return err - } - - brandingDisableUsedPercentage, err := getBool(flags, "branding.disableUsedPercentage") - if err != nil { - return err - } - - brandingTheme, err := getString(flags, "branding.theme") - if err != nil { - return err - } - - brandingFiles, err := getString(flags, "branding.files") - if err != nil { - return err - } - - s := &settings.Settings{ - Key: key, - Signup: signup, - HideLoginButton: hideLoginButton, - CreateUserDir: createUserDir, - MinimumPasswordLength: minLength, - Shell: convertCmdStrToCmdArray(shell), - AuthMethod: authMethod, - Defaults: defaults, - Branding: settings.Branding{ - Name: brandingName, - DisableExternal: brandingDisableExternal, - DisableUsedPercentage: brandingDisableUsedPercentage, - Theme: brandingTheme, - Files: brandingFiles, - }, - } - - s.FileMode, err = getMode(flags, "file-mode") - if err != nil { - return err - } - - s.DirMode, err = getMode(flags, "dir-mode") - if err != nil { - return err - } - - address, err := getString(flags, "address") - if err != nil { - return err - } - - socket, err := getString(flags, "socket") - if err != nil { - return err - } - - root, err := getString(flags, "root") - if err != nil { - return err - } - - baseURL, err := getString(flags, "baseurl") - if err != nil { - return err - } - - tlsKey, err := getString(flags, "key") - if err != nil { - return err - } - - cert, err := getString(flags, "cert") - if err != nil { - return err - } - - port, err := getString(flags, "port") - if err != nil { - return err - } - - log, err := getString(flags, "log") - if err != nil { - return err - } - - ser := &settings.Server{ - Address: address, - Socket: socket, - Root: root, - BaseURL: baseURL, - TLSKey: tlsKey, - TLSCert: cert, - Port: port, - Log: log, - } - - err = d.store.Settings.Save(s) - if err != nil { - return err - } - err = d.store.Settings.SaveServer(ser) - if err != nil { - return err - } - err = d.store.Auth.Save(auther) + err = st.Auth.Save(auther) if err != nil { return err } @@ -184,5 +57,5 @@ Now add your first user via 'filebrowser users add' and then you just need to call the main command to boot up the server. `) return printSettings(ser, s, auther) - }, pythonConfig{noDB: true}), + }, storeOptions{expectsNoDatabase: true}), } diff --git a/cmd/config_set.go b/cmd/config_set.go index 9e577207..df357a02 100644 --- a/cmd/config_set.go +++ b/cmd/config_set.go @@ -2,7 +2,6 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/spf13/pflag" ) func init() { @@ -16,109 +15,47 @@ var configSetCmd = &cobra.Command{ Long: `Updates the configuration. Set the flags for the options you want to change. Other options will remain unchanged.`, Args: cobra.NoArgs, - RunE: python(func(cmd *cobra.Command, _ []string, d *pythonData) error { + RunE: withStore(func(cmd *cobra.Command, _ []string, st *store) error { flags := cmd.Flags() - set, err := d.store.Settings.Get() + + // Read existing config + set, err := st.Settings.Get() if err != nil { return err } - ser, err := d.store.Settings.GetServer() + ser, err := st.Settings.GetServer() if err != nil { return err } - hasAuth := false - flags.Visit(func(flag *pflag.Flag) { - if err != nil { - return - } - switch flag.Name { - case "baseurl": - ser.BaseURL, err = getString(flags, flag.Name) - case "root": - ser.Root, err = getString(flags, flag.Name) - case "socket": - ser.Socket, err = getString(flags, flag.Name) - case "cert": - ser.TLSCert, err = getString(flags, flag.Name) - case "key": - ser.TLSKey, err = getString(flags, flag.Name) - case "address": - ser.Address, err = getString(flags, flag.Name) - case "port": - ser.Port, err = getString(flags, flag.Name) - case "log": - ser.Log, err = getString(flags, flag.Name) - case "hide-login-button": - set.HideLoginButton, err = getBool(flags, flag.Name) - case "signup": - set.Signup, err = getBool(flags, flag.Name) - case "auth.method": - hasAuth = true - case "auth.logoutPage": - set.LogoutPage, err = getString(flags, flag.Name) - case "shell": - var shell string - shell, err = getString(flags, flag.Name) - set.Shell = convertCmdStrToCmdArray(shell) - case "create-user-dir": - set.CreateUserDir, err = getBool(flags, flag.Name) - case "minimum-password-length": - set.MinimumPasswordLength, err = getUint(flags, flag.Name) - case "branding.name": - set.Branding.Name, err = getString(flags, flag.Name) - case "branding.color": - set.Branding.Color, err = getString(flags, flag.Name) - case "branding.theme": - set.Branding.Theme, err = getString(flags, flag.Name) - case "branding.disableExternal": - set.Branding.DisableExternal, err = getBool(flags, flag.Name) - case "branding.disableUsedPercentage": - set.Branding.DisableUsedPercentage, err = getBool(flags, flag.Name) - case "branding.files": - set.Branding.Files, err = getString(flags, flag.Name) - case "file-mode": - set.FileMode, err = getMode(flags, flag.Name) - case "dir-mode": - set.DirMode, err = getMode(flags, flag.Name) - } - }) - + auther, err := st.Auth.Get(set.AuthMethod) if err != nil { return err } - err = getUserDefaults(flags, &set.Defaults, false) + // Get updated config + auther, err = getSettings(flags, set, ser, auther, false) if err != nil { return err } - // read the defaults - auther, err := d.store.Auth.Get(set.AuthMethod) + // Save updated config + err = st.Auth.Save(auther) if err != nil { return err } - // check if there are new flags for existing auth method - set.AuthMethod, auther, err = getAuthentication(flags, hasAuth, set, auther) + err = st.Settings.Save(set) if err != nil { return err } - err = d.store.Auth.Save(auther) - if err != nil { - return err - } - err = d.store.Settings.Save(set) - if err != nil { - return err - } - err = d.store.Settings.SaveServer(ser) + err = st.Settings.SaveServer(ser) if err != nil { return err } return printSettings(ser, set, auther) - }, pythonConfig{}), + }, storeOptions{}), } diff --git a/cmd/docs.go b/cmd/docs.go index 90e5a259..d65a29be 100644 --- a/cmd/docs.go +++ b/cmd/docs.go @@ -3,36 +3,18 @@ package cmd import ( "bytes" "fmt" - "io" "os" - "path/filepath" - "sort" + "path" + "regexp" "strings" "github.com/spf13/cobra" - "github.com/spf13/pflag" + "github.com/spf13/cobra/doc" ) func init() { rootCmd.AddCommand(docsCmd) - docsCmd.Flags().StringP("path", "p", "./docs", "path to save the docs") -} - -func printToc(names []string) { - for i, name := range names { - name = strings.TrimSuffix(name, filepath.Ext(name)) - name = strings.ReplaceAll(name, "-", " ") - names[i] = name - } - - sort.Strings(names) - - toc := "" - for _, name := range names { - toc += "* [" + name + "](cli/" + strings.ReplaceAll(name, " ", "-") + ".md)\n" - } - - fmt.Println(toc) + docsCmd.Flags().String("out", "www/docs/cli", "directory to write the docs to") } var docsCmd = &cobra.Command{ @@ -40,115 +22,61 @@ var docsCmd = &cobra.Command{ Hidden: true, Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { - dir, err := getString(cmd.Flags(), "path") + outputDir, err := cmd.Flags().GetString("out") if err != nil { return err } - err = generateDocs(rootCmd, dir) + tempDir, err := os.MkdirTemp(os.TempDir(), "filebrowser-docs-") if err != nil { return err } - names := []string{} + defer os.RemoveAll(tempDir) - err = filepath.Walk(dir, func(_ string, info os.FileInfo, err error) error { - if err != nil || info.IsDir() { - return err - } + rootCmd.Root().DisableAutoGenTag = true - if !strings.HasPrefix(info.Name(), "filebrowser") { - return nil - } - - names = append(names, info.Name()) - return nil + err = doc.GenMarkdownTreeCustom(cmd.Root(), tempDir, func(_ string) string { + return "" + }, func(s string) string { + return s }) if err != nil { return err } - printToc(names) - return nil - }, -} - -func generateDocs(cmd *cobra.Command, dir string) error { - for _, c := range cmd.Commands() { - if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { - continue - } - - err := generateDocs(c, dir) + entries, err := os.ReadDir(tempDir) if err != nil { return err } - } - basename := strings.ReplaceAll(cmd.CommandPath(), " ", "-") + ".md" - filename := filepath.Join(dir, basename) - f, err := os.Create(filename) - if err != nil { - return err - } - defer f.Close() - return generateMarkdown(cmd, f) -} - -func generateMarkdown(cmd *cobra.Command, w io.Writer) error { - cmd.InitDefaultHelpCmd() - cmd.InitDefaultHelpFlag() - - buf := new(bytes.Buffer) - name := cmd.CommandPath() - - short := cmd.Short - long := cmd.Long - if long == "" { - long = short - } - - buf.WriteString("---\ndescription: " + short + "\n---\n\n") - buf.WriteString("# " + name + "\n\n") - buf.WriteString("## Synopsis\n\n") - buf.WriteString(long + "\n\n") - - if cmd.Runnable() { - _, _ = fmt.Fprintf(buf, "```\n%s\n```\n\n", cmd.UseLine()) - } - - if cmd.Example != "" { - buf.WriteString("## Examples\n\n") - _, _ = fmt.Fprintf(buf, "```\n%s\n```\n\n", cmd.Example) - } - - printOptions(buf, cmd) - _, err := buf.WriteTo(w) - return err -} - -func generateFlagsTable(fs *pflag.FlagSet, buf io.StringWriter) { - _, _ = buf.WriteString("| Name | Shorthand | Usage |\n") - _, _ = buf.WriteString("|------|-----------|-------|\n") - - fs.VisitAll(func(f *pflag.Flag) { - _, _ = buf.WriteString("|" + f.Name + "|" + f.Shorthand + "|" + f.Usage + "|\n") - }) -} - -func printOptions(buf *bytes.Buffer, cmd *cobra.Command) { - flags := cmd.NonInheritedFlags() - flags.SetOutput(buf) - if flags.HasAvailableFlags() { - buf.WriteString("## Options\n\n") - generateFlagsTable(flags, buf) - buf.WriteString("\n") - } - - parentFlags := cmd.InheritedFlags() - parentFlags.SetOutput(buf) - if parentFlags.HasAvailableFlags() { - buf.WriteString("### Inherited\n\n") - generateFlagsTable(parentFlags, buf) - buf.WriteString("\n") - } + headerRegex := regexp.MustCompile(`(?m)^(##)(.*)$`) + linkRegex := regexp.MustCompile(`\(filebrowser(.*)\.md\)`) + + fmt.Println("Generated Documents:") + + for _, entry := range entries { + srcPath := path.Join(tempDir, entry.Name()) + dstPath := path.Join(outputDir, strings.ReplaceAll(entry.Name(), "_", "-")) + + data, err := os.ReadFile(srcPath) + if err != nil { + return err + } + + data = headerRegex.ReplaceAll(data, []byte("#$2")) + data = linkRegex.ReplaceAllFunc(data, func(b []byte) []byte { + return bytes.ReplaceAll(b, []byte("_"), []byte("-")) + }) + data = bytes.ReplaceAll(data, []byte("## SEE ALSO"), []byte("## See Also")) + + err = os.WriteFile(dstPath, data, 0666) + if err != nil { + return err + } + + fmt.Println("- " + dstPath) + } + + return nil + }, } diff --git a/cmd/root.go b/cmd/root.go index 8f793742..dd91c1b2 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -13,20 +13,17 @@ import ( "os" "os/signal" "path/filepath" - "strings" "syscall" "time" - homedir "github.com/mitchellh/go-homedir" "github.com/spf13/afero" "github.com/spf13/cobra" "github.com/spf13/pflag" - v "github.com/spf13/viper" + "github.com/spf13/viper" lumberjack "gopkg.in/natefinch/lumberjack.v2" "github.com/filebrowser/filebrowser/v2/auth" "github.com/filebrowser/filebrowser/v2/diskcache" - fbErrors "github.com/filebrowser/filebrowser/v2/errors" "github.com/filebrowser/filebrowser/v2/frontend" fbhttp "github.com/filebrowser/filebrowser/v2/http" "github.com/filebrowser/filebrowser/v2/img" @@ -36,28 +33,67 @@ import ( ) var ( - cfgFile string + flagNamesMigrations = map[string]string{ + "file-mode": "fileMode", + "dir-mode": "dirMode", + "hide-login-button": "hideLoginButton", + "create-user-dir": "createUserDir", + "minimum-password-length": "minimumPasswordLength", + "socket-perm": "socketPerm", + "disable-thumbnails": "disableThumbnails", + "disable-preview-resize": "disablePreviewResize", + "disable-exec": "disableExec", + "disable-type-detection-by-header": "disableTypeDetectionByHeader", + "img-processors": "imageProcessors", + "cache-dir": "cacheDir", + "token-expiration-time": "tokenExpirationTime", + "baseurl": "baseURL", + } + + warnedFlags = map[string]bool{} ) +// TODO(remove): remove after July 2026. +func migrateFlagNames(_ *pflag.FlagSet, name string) pflag.NormalizedName { + if newName, ok := flagNamesMigrations[name]; ok { + + if !warnedFlags[name] { + warnedFlags[name] = true + log.Printf("DEPRECATION NOTICE: Flag --%s has been deprecated, use --%s instead\n", name, newName) + } + + name = newName + } + + return pflag.NormalizedName(name) +} + func init() { - cobra.OnInitialize(initConfig) rootCmd.SilenceUsage = true + rootCmd.SetGlobalNormalizationFunc(migrateFlagNames) + cobra.MousetrapHelpText = "" rootCmd.SetVersionTemplate("File Browser version {{printf \"%s\" .Version}}\n") - flags := rootCmd.Flags() + // Flags available across the whole program persistent := rootCmd.PersistentFlags() - - persistent.StringVarP(&cfgFile, "config", "c", "", "config file path") + persistent.StringP("config", "c", "", "config file path") persistent.StringP("database", "d", "./filebrowser.db", "database path") - flags.Bool("noauth", false, "use the noauth auther when using quick setup") - flags.String("username", "admin", "username for the first user when using quick config") - flags.String("password", "", "hashed password for the first user when using quick config") + // Runtime flags for the root command + flags := rootCmd.Flags() + flags.Bool("noauth", false, "use the noauth auther when using quick setup") + flags.String("username", "admin", "username for the first user when using quick setup") + flags.String("password", "", "hashed password for the first user when using quick setup") + flags.Uint32("socketPerm", 0666, "unix socket file permissions") + flags.String("cacheDir", "", "file cache directory (disabled if empty)") + flags.Int("imageProcessors", 4, "image processors count") addServerFlags(flags) } +// addServerFlags adds server related flags to the given FlagSet. These flags are available +// in both the root command, config set and config init commands. func addServerFlags(flags *pflag.FlagSet) { flags.StringP("address", "a", "127.0.0.1", "address to listen on") flags.StringP("log", "l", "stdout", "log output") @@ -66,15 +102,12 @@ func addServerFlags(flags *pflag.FlagSet) { flags.StringP("key", "k", "", "tls key") flags.StringP("root", "r", ".", "root to prepend to relative paths") flags.String("socket", "", "socket to listen to (cannot be used with address, port, cert nor key flags)") - flags.Uint32("socket-perm", 0666, "unix socket file permissions") - flags.StringP("baseurl", "b", "", "base url") - flags.String("cache-dir", "", "file cache directory (disabled if empty)") - flags.String("token-expiration-time", "2h", "user session timeout") - flags.Int("img-processors", 4, "image processors count") //nolint:mnd - flags.Bool("disable-thumbnails", false, "disable image thumbnails") - flags.Bool("disable-preview-resize", false, "disable resize of image previews") - flags.Bool("disable-exec", true, "disables Command Runner feature") - flags.Bool("disable-type-detection-by-header", false, "disables type detection by reading file headers") + flags.StringP("baseURL", "b", "", "base url") + flags.String("tokenExpirationTime", "2h", "user session timeout") + flags.Bool("disableThumbnails", false, "disable image thumbnails") + flags.Bool("disablePreviewResize", false, "disable resize of image previews") + flags.Bool("disableExec", true, "disables Command Runner feature") + flags.Bool("disableTypeDetectionByHeader", false, "disables type detection by reading file headers") } var rootCmd = &cobra.Command{ @@ -89,12 +122,14 @@ it. Don't worry: you don't need to setup a separate database server. We're using Bolt DB which is a single file database and all managed by ourselves. -For this specific command, all the flags you have available (except -"config" for the configuration file), can be given either through -environment variables or configuration files. +For this command, all flags are available as environmental variables, +except for "--config", which specifies the configuration file to use. +The environment variables are prefixed by "FB_" followed by the flag name in +UPPER_SNAKE_CASE. For example, the flag "--disablePreviewResize" is available +as FB_DISABLE_PREVIEW_RESIZE. -If you don't set "config", it will look for a configuration file called -.filebrowser.{json, toml, yaml, yml} in the following directories: +If "--config" is not specified, File Browser will look for a configuration +file named .filebrowser.{json, toml, yaml, yml} in the following directories: - ./ - $HOME/ @@ -102,52 +137,40 @@ If you don't set "config", it will look for a configuration file called The precedence of the configuration values are as follows: -- flags -- environment variables -- configuration file -- database values -- defaults - -The environment variables are prefixed by "FB_" followed by the option -name in caps. So to set "database" via an env variable, you should -set FB_DATABASE. +- Flags +- Environment variables +- Configuration file +- Database values +- Defaults Also, if the database path doesn't exist, File Browser will enter into the quick setup mode and a new database will be bootstrapped and a new user created with the credentials from options "username" and "password".`, - RunE: python(func(cmd *cobra.Command, _ []string, d *pythonData) error { - log.Println(cfgFile) - - if !d.hadDB { - err := quickSetup(cmd.Flags(), *d) + RunE: withViperAndStore(func(_ *cobra.Command, _ []string, v *viper.Viper, st *store) error { + if !st.databaseExisted { + err := quickSetup(v, st.Storage) if err != nil { return err } } // build img service - workersCount, err := cmd.Flags().GetInt("img-processors") - if err != nil { - return err - } - if workersCount < 1 { + imgWorkersCount := v.GetInt("imageProcessors") + if imgWorkersCount < 1 { return errors.New("image resize workers count could not be < 1") } - imgSvc := img.New(workersCount) + imageService := img.New(imgWorkersCount) var fileCache diskcache.Interface = diskcache.NewNoOp() - cacheDir, err := cmd.Flags().GetString("cache-dir") - if err != nil { - return err - } + cacheDir := v.GetString("cacheDir") if cacheDir != "" { - if err := os.MkdirAll(cacheDir, 0700); err != nil { //nolint:govet + if err := os.MkdirAll(cacheDir, 0700); err != nil { return fmt.Errorf("can't make directory %s: %w", cacheDir, err) } fileCache = diskcache.New(afero.NewOsFs(), cacheDir) } - server, err := getRunParams(cmd.Flags(), d.store) + server, err := getServerSettings(v, st.Storage) if err != nil { return err } @@ -169,16 +192,13 @@ user created with the credentials from options "username" and "password".`, if err != nil { return err } - socketPerm, err := cmd.Flags().GetUint32("socket-perm") //nolint:govet - if err != nil { - return err - } + socketPerm := v.GetUint32("socketPerm") err = os.Chmod(server.Socket, os.FileMode(socketPerm)) if err != nil { return err } case server.TLSKey != "" && server.TLSCert != "": - cer, err := tls.LoadX509KeyPair(server.TLSCert, server.TLSKey) //nolint:govet + cer, err := tls.LoadX509KeyPair(server.TLSCert, server.TLSKey) if err != nil { return err } @@ -201,7 +221,7 @@ user created with the credentials from options "username" and "password".`, panic(err) } - handler, err := fbhttp.NewHandler(imgSvc, fileCache, d.store, server, assetsFs) + handler, err := fbhttp.NewHandler(imageService, fileCache, st.Storage, server, assetsFs) if err != nil { return err } @@ -233,7 +253,7 @@ user created with the credentials from options "username" and "password".`, sig := <-sigc log.Println("Got signal:", sig) - shutdownCtx, shutdownRelease := context.WithTimeout(context.Background(), 10*time.Second) //nolint:mnd + shutdownCtx, shutdownRelease := context.WithTimeout(context.Background(), 10*time.Second) defer shutdownRelease() if err := srv.Shutdown(shutdownCtx); err != nil { @@ -241,66 +261,78 @@ user created with the credentials from options "username" and "password".`, } log.Println("Graceful shutdown complete.") - switch sig { - case syscall.SIGHUP: - d.err = fbErrors.ErrSighup - case syscall.SIGINT: - d.err = fbErrors.ErrSigint - case syscall.SIGQUIT: - d.err = fbErrors.ErrSigquit - case syscall.SIGTERM: - d.err = fbErrors.ErrSigTerm - } - - return d.err - }, pythonConfig{allowNoDB: true}), + return nil + }, storeOptions{allowsNoDatabase: true}), } -//nolint:gocyclo -func getRunParams(flags *pflag.FlagSet, st *storage.Storage) (*settings.Server, error) { +func getServerSettings(v *viper.Viper, st *storage.Storage) (*settings.Server, error) { server, err := st.Settings.GetServer() if err != nil { return nil, err } - if val, set := getStringParamB(flags, "root"); set { - server.Root = val - } - - if val, set := getStringParamB(flags, "baseurl"); set { - server.BaseURL = val - } - - if val, set := getStringParamB(flags, "log"); set { - server.Log = val - } - isSocketSet := false isAddrSet := false - if val, set := getStringParamB(flags, "address"); set { - server.Address = val - isAddrSet = isAddrSet || set + if v.IsSet("address") { + server.Address = v.GetString("address") + isAddrSet = true } - if val, set := getStringParamB(flags, "port"); set { - server.Port = val - isAddrSet = isAddrSet || set + if v.IsSet("log") { + server.Log = v.GetString("log") } - if val, set := getStringParamB(flags, "key"); set { - server.TLSKey = val - isAddrSet = isAddrSet || set + if v.IsSet("port") { + server.Port = v.GetString("port") + isAddrSet = true } - if val, set := getStringParamB(flags, "cert"); set { - server.TLSCert = val - isAddrSet = isAddrSet || set + if v.IsSet("cert") { + server.TLSCert = v.GetString("cert") + isAddrSet = true } - if val, set := getStringParamB(flags, "socket"); set { - server.Socket = val - isSocketSet = isSocketSet || set + if v.IsSet("key") { + server.TLSKey = v.GetString("key") + isAddrSet = true + } + + if v.IsSet("root") { + server.Root = v.GetString("root") + } + + if v.IsSet("socket") { + server.Socket = v.GetString("socket") + isSocketSet = true + } + + if v.IsSet("baseURL") { + server.BaseURL = v.GetString("baseURL") + // TODO(remove): remove after July 2026. + } else if v := os.Getenv("FB_BASEURL"); v != "" { + log.Println("DEPRECATION NOTICE: Environment variable FB_BASEURL has been deprecated, use FB_BASE_URL instead") + server.BaseURL = v + } + + if v.IsSet("tokenExpirationTime") { + server.TokenExpirationTime = v.GetString("tokenExpirationTime") + } + + if v.IsSet("disableThumbnails") { + server.EnableThumbnails = !v.GetBool("disableThumbnails") + } + + if v.IsSet("disablePreviewResize") { + server.ResizePreview = !v.GetBool("disablePreviewResize") + } + + if v.IsSet("disableTypeDetectionByHeader") { + server.TypeDetectionByHeader = !v.GetBool("disableTypeDetectionByHeader") + } + + if v.IsSet("disableExec") { + server.EnableExec = !v.GetBool("disableExec") } if isAddrSet && isSocketSet { @@ -312,18 +344,6 @@ func getRunParams(flags *pflag.FlagSet, st *storage.Storage) (*settings.Server, server.Socket = "" } - disableThumbnails := getBoolParam(flags, "disable-thumbnails") - server.EnableThumbnails = !disableThumbnails - - disablePreviewResize := getBoolParam(flags, "disable-preview-resize") - server.ResizePreview = !disablePreviewResize - - disableTypeDetectionByHeader := getBoolParam(flags, "disable-type-detection-by-header") - server.TypeDetectionByHeader = !disableTypeDetectionByHeader - - disableExec := getBoolParam(flags, "disable-exec") - server.EnableExec = !disableExec - if server.EnableExec { log.Println("WARNING: Command Runner feature enabled!") log.Println("WARNING: This feature has known security vulnerabilities and should not") @@ -331,71 +351,9 @@ func getRunParams(flags *pflag.FlagSet, st *storage.Storage) (*settings.Server, log.Println("WARNING: read https://github.com/filebrowser/filebrowser/issues/5199") } - if val, set := getStringParamB(flags, "token-expiration-time"); set { - server.TokenExpirationTime = val - } - return server, nil } -// getBoolParamB returns a parameter as a string and a boolean to tell if it is different from the default -// -// NOTE: we could simply bind the flags to viper and use IsSet. -// Although there is a bug on Viper that always returns true on IsSet -// if a flag is binded. Our alternative way is to manually check -// the flag and then the value from env/config/gotten by viper. -// https://github.com/spf13/viper/pull/331 -func getBoolParamB(flags *pflag.FlagSet, key string) (value, ok bool) { - value, _ = flags.GetBool(key) - - // If set on Flags, use it. - if flags.Changed(key) { - return value, true - } - - // If set through viper (env, config), return it. - if v.IsSet(key) { - return v.GetBool(key), true - } - - // Otherwise use default value on flags. - return value, false -} - -func getBoolParam(flags *pflag.FlagSet, key string) bool { - val, _ := getBoolParamB(flags, key) - return val -} - -// getStringParamB returns a parameter as a string and a boolean to tell if it is different from the default -// -// NOTE: we could simply bind the flags to viper and use IsSet. -// Although there is a bug on Viper that always returns true on IsSet -// if a flag is binded. Our alternative way is to manually check -// the flag and then the value from env/config/gotten by viper. -// https://github.com/spf13/viper/pull/331 -func getStringParamB(flags *pflag.FlagSet, key string) (string, bool) { - value, _ := flags.GetString(key) - - // If set on Flags, use it. - if flags.Changed(key) { - return value, true - } - - // If set through viper (env, config), return it. - if v.IsSet(key) { - return v.GetString(key), true - } - - // Otherwise use default value on flags. - return value, false -} - -func getStringParam(flags *pflag.FlagSet, key string) string { - val, _ := getStringParamB(flags, key) - return val -} - func setupLog(logMethod string) { switch logMethod { case "stdout": @@ -414,7 +372,7 @@ func setupLog(logMethod string) { } } -func quickSetup(flags *pflag.FlagSet, d pythonData) error { +func quickSetup(v *viper.Viper, s *storage.Storage) error { log.Println("Performing quick setup") set := &settings.Settings{ @@ -428,7 +386,7 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) error { Scope: ".", Locale: "en", SingleClick: false, - AceEditorTheme: getStringParam(flags, "defaults.aceEditorTheme"), + AceEditorTheme: v.GetString("defaults.aceEditorTheme"), Perm: users.Permissions{ Admin: false, Execute: true, @@ -452,39 +410,44 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) error { } var err error - if _, noauth := getStringParamB(flags, "noauth"); noauth { + if v.GetBool("noauth") { set.AuthMethod = auth.MethodNoAuth - err = d.store.Auth.Save(&auth.NoAuth{}) + err = s.Auth.Save(&auth.NoAuth{}) } else { set.AuthMethod = auth.MethodJSONAuth - err = d.store.Auth.Save(&auth.JSONAuth{}) + err = s.Auth.Save(&auth.JSONAuth{}) } if err != nil { return err } - err = d.store.Settings.Save(set) + err = s.Settings.Save(set) if err != nil { return err } ser := &settings.Server{ - BaseURL: getStringParam(flags, "baseurl"), - Port: getStringParam(flags, "port"), - Log: getStringParam(flags, "log"), - TLSKey: getStringParam(flags, "key"), - TLSCert: getStringParam(flags, "cert"), - Address: getStringParam(flags, "address"), - Root: getStringParam(flags, "root"), + BaseURL: v.GetString("baseURL"), + Port: v.GetString("port"), + Log: v.GetString("log"), + TLSKey: v.GetString("key"), + TLSCert: v.GetString("cert"), + Address: v.GetString("address"), + Root: v.GetString("root"), + TokenExpirationTime: v.GetString("tokenExpirationTime"), + EnableThumbnails: !v.GetBool("disableThumbnails"), + ResizePreview: !v.GetBool("disablePreviewResize"), + EnableExec: !v.GetBool("disableExec"), + TypeDetectionByHeader: !v.GetBool("disableTypeDetectionByHeader"), } - err = d.store.Settings.SaveServer(ser) + err = s.Settings.SaveServer(ser) if err != nil { return err } - username := getStringParam(flags, "username") - password := getStringParam(flags, "password") + username := v.GetString("username") + password := v.GetString("password") if password == "" { var pwd string @@ -515,35 +478,5 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) error { set.Defaults.Apply(user) user.Perm.Admin = true - return d.store.Users.Save(user) -} - -func initConfig() { - if cfgFile == "" { - home, err := homedir.Dir() - if err != nil { - panic(err) - } - v.AddConfigPath(".") - v.AddConfigPath(home) - v.AddConfigPath("/etc/filebrowser/") - v.SetConfigName(".filebrowser") - } else { - v.SetConfigFile(cfgFile) - } - - v.SetEnvPrefix("FB") - v.AutomaticEnv() - v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) - v.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) - - if err := v.ReadInConfig(); err != nil { - var configParseError v.ConfigParseError - if errors.As(err, &configParseError) { - panic(err) - } - cfgFile = "No config file used" - } else { - cfgFile = "Using config file: " + v.ConfigFileUsed() - } + return s.Users.Save(user) } diff --git a/cmd/rule_rm.go b/cmd/rule_rm.go index 26e801ae..8ed8f151 100644 --- a/cmd/rule_rm.go +++ b/cmd/rule_rm.go @@ -40,7 +40,7 @@ including 'index_end'.`, return nil }, - RunE: python(func(cmd *cobra.Command, args []string, d *pythonData) error { + RunE: withStore(func(cmd *cobra.Command, args []string, st *store) error { i, err := strconv.Atoi(args[0]) if err != nil { return err @@ -55,14 +55,14 @@ including 'index_end'.`, user := func(u *users.User) error { u.Rules = append(u.Rules[:i], u.Rules[f+1:]...) - return d.store.Users.Save(u) + return st.Users.Save(u) } global := func(s *settings.Settings) error { s.Rules = append(s.Rules[:i], s.Rules[f+1:]...) - return d.store.Settings.Save(s) + return st.Settings.Save(s) } - return runRules(d.store, cmd, user, global) - }, pythonConfig{}), + return runRules(st.Storage, cmd, user, global) + }, storeOptions{}), } diff --git a/cmd/rules.go b/cmd/rules.go index ffa5b1ae..bdb1d1cf 100644 --- a/cmd/rules.go +++ b/cmd/rules.go @@ -69,11 +69,12 @@ func runRules(st *storage.Storage, cmd *cobra.Command, usersFn func(*users.User) } func getUserIdentifier(flags *pflag.FlagSet) (interface{}, error) { - id, err := getUint(flags, "id") + id, err := flags.GetUint("id") if err != nil { return nil, err } - username, err := getString(flags, "username") + + username, err := flags.GetString("username") if err != nil { return nil, err } diff --git a/cmd/rules_add.go b/cmd/rules_add.go index 9d1f0cf9..3b34d940 100644 --- a/cmd/rules_add.go +++ b/cmd/rules_add.go @@ -21,15 +21,19 @@ var rulesAddCmd = &cobra.Command{ Short: "Add a global rule or user rule", Long: `Add a global rule or user rule.`, Args: cobra.ExactArgs(1), - RunE: python(func(cmd *cobra.Command, args []string, d *pythonData) error { - allow, err := getBool(cmd.Flags(), "allow") + RunE: withStore(func(cmd *cobra.Command, args []string, st *store) error { + flags := cmd.Flags() + + allow, err := flags.GetBool("allow") if err != nil { return err } - regex, err := getBool(cmd.Flags(), "regex") + + regex, err := flags.GetBool("regex") if err != nil { return err } + exp := args[0] if regex { @@ -49,14 +53,14 @@ var rulesAddCmd = &cobra.Command{ user := func(u *users.User) error { u.Rules = append(u.Rules, rule) - return d.store.Users.Save(u) + return st.Users.Save(u) } global := func(s *settings.Settings) error { s.Rules = append(s.Rules, rule) - return d.store.Settings.Save(s) + return st.Settings.Save(s) } - return runRules(d.store, cmd, user, global) - }, pythonConfig{}), + return runRules(st.Storage, cmd, user, global) + }, storeOptions{}), } diff --git a/cmd/rules_ls.go b/cmd/rules_ls.go index 67a279dc..9aa073d0 100644 --- a/cmd/rules_ls.go +++ b/cmd/rules_ls.go @@ -13,7 +13,7 @@ var rulesLsCommand = &cobra.Command{ Short: "List global rules or user specific rules", Long: `List global rules or user specific rules.`, Args: cobra.NoArgs, - RunE: python(func(cmd *cobra.Command, _ []string, d *pythonData) error { - return runRules(d.store, cmd, nil, nil) - }, pythonConfig{}), + RunE: withStore(func(cmd *cobra.Command, _ []string, st *store) error { + return runRules(st.Storage, cmd, nil, nil) + }, storeOptions{}), } diff --git a/cmd/upgrade.go b/cmd/upgrade.go deleted file mode 100644 index 7142b151..00000000 --- a/cmd/upgrade.go +++ /dev/null @@ -1,40 +0,0 @@ -package cmd - -import ( - "github.com/spf13/cobra" - - "github.com/filebrowser/filebrowser/v2/storage/bolt/importer" -) - -func init() { - rootCmd.AddCommand(upgradeCmd) - - upgradeCmd.Flags().String("old.database", "", "") - upgradeCmd.Flags().String("old.config", "", "") - _ = upgradeCmd.MarkFlagRequired("old.database") -} - -var upgradeCmd = &cobra.Command{ - Use: "upgrade", - Short: "Upgrades an old configuration", - Long: `Upgrades an old configuration. This command DOES NOT -import share links because they are incompatible with -this version.`, - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, _ []string) error { - flags := cmd.Flags() - oldDB, err := getString(flags, "old.database") - if err != nil { - return err - } - oldConf, err := getString(flags, "old.config") - if err != nil { - return err - } - db, err := getString(flags, "database") - if err != nil { - return err - } - return importer.Import(oldDB, oldConf, db) - }, -} diff --git a/cmd/users.go b/cmd/users.go index 64cd08ee..86434a42 100644 --- a/cmd/users.go +++ b/cmd/users.go @@ -80,67 +80,66 @@ func addUserFlags(flags *pflag.FlagSet) { flags.Bool("dateFormat", false, "use date format (true for absolute time, false for relative)") flags.Bool("hideDotfiles", false, "hide dotfiles") flags.String("aceEditorTheme", "", "ace editor's syntax highlighting theme for users") - flags.Bool("hide-dotfiles", false, "Hide dotfiles by default") } -func getViewMode(flags *pflag.FlagSet) (users.ViewMode, error) { - viewModeStr, err := getString(flags, "viewMode") +func getAndParseViewMode(flags *pflag.FlagSet) (users.ViewMode, error) { + viewModeStr, err := flags.GetString("viewMode") if err != nil { return "", err } + viewMode := users.ViewMode(viewModeStr) if viewMode != users.ListViewMode && viewMode != users.MosaicViewMode { return "", errors.New("view mode must be \"" + string(users.ListViewMode) + "\" or \"" + string(users.MosaicViewMode) + "\"") } + return viewMode, nil } -//nolint:gocyclo func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all bool) error { - var visitErr error + errs := []error{} + visit := func(flag *pflag.Flag) { - if visitErr != nil { - return - } var err error switch flag.Name { case "scope": - defaults.Scope, err = getString(flags, flag.Name) + defaults.Scope, err = flags.GetString(flag.Name) case "locale": - defaults.Locale, err = getString(flags, flag.Name) + defaults.Locale, err = flags.GetString(flag.Name) case "viewMode": - defaults.ViewMode, err = getViewMode(flags) + defaults.ViewMode, err = getAndParseViewMode(flags) case "singleClick": - defaults.SingleClick, err = getBool(flags, flag.Name) + defaults.SingleClick, err = flags.GetBool(flag.Name) case "aceEditorTheme": - defaults.AceEditorTheme, err = getString(flags, flag.Name) + defaults.AceEditorTheme, err = flags.GetString(flag.Name) case "perm.admin": - defaults.Perm.Admin, err = getBool(flags, flag.Name) + defaults.Perm.Admin, err = flags.GetBool(flag.Name) case "perm.execute": - defaults.Perm.Execute, err = getBool(flags, flag.Name) + defaults.Perm.Execute, err = flags.GetBool(flag.Name) case "perm.create": - defaults.Perm.Create, err = getBool(flags, flag.Name) + defaults.Perm.Create, err = flags.GetBool(flag.Name) case "perm.rename": - defaults.Perm.Rename, err = getBool(flags, flag.Name) + defaults.Perm.Rename, err = flags.GetBool(flag.Name) case "perm.modify": - defaults.Perm.Modify, err = getBool(flags, flag.Name) + defaults.Perm.Modify, err = flags.GetBool(flag.Name) case "perm.delete": - defaults.Perm.Delete, err = getBool(flags, flag.Name) + defaults.Perm.Delete, err = flags.GetBool(flag.Name) case "perm.share": - defaults.Perm.Share, err = getBool(flags, flag.Name) + defaults.Perm.Share, err = flags.GetBool(flag.Name) case "perm.download": - defaults.Perm.Download, err = getBool(flags, flag.Name) + defaults.Perm.Download, err = flags.GetBool(flag.Name) case "commands": defaults.Commands, err = flags.GetStringSlice(flag.Name) case "sorting.by": - defaults.Sorting.By, err = getString(flags, flag.Name) + defaults.Sorting.By, err = flags.GetString(flag.Name) case "sorting.asc": - defaults.Sorting.Asc, err = getBool(flags, flag.Name) - case "hide-dotfiles": - defaults.HideDotfiles, err = getBool(flags, flag.Name) + defaults.Sorting.Asc, err = flags.GetBool(flag.Name) + case "hideDotfiles": + defaults.HideDotfiles, err = flags.GetBool(flag.Name) } + if err != nil { - visitErr = err + errs = append(errs, err) } } @@ -149,5 +148,6 @@ func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all } else { flags.Visit(visit) } - return visitErr + + return errors.Join(errs...) } diff --git a/cmd/users_add.go b/cmd/users_add.go index dce7ff98..daf59aa3 100644 --- a/cmd/users_add.go +++ b/cmd/users_add.go @@ -16,12 +16,13 @@ var usersAddCmd = &cobra.Command{ Short: "Create a new user", Long: `Create a new user and add it to the database.`, Args: cobra.ExactArgs(2), - RunE: python(func(cmd *cobra.Command, args []string, d *pythonData) error { - s, err := d.store.Settings.Get() + RunE: withStore(func(cmd *cobra.Command, args []string, st *store) error { + flags := cmd.Flags() + s, err := st.Settings.Get() if err != nil { return err } - err = getUserDefaults(cmd.Flags(), &s.Defaults, false) + err = getUserDefaults(flags, &s.Defaults, false) if err != nil { return err } @@ -31,39 +32,36 @@ var usersAddCmd = &cobra.Command{ return err } - lockPassword, err := getBool(cmd.Flags(), "lockPassword") - if err != nil { - return err - } - - dateFormat, err := getBool(cmd.Flags(), "dateFormat") - if err != nil { - return err - } - - hideDotfiles, err := getBool(cmd.Flags(), "hideDotfiles") - if err != nil { - return err - } - user := &users.User{ - Username: args[0], - Password: password, - LockPassword: lockPassword, - DateFormat: dateFormat, - HideDotfiles: hideDotfiles, + Username: args[0], + Password: password, + } + + user.LockPassword, err = flags.GetBool("lockPassword") + if err != nil { + return err + } + + user.DateFormat, err = flags.GetBool("dateFormat") + if err != nil { + return err + } + + user.HideDotfiles, err = flags.GetBool("hideDotfiles") + if err != nil { + return err } s.Defaults.Apply(user) - servSettings, err := d.store.Settings.GetServer() + servSettings, err := st.Settings.GetServer() if err != nil { return err } // since getUserDefaults() polluted s.Defaults.Scope // which makes the Scope not the one saved in the db // we need the right s.Defaults.Scope here - s2, err := d.store.Settings.Get() + s2, err := st.Settings.Get() if err != nil { return err } @@ -74,11 +72,11 @@ var usersAddCmd = &cobra.Command{ } user.Scope = userHome - err = d.store.Users.Save(user) + err = st.Users.Save(user) if err != nil { return err } printUsers([]*users.User{user}) return nil - }, pythonConfig{}), + }, storeOptions{}), } diff --git a/cmd/users_export.go b/cmd/users_export.go index d6009a37..9bbec6d8 100644 --- a/cmd/users_export.go +++ b/cmd/users_export.go @@ -14,8 +14,8 @@ var usersExportCmd = &cobra.Command{ Long: `Export all users to a json or yaml file. Please indicate the path to the file where you want to write the users.`, Args: jsonYamlArg, - RunE: python(func(_ *cobra.Command, args []string, d *pythonData) error { - list, err := d.store.Users.Gets("") + RunE: withStore(func(_ *cobra.Command, args []string, st *store) error { + list, err := st.Users.Gets("") if err != nil { return err } @@ -25,5 +25,5 @@ path to the file where you want to write the users.`, return err } return nil - }, pythonConfig{}), + }, storeOptions{}), } diff --git a/cmd/users_find.go b/cmd/users_find.go index 0dea071a..09bc8d47 100644 --- a/cmd/users_find.go +++ b/cmd/users_find.go @@ -26,7 +26,7 @@ var usersLsCmd = &cobra.Command{ RunE: findUsers, } -var findUsers = python(func(_ *cobra.Command, args []string, d *pythonData) error { +var findUsers = withStore(func(_ *cobra.Command, args []string, st *store) error { var ( list []*users.User user *users.User @@ -36,14 +36,14 @@ var findUsers = python(func(_ *cobra.Command, args []string, d *pythonData) erro if len(args) == 1 { username, id := parseUsernameOrID(args[0]) if username != "" { - user, err = d.store.Users.Get("", username) + user, err = st.Users.Get("", username) } else { - user, err = d.store.Users.Get("", id) + user, err = st.Users.Get("", id) } list = []*users.User{user} } else { - list, err = d.store.Users.Gets("") + list, err = st.Users.Gets("") } if err != nil { @@ -51,4 +51,4 @@ var findUsers = python(func(_ *cobra.Command, args []string, d *pythonData) erro } printUsers(list) return nil -}, pythonConfig{}) +}, storeOptions{}) diff --git a/cmd/users_import.go b/cmd/users_import.go index d20dca68..73effca6 100644 --- a/cmd/users_import.go +++ b/cmd/users_import.go @@ -25,7 +25,8 @@ file. You can use this command to import new users to your installation. For that, just don't place their ID on the files list or set it to 0.`, Args: jsonYamlArg, - RunE: python(func(cmd *cobra.Command, args []string, d *pythonData) error { + RunE: withStore(func(cmd *cobra.Command, args []string, st *store) error { + flags := cmd.Flags() fd, err := os.Open(args[0]) if err != nil { return err @@ -45,13 +46,13 @@ list or set it to 0.`, } } - replace, err := getBool(cmd.Flags(), "replace") + replace, err := flags.GetBool("replace") if err != nil { return err } if replace { - oldUsers, userImportErr := d.store.Users.Gets("") + oldUsers, userImportErr := st.Users.Gets("") if userImportErr != nil { return userImportErr } @@ -62,20 +63,20 @@ list or set it to 0.`, } for _, user := range oldUsers { - err = d.store.Users.Delete(user.ID) + err = st.Users.Delete(user.ID) if err != nil { return err } } } - overwrite, err := getBool(cmd.Flags(), "overwrite") + overwrite, err := flags.GetBool("overwrite") if err != nil { return err } for _, user := range list { - onDB, err := d.store.Users.Get("", user.ID) + onDB, err := st.Users.Get("", user.ID) // User exists in DB. if err == nil { @@ -87,7 +88,7 @@ list or set it to 0.`, // with the new username. If there is, print an error and cancel the // operation if user.Username != onDB.Username { - if conflictuous, err := d.store.Users.Get("", user.Username); err == nil { //nolint:govet + if conflictuous, err := st.Users.Get("", user.Username); err == nil { return usernameConflictError(user.Username, conflictuous.ID, user.ID) } } @@ -97,13 +98,13 @@ list or set it to 0.`, user.ID = 0 } - err = d.store.Users.Save(user) + err = st.Users.Save(user) if err != nil { return err } } return nil - }, pythonConfig{}), + }, storeOptions{}), } func usernameConflictError(username string, originalID, newID uint) error { diff --git a/cmd/users_rm.go b/cmd/users_rm.go index 55b973f4..492a55c3 100644 --- a/cmd/users_rm.go +++ b/cmd/users_rm.go @@ -15,14 +15,14 @@ var usersRmCmd = &cobra.Command{ Short: "Delete a user by username or id", Long: `Delete a user by username or id`, Args: cobra.ExactArgs(1), - RunE: python(func(_ *cobra.Command, args []string, d *pythonData) error { + RunE: withStore(func(_ *cobra.Command, args []string, st *store) error { username, id := parseUsernameOrID(args[0]) var err error if username != "" { - err = d.store.Users.Delete(username) + err = st.Users.Delete(username) } else { - err = d.store.Users.Delete(id) + err = st.Users.Delete(id) } if err != nil { @@ -30,5 +30,5 @@ var usersRmCmd = &cobra.Command{ } fmt.Println("user deleted successfully") return nil - }, pythonConfig{}), + }, storeOptions{}), } diff --git a/cmd/users_update.go b/cmd/users_update.go index a939e605..96f1e2d3 100644 --- a/cmd/users_update.go +++ b/cmd/users_update.go @@ -21,19 +21,20 @@ var usersUpdateCmd = &cobra.Command{ Long: `Updates an existing user. Set the flags for the options you want to change.`, Args: cobra.ExactArgs(1), - RunE: python(func(cmd *cobra.Command, args []string, d *pythonData) error { - username, id := parseUsernameOrID(args[0]) + RunE: withStore(func(cmd *cobra.Command, args []string, st *store) error { flags := cmd.Flags() - password, err := getString(flags, "password") - if err != nil { - return err - } - newUsername, err := getString(flags, "username") + username, id := parseUsernameOrID(args[0]) + password, err := flags.GetString("password") if err != nil { return err } - s, err := d.store.Settings.Get() + newUsername, err := flags.GetString("username") + if err != nil { + return err + } + + s, err := st.Settings.Get() if err != nil { return err } @@ -41,13 +42,11 @@ options you want to change.`, var ( user *users.User ) - if id != 0 { - user, err = d.store.Users.Get("", id) + user, err = st.Users.Get("", id) } else { - user, err = d.store.Users.Get("", username) + user, err = st.Users.Get("", username) } - if err != nil { return err } @@ -61,10 +60,12 @@ options you want to change.`, Sorting: user.Sorting, Commands: user.Commands, } + err = getUserDefaults(flags, &defaults, false) if err != nil { return err } + user.Scope = defaults.Scope user.Locale = defaults.Locale user.ViewMode = defaults.ViewMode @@ -72,15 +73,17 @@ options you want to change.`, user.Perm = defaults.Perm user.Commands = defaults.Commands user.Sorting = defaults.Sorting - user.LockPassword, err = getBool(flags, "lockPassword") + user.LockPassword, err = flags.GetBool("lockPassword") if err != nil { return err } - user.DateFormat, err = getBool(flags, "dateFormat") + + user.DateFormat, err = flags.GetBool("dateFormat") if err != nil { return err } - user.HideDotfiles, err = getBool(flags, "hideDotfiles") + + user.HideDotfiles, err = flags.GetBool("hideDotfiles") if err != nil { return err } @@ -96,11 +99,11 @@ options you want to change.`, } } - err = d.store.Users.Update(user) + err = st.Users.Update(user) if err != nil { return err } printUsers([]*users.User{user}) return nil - }, pythonConfig{}), + }, storeOptions{}), } diff --git a/cmd/utils.go b/cmd/utils.go index 1971afd4..ee637fa3 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -12,8 +12,11 @@ import ( "strings" "github.com/asdine/storm/v3" + homedir "github.com/mitchellh/go-homedir" + "github.com/samber/lo" "github.com/spf13/cobra" "github.com/spf13/pflag" + "github.com/spf13/viper" yaml "gopkg.in/yaml.v3" "github.com/filebrowser/filebrowser/v2/settings" @@ -21,42 +24,22 @@ import ( "github.com/filebrowser/filebrowser/v2/storage/bolt" ) -const dbPerms = 0640 +const databasePermissions = 0640 -func returnErr(err error) error { - if err != nil { - return err - } - return nil -} - -func getString(flags *pflag.FlagSet, flag string) (string, error) { - s, err := flags.GetString(flag) - return s, returnErr(err) -} - -func getMode(flags *pflag.FlagSet, flag string) (fs.FileMode, error) { - s, err := getString(flags, flag) +func getAndParseFileMode(flags *pflag.FlagSet, name string) (fs.FileMode, error) { + mode, err := flags.GetString(name) if err != nil { return 0, err } - b, err := strconv.ParseUint(s, 0, 32) + + b, err := strconv.ParseUint(mode, 0, 32) if err != nil { return 0, err } + return fs.FileMode(b), nil } -func getBool(flags *pflag.FlagSet, flag string) (bool, error) { - b, err := flags.GetBool(flag) - return b, returnErr(err) -} - -func getUint(flags *pflag.FlagSet, flag string) (uint, error) { - b, err := flags.GetUint(flag) - return b, returnErr(err) -} - func generateKey() []byte { k, err := settings.GenerateKey() if err != nil { @@ -65,20 +48,6 @@ func generateKey() []byte { return k } -type cobraFunc func(cmd *cobra.Command, args []string) error -type pythonFunc func(cmd *cobra.Command, args []string, data *pythonData) error - -type pythonConfig struct { - noDB bool - allowNoDB bool -} - -type pythonData struct { - hadDB bool - store *storage.Storage - err error -} - func dbExists(path string) (bool, error) { stat, err := os.Stat(path) if err == nil { @@ -89,7 +58,7 @@ func dbExists(path string) (bool, error) { d := filepath.Dir(path) _, err = os.Stat(d) if os.IsNotExist(err) { - if err := os.MkdirAll(d, 0700); err != nil { //nolint:govet + if err := os.MkdirAll(d, 0700); err != nil { return false, err } return false, nil @@ -99,42 +68,137 @@ func dbExists(path string) (bool, error) { return false, err } -func python(fn pythonFunc, cfg pythonConfig) cobraFunc { +// Generate the replacements for all environment variables. This allows to +// use FB_BRANDING_DISABLE_EXTERNAL environment variables, even when the +// option name is branding.disableExternal. +func generateEnvKeyReplacements(cmd *cobra.Command) []string { + replacements := []string{} + + cmd.Flags().VisitAll(func(f *pflag.Flag) { + oldName := strings.ToUpper(f.Name) + newName := strings.ToUpper(lo.SnakeCase(f.Name)) + replacements = append(replacements, oldName, newName) + }) + + return replacements +} + +func initViper(cmd *cobra.Command) (*viper.Viper, error) { + v := viper.New() + + // Get config file from flag + cfgFile, err := cmd.Flags().GetString("config") + if err != nil { + return nil, err + } + + // Configuration file + if cfgFile == "" { + home, err := homedir.Dir() + if err != nil { + return nil, err + } + v.AddConfigPath(".") + v.AddConfigPath(home) + v.AddConfigPath("/etc/filebrowser/") + v.SetConfigName(".filebrowser") + } else { + v.SetConfigFile(cfgFile) + } + + // Environment variables + v.SetEnvPrefix("FB") + v.AutomaticEnv() + v.SetEnvKeyReplacer(strings.NewReplacer(generateEnvKeyReplacements(cmd)...)) + + // Bind the flags + err = v.BindPFlags(cmd.Flags()) + if err != nil { + return nil, err + } + + // Read in configuration + if err := v.ReadInConfig(); err != nil { + if errors.Is(err, viper.ConfigParseError{}) { + return nil, err + } + + log.Println("No config file used") + } else { + log.Printf("Using config file: %s", v.ConfigFileUsed()) + } + + // Return Viper + return v, nil +} + +type store struct { + *storage.Storage + databaseExisted bool +} + +type storeOptions struct { + expectsNoDatabase bool + allowsNoDatabase bool +} + +type cobraFunc func(cmd *cobra.Command, args []string) error + +// withViperAndStore initializes Viper and the storage.Store and passes them to the callback function. +// This function should only be used by [withStore] and the root command. No other command should call +// this function directly. +func withViperAndStore(fn func(cmd *cobra.Command, args []string, v *viper.Viper, store *store) error, options storeOptions) cobraFunc { return func(cmd *cobra.Command, args []string) error { - data := &pythonData{hadDB: true} - - path := getStringParam(cmd.Flags(), "database") - absPath, err := filepath.Abs(path) + v, err := initViper(cmd) if err != nil { - panic(err) + return err } + + path, err := filepath.Abs(v.GetString("database")) + if err != nil { + return err + } + exists, err := dbExists(path) - - if err != nil { - panic(err) - } else if exists && cfg.noDB { - log.Fatal(absPath + " already exists") - } else if !exists && !cfg.noDB && !cfg.allowNoDB { - log.Fatal(absPath + " does not exist. Please run 'filebrowser config init' first.") - } else if !exists && !cfg.noDB { - log.Println("Warning: filebrowser.db can't be found. Initialing in " + strings.TrimSuffix(absPath, "filebrowser.db")) + switch { + case err != nil: + return err + case exists && options.expectsNoDatabase: + log.Fatal(path + " already exists") + case !exists && !options.expectsNoDatabase && !options.allowsNoDatabase: + log.Fatal(path + " does not exist. Please run 'filebrowser config init' first.") + case !exists && !options.expectsNoDatabase: + log.Println("WARNING: filebrowser.db can't be found. Initialing in " + strings.TrimSuffix(path, "filebrowser.db")) } - log.Println("Using database: " + absPath) - data.hadDB = exists - db, err := storm.Open(path, storm.BoltOptions(dbPerms, nil)) + log.Println("Using database: " + path) + + db, err := storm.Open(path, storm.BoltOptions(databasePermissions, nil)) if err != nil { return err } defer db.Close() - data.store, err = bolt.NewStorage(db) + + storage, err := bolt.NewStorage(db) if err != nil { return err } - return fn(cmd, args, data) + + store := &store{ + Storage: storage, + databaseExisted: exists, + } + + return fn(cmd, args, v, store) } } +func withStore(fn func(cmd *cobra.Command, args []string, store *store) error, options storeOptions) cobraFunc { + return withViperAndStore(func(cmd *cobra.Command, args []string, _ *viper.Viper, store *store) error { + return fn(cmd, args, store) + }, options) +} + func marshal(filename string, data interface{}) error { fd, err := os.Create(filename) if err != nil { diff --git a/diskcache/file_cache.go b/diskcache/file_cache.go index cd5e27c7..b2979e4b 100644 --- a/diskcache/file_cache.go +++ b/diskcache/file_cache.go @@ -2,7 +2,7 @@ package diskcache import ( "context" - "crypto/sha1" //nolint:gosec + "crypto/sha1" "encoding/hex" "errors" "fmt" @@ -103,7 +103,7 @@ func (f *FileCache) getScopedLocks(key string) (lock sync.Locker) { } func (f *FileCache) getFileName(key string) string { - hasher := sha1.New() //nolint:gosec + hasher := sha1.New() _, _ = hasher.Write([]byte(key)) hash := hex.EncodeToString(hasher.Sum(nil)) return fmt.Sprintf("%s/%s/%s", hash[:1], hash[1:3], hash) diff --git a/diskcache/file_cache_test.go b/diskcache/file_cache_test.go index 31d58c8e..c6c750c0 100644 --- a/diskcache/file_cache_test.go +++ b/diskcache/file_cache_test.go @@ -25,12 +25,12 @@ func TestFileCache(t *testing.T) { // store new key err := cache.Store(ctx, key, []byte(value)) require.NoError(t, err) - checkValue(t, ctx, fs, filepath.Join(cacheRoot, cachedFilePath), cache, key, value) + checkValue(ctx, t, fs, filepath.Join(cacheRoot, cachedFilePath), cache, key, value) // update existing key err = cache.Store(ctx, key, []byte(newValue)) require.NoError(t, err) - checkValue(t, ctx, fs, filepath.Join(cacheRoot, cachedFilePath), cache, key, newValue) + checkValue(ctx, t, fs, filepath.Join(cacheRoot, cachedFilePath), cache, key, newValue) // delete key err = cache.Delete(ctx, key) @@ -40,7 +40,7 @@ func TestFileCache(t *testing.T) { require.False(t, exists) } -func checkValue(t *testing.T, ctx context.Context, fs afero.Fs, fileFullPath string, cache *FileCache, key, wantValue string) { //nolint:revive +func checkValue(ctx context.Context, t *testing.T, fs afero.Fs, fileFullPath string, cache *FileCache, key, wantValue string) { t.Helper() // check actual file content b, err := afero.ReadFile(fs, fileFullPath) diff --git a/docker/common/defaults/settings.json b/docker/common/defaults/settings.json index e787ef87..cf7fb4ee 100644 --- a/docker/common/defaults/settings.json +++ b/docker/common/defaults/settings.json @@ -5,4 +5,4 @@ "log": "stdout", "database": "/database/filebrowser.db", "root": "/srv" -} \ No newline at end of file +} diff --git a/errors/errors.go b/errors/errors.go index f8abee59..5fd760c2 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -3,15 +3,6 @@ package errors import ( "errors" "fmt" - "os" - "syscall" -) - -const ( - ExitCodeSigTerm = 128 + int(syscall.SIGTERM) - ExitCodeSighup = 128 + int(syscall.SIGHUP) - ExitCodeSigint = 128 + int(syscall.SIGINT) - ExitCodeSigquit = 128 + int(syscall.SIGQUIT) ) var ( @@ -31,10 +22,6 @@ var ( ErrInvalidRequestParams = errors.New("invalid request params") ErrSourceIsParent = errors.New("source is parent") ErrRootUserDeletion = errors.New("user with id 1 can't be deleted") - ErrSigTerm = errors.New("exit on signal: sigterm") - ErrSighup = errors.New("exit on signal: sighup") - ErrSigint = errors.New("exit on signal: sigint") - ErrSigquit = errors.New("exit on signal: sigquit") ) type ErrShortPassword struct { @@ -44,44 +31,3 @@ type ErrShortPassword struct { func (e ErrShortPassword) Error() string { return fmt.Sprintf("password is too short, minimum length is %d", e.MinimumLength) } - -// GetExitCode returns the exit code for a given error. -func GetExitCode(err error) int { - if err == nil { - return 0 - } - - exitCodeMap := map[error]int{ - ErrSigTerm: ExitCodeSigTerm, - ErrSighup: ExitCodeSighup, - ErrSigint: ExitCodeSigint, - ErrSigquit: ExitCodeSigquit, - } - - for e, code := range exitCodeMap { - if errors.Is(err, e) { - return code - } - } - - if exitErr, ok := err.(interface{ ExitCode() int }); ok { - return exitErr.ExitCode() - } - - var pathErr *os.PathError - if errors.As(err, &pathErr) { - return 1 - } - - var syscallErr *os.SyscallError - if errors.As(err, &syscallErr) { - return 1 - } - - var errno syscall.Errno - if errors.As(err, &errno) { - return 1 - } - - return 1 -} diff --git a/files/file.go b/files/file.go index 8e27e549..0f96440e 100644 --- a/files/file.go +++ b/files/file.go @@ -1,8 +1,8 @@ package files import ( - "crypto/md5" //nolint:gosec - "crypto/sha1" //nolint:gosec + "crypto/md5" + "crypto/sha1" "crypto/sha256" "crypto/sha512" "encoding/hex" @@ -90,7 +90,7 @@ func NewFileInfo(opts *FileOptions) (*FileInfo, error) { if opts.Expand { if file.IsDir { - if err := file.readListing(opts.Checker, opts.ReadHeader); err != nil { //nolint:govet + if err := file.readListing(opts.Checker, opts.ReadHeader); err != nil { return nil, err } return file, nil @@ -183,7 +183,6 @@ func (i *FileInfo) Checksum(algo string) error { var h hash.Hash - //nolint:gosec switch algo { case "md5": h = md5.New() diff --git a/files/mime.go b/files/mime.go index 33fd93bd..baa4d6d5 100644 --- a/files/mime.go +++ b/files/mime.go @@ -600,7 +600,6 @@ var types = map[string]string{ ".epub": "application/epub+zip", } -//nolint:gochecknoinits func init() { for ext, typ := range types { // skip errors diff --git a/frontend/package.json b/frontend/package.json index ade91ff1..f7c9d531 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -71,5 +71,5 @@ "vite-plugin-compression2": "^2.3.1", "vue-tsc": "^3.1.3" }, - "packageManager": "pnpm@10.22.0+sha512.bf049efe995b28f527fd2b41ae0474ce29186f7edcb3bf545087bd61fbbebb2bf75362d1307fda09c2d288e1e499787ac12d4fcb617a974718a6051f2eee741c" + "packageManager": "pnpm@10.24.0+sha512.01ff8ae71b4419903b65c60fb2dc9d34cf8bb6e06d03bde112ef38f7a34d6904c424ba66bea5cdcf12890230bf39f9580473140ed9c946fef328b6e5238a345a" } diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 4f4907ee..670e35fe 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -10,13 +10,13 @@ importers: dependencies: '@chenfengyuan/vue-number-input': specifier: ^2.0.1 - version: 2.0.1(vue@3.5.24(typescript@5.9.3)) + version: 2.0.1(vue@3.5.25(typescript@5.9.3)) '@vueuse/core': specifier: ^14.0.0 - version: 14.0.0(vue@3.5.24(typescript@5.9.3)) + version: 14.1.0(vue@3.5.25(typescript@5.9.3)) '@vueuse/integrations': specifier: ^14.0.0 - version: 14.0.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.24(typescript@5.9.3)) + version: 14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.25(typescript@5.9.3)) ace-builds: specifier: ^1.43.2 version: 1.43.4 @@ -43,7 +43,7 @@ importers: version: 4.17.21 marked: specifier: ^17.0.0 - version: 17.0.0 + version: 17.0.1 material-icons: specifier: ^1.13.14 version: 1.13.14 @@ -52,13 +52,13 @@ importers: version: 8.0.1 pinia: specifier: ^3.0.4 - version: 3.0.4(typescript@5.9.3)(vue@3.5.24(typescript@5.9.3)) + version: 3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)) pretty-bytes: specifier: ^7.1.0 version: 7.1.0 qrcode.vue: specifier: ^3.6.0 - version: 3.6.0(vue@3.5.24(typescript@5.9.3)) + version: 3.6.0(vue@3.5.25(typescript@5.9.3)) tus-js-client: specifier: ^4.3.1 version: 4.3.1 @@ -76,13 +76,13 @@ importers: version: 1.1.1(video.js@8.23.4) vue: specifier: ^3.5.17 - version: 3.5.24(typescript@5.9.3) + version: 3.5.25(typescript@5.9.3) vue-final-modal: specifier: ^4.5.5 - version: 4.5.5(@vueuse/core@14.0.0(vue@3.5.24(typescript@5.9.3)))(@vueuse/integrations@14.0.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.24(typescript@5.9.3)))(focus-trap@7.6.2)(vue@3.5.24(typescript@5.9.3)) + version: 4.5.5(@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3)))(@vueuse/integrations@14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.25(typescript@5.9.3)))(focus-trap@7.6.2)(vue@3.5.25(typescript@5.9.3)) vue-i18n: specifier: ^11.1.10 - version: 11.1.12(vue@3.5.24(typescript@5.9.3)) + version: 11.2.2(vue@3.5.25(typescript@5.9.3)) vue-lazyload: specifier: ^3.0.0 version: 3.0.0 @@ -91,17 +91,17 @@ importers: version: 1.3.3 vue-router: specifier: ^4.5.1 - version: 4.6.3(vue@3.5.24(typescript@5.9.3)) + version: 4.6.3(vue@3.5.25(typescript@5.9.3)) vue-toastification: specifier: ^2.0.0-rc.5 - version: 2.0.0-rc.5(vue@3.5.24(typescript@5.9.3)) + version: 2.0.0-rc.5(vue@3.5.25(typescript@5.9.3)) devDependencies: '@intlify/unplugin-vue-i18n': specifier: ^11.0.1 - version: 11.0.1(@vue/compiler-dom@3.5.24)(eslint@9.39.1)(rollup@4.52.5)(typescript@5.9.3)(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3)) + version: 11.0.1(@vue/compiler-dom@3.5.25)(eslint@9.39.1)(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)) '@tsconfig/node24': specifier: ^24.0.2 - version: 24.0.2 + version: 24.0.3 '@types/lodash-es': specifier: ^4.17.12 version: 4.17.12 @@ -110,22 +110,22 @@ importers: version: 24.10.1 '@typescript-eslint/eslint-plugin': specifier: ^8.37.0 - version: 8.46.4(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3) + version: 8.48.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3) '@vitejs/plugin-legacy': specifier: ^7.2.1 - version: 7.2.1(terser@5.44.1)(vite@7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0)) + version: 7.2.1(terser@5.44.1)(vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0)) '@vitejs/plugin-vue': specifier: ^6.0.1 - version: 6.0.1(vite@7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.24(typescript@5.9.3)) + version: 6.0.2(vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.25(typescript@5.9.3)) '@vue/eslint-config-prettier': specifier: ^10.2.0 - version: 10.2.0(eslint@9.39.1)(prettier@3.6.2) + version: 10.2.0(eslint@9.39.1)(prettier@3.7.2) '@vue/eslint-config-typescript': specifier: ^14.6.0 - version: 14.6.0(eslint-plugin-vue@10.5.1(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)))(eslint@9.39.1)(typescript@5.9.3) + version: 14.6.0(eslint-plugin-vue@10.6.2(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)))(eslint@9.39.1)(typescript@5.9.3) '@vue/tsconfig': specifier: ^0.8.1 - version: 0.8.1(typescript@5.9.3)(vue@3.5.24(typescript@5.9.3)) + version: 0.8.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)) autoprefixer: specifier: ^10.4.21 version: 10.4.22(postcss@8.5.6) @@ -137,16 +137,16 @@ importers: version: 10.1.8(eslint@9.39.1) eslint-plugin-prettier: specifier: ^5.5.1 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.6.2) + version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.7.2) eslint-plugin-vue: specifier: ^10.5.1 - version: 10.5.1(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)) + version: 10.6.2(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)) postcss: specifier: ^8.5.6 version: 8.5.6 prettier: specifier: ^3.6.2 - version: 3.6.2 + version: 3.7.2 terser: specifier: ^5.43.1 version: 5.44.1 @@ -155,13 +155,13 @@ importers: version: 5.9.3 vite: specifier: ^7.2.2 - version: 7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0) + version: 7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0) vite-plugin-compression2: specifier: ^2.3.1 - version: 2.3.1(rollup@4.52.5) + version: 2.3.1(rollup@4.53.3) vue-tsc: specifier: ^3.1.3 - version: 3.1.3(typescript@5.9.3) + version: 3.1.5(typescript@5.9.3) packages: @@ -665,158 +665,158 @@ packages: peerDependencies: vue: ^3.0.0 - '@esbuild/aix-ppc64@0.25.11': - resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==} + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.11': - resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==} + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.11': - resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==} + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.11': - resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==} + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.11': - resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==} + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.11': - resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==} + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.11': - resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==} + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.11': - resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==} + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.11': - resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==} + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.11': - resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==} + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.11': - resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==} + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.11': - resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==} + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.11': - resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==} + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.11': - resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==} + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.11': - resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==} + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.11': - resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==} + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.11': - resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==} + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.11': - resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==} + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.11': - resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==} + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.11': - resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==} + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.11': - resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==} + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.11': - resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==} + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.11': - resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==} + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.11': - resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==} + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.11': - resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==} + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.11': - resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==} + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -887,18 +887,22 @@ packages: vue-i18n: optional: true - '@intlify/core-base@11.1.12': - resolution: {integrity: sha512-whh0trqRsSqVLNEUCwU59pyJZYpU8AmSWl8M3Jz2Mv5ESPP6kFh4juas2NpZ1iCvy7GlNRffUD1xr84gceimjg==} + '@intlify/core-base@11.2.2': + resolution: {integrity: sha512-0mCTBOLKIqFUP3BzwuFW23hYEl9g/wby6uY//AC5hTgQfTsM2srCYF2/hYGp+a5DZ/HIFIgKkLJMzXTt30r0JQ==} engines: {node: '>= 16'} - '@intlify/message-compiler@11.1.12': - resolution: {integrity: sha512-Fv9iQSJoJaXl4ZGkOCN1LDM3trzze0AS2zRz2EHLiwenwL6t0Ki9KySYlyr27yVOj5aVz0e55JePO+kELIvfdQ==} + '@intlify/message-compiler@11.2.2': + resolution: {integrity: sha512-XS2p8Ff5JxWsKhgfld4/MRQzZRQ85drMMPhb7Co6Be4ZOgqJX1DzcZt0IFgGTycgqL8rkYNwgnD443Q+TapOoA==} engines: {node: '>= 16'} '@intlify/shared@11.1.12': resolution: {integrity: sha512-Om86EjuQtA69hdNj3GQec9ZC0L0vPSAnXzB3gP/gyJ7+mA7t06d9aOAiqMZ+xEOsumGP4eEBlfl8zF2LOTzf2A==} engines: {node: '>= 16'} + '@intlify/shared@11.2.2': + resolution: {integrity: sha512-OtCmyFpSXxNu/oET/aN6HtPCbZ01btXVd0f3w00YsHOb13Kverk1jzA2k47pAekM55qbUw421fvPF1yxZ+gicw==} + engines: {node: '>= 16'} + '@intlify/unplugin-vue-i18n@11.0.1': resolution: {integrity: sha512-nH5NJdNjy/lO6Ne8LDtZzv4SbpVsMhPE+LbvBDmMeIeJDiino8sOJN2QB3MXzTliYTnqe3aB9Fw5+LJ/XVaXCg==} engines: {node: '>= 20'} @@ -965,8 +969,8 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@rolldown/pluginutils@1.0.0-beta.29': - resolution: {integrity: sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==} + '@rolldown/pluginutils@1.0.0-beta.50': + resolution: {integrity: sha512-5e76wQiQVeL1ICOZVUg4LSOVYg9jyhGCin+icYozhsUzM+fHE7kddi1bdiE0jwVqTfkjba3jUFbEkoC9WkdvyA==} '@rollup/pluginutils@5.3.0': resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} @@ -977,118 +981,118 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.52.5': - resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==} + '@rollup/rollup-android-arm-eabi@4.53.3': + resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.52.5': - resolution: {integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==} + '@rollup/rollup-android-arm64@4.53.3': + resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.52.5': - resolution: {integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==} + '@rollup/rollup-darwin-arm64@4.53.3': + resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.52.5': - resolution: {integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==} + '@rollup/rollup-darwin-x64@4.53.3': + resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.52.5': - resolution: {integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==} + '@rollup/rollup-freebsd-arm64@4.53.3': + resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.52.5': - resolution: {integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==} + '@rollup/rollup-freebsd-x64@4.53.3': + resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.52.5': - resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==} + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.52.5': - resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==} + '@rollup/rollup-linux-arm-musleabihf@4.53.3': + resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.52.5': - resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==} + '@rollup/rollup-linux-arm64-gnu@4.53.3': + resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.52.5': - resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==} + '@rollup/rollup-linux-arm64-musl@4.53.3': + resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.52.5': - resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==} + '@rollup/rollup-linux-loong64-gnu@4.53.3': + resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.52.5': - resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==} + '@rollup/rollup-linux-ppc64-gnu@4.53.3': + resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.52.5': - resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==} + '@rollup/rollup-linux-riscv64-gnu@4.53.3': + resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.52.5': - resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==} + '@rollup/rollup-linux-riscv64-musl@4.53.3': + resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.52.5': - resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==} + '@rollup/rollup-linux-s390x-gnu@4.53.3': + resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.52.5': - resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==} + '@rollup/rollup-linux-x64-gnu@4.53.3': + resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.52.5': - resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==} + '@rollup/rollup-linux-x64-musl@4.53.3': + resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} cpu: [x64] os: [linux] - '@rollup/rollup-openharmony-arm64@4.52.5': - resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==} + '@rollup/rollup-openharmony-arm64@4.53.3': + resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.52.5': - resolution: {integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==} + '@rollup/rollup-win32-arm64-msvc@4.53.3': + resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.52.5': - resolution: {integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==} + '@rollup/rollup-win32-ia32-msvc@4.53.3': + resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.52.5': - resolution: {integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==} + '@rollup/rollup-win32-x64-gnu@4.53.3': + resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.52.5': - resolution: {integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==} + '@rollup/rollup-win32-x64-msvc@4.53.3': + resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} cpu: [x64] os: [win32] - '@tsconfig/node24@24.0.2': - resolution: {integrity: sha512-CNeOLUPI9PjbBc1DSIqb3GF/u+3kX/TDe9DKCzoI62mYI4dEDrMQ0r/9+SfYACP4UNMbiTlz7n8H7Rx/xTisQg==} + '@tsconfig/node24@24.0.3': + resolution: {integrity: sha512-vcERKtKQKHgzt/vfS3Gjasd8SUI2a0WZXpgJURdJsMySpS5+ctgbPfuLj2z/W+w4lAfTWxoN4upKfu2WzIRYnw==} '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} @@ -1123,11 +1127,11 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/eslint-plugin@8.46.4': - resolution: {integrity: sha512-R48VhmTJqplNyDxCyqqVkFSZIx1qX6PzwqgcXn1olLrzxcSBDlOsbtcnQuQhNtnNiJ4Xe5gREI1foajYaYU2Vg==} + '@typescript-eslint/eslint-plugin@8.48.0': + resolution: {integrity: sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.46.4 + '@typescript-eslint/parser': ^8.48.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' @@ -1150,6 +1154,12 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/project-service@8.48.0': + resolution: {integrity: sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/scope-manager@8.37.0': resolution: {integrity: sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1158,6 +1168,10 @@ packages: resolution: {integrity: sha512-tMDbLGXb1wC+McN1M6QeDx7P7c0UWO5z9CXqp7J8E+xGcJuUuevWKxuG8j41FoweS3+L41SkyKKkia16jpX7CA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.48.0': + resolution: {integrity: sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/tsconfig-utils@8.37.0': resolution: {integrity: sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1170,6 +1184,12 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/tsconfig-utils@8.48.0': + resolution: {integrity: sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/type-utils@8.37.0': resolution: {integrity: sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1177,8 +1197,8 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/type-utils@8.46.4': - resolution: {integrity: sha512-V4QC8h3fdT5Wro6vANk6eojqfbv5bpwHuMsBcJUJkqs2z5XnYhJzyz9Y02eUmF9u3PgXEUiOt4w4KHR3P+z0PQ==} + '@typescript-eslint/type-utils@8.48.0': + resolution: {integrity: sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -1192,6 +1212,10 @@ packages: resolution: {integrity: sha512-USjyxm3gQEePdUwJBFjjGNG18xY9A2grDVGuk7/9AkjIF1L+ZrVnwR5VAU5JXtUnBL/Nwt3H31KlRDaksnM7/w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.48.0': + resolution: {integrity: sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@8.37.0': resolution: {integrity: sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1204,6 +1228,12 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/typescript-estree@8.48.0': + resolution: {integrity: sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/utils@8.37.0': resolution: {integrity: sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1211,8 +1241,8 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/utils@8.46.4': - resolution: {integrity: sha512-AbSv11fklGXV6T28dp2Me04Uw90R2iJ30g2bgLz529Koehrmkbs1r7paFqr1vPCZi7hHwYxYtxfyQMRC8QaVSg==} + '@typescript-eslint/utils@8.48.0': + resolution: {integrity: sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -1226,6 +1256,10 @@ packages: resolution: {integrity: sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.48.0': + resolution: {integrity: sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@videojs/http-streaming@3.17.2': resolution: {integrity: sha512-VBQ3W4wnKnVKb/limLdtSD2rAd5cmHN70xoMf4OmuDd0t2kfJX04G+sfw6u2j8oOm2BXYM9E1f4acHruqKnM1g==} engines: {node: '>=8', npm: '>=5'} @@ -1246,8 +1280,8 @@ packages: terser: ^5.16.0 vite: ^7.0.0 - '@vitejs/plugin-vue@6.0.1': - resolution: {integrity: sha512-+MaE752hU0wfPFJEUAIxqw18+20euHHdxVtMvbFcOEpjEyfqXH/5DCoTHiVJ0J29EhTJdoTkjEv5YBKU9dnoTw==} + '@vitejs/plugin-vue@6.0.2': + resolution: {integrity: sha512-iHmwV3QcVGGvSC1BG5bZ4z6iwa1SOpAPWmnjOErd4Ske+lZua5K9TtAVdx0gMBClJ28DViCbSmZitjWZsWO3LA==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 @@ -1262,17 +1296,17 @@ packages: '@volar/typescript@2.4.23': resolution: {integrity: sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==} - '@vue/compiler-core@3.5.24': - resolution: {integrity: sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig==} + '@vue/compiler-core@3.5.25': + resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==} - '@vue/compiler-dom@3.5.24': - resolution: {integrity: sha512-1QHGAvs53gXkWdd3ZMGYuvQFXHW4ksKWPG8HP8/2BscrbZ0brw183q2oNWjMrSWImYLHxHrx1ItBQr50I/q2zw==} + '@vue/compiler-dom@3.5.25': + resolution: {integrity: sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==} - '@vue/compiler-sfc@3.5.24': - resolution: {integrity: sha512-8EG5YPRgmTB+YxYBM3VXy8zHD9SWHUJLIGPhDovo3Z8VOgvP+O7UP5vl0J4BBPWYD9vxtBabzW1EuEZ+Cqs14g==} + '@vue/compiler-sfc@3.5.25': + resolution: {integrity: sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==} - '@vue/compiler-ssr@3.5.24': - resolution: {integrity: sha512-trOvMWNBMQ/odMRHW7Ae1CdfYx+7MuiQu62Jtu36gMLXcaoqKvAyh+P73sYG9ll+6jLB6QPovqoKGGZROzkFFg==} + '@vue/compiler-ssr@3.5.25': + resolution: {integrity: sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==} '@vue/devtools-api@6.6.4': resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} @@ -1303,30 +1337,30 @@ packages: typescript: optional: true - '@vue/language-core@3.1.3': - resolution: {integrity: sha512-KpR1F/eGAG9D1RZ0/T6zWJs6dh/pRLfY5WupecyYKJ1fjVmDMgTPw9wXmKv2rBjo4zCJiOSiyB8BDP1OUwpMEA==} + '@vue/language-core@3.1.5': + resolution: {integrity: sha512-FMcqyzWN+sYBeqRMWPGT2QY0mUasZMVIuHvmb5NT3eeqPrbHBYtCP8JWEUCDCgM+Zr62uuWY/qoeBrPrzfa78w==} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true - '@vue/reactivity@3.5.24': - resolution: {integrity: sha512-BM8kBhtlkkbnyl4q+HiF5R5BL0ycDPfihowulm02q3WYp2vxgPcJuZO866qa/0u3idbMntKEtVNuAUp5bw4teg==} + '@vue/reactivity@3.5.25': + resolution: {integrity: sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==} - '@vue/runtime-core@3.5.24': - resolution: {integrity: sha512-RYP/byyKDgNIqfX/gNb2PB55dJmM97jc9wyF3jK7QUInYKypK2exmZMNwnjueWwGceEkP6NChd3D2ZVEp9undQ==} + '@vue/runtime-core@3.5.25': + resolution: {integrity: sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==} - '@vue/runtime-dom@3.5.24': - resolution: {integrity: sha512-Z8ANhr/i0XIluonHVjbUkjvn+CyrxbXRIxR7wn7+X7xlcb7dJsfITZbkVOeJZdP8VZwfrWRsWdShH6pngMxRjw==} + '@vue/runtime-dom@3.5.25': + resolution: {integrity: sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==} - '@vue/server-renderer@3.5.24': - resolution: {integrity: sha512-Yh2j2Y4G/0/4z/xJ1Bad4mxaAk++C2v4kaa8oSYTMJBJ00/ndPuxCnWeot0/7/qafQFLh5pr6xeV6SdMcE/G1w==} + '@vue/server-renderer@3.5.25': + resolution: {integrity: sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==} peerDependencies: - vue: 3.5.24 + vue: 3.5.25 - '@vue/shared@3.5.24': - resolution: {integrity: sha512-9cwHL2EsJBdi8NY22pngYYWzkTDhld6fAD6jlaeloNGciNSJL6bLpbxVgXl96X00Jtc6YWQv96YA/0sxex/k1A==} + '@vue/shared@3.5.25': + resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==} '@vue/tsconfig@0.8.1': resolution: {integrity: sha512-aK7feIWPXFSUhsCP9PFqPyFOcz4ENkb8hZ2pneL6m2UjCkccvaOhC/5KCKluuBufvp2KzkbdA2W2pk20vLzu3g==} @@ -1339,13 +1373,13 @@ packages: vue: optional: true - '@vueuse/core@14.0.0': - resolution: {integrity: sha512-d6tKRWkZE8IQElX2aHBxXOMD478fHIYV+Dzm2y9Ag122ICBpNKtGICiXKOhWU3L1kKdttDD9dCMS4bGP3jhCTQ==} + '@vueuse/core@14.1.0': + resolution: {integrity: sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw==} peerDependencies: vue: ^3.5.0 - '@vueuse/integrations@14.0.0': - resolution: {integrity: sha512-5A0X7q9qyLtM3xyghq5nK/NEESf7cpcZlkQgXTMuW4JWiAMYxc1ImdhhGrk4negFBsq3ejvAlRmLdNrkcTzk1Q==} + '@vueuse/integrations@14.1.0': + resolution: {integrity: sha512-eNQPdisnO9SvdydTIXnTE7c29yOsJBD/xkwEyQLdhDC/LKbqrFpXHb3uS//7NcIrQO3fWVuvMGp8dbK6mNEMCA==} peerDependencies: async-validator: ^4 axios: ^1 @@ -1386,11 +1420,11 @@ packages: universal-cookie: optional: true - '@vueuse/metadata@14.0.0': - resolution: {integrity: sha512-6yoGqbJcMldVCevkFiHDBTB1V5Hq+G/haPlGIuaFZHpXC0HADB0EN1ryQAAceiW+ryS3niUwvdFbGiqHqBrfVA==} + '@vueuse/metadata@14.1.0': + resolution: {integrity: sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA==} - '@vueuse/shared@14.0.0': - resolution: {integrity: sha512-mTCA0uczBgurRlwVaQHfG0Ja7UdGe4g9mwffiJmvLiTtp1G4AQyIjej6si/k8c8pUwTfVpNufck+23gXptPAkw==} + '@vueuse/shared@14.1.0': + resolution: {integrity: sha512-EcKxtYvn6gx1F8z9J5/rsg3+lTQnvOruQd8fUecW99DCK04BkWD7z5KQ/wTAx+DazyoEE9dJt/zV8OIEQbM6kw==} peerDependencies: vue: ^3.5.0 @@ -1544,8 +1578,8 @@ packages: engines: {node: '>=4'} hasBin: true - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} custom-error-instance@2.1.1: resolution: {integrity: sha512-p6JFxJc3M4OTD2li2qaHkDCw9SfMw82Ldr6OC9Je1aXiGfhx2W8p3GaoeaGrPJTUN9NirTM/KTxHWMUdR1rsUg==} @@ -1596,8 +1630,8 @@ packages: resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} engines: {node: '>=0.12'} - esbuild@0.25.11: - resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==} + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} engines: {node: '>=18'} hasBin: true @@ -1634,8 +1668,8 @@ packages: eslint-config-prettier: optional: true - eslint-plugin-vue@10.5.1: - resolution: {integrity: sha512-SbR9ZBUFKgvWAbq3RrdCtWaW0IKm6wwUiApxf3BVTNfqUIo4IQQmreMg2iHFJJ6C/0wss3LXURBJ1OwS/MhFcQ==} + eslint-plugin-vue@10.6.2: + resolution: {integrity: sha512-nA5yUs/B1KmKzvC42fyD0+l9Yd+LtEpVhWRbXuDj0e+ZURcTtyRbMDWUeJmTAh2wC6jC83raS63anNM2YT3NPw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@stylistic/eslint-plugin': ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 @@ -1973,8 +2007,8 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - marked@17.0.0: - resolution: {integrity: sha512-KkDYEWEEiYJw/KC+DVm1zzlpMQSMIu6YRltkcCvwheCp8HWPXCk9JwOmHJKBlGfzcpzcIt6x3sMnTsRm/51oDg==} + marked@17.0.1: + resolution: {integrity: sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==} engines: {node: '>= 20'} hasBin: true @@ -2114,8 +2148,8 @@ packages: resolution: {integrity: sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==} hasBin: true - postcss-selector-parser@6.1.2: - resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} engines: {node: '>=4'} postcss-value-parser@4.2.0: @@ -2133,8 +2167,8 @@ packages: resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} engines: {node: '>=6.0.0'} - prettier@3.6.2: - resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + prettier@3.7.2: + resolution: {integrity: sha512-n3HV2J6QhItCXndGa3oMWvWFAgN1ibnS7R9mt6iokScBOC0Ul9/iZORmU2IWUMcyAQaMPjTlY3uT34TqocUxMA==} engines: {node: '>=14'} hasBin: true @@ -2214,8 +2248,8 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rollup@4.52.5: - resolution: {integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==} + rollup@4.53.3: + resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2405,8 +2439,8 @@ packages: vite-plugin-compression2@2.3.1: resolution: {integrity: sha512-bnhLTsurtvOiiP6EMISIKVsOMCeTAjE6FJbyqQus3W4mtAxF7pCuC4puUIAiCgNs98tOCpqo6GIXJXTLufzIaw==} - vite@7.2.2: - resolution: {integrity: sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==} + vite@7.2.4: + resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -2462,8 +2496,8 @@ packages: focus-trap: '>=7.2.0' vue: '>=3.2.0' - vue-i18n@11.1.12: - resolution: {integrity: sha512-BnstPj3KLHLrsqbVU2UOrPmr0+Mv11bsUZG0PyCOzsawCivk8W00GMXHeVUWIDOgNaScCuZah47CZFE+Wnl8mw==} + vue-i18n@11.2.2: + resolution: {integrity: sha512-ULIKZyRluUPRCZmihVgUvpq8hJTtOqnbGZuv4Lz+byEKZq4mU0g92og414l6f/4ju+L5mORsiUuEPYrAuX2NJg==} engines: {node: '>= 16'} peerDependencies: vue: ^3.0.0 @@ -2484,14 +2518,14 @@ packages: peerDependencies: vue: ^3.0.2 - vue-tsc@3.1.3: - resolution: {integrity: sha512-StMNfZHwPIXQgY3KxPKM0Jsoc8b46mDV3Fn2UlHCBIwRJApjqrSwqeMYgWf0zpN+g857y74pv7GWuBm+UqQe1w==} + vue-tsc@3.1.5: + resolution: {integrity: sha512-L/G9IUjOWhBU0yun89rv8fKqmKC+T0HfhrFjlIml71WpfBv9eb4E9Bev8FMbyueBIU9vxQqbd+oOsVcDa5amGw==} hasBin: true peerDependencies: typescript: '>=5.0.0' - vue@3.5.24: - resolution: {integrity: sha512-uTHDOpVQTMjcGgrqFPSb8iO2m1DUvo+WbGqoXQz8Y1CeBYQ0FXf2z1gLRaBtHjlRz7zZUBHxjVB5VTLzYkvftg==} + vue@3.5.25: + resolution: {integrity: sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -3186,86 +3220,86 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@chenfengyuan/vue-number-input@2.0.1(vue@3.5.24(typescript@5.9.3))': + '@chenfengyuan/vue-number-input@2.0.1(vue@3.5.25(typescript@5.9.3))': dependencies: - vue: 3.5.24(typescript@5.9.3) + vue: 3.5.25(typescript@5.9.3) - '@esbuild/aix-ppc64@0.25.11': + '@esbuild/aix-ppc64@0.25.12': optional: true - '@esbuild/android-arm64@0.25.11': + '@esbuild/android-arm64@0.25.12': optional: true - '@esbuild/android-arm@0.25.11': + '@esbuild/android-arm@0.25.12': optional: true - '@esbuild/android-x64@0.25.11': + '@esbuild/android-x64@0.25.12': optional: true - '@esbuild/darwin-arm64@0.25.11': + '@esbuild/darwin-arm64@0.25.12': optional: true - '@esbuild/darwin-x64@0.25.11': + '@esbuild/darwin-x64@0.25.12': optional: true - '@esbuild/freebsd-arm64@0.25.11': + '@esbuild/freebsd-arm64@0.25.12': optional: true - '@esbuild/freebsd-x64@0.25.11': + '@esbuild/freebsd-x64@0.25.12': optional: true - '@esbuild/linux-arm64@0.25.11': + '@esbuild/linux-arm64@0.25.12': optional: true - '@esbuild/linux-arm@0.25.11': + '@esbuild/linux-arm@0.25.12': optional: true - '@esbuild/linux-ia32@0.25.11': + '@esbuild/linux-ia32@0.25.12': optional: true - '@esbuild/linux-loong64@0.25.11': + '@esbuild/linux-loong64@0.25.12': optional: true - '@esbuild/linux-mips64el@0.25.11': + '@esbuild/linux-mips64el@0.25.12': optional: true - '@esbuild/linux-ppc64@0.25.11': + '@esbuild/linux-ppc64@0.25.12': optional: true - '@esbuild/linux-riscv64@0.25.11': + '@esbuild/linux-riscv64@0.25.12': optional: true - '@esbuild/linux-s390x@0.25.11': + '@esbuild/linux-s390x@0.25.12': optional: true - '@esbuild/linux-x64@0.25.11': + '@esbuild/linux-x64@0.25.12': optional: true - '@esbuild/netbsd-arm64@0.25.11': + '@esbuild/netbsd-arm64@0.25.12': optional: true - '@esbuild/netbsd-x64@0.25.11': + '@esbuild/netbsd-x64@0.25.12': optional: true - '@esbuild/openbsd-arm64@0.25.11': + '@esbuild/openbsd-arm64@0.25.12': optional: true - '@esbuild/openbsd-x64@0.25.11': + '@esbuild/openbsd-x64@0.25.12': optional: true - '@esbuild/openharmony-arm64@0.25.11': + '@esbuild/openharmony-arm64@0.25.12': optional: true - '@esbuild/sunos-x64@0.25.11': + '@esbuild/sunos-x64@0.25.12': optional: true - '@esbuild/win32-arm64@0.25.11': + '@esbuild/win32-arm64@0.25.12': optional: true - '@esbuild/win32-ia32@0.25.11': + '@esbuild/win32-ia32@0.25.12': optional: true - '@esbuild/win32-x64@0.25.11': + '@esbuild/win32-x64@0.25.12': optional: true '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1)': @@ -3325,39 +3359,41 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@intlify/bundle-utils@11.0.1(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))': + '@intlify/bundle-utils@11.0.1(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))': dependencies: - '@intlify/message-compiler': 11.1.12 + '@intlify/message-compiler': 11.2.2 '@intlify/shared': 11.1.12 acorn: 8.15.0 - esbuild: 0.25.11 + esbuild: 0.25.12 escodegen: 2.1.0 estree-walker: 2.0.2 jsonc-eslint-parser: 2.4.0 source-map-js: 1.2.1 yaml-eslint-parser: 1.2.3 optionalDependencies: - vue-i18n: 11.1.12(vue@3.5.24(typescript@5.9.3)) + vue-i18n: 11.2.2(vue@3.5.25(typescript@5.9.3)) - '@intlify/core-base@11.1.12': + '@intlify/core-base@11.2.2': dependencies: - '@intlify/message-compiler': 11.1.12 - '@intlify/shared': 11.1.12 + '@intlify/message-compiler': 11.2.2 + '@intlify/shared': 11.2.2 - '@intlify/message-compiler@11.1.12': + '@intlify/message-compiler@11.2.2': dependencies: - '@intlify/shared': 11.1.12 + '@intlify/shared': 11.2.2 source-map-js: 1.2.1 '@intlify/shared@11.1.12': {} - '@intlify/unplugin-vue-i18n@11.0.1(@vue/compiler-dom@3.5.24)(eslint@9.39.1)(rollup@4.52.5)(typescript@5.9.3)(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))': + '@intlify/shared@11.2.2': {} + + '@intlify/unplugin-vue-i18n@11.0.1(@vue/compiler-dom@3.5.25)(eslint@9.39.1)(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) - '@intlify/bundle-utils': 11.0.1(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3))) + '@intlify/bundle-utils': 11.0.1(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3))) '@intlify/shared': 11.1.12 - '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.12)(@vue/compiler-dom@3.5.24)(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3)) - '@rollup/pluginutils': 5.3.0(rollup@4.52.5) + '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.12)(@vue/compiler-dom@3.5.25)(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)) + '@rollup/pluginutils': 5.3.0(rollup@4.53.3) '@typescript-eslint/scope-manager': 8.46.4 '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3) debug: 4.4.3 @@ -3365,9 +3401,9 @@ snapshots: pathe: 2.0.3 picocolors: 1.1.1 unplugin: 2.3.10 - vue: 3.5.24(typescript@5.9.3) + vue: 3.5.25(typescript@5.9.3) optionalDependencies: - vue-i18n: 11.1.12(vue@3.5.24(typescript@5.9.3)) + vue-i18n: 11.2.2(vue@3.5.25(typescript@5.9.3)) transitivePeerDependencies: - '@vue/compiler-dom' - eslint @@ -3375,14 +3411,14 @@ snapshots: - supports-color - typescript - '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.12)(@vue/compiler-dom@3.5.24)(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))': + '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.12)(@vue/compiler-dom@3.5.25)(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))': dependencies: '@babel/parser': 7.28.5 optionalDependencies: '@intlify/shared': 11.1.12 - '@vue/compiler-dom': 3.5.24 - vue: 3.5.24(typescript@5.9.3) - vue-i18n: 11.1.12(vue@3.5.24(typescript@5.9.3)) + '@vue/compiler-dom': 3.5.25 + vue: 3.5.25(typescript@5.9.3) + vue-i18n: 11.2.2(vue@3.5.25(typescript@5.9.3)) '@jridgewell/gen-mapping@0.3.13': dependencies: @@ -3422,83 +3458,83 @@ snapshots: '@pkgr/core@0.2.9': {} - '@rolldown/pluginutils@1.0.0-beta.29': {} + '@rolldown/pluginutils@1.0.0-beta.50': {} - '@rollup/pluginutils@5.3.0(rollup@4.52.5)': + '@rollup/pluginutils@5.3.0(rollup@4.53.3)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: - rollup: 4.52.5 + rollup: 4.53.3 - '@rollup/rollup-android-arm-eabi@4.52.5': + '@rollup/rollup-android-arm-eabi@4.53.3': optional: true - '@rollup/rollup-android-arm64@4.52.5': + '@rollup/rollup-android-arm64@4.53.3': optional: true - '@rollup/rollup-darwin-arm64@4.52.5': + '@rollup/rollup-darwin-arm64@4.53.3': optional: true - '@rollup/rollup-darwin-x64@4.52.5': + '@rollup/rollup-darwin-x64@4.53.3': optional: true - '@rollup/rollup-freebsd-arm64@4.52.5': + '@rollup/rollup-freebsd-arm64@4.53.3': optional: true - '@rollup/rollup-freebsd-x64@4.52.5': + '@rollup/rollup-freebsd-x64@4.53.3': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.52.5': + '@rollup/rollup-linux-arm-musleabihf@4.53.3': optional: true - '@rollup/rollup-linux-arm64-gnu@4.52.5': + '@rollup/rollup-linux-arm64-gnu@4.53.3': optional: true - '@rollup/rollup-linux-arm64-musl@4.52.5': + '@rollup/rollup-linux-arm64-musl@4.53.3': optional: true - '@rollup/rollup-linux-loong64-gnu@4.52.5': + '@rollup/rollup-linux-loong64-gnu@4.53.3': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.52.5': + '@rollup/rollup-linux-ppc64-gnu@4.53.3': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.52.5': + '@rollup/rollup-linux-riscv64-gnu@4.53.3': optional: true - '@rollup/rollup-linux-riscv64-musl@4.52.5': + '@rollup/rollup-linux-riscv64-musl@4.53.3': optional: true - '@rollup/rollup-linux-s390x-gnu@4.52.5': + '@rollup/rollup-linux-s390x-gnu@4.53.3': optional: true - '@rollup/rollup-linux-x64-gnu@4.52.5': + '@rollup/rollup-linux-x64-gnu@4.53.3': optional: true - '@rollup/rollup-linux-x64-musl@4.52.5': + '@rollup/rollup-linux-x64-musl@4.53.3': optional: true - '@rollup/rollup-openharmony-arm64@4.52.5': + '@rollup/rollup-openharmony-arm64@4.53.3': optional: true - '@rollup/rollup-win32-arm64-msvc@4.52.5': + '@rollup/rollup-win32-arm64-msvc@4.53.3': optional: true - '@rollup/rollup-win32-ia32-msvc@4.52.5': + '@rollup/rollup-win32-ia32-msvc@4.53.3': optional: true - '@rollup/rollup-win32-x64-gnu@4.52.5': + '@rollup/rollup-win32-x64-gnu@4.53.3': optional: true - '@rollup/rollup-win32-x64-msvc@4.52.5': + '@rollup/rollup-win32-x64-msvc@4.53.3': optional: true - '@tsconfig/node24@24.0.2': {} + '@tsconfig/node24@24.0.3': {} '@types/estree@1.0.8': {} @@ -3540,14 +3576,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.46.4(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 '@typescript-eslint/parser': 8.37.0(eslint@9.39.1)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.46.4 - '@typescript-eslint/type-utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.46.4 + '@typescript-eslint/scope-manager': 8.48.0 + '@typescript-eslint/type-utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.48.0 eslint: 9.39.1 graphemer: 1.4.0 ignore: 7.0.5 @@ -3587,6 +3623,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/project-service@8.48.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3) + '@typescript-eslint/types': 8.48.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/scope-manager@8.37.0': dependencies: '@typescript-eslint/types': 8.37.0 @@ -3597,6 +3642,11 @@ snapshots: '@typescript-eslint/types': 8.46.4 '@typescript-eslint/visitor-keys': 8.46.4 + '@typescript-eslint/scope-manager@8.48.0': + dependencies: + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/visitor-keys': 8.48.0 + '@typescript-eslint/tsconfig-utils@8.37.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 @@ -3605,6 +3655,10 @@ snapshots: dependencies: typescript: 5.9.3 + '@typescript-eslint/tsconfig-utils@8.48.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@typescript-eslint/type-utils@8.37.0(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.37.0 @@ -3617,11 +3671,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.46.4(eslint@9.39.1)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.48.0(eslint@9.39.1)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.46.4 - '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.1 ts-api-utils: 2.1.0(typescript@5.9.3) @@ -3633,6 +3687,8 @@ snapshots: '@typescript-eslint/types@8.46.4': {} + '@typescript-eslint/types@8.48.0': {} + '@typescript-eslint/typescript-estree@8.37.0(typescript@5.9.3)': dependencies: '@typescript-eslint/project-service': 8.37.0(typescript@5.9.3) @@ -3665,6 +3721,21 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/typescript-estree@8.48.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.48.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3) + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/visitor-keys': 8.48.0 + debug: 4.4.3 + minimatch: 9.0.5 + semver: 7.7.3 + tinyglobby: 0.2.15 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/utils@8.37.0(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) @@ -3676,12 +3747,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.46.4(eslint@9.39.1)(typescript@5.9.3)': + '@typescript-eslint/utils@8.48.0(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) - '@typescript-eslint/scope-manager': 8.46.4 - '@typescript-eslint/types': 8.46.4 - '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.48.0 + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) eslint: 9.39.1 typescript: 5.9.3 transitivePeerDependencies: @@ -3697,6 +3768,11 @@ snapshots: '@typescript-eslint/types': 8.46.4 eslint-visitor-keys: 4.2.1 + '@typescript-eslint/visitor-keys@8.48.0': + dependencies: + '@typescript-eslint/types': 8.48.0 + eslint-visitor-keys: 4.2.1 + '@videojs/http-streaming@3.17.2(video.js@8.23.4)': dependencies: '@babel/runtime': 7.28.4 @@ -3719,7 +3795,7 @@ snapshots: global: 4.4.0 is-function: 1.0.2 - '@vitejs/plugin-legacy@7.2.1(terser@5.44.1)(vite@7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))': + '@vitejs/plugin-legacy@7.2.1(terser@5.44.1)(vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.5) @@ -3734,15 +3810,15 @@ snapshots: regenerator-runtime: 0.14.1 systemjs: 6.15.1 terser: 5.44.1 - vite: 7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0) + vite: 7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0) transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@6.0.1(vite@7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.24(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.2(vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.25(typescript@5.9.3))': dependencies: - '@rolldown/pluginutils': 1.0.0-beta.29 - vite: 7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0) - vue: 3.5.24(typescript@5.9.3) + '@rolldown/pluginutils': 1.0.0-beta.50 + vite: 7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0) + vue: 3.5.25(typescript@5.9.3) '@volar/language-core@2.4.23': dependencies: @@ -3756,35 +3832,35 @@ snapshots: path-browserify: 1.0.1 vscode-uri: 3.1.0 - '@vue/compiler-core@3.5.24': + '@vue/compiler-core@3.5.25': dependencies: '@babel/parser': 7.28.5 - '@vue/shared': 3.5.24 + '@vue/shared': 3.5.25 entities: 4.5.0 estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-dom@3.5.24': + '@vue/compiler-dom@3.5.25': dependencies: - '@vue/compiler-core': 3.5.24 - '@vue/shared': 3.5.24 + '@vue/compiler-core': 3.5.25 + '@vue/shared': 3.5.25 - '@vue/compiler-sfc@3.5.24': + '@vue/compiler-sfc@3.5.25': dependencies: '@babel/parser': 7.28.5 - '@vue/compiler-core': 3.5.24 - '@vue/compiler-dom': 3.5.24 - '@vue/compiler-ssr': 3.5.24 - '@vue/shared': 3.5.24 + '@vue/compiler-core': 3.5.25 + '@vue/compiler-dom': 3.5.25 + '@vue/compiler-ssr': 3.5.25 + '@vue/shared': 3.5.25 estree-walker: 2.0.2 magic-string: 0.30.21 postcss: 8.5.6 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.24': + '@vue/compiler-ssr@3.5.25': dependencies: - '@vue/compiler-dom': 3.5.24 - '@vue/shared': 3.5.24 + '@vue/compiler-dom': 3.5.25 + '@vue/shared': 3.5.25 '@vue/devtools-api@6.6.4': {} @@ -3806,20 +3882,20 @@ snapshots: dependencies: rfdc: 1.4.1 - '@vue/eslint-config-prettier@10.2.0(eslint@9.39.1)(prettier@3.6.2)': + '@vue/eslint-config-prettier@10.2.0(eslint@9.39.1)(prettier@3.7.2)': dependencies: eslint: 9.39.1 eslint-config-prettier: 10.1.8(eslint@9.39.1) - eslint-plugin-prettier: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.6.2) - prettier: 3.6.2 + eslint-plugin-prettier: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.7.2) + prettier: 3.7.2 transitivePeerDependencies: - '@types/eslint' - '@vue/eslint-config-typescript@14.6.0(eslint-plugin-vue@10.5.1(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)))(eslint@9.39.1)(typescript@5.9.3)': + '@vue/eslint-config-typescript@14.6.0(eslint-plugin-vue@10.6.2(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)))(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@typescript-eslint/utils': 8.37.0(eslint@9.39.1)(typescript@5.9.3) eslint: 9.39.1 - eslint-plugin-vue: 10.5.1(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)) + eslint-plugin-vue: 10.6.2(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)) fast-glob: 3.3.3 typescript-eslint: 8.37.0(eslint@9.39.1)(typescript@5.9.3) vue-eslint-parser: 10.2.0(eslint@9.39.1) @@ -3828,11 +3904,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@vue/language-core@3.1.3(typescript@5.9.3)': + '@vue/language-core@3.1.5(typescript@5.9.3)': dependencies: '@volar/language-core': 2.4.23 - '@vue/compiler-dom': 3.5.24 - '@vue/shared': 3.5.24 + '@vue/compiler-dom': 3.5.25 + '@vue/shared': 3.5.25 alien-signals: 3.1.0 muggle-string: 0.4.1 path-browserify: 1.0.1 @@ -3840,56 +3916,56 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@vue/reactivity@3.5.24': + '@vue/reactivity@3.5.25': dependencies: - '@vue/shared': 3.5.24 + '@vue/shared': 3.5.25 - '@vue/runtime-core@3.5.24': + '@vue/runtime-core@3.5.25': dependencies: - '@vue/reactivity': 3.5.24 - '@vue/shared': 3.5.24 + '@vue/reactivity': 3.5.25 + '@vue/shared': 3.5.25 - '@vue/runtime-dom@3.5.24': + '@vue/runtime-dom@3.5.25': dependencies: - '@vue/reactivity': 3.5.24 - '@vue/runtime-core': 3.5.24 - '@vue/shared': 3.5.24 - csstype: 3.1.3 + '@vue/reactivity': 3.5.25 + '@vue/runtime-core': 3.5.25 + '@vue/shared': 3.5.25 + csstype: 3.2.3 - '@vue/server-renderer@3.5.24(vue@3.5.24(typescript@5.9.3))': + '@vue/server-renderer@3.5.25(vue@3.5.25(typescript@5.9.3))': dependencies: - '@vue/compiler-ssr': 3.5.24 - '@vue/shared': 3.5.24 - vue: 3.5.24(typescript@5.9.3) + '@vue/compiler-ssr': 3.5.25 + '@vue/shared': 3.5.25 + vue: 3.5.25(typescript@5.9.3) - '@vue/shared@3.5.24': {} + '@vue/shared@3.5.25': {} - '@vue/tsconfig@0.8.1(typescript@5.9.3)(vue@3.5.24(typescript@5.9.3))': + '@vue/tsconfig@0.8.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))': optionalDependencies: typescript: 5.9.3 - vue: 3.5.24(typescript@5.9.3) + vue: 3.5.25(typescript@5.9.3) - '@vueuse/core@14.0.0(vue@3.5.24(typescript@5.9.3))': + '@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3))': dependencies: '@types/web-bluetooth': 0.0.21 - '@vueuse/metadata': 14.0.0 - '@vueuse/shared': 14.0.0(vue@3.5.24(typescript@5.9.3)) - vue: 3.5.24(typescript@5.9.3) + '@vueuse/metadata': 14.1.0 + '@vueuse/shared': 14.1.0(vue@3.5.25(typescript@5.9.3)) + vue: 3.5.25(typescript@5.9.3) - '@vueuse/integrations@14.0.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.24(typescript@5.9.3))': + '@vueuse/integrations@14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.25(typescript@5.9.3))': dependencies: - '@vueuse/core': 14.0.0(vue@3.5.24(typescript@5.9.3)) - '@vueuse/shared': 14.0.0(vue@3.5.24(typescript@5.9.3)) - vue: 3.5.24(typescript@5.9.3) + '@vueuse/core': 14.1.0(vue@3.5.25(typescript@5.9.3)) + '@vueuse/shared': 14.1.0(vue@3.5.25(typescript@5.9.3)) + vue: 3.5.25(typescript@5.9.3) optionalDependencies: focus-trap: 7.6.2 jwt-decode: 4.0.0 - '@vueuse/metadata@14.0.0': {} + '@vueuse/metadata@14.1.0': {} - '@vueuse/shared@14.0.0(vue@3.5.24(typescript@5.9.3))': + '@vueuse/shared@14.1.0(vue@3.5.25(typescript@5.9.3))': dependencies: - vue: 3.5.24(typescript@5.9.3) + vue: 3.5.25(typescript@5.9.3) '@xmldom/xmldom@0.7.13': {} @@ -4041,7 +4117,7 @@ snapshots: cssesc@3.0.0: {} - csstype@3.1.3: {} + csstype@3.2.3: {} custom-error-instance@2.1.1: {} @@ -4098,34 +4174,34 @@ snapshots: d: 1.0.2 ext: 1.7.0 - esbuild@0.25.11: + esbuild@0.25.12: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.11 - '@esbuild/android-arm': 0.25.11 - '@esbuild/android-arm64': 0.25.11 - '@esbuild/android-x64': 0.25.11 - '@esbuild/darwin-arm64': 0.25.11 - '@esbuild/darwin-x64': 0.25.11 - '@esbuild/freebsd-arm64': 0.25.11 - '@esbuild/freebsd-x64': 0.25.11 - '@esbuild/linux-arm': 0.25.11 - '@esbuild/linux-arm64': 0.25.11 - '@esbuild/linux-ia32': 0.25.11 - '@esbuild/linux-loong64': 0.25.11 - '@esbuild/linux-mips64el': 0.25.11 - '@esbuild/linux-ppc64': 0.25.11 - '@esbuild/linux-riscv64': 0.25.11 - '@esbuild/linux-s390x': 0.25.11 - '@esbuild/linux-x64': 0.25.11 - '@esbuild/netbsd-arm64': 0.25.11 - '@esbuild/netbsd-x64': 0.25.11 - '@esbuild/openbsd-arm64': 0.25.11 - '@esbuild/openbsd-x64': 0.25.11 - '@esbuild/openharmony-arm64': 0.25.11 - '@esbuild/sunos-x64': 0.25.11 - '@esbuild/win32-arm64': 0.25.11 - '@esbuild/win32-ia32': 0.25.11 - '@esbuild/win32-x64': 0.25.11 + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 escalade@3.2.0: {} @@ -4143,22 +4219,22 @@ snapshots: dependencies: eslint: 9.39.1 - eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.6.2): + eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.7.2): dependencies: eslint: 9.39.1 - prettier: 3.6.2 + prettier: 3.7.2 prettier-linter-helpers: 1.0.0 synckit: 0.11.11 optionalDependencies: eslint-config-prettier: 10.1.8(eslint@9.39.1) - eslint-plugin-vue@10.5.1(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)): + eslint-plugin-vue@10.6.2(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)): dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) eslint: 9.39.1 natural-compare: 1.4.0 nth-check: 2.1.1 - postcss-selector-parser: 6.1.2 + postcss-selector-parser: 7.1.1 semver: 7.7.3 vue-eslint-parser: 10.2.0(eslint@9.39.1) xml-name-validator: 4.0.0 @@ -4487,7 +4563,7 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - marked@17.0.0: {} + marked@17.0.1: {} marks-pane@1.0.9: {} @@ -4591,10 +4667,10 @@ snapshots: picomatch@4.0.3: {} - pinia@3.0.4(typescript@5.9.3)(vue@3.5.24(typescript@5.9.3)): + pinia@3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)): dependencies: '@vue/devtools-api': 7.7.8 - vue: 3.5.24(typescript@5.9.3) + vue: 3.5.25(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -4602,7 +4678,7 @@ snapshots: dependencies: '@babel/runtime': 7.28.4 - postcss-selector-parser@6.1.2: + postcss-selector-parser@7.1.1: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 @@ -4621,7 +4697,7 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier@3.6.2: {} + prettier@3.7.2: {} pretty-bytes@7.1.0: {} @@ -4637,9 +4713,9 @@ snapshots: punycode@2.3.1: {} - qrcode.vue@3.6.0(vue@3.5.24(typescript@5.9.3)): + qrcode.vue@3.6.0(vue@3.5.25(typescript@5.9.3)): dependencies: - vue: 3.5.24(typescript@5.9.3) + vue: 3.5.25(typescript@5.9.3) querystringify@2.2.0: {} @@ -4694,32 +4770,32 @@ snapshots: rfdc@1.4.1: {} - rollup@4.52.5: + rollup@4.53.3: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.52.5 - '@rollup/rollup-android-arm64': 4.52.5 - '@rollup/rollup-darwin-arm64': 4.52.5 - '@rollup/rollup-darwin-x64': 4.52.5 - '@rollup/rollup-freebsd-arm64': 4.52.5 - '@rollup/rollup-freebsd-x64': 4.52.5 - '@rollup/rollup-linux-arm-gnueabihf': 4.52.5 - '@rollup/rollup-linux-arm-musleabihf': 4.52.5 - '@rollup/rollup-linux-arm64-gnu': 4.52.5 - '@rollup/rollup-linux-arm64-musl': 4.52.5 - '@rollup/rollup-linux-loong64-gnu': 4.52.5 - '@rollup/rollup-linux-ppc64-gnu': 4.52.5 - '@rollup/rollup-linux-riscv64-gnu': 4.52.5 - '@rollup/rollup-linux-riscv64-musl': 4.52.5 - '@rollup/rollup-linux-s390x-gnu': 4.52.5 - '@rollup/rollup-linux-x64-gnu': 4.52.5 - '@rollup/rollup-linux-x64-musl': 4.52.5 - '@rollup/rollup-openharmony-arm64': 4.52.5 - '@rollup/rollup-win32-arm64-msvc': 4.52.5 - '@rollup/rollup-win32-ia32-msvc': 4.52.5 - '@rollup/rollup-win32-x64-gnu': 4.52.5 - '@rollup/rollup-win32-x64-msvc': 4.52.5 + '@rollup/rollup-android-arm-eabi': 4.53.3 + '@rollup/rollup-android-arm64': 4.53.3 + '@rollup/rollup-darwin-arm64': 4.53.3 + '@rollup/rollup-darwin-x64': 4.53.3 + '@rollup/rollup-freebsd-arm64': 4.53.3 + '@rollup/rollup-freebsd-x64': 4.53.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 + '@rollup/rollup-linux-arm-musleabihf': 4.53.3 + '@rollup/rollup-linux-arm64-gnu': 4.53.3 + '@rollup/rollup-linux-arm64-musl': 4.53.3 + '@rollup/rollup-linux-loong64-gnu': 4.53.3 + '@rollup/rollup-linux-ppc64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-musl': 4.53.3 + '@rollup/rollup-linux-s390x-gnu': 4.53.3 + '@rollup/rollup-linux-x64-gnu': 4.53.3 + '@rollup/rollup-linux-x64-musl': 4.53.3 + '@rollup/rollup-openharmony-arm64': 4.53.3 + '@rollup/rollup-win32-arm64-msvc': 4.53.3 + '@rollup/rollup-win32-ia32-msvc': 4.53.3 + '@rollup/rollup-win32-x64-gnu': 4.53.3 + '@rollup/rollup-win32-x64-msvc': 4.53.3 fsevents: 2.3.3 run-parallel@1.2.0: @@ -4902,20 +4978,20 @@ snapshots: dependencies: global: 4.4.0 - vite-plugin-compression2@2.3.1(rollup@4.52.5): + vite-plugin-compression2@2.3.1(rollup@4.53.3): dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.52.5) + '@rollup/pluginutils': 5.3.0(rollup@4.53.3) tar-mini: 0.2.0 transitivePeerDependencies: - rollup - vite@7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0): + vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0): dependencies: - esbuild: 0.25.11 + esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.52.5 + rollup: 4.53.3 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.10.1 @@ -4937,19 +5013,19 @@ snapshots: transitivePeerDependencies: - supports-color - vue-final-modal@4.5.5(@vueuse/core@14.0.0(vue@3.5.24(typescript@5.9.3)))(@vueuse/integrations@14.0.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.24(typescript@5.9.3)))(focus-trap@7.6.2)(vue@3.5.24(typescript@5.9.3)): + vue-final-modal@4.5.5(@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3)))(@vueuse/integrations@14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.25(typescript@5.9.3)))(focus-trap@7.6.2)(vue@3.5.25(typescript@5.9.3)): dependencies: - '@vueuse/core': 14.0.0(vue@3.5.24(typescript@5.9.3)) - '@vueuse/integrations': 14.0.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.24(typescript@5.9.3)) + '@vueuse/core': 14.1.0(vue@3.5.25(typescript@5.9.3)) + '@vueuse/integrations': 14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.25(typescript@5.9.3)) focus-trap: 7.6.2 - vue: 3.5.24(typescript@5.9.3) + vue: 3.5.25(typescript@5.9.3) - vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)): + vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)): dependencies: - '@intlify/core-base': 11.1.12 - '@intlify/shared': 11.1.12 + '@intlify/core-base': 11.2.2 + '@intlify/shared': 11.2.2 '@vue/devtools-api': 6.6.4 - vue: 3.5.24(typescript@5.9.3) + vue: 3.5.25(typescript@5.9.3) vue-lazyload@3.0.0: {} @@ -4957,28 +5033,28 @@ snapshots: dependencies: epubjs: 0.3.93 - vue-router@4.6.3(vue@3.5.24(typescript@5.9.3)): + vue-router@4.6.3(vue@3.5.25(typescript@5.9.3)): dependencies: '@vue/devtools-api': 6.6.4 - vue: 3.5.24(typescript@5.9.3) + vue: 3.5.25(typescript@5.9.3) - vue-toastification@2.0.0-rc.5(vue@3.5.24(typescript@5.9.3)): + vue-toastification@2.0.0-rc.5(vue@3.5.25(typescript@5.9.3)): dependencies: - vue: 3.5.24(typescript@5.9.3) + vue: 3.5.25(typescript@5.9.3) - vue-tsc@3.1.3(typescript@5.9.3): + vue-tsc@3.1.5(typescript@5.9.3): dependencies: '@volar/typescript': 2.4.23 - '@vue/language-core': 3.1.3(typescript@5.9.3) + '@vue/language-core': 3.1.5(typescript@5.9.3) typescript: 5.9.3 - vue@3.5.24(typescript@5.9.3): + vue@3.5.25(typescript@5.9.3): dependencies: - '@vue/compiler-dom': 3.5.24 - '@vue/compiler-sfc': 3.5.24 - '@vue/runtime-dom': 3.5.24 - '@vue/server-renderer': 3.5.24(vue@3.5.24(typescript@5.9.3)) - '@vue/shared': 3.5.24 + '@vue/compiler-dom': 3.5.25 + '@vue/compiler-sfc': 3.5.25 + '@vue/runtime-dom': 3.5.25 + '@vue/server-renderer': 3.5.25(vue@3.5.25(typescript@5.9.3)) + '@vue/shared': 3.5.25 optionalDependencies: typescript: 5.9.3 diff --git a/frontend/src/components/ContextMenu.vue b/frontend/src/components/ContextMenu.vue new file mode 100644 index 00000000..14663fd9 --- /dev/null +++ b/frontend/src/components/ContextMenu.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/frontend/src/components/files/ListingItem.vue b/frontend/src/components/files/ListingItem.vue index 14d897cf..5db88aba 100644 --- a/frontend/src/components/files/ListingItem.vue +++ b/frontend/src/components/files/ListingItem.vue @@ -20,6 +20,7 @@ :aria-label="name" :aria-selected="isSelected" :data-ext="getExtension(name).toLowerCase()" + @contextmenu="contextMenu" >
{{ $t("prompts.moveMessage") }}