This commit is contained in:
Timi
2026-07-30 18:28:25 +08:00
parent 8b24804b22
commit f0d1090932
21 changed files with 915 additions and 268 deletions
+2
View File
@@ -0,0 +1,2 @@
/cache
/project.local.yml
+154
View File
@@ -0,0 +1,154 @@
# the name by which the project can be referenced within Serena
project_name: "timi-web"
# list of languages for which language servers are started; choose from:
# al bash clojure cpp csharp
# csharp_omnisharp dart elixir elm erlang
# fortran fsharp go groovy haskell
# haxe java julia kotlin lua
# markdown
# matlab nix pascal perl php
# php_phpactor powershell python python_jedi r
# rego ruby ruby_solargraph rust scala
# swift terraform toml typescript typescript_vts
# vue yaml zig
# (This list may be outdated. For the current list, see values of Language enum here:
# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py
# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.)
# Note:
# - For C, use cpp
# - For JavaScript, use typescript
# - For Free Pascal/Lazarus, use pascal
# Special requirements:
# Some languages require additional setup/installations.
# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers
# When using multiple languages, the first language server that supports a given file will be used for that file.
# The first language is the default language and the respective language server will be used as a fallback.
# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored.
languages:
- vue
# the encoding used by text files in the project
# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings
encoding: "utf-8"
# line ending convention to use when writing source files.
# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default)
# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings.
line_ending:
# The language backend to use for this project.
# If not set, the global setting from serena_config.yml is used.
# Valid values: LSP, JetBrains
# Note: the backend is fixed at startup. If a project with a different backend
# is activated post-init, an error will be returned.
language_backend:
# whether to use project's .gitignore files to ignore files
ignore_all_files_in_gitignore: true
# advanced configuration option allowing to configure language server-specific options.
# Maps the language key to the options.
# Have a look at the docstring of the constructors of the LS implementations within solidlsp (e.g., for C# or PHP) to see which options are available.
# No documentation on options means no options are available.
ls_specific_settings: {}
# list of additional paths to ignore in this project.
# Same syntax as gitignore, so you can use * and **.
# Note: global ignored_paths from serena_config.yml are also applied additively.
ignored_paths: []
# whether the project is in read-only mode
# If set to true, all editing tools will be disabled and attempts to use them will result in an error
# Added on 2025-04-18
read_only: false
# list of tool names to exclude.
# This extends the existing exclusions (e.g. from the global configuration)
#
# Below is the complete list of tools for convenience.
# To make sure you have the latest list of tools, and to view their descriptions,
# execute `uv run scripts/print_tool_overview.py`.
#
# * `activate_project`: Activates a project based on the project name or path.
# * `check_onboarding_performed`: Checks whether project onboarding was already performed.
# * `create_text_file`: Creates/overwrites a file in the project directory.
# * `delete_memory`: Delete a memory file. Should only happen if a user asks for it explicitly,
# for example by saying that the information retrieved from a memory file is no longer correct
# or no longer relevant for the project.
# * `edit_memory`: Replaces content matching a regular expression in a memory.
# * `execute_shell_command`: Executes a shell command.
# * `find_file`: Finds files in the given relative paths
# * `find_referencing_symbols`: Finds symbols that reference the given symbol using the language server backend
# * `find_symbol`: Performs a global (or local) search using the language server backend.
# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file.
# * `initial_instructions`: Provides instructions Serena usage (i.e. the 'Serena Instructions Manual')
# for clients that do not read the initial instructions when the MCP server is connected.
# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
# * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
# * `list_memories`: List available memories. Any memory can be read using the `read_memory` tool.
# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
# * `read_file`: Reads a file within the project directory.
# * `read_memory`: Read the content of a memory file. This tool should only be used if the information
# is relevant to the current task. You can infer whether the information
# is relevant from the memory file name.
# You should not read the same memory file multiple times in the same conversation.
# * `rename_memory`: Renames or moves a memory. Moving between project and global scope is supported
# (e.g., renaming "global/foo" to "bar" moves it from global to project scope).
# * `rename_symbol`: Renames a symbol throughout the codebase using language server refactoring capabilities.
# For JB, we use a separate tool.
# * `replace_content`: Replaces content in a file (optionally using regular expressions).
# * `replace_symbol_body`: Replaces the full definition of a symbol using the language server backend.
# * `safe_delete_symbol`:
# * `search_for_pattern`: Performs a search for a pattern in the project.
# * `write_memory`: Write some information (utf-8-encoded) about this project that can be useful for future tasks to a memory in md format.
# The memory name should be meaningful.
excluded_tools: []
# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default).
# This extends the existing inclusions (e.g. from the global configuration).
included_optional_tools: []
# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools.
# This cannot be combined with non-empty excluded_tools or included_optional_tools.
fixed_tools: []
# list of mode names to that are always to be included in the set of active modes
# The full set of modes to be activated is base_modes + default_modes.
# If the setting is undefined, the base_modes from the global configuration (serena_config.yml) apply.
# Otherwise, this setting overrides the global configuration.
# Set this to [] to disable base modes for this project.
# Set this to a list of mode names to always include the respective modes for this project.
base_modes:
# list of mode names that are to be activated by default.
# The full set of modes to be activated is base_modes + default_modes.
# If the setting is undefined, the default_modes from the global configuration (serena_config.yml) apply.
# Otherwise, this overrides the setting from the global configuration (serena_config.yml).
# This setting can, in turn, be overridden by CLI parameters (--mode).
default_modes:
# initial prompt for the project. It will always be given to the LLM upon activating the project
# (contrary to the memories, which are loaded on demand).
initial_prompt: ""
# time budget (seconds) per tool call for the retrieval of additional symbol information
# such as docstrings or parameter information.
# This overrides the corresponding setting in the global configuration; see the documentation there.
# If null or missing, use the setting from the global configuration.
symbol_info_budget:
# list of regex patterns which, when matched, mark a memory entry as readonly.
# Extends the list from the global configuration, merging the two lists.
read_only_memory_patterns: []
# list of regex patterns for memories to completely ignore.
# Matching memories will not appear in list_memories or activate_project output
# and cannot be accessed via read_memory or write_memory.
# To access ignored memory files, use the read_file tool on the raw file path.
# Extends the list from the global configuration, merging the two lists.
# Example: ["_archive/.*", "_episodes/.*"]
ignored_memory_patterns: []
+4 -3
View File
@@ -39,8 +39,9 @@
"node": ">=16.0.0" "node": ">=16.0.0"
}, },
"dependencies": { "dependencies": {
"axios": "1.13.5", "axios": "1.18.0",
"less": "4.5.1", "less": "4.5.1",
"pinia": "^3.0.2",
"marked": "^17.0.1", "marked": "^17.0.1",
"marked-gfm-heading-id": "^4.1.3", "marked-gfm-heading-id": "^4.1.3",
"marked-highlight": "^2.2.3", "marked-highlight": "^2.2.3",
@@ -49,7 +50,6 @@
"terser": "^5.44.1" "terser": "^5.44.1"
}, },
"devDependencies": { "devDependencies": {
"@types/marked": "^6.0.0",
"@types/node": "^25.0.8", "@types/node": "^25.0.8",
"@types/prismjs": "1.26.5", "@types/prismjs": "1.26.5",
"@typescript-eslint/eslint-plugin": "^8.53.0", "@typescript-eslint/eslint-plugin": "^8.53.0",
@@ -73,6 +73,7 @@
"vite-plugin-vue-setup-extend": "^0.4.0", "vite-plugin-vue-setup-extend": "^0.4.0",
"vitest": "^4.1.4", "vitest": "^4.1.4",
"vue": "^3.5.26", "vue": "^3.5.26",
"vue-tsc": "^3.2.2" "vue-tsc": "^3.2.2",
"vue-eslint-parser": "^10.0.0"
} }
} }
+159 -59
View File
@@ -9,8 +9,8 @@ importers:
.: .:
dependencies: dependencies:
axios: axios:
specifier: 1.13.5 specifier: 1.18.0
version: 1.13.5 version: 1.18.0
less: less:
specifier: 4.5.1 specifier: 4.5.1
version: 4.5.1 version: 4.5.1
@@ -26,6 +26,9 @@ importers:
marked-mangle: marked-mangle:
specifier: ^1.1.12 specifier: ^1.1.12
version: 1.1.12(marked@17.0.1) version: 1.1.12(marked@17.0.1)
pinia:
specifier: ^3.0.2
version: 3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3))
prismjs: prismjs:
specifier: 1.30.0 specifier: 1.30.0
version: 1.30.0 version: 1.30.0
@@ -33,9 +36,6 @@ importers:
specifier: ^5.44.1 specifier: ^5.44.1
version: 5.44.1 version: 5.44.1
devDependencies: devDependencies:
'@types/marked':
specifier: ^6.0.0
version: 6.0.0
'@types/node': '@types/node':
specifier: ^25.0.8 specifier: ^25.0.8
version: 25.0.8 version: 25.0.8
@@ -54,9 +54,6 @@ importers:
'@vitest/coverage-v8': '@vitest/coverage-v8':
specifier: ^4.1.4 specifier: ^4.1.4
version: 4.1.4(vitest@4.1.4) version: 4.1.4(vitest@4.1.4)
'@vitest/mocker':
specifier: ^4.1.4
version: 4.1.4(vite@8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@25.0.8)(less@4.5.1)(terser@5.44.1))
'@vue/test-utils': '@vue/test-utils':
specifier: ^2.4.6 specifier: ^2.4.6
version: 2.4.6 version: 2.4.6
@@ -74,7 +71,7 @@ importers:
version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.2))(eslint@9.39.2)(prettier@3.8.0) version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.2))(eslint@9.39.2)(prettier@3.8.0)
eslint-plugin-vue: eslint-plugin-vue:
specifier: ^10.6.2 specifier: ^10.6.2
version: 10.6.2(@typescript-eslint/parser@8.53.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(vue-eslint-parser@9.4.3(eslint@9.39.2)) version: 10.6.2(@typescript-eslint/parser@8.53.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(vue-eslint-parser@10.4.1(eslint@9.39.2))
happy-dom: happy-dom:
specifier: ^20.8.9 specifier: ^20.8.9
version: 20.8.9 version: 20.8.9
@@ -108,6 +105,9 @@ importers:
vue: vue:
specifier: ^3.5.26 specifier: ^3.5.26
version: 3.5.26(typescript@5.9.3) version: 3.5.26(typescript@5.9.3)
vue-eslint-parser:
specifier: ^10.0.0
version: 10.4.1(eslint@9.39.2)
vue-tsc: vue-tsc:
specifier: ^3.2.2 specifier: ^3.2.2
version: 3.2.2(typescript@5.9.3) version: 3.2.2(typescript@5.9.3)
@@ -691,10 +691,6 @@ packages:
'@types/json-schema@7.0.15': '@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
'@types/marked@6.0.0':
resolution: {integrity: sha512-jmjpa4BwUsmhxcfsgUit/7A9KbrC48Q0q8KvnY107ogcjGgTFDlIL3RpihNpx2Mu1hM4mdFQjoVc4O6JoGKHsA==}
deprecated: This is a stub types definition. marked provides its own type definitions, so you do not need this installed.
'@types/node@25.0.8': '@types/node@25.0.8':
resolution: {integrity: sha512-powIePYMmC3ibL0UJ2i2s0WIbq6cg6UyVFQxSCpaPxxzAaziRfimGivjdF943sSGV6RADVbk0Nvlm5P/FB44Zg==} resolution: {integrity: sha512-powIePYMmC3ibL0UJ2i2s0WIbq6cg6UyVFQxSCpaPxxzAaziRfimGivjdF943sSGV6RADVbk0Nvlm5P/FB44Zg==}
@@ -862,6 +858,15 @@ packages:
'@vue/compiler-vue2@2.7.16': '@vue/compiler-vue2@2.7.16':
resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==}
'@vue/devtools-api@7.7.10':
resolution: {integrity: sha512-KxtEpUOOpFz/qOGRrAwA36QF7DqIA+FXgCYit9mk9wjbaZt0sXOFz81ElOZtKA4HbWHUdwNjZHBFsFFyp5BZiA==}
'@vue/devtools-kit@7.7.10':
resolution: {integrity: sha512-3WNi2Kq4tbpVbmhml7RiphmAt0279oh3fKNeWMQIrltfX8Q91b4i5PL8DtyNKdwmcsGrV4fg+erwWOmD05CLIw==}
'@vue/devtools-shared@7.7.10':
resolution: {integrity: sha512-wOPslzB8vTvpxwdaOcR2qAbwmuSP0L+rhpoC6Cf56V3Jip+HWb7PQQXOUPgBNQARpXsbQX/+mvi8kKucmBGRwQ==}
'@vue/language-core@2.2.0': '@vue/language-core@2.2.0':
resolution: {integrity: sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==} resolution: {integrity: sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==}
peerDependencies: peerDependencies:
@@ -918,6 +923,10 @@ packages:
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
hasBin: true hasBin: true
agent-base@6.0.2:
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
engines: {node: '>= 6.0.0'}
ajv-draft-04@1.0.0: ajv-draft-04@1.0.0:
resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==}
peerDependencies: peerDependencies:
@@ -985,8 +994,8 @@ packages:
asynckit@0.4.0: asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
axios@1.13.5: axios@1.18.0:
resolution: {integrity: sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==} resolution: {integrity: sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==}
babel-plugin-prismjs@2.1.0: babel-plugin-prismjs@2.1.0:
resolution: {integrity: sha512-ehzSKYfeAz4U78zi/sfwsjDPlq0LvDKxNefcZTJ/iKBu+plsHsLqZhUeGf1+82LAcA35UZGbU6ksEx2Utphc/g==} resolution: {integrity: sha512-ehzSKYfeAz4U78zi/sfwsjDPlq0LvDKxNefcZTJ/iKBu+plsHsLqZhUeGf1+82LAcA35UZGbU6ksEx2Utphc/g==}
@@ -996,6 +1005,9 @@ packages:
balanced-match@1.0.2: balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
birpc@2.9.0:
resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==}
boolbase@1.0.0: boolbase@1.0.0:
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
@@ -1085,6 +1097,10 @@ packages:
copy-anything@2.0.6: copy-anything@2.0.6:
resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==}
copy-anything@4.0.5:
resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==}
engines: {node: '>=18'}
cross-spawn@7.0.6: cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@@ -1248,10 +1264,6 @@ packages:
'@typescript-eslint/parser': '@typescript-eslint/parser':
optional: true optional: true
eslint-scope@7.2.2:
resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
eslint-scope@8.4.0: eslint-scope@8.4.0:
resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -1278,14 +1290,14 @@ packages:
resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
espree@9.6.1:
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
esquery@1.5.0: esquery@1.5.0:
resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
engines: {node: '>=0.10'} engines: {node: '>=0.10'}
esquery@1.7.0:
resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==}
engines: {node: '>=0.10'}
esrecurse@4.3.0: esrecurse@4.3.0:
resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
engines: {node: '>=4.0'} engines: {node: '>=4.0'}
@@ -1350,8 +1362,8 @@ packages:
flatted@3.3.1: flatted@3.3.1:
resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
follow-redirects@1.15.11: follow-redirects@1.16.0:
resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==}
engines: {node: '>=4.0'} engines: {node: '>=4.0'}
peerDependencies: peerDependencies:
debug: '*' debug: '*'
@@ -1446,9 +1458,16 @@ packages:
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
hasBin: true hasBin: true
hookable@5.5.3:
resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
html-escaper@2.0.2: html-escaper@2.0.2:
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
https-proxy-agent@5.0.1:
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
engines: {node: '>= 6'}
iconv-lite@0.6.3: iconv-lite@0.6.3:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@@ -1499,6 +1518,10 @@ packages:
is-what@3.14.1: is-what@3.14.1:
resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==}
is-what@5.5.0:
resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==}
engines: {node: '>=18'}
isexe@2.0.0: isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
@@ -1759,6 +1782,9 @@ packages:
resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==}
engines: {node: '>=16 || 14 >=14.17'} engines: {node: '>=16 || 14 >=14.17'}
mitt@3.0.1:
resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
mlly@1.7.4: mlly@1.7.4:
resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==}
@@ -1850,6 +1876,9 @@ packages:
pathe@2.0.3: pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
perfect-debounce@1.0.0:
resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
picocolors@1.0.0: picocolors@1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
@@ -1872,6 +1901,15 @@ packages:
resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
engines: {node: '>=6'} engines: {node: '>=6'}
pinia@3.0.4:
resolution: {integrity: sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==}
peerDependencies:
typescript: '>=4.5.0'
vue: ^3.5.11
peerDependenciesMeta:
typescript:
optional: true
pkg-types@1.3.1: pkg-types@1.3.1:
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
@@ -1917,8 +1955,9 @@ packages:
proto-list@1.2.4: proto-list@1.2.4:
resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
proxy-from-env@1.1.0: proxy-from-env@2.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==}
engines: {node: '>=10'}
prr@1.0.1: prr@1.0.1:
resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==}
@@ -1949,6 +1988,9 @@ packages:
resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
hasBin: true hasBin: true
rfdc@1.4.1:
resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
rolldown@1.0.0-rc.12: rolldown@1.0.0-rc.12:
resolution: {integrity: sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==} resolution: {integrity: sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -2025,6 +2067,10 @@ packages:
resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
deprecated: Please use @jridgewell/sourcemap-codec instead deprecated: Please use @jridgewell/sourcemap-codec instead
speakingurl@14.0.1:
resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==}
engines: {node: '>=0.10.0'}
sprintf-js@1.0.3: sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
@@ -2061,6 +2107,10 @@ packages:
strip-literal@3.1.0: strip-literal@3.1.0:
resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==}
superjson@2.2.6:
resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==}
engines: {node: '>=16'}
supports-color@5.5.0: supports-color@5.5.0:
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
engines: {node: '>=4'} engines: {node: '>=4'}
@@ -2295,11 +2345,11 @@ packages:
vue-component-type-helpers@2.2.12: vue-component-type-helpers@2.2.12:
resolution: {integrity: sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==} resolution: {integrity: sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==}
vue-eslint-parser@9.4.3: vue-eslint-parser@10.4.1:
resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==} resolution: {integrity: sha512-Gk6gRDj0n/fkRa3C3l0bBheoBckUq/Rs0F/TvMWIS6nzzx67amAViMe9CkNgsP2tXyQONvGiHQESHwFtZ3aYDA==}
engines: {node: ^14.17.0 || >=16.0.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: '>=6.0.0' eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
vue-tsc@3.2.2: vue-tsc@3.2.2:
resolution: {integrity: sha512-r9YSia/VgGwmbbfC06hDdAatH634XJ9nVl6Zrnz1iK4ucp8Wu78kawplXnIDa3MSu1XdQQePTHLXYwPDWn+nyQ==} resolution: {integrity: sha512-r9YSia/VgGwmbbfC06hDdAatH634XJ9nVl6Zrnz1iK4ucp8Wu78kawplXnIDa3MSu1XdQQePTHLXYwPDWn+nyQ==}
@@ -2904,10 +2954,6 @@ snapshots:
'@types/json-schema@7.0.15': {} '@types/json-schema@7.0.15': {}
'@types/marked@6.0.0':
dependencies:
marked: 17.0.1
'@types/node@25.0.8': '@types/node@25.0.8':
dependencies: dependencies:
undici-types: 7.16.0 undici-types: 7.16.0
@@ -3174,6 +3220,24 @@ snapshots:
de-indent: 1.0.2 de-indent: 1.0.2
he: 1.2.0 he: 1.2.0
'@vue/devtools-api@7.7.10':
dependencies:
'@vue/devtools-kit': 7.7.10
'@vue/devtools-kit@7.7.10':
dependencies:
'@vue/devtools-shared': 7.7.10
birpc: 2.9.0
hookable: 5.5.3
mitt: 3.0.1
perfect-debounce: 1.0.0
speakingurl: 14.0.1
superjson: 2.2.6
'@vue/devtools-shared@7.7.10':
dependencies:
rfdc: 1.4.1
'@vue/language-core@2.2.0(typescript@5.9.3)': '@vue/language-core@2.2.0(typescript@5.9.3)':
dependencies: dependencies:
'@volar/language-core': 2.4.11 '@volar/language-core': 2.4.11
@@ -3240,6 +3304,12 @@ snapshots:
acorn@8.15.0: {} acorn@8.15.0: {}
agent-base@6.0.2:
dependencies:
debug: 4.4.3
transitivePeerDependencies:
- supports-color
ajv-draft-04@1.0.0(ajv@8.13.0): ajv-draft-04@1.0.0(ajv@8.13.0):
optionalDependencies: optionalDependencies:
ajv: 8.13.0 ajv: 8.13.0
@@ -3303,13 +3373,15 @@ snapshots:
asynckit@0.4.0: {} asynckit@0.4.0: {}
axios@1.13.5: axios@1.18.0:
dependencies: dependencies:
follow-redirects: 1.15.11 follow-redirects: 1.16.0
form-data: 4.0.5 form-data: 4.0.5
proxy-from-env: 1.1.0 https-proxy-agent: 5.0.1
proxy-from-env: 2.1.0
transitivePeerDependencies: transitivePeerDependencies:
- debug - debug
- supports-color
babel-plugin-prismjs@2.1.0(prismjs@1.30.0): babel-plugin-prismjs@2.1.0(prismjs@1.30.0):
dependencies: dependencies:
@@ -3317,6 +3389,8 @@ snapshots:
balanced-match@1.0.2: {} balanced-match@1.0.2: {}
birpc@2.9.0: {}
boolbase@1.0.0: {} boolbase@1.0.0: {}
brace-expansion@1.1.11: brace-expansion@1.1.11:
@@ -3402,6 +3476,10 @@ snapshots:
dependencies: dependencies:
is-what: 3.14.1 is-what: 3.14.1
copy-anything@4.0.5:
dependencies:
is-what: 5.5.0
cross-spawn@7.0.6: cross-spawn@7.0.6:
dependencies: dependencies:
path-key: 3.1.1 path-key: 3.1.1
@@ -3504,7 +3582,7 @@ snapshots:
optionalDependencies: optionalDependencies:
eslint-config-prettier: 10.1.8(eslint@9.39.2) eslint-config-prettier: 10.1.8(eslint@9.39.2)
eslint-plugin-vue@10.6.2(@typescript-eslint/parser@8.53.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(vue-eslint-parser@9.4.3(eslint@9.39.2)): eslint-plugin-vue@10.6.2(@typescript-eslint/parser@8.53.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(vue-eslint-parser@10.4.1(eslint@9.39.2)):
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@9.39.2) '@eslint-community/eslint-utils': 4.4.0(eslint@9.39.2)
eslint: 9.39.2 eslint: 9.39.2
@@ -3512,16 +3590,11 @@ snapshots:
nth-check: 2.1.1 nth-check: 2.1.1
postcss-selector-parser: 7.1.1 postcss-selector-parser: 7.1.1
semver: 7.7.1 semver: 7.7.1
vue-eslint-parser: 9.4.3(eslint@9.39.2) vue-eslint-parser: 10.4.1(eslint@9.39.2)
xml-name-validator: 4.0.0 xml-name-validator: 4.0.0
optionalDependencies: optionalDependencies:
'@typescript-eslint/parser': 8.53.0(eslint@9.39.2)(typescript@5.9.3) '@typescript-eslint/parser': 8.53.0(eslint@9.39.2)(typescript@5.9.3)
eslint-scope@7.2.2:
dependencies:
esrecurse: 4.3.0
estraverse: 5.3.0
eslint-scope@8.4.0: eslint-scope@8.4.0:
dependencies: dependencies:
esrecurse: 4.3.0 esrecurse: 4.3.0
@@ -3576,16 +3649,14 @@ snapshots:
acorn-jsx: 5.3.2(acorn@8.15.0) acorn-jsx: 5.3.2(acorn@8.15.0)
eslint-visitor-keys: 4.2.1 eslint-visitor-keys: 4.2.1
espree@9.6.1:
dependencies:
acorn: 8.15.0
acorn-jsx: 5.3.2(acorn@8.15.0)
eslint-visitor-keys: 3.4.3
esquery@1.5.0: esquery@1.5.0:
dependencies: dependencies:
estraverse: 5.3.0 estraverse: 5.3.0
esquery@1.7.0:
dependencies:
estraverse: 5.3.0
esrecurse@4.3.0: esrecurse@4.3.0:
dependencies: dependencies:
estraverse: 5.3.0 estraverse: 5.3.0
@@ -3634,7 +3705,7 @@ snapshots:
flatted@3.3.1: {} flatted@3.3.1: {}
follow-redirects@1.15.11: {} follow-redirects@1.16.0: {}
foreground-child@3.3.1: foreground-child@3.3.1:
dependencies: dependencies:
@@ -3731,8 +3802,17 @@ snapshots:
he@1.2.0: {} he@1.2.0: {}
hookable@5.5.3: {}
html-escaper@2.0.2: {} html-escaper@2.0.2: {}
https-proxy-agent@5.0.1:
dependencies:
agent-base: 6.0.2
debug: 4.4.3
transitivePeerDependencies:
- supports-color
iconv-lite@0.6.3: iconv-lite@0.6.3:
dependencies: dependencies:
safer-buffer: 2.1.2 safer-buffer: 2.1.2
@@ -3770,6 +3850,8 @@ snapshots:
is-what@3.14.1: {} is-what@3.14.1: {}
is-what@5.5.0: {}
isexe@2.0.0: {} isexe@2.0.0: {}
istanbul-lib-coverage@3.2.2: {} istanbul-lib-coverage@3.2.2: {}
@@ -4007,6 +4089,8 @@ snapshots:
minipass@7.1.3: {} minipass@7.1.3: {}
mitt@3.0.1: {}
mlly@1.7.4: mlly@1.7.4:
dependencies: dependencies:
acorn: 8.14.1 acorn: 8.14.1
@@ -4091,6 +4175,8 @@ snapshots:
pathe@2.0.3: {} pathe@2.0.3: {}
perfect-debounce@1.0.0: {}
picocolors@1.0.0: {} picocolors@1.0.0: {}
picocolors@1.1.1: {} picocolors@1.1.1: {}
@@ -4104,6 +4190,13 @@ snapshots:
pify@4.0.1: pify@4.0.1:
optional: true optional: true
pinia@3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)):
dependencies:
'@vue/devtools-api': 7.7.10
vue: 3.5.26(typescript@5.9.3)
optionalDependencies:
typescript: 5.9.3
pkg-types@1.3.1: pkg-types@1.3.1:
dependencies: dependencies:
confbox: 0.1.8 confbox: 0.1.8
@@ -4157,7 +4250,7 @@ snapshots:
proto-list@1.2.4: {} proto-list@1.2.4: {}
proxy-from-env@1.1.0: {} proxy-from-env@2.1.0: {}
prr@1.0.1: prr@1.0.1:
optional: true optional: true
@@ -4180,6 +4273,8 @@ snapshots:
path-parse: 1.0.7 path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0 supports-preserve-symlinks-flag: 1.0.0
rfdc@1.4.1: {}
rolldown@1.0.0-rc.12(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2): rolldown@1.0.0-rc.12(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2):
dependencies: dependencies:
'@oxc-project/types': 0.122.0 '@oxc-project/types': 0.122.0
@@ -4280,6 +4375,8 @@ snapshots:
sourcemap-codec@1.4.8: {} sourcemap-codec@1.4.8: {}
speakingurl@14.0.1: {}
sprintf-js@1.0.3: {} sprintf-js@1.0.3: {}
stackback@0.0.2: {} stackback@0.0.2: {}
@@ -4314,6 +4411,10 @@ snapshots:
dependencies: dependencies:
js-tokens: 9.0.1 js-tokens: 9.0.1
superjson@2.2.6:
dependencies:
copy-anything: 4.0.5
supports-color@5.5.0: supports-color@5.5.0:
dependencies: dependencies:
has-flag: 3.0.0 has-flag: 3.0.0
@@ -4519,15 +4620,14 @@ snapshots:
vue-component-type-helpers@2.2.12: {} vue-component-type-helpers@2.2.12: {}
vue-eslint-parser@9.4.3(eslint@9.39.2): vue-eslint-parser@10.4.1(eslint@9.39.2):
dependencies: dependencies:
debug: 4.4.3 debug: 4.4.3
eslint: 9.39.2 eslint: 9.39.2
eslint-scope: 7.2.2 eslint-scope: 8.4.0
eslint-visitor-keys: 3.4.3 eslint-visitor-keys: 4.2.1
espree: 9.6.1 espree: 10.4.0
esquery: 1.5.0 esquery: 1.7.0
lodash: 4.17.21
semver: 7.7.3 semver: 7.7.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
+2 -2
View File
@@ -7,7 +7,7 @@ import { axios } from "./BaseAPI";
* @param id 文章 ID * @param id 文章 ID
* @returns 文章数据 * @returns 文章数据
*/ */
async function view(id: number): Promise<ArticleView<any>> { async function view(id: string): Promise<ArticleView<any>> {
return axios.get(`/article/${id}`); return axios.get(`/article/${id}`);
} }
@@ -17,7 +17,7 @@ async function view(id: number): Promise<ArticleView<any>> {
* @param id 文章 ID * @param id 文章 ID
* @returns 最新喜欢数量 * @returns 最新喜欢数量
*/ */
async function like(id: number): Promise<number> { async function like(id: string): Promise<number> {
return axios.get(`/article/like/${id}`); return axios.get(`/article/like/${id}`);
} }
+58
View File
@@ -0,0 +1,58 @@
import {Attachment, BizUpdateReq, TempFileResp} from "../types";
import {axios} from "./BaseAPI";
import CommonAPI from "./CommonAPI";
const BASE_URI = "/attach";
/**
* 上传临时附件
*
* @param file 文件或文件列表
* @param ttl 有效期
* @returns 临时附件列表
*/
async function uploadTemp(file: File | File[], ttl?: string): Promise<TempFileResp[]> {
const formData = new FormData();
const fileList = Array.isArray(file) ? file : [file];
for (const item of fileList) {
formData.append("file", item);
}
if (ttl) {
formData.append("ttl", ttl);
}
return await axios.post(`${BASE_URI}/temp/upload`, formData);
}
/**
* 按业务差分更新附件
*
* @param req 更新请求
*/
async function updateByBiz(req: BizUpdateReq): Promise<void> {
return await axios.post(`${BASE_URI}/update/biz`, req);
}
/**
* 按业务查询附件列表
*
* @param bizType 业务类型
* @param bizId 业务 ID
* @param attachTypeList 附件类型列表
*/
async function listByBiz(bizType: string, bizId: string, attachTypeList?: string[]): Promise<Attachment[]> {
return await axios.get(`${BASE_URI}/list/biz`, {
params: {
bizType,
bizId,
attachTypeList
}
});
}
export default {
uploadTemp,
updateByBiz,
listByBiz,
getReadURL: CommonAPI.getAttachmentReadAPI,
getTempReadURL: CommonAPI.getAttachmentTempReadAPI
};
+19 -3
View File
@@ -1,9 +1,23 @@
import {Setting, TemplateBizType} from "../types"; import {CaptchaResult, Setting, TemplateBizType} from "../types";
import {axios} from "./BaseAPI"; import {axios} from "./BaseAPI";
const getCaptchaAPI = () => axios.defaults.baseURL + "/captcha"; function getBaseURI(): string {
const baseURL = axios.defaults.baseURL;
if (!baseURL || baseURL === "undefined") {
return "";
}
return baseURL.replace(/\/$/, "");
}
const getAttachmentReadAPI = (mongoId: string) => `${axios.defaults.baseURL}/attachment/read/${mongoId}`; const getCaptchaAPI = () => `${getBaseURI()}/captcha`;
async function captcha(width: number, height: number): Promise<CaptchaResult> {
return await axios.get(`/captcha?width=${width}&height=${height}`);
}
const getAttachmentReadAPI = (id: string) => `${getBaseURI()}/attach/read/${id}`;
const getAttachmentTempReadAPI = (id: string) => `${getBaseURI()}/attach/temp/read?id=${id}`;
async function getTemplate(bizType: TemplateBizType, code: string): Promise<string> { async function getTemplate(bizType: TemplateBizType, code: string): Promise<string> {
return axios.get(`/template?bizType=${bizType}&bizCode=${code}`); return axios.get(`/template?bizType=${bizType}&bizCode=${code}`);
@@ -30,7 +44,9 @@ async function settingMap(map: Record<string, string[]>): Promise<Map<string, Ma
export default { export default {
getCaptchaAPI, getCaptchaAPI,
captcha,
getAttachmentReadAPI, getAttachmentReadAPI,
getAttachmentTempReadAPI,
getTemplate, getTemplate,
settingMap settingMap
}; };
+29
View File
@@ -0,0 +1,29 @@
import { axios } from "./BaseAPI";
import type { Page, PageResult, Permission, PermissionPayload } from "../types";
const BASE_URI = "/user/permission";
async function list(req: Page<Permission>): Promise<PageResult<Permission>> {
return axios.post(`${BASE_URI}/list`, req);
}
async function create(req: PermissionPayload): Promise<void> {
return axios.post(`${BASE_URI}/create`, req);
}
async function update(req: PermissionPayload): Promise<void> {
return axios.post(`${BASE_URI}/update`, req);
}
async function remove(id: string): Promise<void> {
return axios.post(`${BASE_URI}/delete`, undefined, {
params: { id }
});
}
export default {
list,
create,
update,
remove
};
+55
View File
@@ -0,0 +1,55 @@
import { axios } from "./BaseAPI";
import type { Page, PageResult, Permission, Role, RolePayload, UserRoleAuthorizeReq } from "../types";
const BASE_URI = "/user/role";
async function list(req: Page<Role>): Promise<PageResult<Role>> {
return axios.post(`${BASE_URI}/list`, req);
}
async function detail(id: string): Promise<Role> {
return axios.post(`${BASE_URI}/detail`, undefined, {
params: { id }
});
}
async function create(req: RolePayload): Promise<void> {
return axios.post(`${BASE_URI}/create`, req);
}
async function update(req: RolePayload): Promise<void> {
return axios.post(`${BASE_URI}/update`, req);
}
async function remove(id: string): Promise<void> {
return axios.post(`${BASE_URI}/delete`, undefined, {
params: { id }
});
}
async function authorizedList(userId: string): Promise<Role[]> {
return axios.post(`${BASE_URI}/authorized/list`, undefined, {
params: { userId }
});
}
async function authorize(req: UserRoleAuthorizeReq): Promise<void> {
return axios.post(`${BASE_URI}/authorized/create`, req);
}
async function authorizedPermission(userId: string): Promise<Permission[]> {
return axios.post(`${BASE_URI}/authorized/permission`, undefined, {
params: { userId }
});
}
export default {
list,
detail,
create,
update,
remove,
authorizedList,
authorize,
authorizedPermission
};
+32 -32
View File
@@ -1,30 +1,21 @@
import { import {Attachment, CaptchaData, LoginRequest, LoginResponse, RegisterRequest, UpdatePasswordRequest, User, UserAttachType} from "../types";
Attachment,
CaptchaData,
LoginRequest,
LoginResponse,
RegisterRequest,
UserAttachType,
UserProfileView,
UserView
} from "../types";
import {axios} from "./BaseAPI"; import {axios} from "./BaseAPI";
import CommonAPI from "./CommonAPI"; import CommonAPI from "./CommonAPI";
const BASE_URI = "/user"; const BASE_URI = "/user";
async function register(captchaData: CaptchaData<RegisterRequest>): Promise<LoginResponse> { async function register(req: CaptchaData<RegisterRequest>): Promise<LoginResponse> {
return axios.post(`${BASE_URI}/register`, captchaData); return await axios.post(`${BASE_URI}/register`, req);
} }
/** /**
* 登录 * 登录
* *
* @param captchaData 验证码登录对象 * @param req 验证码登录对象
* @returns LoginResponse * @returns LoginResponse
*/ */
async function login(captchaData: CaptchaData<LoginRequest>): Promise<LoginResponse> { async function login(req: CaptchaData<LoginRequest>): Promise<LoginResponse> {
return axios.post(`${BASE_URI}/login`, captchaData); return await axios.post(`${BASE_URI}/login`, req);
} }
/** /**
@@ -32,12 +23,20 @@ async function login(captchaData: CaptchaData<LoginRequest>): Promise<LoginRespo
* *
* @returns true 为已登录 * @returns true 为已登录
*/ */
async function login4Token(): Promise<LoginResponse> { async function loginByToken(): Promise<LoginResponse> {
return axios.post(`${BASE_URI}/login/token`); return await axios.post(`${BASE_URI}/login/token`);
} }
async function logout(): Promise<void> { async function logout(): Promise<void> {
return axios.post(`${BASE_URI}/logout`); return await axios.post(`${BASE_URI}/logout`);
}
async function updateCurrent(req: User): Promise<LoginResponse> {
return await axios.post(`${BASE_URI}/current/update`, req);
}
async function updatePassword(req: UpdatePasswordRequest): Promise<void> {
return await axios.post(`${BASE_URI}/update/password`, req);
} }
/** /**
@@ -46,29 +45,28 @@ async function logout(): Promise<void> {
* @param id 用户 ID * @param id 用户 ID
* @returns 用户数据 * @returns 用户数据
*/ */
async function view(id: number): Promise<UserView> { async function view(id: string): Promise<User> {
return axios.post(`${BASE_URI}/view/${id}`); return await axios.post(`${BASE_URI}/view/${id}`);
} }
function getAvatarURL(profile?: UserProfileView) { function getAvatarURL(user?: User) {
if (profile && profile.attachmentList) { if (user?.attachmentList) {
return findAttachmentByType(profile.attachmentList, [UserAttachType.AVATAR, UserAttachType.DEFAULT_AVATAR]); return findAttachmentByType(user.attachmentList, [UserAttachType.AVATAR, UserAttachType.DEFAULT_AVATAR]);
} }
} }
function getWrapperURL(profile?: UserProfileView) { function getWrapperURL(user?: User) {
if (profile && profile.attachmentList) { if (user?.attachmentList) {
return findAttachmentByType(profile.attachmentList, [UserAttachType.WRAPPER, UserAttachType.DEFAULT_WRAPPER]); return findAttachmentByType(user.attachmentList, [UserAttachType.WRAPPER, UserAttachType.DEFAULT_WRAPPER]);
} }
} }
function findAttachmentByType(attachmentList: Attachment[], types: UserAttachType[]) { function findAttachmentByType(attachmentList: Attachment[], types: UserAttachType[]) {
for (let i = 0; i < attachmentList.length; i++) { for (let i = 0; i < attachmentList.length; i++) {
const attachType = (<any>UserAttachType)[attachmentList[i].attachType!]; const attachType = attachmentList[i].attachType as UserAttachType | undefined;
for (let type of types) { const id = attachmentList[i].id;
if (attachType === type) { if (id && attachType && types.includes(attachType)) {
return CommonAPI.getAttachmentReadAPI(attachmentList[i].mongoId); return CommonAPI.getAttachmentReadAPI(id);
}
} }
} }
} }
@@ -76,8 +74,10 @@ function findAttachmentByType(attachmentList: Attachment[], types: UserAttachTyp
export default { export default {
register, register,
login, login,
login4Token, loginByToken,
logout, logout,
updateCurrent,
updatePassword,
view, view,
getAvatarURL, getAvatarURL,
+3
View File
@@ -1,5 +1,8 @@
export { default as ArticleAPI } from "./ArticleAPI"; export { default as ArticleAPI } from "./ArticleAPI";
export { default as AttachmentAPI } from "./AttachmentAPI";
export { default as CommentAPI } from "./CommentAPI"; export { default as CommentAPI } from "./CommentAPI";
export { default as CommonAPI } from "./CommonAPI"; export { default as CommonAPI } from "./CommonAPI";
export { default as DeveloperAPI } from "./DeveloperAPI"; export { default as DeveloperAPI } from "./DeveloperAPI";
export { default as PermissionAPI } from "./PermissionAPI";
export { default as RoleAPI } from "./RoleAPI";
export { default as UserAPI } from "./UserAPI"; export { default as UserAPI } from "./UserAPI";
+78 -21
View File
@@ -1,46 +1,103 @@
<template> <template>
<img <button
class="tui-captcha ir-pixelated" class="tui-captcha ir-pixelated"
v-if="src" type="button"
:width="width" :style="captchaStyle"
:height="height" :disabled="isLoading"
:src="src" :title="title"
alt="验证码" @click="update"
@click="update()" >
/> <img v-if="src" :src="src" :alt="title" />
<span v-else v-text="placeholder" />
</button>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import Toolkit from "../../utils/Toolkit"; import {CommonAPI} from "../../api";
import type {CaptchaResult} from "../../types";
defineOptions({ defineOptions({
name: "Captcha" name: "Captcha"
}); });
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
width: number, width?: number,
height: number, height?: number,
from: string, title?: string,
api: string, placeholder?: string,
}>(), {}); }>(), {
const { width, height, from, api } = toRefs(props); width: 90,
height: 40,
title: "验证码",
placeholder: "刷新"
});
const emit = defineEmits<{
update: [result: CaptchaResult],
error: [error: unknown]
}>();
const { width, height, title, placeholder } = toRefs(props);
const src = ref(""); const src = ref("");
function update() { const captchaId = ref("");
src.value = `${api.value}?from=${from.value}&width=${width.value}&height=${height.value}&r=${Toolkit.random(0, 999999)}`; const isLoading = ref(false);
const captchaStyle = computed(() => {
return {
width: `${width.value / 16}rem`,
height: `${height.value / 16}rem`
};
});
async function update(): Promise<void> {
isLoading.value = true;
try {
const result = await CommonAPI.captcha(width.value, height.value);
captchaId.value = result.id;
src.value = result.data;
emit("update", result);
} catch (error) {
emit("error", error);
} finally {
isLoading.value = false;
} }
onMounted(update); }
onMounted(async () => {
await update();
});
defineExpose({ defineExpose({
captchaId,
src,
isLoading,
update update
}); });
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.tui-captcha { .tui-captcha {
cursor: var(--tui-cur-pointer); margin: 0;
border: 1px solid gray; border: 0;
display: block; padding: 0;
display: grid;
background: #f8fafc;
overflow: hidden;
cursor: pointer;
color: #64748b;
flex: 0 0 auto;
pointer-events: all; pointer-events: all;
place-items: center;
border-radius: .5rem;
&:disabled {
cursor: not-allowed;
opacity: .64;
}
img {
width: 100%;
height: 100%;
display: block;
}
} }
</style> </style>
+166 -50
View File
@@ -1,79 +1,195 @@
import { LoginResponse, LoginToken, LoginUser, UserToken } from "../types"; import {defineStore} from "pinia";
import {computed, reactive, readonly, ref} from "vue";
import {CaptchaData, LoginRequest, LoginResponse, LoginUser} from "../types";
import Cooker from "../utils/Cooker";
import Storage from "../utils/Storage"; import Storage from "../utils/Storage";
import UserAPI from "../api/UserAPI"; import {UserAPI} from "../api";
const loginUser = reactive<LoginUser>({ /** 用户 Store 配置项 */
token: undefined, interface UserStoreOptions {
user: undefined /** localStorage 储存 key,默认 "loginUser" */
}); storageKey?: string;
function isLogged(): boolean {
return !!loginUser.user;
} }
async function login4Token(token: LoginToken): Promise<LoginResponse | null> { /** 访问控制匹配模式 */
export type AccessMatchMode = "and" | "or";
let _storageKey = "loginUser";
function normalizeAccessList(list?: string[]): string[] {
if (!list?.length) {
return [];
}
return list
.map(item => item?.trim())
.filter((item): item is string => !!item);
}
function matchAccess(sourceList?: string[], targetList?: string | string[], mode: AccessMatchMode = "or"): boolean {
const normalizedTargetList = normalizeAccessList(Array.isArray(targetList) ? targetList : [targetList || ""]);
if (!normalizedTargetList.length) {
return true;
}
const sourceSet = new Set(normalizeAccessList(sourceList));
if (!sourceSet.size) {
return false;
}
if (mode === "and") {
return normalizedTargetList.every(item => sourceSet.has(item));
}
return normalizedTargetList.some(item => sourceSet.has(item));
}
/**
* 配置用户 Store,应在使用 useUserStore 之前调用
* @param options 配置项
*/
function configureUserStore(options: UserStoreOptions): void {
if (options.storageKey) {
_storageKey = options.storageKey;
}
}
const useUserStore = defineStore("user", () => {
type LoginUserState = LoginUser & Record<string, unknown>;
const loginUser = reactive<LoginUserState>({});
const isRestored = ref(false);
const token = computed(() => loginUser.token ?? "");
const isLoggedIn = computed(() => isValidLoginUser(loginUser));
function resetLoginUser(nextUser?: LoginUserState): void {
Object.keys(loginUser).forEach((key) => {
delete loginUser[key];
});
if (nextUser) {
Object.assign(loginUser, nextUser);
}
}
function isValidLoginUser(user?: LoginUserState | null): user is LoginResponse {
return !!user?.token && !!user.expireAt && new Date().getTime() < user.expireAt;
}
function isLogged(): boolean {
return isLoggedIn.value;
}
function getLoginUser<T extends LoginUser = LoginUser>(): T | null {
if (!isLogged()) {
return null;
}
return loginUser as T;
}
function getRoleList(): string[] {
return normalizeAccessList(loginUser.user?.roleList);
}
function getPermissionList(): string[] {
return normalizeAccessList(loginUser.user?.permissionList);
}
function hasRoles(roleList: string | string[], mode: AccessMatchMode = "or"): boolean {
return matchAccess(getRoleList(), roleList, mode);
}
function hasPermissions(permissionList: string | string[], mode: AccessMatchMode = "or"): boolean {
return matchAccess(getPermissionList(), permissionList, mode);
}
async function login<T extends LoginUser = LoginUser>(req: CaptchaData<LoginRequest>): Promise<T> {
const result = await UserAPI.login(req);
const nextUser = result as unknown as T;
await updateLoginUser(nextUser);
return nextUser;
}
async function loginByToken<T extends LoginUser = LoginUser>(token: string): Promise<T | null> {
loginUser.token = token; loginUser.token = token;
// 未过期 // 未过期
try { try {
const resp = await UserAPI.login4Token(); const result = await UserAPI.loginByToken();
await updateToken(resp); if (!result) {
return resp; return null;
}
const nextUser = result as unknown as T;
await updateLoginUser(nextUser);
return nextUser;
} catch (e) { } catch (e) {
await logout(); console.error(e);
clearLoginUser();
} }
return null; return null;
} }
async function login4Storage(): Promise<LoginResponse | null> { async function loginByStorage<T extends LoginUser = LoginUser>(): Promise<T | null> {
if (!loginUser.user && (loginUser.token || Storage.has("token"))) { if (loginUser.token) {
// 未登录,储存有令牌 isRestored.value = true;
const token = Storage.getJSON("token") as UserToken; return getLoginUser<T>();
if (new Date().getTime() < token.expireAt) {
return await login4Token(token);
}
} }
if (!Storage.has(_storageKey)) {
isRestored.value = true;
return null; return null;
} }
async function updateToken(loginResponse: LoginResponse): Promise<void> { // 未登录,储存有令牌。
loginUser.token = { const storageUser = Storage.getJSON(_storageKey) as T;
id: loginResponse.id, if (isValidLoginUser(storageUser)) {
value: loginResponse.token, const result = await loginByToken<T>(storageUser.token);
expireAt: loginResponse.expireAt isRestored.value = true;
}; return result;
loginUser.user = await UserAPI.view(loginResponse.id); }
Storage.setJSON("token", { clearLoginUser();
value: loginUser.token.value, isRestored.value = true;
expireAt: loginUser.token.expireAt return null;
} as UserToken); }
async function updateLoginUser<T extends LoginUser = LoginUser>(user: T): Promise<void> {
resetLoginUser(user as LoginUserState);
Storage.setJSON(_storageKey, user);
}
function clearLoginUser(): void {
resetLoginUser();
Cooker.remove("Token");
Storage.remove(_storageKey);
} }
async function logout(): Promise<void> { async function logout(): Promise<void> {
try {
await UserAPI.logout(); await UserAPI.logout();
} finally {
loginUser.token = undefined; clearLoginUser();
loginUser.user = undefined;
Storage.remove("token");
}
async function reloadProfile() {
if (loginUser.token && loginUser.token.id) {
loginUser.user = await UserAPI.view(loginUser.token.id);
} }
} }
const userStore = { return {
loginUser, token,
isLoggedIn,
isRestored,
getRoleList,
getPermissionList,
hasRoles,
hasPermissions,
isLogged, isLogged,
login4Token, loginUser: readonly(loginUser),
login4Storage, getLoginUser,
updateToken, login,
logout, loginByToken,
reloadProfile loginByStorage,
updateLoginUser,
clearLoginUser,
logout
}; };
});
export { export {
userStore useUserStore,
configureUserStore
}; };
+2 -2
View File
@@ -1,4 +1,4 @@
import type { AttachmentView } from "./Attachment"; import type { Attachment } from "./Attachment";
import type { Model } from "./Model"; import type { Model } from "./Model";
// 文章 // 文章
@@ -17,7 +17,7 @@ export type Article<E extends ArticleMusicExtendData | ArticleSoftwareExtendData
export type ArticleView<E extends ArticleMusicExtendData | ArticleSoftwareExtendData> = { export type ArticleView<E extends ArticleMusicExtendData | ArticleSoftwareExtendData> = {
comments?: number; comments?: number;
attachmentList: AttachmentView[]; attachmentList: Attachment[];
} & Article<E>; } & Article<E>;
export enum ArticleType { export enum ArticleType {
+29 -11
View File
@@ -2,23 +2,41 @@ import { Model } from "./Model";
export type Attachment = { export type Attachment = {
bizType: AttachmentBizType; bizType: AttachmentBizType;
bizId: number; bizId: string;
attachType?: string; attachType?: string;
mongoId: string; mongoId: string;
lidTitle?: number;
name?: string;
size: number;
} & Model
export type AttachmentView = {
title?: string; title?: string;
} & Attachment name?: string;
mimeType?: string;
metadata?: unknown;
size?: number;
md5?: string;
uploaderIp?: string;
isDestroyed?: boolean;
destroyAt?: number;
tempFileId?: string;
} & Model;
export type TempFileResp = {
id: string;
expireAt?: number;
};
export type BizUpdateReq = {
bizType: AttachmentBizType;
bizId: string;
items: Partial<Attachment>[];
};
export enum AttachmentBizType { export enum AttachmentBizType {
GIT_ISSUE, USER = "USER",
GIT_MERGE, GAO_CUSTOMER = "GAO_CUSTOMER",
GIT_RELEASE GAO_REGISTER_RECORD = "GAO_REGISTER_RECORD",
TEMP_FILE = "TEMP_FILE",
MIRROR = "MIRROR"
} }
+4 -4
View File
@@ -1,5 +1,5 @@
import { Model, Page } from "./Model"; import { Model, Page } from "./Model";
import { UserView } from "./User"; import { User } from "./User";
/** 评论 */ /** 评论 */
export type Comment = { export type Comment = {
@@ -10,7 +10,7 @@ export type Comment = {
content?: string; content?: string;
/** 所属用户 */ /** 所属用户 */
user?: UserView; user?: User;
/** 回复列表 */ /** 回复列表 */
replies?: CommentReply[]; replies?: CommentReply[];
@@ -41,8 +41,8 @@ export type CommentReply = {
content?: string; content?: string;
comment?: Comment; comment?: Comment;
sender?: UserView; sender?: User;
receiver?: UserView; receiver?: User;
} & Model; } & Model;
export enum CommentReplyBizType { export enum CommentReplyBizType {
+6 -19
View File
@@ -6,7 +6,7 @@ export enum RunEnv {
// 基本实体模型 // 基本实体模型
export type Model = { export type Model = {
id?: number; id?: string;
createdAt?: number; createdAt?: number;
updatedAt?: number; updatedAt?: number;
@@ -39,28 +39,15 @@ export type PageResult<T> = {
// 携带验证码的请求体 // 携带验证码的请求体
export type CaptchaData<T> = { export type CaptchaData<T> = {
from: string; captchaId: string;
captcha: string; captcha: string;
data: T; data: T;
} }
export enum CaptchaFrom { // 图形验证码
export type CaptchaResult = {
LOGIN = "LOGIN", id: string;
data: string;
REGISTER = "REGISTER",
/** 评论 */
COMMENT = "COMMENT",
/** 评论回复 */
COMMENT_REPLY = "COMMENT_REPLY",
/** Git 反馈 */
GIT_ISSUE = "GIT_ISSUE",
/** Git 合并请求 */
GIT_MERGE = "GIT_MERGE",
} }
export enum ImageType { export enum ImageType {
+17
View File
@@ -0,0 +1,17 @@
export type ModuleCode = "CORE" | "GAO";
export interface Permission {
id: string;
moduleCode: ModuleCode;
code: string;
nameLangId?: string;
name?: string;
description?: string;
createdAt?: number;
updatedAt?: number;
deletedAt?: number;
}
export type PermissionPayload = Pick<Permission, "moduleCode" | "code" | "nameLangId" | "name" | "description"> & {
id?: string;
};
+31
View File
@@ -0,0 +1,31 @@
import type { ModuleCode, Permission } from "./Permission";
export interface Role {
id: string;
moduleCode: ModuleCode;
code: string;
nameLangId?: string;
name?: string;
description?: string;
permissionList?: Permission[];
allPermissionList?: Permission[];
childRoleList?: Role[];
permissionIdList?: string[];
childRoleIdList?: string[];
createdAt?: number;
updatedAt?: number;
deletedAt?: number;
}
export type RolePayload = Pick<Role, "moduleCode" | "code" | "nameLangId" | "name" | "description"> & {
id?: string;
permissionIdList?: string[];
childRoleIdList?: string[];
};
export interface UserRoleAuthorizeReq {
userId: string;
moduleCode?: ModuleCode;
roleIdList?: string[];
roleCodeList?: string[];
}
+48 -47
View File
@@ -1,79 +1,80 @@
import { ImageType, Model } from "./Model"; import { ImageType, Model } from "./Model";
import { AttachmentView } from "./Attachment"; import { Attachment } from "./Attachment";
import type { Setting } from "./Setting";
export type User = { export type User = {
name: string; name: string;
nick?: string;
password?: string;
email?: string; email?: string;
emailVerifyAt: number; emailVerifyAt?: number;
unmuteAt?: number; phoneNo?: string;
unbanAt?: number; phoneNoVerifyAt?: number;
} & Model; wrapperType?: ImageType;
avatarType?: ImageType;
export type UserView = { exp?: number;
profile: UserProfileView
} & User;
export enum UserAttachType {
AVATAR,
WRAPPER,
DEFAULT_AVATAR,
DEFAULT_WRAPPER,
}
export type UserProfile = {
userId: number;
avatarType: ImageType;
wrapperType: ImageType;
exp: number;
sex?: number; sex?: number;
birthdate?: number; birthdate?: number;
qq?: string; qq?: string;
description: string; description?: string;
lastLoginIP?: string; lastLoginIP?: string;
lastLoginAt?: number; lastLoginAt?: number;
updatedAt?: number; unmuteAt?: number;
} unbanAt?: number;
roleList?: string[];
permissionList?: string[];
attachmentList?: Attachment[];
settingList?: Setting[];
tempFileIdList?: string[];
muting?: boolean;
banning?: boolean;
emailVerified?: boolean;
phoneNoVerified?: boolean;
} & Model;
export type UserProfileView = { export enum UserAttachType {
attachmentList?: AttachmentView[]
} & UserProfile
export type UserToken = { AVATAR = "AVATAR",
value: string;
expireAt: number; WRAPPER = "WRAPPER",
LICENSE = "LICENSE",
DEFAULT_AVATAR = "DEFAULT_AVATAR",
DEFAULT_WRAPPER = "DEFAULT_WRAPPER"
} }
export type RegisterRequest = { export type RegisterRequest = {
name: string; name: string;
password: string; password: string;
email?: string; email?: string;
} };
export type LoginRequest = { export type LoginRequest = {
user: string; user: string;
password: string; password: string;
} };
export type UpdatePasswordRequest = {
oldValue: string;
newValue: string;
};
// 登录返回 // 登录返回
export type LoginResponse = { export type LoginResponse = {
id: number; id: string;
token: string; token: string;
expireAt: number; expireAt: number;
} user?: User;
};
export type LoginUser = { export type LoginUser = {
token?: LoginToken; id?: string;
user?: UserView token?: string;
} expireAt?: number;
user?: User;
export type LoginToken = { };
id?: number;
} & UserToken;
export enum LoginType { export enum LoginType {
ALERT, ALERT,
+2
View File
@@ -5,6 +5,8 @@ export * from "./Article";
export * from "./Setting"; export * from "./Setting";
export * from "./Attachment"; export * from "./Attachment";
export * from "./Model"; export * from "./Model";
export * from "./Permission";
export * from "./Role";
export * from "./User"; export * from "./User";
export * from "./Template"; export * from "./Template";
export * from "./Comment"; export * from "./Comment";