diff --git a/.cspell.json b/.cspell.json new file mode 100644 index 0000000000..6e5c3664ec --- /dev/null +++ b/.cspell.json @@ -0,0 +1,10 @@ +{ + "version": "0.2", + "language": "en", + "words": [ + "githubusercontent", + "commitlint", + "EDITMSG", + "codespell" + ] +} \ No newline at end of file diff --git a/.github/hooks/todo-warning.sh b/.github/hooks/todo-warning.sh new file mode 100755 index 0000000000..fa3b7aab7a --- /dev/null +++ b/.github/hooks/todo-warning.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +ORANGE='\033[0;33m' +NC='\033[0m' +BOLD='\033[1m' +NORMAL='\033[0m' + + +echo $GIT_COMMIT + +check_file() { + local file=$1 + local match_pattern=$2 + + local file_changes_with_context=$(git diff -U999999999 -p --cached --color=always -- $file) + local matched_additions=$(echo "$file_changes_with_context" | grep -C4 $'^\e\\[32m\+.*'"$match_pattern") + + if [ -n "$matched_additions" ]; then + echo -e "${ORANGE}[WARNING]${NC} ${BOLD}$file${NORMAL} contains some $match_pattern." + echo "$matched_additions" + echo -e "\n" + fi +} + + +for file in `git diff --cached -p --name-status | cut -c3-`; do + check_file $file 'TODO' +done +exit \ No newline at end of file diff --git a/.github/workflows/validate-pr-title.yaml b/.github/workflows/validate-pr-title.yaml new file mode 100644 index 0000000000..1bba088bb1 --- /dev/null +++ b/.github/workflows/validate-pr-title.yaml @@ -0,0 +1,72 @@ +name: Validate PR Title +on: + pull_request: + types: [opened, edited, synchronize] +permissions: + pull-requests: write + contents: read +jobs: + lint: + name: 'Lint' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + - name: Install Commitlint and CSpell + run: npm install --save-dev @commitlint/{config-conventional,cli} cspell + - run: echo "${{ github.event.pull_request.title }}" > pr-title.txt + - name: Run Commitlint + id: commitlint + run: npx commitlint --edit pr-title.txt > commitlint_output.txt 2>&1 + if: always() + - name: Run CSpell + id: cspell + run: npx cspell --config .cspell.json pr-title.txt > cspell_output.txt 2>&1 + if: always() + - name: Delete Old Bot Comments + if: always() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # Fetch all comments on the PR + COMMENTS=$(gh api repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments --jq '.[] | select(.user.login == "github-actions[bot]") | .id') + + # Delete comments authored by the bot + for COMMENT_ID in $COMMENTS; do + gh api repos/${{ github.repository }}/issues/comments/$COMMENT_ID -X DELETE + done + - name: Post PR Comment + if: always() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # Initialize status messages + STATUS_COMMITLINT="PASSED" + STATUS_CSPELL="PASSED" + COMMITLINT_OUTPUT=$(cat commitlint_output.txt) + CSPELL_OUTPUT=$(cat cspell_output.txt) + COMMENT_BODY="### Found Issues In PR Title\n" + + if [ "${{ steps.commitlint.outcome }}" == "failure" ]; then + STATUS_COMMITLINT="FAILED" + fi + + if [ "${{ steps.cspell.outcome }}" == "failure" ]; then + STATUS_CSPELL="FAILED" + fi + + if [ "$STATUS_COMMITLINT" == "FAILED" ]; then + COMMENT_BODY+="**❌ Conventional Commit Format**\n" + COMMENT_BODY+="\n\`\`\`\n$COMMITLINT_OUTPUT\n\`\`\`\n" + fi + if [ "$STATUS_CSPELL" == "FAILED" ]; then + COMMENT_BODY+="**❌ Spelling Error**\n" + COMMENT_BODY+="\n\`\`\`\n$CSPELL_OUTPUT\n\`\`\`\n" + COMMENT_BODY+="\n> If you believe the spelling error is a false positive, please add the word in **cspell.json** file.\n" + fi + + if [ "$STATUS_COMMITLINT" == "FAILED" ] || [ "$STATUS_CSPELL" == "FAILED" ]; then + # Post the comment + echo -e "$COMMENT_BODY" | gh pr comment ${{ github.event.pull_request.number }} --body-file - + fi diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c30be2de52..30c315a294 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -32,10 +32,38 @@ repos: - id: check-toml - id: check-yaml - - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.6.5 hooks: - id: ruff args: [--fix] - - id: ruff-format \ No newline at end of file + - id: ruff-format + + - repo: local + hooks: + - id: commitlint + name: check commit message format + entry: npx commitlint --edit .git/COMMIT_EDITMSG + language: system + stages: [commit-msg] + always_run: true + + - id: cspell-commit-msg + name: check commit message spelling + entry: npx cspell --config .cspell.json .git/COMMIT_EDITMSG + language: system + stages: [commit-msg] + always_run: true + + - id: cspell-modified-files + name: check spelling of files + entry: sh -c "npx cspell --config .cspell.json `git diff --cached -p --name-status | cut -c3- | tr '\n' ' '`" + language: system + stages: [pre-commit] + + - id: todo-warning + name: check todos + entry: .github/hooks/todo-warning.sh + language: script + stages: [pre-commit] + verbose: true diff --git a/commitlint.config.js b/commitlint.config.js index 8847564e53..21be2907dd 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -1,25 +1,11 @@ module.exports = { - parserPreset: 'conventional-changelog-conventionalcommits', + extends: ['@commitlint/config-conventional'], rules: { - 'subject-empty': [2, 'never'], - 'type-case': [2, 'always', 'lower-case'], - 'type-empty': [2, 'never'], - 'type-enum': [ - 2, - 'always', - [ - 'build', - 'chore', - 'ci', - 'docs', - 'feat', - 'fix', - 'perf', - 'refactor', - 'revert', - 'style', - 'test', - ], - ], + 'header-max-length': [2, 'always', 72], + 'subject-case': [2, 'always', 'sentence-case'], + 'scope-case': [2, 'always', 'kebab-case'], + 'body-case': [2, 'always', 'sentence-case'], + 'body-leading-blank': [2, 'always'], + 'footer-leading-blank': [2, 'always'], }, }; diff --git a/dashboard/src2/components/NavigationItems.vue b/dashboard/src2/components/NavigationItems.vue index 03055b9b4a..8a88848b9b 100644 --- a/dashboard/src2/components/NavigationItems.vue +++ b/dashboard/src2/components/NavigationItems.vue @@ -14,6 +14,7 @@ import WalletCards from '~icons/lucide/wallet-cards'; import Settings from '~icons/lucide/settings'; import App from '~icons/lucide/layout-grid'; import DatabaseZap from '~icons/lucide/database-zap'; +import Activity from '~icons/lucide/activity'; import Logs from '~icons/lucide/scroll-text'; import Globe from '~icons/lucide/globe'; import Notification from '~icons/lucide/inbox'; @@ -129,9 +130,18 @@ export default { icon: () => h(Logs), route: '/log-browser', isActive: routeName === 'Log Browser' + }, + { + name: 'DB Analyzer', + icon: () => h(Activity), + route: '/database-analyzer', + isActive: routeName === 'DB Analyzer', + condition: this.$team.doc?.is_desk_user } - ], - isActive: ['SQL Playground', 'Log Browser'].includes(routeName), + ].filter(item => item.condition ?? true), + isActive: ['SQL Playground', 'DB Analyzer', 'Log Browser'].includes( + routeName + ), disabled: enforce2FA }, { diff --git a/dashboard/src2/components/ToggleContent.vue b/dashboard/src2/components/ToggleContent.vue new file mode 100644 index 0000000000..01a1e049fc --- /dev/null +++ b/dashboard/src2/components/ToggleContent.vue @@ -0,0 +1,51 @@ + + + diff --git a/dashboard/src2/components/devtools/database/DatabaseAddIndexButton.vue b/dashboard/src2/components/devtools/database/DatabaseAddIndexButton.vue new file mode 100644 index 0000000000..49ec1289cd --- /dev/null +++ b/dashboard/src2/components/devtools/database/DatabaseAddIndexButton.vue @@ -0,0 +1,76 @@ + + diff --git a/dashboard/src2/components/devtools/database/DatabasePerformanceSchemaDisabledNotice.vue b/dashboard/src2/components/devtools/database/DatabasePerformanceSchemaDisabledNotice.vue new file mode 100644 index 0000000000..7a85817e8f --- /dev/null +++ b/dashboard/src2/components/devtools/database/DatabasePerformanceSchemaDisabledNotice.vue @@ -0,0 +1,19 @@ + + diff --git a/dashboard/src2/components/devtools/database/DatabaseProcessKillButton.vue b/dashboard/src2/components/devtools/database/DatabaseProcessKillButton.vue new file mode 100644 index 0000000000..89a72ae51e --- /dev/null +++ b/dashboard/src2/components/devtools/database/DatabaseProcessKillButton.vue @@ -0,0 +1,55 @@ + + diff --git a/dashboard/src2/components/devtools/database/DatabaseTableSchemaDialog.vue b/dashboard/src2/components/devtools/database/DatabaseTableSchemaDialog.vue index 6e88a09148..5bd9143cd6 100644 --- a/dashboard/src2/components/devtools/database/DatabaseTableSchemaDialog.vue +++ b/dashboard/src2/components/devtools/database/DatabaseTableSchemaDialog.vue @@ -20,7 +20,10 @@ v-if="selectedSchema" /> -
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/dashboard/src2/components/site_database_user/SiteDatabaseUserCredentialDialog.vue b/dashboard/src2/components/site_database_user/SiteDatabaseUserCredentialDialog.vue index 27ef6ecc72..706554001f 100644 --- a/dashboard/src2/components/site_database_user/SiteDatabaseUserCredentialDialog.vue +++ b/dashboard/src2/components/site_database_user/SiteDatabaseUserCredentialDialog.vue @@ -43,7 +43,7 @@

- Using MariaDB Client + Using MariaDB CLI

Run this command in your terminal to access MariaDB console @@ -55,12 +55,43 @@ computer.

+
+

SSL Info

+

+ You need to use SSL to connect to the database. +

+ + +
+
+

Need Help?

+

+ Please check out the + documentation + to get guides on troubleshooting. +

+
diff --git a/dashboard/src2/pages/devtools/database/DatabaseSQLPlayground.vue b/dashboard/src2/pages/devtools/database/DatabaseSQLPlayground.vue index 7abd8543f8..db6dd68da2 100644 --- a/dashboard/src2/pages/devtools/database/DatabaseSQLPlayground.vue +++ b/dashboard/src2/pages/devtools/database/DatabaseSQLPlayground.vue @@ -63,6 +63,8 @@ v-model="query" v-if="sqlSchemaForAutocompletion" :schema="sqlSchemaForAutocompletion" + @codeSelected="handleCodeSelected" + @codeUnselected="handleCodeUnselected" />
@@ -73,13 +75,24 @@
- +
+ + +
@@ -143,7 +157,7 @@ import { toast } from 'vue-sonner'; import Header from '../../../components/Header.vue'; import { Tabs, Breadcrumbs } from 'frappe-ui'; -import SQLResultTable from '../../../components/devtools/database/SQLResultTable.vue'; +import SQLResultTable from '../../../components/devtools/database/ResultTable.vue'; import SQLCodeEditor from '../../../components/devtools/database/SQLCodeEditor.vue'; import { confirmDialog } from '../../../utils/components'; import DatabaseSQLPlaygroundLog from '../../../components/devtools/database/DatabaseSQLPlaygroundLog.vue'; @@ -170,6 +184,7 @@ export default { site: null, tabIndex: 0, query: '', + selectedQuery: null, commit: false, execution_successful: null, data: null, @@ -250,7 +265,7 @@ export default { for (const tableName in tableSchemas) { childrenSchemas[tableName] = { self: { label: tableName, type: 'table' }, - children: tableSchemas[tableName].map(x => ({ + children: tableSchemas[tableName].columns.map(x => ({ label: x.column, type: 'column', detail: x.data_type @@ -284,6 +299,12 @@ export default { } }, methods: { + handleCodeSelected(selectedCode) { + this.selectedQuery = selectedCode; + }, + handleCodeUnselected() { + this.selectedQuery = null; + }, fetchTableSchemas({ site_name = null, reload = false } = {}) { if (!site_name) site_name = this.site; if (!site_name) return; @@ -296,7 +317,7 @@ export default { } }); }, - runSQLQuery(ignore_validation = false) { + runSQLQuery(ignore_validation = false, run_selected_query = false) { if (!this.query) return; if (this.mode === 'read-only' || ignore_validation) { this.$resources.runSQLQuery.submit({ @@ -304,7 +325,7 @@ export default { dn: this.site, method: 'run_sql_query_in_database', args: { - query: this.query, + query: run_selected_query ? this.selectedQuery : this.query, commit: this.mode === 'read-write' } }); @@ -321,7 +342,28 @@ Are you sure you want to run the query?`, label: 'Run Query', variant: 'solid', onClick: ({ hide }) => { - this.runSQLQuery(true); + this.runSQLQuery(true, run_selected_query); + hide(); + } + } + }); + }, + runSelectedSQLQuery() { + if (!this.selectedQuery) { + return; + } + confirmDialog({ + title: 'Verify Query', + message: ` +Are you sure you want to run the query? +
+
${this.selectedQuery}
+ `, + primaryAction: { + label: 'Run Query', + variant: 'solid', + onClick: ({ hide }) => { + this.runSQLQuery(false, true); hide(); } } diff --git a/dashboard/src2/router.js b/dashboard/src2/router.js index 3113d083bd..19afb7b733 100644 --- a/dashboard/src2/router.js +++ b/dashboard/src2/router.js @@ -291,6 +291,11 @@ let router = createRouter({ component: () => import('./pages/devtools/database/DatabaseSQLPlayground.vue') }, + { + path: '/database-analyzer', + name: 'DB Analyzer', + component: () => import('./pages/devtools/database/DatabaseAnalyzer.vue') + }, { path: '/log-browser/:mode?/:docName?/:logId?', name: 'Log Browser', diff --git a/package.json b/package.json index 6b0c346679..969e90b6e2 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,10 @@ "@tailwindcss/typography": "^0.5.1", "autoprefixer": "^10.4.2", "postcss": "^8.4.6", - "tailwindcss": "^3.2" + "tailwindcss": "^3.2", + "@commitlint/config-conventional": "^19.6.0", + "commitlint": "^19.6.1", + "cspell": "^8.17.1" }, "dependencies": { "dayjs": "^1.11.10", diff --git a/press/agent.py b/press/agent.py index 34ea88f61f..b102b736cf 100644 --- a/press/agent.py +++ b/press/agent.py @@ -1161,13 +1161,18 @@ def get_site_apps(self, site): apps: list[str] = [line.split()[0] for line in raw_apps_list["data"].splitlines() if line] return apps - def fetch_database_table_schema(self, site): + def fetch_database_table_schema( + self, site, include_table_size: bool = False, include_index_info: bool = False + ): return self.create_agent_job( "Fetch Database Table Schema", f"benches/{site.bench}/sites/{site.name}/database/schema", bench=site.bench, site=site.name, - data={}, + data={ + "include_table_size": include_table_size, + "include_index_info": include_index_info, + }, reference_doctype="Site", reference_name=site.name, ) @@ -1178,6 +1183,48 @@ def run_sql_query_in_database(self, site, query, commit): data={"query": query, "commit": commit, "as_dict": False}, ) + def get_summarized_performance_report_of_database(self, site): + return self.post( + f"benches/{site.bench}/sites/{site.name}/database/performance-report", + data={"mariadb_root_password": get_mariadb_root_password(site)}, + ) + + def analyze_slow_queries(self, site, normalized_queries: list[dict]): + """ + normalized_queries format: + [ + { + "example": "", + "normalized" : "", + } + ] + """ + return self.create_agent_job( + "Analyze Slow Queries", + f"benches/{site.bench}/sites/{site.name}/database/analyze-slow-queries", + data={ + "queries": normalized_queries, + "mariadb_root_password": get_mariadb_root_password(site), + }, + site=site.name, + ) + + def fetch_database_processes(self, site): + return self.post( + f"benches/{site.bench}/sites/{site.name}/database/processes", + data={ + "mariadb_root_password": get_mariadb_root_password(site), + }, + ) + + def kill_database_process(self, site, id): + return self.post( + f"benches/{site.bench}/sites/{site.name}/database/kill-process/{id}", + data={ + "mariadb_root_password": get_mariadb_root_password(site), + }, + ) + class AgentCallbackException(Exception): pass diff --git a/press/api/__init__.py b/press/api/__init__.py index 1a47323294..ad1fcc1c79 100644 --- a/press/api/__init__.py +++ b/press/api/__init__.py @@ -1,9 +1,10 @@ import frappe -from press.utils import get_minified_script, get_minified_script_2 +from press.api.client import dashboard_whitelist from press.saas.doctype.product_trial_request.product_trial_request import ( get_app_trial_page_url, ) +from press.utils import get_full_chain_cert_of_domain, get_minified_script, get_minified_script_2, log_error @frappe.whitelist(allow_guest=True) @@ -20,3 +21,18 @@ def script_2(): def handle_suspended_site_redirection(): frappe.local.response["type"] = "redirect" frappe.local.response["location"] = get_app_trial_page_url() or "/dashboard" + + +@dashboard_whitelist() +def download_ssl_cert(domain: str): + if ( + not (domain.endswith("frappe.cloud") or domain.endswith("frappecloud.com")) + and not frappe.conf.developer_mode + ): + frappe.throw("Invalid domain provided") + + try: + return get_full_chain_cert_of_domain(domain) + except Exception as e: + log_error("Error downloading SSL certificate", data=e) + frappe.throw("Failed to download SSL certificate. Please try again later.") diff --git a/press/api/analytics.py b/press/api/analytics.py index a00d11ecad..63e491f16a 100644 --- a/press/api/analytics.py +++ b/press/api/analytics.py @@ -24,9 +24,6 @@ from press.agent import Agent from press.api.site import protected from press.press.doctype.site_plan.site_plan import get_plan_config -from press.press.report.binary_log_browser.binary_log_browser import ( - convert_user_timezone_to_utc, -) from press.press.report.binary_log_browser.binary_log_browser import ( get_data as get_binary_log_data, ) @@ -654,7 +651,7 @@ def get_current_cpu_usage_for_sites_on_server(server): metric = row["usage"]["counter"]["top"] if metric: result[site] = metric[0]["metrics"]["json.request.counter"] - return result + return result @frappe.whitelist() @@ -767,28 +764,19 @@ def mariadb_slow_queries( @frappe.whitelist() @protected("Site") -def deadlock_report(site, start, end, max_lines=20): - from press.press.report.mariadb_deadlock_browser.mariadb_deadlock_browser import ( - post_process, - ) - - server = frappe.db.get_value("Site", site, "server") - db_server_name = frappe.db.get_value("Server", server, "database_server") - database_server = frappe.get_doc("Database Server", db_server_name) - agent = Agent(database_server.name, "Database Server") - - data = { - "private_ip": database_server.private_ip, - "mariadb_root_password": database_server.get_password("mariadb_root_password"), - "database": database_server.name, - "start_datetime": convert_user_timezone_to_utc(start), - "stop_datetime": convert_user_timezone_to_utc(end), - "max_lines": max_lines, - } - - results = agent.post("database/deadlocks", data=data) +def deadlock_report(name, start_datetime, stop_datetime, max_log_size=500): + from press.press.report.mariadb_deadlock_browser.mariadb_deadlock_browser import execute - return post_process(results) + meta = frappe._dict( + { + "site": name, + "start_datetime": start_datetime, + "stop_datetime": stop_datetime, + "max_log_size": max_log_size, + } + ) + _, data = execute(filters=meta) + return data # MARKETPLACE - Plausible diff --git a/press/api/dboptimize.py b/press/api/dboptimize.py deleted file mode 100644 index 37209e0408..0000000000 --- a/press/api/dboptimize.py +++ /dev/null @@ -1,176 +0,0 @@ -import json - -import frappe - -from press.api.site import protected -from press.press.report.mariadb_slow_queries.db_optimizer import ( - ColumnStat, - DBExplain, - DBOptimizer, - DBTable, -) -from press.press.report.mariadb_slow_queries.mariadb_slow_queries import ( - OptimizeDatabaseQuery, - _fetch_column_stats, - _fetch_table_stats, -) -from press.utils import log_error - - -@frappe.whitelist() -@protected("Site") -def mariadb_analyze_query(name, row): - return analyze_query(row=row, site=name) - - -def analyze_query(row, site): - # if mariadb_analyze_query_already_exists(site, row["query"]): - # frappe.throw("The query seems to have already been optimized") - doc = frappe.get_doc( - { - "doctype": "MariaDB Analyze Query", - "site": site, - "tables_in_query": [], - } - ) - doc.status = "Running" - - query = row["example"] - doc.query = query - doc.normalized_query = row["query"] - - if not query.lower().startswith(("select", "update", "delete")): - doc.status = "Failure" - doc.save(ignore_permissions=True) - frappe.db.commit() - return None - - doc.save(ignore_permissions=True) - frappe.db.commit() - - analyzer = OptimizeDatabaseQuery(site, query) - explain_output = analyzer.fetch_explain() or [] - doc.explain_output = json.dumps(explain_output) - explain_output = [DBExplain.from_frappe_ouput(e) for e in explain_output] - - optimizer = DBOptimizer(query=analyzer.query, explain_plan=explain_output) - for table in optimizer.tables_examined: - stats = _fetch_table_stats(analyzer.site, table) - doc.append("tables_in_query", {"table": table, "table_statistics": json.dumps(stats)}) - - if not stats: - # Old framework version - doc.status = "Failure" - doc.save(ignore_permissions=True) - frappe.db.commit() - return None - - # This is an agent job. Remaining is processed in the callback. - _fetch_column_stats(analyzer.site, table, doc.get_title()) - - doc.save(ignore_permissions=True) - return doc.status - - -def check_if_all_fetch_column_stats_was_successful(doc): - return all(item.status == "Success" for item in doc.tables_in_query) - - -def fetch_column_stats_update(job, response_data): - request_data_json = json.loads(job.request_data) - doc_name = request_data_json["doc_name"] - table = request_data_json["table"] - - if job.status == "Success": - column_statistics = response_data["steps"][0]["data"]["output"] - doc = frappe.get_doc("MariaDB Analyze Query", doc_name) - for item in doc.tables_in_query: - if item.table == table: - item.column_statistics = column_statistics - item.status = "Success" - doc.save() - frappe.db.commit() - if check_if_all_fetch_column_stats_was_successful(doc): - doc.status = "Success" - doc.save() - frappe.db.commit() - # Persists within doctype - save_suggested_index(doc) - elif job.status == "Failure": - doc = frappe.get_doc("MariaDB Analyze Query", doc_name) - for item in doc.tables_in_query: - if item.table == table: - item.status = "Failure" - doc.save() - - doc.status = "Failure" - doc.save() - frappe.db.commit() - - -def save_suggested_index(doc): - explain_output = json.loads(doc.explain_output) - explain_output = [DBExplain.from_frappe_ouput(e) for e in explain_output] - optimizer = DBOptimizer(query=doc.query, explain_plan=explain_output) - for item in doc.tables_in_query: - stats = json.loads(item.table_statistics) - if not stats: - # Old framework version - return - db_table = DBTable.from_frappe_ouput(stats) - column_stats = json.loads(item.column_statistics) - column_stats = [ColumnStat.from_frappe_ouput(c) for c in column_stats] - db_table.update_cardinality(column_stats) - optimizer.update_table_data(db_table) - index = optimizer.suggest_index() - doc.suggested_index = f"{index.table}.{index.column}" - doc.save() - - -@frappe.whitelist() -@protected("Site") -def get_status_of_mariadb_analyze_query(name, query): - filters = {"site": name, "query": query} - doc = frappe.get_all( - "MariaDB Analyze Query", - filters=filters, - fields=["status", "suggested_index"], - limit=1, - ) - if doc: - return doc[0] - return None - - -def mariadb_analyze_query_already_exists(site, normalized_query): - if frappe.db.exists("MariaDB Analyze Query", {"site": site, "normalized_query": normalized_query}): - return True - return False - - -@frappe.whitelist() -@protected("Site") -def mariadb_analyze_query_already_running_for_site(name): - if frappe.db.exists("MariaDB Analyze Query", {"site": name, "status": "Running"}): - return True - return False - - -@frappe.whitelist() -@protected("Site") -def get_suggested_index(name, normalized_query): - return frappe.get_value( - "MariaDB Analyze Query", - {"site": name, "status": "Success", "normalized_query": normalized_query}, - ["site", "normalized_query", "suggested_index"], - as_dict=True, - ) - - -def delete_all_occurences_of_mariadb_analyze_query(job): - try: - if job.status == "Success" or job.status == "Failure": - frappe.db.delete("MariaDB Analyze Query", {"site": job.site}) - frappe.db.commit() - except Exception as e: - log_error("Deleting all occurrences of MariaDB Analyze Query Failed", data=e) diff --git a/press/api/server.py b/press/api/server.py index df37dbd7ab..e36746ef47 100644 --- a/press/api/server.py +++ b/press/api/server.py @@ -300,6 +300,42 @@ def analytics(name, query, timezone, duration): f"""node_memory_MemTotal_bytes{{instance="{name}",job="node"}} - node_memory_MemFree_bytes{{instance="{name}",job="node"}} - (node_memory_Cached_bytes{{instance="{name}",job="node"}} + node_memory_Buffers_bytes{{instance="{name}",job="node"}})""", lambda x: "Used", ), + "database_uptime": ( + f"""mysql_up{{instance="{name}",job="mariadb"}}""", + lambda x: "Uptime", + ), + "database_commands_count": ( + f"""sum(round(increase(mysql_global_status_commands_total{{instance='{name}', command=~"select|update|insert|delete|begin|commit|rollback"}}[{timegrain}s]))) by (command)""", + lambda x: x["command"], + ), + "database_connections": ( + f"""{{__name__=~"mysql_global_status_threads_connected|mysql_global_variables_max_connections", instance="{name}"}}""", + lambda x: "Max Connections" + if x["__name__"] == "mysql_global_variables_max_connections" + else "Connected Clients", + ), + "innodb_bp_size": ( + f"""mysql_global_variables_innodb_buffer_pool_size{{instance='{name}'}}""", + lambda x: "Buffer Pool Size", + ), + "innodb_bp_size_of_total_ram": ( + f"""avg by (instance) ((mysql_global_variables_innodb_buffer_pool_size{{instance=~"{name}"}} * 100)) / on (instance) (avg by (instance) (node_memory_MemTotal_bytes{{instance=~"{name}"}}))""", + lambda x: "Buffer Pool Size of Total Ram", + ), + "innodb_bp_miss_percent": ( + f""" +avg by (instance) ( + rate(mysql_global_status_innodb_buffer_pool_reads{{instance=~"{name}"}}[{timegrain}s]) + / + rate(mysql_global_status_innodb_buffer_pool_read_requests{{instance=~"{name}"}}[{timegrain}s]) +) +""", + lambda x: "Buffer Pool Miss Percentage", + ), + "innodb_avg_row_lock_time": ( + f"""(rate(mysql_global_status_innodb_row_lock_time{{instance="{name}"}}[{timegrain}s]) / 1000)/rate(mysql_global_status_innodb_row_lock_waits{{instance="{name}"}}[{timegrain}s])""", + lambda x: "Avg Row Lock Time", + ), } return prometheus_query(query_map[query][0], query_map[query][1], timezone, timespan, timegrain) diff --git a/press/fixtures/agent_job_type.json b/press/fixtures/agent_job_type.json index b6b044d9e4..a4b52ccdaa 100644 --- a/press/fixtures/agent_job_type.json +++ b/press/fixtures/agent_job_type.json @@ -2260,5 +2260,35 @@ "step_name": "Modify Database User Permissions" } ] + }, + { + "disabled_auto_retry": 1, + "docstatus": 0, + "doctype": "Agent Job Type", + "max_retry_count": 1, + "modified": "2024-10-28 14:49:19.894247", + "name": "Fetch Database Table Schema", + "request_method": "POST", + "request_path": "/benches/{bench}/sites/{site}/database/schema", + "steps": [ + { + "step_name": "Fetch Database Table Schema" + } + ] + }, + { + "disabled_auto_retry": 1, + "docstatus": 0, + "doctype": "Agent Job Type", + "max_retry_count": 3, + "modified": "2024-12-19 17:21:14.136650", + "name": "Analyze Slow Queries", + "request_method": "POST", + "request_path": "/benches/{bench}/sites/{site}/database/analyze-slow-queries", + "steps": [ + { + "step_name": "Analyze Slow Queries" + } + ] } ] \ No newline at end of file diff --git a/press/press/doctype/account_request/account_request.py b/press/press/doctype/account_request/account_request.py index 3cf9287121..f907bca7a5 100644 --- a/press/press/doctype/account_request/account_request.py +++ b/press/press/doctype/account_request/account_request.py @@ -10,7 +10,7 @@ from frappe.model.document import Document from frappe.utils import get_url, random_string -from press.utils import get_country_info +from press.utils import get_country_info, is_valid_email_address from press.utils.telemetry import capture @@ -63,6 +63,17 @@ class AccountRequest(Document): # end: auto-generated types def before_insert(self): + # This pre-verification is only beneficial for SaaS signup + # because, in general flow we already have e-mail link/otp based verification + if ( + not frappe.conf.developer_mode + and frappe.db.get_single_value("Press Settings", "enable_email_pre_verification") + and self.saas + and not self.oauth_signup + and not is_valid_email_address(self.email) + ): + frappe.throw(f"{self.email} is not a valid email address") + if not self.team: self.team = self.email diff --git a/press/press/doctype/agent_job/agent_job.py b/press/press/doctype/agent_job/agent_job.py index 69ab83a916..f0c7589f62 100644 --- a/press/press/doctype/agent_job/agent_job.py +++ b/press/press/doctype/agent_job/agent_job.py @@ -879,10 +879,6 @@ def process_job_updates(job_name: str, response_data: dict | None = None): # no start = now_datetime() try: - from press.api.dboptimize import ( - delete_all_occurences_of_mariadb_analyze_query, - fetch_column_stats_update, - ) from press.press.doctype.agent_job.agent_job_notifications import ( send_job_failure_notification, ) @@ -912,6 +908,7 @@ def process_job_updates(job_name: str, response_data: dict | None = None): # no process_archive_site_job_update, process_complete_setup_wizard_job_update, process_create_user_job_update, + process_fetch_database_table_schema_job_update, process_install_app_site_job_update, process_migrate_site_job_update, process_move_site_to_bench_job_update, @@ -923,9 +920,6 @@ def process_job_updates(job_name: str, response_data: dict | None = None): # no process_uninstall_app_site_job_update, ) from press.press.doctype.site_backup.site_backup import process_backup_site_job_update - from press.press.doctype.site_database_table_schema.site_database_table_schema import ( - SiteDatabaseTableSchema, - ) from press.press.doctype.site_domain.site_domain import process_new_host_job_update from press.press.doctype.site_update.site_update import ( process_update_site_job_update, @@ -1001,23 +995,8 @@ def process_job_updates(job_name: str, response_data: dict | None = None): # no AppPatch.process_patch_app(job) elif job.job_type == "Run Remote Builder": DeployCandidate.process_run_build(job, response_data) - elif job.job_type == "Column Statistics": - frappe.enqueue( - fetch_column_stats_update, - queue="default", - timeout=None, - is_async=True, - now=False, - job_name="Fetch Column Updates Through Enque", - enqueue_after_commit=False, - at_front=False, - job=job, - response_data=response_data, - ) elif job.job_type == "Create User": process_create_user_job_update(job) - elif job.job_type == "Add Database Index": - delete_all_occurences_of_mariadb_analyze_query(job) elif job.job_type == "Complete Setup Wizard": process_complete_setup_wizard_job_update(job) elif job.job_type == "Update Bench In Place": @@ -1025,7 +1004,7 @@ def process_job_updates(job_name: str, response_data: dict | None = None): # no elif job.job_type == "Recover Update In Place": Bench.process_recover_update_inplace(job) elif job.job_type == "Fetch Database Table Schema": - SiteDatabaseTableSchema.process_job_update(job) + process_fetch_database_table_schema_job_update(job) elif job.job_type in [ "Create Database User", "Remove Database User", diff --git a/press/press/doctype/bench/bench.py b/press/press/doctype/bench/bench.py index 29bd5b4bf2..b3ee8b2cdc 100644 --- a/press/press/doctype/bench/bench.py +++ b/press/press/doctype/bench/bench.py @@ -598,6 +598,14 @@ def allocate_workers( round(self.workload / server_workload * max_gunicorn_workers), ), # min 2 max 36 ) + if self.gunicorn_threads_per_worker: + # Allocate fewer workers if threaded workers are used + # Roughly workers / threads_per_worker = total number of workers + # 1. At least one worker + # 2. Slightly more workers than required + self.gunicorn_workers = frappe.utils.ceil( + self.gunicorn_workers / self.gunicorn_threads_per_worker + ) self.background_workers = min( max_bg or MAX_BACKGROUND_WORKERS, max( diff --git a/press/press/doctype/invoice/invoice.py b/press/press/doctype/invoice/invoice.py index 3c4c0d5d6c..143c29c97c 100644 --- a/press/press/doctype/invoice/invoice.py +++ b/press/press/doctype/invoice/invoice.py @@ -506,11 +506,23 @@ def validate_dates(self): def update_item_descriptions(self): for item in self.items: - if not item.description and item.document_type == "Site" and item.plan: - site_name = item.document_name.split(".archived")[0] - plan = frappe.get_cached_value("Site Plan", item.plan, "plan_title") + if not item.description: how_many_days = f"{cint(item.quantity)} day{'s' if item.quantity > 1 else ''}" - item.description = f"{site_name} active for {how_many_days} on {plan} plan" + if item.document_type == "Site" and item.plan: + site_name = item.document_name.split(".archived")[0] + plan = frappe.get_cached_value("Site Plan", item.plan, "plan_title") + item.description = f"{site_name} active for {how_many_days} on {plan} plan" + elif item.document_type in ["Server", "Database Server"]: + server_title = frappe.get_cached_value(item.document_type, item.document_name, "title") + if item.plan == "Add-on Storage plan": + item.description = f"{server_title} Storage Add-on for {how_many_days}" + else: + item.description = f"{server_title} active for {how_many_days}" + elif item.document_type == "Marketplace App": + app_title = frappe.get_cached_value("Marketplace App", item.document_name, "title") + item.description = f"Marketplace app {app_title} active for {how_many_days}" + else: + item.description = "Prepaid Credits" def add_usage_record(self, usage_record): if self.type != "Subscription": diff --git a/press/press/doctype/mariadb_analyze_query/__init__.py b/press/press/doctype/mariadb_analyze_query/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/press/press/doctype/mariadb_analyze_query/mariadb_analyze_query.js b/press/press/doctype/mariadb_analyze_query/mariadb_analyze_query.js deleted file mode 100644 index f6228a4cd9..0000000000 --- a/press/press/doctype/mariadb_analyze_query/mariadb_analyze_query.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2024, Frappe and contributors -// For license information, please see license.txt - -// frappe.ui.form.on("MariaDB Analyze Query", { -// refresh(frm) { - -// }, -// }); diff --git a/press/press/doctype/mariadb_analyze_query/mariadb_analyze_query.json b/press/press/doctype/mariadb_analyze_query/mariadb_analyze_query.json deleted file mode 100644 index 17e02dffe0..0000000000 --- a/press/press/doctype/mariadb_analyze_query/mariadb_analyze_query.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "actions": [], - "allow_rename": 1, - "creation": "2024-07-21 16:44:56.074012", - "doctype": "DocType", - "engine": "InnoDB", - "field_order": [ - "site", - "normalized_query", - "column_break_holt", - "query", - "status", - "section_break_cdwy", - "explain_output", - "tables_in_query", - "suggested_index" - ], - "fields": [ - { - "fieldname": "query", - "fieldtype": "Long Text", - "label": "Query", - "reqd": 1 - }, - { - "fieldname": "site", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Site", - "reqd": 1 - }, - { - "fieldname": "tables_in_query", - "fieldtype": "Table", - "label": "Tables In Query", - "options": "MariaDB Analyze Query Tables" - }, - { - "fieldname": "suggested_index", - "fieldtype": "Data", - "label": "Suggested Index" - }, - { - "fieldname": "explain_output", - "fieldtype": "Code", - "label": "Explain Output" - }, - { - "fieldname": "status", - "fieldtype": "Data", - "label": "Status" - }, - { - "fieldname": "column_break_holt", - "fieldtype": "Column Break" - }, - { - "fieldname": "normalized_query", - "fieldtype": "Long Text", - "label": "Normalized Query", - "reqd": 1 - }, - { - "fieldname": "section_break_cdwy", - "fieldtype": "Section Break" - } - ], - "index_web_pages_for_search": 1, - "links": [], - "modified": "2024-07-29 17:32:21.578471", - "modified_by": "Administrator", - "module": "Press", - "name": "MariaDB Analyze Query", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "sort_field": "creation", - "sort_order": "DESC", - "states": [] -} \ No newline at end of file diff --git a/press/press/doctype/mariadb_analyze_query/mariadb_analyze_query.py b/press/press/doctype/mariadb_analyze_query/mariadb_analyze_query.py deleted file mode 100644 index cb963a42af..0000000000 --- a/press/press/doctype/mariadb_analyze_query/mariadb_analyze_query.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2024, Frappe and contributors -# For license information, please see license.txt - -# import frappe -from frappe.model.document import Document - - -class MariaDBAnalyzeQuery(Document): - # begin: auto-generated types - # This code is auto-generated. Do not modify anything in this block. - - from typing import TYPE_CHECKING - - if TYPE_CHECKING: - from frappe.types import DF - from press.press.doctype.mariadb_analyze_query_tables.mariadb_analyze_query_tables import ( - MariaDBAnalyzeQueryTables, - ) - - explain_output: DF.Code | None - normalized_query: DF.LongText - query: DF.LongText - site: DF.Data - status: DF.Data | None - suggested_index: DF.Data | None - tables_in_query: DF.Table[MariaDBAnalyzeQueryTables] - # end: auto-generated types - - pass diff --git a/press/press/doctype/mariadb_analyze_query/test_mariadb_analyze_query.py b/press/press/doctype/mariadb_analyze_query/test_mariadb_analyze_query.py deleted file mode 100644 index 082e41b5b7..0000000000 --- a/press/press/doctype/mariadb_analyze_query/test_mariadb_analyze_query.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2024, Frappe and Contributors -# See license.txt - -# import frappe -from frappe.tests.utils import FrappeTestCase - - -class TestMariaDBAnalyzeQuery(FrappeTestCase): - pass diff --git a/press/press/doctype/mariadb_analyze_query_tables/__init__.py b/press/press/doctype/mariadb_analyze_query_tables/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/press/press/doctype/mariadb_analyze_query_tables/mariadb_analyze_query_tables.json b/press/press/doctype/mariadb_analyze_query_tables/mariadb_analyze_query_tables.json deleted file mode 100644 index dc8bb19960..0000000000 --- a/press/press/doctype/mariadb_analyze_query_tables/mariadb_analyze_query_tables.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "actions": [], - "allow_rename": 1, - "creation": "2024-07-21 16:49:47.144539", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "table", - "table_statistics", - "column_statistics", - "status" - ], - "fields": [ - { - "fieldname": "table", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Table" - }, - { - "fieldname": "column_statistics", - "fieldtype": "Code", - "in_list_view": 1, - "label": "Column Statistics" - }, - { - "fieldname": "table_statistics", - "fieldtype": "Code", - "in_list_view": 1, - "label": "Table Statistics" - }, - { - "fieldname": "status", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Status" - } - ], - "index_web_pages_for_search": 1, - "istable": 1, - "links": [], - "modified": "2024-07-24 11:46:38.741427", - "modified_by": "Administrator", - "module": "Press", - "name": "MariaDB Analyze Query Tables", - "owner": "Administrator", - "permissions": [], - "sort_field": "creation", - "sort_order": "DESC", - "states": [] -} \ No newline at end of file diff --git a/press/press/doctype/mariadb_analyze_query_tables/mariadb_analyze_query_tables.py b/press/press/doctype/mariadb_analyze_query_tables/mariadb_analyze_query_tables.py deleted file mode 100644 index c0a058d29d..0000000000 --- a/press/press/doctype/mariadb_analyze_query_tables/mariadb_analyze_query_tables.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2024, Frappe and contributors -# For license information, please see license.txt - -# import frappe -from frappe.model.document import Document - - -class MariaDBAnalyzeQueryTables(Document): - # begin: auto-generated types - # This code is auto-generated. Do not modify anything in this block. - - from typing import TYPE_CHECKING - - if TYPE_CHECKING: - from frappe.types import DF - - column_statistics: DF.Code | None - parent: DF.Data - parentfield: DF.Data - parenttype: DF.Data - status: DF.Data | None - table: DF.Data | None - table_statistics: DF.Code | None - # end: auto-generated types - - pass diff --git a/press/press/doctype/press_settings/press_settings.json b/press/press/doctype/press_settings/press_settings.json index 71c8c7e90a..56f2644310 100644 --- a/press/press/doctype/press_settings/press_settings.json +++ b/press/press/doctype/press_settings/press_settings.json @@ -193,6 +193,7 @@ "column_break_rdlr", "disable_auto_retry", "disable_agent_job_deduplication", + "enable_email_pre_verification", "section_break_jstu", "enable_app_grouping", "default_apps", @@ -1249,8 +1250,8 @@ "fieldtype": "Link", "label": "Press Trial Plan", "options": "Site Plan" - }, - { + }, + { "fieldname": "section_break_jstu", "fieldtype": "Section Break" }, @@ -1265,11 +1266,17 @@ "fieldtype": "Table", "label": "Default Apps", "options": "App Group" + }, + { + "default": "0", + "fieldname": "enable_email_pre_verification", + "fieldtype": "Check", + "label": "Enable Email Pre-Verification" } ], "issingle": 1, "links": [], - "modified": "2024-10-14 21:02:12.948747", + "modified": "2024-12-10 15:07:57.494659", "modified_by": "Administrator", "module": "Press", "name": "Press Settings", diff --git a/press/press/doctype/press_settings/press_settings.py b/press/press/doctype/press_settings/press_settings.py index cedb08f91c..bc4c1a559b 100644 --- a/press/press/doctype/press_settings/press_settings.py +++ b/press/press/doctype/press_settings/press_settings.py @@ -64,6 +64,7 @@ class PressSettings(Document): domain: DF.Link | None eff_registration_email: DF.Data enable_app_grouping: DF.Check + enable_email_pre_verification: DF.Check enable_google_oauth: DF.Check enable_site_pooling: DF.Check enforce_storage_limits: DF.Check diff --git a/press/press/doctype/proxy_server/proxy_server.json b/press/press/doctype/proxy_server/proxy_server.json index 6b1b73e31d..cb7a053fd9 100644 --- a/press/press/doctype/proxy_server/proxy_server.json +++ b/press/press/doctype/proxy_server/proxy_server.json @@ -18,6 +18,9 @@ "is_self_hosted", "team", "public", + "storage_section", + "auto_add_storage_min", + "auto_add_storage_max", "section_break_8", "ip", "enabled_default_routing", @@ -397,10 +400,31 @@ "fieldname": "public", "fieldtype": "Check", "label": "Public" + }, + { + "fieldname": "storage_section", + "fieldtype": "Section Break", + "label": "Storage" + }, + { + "default": "10", + "description": "Minimum storage to add automatically each time", + "fieldname": "auto_add_storage_min", + "fieldtype": "Int", + "label": "Auto Add Storage Min", + "non_negative": 1 + }, + { + "default": "50", + "description": "Maximum storage to add automatically each time", + "fieldname": "auto_add_storage_max", + "fieldtype": "Int", + "label": "Auto Add Storage Max", + "non_negative": 1 } ], "links": [], - "modified": "2024-09-10 15:44:10.989216", + "modified": "2024-12-26 13:20:05.120010", "modified_by": "Administrator", "module": "Press", "name": "Proxy Server", diff --git a/press/press/doctype/proxy_server/proxy_server.py b/press/press/doctype/proxy_server/proxy_server.py index f2d77c5f81..6a517662da 100644 --- a/press/press/doctype/proxy_server/proxy_server.py +++ b/press/press/doctype/proxy_server/proxy_server.py @@ -1,7 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe and contributors # For license information, please see license.txt - +from __future__ import annotations from typing import TYPE_CHECKING @@ -9,13 +8,13 @@ from frappe.utils import unique from press.agent import Agent -from press.press.doctype.root_domain.root_domain import RootDomain from press.press.doctype.server.server import BaseServer from press.runner import Ansible from press.utils import log_error if TYPE_CHECKING: from press.press.doctype.bench.bench import Bench + from press.press.doctype.root_domain.root_domain import RootDomain class ProxyServer(BaseServer): @@ -26,11 +25,12 @@ class ProxyServer(BaseServer): if TYPE_CHECKING: from frappe.types import DF - from press.press.doctype.proxy_server_domain.proxy_server_domain import ( - ProxyServerDomain, - ) + + from press.press.doctype.proxy_server_domain.proxy_server_domain import ProxyServerDomain agent_password: DF.Password | None + auto_add_storage_max: DF.Int + auto_add_storage_min: DF.Int cluster: DF.Link | None disable_agent_job_auto_retry: DF.Check domain: DF.Link | None @@ -83,7 +83,7 @@ def validate_domains(self): code_servers = [row.code_server for row in self.domains] # Always include self.domain in the domains child table # Remove duplicates - domains = unique([self.domain] + domains) + domains = unique([self.domain, *domains]) self.domains = [] for i, domain in enumerate(domains): if not frappe.db.exists( @@ -133,23 +133,17 @@ def _setup_server(self): "TLS Certificate", {"wildcard": True, "domain": self.domain}, "name" ) certificate = frappe.get_doc("TLS Certificate", certificate_name) - monitoring_password = frappe.get_doc("Cluster", self.cluster).get_password( - "monitoring_password" - ) + monitoring_password = frappe.get_doc("Cluster", self.cluster).get_password("monitoring_password") log_server = frappe.db.get_single_value("Press Settings", "log_server") if log_server: - kibana_password = frappe.get_doc("Log Server", log_server).get_password( - "kibana_password" - ) + kibana_password = frappe.get_doc("Log Server", log_server).get_password("kibana_password") else: kibana_password = None try: ansible = Ansible( - playbook="self_hosted_proxy.yml" - if getattr(self, "is_self_hosted", False) - else "proxy.yml", + playbook="self_hosted_proxy.yml" if getattr(self, "is_self_hosted", False) else "proxy.yml", server=self, user=self.ssh_user or "root", port=self.ssh_port or 22, @@ -181,9 +175,7 @@ def _setup_server(self): self.save() def _install_exporters(self): - monitoring_password = frappe.get_doc("Cluster", self.cluster).get_password( - "monitoring_password" - ) + monitoring_password = frappe.get_doc("Cluster", self.cluster).get_password("monitoring_password") try: ansible = Ansible( playbook="proxy_exporters.yml", @@ -201,9 +193,7 @@ def _install_exporters(self): @frappe.whitelist() def setup_ssh_proxy(self): - frappe.enqueue_doc( - self.doctype, self.name, "_setup_ssh_proxy", queue="long", timeout=1200 - ) + frappe.enqueue_doc(self.doctype, self.name, "_setup_ssh_proxy", queue="long", timeout=1200) def _setup_ssh_proxy(self): settings = frappe.db.get_value( @@ -238,9 +228,7 @@ def _setup_ssh_proxy(self): def setup_fail2ban(self): self.status = "Installing" self.save() - frappe.enqueue_doc( - self.doctype, self.name, "_setup_fail2ban", queue="long", timeout=1200 - ) + frappe.enqueue_doc(self.doctype, self.name, "_setup_fail2ban", queue="long", timeout=1200) def _setup_fail2ban(self): try: @@ -261,9 +249,7 @@ def _setup_fail2ban(self): @frappe.whitelist() def setup_proxysql(self): - frappe.enqueue_doc( - self.doctype, self.name, "_setup_proxysql", queue="long", timeout=1200 - ) + frappe.enqueue_doc(self.doctype, self.name, "_setup_proxysql", queue="long", timeout=1200) def _setup_proxysql(self): try: @@ -294,9 +280,7 @@ def _setup_proxysql(self): def setup_replication(self): self.status = "Installing" self.save() - frappe.enqueue_doc( - self.doctype, self.name, "_setup_replication", queue="long", timeout=1200 - ) + frappe.enqueue_doc(self.doctype, self.name, "_setup_replication", queue="long", timeout=1200) def _setup_replication(self): self._setup_secondary() @@ -351,9 +335,7 @@ def trigger_failover(self): return self.status = "Installing" self.save() - frappe.enqueue_doc( - self.doctype, self.name, "_trigger_failover", queue="long", timeout=3600 - ) + frappe.enqueue_doc(self.doctype, self.name, "_trigger_failover", queue="long", timeout=3600) def stop_primary(self): primary = frappe.get_doc("Proxy Server", self.primary) @@ -387,9 +369,7 @@ def remove_primarys_access(self): playbook="failover_remove_primary_access.yml", server=self, variables={ - "primary_public_key": frappe.db.get_value( - "Proxy Server", self.primary, "frappe_public_key" - ) + "primary_public_key": frappe.db.get_value("Proxy Server", self.primary, "frappe_public_key") }, ) ansible.run() @@ -445,9 +425,7 @@ def add_ssh_users_for_existing_benches(self): bench.add_ssh_user() def update_app_servers(self): - frappe.db.set_value( - "Server", {"proxy_server": self.primary}, "proxy_server", self.name - ) + frappe.db.set_value("Server", {"proxy_server": self.primary}, "proxy_server", self.name) def switch_primary(self): frappe.db.set_value("Proxy Server", self.primary, "is_primary", False) @@ -458,9 +436,7 @@ def switch_primary(self): @frappe.whitelist() def setup_proxysql_monitor(self): - frappe.enqueue_doc( - self.doctype, self.name, "_setup_proxysql_monitor", queue="long", timeout=1200 - ) + frappe.enqueue_doc(self.doctype, self.name, "_setup_proxysql_monitor", queue="long", timeout=1200) def _setup_proxysql_monitor(self): try: @@ -486,9 +462,7 @@ def _setup_proxysql_monitor(self): @frappe.whitelist() def setup_wireguard(self): if not self.private_ip_interface_id: - play = frappe.get_last_doc( - "Ansible Play", {"play": "Ping Server", "server": self.name} - ) + play = frappe.get_last_doc("Ansible Play", {"play": "Ping Server", "server": self.name}) task = frappe.get_doc("Ansible Task", {"play": play.name, "task": "Gather Facts"}) import json @@ -497,9 +471,7 @@ def setup_wireguard(self): if task_res[i]["ipv4"]["address"] == self.private_ip: self.private_ip_interface_id = task_res[i]["device"] self.save() - frappe.enqueue_doc( - self.doctype, self.name, "_setup_wireguard", queue="long", timeout=1200 - ) + frappe.enqueue_doc(self.doctype, self.name, "_setup_wireguard", queue="long", timeout=1200) def _setup_wireguard(self): try: @@ -516,7 +488,7 @@ def _setup_wireguard(self): "wireguard_private_key": False, "wireguard_public_key": False, "peers": "", - "reload_wireguard": True if self.is_wireguard_setup else False, + "reload_wireguard": bool(self.is_wireguard_setup), }, ) play = ansible.run() @@ -536,9 +508,7 @@ def _setup_wireguard(self): @frappe.whitelist() def reload_wireguard(self): - frappe.enqueue_doc( - "Proxy Server", self.name, "_reload_wireguard", queue="default", timeout=1200 - ) + frappe.enqueue_doc("Proxy Server", self.name, "_reload_wireguard", queue="default", timeout=1200) def _reload_wireguard(self): import json diff --git a/press/press/doctype/server/server.py b/press/press/doctype/server/server.py index 6631e40da9..cbdf82d9c9 100644 --- a/press/press/doctype/server/server.py +++ b/press/press/doctype/server/server.py @@ -15,6 +15,7 @@ from frappe.core.utils import find, find_all from frappe.installer import subprocess from frappe.model.document import Document +from frappe.utils import cint from frappe.utils.user import is_system_user from press.agent import Agent @@ -634,7 +635,7 @@ def create_subscription_for_storage(self, increment: int) -> None: "Subscription", existing_subscription.name, "additional_storage", - increment + int(existing_subscription.additional_storage), + increment + cint(existing_subscription.additional_storage), ) else: frappe.get_doc( diff --git a/press/press/doctype/site/site.py b/press/press/doctype/site/site.py index 39fd53254d..c6360ef912 100644 --- a/press/press/doctype/site/site.py +++ b/press/press/doctype/site/site.py @@ -13,6 +13,8 @@ import dateutil.parser import frappe +import frappe.data +import frappe.utils import pytz import requests from frappe import _ @@ -68,6 +70,9 @@ from press.press.doctype.site_activity.site_activity import log_site_activity from press.press.doctype.site_analytics.site_analytics import create_site_analytics from press.press.doctype.site_plan.site_plan import get_plan_config +from press.press.report.mariadb_slow_queries.mariadb_slow_queries import ( + get_doctype_name, +) from press.utils import ( convert, fmt_timedelta, @@ -2265,10 +2270,92 @@ def get_update_information(self): out.update_available = any([app["update_available"] for app in out.apps]) return out - @frappe.whitelist() - def optimize_tables(self): + def fetch_running_optimize_tables_job(self): + return frappe.db.exists( + "Agent Job", + { + "site": self.name, + "job_type": "Optimize Tables", + "status": ["in", ["Undelivered", "Running", "Pending"]], + }, + ) + + @dashboard_whitelist() + def optimize_tables(self, ignore_checks: bool = False): + if not ignore_checks: + # check for running `Optimize Tables` agent job + if job := self.fetch_running_optimize_tables_job(): + return { + "success": True, + "message": "Optimize Tables job is already running on this site.", + "job_name": job, + } + # check if `Optimize Tables` has run in last 1 hour + recent_agent_job_name = frappe.db.exists( + "Agent Job", + { + "site": self.name, + "job_type": "Optimize Tables", + "status": ["not in", ["Failure", "Delivery Failure"]], + "creation": [">", frappe.utils.add_to_date(frappe.utils.now_datetime(), hours=-1)], + }, + ) + if recent_agent_job_name: + return { + "success": False, + "message": "Optimize Tables job has already run in the last 1 hour. Try later.", + "job_name": None, + } + agent = Agent(self.server) - agent.optimize_tables(self) + job_name = agent.optimize_tables(self).name + return { + "success": True, + "message": "Optimize Tables has been triggered on this site.", + "job_name": job_name, + } + + @dashboard_whitelist() + def get_database_performance_report(self): + from press.press.report.mariadb_slow_queries.mariadb_slow_queries import get_data as get_slow_queries + + agent = Agent(self.server) + result = agent.get_summarized_performance_report_of_database(self) + # fetch slow queries of last 7 days + slow_queries = get_slow_queries( + frappe._dict( + { + "database": self.database_name, + "start_datetime": frappe.utils.add_to_date(None, days=-7), + "stop_datetime": frappe.utils.now_datetime(), + "search_pattern": ".*", + "max_lines": 2000, + "normalize_queries": True, + } + ) + ) + # remove `parent` & `creation` indexes from unused_indexes + result["unused_indexes"] = [ + index + for index in result.get("unused_indexes", []) + if index["index_name"] not in ["parent", "creation"] + ] + + # convert all the float to int + for query in slow_queries: + for key, value in query.items(): + if isinstance(value, float): + query[key] = int(value) + # sort the slow queries by `rows_examined` + result["slow_queries"] = sorted(slow_queries, key=lambda x: x["rows_examined"], reverse=True) + result["is_performance_schema_enabled"] = False + if database_server := frappe.db.get_value("Server", self.server, "database_server"): + result["is_performance_schema_enabled"] = frappe.db.get_value( + "Database Server", + database_server, + "is_performance_schema_enabled", + ) + return result @property def server_logs(self): @@ -2625,19 +2712,66 @@ def forcefully_remove_site(self, bench): @dashboard_whitelist() def fetch_database_table_schema(self, reload=False): - if not frappe.db.exists("Site Database Table Schema", {"site": self.name}): - frappe.get_doc({"doctype": "Site Database Table Schema", "site": self.name}).insert( - ignore_permissions=True - ) + """ + Store dump in redis cache + """ + key_for_schema = f"database_table_schema__data:{self.name}" + key_for_schema_status = ( + f"database_table_schema__status:{self.name}" # 1 - loading, 2 - done, None - not available + ) + + if reload: + frappe.cache().delete_value(key_for_schema) + frappe.cache().delete_value(key_for_schema_status) + + status = frappe.utils.cint(frappe.cache().get_value(key_for_schema_status)) + if status: + if status == 1: + return { + "loading": True, + "data": [], + } + if status == 2: + return { + "loading": False, + "data": json.loads(frappe.cache().get_value(key_for_schema)), + } - doc = frappe.get_doc("Site Database Table Schema", {"site": self.name}) - loading, data = doc.fetch(reload) + # Check if any agent job is created within 5 minutes and in pending/running condition + # Checks to prevent duplicate agent job creation due to race condition + if not frappe.db.exists( + "Agent Job", + { + "job_type": "Fetch Database Table Schema", + "site": self.name, + "status": ["in", ["Undelivered", "Pending", "Running"]], + "creation": (">", frappe.utils.add_to_date(None, minutes=-5)), + }, + ): + # create the agent job and put it in loading state + frappe.cache().set_value(key_for_schema_status, 1, expires_in_sec=600) + Agent(self.server).fetch_database_table_schema( + self, include_index_info=True, include_table_size=True + ) return { - "loading": loading, - "data": data, - "last_updated": doc.last_updated, + "loading": True, + "data": [], } + @dashboard_whitelist() + def fetch_database_processes(self): + agent = Agent(self.server) + if agent.should_skip_requests(): + return None + return agent.fetch_database_processes(self) + + @dashboard_whitelist() + def kill_database_process(self, id): + agent = Agent(self.server) + if agent.should_skip_requests(): + return None + return agent.kill_database_process(self, id) + @dashboard_whitelist() def run_sql_query_in_database(self, query: str, commit: bool): if not query: @@ -2656,6 +2790,88 @@ def run_sql_query_in_database(self, query: str, commit: bool): doc.insert(ignore_permissions=True) return response + @dashboard_whitelist() + def suggest_database_indexes(self): + from press.press.report.mariadb_slow_queries.mariadb_slow_queries import get_data as get_slow_queries + + existing_agent_job_name = frappe.db.exists( + "Agent Job", + { + "site": self.name, + "status": ("not in", ("Failure", "Delivery Failure")), + "job_type": "Analyze Slow Queries", + "creation": ( + ">", + frappe.utils.add_to_date(None, minutes=-30), + ), + "retry_count": 0, + }, + ) + + if existing_agent_job_name: + existing_agent_job = frappe.get_doc("Agent Job", existing_agent_job_name) + if existing_agent_job.status == "Success": + return { + "loading": False, + "data": json.loads(existing_agent_job.data).get("result", []), + } + return { + "loading": True, + "data": [], + } + + # fetch slow queries of last 7 days + slow_queries = get_slow_queries( + frappe._dict( + { + "database": self.database_name, + "start_datetime": frappe.utils.add_to_date(None, days=-7), + "stop_datetime": frappe.utils.now_datetime(), + "search_pattern": ".*", + "max_lines": 1000, + "normalize_queries": True, + } + ) + ) + slow_queries = [{"example": x["example"], "normalized": x["query"]} for x in slow_queries] + if len(slow_queries) == 0: + return { + "loading": False, + "data": [], + } + agent = Agent(self.server) + agent.analyze_slow_queries(self, slow_queries) + + return { + "loading": True, + "data": [], + } + + @dashboard_whitelist() + def add_database_index(self, table, column): + record = frappe.db.exists( + "Agent Job", + { + "site": self.name, + "status": ["in", ["Undelivered", "Running", "Pending"]], + "job_type": "Add Database Index", + }, + ) + if record: + return { + "success": False, + "message": "There is already a job running for adding database index. Please wait until finished.", + "job_name": record, + } + doctype = get_doctype_name(table) + agent = Agent(self.server) + job = agent.add_database_index(self, doctype=doctype, columns=[column]) + return { + "success": True, + "message": "Database index will be added on site.", + "job_name": job.name, + } + def site_cleanup_after_archive(site): delete_site_domains(site) @@ -2689,6 +2905,51 @@ def release_name(name): frappe.rename_doc("Site", name, new_name) +def process_fetch_database_table_schema_job_update(job): + key_for_schema = f"database_table_schema__data:{job.site}" + key_for_schema_status = ( + f"database_table_schema__status:{job.site}" # 1 - loading, 2 - done, None - not available + ) + + if job.status in ["Failure", "Delivery Failure"]: + frappe.cache().delete_value(key_for_schema) + frappe.cache().delete_value(key_for_schema_status) + return + + if job.status == "Success": + """ + Support old agent versions + Remove this once all agents are updated + """ + data = json.loads(job.data) + is_old_agent = False + + if len(data) > 0 and isinstance(data[next(iter(data.keys()))], list): + is_old_agent = True + + if is_old_agent: + data_copy = data.copy() + data = {} + for key, value in data_copy.items(): + data[key] = { + "columns": value, + "size": { + "data_length": 0, + "index_length": 0, + "total_size": 0, + }, # old agent api doesn't have size info + } + for column in data[key]["columns"]: + column["index_info"] = { + "index_usage": {x: 0 for x in column["indexes"]}, # just fill some dummy value + "indexes": column["indexes"], + "is_indexed": len(column["indexes"]) > 0, + } + + frappe.cache().set_value(key_for_schema, json.dumps(data), expires_in_sec=6000) + frappe.cache().set_value(key_for_schema_status, 2, expires_in_sec=6000) + + def process_new_site_job_update(job): # noqa: C901 site_status = frappe.get_value("Site", job.site, "status", for_update=True) diff --git a/press/press/doctype/site_database_table_schema/__init__.py b/press/press/doctype/site_database_table_schema/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/press/press/doctype/site_database_table_schema/site_database_table_schema.js b/press/press/doctype/site_database_table_schema/site_database_table_schema.js deleted file mode 100644 index 4747337e12..0000000000 --- a/press/press/doctype/site_database_table_schema/site_database_table_schema.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2024, Frappe and contributors -// For license information, please see license.txt - -// frappe.ui.form.on("Site Database Table Schema", { -// refresh(frm) { - -// }, -// }); diff --git a/press/press/doctype/site_database_table_schema/site_database_table_schema.json b/press/press/doctype/site_database_table_schema/site_database_table_schema.json deleted file mode 100644 index 7917ec3755..0000000000 --- a/press/press/doctype/site_database_table_schema/site_database_table_schema.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "actions": [], - "creation": "2024-10-28 11:45:28.634612", - "doctype": "DocType", - "engine": "InnoDB", - "field_order": [ - "site", - "column_break_mufi", - "agent_job", - "section_break_heok", - "schema_json" - ], - "fields": [ - { - "fieldname": "site", - "fieldtype": "Link", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Site", - "options": "Site", - "reqd": 1, - "unique": 1 - }, - { - "fieldname": "agent_job", - "fieldtype": "Link", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Agent Job", - "options": "Agent Job" - }, - { - "fieldname": "column_break_mufi", - "fieldtype": "Column Break" - }, - { - "fieldname": "section_break_heok", - "fieldtype": "Section Break" - }, - { - "default": "{}", - "fieldname": "schema_json", - "fieldtype": "Long Text", - "label": "Schema JSON", - "reqd": 1 - } - ], - "index_web_pages_for_search": 1, - "links": [], - "modified": "2024-10-28 15:43:58.768773", - "modified_by": "Administrator", - "module": "Press", - "name": "Site Database Table Schema", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "write": 1 - }, - { - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Press Admin", - "share": 1 - }, - { - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Press Member", - "share": 1 - } - ], - "sort_field": "creation", - "sort_order": "DESC", - "states": [], - "title_field": "site" -} \ No newline at end of file diff --git a/press/press/doctype/site_database_table_schema/site_database_table_schema.py b/press/press/doctype/site_database_table_schema/site_database_table_schema.py deleted file mode 100644 index cf13d99e5c..0000000000 --- a/press/press/doctype/site_database_table_schema/site_database_table_schema.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright (c) 2024, Frappe and contributors -# For license information, please see license.txt -from __future__ import annotations - -import json -from typing import TYPE_CHECKING - -import frappe -from frappe.model.document import Document - -from press.agent import Agent - -if TYPE_CHECKING: - from press.press.doctype.site_migration.site_migration import AgentJob - - -class SiteDatabaseTableSchema(Document): - # begin: auto-generated types - # This code is auto-generated. Do not modify anything in this block. - - from typing import TYPE_CHECKING - - if TYPE_CHECKING: - from frappe.types import DF - - agent_job: DF.Link | None - schema_json: DF.LongText - site: DF.Link - # end: auto-generated types - - def fetch(self, reload=False) -> tuple[bool, dict]: - """ - This function will return the schema of the database table - - Args: - reload: bool - if True, it will fetch the schema from the server again - - Returns: - tuple[bool, list] - - 1st element: bool - Loading status - - 2nd element: dict - Dictionary of table schemas - Example - - { - "__Auth": [ - { - "column": "doctype", - "data_type": "varchar", - "default": "NULL", - "indexes": [ - "PRIMARY" - ], - "is_nullable": false - }, - .... - ], - .... - } - """ - if len(self.schema) > 0 and not reload: - return False, self.schema - - if self.agent_job is not None and frappe.get_value("Agent Job", self.agent_job, "status") in [ - "Undelivered", - "Pending", - "Running", - ]: - return True, {} - - self.schema_json = "{}" - site = frappe.get_doc("Site", self.site) - self.agent_job = Agent(site.server).fetch_database_table_schema(site).name - self.save(ignore_permissions=True) - - return True, {} - - @property - def last_updated(self) -> str: - return self.modified or self.creation - - @property - def schema(self) -> dict: - try: - return json.loads(self.schema_json) - except frappe.DoesNotExistError: - return {} - - @staticmethod - def process_job_update(job: "AgentJob"): - if job.status != "Success": - return - response_data = json.loads(job.data) or {} - if response_data and frappe.db.exists("Site Database Table Schema", {"site": job.site}): - doc = frappe.get_doc("Site Database Table Schema", {"site": job.site}) - doc.schema_json = json.dumps(response_data) - doc.save(ignore_permissions=True) diff --git a/press/press/doctype/site_database_table_schema/test_site_database_table_schema.py b/press/press/doctype/site_database_table_schema/test_site_database_table_schema.py deleted file mode 100644 index b75f628d81..0000000000 --- a/press/press/doctype/site_database_table_schema/test_site_database_table_schema.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2024, Frappe and Contributors -# See license.txt - -# import frappe -from frappe.tests import UnitTestCase - -# On IntegrationTestCase, the doctype test records and all -# link-field test record depdendencies are recursively loaded -# Use these module variables to add/remove to/from that list -EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"] -IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"] - - -class TestSiteDatabaseTableSchema(UnitTestCase): - """ - Unit tests for SiteDatabaseTableSchema. - Use this class for testing individual functions and methods. - """ - - pass diff --git a/press/press/doctype/subscription/subscription.py b/press/press/doctype/subscription/subscription.py index e85364a2be..fd707a178b 100644 --- a/press/press/doctype/subscription/subscription.py +++ b/press/press/doctype/subscription/subscription.py @@ -7,6 +7,7 @@ import rq from frappe.model.document import Document from frappe.query_builder.functions import Coalesce, Count +from frappe.utils import cint from press.overrides import get_permission_query_conditions_for_doctype from press.press.doctype.site_plan.site_plan import SitePlan @@ -127,12 +128,12 @@ def disable(self): frappe.log_error(title="Disable Subscription Error") @frappe.whitelist() - def create_usage_record(self): + def create_usage_record(self, date: DF.Date | None = None): cannot_charge = not self.can_charge_for_subscription() if cannot_charge: return None - if self.is_usage_record_created(): + if self.is_usage_record_created(date): return None team = frappe.get_cached_doc("Team", self.team) @@ -151,7 +152,7 @@ def create_usage_record(self): if self.additional_storage: price = plan.price_inr if team.currency == "INR" else plan.price_usd price_per_day = price / plan.period # no rounding off to avoid discrepancies - amount = price_per_day * int(self.additional_storage) + amount = price_per_day * cint(self.additional_storage) else: amount = plan.get_price_for_interval(self.interval, team.currency) @@ -163,6 +164,7 @@ def create_usage_record(self): plan_type=self.plan_type, plan=plan.name, amount=amount, + date=date, subscription=self.name, interval=self.interval, site=( @@ -186,7 +188,7 @@ def can_charge_for_subscription(self): return True - def is_usage_record_created(self): + def is_usage_record_created(self, date=None): filters = { "team": self.team, "document_type": self.document_type, @@ -197,7 +199,8 @@ def is_usage_record_created(self): } if self.interval == "Daily": - filters.update({"date": frappe.utils.today()}) + date = date or frappe.utils.today() + filters.update({"date": date}) if self.interval == "Monthly": date = frappe.utils.getdate() diff --git a/press/press/doctype/team/team.py b/press/press/doctype/team/team.py index 546d9cb06d..542b989e64 100644 --- a/press/press/doctype/team/team.py +++ b/press/press/doctype/team/team.py @@ -111,6 +111,7 @@ class Team(Document): "is_developer", "enable_performance_tuning", "enable_inplace_updates", + "servers_enabled", ) def get_doc(self, doc): @@ -1094,7 +1095,9 @@ def suspend_sites(self, reason=None): def get_sites_to_suspend(self): plan = frappe.qb.DocType("Site Plan") query = ( - frappe.qb.from_(plan).select(plan.name).where((plan.enabled == 1) & ((plan.is_frappe_plan == 1) | (plan.is_trial_plan == 1))) + frappe.qb.from_(plan) + .select(plan.name) + .where((plan.enabled == 1) & ((plan.is_frappe_plan == 1) | (plan.is_trial_plan == 1))) ).run(as_dict=True) frappe_plans = [d.name for d in query] diff --git a/press/press/doctype/virtual_disk_snapshot/virtual_disk_snapshot.py b/press/press/doctype/virtual_disk_snapshot/virtual_disk_snapshot.py index 2ba94babf8..55c88c9505 100644 --- a/press/press/doctype/virtual_disk_snapshot/virtual_disk_snapshot.py +++ b/press/press/doctype/virtual_disk_snapshot/virtual_disk_snapshot.py @@ -184,6 +184,7 @@ def sync_all_snapshots_from_aws(): if _should_skip_snapshot(snapshot): continue try: + delete_duplicate_snapshot_docs(snapshot) if _update_snapshot_if_exists(snapshot, random_snapshot): continue tag_name = next(tag["Value"] for tag in snapshot["Tags"] if tag["Key"] == "Name") @@ -238,6 +239,23 @@ def _should_skip_snapshot(snapshot): return False +def delete_duplicate_snapshot_docs(snapshot): + # Delete all except one snapshot document + # It doesn't matter which one we keep + snapshot_id = snapshot["SnapshotId"] + snapshot_count = frappe.db.count("Virtual Disk Snapshot", {"snapshot_id": snapshot_id}) + if snapshot_count > 1: + frappe.db.sql( + """ + DELETE + FROM `tabVirtual Disk Snapshot` + WHERE snapshot_id=%s + LIMIT %s + """, + (snapshot_id, snapshot_count - 1), + ) + + def _update_snapshot_if_exists(snapshot, random_snapshot): snapshot_id = snapshot["SnapshotId"] if frappe.db.exists("Virtual Disk Snapshot", {"snapshot_id": snapshot_id}): diff --git a/press/press/report/mariadb_deadlock_browser/mariadb_deadlock_browser.py b/press/press/report/mariadb_deadlock_browser/mariadb_deadlock_browser.py index d0afa62572..3c58a3e5ac 100644 --- a/press/press/report/mariadb_deadlock_browser/mariadb_deadlock_browser.py +++ b/press/press/report/mariadb_deadlock_browser/mariadb_deadlock_browser.py @@ -248,7 +248,7 @@ def deadlock_summary(transactions: list[DatabaseTransactionLog]) -> list[dict]: def execute(filters=None): - frappe.only_for(["System Manager", "Site Manager"]) + frappe.only_for(["System Manager", "Site Manager", "Press Admin", "Press Member"]) filters.database = frappe.db.get_value("Site", filters.site, "database_name") if not filters.database: frappe.throw( diff --git a/press/press/report/mariadb_slow_queries/db_optimizer.py b/press/press/report/mariadb_slow_queries/db_optimizer.py deleted file mode 100644 index 36f6ad5afb..0000000000 --- a/press/press/report/mariadb_slow_queries/db_optimizer.py +++ /dev/null @@ -1,352 +0,0 @@ -"""Basic DB optimizer for Frappe Framework based app. - -This is largely based on heuristics and known good practices for indexing. -""" - -from collections import defaultdict -from dataclasses import dataclass -from typing import Literal -import re -import frappe -from frappe.utils import cint, cstr, flt -from sql_metadata import Parser - -# Any index that reads more than 30% table on average is not "useful" -INDEX_SCORE_THRESHOLD = 0.3 -# Anything reading less than this percent of table is considered optimal -OPTIMIZATION_THRESHOLD = 0.1 - - -@dataclass -class DBExplain: - # refer: https://mariadb.com/kb/en/explain/ - # Anything not explicitly encoded here is likely not supported. - select_type: Literal["SIMPLE", "PRIMARY", "SUBQUERY", "UNION", "DERIVED"] - table: str - scan_type: Literal[ # What type of scan will be performed - "ALL", # Full table scan - "CONST", # Single row will be read - "EQ_REF", # A single row is found from *unique* index - "REF", # Index is used, but MIGHT hit more than 1 rows as it's non-unique - "RANGE", # The table will be accessed with a key over one or more value ranges. - "INDEX_MERGE", # multiple indexes are used and merged smartly. Equivalent to RANGE - "INDEX_SUBQUERY", - "INDEX", # Full index scan is performed. Similar to full table scan in case of large number of rows. - "REF_OR_NULL", - "UNIQUE_SUBQUERY", - "FULLTEXT", # Full text index is used, - ] - possible_keys: list[str] | None = None # possible indexes that can be used - key: str | None = None # This index is being used - key_len: int | None = None # How many prefix bytes from index are being used - ref: str | None = None # is reference constant or some other column - rows: int = 0 # roughly how many rows will be examined - extra: str | None = None - - @classmethod - def from_frappe_ouput(cls, data) -> "DBExplain": - return cls( - select_type=cstr(data["select_type"]).upper(), - table=data["table"], - scan_type=cstr(data["type"]).upper(), - possible_keys=data["possible_keys"], - key=data["key"], - key_len=cint(data["key_len"]) if data["key_len"] else None, - ref=data["ref"], - rows=cint(data["rows"]), - extra=data.get("Extra"), - ) - - -@dataclass -class DBColumn: - name: str - cardinality: int | None - is_nullable: bool - default: str - data_type: str - - @classmethod - def from_frappe_ouput(cls, data) -> "DBColumn": - "Parse DBColumn from output of describe-database-table command in Frappe" - return cls( - name=data["column"], - cardinality=data.get("cardinality"), - is_nullable=data["is_nullable"], - default=data["default"], - data_type=data["type"], - ) - - -@dataclass -class DBIndex: - name: str - column: str - table: str - unique: bool | None = None - cardinality: int | None = None - sequence: int = 1 - nullable: bool = True - _score: float = 0.0 - - def __eq__(self, other: "DBIndex") -> bool: - return ( - self.column == other.column - and self.sequence == other.sequence - and self.table == other.table - ) - - def __repr__(self): - return f"DBIndex(`{self.table}`.`{self.column}`)" - - @classmethod - def from_frappe_ouput(cls, data, table) -> "DBIndex": - "Parse DBIndex from output of describe-database-table command in Frappe" - return cls( - name=data["name"], - table=table, - unique=data["unique"], - cardinality=data["cardinality"], - sequence=data["sequence"], - nullable=data["nullable"], - column=data["column"], - ) - - -@dataclass -class ColumnStat: - column_name: str - avg_frequency: float - avg_length: float - nulls_ratio: float | None = None - histogram: list[float] = None - - def __post_init__(self): - if not self.histogram: - self.histogram = [] - - @classmethod - def from_frappe_ouput(cls, data) -> "ColumnStat": - return cls( - column_name=data["column_name"], - avg_frequency=data["avg_frequency"], - avg_length=data["avg_length"], - nulls_ratio=data["nulls_ratio"], - histogram=[flt(bin) for bin in data["histogram"].split(",")] - if data["histogram"] - else [], - ) - - -@dataclass -class DBTable: - name: str - total_rows: int - schema: list[DBColumn] | None = None - indexes: list[DBIndex] | None = None - - def __post_init__(self): - if not self.schema: - self.schema = [] - if not self.indexes: - self.indexes = [] - - def update_cardinality(self, column_stats: list[ColumnStat]) -> None: - """Estimate cardinality using mysql.column_stat""" - for column_stat in column_stats: - for col in self.schema: - if ( - col.name == column_stat.column_name - and not col.cardinality - and column_stat.avg_frequency - ): - # "hack" or "math" - average frequency is on average how frequently a row value appears. - # Avg = total_rows / cardinality, so... - col.cardinality = self.total_rows / column_stat.avg_frequency - - @classmethod - def from_frappe_ouput(cls, data) -> "DBTable": - "Parse DBTable from output of describe-database-table command in Frappe" - table_name = data["table_name"] - return cls( - name=table_name, - total_rows=data["total_rows"], - schema=[DBColumn.from_frappe_ouput(c) for c in data["schema"]], - indexes=[DBIndex.from_frappe_ouput(i, table_name) for i in data["indexes"]], - ) - - def has_column(self, column: str) -> bool: - for col in self.schema: - if col.name == column: - return True - return False - - -@dataclass -class DBOptimizer: - query: str # raw query in string format - explain_plan: list[DBExplain] = None - tables: dict[str, DBTable] = None - parsed_query: Parser = None - - def __post_init__(self): - if not self.explain_plan: - self.explain_plan = [] - if not self.tables: - self.tables = {} - for explain_entry in self.explain_plan: - explain_entry.select_type = explain_entry.select_type.upper() - explain_entry.scan_type = explain_entry.scan_type.upper() - self.parsed_query = Parser(re.sub(r'"(\S+)"', r"'\1'", self.query)) - - @property - def tables_examined(self) -> list[str]: - return self.parsed_query.tables - - def update_table_data(self, table: DBTable): - self.tables[table.name] = table - - def potential_indexes(self) -> list[DBIndex]: - """Get all columns that can potentially be indexed to speed up this query.""" - - possible_indexes = [] - - # Where claus columns using these operators benefit from index - # 1. = (equality) - # 2. >, <, >=, <= - # 3. LIKE 'xyz%' (Prefix search) - # 4. BETWEEN (for date[time] fields) - # 5. IN (similar to equality) - if where_columns := self.parsed_query.columns_dict.get("where"): - # TODO: Apply some heuristics here, not all columns in where clause are actually useful - possible_indexes.extend(where_columns) - - # Join clauses - Both sides of join should ideally be indexed. One will *usually* be primary key. - if join_columns := self.parsed_query.columns_dict.get("join"): - possible_indexes.extend(join_columns) - - # Top N query variant - Order by column can possibly speed up the query - if order_by_columns := self.parsed_query.columns_dict.get("order_by"): - if self.parsed_query.limit_and_offset: - possible_indexes.extend(order_by_columns) - - possible_db_indexes = [self._convert_to_db_index(i) for i in possible_indexes] - possible_db_indexes = [ - i for i in possible_db_indexes if i.column not in ("*", "name") - ] - possible_db_indexes.sort(key=lambda i: (i.table, i.column)) - - return self._remove_existing_indexes(possible_db_indexes) - - def _convert_to_db_index(self, column: str) -> DBIndex: - column_name, table = None, None - - if "." in column: - table, column_name = column.split(".") - else: - column_name = column - for table_name, db_table in self.tables.items(): - if db_table.has_column(column): - table = table_name - break - return DBIndex(column=column_name, name=column_name, table=table) - - def _remove_existing_indexes(self, potential_indexes: list[DBIndex]) -> list[DBIndex]: - """Given list of potential index candidates remove the ones that already exist. - - This also removes multi-column indexes for parts that are applicable to query. - Example: If multi-col index A+B+C exists and query utilizes A+B then - A+B are removed from potential indexes. - """ - - def remove_maximum_indexes(idx: list[DBIndex]): - """Try to remove entire index from potential indexes, if not possible, reduce one part and try again until no parts are left.""" - if not idx: - return - matched_sub_index = [] - for idx_part in list(idx): - matching_part = [ - i - for i in potential_indexes - if i.column == idx_part.column and i.table == idx_part.table - ] - if not matching_part: - # pop and recurse - idx.pop() - return remove_maximum_indexes(idx) - else: - matched_sub_index.extend(matching_part) - - # Every part matched now, lets remove those parts - for i in matched_sub_index: - potential_indexes.remove(i) - - # Reconstruct multi-col index - for table in self.tables.values(): - merged_indexes = defaultdict(list) - for index in table.indexes: - merged_indexes[index.name].append(index) - - for idx in merged_indexes.values(): - idx.sort(key=lambda x: x.sequence) - - for idx in merged_indexes.values(): - remove_maximum_indexes(idx) - return potential_indexes - - def suggest_index(self) -> DBIndex | None: - """Suggest best possible column to index given query and table stats.""" - if missing_tables := (set(self.tables_examined) - set(self.tables.keys())): - frappe.throw("DBTable infomation missing for: " + ", ".join(missing_tables)) - - potential_indexes = self.potential_indexes() - - for index in list(potential_indexes): - table = self.tables[index.table] - - # Data type is not easily indexable - skip - column = [c for c in table.schema if c.name == index.column][0] - if "text" in column.data_type.lower() or "json" in column.data_type.lower(): - potential_indexes.remove(index) - # Update cardinality from column so scoring can be done - index.cardinality = column.cardinality - - for index in potential_indexes: - index._score = self.index_score(index) - - potential_indexes.sort(key=lambda i: i._score) - if ( - potential_indexes - and (best_index := potential_indexes[0]) - and best_index._score < INDEX_SCORE_THRESHOLD - ): - return best_index - - def index_score(self, index: DBIndex) -> float: - """Score an index from 0 to 1 based on usefulness. - - A score of 0.5 indicates on average this index will read 50% of the table. (e.g. checkboxes)""" - table = self.tables[index.table] - - cardinality = index.cardinality or 2 - total_rows = table.total_rows or cardinality or 1 - - # We assume most unique values are evenly distributed, this is - # definitely not the case IRL but it should be good enough assumptions - # Score is rouhgly what percentage of table we will end up reading on typical query - rows_fetched_on_average = (table.total_rows or cardinality) / cardinality - return rows_fetched_on_average / total_rows - - def can_be_optimized(self) -> bool: - """Return true if it's worth optimizeing. - - Few cases can not be optimized any further. E.g. ref/eq_ref/cost type - of queries. Assume that anything that reads <10% of table already is - not possible to truly optimize with these heuristics.""" - for explain in self.explain_plan: - for table in self.tables.values(): - if table.name != explain.table: - continue - if (explain.rows / table.total_rows) > OPTIMIZATION_THRESHOLD: - return True - return False diff --git a/press/press/report/mariadb_slow_queries/mariadb_slow_queries.json b/press/press/report/mariadb_slow_queries/mariadb_slow_queries.json index 5897aaffd9..d32316c08f 100644 --- a/press/press/report/mariadb_slow_queries/mariadb_slow_queries.json +++ b/press/press/report/mariadb_slow_queries/mariadb_slow_queries.json @@ -1,15 +1,15 @@ { "add_total_row": 0, "columns": [], - "creation": "2021-11-01 19:16:08.357082", - "disable_prepared_report": 0, + "creation": "2024-12-23 11:36:40.301426", "disabled": 0, "docstatus": 0, "doctype": "Report", "filters": [], "idx": 0, "is_standard": "Yes", - "modified": "2022-11-08 17:10:41.382656", + "letterhead": null, + "modified": "2024-12-23 11:36:40.301426", "modified_by": "Administrator", "module": "Press", "name": "MariaDB Slow Queries", @@ -25,5 +25,6 @@ { "role": "Site Manager" } - ] + ], + "timeout": 0 } \ No newline at end of file diff --git a/press/press/report/mariadb_slow_queries/mariadb_slow_queries.py b/press/press/report/mariadb_slow_queries/mariadb_slow_queries.py index 902c4cd70c..a546e699db 100644 --- a/press/press/report/mariadb_slow_queries/mariadb_slow_queries.py +++ b/press/press/report/mariadb_slow_queries/mariadb_slow_queries.py @@ -3,28 +3,16 @@ from __future__ import annotations -import json import re from collections import defaultdict -from dataclasses import dataclass import frappe import requests import sqlparse from frappe.core.doctype.access_log.access_log import make_access_log from frappe.utils import convert_utc_to_timezone, get_system_timezone -from frappe.utils.caching import redis_cache from frappe.utils.password import get_decrypted_password -from press.agent import Agent -from press.api.site import protected -from press.press.report.mariadb_slow_queries.db_optimizer import ( - DBExplain, - DBIndex, - DBOptimizer, - DBTable, -) - def execute(filters=None): frappe.only_for(["System Manager", "Site Manager", "Press Admin", "Press Member"]) @@ -89,15 +77,6 @@ def execute(filters=None): }, ) - if filters.analyze: - columns.append( - { - "fieldname": "suggested_index", - "label": frappe._("Suggest Index"), - "fieldtype": "Data", - }, - ) - data = get_data(filters) return columns, data @@ -120,13 +99,13 @@ def get_data(filters): get_system_timezone(), ) + # Filter out queries starting with `SET` + dql_stmt = ["SELECT", "UPDATE", "DELETE", "INSERT"] + rows = [x for x in rows if any(x["query"].startswith(stmt) for stmt in dql_stmt)] + if filters.normalize_queries: rows = summarize_by_query(rows) - # You can not analyze a query unless it has been normalized. - if filters.analyze: - rows = analyze_queries(rows, filters.site) - return rows @@ -211,111 +190,5 @@ def summarize_by_query(data): return result -def analyze_queries(data, site): - # TODO: handle old framework and old agents and general failures - for row in data: - query = row["example"] - if not query.lower().startswith(("select", "update", "delete")): - continue - analyzer = OptimizeDatabaseQuery(site, query) - if index := analyzer.analyze(): - row["suggested_index"] = f"{index.table}.{index.column}" - return data - - -@dataclass -class OptimizeDatabaseQuery: - site: str - query: str - - def analyze(self) -> DBIndex | None: - explain_output = self.fetch_explain() or [] - - explain_output = [DBExplain.from_frappe_ouput(e) for e in explain_output] - optimizer = DBOptimizer(query=self.query, explain_plan=explain_output) - tables = optimizer.tables_examined - - for table in tables: - stats = _fetch_table_stats(self.site, table) - if not stats: - # Old framework version - return None - db_table = DBTable.from_frappe_ouput(stats) - column_stats = _fetch_column_stats(self.site, table) - if not column_stats: - # Failing due to large size, TODO: move this to a job - return None - db_table.update_cardinality(column_stats) - optimizer.update_table_data(db_table) - - return optimizer.suggest_index() - - def fetch_explain(self) -> list[dict]: - site = frappe.get_cached_doc("Site", self.site) - db_server_name = frappe.db.get_value("Server", site.server, "database_server", cache=True) - database_server = frappe.get_cached_doc("Database Server", db_server_name) - agent = Agent(database_server.name, "Database Server") - - data = { - "schema": site.database_name, - "query": self.query, - "private_ip": database_server.private_ip, - "mariadb_root_password": database_server.get_password("mariadb_root_password"), - } - - return agent.post("database/explain", data=data) - - -@redis_cache(ttl=60 * 5) -def _fetch_table_stats(site: str, table: str): - site = frappe.get_cached_doc("Site", site) - agent = Agent(site.server) - return agent.describe_database_table( - site, - doctype=get_doctype_name(table), - columns=[], - ) - - -@redis_cache(ttl=60 * 5) -def _fetch_column_stats(site, table, doc_name): - site = frappe.get_cached_doc("Site", site) - db_server_name = frappe.db.get_value("Server", site.server, "database_server", cache=True) - database_server = frappe.get_cached_doc("Database Server", db_server_name) - agent = Agent(database_server.name, "Database Server") - - data = { - # "site": site, - "doc_name": doc_name, - "schema": site.database_name, - "table": table, - "private_ip": database_server.private_ip, - "mariadb_root_password": database_server.get_password("mariadb_root_password"), - } - agent.create_agent_job("Column Statistics", "/database/column-stats", data) - - def get_doctype_name(table_name: str) -> str: return table_name.removeprefix("tab") - - -@frappe.whitelist() -@protected("Site") -def add_suggested_index(name, indexes): - if isinstance(indexes, str): - indexes = json.loads(indexes) - frappe.enqueue(_add_suggested_index, indexes=indexes, site_name=name) - - -def _add_suggested_index(site_name, indexes): - if not indexes: - frappe.throw("No index suggested") - - for index in indexes: - table, column = index.split(".") - doctype = get_doctype_name(table) - - site = frappe.get_cached_doc("Site", site_name) - agent = Agent(site.server) - agent.add_database_index(site, doctype=doctype, columns=[column]) - frappe.msgprint(f"Index {index} added on site {site_name} successfully", realtime=True) diff --git a/press/press/report/mariadb_slow_queries/test_db_optimizer.py b/press/press/report/mariadb_slow_queries/test_db_optimizer.py deleted file mode 100644 index 65eead5535..0000000000 --- a/press/press/report/mariadb_slow_queries/test_db_optimizer.py +++ /dev/null @@ -1,618 +0,0 @@ -# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors -# License: MIT. See LICENSE - -import json - -from frappe.tests.utils import FrappeTestCase - -from press.press.report.mariadb_slow_queries.db_optimizer import ( - DBExplain, - DBOptimizer, - DBTable, -) - - -class TestDBOptimizer(FrappeTestCase): - def test_basic_index_existence_analysis(self): - def possible_indexes(q): - user = DBTable.from_frappe_ouput(USER_TABLE) - has_role = DBTable.from_frappe_ouput(HAS_ROLE_TABLE) - return [ - i.column - for i in DBOptimizer( - query=q, - tables={"tabUser": user, "tabHas Role": has_role}, - ).potential_indexes() - ] - - self.assertEqual( - ["creation"], - possible_indexes("select `name` from `tabUser` order by `creation` desc limit 1"), - ) - - self.assertEqual( - ["full_name"], - possible_indexes("select `name` from `tabUser` where full_name = 'xyz'"), - ) - - self.assertIn( - "user", - possible_indexes( - "select `name` from `tabUser` u join `tabHas Role` h on h.user = u.name" - ), - ) - - def test_suggestion_using_table_stats(self): - user = DBTable.from_frappe_ouput(USER_TABLE) - has_role = DBTable.from_frappe_ouput(HAS_ROLE_TABLE) - - tables = {"tabUser": user, "tabHas Role": has_role} - self.assertEqual(user.total_rows, 92) - - # This should suggest adding api_key as it definitely has highest cardinality. - optimizer = DBOptimizer( - query="select name from tabUser where enabled = 1 and api_key = 'xyz'", tables=tables - ) - self.assertIn("api_key", [i.column for i in optimizer.potential_indexes()]) - - index = optimizer.suggest_index() - self.assertEqual(index.column, "api_key") - - # This should suggest nothing as modified is already indexed - optimizer = DBOptimizer( - query="select name from tabUser order by modified asc", - tables=tables, - ) - self.assertIsNone(optimizer.suggest_index()) - - # This should suggest nothing as modified is already indexed - optimizer = DBOptimizer( - query="select name from tabUser u join `tabHas Role` r on r.parent = u.name where r.role='System Manager'", - tables=tables, - ) - index = optimizer.suggest_index() - self.assertEqual(index.column, "role") - self.assertEqual(index.table, "tabHas Role") - - def test_complex_sub_query_aliases(self): - """Check if table identification is correct for subqueries.""" - - q = """SELECT *, - (SELECT COUNT(*) FROM `tabHD Ticket Comment` WHERE `tabHD Ticket Comment`.`reference_ticket`=`tabHD Ticket`.`name`) `count_comment`, - (SELECT COUNT(*) FROM `tabCommunication` WHERE `tabCommunication`.`reference_doctype`='HD Ticket' AND `tabCommunication`.`reference_name`=`tabHD Ticket`.`name`) `count_msg`, - FROM `tabHD Ticket` - WHERE `agent_group`='L2' - ORDER BY `modified` DESC - LIMIT 20 - """ - explain = [DBExplain.from_frappe_ouput(e) for e in json.loads(EXPLAIN_OUTPUT)] - optimizer = DBOptimizer(query=q, explain_plan=explain) - optimizer.update_table_data(DBTable.from_frappe_ouput(HD_TICKET_TABLE)) - optimizer.update_table_data(DBTable.from_frappe_ouput(HD_TICKET_COMMENT_TABLE)) - optimizer.update_table_data(DBTable.from_frappe_ouput(COMMUNICATION_TABLE)) - - self.assertTrue(optimizer.can_be_optimized()) - index = optimizer.suggest_index() - self.assertEqual(index.table, "tabHD Ticket Comment") - self.assertEqual(index.column, "reference_ticket") - - -# Table stats extracted using describe-database-table for testing. - -USER_TABLE = { - "table_name": "tabUser", - "total_rows": 92, - "schema": [ - { - "column": "name", - "type": "varchar(140)", - "is_nullable": False, - "default": None, - "cardinality": 91, - }, - {"column": "creation", "type": "datetime(6)", "is_nullable": True, "default": None}, - { - "column": "modified", - "type": "datetime(6)", - "is_nullable": True, - "default": None, - "cardinality": 91, - }, - { - "column": "modified_by", - "type": "varchar(140)", - "is_nullable": True, - "default": None, - }, - {"column": "owner", "type": "varchar(140)", "is_nullable": True, "default": None}, - {"column": "docstatus", "type": "int(1)", "is_nullable": False, "default": "0"}, - {"column": "idx", "type": "int(8)", "is_nullable": False, "default": "0"}, - {"column": "enabled", "type": "int(1)", "is_nullable": False, "default": "1"}, - {"column": "email", "type": "varchar(140)", "is_nullable": False, "default": ""}, - { - "column": "first_name", - "type": "varchar(140)", - "is_nullable": True, - "default": None, - "cardinality": 88, - }, - { - "column": "reset_password_key", - "type": "varchar(140)", - "is_nullable": True, - "default": None, - "cardinality": 84, - }, - { - "column": "user_type", - "type": "varchar(140)", - "is_nullable": True, - "default": "System User", - "cardinality": 2, - }, - { - "column": "api_key", - "type": "varchar(140)", - "is_nullable": True, - "default": None, - "cardinality": 70, - }, - {"column": "api_secret", "type": "text", "is_nullable": True, "default": None}, - {"column": "_user_tags", "type": "text", "is_nullable": True, "default": None}, - {"column": "_comments", "type": "text", "is_nullable": True, "default": None}, - {"column": "_assign", "type": "text", "is_nullable": True, "default": None}, - {"column": "_liked_by", "type": "text", "is_nullable": True, "default": None}, - ], - "indexes": [ - { - "unique": True, - "cardinality": 91, - "name": "PRIMARY", - "sequence": 1, - "nullable": False, - "column": "name", - "type": "BTREE", - }, - { - "unique": True, - "cardinality": 91, - "name": "username", - "sequence": 1, - "nullable": True, - "column": "username", - "type": "BTREE", - }, - { - "unique": False, - "cardinality": 91, - "name": "modified", - "sequence": 1, - "nullable": True, - "column": "modified", - "type": "BTREE", - }, - { - "unique": False, - "cardinality": 91, - "name": "reset_password_key_index", - "sequence": 1, - "nullable": True, - "column": "reset_password_key", - "type": "BTREE", - }, - ], -} - - -HAS_ROLE_TABLE = { - "table_name": "tabHas Role", - "total_rows": 96, - "schema": [ - { - "column": "name", - "type": "varchar(140)", - "is_nullable": "NO", - "default": None, - "cardinality": 92, - }, - {"column": "creation", "type": "datetime(6)", "is_nullable": "YES", "default": None}, - {"column": "modified", "type": "datetime(6)", "is_nullable": "YES", "default": None}, - { - "column": "modified_by", - "type": "varchar(140)", - "is_nullable": "YES", - "default": None, - }, - {"column": "owner", "type": "varchar(140)", "is_nullable": "YES", "default": None}, - {"column": "docstatus", "type": "int(1)", "is_nullable": "NO", "default": "0"}, - {"column": "idx", "type": "int(8)", "is_nullable": "NO", "default": "0"}, - { - "column": "role", - "type": "varchar(140)", - "is_nullable": "YES", - "default": None, - "cardinality": 78, - }, - { - "column": "parent", - "type": "varchar(140)", - "is_nullable": "YES", - "default": None, - "cardinality": 92, - }, - { - "column": "parentfield", - "type": "varchar(140)", - "is_nullable": "YES", - "default": None, - }, - { - "column": "parenttype", - "type": "varchar(140)", - "is_nullable": "YES", - "default": None, - }, - ], - "indexes": [ - { - "unique": True, - "cardinality": 92, - "name": "PRIMARY", - "sequence": 1, - "nullable": "", - "column": "name", - "type": "BTREE", - }, - { - "unique": False, - "cardinality": 92, - "name": "parent", - "sequence": 1, - "nullable": "YES", - "column": "parent", - "type": "BTREE", - }, - ], -} - - -HD_TICKET_TABLE = { - "table_name": "tabHD Ticket", - "total_rows": 3820, - "schema": [ - { - "column": "name", - "type": "bigint(20)", - "is_nullable": False, - "default": None, - "cardinality": 3529, - }, - {"column": "creation", "type": "datetime(6)", "is_nullable": True, "default": None}, - { - "column": "modified", - "type": "datetime(6)", - "is_nullable": True, - "default": None, - "cardinality": 3529, - }, - { - "column": "modified_by", - "type": "varchar(140)", - "is_nullable": True, - "default": None, - }, - {"column": "owner", "type": "varchar(140)", "is_nullable": True, "default": None}, - {"column": "docstatus", "type": "int(1)", "is_nullable": False, "default": "0"}, - {"column": "idx", "type": "int(8)", "is_nullable": False, "default": "0"}, - {"column": "subject", "type": "varchar(140)", "is_nullable": True, "default": None}, - {"column": "raised_by", "type": "varchar(140)", "is_nullable": True, "default": None}, - { - "column": "status", - "type": "varchar(140)", - "is_nullable": True, - "default": "Open", - "cardinality": 8, - }, - {"column": "priority", "type": "varchar(140)", "is_nullable": True, "default": None}, - { - "column": "ticket_type", - "type": "varchar(140)", - "is_nullable": True, - "default": None, - }, - { - "column": "agent_group", - "type": "varchar(140)", - "is_nullable": True, - "default": "L1", - "cardinality": 9, - }, - { - "column": "ticket_split_from", - "type": "varchar(140)", - "is_nullable": True, - "default": None, - }, - {"column": "description", "type": "longtext", "is_nullable": True, "default": None}, - {"column": "template", "type": "varchar(140)", "is_nullable": True, "default": None}, - {"column": "sla", "type": "varchar(140)", "is_nullable": True, "default": None}, - { - "column": "response_by", - "type": "datetime(6)", - "is_nullable": True, - "default": None, - }, - { - "column": "response_by_variance", - "type": "decimal(21,9)", - "is_nullable": True, - "default": None, - }, - { - "column": "agreement_status", - "type": "varchar(140)", - "is_nullable": True, - "default": None, - }, - { - "column": "resolution_by", - "type": "datetime(6)", - "is_nullable": True, - "default": None, - }, - { - "column": "resolution_by_variance", - "type": "decimal(21,9)", - "is_nullable": True, - "default": None, - }, - { - "column": "service_level_agreement_creation", - "type": "datetime(6)", - "is_nullable": True, - "default": None, - }, - { - "column": "on_hold_since", - "type": "datetime(6)", - "is_nullable": True, - "default": None, - }, - { - "column": "total_hold_time", - "type": "decimal(21,9)", - "is_nullable": True, - "default": None, - }, - { - "column": "first_response_time", - "type": "decimal(21,9)", - "is_nullable": True, - "default": None, - }, - { - "column": "first_responded_on", - "type": "datetime(6)", - "is_nullable": True, - "default": None, - }, - { - "column": "avg_response_time", - "type": "decimal(21,9)", - "is_nullable": True, - "default": None, - }, - { - "column": "resolution_details", - "type": "longtext", - "is_nullable": True, - "default": None, - }, - {"column": "opening_date", "type": "date", "is_nullable": True, "default": None}, - {"column": "opening_time", "type": "time(6)", "is_nullable": True, "default": None}, - { - "column": "resolution_date", - "type": "datetime(6)", - "is_nullable": True, - "default": None, - }, - { - "column": "resolution_time", - "type": "decimal(21,9)", - "is_nullable": True, - "default": None, - }, - { - "column": "user_resolution_time", - "type": "decimal(21,9)", - "is_nullable": True, - "default": None, - }, - {"column": "contact", "type": "varchar(140)", "is_nullable": True, "default": None}, - {"column": "customer", "type": "varchar(140)", "is_nullable": True, "default": None}, - { - "column": "email_account", - "type": "varchar(140)", - "is_nullable": True, - "default": None, - }, - {"column": "attachment", "type": "text", "is_nullable": True, "default": None}, - {"column": "_user_tags", "type": "text", "is_nullable": True, "default": None}, - {"column": "_comments", "type": "text", "is_nullable": True, "default": None}, - {"column": "_assign", "type": "text", "is_nullable": True, "default": None}, - {"column": "_liked_by", "type": "text", "is_nullable": True, "default": None}, - {"column": "_seen", "type": "text", "is_nullable": True, "default": None}, - ], - "indexes": [ - { - "unique": True, - "cardinality": 3529, - "name": "PRIMARY", - "sequence": 1, - "nullable": False, - "column": "name", - "type": "BTREE", - }, - { - "unique": False, - "cardinality": 8, - "name": "status", - "sequence": 1, - "nullable": True, - "column": "status", - "type": "BTREE", - }, - { - "unique": False, - "cardinality": 3529, - "name": "modified", - "sequence": 1, - "nullable": True, - "column": "modified", - "type": "BTREE", - }, - ], -} - - -HD_TICKET_COMMENT_TABLE = { - "table_name": "tabHD Ticket Comment", - "total_rows": 2683, - "schema": [ - { - "column": "name", - "type": "varchar(140)", - "is_nullable": False, - "default": None, - "cardinality": 2683, - }, - {"column": "creation", "type": "datetime(6)", "is_nullable": True, "default": None}, - { - "column": "modified", - "type": "datetime(6)", - "is_nullable": True, - "default": None, - "cardinality": 2345, - }, - { - "column": "reference_ticket", - "type": "varchar(140)", - "is_nullable": True, - "default": None, - "cardinality": 1379, - }, - { - "column": "commented_by", - "type": "varchar(140)", - "is_nullable": True, - "default": None, - }, - {"column": "content", "type": "longtext", "is_nullable": True, "default": None}, - {"column": "is_pinned", "type": "int(1)", "is_nullable": False, "default": "0"}, - ], - "indexes": [ - { - "unique": True, - "cardinality": 2345, - "name": "PRIMARY", - "sequence": 1, - "nullable": False, - "column": "name", - "type": "BTREE", - }, - { - "unique": False, - "cardinality": 2345, - "name": "modified", - "sequence": 1, - "nullable": True, - "column": "modified", - "type": "BTREE", - }, - ], -} - - -COMMUNICATION_TABLE = { - "table_name": "tabCommunication", - "total_rows": 20727, - "schema": [ - { - "column": "name", - "type": "varchar(140)", - "is_nullable": False, - "default": None, - "cardinality": 19713, - }, - {"column": "creation", "type": "datetime(6)", "is_nullable": True, "default": None}, - { - "column": "modified", - "type": "datetime(6)", - "is_nullable": True, - "default": None, - "cardinality": 19713, - }, - { - "column": "reference_doctype", - "type": "varchar(140)", - "is_nullable": True, - "default": None, - "cardinality": 1, - }, - { - "column": "reference_name", - "type": "varchar(140)", - "is_nullable": True, - "default": None, - "cardinality": 3798, - }, - { - "column": "reference_owner", - "type": "varchar(140)", - "is_nullable": True, - "default": None, - "cardinality": 1314, - }, - ], - "indexes": [ - { - "unique": True, - "cardinality": 19713, - "name": "PRIMARY", - "sequence": 1, - "nullable": False, - "column": "name", - "type": "BTREE", - }, - { - "unique": False, - "cardinality": 19713, - "name": "modified", - "sequence": 1, - "nullable": True, - "column": "modified", - "type": "BTREE", - }, - { - "unique": False, - "cardinality": 2, - "name": "reference_doctype_reference_name_index", - "sequence": 1, - "nullable": True, - "column": "reference_doctype", - "type": "BTREE", - }, - { - "unique": False, - "cardinality": 9856, - "name": "reference_doctype_reference_name_index", - "sequence": 2, - "nullable": True, - "column": "reference_name", - "type": "BTREE", - }, - ], -} - - -EXPLAIN_OUTPUT = """[{"Extra": "", "id": 1, "key": "modified", "key_len": "9", "possible_keys": null, "ref": null, "rows": "20", "select_type": "PRIMARY", "table": "tabHD Ticket", "type": "index"}, {"Extra": "Using index condition; Using where", "id": 4, "key": "reference_doctype_reference_name_index", "key_len": "563", "possible_keys": "reference_doctype_reference_name_index", "ref": "const", "rows": "10236", "select_type": "DEPENDENT SUBQUERY", "table": "tabCommunication", "type": "ref"}, {"Extra": "Using index condition; Using where", "id": 3, "key": "reference_doctype_reference_name_index", "key_len": "563", "possible_keys": "reference_doctype_reference_name_index", "ref": "const", "rows": "10236", "select_type": "DEPENDENT SUBQUERY", "table": "tabCommunication", "type": "ref"}, {"Extra": "Using where; Using index", "id": 2, "key": "reference_ticket_index", "key_len": "563", "possible_keys": "reference_ticket_index", "ref": null, "rows": "2823", "select_type": "DEPENDENT SUBQUERY", "table": "tabHD Ticket Comment", "type": "index"}]""" diff --git a/press/utils/__init__.py b/press/utils/__init__.py index 5d40ae330c..4f05b1190d 100644 --- a/press/utils/__init__.py +++ b/press/utils/__init__.py @@ -6,21 +6,29 @@ import functools import json import re +import socket +import ssl import time from datetime import datetime, timedelta from pathlib import Path from typing import TypedDict, TypeVar from urllib.parse import urljoin +from urllib.request import urlopen import frappe import pytz import requests import wrapt from babel.dates import format_timedelta +from cryptography import x509 +from cryptography.hazmat.backends import default_backend +from cryptography.x509.oid import ExtensionOID from frappe.utils import get_datetime, get_system_timezone from frappe.utils.caching import site_cache from pymysql.err import InterfaceError +from press.utils.email_validator import validate_email + class SupervisorProcess(TypedDict): program: str @@ -840,3 +848,51 @@ def get_mariadb_root_password(site): field = "mariadb_root_password" return get_decrypted_password(doctype, name, field) + + +def is_valid_email_address(email) -> bool: + if frappe.cache.exists(f"email_validity:{email}"): + return bool(frappe.utils.data.cint(frappe.cache.get_value(f"email_validity:{email}"))) + try: + is_valid = bool(validate_email(email=email, check_mx=True, verify=True, smtp_timeout=10)) + frappe.cache.set_value(f"email_validity:{email}", int(is_valid), expires_in_sec=3600) + if not is_valid: + log_error("Invalid email address on signup", data=email) + return bool(is_valid) + except Exception as e: + log_error("Email validation error on signup", data=e) + frappe.cache.set_value(f"email_validity:{email}", 0, expires_in_sec=3600) + return False + + +def get_full_chain_cert_of_domain(domain: str) -> str: + cert_chain = [] + + # Get initial certificate + context = ssl.create_default_context() + with socket.create_connection((domain, 443)) as sock: # noqa: SIM117 + with context.wrap_socket(sock, server_hostname=domain) as ssl_socket: + cert_pem = ssl.DER_cert_to_PEM_cert(ssl_socket.getpeercert(True)) + cert = x509.load_pem_x509_certificate(cert_pem.encode(), default_backend()) + cert_chain.append(cert_pem) + + # Walk up the chain via certificate authority information access (AIA) + while True: + try: + aia = cert.extensions.get_extension_for_oid(ExtensionOID.AUTHORITY_INFORMATION_ACCESS) + for access in aia.value: + if access.access_method._name == "caIssuers": + uri = access.access_location._value + with urlopen(uri) as response: + der_cert = response.read() + pem_cert = ssl.DER_cert_to_PEM_cert(der_cert) + cert = x509.load_pem_x509_certificate(pem_cert.encode(), default_backend()) + cert_chain.append(pem_cert) + break + except: # noqa: E722 + break + + cert_chain_str = "" + for cert in cert_chain: + cert_chain_str += cert + "\n" + return cert_chain_str diff --git a/press/utils/email_validator.py b/press/utils/email_validator.py new file mode 100644 index 0000000000..5cc03fb7e1 --- /dev/null +++ b/press/utils/email_validator.py @@ -0,0 +1,170 @@ +""" +Customized function of validate-email package + +RFC 2822 - style email validation for Python + +(c) 2012 Syrus Akbary +Extended from (c) 2011 Noel Bush for support of mx and user check + +This code is made available to you under the GNU LGPLv3. + +This module provides a single method, valid_email_address(), which returns True or False to indicate +whether a given address is valid according to the 'addr-spec' part of the specification given in RFC +2822. Ideally, we would like to find this in some other library, already thoroughly tested and +well-maintained. The standard Python library email.utils contains a parse_addr() function, but it +is not sufficient to detect many malformed addresses. + +This implementation aims to be faithful to the RFC, with the +exception of a circular definition (see comments below), and +with the omission of the pattern components marked as "obsolete". +""" + +import contextlib +import re +import smtplib + +from dns.resolver import Resolver + +# All we are really doing is comparing the input string to one +# gigantic regular expression. But building that regexp, and +# ensuring its correctness, is made much easier by assembling it +# from the "tokens" defined by the RFC. Each of these tokens is +# tested in the accompanying unit test file. +# +# The section of RFC 2822 from which each pattern component is +# derived is given in an accompanying comment. +# +# (To make things simple, every string below is given as 'raw', +# even when it's not strictly necessary. This way we don't forget +# when it is necessary.) + +WSP = r"[ \t]" # see 2.2.2. Structured Header Field Bodies +CRLF = r"(?:\r\n)" # see 2.2.3. Long Header Fields +NO_WS_CTL = r"\x01-\x08\x0b\x0c\x0f-\x1f\x7f" # see 3.2.1. Primitive Tokens +QUOTED_PAIR = r"(?:\\.)" # see 3.2.2. Quoted characters +FWS = r"(?:(?:" + WSP + r"*" + CRLF + r")?" + WSP + r"+)" # see 3.2.3. Folding white space and comments +CTEXT = r"[" + NO_WS_CTL + r"\x21-\x27\x2a-\x5b\x5d-\x7e]" # see 3.2.3 +CCONTENT = r"(?:" + CTEXT + r"|" + QUOTED_PAIR + r")" # see 3.2.3 (NB: The RFC includes COMMENT here +# as well, but that would be circular.) +COMMENT = r"\((?:" + FWS + r"?" + CCONTENT + r")*" + FWS + r"?\)" # see 3.2.3 +CFWS = r"(?:" + FWS + r"?" + COMMENT + ")*(?:" + FWS + "?" + COMMENT + "|" + FWS + ")" # see 3.2.3 +ATEXT = r"[\w!#$%&\'\*\+\-/=\?\^`\{\|\}~]" # see 3.2.4. Atom +ATOM = CFWS + r"?" + ATEXT + r"+" + CFWS + r"?" # see 3.2.4 +DOT_ATOM_TEXT = ATEXT + r"+(?:\." + ATEXT + r"+)*" # see 3.2.4 +DOT_ATOM = CFWS + r"?" + DOT_ATOM_TEXT + CFWS + r"?" # see 3.2.4 +QTEXT = r"[" + NO_WS_CTL + r"\x21\x23-\x5b\x5d-\x7e]" # see 3.2.5. Quoted strings +QCONTENT = r"(?:" + QTEXT + r"|" + QUOTED_PAIR + r")" # see 3.2.5 +QUOTED_STRING = CFWS + r"?" + r'"(?:' + FWS + r"?" + QCONTENT + r")*" + FWS + r"?" + r'"' + CFWS + r"?" +LOCAL_PART = r"(?:" + DOT_ATOM + r"|" + QUOTED_STRING + r")" # see 3.4.1. Addr-spec specification +DTEXT = r"[" + NO_WS_CTL + r"\x21-\x5a\x5e-\x7e]" # see 3.4.1 +DCONTENT = r"(?:" + DTEXT + r"|" + QUOTED_PAIR + r")" # see 3.4.1 +DOMAIN_LITERAL = ( + CFWS + r"?" + r"\[" + r"(?:" + FWS + r"?" + DCONTENT + r")*" + FWS + r"?\]" + CFWS + r"?" +) # see 3.4.1 +DOMAIN = r"(?:" + DOT_ATOM + r"|" + DOMAIN_LITERAL + r")" # see 3.4.1 +ADDR_SPEC = LOCAL_PART + r"@" + DOMAIN # see 3.4.1 + +# A valid address will match exactly the 3.4.1 addr-spec. +VALID_ADDRESS_REGEXP = re.compile(r"^" + ADDR_SPEC + r"$") + +MX_DNS_CACHE = {} +MX_CHECK_CACHE = {} + + +def get_mx_ip(mx_host): + """ + Get the IP address of a given MX host + + :param mx_host: The host being looked up + :type mx_host: str + :return: A list of IP addresses + :rtype: list + """ + if mx_host not in MX_DNS_CACHE: + try: + resolver = Resolver(configure=False) + resolver.nameservers = ["1.1.1.1", "1.0.0.1", "8.8.8.8", "8.8.4.4"] + answers = resolver.query(mx_host, "MX") + + mx_lookup_result = [] + + for answer in answers: + mx_lookup_result.append((answer.preference, answer.exchange.to_text()[:-1])) + MX_DNS_CACHE[mx_host] = mx_lookup_result + except Exception: + raise + return MX_DNS_CACHE[mx_host] + + +def check_mx_record(email, verify=False, smtp_timeout=10): + """ + Checks for an MX record on the given email addresses' hostname. + + :param email: The email address + :type email: str + :param verify: Whether the email address' existence should be verified + :type verify: bool + :param smtp_timeout: Maximum wait time on an SMTP connection + :type smtp_timeout: int + :return: bool or None + """ + hostname = email[email.find("@") + 1 :] + mx_hosts = get_mx_ip(hostname) + if mx_hosts is None: + return False + for mx_host in mx_hosts: + with contextlib.suppress(Exception): + if not verify and mx_host[1] in MX_CHECK_CACHE: + return MX_CHECK_CACHE[mx_host[1]] + smtp = smtplib.SMTP(timeout=smtp_timeout) + smtp.connect(mx_host[1]) + MX_CHECK_CACHE[mx_host[1]] = True + if not verify: + try: # noqa: SIM105 + smtp.quit() + except smtplib.SMTPServerDisconnected: + pass + return True + status, _ = smtp.helo() + if status != 250: + smtp.quit() + continue + smtp.mail("") + status, _ = smtp.rcpt(email) + if status == 250: + smtp.quit() + return True + smtp.quit() + return None + + +def validate_email(email, check_mx=False, verify=False, smtp_timeout=10, **kwargs): + """ + Indicate whether the given string is a valid email address according to the 'addr-spec' portion + of RFC 2822 (see section 3.4.1). Parts of the spec that are marked obsolete are *not* included + in this test, and certain arcane constructions that depend on circular definitions in the spec + may not pass, but in general this should correctly identify any email address likely to be in + use as of 2011. + + :param email: The email address to be validated + :type email: str + :param check_mx: Whether or not MX records should be verified + :type check_mx: bool + :param verify: Whether or not the email addresses' actual existence should be verified + :type verify: bool + :param smtp_timeout: Maximum wait time on an SMTP connection + :type smtp_timeout: int + :return: The validity of the given email address + :rtype: bool or None + """ + try: + if re.match(VALID_ADDRESS_REGEXP, email) is not None: + check_mx |= verify + if check_mx: + return check_mx_record(email, verify=verify, smtp_timeout=smtp_timeout) + else: + return False + except Exception: + return None + else: + return True diff --git a/setup-pre-commit.sh b/setup-pre-commit.sh new file mode 100755 index 0000000000..7448d6c743 --- /dev/null +++ b/setup-pre-commit.sh @@ -0,0 +1,15 @@ +# !/usr/bin/env bash + +echo "Installing python dev dependencies" +pip install -r dev-requirements.txt + +echo "Installing nodejs dev dependencies" +yarn install --frozen-lockfile --dev + +echo "Setting up pre-commit hooks" +pre-commit install + +echo "Setting up commit-msg hooks" +pre-commit install -t commit-msg + +echo "Setup complete" \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 3fcc5b1c88..446208a131 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4,7 +4,7 @@ "@alloc/quick-lru@^5.2.0": version "5.2.0" - resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" + resolved "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz" integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== "@babel/code-frame@^7.0.0": @@ -15,9 +15,9 @@ "@babel/highlight" "^7.14.5" "@babel/helper-validator-identifier@^7.14.5": - version "7.14.9" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz" - integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g== + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== "@babel/highlight@^7.14.5": version "7.14.5" @@ -28,16 +28,566 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@commitlint/cli@^19.6.1": + version "19.6.1" + resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-19.6.1.tgz#24edd26595d911cc6b680cdfbb1fb083bfd5f73d" + integrity sha512-8hcyA6ZoHwWXC76BoC8qVOSr8xHy00LZhZpauiD0iO0VYbVhMnED0da85lTfIULxl7Lj4c6vZgF0Wu/ed1+jlQ== + dependencies: + "@commitlint/format" "^19.5.0" + "@commitlint/lint" "^19.6.0" + "@commitlint/load" "^19.6.1" + "@commitlint/read" "^19.5.0" + "@commitlint/types" "^19.5.0" + tinyexec "^0.3.0" + yargs "^17.0.0" + +"@commitlint/config-conventional@^19.6.0": + version "19.6.0" + resolved "https://registry.yarnpkg.com/@commitlint/config-conventional/-/config-conventional-19.6.0.tgz#badba72c8639ea79291e2941001bd7ea7fad3a2c" + integrity sha512-DJT40iMnTYtBtUfw9ApbsLZFke1zKh6llITVJ+x9mtpHD08gsNXaIRqHTmwTZL3dNX5+WoyK7pCN/5zswvkBCQ== + dependencies: + "@commitlint/types" "^19.5.0" + conventional-changelog-conventionalcommits "^7.0.2" + +"@commitlint/config-validator@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/config-validator/-/config-validator-19.5.0.tgz#f0a4eda2109fc716ef01bb8831af9b02e3a1e568" + integrity sha512-CHtj92H5rdhKt17RmgALhfQt95VayrUo2tSqY9g2w+laAXyk7K/Ef6uPm9tn5qSIwSmrLjKaXK9eiNuxmQrDBw== + dependencies: + "@commitlint/types" "^19.5.0" + ajv "^8.11.0" + +"@commitlint/ensure@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/ensure/-/ensure-19.5.0.tgz#b087374a6a0a0140e5925a82901d234885d9f6dd" + integrity sha512-Kv0pYZeMrdg48bHFEU5KKcccRfKmISSm9MvgIgkpI6m+ohFTB55qZlBW6eYqh/XDfRuIO0x4zSmvBjmOwWTwkg== + dependencies: + "@commitlint/types" "^19.5.0" + lodash.camelcase "^4.3.0" + lodash.kebabcase "^4.1.1" + lodash.snakecase "^4.1.1" + lodash.startcase "^4.4.0" + lodash.upperfirst "^4.3.1" + +"@commitlint/execute-rule@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/execute-rule/-/execute-rule-19.5.0.tgz#c13da8c03ea0379f30856111e27d57518e25b8a2" + integrity sha512-aqyGgytXhl2ejlk+/rfgtwpPexYyri4t8/n4ku6rRJoRhGZpLFMqrZ+YaubeGysCP6oz4mMA34YSTaSOKEeNrg== + +"@commitlint/format@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/format/-/format-19.5.0.tgz#d879db2d97d70ae622397839fb8603d56e85a250" + integrity sha512-yNy088miE52stCI3dhG/vvxFo9e4jFkU1Mj3xECfzp/bIS/JUay4491huAlVcffOoMK1cd296q0W92NlER6r3A== + dependencies: + "@commitlint/types" "^19.5.0" + chalk "^5.3.0" + +"@commitlint/is-ignored@^19.6.0": + version "19.6.0" + resolved "https://registry.yarnpkg.com/@commitlint/is-ignored/-/is-ignored-19.6.0.tgz#6adb9097d36b68e00b9c06a73d7a08e9f54c54dc" + integrity sha512-Ov6iBgxJQFR9koOupDPHvcHU9keFupDgtB3lObdEZDroiG4jj1rzky60fbQozFKVYRTUdrBGICHG0YVmRuAJmw== + dependencies: + "@commitlint/types" "^19.5.0" + semver "^7.6.0" + +"@commitlint/lint@^19.6.0": + version "19.6.0" + resolved "https://registry.yarnpkg.com/@commitlint/lint/-/lint-19.6.0.tgz#f9fc9b11b808c96bd3f85e882e056daabac40c36" + integrity sha512-LRo7zDkXtcIrpco9RnfhOKeg8PAnE3oDDoalnrVU/EVaKHYBWYL1DlRR7+3AWn0JiBqD8yKOfetVxJGdEtZ0tg== + dependencies: + "@commitlint/is-ignored" "^19.6.0" + "@commitlint/parse" "^19.5.0" + "@commitlint/rules" "^19.6.0" + "@commitlint/types" "^19.5.0" + +"@commitlint/load@^19.6.1": + version "19.6.1" + resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-19.6.1.tgz#5fae8843a6048a2d3d1cc16da0af8ee532fa9db4" + integrity sha512-kE4mRKWWNju2QpsCWt428XBvUH55OET2N4QKQ0bF85qS/XbsRGG1MiTByDNlEVpEPceMkDr46LNH95DtRwcsfA== + dependencies: + "@commitlint/config-validator" "^19.5.0" + "@commitlint/execute-rule" "^19.5.0" + "@commitlint/resolve-extends" "^19.5.0" + "@commitlint/types" "^19.5.0" + chalk "^5.3.0" + cosmiconfig "^9.0.0" + cosmiconfig-typescript-loader "^6.1.0" + lodash.isplainobject "^4.0.6" + lodash.merge "^4.6.2" + lodash.uniq "^4.5.0" + +"@commitlint/message@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/message/-/message-19.5.0.tgz#c062d9a1d2b3302c3a8cac25d6d1125ea9c019b2" + integrity sha512-R7AM4YnbxN1Joj1tMfCyBryOC5aNJBdxadTZkuqtWi3Xj0kMdutq16XQwuoGbIzL2Pk62TALV1fZDCv36+JhTQ== + +"@commitlint/parse@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/parse/-/parse-19.5.0.tgz#b450dad9b5a95ac5ba472d6d0fdab822dce946fc" + integrity sha512-cZ/IxfAlfWYhAQV0TwcbdR1Oc0/r0Ik1GEessDJ3Lbuma/MRO8FRQX76eurcXtmhJC//rj52ZSZuXUg0oIX0Fw== + dependencies: + "@commitlint/types" "^19.5.0" + conventional-changelog-angular "^7.0.0" + conventional-commits-parser "^5.0.0" + +"@commitlint/read@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/read/-/read-19.5.0.tgz#601f9f1afe69852b0f28aa81cd455b40979fad6b" + integrity sha512-TjS3HLPsLsxFPQj6jou8/CZFAmOP2y+6V4PGYt3ihbQKTY1Jnv0QG28WRKl/d1ha6zLODPZqsxLEov52dhR9BQ== + dependencies: + "@commitlint/top-level" "^19.5.0" + "@commitlint/types" "^19.5.0" + git-raw-commits "^4.0.0" + minimist "^1.2.8" + tinyexec "^0.3.0" + +"@commitlint/resolve-extends@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/resolve-extends/-/resolve-extends-19.5.0.tgz#f3ec33e12d10df90cae0bfad8e593431fb61b18e" + integrity sha512-CU/GscZhCUsJwcKTJS9Ndh3AKGZTNFIOoQB2n8CmFnizE0VnEuJoum+COW+C1lNABEeqk6ssfc1Kkalm4bDklA== + dependencies: + "@commitlint/config-validator" "^19.5.0" + "@commitlint/types" "^19.5.0" + global-directory "^4.0.1" + import-meta-resolve "^4.0.0" + lodash.mergewith "^4.6.2" + resolve-from "^5.0.0" + +"@commitlint/rules@^19.6.0": + version "19.6.0" + resolved "https://registry.yarnpkg.com/@commitlint/rules/-/rules-19.6.0.tgz#2436da7974c3cf2a7236257f3ef5dd40c4d91312" + integrity sha512-1f2reW7lbrI0X0ozZMesS/WZxgPa4/wi56vFuJENBmed6mWq5KsheN/nxqnl/C23ioxpPO/PL6tXpiiFy5Bhjw== + dependencies: + "@commitlint/ensure" "^19.5.0" + "@commitlint/message" "^19.5.0" + "@commitlint/to-lines" "^19.5.0" + "@commitlint/types" "^19.5.0" + +"@commitlint/to-lines@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/to-lines/-/to-lines-19.5.0.tgz#e4b7f34f09064568c96a74de4f1fc9f466c4d472" + integrity sha512-R772oj3NHPkodOSRZ9bBVNq224DOxQtNef5Pl8l2M8ZnkkzQfeSTr4uxawV2Sd3ui05dUVzvLNnzenDBO1KBeQ== + +"@commitlint/top-level@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/top-level/-/top-level-19.5.0.tgz#0017ffe39b5ba3611a1debd62efe28803601a14f" + integrity sha512-IP1YLmGAk0yWrImPRRc578I3dDUI5A2UBJx9FbSOjxe9sTlzFiwVJ+zeMLgAtHMtGZsC8LUnzmW1qRemkFU4ng== + dependencies: + find-up "^7.0.0" + +"@commitlint/types@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/types/-/types-19.5.0.tgz#c5084d1231d4dd50e40bdb656ee7601f691400b3" + integrity sha512-DSHae2obMSMkAtTBSOulg5X7/z+rGLxcXQIkg3OmWvY6wifojge5uVMydfhUvs7yQj+V7jNmRZ2Xzl8GJyqRgg== + dependencies: + "@types/conventional-commits-parser" "^5.0.0" + chalk "^5.3.0" + +"@cspell/cspell-bundled-dicts@8.17.1": + version "8.17.1" + resolved "https://registry.yarnpkg.com/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-8.17.1.tgz#61adad73f1bb1e12b182ffa04423d6052b18f0fc" + integrity sha512-HmkXS5uX4bk/XxsRS4Q+zRvhgRa81ddGiR2/Xfag9MIi5L5UnEJ4g21EpmIlXkMxYrTu2fp69SZFss5NfcFF9Q== + dependencies: + "@cspell/dict-ada" "^4.0.5" + "@cspell/dict-al" "^1.0.3" + "@cspell/dict-aws" "^4.0.7" + "@cspell/dict-bash" "^4.1.8" + "@cspell/dict-companies" "^3.1.8" + "@cspell/dict-cpp" "^6.0.2" + "@cspell/dict-cryptocurrencies" "^5.0.3" + "@cspell/dict-csharp" "^4.0.5" + "@cspell/dict-css" "^4.0.16" + "@cspell/dict-dart" "^2.2.4" + "@cspell/dict-django" "^4.1.3" + "@cspell/dict-docker" "^1.1.11" + "@cspell/dict-dotnet" "^5.0.8" + "@cspell/dict-elixir" "^4.0.6" + "@cspell/dict-en-common-misspellings" "^2.0.7" + "@cspell/dict-en-gb" "1.1.33" + "@cspell/dict-en_us" "^4.3.28" + "@cspell/dict-filetypes" "^3.0.9" + "@cspell/dict-flutter" "^1.0.3" + "@cspell/dict-fonts" "^4.0.3" + "@cspell/dict-fsharp" "^1.0.4" + "@cspell/dict-fullstack" "^3.2.3" + "@cspell/dict-gaming-terms" "^1.0.9" + "@cspell/dict-git" "^3.0.3" + "@cspell/dict-golang" "^6.0.17" + "@cspell/dict-google" "^1.0.4" + "@cspell/dict-haskell" "^4.0.4" + "@cspell/dict-html" "^4.0.10" + "@cspell/dict-html-symbol-entities" "^4.0.3" + "@cspell/dict-java" "^5.0.10" + "@cspell/dict-julia" "^1.0.4" + "@cspell/dict-k8s" "^1.0.9" + "@cspell/dict-latex" "^4.0.3" + "@cspell/dict-lorem-ipsum" "^4.0.3" + "@cspell/dict-lua" "^4.0.6" + "@cspell/dict-makefile" "^1.0.3" + "@cspell/dict-markdown" "^2.0.7" + "@cspell/dict-monkeyc" "^1.0.9" + "@cspell/dict-node" "^5.0.5" + "@cspell/dict-npm" "^5.1.17" + "@cspell/dict-php" "^4.0.13" + "@cspell/dict-powershell" "^5.0.13" + "@cspell/dict-public-licenses" "^2.0.11" + "@cspell/dict-python" "^4.2.13" + "@cspell/dict-r" "^2.0.4" + "@cspell/dict-ruby" "^5.0.7" + "@cspell/dict-rust" "^4.0.10" + "@cspell/dict-scala" "^5.0.6" + "@cspell/dict-software-terms" "^4.1.19" + "@cspell/dict-sql" "^2.1.8" + "@cspell/dict-svelte" "^1.0.5" + "@cspell/dict-swift" "^2.0.4" + "@cspell/dict-terraform" "^1.0.6" + "@cspell/dict-typescript" "^3.1.11" + "@cspell/dict-vue" "^3.0.3" + +"@cspell/cspell-json-reporter@8.17.1": + version "8.17.1" + resolved "https://registry.yarnpkg.com/@cspell/cspell-json-reporter/-/cspell-json-reporter-8.17.1.tgz#c1678665f183589e5fc19a1c0933b8d362165a43" + integrity sha512-EV9Xkh42Xw3aORvDZfxusICX91DDbqQpYdGKBdPGuhgxWOUYYZKpLXsHCmDkhruMPo2m5gDh++/OqjLRPZofKQ== + dependencies: + "@cspell/cspell-types" "8.17.1" + +"@cspell/cspell-pipe@8.17.1": + version "8.17.1" + resolved "https://registry.yarnpkg.com/@cspell/cspell-pipe/-/cspell-pipe-8.17.1.tgz#c247d4bd1c8ec43c49c46dc4458f00489e98232b" + integrity sha512-uhC99Ox+OH3COSgShv4fpVHiotR70dNvAOSkzRvKVRzV6IGyFnxHjmyVVPEV0dsqzVLxltwYTqFhwI+UOwm45A== + +"@cspell/cspell-resolver@8.17.1": + version "8.17.1" + resolved "https://registry.yarnpkg.com/@cspell/cspell-resolver/-/cspell-resolver-8.17.1.tgz#6377c9c8c05c940fee675c74e31f893b7b2f38ab" + integrity sha512-XEK2ymTdQNgsV3ny60VkKzWskbICl4zNXh/DbxsoRXHqIRg43MXFpTNkEJ7j873EqdX7BU4opQQ+5D4stWWuhQ== + dependencies: + global-directory "^4.0.1" + +"@cspell/cspell-service-bus@8.17.1": + version "8.17.1" + resolved "https://registry.yarnpkg.com/@cspell/cspell-service-bus/-/cspell-service-bus-8.17.1.tgz#8d6d82ea3ab0fc9d7efed8523b070e4842780bd1" + integrity sha512-2sFWQtMEWZ4tdz7bw0bAx4NaV1t0ynGfjpuKWdQppsJFKNb+ZPZZ6Ah1dC13AdRRMZaG194kDRFwzNvRaCgWkQ== + +"@cspell/cspell-types@8.17.1": + version "8.17.1" + resolved "https://registry.yarnpkg.com/@cspell/cspell-types/-/cspell-types-8.17.1.tgz#5512030b4c2e7881a8822ab3afabbd4f5ddffb6f" + integrity sha512-NJbov7Jp57fh8addoxesjb8atg/APQfssCH5Q9uZuHBN06wEJDgs7fhfE48bU+RBViC9gltblsYZzZZQKzHYKg== + +"@cspell/dict-ada@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@cspell/dict-ada/-/dict-ada-4.0.5.tgz#c14aae2faaecbad2d99f0d701e4700a48c68ef60" + integrity sha512-6/RtZ/a+lhFVmrx/B7bfP7rzC4yjEYe8o74EybXcvu4Oue6J4Ey2WSYj96iuodloj1LWrkNCQyX5h4Pmcj0Iag== + +"@cspell/dict-al@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-al/-/dict-al-1.0.3.tgz#09e288b5ab56b126dce895d3301faf7c0dd732d6" + integrity sha512-V1HClwlfU/qwSq2Kt+MkqRAsonNu3mxjSCDyGRecdLGIHmh7yeEeaxqRiO/VZ4KP+eVSiSIlbwrb5YNFfxYZbw== + +"@cspell/dict-aws@^4.0.7": + version "4.0.7" + resolved "https://registry.yarnpkg.com/@cspell/dict-aws/-/dict-aws-4.0.7.tgz#f96f3b70cd52a25b895eb08e297de5a5cc3fc5b6" + integrity sha512-PoaPpa2NXtSkhGIMIKhsJUXB6UbtTt6Ao3x9JdU9kn7fRZkwD4RjHDGqulucIOz7KeEX/dNRafap6oK9xHe4RA== + +"@cspell/dict-bash@^4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@cspell/dict-bash/-/dict-bash-4.1.8.tgz#26dc898e06eddea069cf1ad475ee0e867c89e632" + integrity sha512-I2CM2pTNthQwW069lKcrVxchJGMVQBzru2ygsHCwgidXRnJL/NTjAPOFTxN58Jc1bf7THWghfEDyKX/oyfc0yg== + +"@cspell/dict-companies@^3.1.8": + version "3.1.11" + resolved "https://registry.yarnpkg.com/@cspell/dict-companies/-/dict-companies-3.1.11.tgz#3a4f6fd052d5ac5a2869c763e169aff3a1f062c6" + integrity sha512-1gbPfN4fk6Cmg8DbCc+3nFxnHJNNGN1R5T/VzGEp8UpVBcW3OFET2xXFKcJiKSh+DyXB+M2tAx3so6WBEwOK1Q== + +"@cspell/dict-cpp@^6.0.2": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@cspell/dict-cpp/-/dict-cpp-6.0.2.tgz#e4549ee1bdf4b6402c0b978eb9dd3deac0eb05df" + integrity sha512-yw5eejWvY4bAnc6LUA44m4WsFwlmgPt2uMSnO7QViGMBDuoeopMma4z9XYvs4lSjTi8fIJs/A1YDfM9AVzb8eg== + +"@cspell/dict-cryptocurrencies@^5.0.3": + version "5.0.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-5.0.3.tgz#502f9fffcb2835a3379668ddebdc487678ce6207" + integrity sha512-bl5q+Mk+T3xOZ12+FG37dB30GDxStza49Rmoax95n37MTLksk9wBo1ICOlPJ6PnDUSyeuv4SIVKgRKMKkJJglA== + +"@cspell/dict-csharp@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@cspell/dict-csharp/-/dict-csharp-4.0.5.tgz#c677c50be09ca5bb3a2cc0be15f3cd05141fd2f7" + integrity sha512-c/sFnNgtRwRJxtC3JHKkyOm+U3/sUrltFeNwml9VsxKBHVmvlg4tk4ar58PdpW9/zTlGUkWi2i85//DN1EsUCA== + +"@cspell/dict-css@^4.0.16": + version "4.0.16" + resolved "https://registry.yarnpkg.com/@cspell/dict-css/-/dict-css-4.0.16.tgz#b7b87b5ea0f1157b023205bdb00070a7d231e367" + integrity sha512-70qu7L9z/JR6QLyJPk38fNTKitlIHnfunx0wjpWQUQ8/jGADIhMCrz6hInBjqPNdtGpYm8d1dNFyF8taEkOgrQ== + +"@cspell/dict-dart@^2.2.4": + version "2.2.4" + resolved "https://registry.yarnpkg.com/@cspell/dict-dart/-/dict-dart-2.2.4.tgz#8b877161ccdc65cead912b742b71aa55099c1706" + integrity sha512-of/cVuUIZZK/+iqefGln8G3bVpfyN6ZtH+LyLkHMoR5tEj+2vtilGNk9ngwyR8L4lEqbKuzSkOxgfVjsXf5PsQ== + +"@cspell/dict-data-science@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@cspell/dict-data-science/-/dict-data-science-2.0.5.tgz#816e9b394c2a423d14cdc9a5de5d6fc6141d3900" + integrity sha512-nNSILXmhSJox9/QoXICPQgm8q5PbiSQP4afpbkBqPi/u/b3K9MbNH5HvOOa6230gxcGdbZ9Argl2hY/U8siBlg== + +"@cspell/dict-django@^4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-django/-/dict-django-4.1.3.tgz#a02a4a9ef8c9f47344f2d4a0c3964bcb62069ef5" + integrity sha512-yBspeL3roJlO0a1vKKNaWABURuHdHZ9b1L8d3AukX0AsBy9snSggc8xCavPmSzNfeMDXbH+1lgQiYBd3IW03fg== + +"@cspell/dict-docker@^1.1.11": + version "1.1.11" + resolved "https://registry.yarnpkg.com/@cspell/dict-docker/-/dict-docker-1.1.11.tgz#6fce86eb6d86d73f77e18d3e7b9747bad3ca98de" + integrity sha512-s0Yhb16/R+UT1y727ekbR/itWQF3Qz275DR1ahOa66wYtPjHUXmhM3B/LT3aPaX+hD6AWmK23v57SuyfYHUjsw== + +"@cspell/dict-dotnet@^5.0.8": + version "5.0.8" + resolved "https://registry.yarnpkg.com/@cspell/dict-dotnet/-/dict-dotnet-5.0.8.tgz#8a110ca302946025e0273a9940079483ec33a88a" + integrity sha512-MD8CmMgMEdJAIPl2Py3iqrx3B708MbCIXAuOeZ0Mzzb8YmLmiisY7QEYSZPg08D7xuwARycP0Ki+bb0GAkFSqg== + +"@cspell/dict-elixir@^4.0.6": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@cspell/dict-elixir/-/dict-elixir-4.0.6.tgz#3d8965c558d8afd190356e9a900b02c546741feb" + integrity sha512-TfqSTxMHZ2jhiqnXlVKM0bUADtCvwKQv2XZL/DI0rx3doG8mEMS8SGPOmiyyGkHpR/pGOq18AFH3BEm4lViHIw== + +"@cspell/dict-en-common-misspellings@^2.0.7": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@cspell/dict-en-common-misspellings/-/dict-en-common-misspellings-2.0.7.tgz#62861cc9e813c947ebd71c7a50fc720767b4b543" + integrity sha512-qNFo3G4wyabcwnM+hDrMYKN9vNVg/k9QkhqSlSst6pULjdvPyPs1mqz1689xO/v9t8e6sR4IKc3CgUXDMTYOpA== + +"@cspell/dict-en-gb@1.1.33": + version "1.1.33" + resolved "https://registry.yarnpkg.com/@cspell/dict-en-gb/-/dict-en-gb-1.1.33.tgz#7f1fd90fc364a5cb77111b5438fc9fcf9cc6da0e" + integrity sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g== + +"@cspell/dict-en_us@^4.3.28": + version "4.3.28" + resolved "https://registry.yarnpkg.com/@cspell/dict-en_us/-/dict-en_us-4.3.28.tgz#41169e1ed18465e7ff367a4f4488d4cbc6cf0baa" + integrity sha512-BN1PME7cOl7DXRQJ92pEd1f0Xk5sqjcDfThDGkKcsgwbSOY7KnTc/czBW6Pr3WXIchIm6cT12KEfjNqx7U7Rrw== + +"@cspell/dict-filetypes@^3.0.9": + version "3.0.9" + resolved "https://registry.yarnpkg.com/@cspell/dict-filetypes/-/dict-filetypes-3.0.9.tgz#f4d5c35c341e6c3b77c08aec00678412641e1504" + integrity sha512-U7ycC1cE32A5aEgwzp/iE0TVabonUFnVt+Ygbf6NsIWqEuFWZgZChC7gfztA4T1fpuj602nFdp7eOnTWKORsnQ== + +"@cspell/dict-flutter@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-flutter/-/dict-flutter-1.0.3.tgz#23e552209ab2238733d30ca3f2a141359756af51" + integrity sha512-52C9aUEU22ptpgYh6gQyIdA4MP6NPwzbEqndfgPh3Sra191/kgs7CVqXiO1qbtZa9gnYHUoVApkoxRE7mrXHfg== + +"@cspell/dict-fonts@^4.0.3": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-fonts/-/dict-fonts-4.0.3.tgz#abf578c10a2e7b2bd8f4374002677625288560d9" + integrity sha512-sPd17kV5qgYXLteuHFPn5mbp/oCHKgitNfsZLFC3W2fWEgZlhg4hK+UGig3KzrYhhvQ8wBnmZrAQm0TFKCKzsA== + +"@cspell/dict-fsharp@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@cspell/dict-fsharp/-/dict-fsharp-1.0.4.tgz#19a7263a61ca89cd3ec9c17537e424907b81ef38" + integrity sha512-G5wk0o1qyHUNi9nVgdE1h5wl5ylq7pcBjX8vhjHcO4XBq20D5eMoXjwqMo/+szKAqzJ+WV3BgAL50akLKrT9Rw== + +"@cspell/dict-fullstack@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-fullstack/-/dict-fullstack-3.2.3.tgz#f6fff74eff00c6759cba510168acada0619004cc" + integrity sha512-62PbndIyQPH11mAv0PyiyT0vbwD0AXEocPpHlCHzfb5v9SspzCCbzQ/LIBiFmyRa+q5LMW35CnSVu6OXdT+LKg== + +"@cspell/dict-gaming-terms@^1.0.9": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@cspell/dict-gaming-terms/-/dict-gaming-terms-1.0.9.tgz#6b920386d281b89f70857e6dacea10ab89e88658" + integrity sha512-AVIrZt3YiUnxsUzzGYTZ1XqgtkgwGEO0LWIlEf+SiDUEVLtv4CYmmyXFQ+WXDN0pyJ0wOwDazWrP0Cu7avYQmQ== + +"@cspell/dict-git@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-git/-/dict-git-3.0.3.tgz#3a3805ab9902bffc9255ec48f648145b957eb30b" + integrity sha512-LSxB+psZ0qoj83GkyjeEH/ZViyVsGEF/A6BAo8Nqc0w0HjD2qX/QR4sfA6JHUgQ3Yi/ccxdK7xNIo67L2ScW5A== + +"@cspell/dict-golang@^6.0.17": + version "6.0.18" + resolved "https://registry.yarnpkg.com/@cspell/dict-golang/-/dict-golang-6.0.18.tgz#44e144409c3141ee58d854e49e118f7d264c9d43" + integrity sha512-Mt+7NwfodDwUk7423DdaQa0YaA+4UoV3XSxQwZioqjpFBCuxfvvv4l80MxCTAAbK6duGj0uHbGTwpv8fyKYPKg== + +"@cspell/dict-google@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@cspell/dict-google/-/dict-google-1.0.4.tgz#e15a7ea2dee73800231a81840a59d3b50d49346f" + integrity sha512-JThUT9eiguCja1mHHLwYESgxkhk17Gv7P3b1S7ZJzXw86QyVHPrbpVoMpozHk0C9o+Ym764B7gZGKmw9uMGduQ== + +"@cspell/dict-haskell@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@cspell/dict-haskell/-/dict-haskell-4.0.4.tgz#37e9cb9a7f5be337a697bcffd0a0d25e80aab50d" + integrity sha512-EwQsedEEnND/vY6tqRfg9y7tsnZdxNqOxLXSXTsFA6JRhUlr8Qs88iUUAfsUzWc4nNmmzQH2UbtT25ooG9x4nA== + +"@cspell/dict-html-symbol-entities@^4.0.3": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.3.tgz#bf2887020ca4774413d8b1f27c9b6824ba89e9ef" + integrity sha512-aABXX7dMLNFdSE8aY844X4+hvfK7977sOWgZXo4MTGAmOzR8524fjbJPswIBK7GaD3+SgFZ2yP2o0CFvXDGF+A== + +"@cspell/dict-html@^4.0.10": + version "4.0.10" + resolved "https://registry.yarnpkg.com/@cspell/dict-html/-/dict-html-4.0.10.tgz#7b536b2adca4b58ed92752c9d3c7ffc724dd5991" + integrity sha512-I9uRAcdtHbh0wEtYZlgF0TTcgH0xaw1B54G2CW+tx4vHUwlde/+JBOfIzird4+WcMv4smZOfw+qHf7puFUbI5g== + +"@cspell/dict-java@^5.0.10": + version "5.0.10" + resolved "https://registry.yarnpkg.com/@cspell/dict-java/-/dict-java-5.0.10.tgz#e6383ca645046b9f05a04a2c2e858fcc80c6fc63" + integrity sha512-pVNcOnmoGiNL8GSVq4WbX/Vs2FGS0Nej+1aEeGuUY9CU14X8yAVCG+oih5ZoLt1jaR8YfR8byUF8wdp4qG4XIw== + +"@cspell/dict-julia@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@cspell/dict-julia/-/dict-julia-1.0.4.tgz#e478c20d742cd6857b6de41dc61a92036dafb4bc" + integrity sha512-bFVgNX35MD3kZRbXbJVzdnN7OuEqmQXGpdOi9jzB40TSgBTlJWA4nxeAKV4CPCZxNRUGnLH0p05T/AD7Aom9/w== + +"@cspell/dict-k8s@^1.0.9": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@cspell/dict-k8s/-/dict-k8s-1.0.9.tgz#e9392a002797c67ffc3e96893156cc15af3774d1" + integrity sha512-Q7GELSQIzo+BERl2ya/nBEnZeQC+zJP19SN1pI6gqDYraM51uYJacbbcWLYYO2Y+5joDjNt/sd/lJtLaQwoSlA== + +"@cspell/dict-latex@^4.0.3": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-latex/-/dict-latex-4.0.3.tgz#a1254c7d9c3a2d70cd6391a9f2f7694431b1b2cb" + integrity sha512-2KXBt9fSpymYHxHfvhUpjUFyzrmN4c4P8mwIzweLyvqntBT3k0YGZJSriOdjfUjwSygrfEwiuPI1EMrvgrOMJw== + +"@cspell/dict-lorem-ipsum@^4.0.3": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-4.0.3.tgz#c5fc631d934f1daf8b10c88b795278701a2469ec" + integrity sha512-WFpDi/PDYHXft6p0eCXuYnn7mzMEQLVeqpO+wHSUd+kz5ADusZ4cpslAA4wUZJstF1/1kMCQCZM6HLZic9bT8A== + +"@cspell/dict-lua@^4.0.6": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@cspell/dict-lua/-/dict-lua-4.0.6.tgz#7de412bfaead794445e26d566aec222e20ad69ba" + integrity sha512-Jwvh1jmAd9b+SP9e1GkS2ACbqKKRo9E1f9GdjF/ijmooZuHU0hPyqvnhZzUAxO1egbnNjxS/J2T6iUtjAUK2KQ== + +"@cspell/dict-makefile@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-makefile/-/dict-makefile-1.0.3.tgz#08d3349bf7cbd8f5dacf8641f3d35092ca0b8b38" + integrity sha512-R3U0DSpvTs6qdqfyBATnePj9Q/pypkje0Nj26mQJ8TOBQutCRAJbr2ZFAeDjgRx5EAJU/+8txiyVF97fbVRViw== + +"@cspell/dict-markdown@^2.0.7": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@cspell/dict-markdown/-/dict-markdown-2.0.7.tgz#15d6f9eed6bd1b33921b4332426ff387961163f1" + integrity sha512-F9SGsSOokFn976DV4u/1eL4FtKQDSgJHSZ3+haPRU5ki6OEqojxKa8hhj4AUrtNFpmBaJx/WJ4YaEzWqG7hgqg== + +"@cspell/dict-monkeyc@^1.0.9": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@cspell/dict-monkeyc/-/dict-monkeyc-1.0.9.tgz#58b5f6f15fc7c11ce0eeffd0742fba4b39fc0b8b" + integrity sha512-Jvf6g5xlB4+za3ThvenYKREXTEgzx5gMUSzrAxIiPleVG4hmRb/GBSoSjtkGaibN3XxGx5x809gSTYCA/IHCpA== + +"@cspell/dict-node@^5.0.5": + version "5.0.5" + resolved "https://registry.yarnpkg.com/@cspell/dict-node/-/dict-node-5.0.5.tgz#11653612ebdd833208432e8b3cbe61bd6dd35dc3" + integrity sha512-7NbCS2E8ZZRZwlLrh2sA0vAk9n1kcTUiRp/Nia8YvKaItGXLfxYqD2rMQ3HpB1kEutal6hQLVic3N2Yi1X7AaA== + +"@cspell/dict-npm@^5.1.17": + version "5.1.20" + resolved "https://registry.yarnpkg.com/@cspell/dict-npm/-/dict-npm-5.1.20.tgz#5e54b428d7609267263d426d0edc9d51d53f0a6f" + integrity sha512-vE9pFIifCDChsVhhUDuVtnwxygOdtHNluDm+8FkgC84M6LwiUVJr/CuSOI/SCR0oI9iiFp0VvMz194B6XwMv3g== + +"@cspell/dict-php@^4.0.13": + version "4.0.13" + resolved "https://registry.yarnpkg.com/@cspell/dict-php/-/dict-php-4.0.13.tgz#86f1e6fb2174b2b0fa012baf86c448b2730f04f9" + integrity sha512-P6sREMZkhElzz/HhXAjahnICYIqB/HSGp1EhZh+Y6IhvC15AzgtDP8B8VYCIsQof6rPF1SQrFwunxOv8H1e2eg== + +"@cspell/dict-powershell@^5.0.13": + version "5.0.13" + resolved "https://registry.yarnpkg.com/@cspell/dict-powershell/-/dict-powershell-5.0.13.tgz#f557aa04ee9bda4fe091308a0bcaea09ed12fa76" + integrity sha512-0qdj0XZIPmb77nRTynKidRJKTU0Fl+10jyLbAhFTuBWKMypVY06EaYFnwhsgsws/7nNX8MTEQuewbl9bWFAbsg== + +"@cspell/dict-public-licenses@^2.0.11": + version "2.0.11" + resolved "https://registry.yarnpkg.com/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.11.tgz#37550c4e0cd445991caba528bf4ba58ce7a935c3" + integrity sha512-rR5KjRUSnVKdfs5G+gJ4oIvQvm8+NJ6cHWY2N+GE69/FSGWDOPHxulCzeGnQU/c6WWZMSimG9o49i9r//lUQyA== + +"@cspell/dict-python@^4.2.13": + version "4.2.13" + resolved "https://registry.yarnpkg.com/@cspell/dict-python/-/dict-python-4.2.13.tgz#c3dbaa7e2434c835e11540345e2168e5e685190a" + integrity sha512-mZIcmo9qif8LkJ6N/lqTZawcOk2kVTcuWIUOSbMcjyomO0XZ7iWz15TfONyr03Ea/l7o5ULV+MZ4vx76bAUb7w== + dependencies: + "@cspell/dict-data-science" "^2.0.5" + +"@cspell/dict-r@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@cspell/dict-r/-/dict-r-2.0.4.tgz#31b5abd91cc12aebfffdde4be4d2902668789311" + integrity sha512-cBpRsE/U0d9BRhiNRMLMH1PpWgw+N+1A2jumgt1if9nBGmQw4MUpg2u9I0xlFVhstTIdzXiLXMxP45cABuiUeQ== + +"@cspell/dict-ruby@^5.0.7": + version "5.0.7" + resolved "https://registry.yarnpkg.com/@cspell/dict-ruby/-/dict-ruby-5.0.7.tgz#3593a955baaffe3c5d28fb178b72fdf93c7eec71" + integrity sha512-4/d0hcoPzi5Alk0FmcyqlzFW9lQnZh9j07MJzPcyVO62nYJJAGKaPZL2o4qHeCS/od/ctJC5AHRdoUm0ktsw6Q== + +"@cspell/dict-rust@^4.0.10": + version "4.0.10" + resolved "https://registry.yarnpkg.com/@cspell/dict-rust/-/dict-rust-4.0.10.tgz#8ae6eaf31a0ebce9dc8fd8dd68e5925e1d5290ee" + integrity sha512-6o5C8566VGTTctgcwfF3Iy7314W0oMlFFSQOadQ0OEdJ9Z9ERX/PDimrzP3LGuOrvhtEFoK8pj+BLnunNwRNrw== + +"@cspell/dict-scala@^5.0.6": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@cspell/dict-scala/-/dict-scala-5.0.6.tgz#5e925def2fe6dc27ee2ad1c452941c3d6790fb6d" + integrity sha512-tl0YWAfjUVb4LyyE4JIMVE8DlLzb1ecHRmIWc4eT6nkyDqQgHKzdHsnusxFEFMVLIQomgSg0Zz6hJ5S1E4W4ww== + +"@cspell/dict-software-terms@^4.1.19": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@cspell/dict-software-terms/-/dict-software-terms-4.2.1.tgz#d2fd5c9de75024eaabe329639110a5853bbade9b" + integrity sha512-8FiZHeeTqBdjsw4uBsZ9GIV9zEUbr49bBeEyVGFmUMZYwhAzC9riGqbTWco277X5Mabe8OjbYxqiP2/snC6w5w== + +"@cspell/dict-sql@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@cspell/dict-sql/-/dict-sql-2.1.8.tgz#45ea53b3e57fd2cc5f839f49b644aa743dac4990" + integrity sha512-dJRE4JV1qmXTbbGm6WIcg1knmR6K5RXnQxF4XHs5HA3LAjc/zf77F95i5LC+guOGppVF6Hdl66S2UyxT+SAF3A== + +"@cspell/dict-svelte@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@cspell/dict-svelte/-/dict-svelte-1.0.5.tgz#09752e01ff6667e737566d9dfc704c8dcc9a6492" + integrity sha512-sseHlcXOqWE4Ner9sg8KsjxwSJ2yssoJNqFHR9liWVbDV+m7kBiUtn2EB690TihzVsEmDr/0Yxrbb5Bniz70mA== + +"@cspell/dict-swift@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@cspell/dict-swift/-/dict-swift-2.0.4.tgz#bc19522418ed68cf914736b612c4e4febbf07e8d" + integrity sha512-CsFF0IFAbRtYNg0yZcdaYbADF5F3DsM8C4wHnZefQy8YcHP/qjAF/GdGfBFBLx+XSthYuBlo2b2XQVdz3cJZBw== + +"@cspell/dict-terraform@^1.0.6": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@cspell/dict-terraform/-/dict-terraform-1.0.7.tgz#815a523c86f647cb7695d48b69e4a793c49f875e" + integrity sha512-Ip7tOlAt/qUVdWYyDMA7DlKMpQ6sjtrsXk4vcpqXoYpoJlzMoDce7pw+fPhHshtNOFBAZ4nOrszlLu6APuy+HQ== + +"@cspell/dict-typescript@^3.1.11": + version "3.1.11" + resolved "https://registry.yarnpkg.com/@cspell/dict-typescript/-/dict-typescript-3.1.11.tgz#40586f13b0337bd9cba958e0661b35888580b249" + integrity sha512-FwvK5sKbwrVpdw0e9+1lVTl8FPoHYvfHRuQRQz2Ql5XkC0gwPPkpoyD1zYImjIyZRoYXk3yp9j8ss4iz7A7zoQ== + +"@cspell/dict-vue@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-vue/-/dict-vue-3.0.3.tgz#295c288f6fd363879898223202ec3be048663b98" + integrity sha512-akmYbrgAGumqk1xXALtDJcEcOMYBYMnkjpmGzH13Ozhq1mkPF4VgllFQlm1xYde+BUKNnzMgPEzxrL2qZllgYA== + +"@cspell/dynamic-import@8.17.1": + version "8.17.1" + resolved "https://registry.yarnpkg.com/@cspell/dynamic-import/-/dynamic-import-8.17.1.tgz#2b3f3325b6013a067a1a49cda8b69ae73aaed36a" + integrity sha512-XQtr2olYOtqbg49E+8SISd6I5DzfxmsKINDn0ZgaTFeLalnNdF3ewDU4gOEbApIzGffRa1mW9t19MsiVrznSDw== + dependencies: + "@cspell/url" "8.17.1" + import-meta-resolve "^4.1.0" + +"@cspell/filetypes@8.17.1": + version "8.17.1" + resolved "https://registry.yarnpkg.com/@cspell/filetypes/-/filetypes-8.17.1.tgz#d193afc5029364334f005ff23f4c4cb80170c374" + integrity sha512-AxYw6j7EPYtDFAFjwybjFpMc9waXQzurfBXmEVfQ5RQRlbylujLZWwR6GnMqofeNg4oGDUpEjcAZFrgdkvMQlA== + +"@cspell/strong-weak-map@8.17.1": + version "8.17.1" + resolved "https://registry.yarnpkg.com/@cspell/strong-weak-map/-/strong-weak-map-8.17.1.tgz#2fa88f283ef10222fad25134b5ebb54edaad985f" + integrity sha512-8cY3vLAKdt5gQEMM3Gr57BuQ8sun2NjYNh9qTdrctC1S9gNC7XzFghTYAfHSWR4VrOUcMFLO/izMdsc1KFvFOA== + +"@cspell/url@8.17.1": + version "8.17.1" + resolved "https://registry.yarnpkg.com/@cspell/url/-/url-8.17.1.tgz#e7daec1597fa31b4d0a7a685e7a24a11b0c8a193" + integrity sha512-LMvReIndW1ckvemElfDgTt282fb2C3C/ZXfsm0pJsTV5ZmtdelCHwzmgSBmY5fDr7D66XDp8EurotSE0K6BTvw== + "@floating-ui/core@^1.6.0": version "1.6.4" - resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.4.tgz#0140cf5091c8dee602bff9da5ab330840ff91df6" + resolved "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.4.tgz" integrity sha512-a4IowK4QkXl4SCWTGUR0INAfEOX3wtsYw3rKK5InQEHMGObkR8Xk44qYQD9P4r6HHw0iIfK6GUKECmY8sTkqRA== dependencies: "@floating-ui/utils" "^0.2.4" "@floating-ui/dom@^1.0.0", "@floating-ui/dom@^1.6.7": version "1.6.7" - resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.7.tgz#85d22f731fcc5b209db504478fb1df5116a83015" + resolved "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.7.tgz" integrity sha512-wmVfPG5o2xnKDU4jx/m4w5qva9FWHcnZ8BvzEe90D/RpwsJaTAVYPEPdQ8sbr/N8zZTAHlZUTQdqg8ZUbzHmng== dependencies: "@floating-ui/core" "^1.6.0" @@ -45,12 +595,12 @@ "@floating-ui/utils@^0.2.4": version "0.2.4" - resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.4.tgz#1d459cee5031893a08a0e064c406ad2130cced7c" + resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.4.tgz" integrity sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA== "@floating-ui/vue@^1.1.0": version "1.1.1" - resolved "https://registry.yarnpkg.com/@floating-ui/vue/-/vue-1.1.1.tgz#008abc526108f3b01f005a7948f4f75e147d6321" + resolved "https://registry.npmjs.org/@floating-ui/vue/-/vue-1.1.1.tgz" integrity sha512-cyawjk9etPZPl/RVtMRnWrwtAhWbPVSrRVYARgOzhLIqxr0k2up1APrrFjqP9QwRQ0AwjKSvbWg4YC6jESutow== dependencies: "@floating-ui/dom" "^1.0.0" @@ -59,28 +609,28 @@ "@headlessui/vue@^1.7.14": version "1.7.22" - resolved "https://registry.yarnpkg.com/@headlessui/vue/-/vue-1.7.22.tgz#8d55a3a670c3d48beb660b7c47a7a8ff76caacfe" + resolved "https://registry.npmjs.org/@headlessui/vue/-/vue-1.7.22.tgz" integrity sha512-Hoffjoolq1rY+LOfJ+B/OvkhuBXXBFgd8oBlN+l1TApma2dB0En0ucFZrwQtb33SmcCqd32EQd0y07oziXWNYg== dependencies: "@tanstack/vue-virtual" "^3.0.0-beta.60" "@internationalized/date@^3.5.4": version "3.5.4" - resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.5.4.tgz#49ba11634fd4350b7a9308e297032267b4063c44" + resolved "https://registry.npmjs.org/@internationalized/date/-/date-3.5.4.tgz" integrity sha512-qoVJVro+O0rBaw+8HPjUB1iH8Ihf8oziEnqMnvhJUSuVIrHOuZ6eNLHNvzXJKUvAtaDiqMnRlg8Z2mgh09BlUw== dependencies: "@swc/helpers" "^0.5.0" "@internationalized/number@^3.5.3": version "3.5.3" - resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.5.3.tgz#9fa060c1c4809f23fb3d38dd3f3d1ae4c87e95a8" + resolved "https://registry.npmjs.org/@internationalized/number/-/number-3.5.3.tgz" integrity sha512-rd1wA3ebzlp0Mehj5YTuTI50AQEx80gWFyHcQu+u91/5NgdwBecO8BH6ipPfE+lmQ9d63vpB3H9SHoIUiupllw== dependencies: "@swc/helpers" "^0.5.0" "@jridgewell/gen-mapping@^0.3.2": version "0.3.3" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz" integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== dependencies: "@jridgewell/set-array" "^1.0.1" @@ -89,22 +639,22 @@ "@jridgewell/resolve-uri@^3.1.0": version "3.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz" integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== "@jridgewell/set-array@^1.0.1": version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + version "1.5.0" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== "@jridgewell/trace-mapping@^0.3.9": version "0.3.20" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz" integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== dependencies: "@jridgewell/resolve-uri" "^3.1.0" @@ -133,29 +683,29 @@ "@popperjs/core@^2.11.2", "@popperjs/core@^2.9.0": version "2.11.8" - resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" + resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz" integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== "@remirror/core-constants@^2.0.2": version "2.0.2" - resolved "https://registry.yarnpkg.com/@remirror/core-constants/-/core-constants-2.0.2.tgz#f05eccdc69e3a65e7d524b52548f567904a11a1a" + resolved "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-2.0.2.tgz" integrity sha512-dyHY+sMF0ihPus3O27ODd4+agdHMEmuRdyiZJ2CCWjPV5UFmn17ZbElvk6WOGVE4rdCJKZQCrPV2BcikOMLUGQ== "@socket.io/component-emitter@~3.1.0": version "3.1.2" - resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz#821f8442f4175d8f0467b9daf26e3a18e2d02af2" + resolved "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz" integrity sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA== "@swc/helpers@^0.5.0": version "0.5.12" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.12.tgz#37aaca95284019eb5d2207101249435659709f4b" + resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.12.tgz" integrity sha512-KMZNXiGibsW9kvZAO1Pam2JPTDBm+KSHMMHWdsyI/1DbIZjT2A6Gy3hblVXUMEDvUAKq+e0vL0X0o54owWji7g== dependencies: tslib "^2.4.0" "@tailwindcss/container-queries@^0.1.1": version "0.1.1" - resolved "https://registry.yarnpkg.com/@tailwindcss/container-queries/-/container-queries-0.1.1.tgz#9a759ce2cb8736a4c6a0cb93aeb740573a731974" + resolved "https://registry.npmjs.org/@tailwindcss/container-queries/-/container-queries-0.1.1.tgz" integrity sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA== "@tailwindcss/forms@^0.4.0": @@ -167,7 +717,7 @@ "@tailwindcss/forms@^0.5.3": version "0.5.7" - resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.7.tgz#db5421f062a757b5f828bc9286ba626c6685e821" + resolved "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz" integrity sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw== dependencies: mini-svg-data-uri "^1.2.3" @@ -215,7 +765,7 @@ "@tailwindcss/typography@^0.5.0": version "0.5.13" - resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.13.tgz#cd788a4fa4d0ca2506e242d512f377b22c1f7932" + resolved "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.13.tgz" integrity sha512-ADGcJ8dX21dVVHIwTRgzrcunY6YY9uSlAHHGVKvkA+vLc5qLwEszvKts40lx7z0qc4clpjclwLeK5rVCV2P/uw== dependencies: lodash.castarray "^4.4.0" @@ -234,195 +784,195 @@ "@tanstack/virtual-core@3.8.3": version "3.8.3" - resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.8.3.tgz#9db61ab2a96e43d9e035b1cfd82eeede6d52f171" + resolved "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.8.3.tgz" integrity sha512-vd2A2TnM5lbnWZnHi9B+L2gPtkSeOtJOAw358JqokIH1+v2J7vUAzFVPwB/wrye12RFOurffXu33plm4uQ+JBQ== "@tanstack/vue-virtual@^3.0.0-beta.60", "@tanstack/vue-virtual@^3.8.1": version "3.8.3" - resolved "https://registry.yarnpkg.com/@tanstack/vue-virtual/-/vue-virtual-3.8.3.tgz#865410616bd6291387892db2bfc260c91926d770" + resolved "https://registry.npmjs.org/@tanstack/vue-virtual/-/vue-virtual-3.8.3.tgz" integrity sha512-xrFLkOiqLoGwohgr1+Q880hkNdQWqwi19EXzx38iAjVEm1Db3KIAV0aVP57/dnNXU3NO1Vx8wnIHII5J4n1LyA== dependencies: "@tanstack/virtual-core" "3.8.3" "@tiptap/core@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.5.4.tgz#8b08113512dd8dc9d98268ad6f982d62c85433d2" + resolved "https://registry.npmjs.org/@tiptap/core/-/core-2.5.4.tgz" integrity sha512-Zs/hShr4+W02+0nOlpmr5cS2YjDRLqd+XMt+jsiQH0QNr3s1Lc82pfF6C3CjgLEZtdUzImZrW2ABtLlpvbogaA== "@tiptap/extension-blockquote@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.5.4.tgz#7b0bbf2bed91533a73887b0217bf8000681b8b5a" + resolved "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.5.4.tgz" integrity sha512-UqeJunZM3IiCQGZE0X5YNUOWYkuIieqrwPgOEghAIjnhDcQizQcouRQ5R7cwwv/scNr2JvZHncOTLrALV3Janw== "@tiptap/extension-bold@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.5.4.tgz#c6e98a02da288ad171df4491a12870c7793c2ee2" + resolved "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.5.4.tgz" integrity sha512-H5sjqloFMjq7VOSfE+U4T7dqGoflOiF6RW6/gZm/U6KYeHG2/bG0ktq7mWAnnhbiKiy7gUcxyJCV+ILdGX9C5g== "@tiptap/extension-bubble-menu@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.5.4.tgz#eaff01a21869a9d65b8fd6e29043008c8ad1b03c" + resolved "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.5.4.tgz" integrity sha512-GHwef912K1yd75pp9JGDnKSp1DvdOHH8BcHQv0no+a3q2ePFPYcgaSwVRR59jHRX9WzdVfoLcqDSAeoNGOrISw== dependencies: tippy.js "^6.3.7" "@tiptap/extension-bullet-list@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.5.4.tgz#96949f7e418fbc00614eb9f601377fa14606937b" + resolved "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.5.4.tgz" integrity sha512-aAfpALeD6OxymkbtrzDqbgkAkzVVHudxOb8GsK1N6m42nFL7Q9JzHJ5/8KzB+xi25CcIbS+HmXJkRIQJXgNbSA== "@tiptap/extension-code-block@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.5.4.tgz#03931fa50e0498d3d032f34ab29ba20dacd55edc" + resolved "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.5.4.tgz" integrity sha512-lZRz44ACSL0IC4syWkNsNSe90sZuLig0yidfV9rs2muSCLoS3PRcCIJv4GjdBHouangxxBZqzIqWgPBqe6pqwA== "@tiptap/extension-code@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.5.4.tgz#100d437183f0810195eaaf03870ca8a23a37aff8" + resolved "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.5.4.tgz" integrity sha512-PCP0VcWR0Jsj3rum3czp1jateR+kv1iuB9E+TieGLN4vFqhoiUwSv2UAuhvD8x66MGCYLA3btgnmPov1w/iNmA== "@tiptap/extension-color@^2.0.3": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-color/-/extension-color-2.5.4.tgz#9d046ea49428655194b49e8ead373201410fb599" + resolved "https://registry.npmjs.org/@tiptap/extension-color/-/extension-color-2.5.4.tgz" integrity sha512-f4ltxa4Y9NzD6+xFkjVo925+OltZbtYEuwUSXQKU4NJyjiMBMUOzW+mCgQM2TB5V36VP2ttIvdQ+W99yazJqUg== "@tiptap/extension-document@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.5.4.tgz#99279433ddd1572bd8e92f43cb40aa72ab576574" + resolved "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.5.4.tgz" integrity sha512-4RDrhASxCTOZETYhIhEW1TfZqx3Tm+LQxouvBMFyODmT1PSgsg5Xz1FYpDPr+J49bGAK0Pr9ae0XcGW011L3sA== "@tiptap/extension-dropcursor@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.5.4.tgz#637984ea57d78ae24282c5d7f2328944855a1007" + resolved "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.5.4.tgz" integrity sha512-jzSnuuYhlc0SsHvAteWkE9TJy3eRwkxQs4MO2JxALOzJECN4G82nlX8vciihBD6xf7lVgVSBACejK9+rsTHqCg== "@tiptap/extension-floating-menu@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.5.4.tgz#a80e54c685c24c320ef389b8d13f7382bc7e8f8f" + resolved "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.5.4.tgz" integrity sha512-EqD4rgi3UhnDcV3H1+ndAS4Ue2zpsU7hFKoevOIV6GS7xVnWN70AGt6swH24QzuHKKISFtWoLpKjrwRORNIxuA== dependencies: tippy.js "^6.3.7" "@tiptap/extension-gapcursor@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.5.4.tgz#45f6ef87458e7261e51fbc7f3343278c3e8f4534" + resolved "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.5.4.tgz" integrity sha512-wzTh1piODZBS0wmuDgPjjg8PQwclYa5LssnxDIo9pDSnt4l3AfHSAJIJSGIfgt96KnzF1wqRTRpe08qNa1n7/g== "@tiptap/extension-hard-break@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.5.4.tgz#df6e70930e6b426b527d1150ff0bde8118ea6d41" + resolved "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.5.4.tgz" integrity sha512-nLn6HP9tqgdGGwbMORXVtcY30DTGctYFaWADRthvBjVgacYSeKlhUcsSu3YgaxtbxZp6BhfRvD2kKrxyQsSjnQ== "@tiptap/extension-heading@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.5.4.tgz#b901d08a2c268bda54eef345836efa2a0b5f388a" + resolved "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.5.4.tgz" integrity sha512-DuAB58/e7eho1rkyad0Z/SjW+EB+H2hRqHlswEeZZYhBTjzey5UmBwkMWTGC/SQiRisx1xYQYTd8T0fiABi5hw== "@tiptap/extension-highlight@^2.0.3": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.5.4.tgz#c5b25bc01ab3b277cbcdb149da2b4d8d5361a0a8" + resolved "https://registry.npmjs.org/@tiptap/extension-highlight/-/extension-highlight-2.5.4.tgz" integrity sha512-TSYnFBluZu1YQdTCyXl2wuxFuhFUYFzbaV0f1wq2P2Nc8U2OiiuaNz+QggHw5Hf3ILzkRxQCUQnq97Q/5smMwQ== "@tiptap/extension-history@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.5.4.tgz#53cda40d723120a3d599d75eee0ab2c533dbdd25" + resolved "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.5.4.tgz" integrity sha512-WB1fZYGIlpahAD6Ba+mj9vIb1tk8S3TsADXDFKxLVpZWZPQ+B7duGJP7g/vRH2XAXEs836JzC2oxjKeaop3k7A== "@tiptap/extension-horizontal-rule@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.5.4.tgz#2c595a17114653f11236107c0bb1f094ab7f261d" + resolved "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.5.4.tgz" integrity sha512-uXLDe/iyzQbyfDkJ8kE5XaAkY3EOcbTFLjbueqGlkbWtjJgy+3LysGvh8fQj8PAOaIBMaFRFhTq7GMbW2ebRog== "@tiptap/extension-image@^2.0.3": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.5.4.tgz#bdf8dd9c820f17d8a77c2c5ae7db7f3f6f821659" + resolved "https://registry.npmjs.org/@tiptap/extension-image/-/extension-image-2.5.4.tgz" integrity sha512-4ySSP7iPsbbo1SlPJYj546TKettuO6FGY5MQKxH8AGnZWyQGZYl89GpU1iGFAaeHq4dKUemM5D3ikgSynEQLow== "@tiptap/extension-italic@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.5.4.tgz#9bc9674f1094a6f55fa9b59a9dcacd3bec8c2b46" + resolved "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.5.4.tgz" integrity sha512-TAhtl/fNBgv1elzF3HWES8uwVdpKBSYrq1e6yeYfj74mQn//3ksvdhWQrLzc1e+zcoHbk1PeOp/5ODdPuZ6tkg== "@tiptap/extension-link@^2.0.3": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.5.4.tgz#a256652198cc0abb662608802c7bb98ee1914067" + resolved "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-2.5.4.tgz" integrity sha512-xTB/+T6SHHCXInJni8WdqOfF40a/MiFUf5OoWW9cPrApx3I7TzJ9j8/WDshM0BOnDDw80w1bl9F2zkUQjC0Y2A== dependencies: linkifyjs "^4.1.0" "@tiptap/extension-list-item@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.5.4.tgz#ad837a7ba2a0c6362020c2c1c4a2a14de684d80d" + resolved "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.5.4.tgz" integrity sha512-bPxUCFt9HnAfoaZQgwqCfRAZ6L3QlYhIRDDbOvZag7IxCdQuZmeY4k5OZfQIGijNDTag7CN9cdL4fl9rnm6/sQ== "@tiptap/extension-mention@^2.0.3": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-mention/-/extension-mention-2.5.4.tgz#9f535a1393c43bb4750b9773bacf30f51f39bef2" + resolved "https://registry.npmjs.org/@tiptap/extension-mention/-/extension-mention-2.5.4.tgz" integrity sha512-U5Kqjhs7FraJzopZydy14/v0+X6unmfYYt42QHhVeSEdZ8y7QtyFigJktJUBzE12CpwGkyh8e3xI9Ozi7lFb0w== "@tiptap/extension-ordered-list@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.5.4.tgz#b007d46440568df87bfd166d3dea203239916744" + resolved "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.5.4.tgz" integrity sha512-cl3cTJitY6yDUmxqgjDUtDWCyX1VVsZNJ6i9yiPeARcxvzFc81KmUJxTGl8WPT5TjqmM+TleRkZjsxgvXX57+Q== "@tiptap/extension-paragraph@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.5.4.tgz#6aa8da578161ecedfb12e37cc515147d4bd5b476" + resolved "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.5.4.tgz" integrity sha512-pC1YIkkRPXoU0eDrhfAf8ZrFJQzvw2ftP6KRhLnnSw/Ot1DOjT1r95l7zsFefS9oCDMT/L4HghTAiPZ4rcpPbg== "@tiptap/extension-placeholder@^2.0.3": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.5.4.tgz#6841b137011d7873725c99ff07074b0f21af847b" + resolved "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-2.5.4.tgz" integrity sha512-mcj4j2Z/L1H5dzWHbbWChuAdJK9F2p06fcjqL4iyJtVx38QQFzCdVmGaTAim8CLp/EynbAOYJ5gk9w2PTdv7+w== "@tiptap/extension-strike@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.5.4.tgz#756af9aaef76d0b061741020d766654ea5bf1b63" + resolved "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.5.4.tgz" integrity sha512-OSN6ePbCwEhi3hYZZOPow/P9Ym2Kv3NhVbUvasjZCiqQuk8TGc33xirPWl9DTjb/BLfL66TtJ2tKUEVOKl5dKg== "@tiptap/extension-table-cell@^2.0.3": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-table-cell/-/extension-table-cell-2.5.4.tgz#2c2f41023f76d3c1eb47e78bd2604ecdf06df5d8" + resolved "https://registry.npmjs.org/@tiptap/extension-table-cell/-/extension-table-cell-2.5.4.tgz" integrity sha512-ntiexoIOchSQEtyxJ7RfRcX8SIMKoNl/RZT7e7q8luh6O8BAg8ijbjOnPcwaSJhcQIR+fGHqZCqu7Qud2Usp/g== "@tiptap/extension-table-header@^2.0.3": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-table-header/-/extension-table-header-2.5.4.tgz#4983591f2de9557a4802c12c383d16cb7976d0ef" + resolved "https://registry.npmjs.org/@tiptap/extension-table-header/-/extension-table-header-2.5.4.tgz" integrity sha512-0JV7yxf7UQXcnNBeh0ruJzpgxbPWtJjQ5CB7R/2nGGJtK5Zd4qbBSvPwZb90rrzbfGG6gPyH/840nBOV9Hihqw== "@tiptap/extension-table-row@^2.0.3": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-table-row/-/extension-table-row-2.5.4.tgz#72ecb52775990eb3f75bb45d7bc7eced64cac03b" + resolved "https://registry.npmjs.org/@tiptap/extension-table-row/-/extension-table-row-2.5.4.tgz" integrity sha512-syE0HO+1nZ6cZP+A1BnOfyBLY5/fSzlqXId1SzDxp3w2RfUldXfrV9ltyyEE6wxruxCgI+V5J3wV3ObSXy9PMA== "@tiptap/extension-table@^2.0.3": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-2.5.4.tgz#5e68f06a812113671b8d23a3412cdbb42419accb" + resolved "https://registry.npmjs.org/@tiptap/extension-table/-/extension-table-2.5.4.tgz" integrity sha512-EvK3XQmbuje0re8xCXuGcPO1NgnRh1MYUe2zi4++rPNDN2nTzCvJI1QdYfA9DYMdklnpvygnXCJhgvx1rB/26Q== "@tiptap/extension-text-align@^2.0.3": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-text-align/-/extension-text-align-2.5.4.tgz#d4521ba87cab5249b5df7b0f1e4db5ac40c387a0" + resolved "https://registry.npmjs.org/@tiptap/extension-text-align/-/extension-text-align-2.5.4.tgz" integrity sha512-hQT7wPVISw7fgMTT0XfK6uk3T2qLKpeYWOUBO1ENEdim6HQmFTOIgNyAdVcCipaedQSlD72ysfRXq2S1mzWzEw== "@tiptap/extension-text-style@^2.0.3": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.5.4.tgz#ff7f67f7eb8f035a8ca8d98b112948bc850c9364" + resolved "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-2.5.4.tgz" integrity sha512-OwQ6rQrwVSCTicxJJ67C5Z+LQjZp9HyZDeEcrQgPsv/gtk6H69qo1jShHAdmYn4ck40CkuNyN6VKczd9VZf0+g== "@tiptap/extension-text@^2.5.4": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.5.4.tgz#235638ad08975a321dae4f2a2c1e495f38bd3adb" + resolved "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.5.4.tgz" integrity sha512-+3x/hYqhmCYbvedCcQzQHFtZ5MAcMOlKuczomZtygf8AfDfuQVrG1m4GoJyNzJdqxjN80/xq4e2vDVvqQxYTCw== "@tiptap/extension-typography@^2.0.3": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/extension-typography/-/extension-typography-2.5.4.tgz#6b3615e047de4ae0574c258ae865a2a96187f79c" + resolved "https://registry.npmjs.org/@tiptap/extension-typography/-/extension-typography-2.5.4.tgz" integrity sha512-LXctwoKdmWw9geXngQWGHcwEHIYLJ5v7GX3GuudN+oHhSV2MTGUTYZ2qv/RLIR9kvB0vcV9vTF98YJxEnjU5Fw== "@tiptap/pm@^2.0.3": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.5.4.tgz#6d66cd8ab3bd696958a4a62f34d2032a82a28910" + resolved "https://registry.npmjs.org/@tiptap/pm/-/pm-2.5.4.tgz" integrity sha512-oFIsuniptdUXn93x4aM2sVN3hYKo9Fj55zAkYrWhwxFYUYcPxd5ibra2we+wRK5TaiPu098wpC+yMSTZ/KKMpA== dependencies: prosemirror-changeset "^2.2.1" @@ -446,7 +996,7 @@ "@tiptap/starter-kit@^2.0.3": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.5.4.tgz#81150a023e07f8c3a4c05e8fd3d0cfe0c4381df8" + resolved "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-2.5.4.tgz" integrity sha512-IYnSETtBUSsy+Ece4kfVyzew+zyj7W9rP2Ronx0CbjeWQarfCAGxjuZ6uGLPB+tC5ZuMVt68Gyqb2y8GFes2Yw== dependencies: "@tiptap/core" "^2.5.4" @@ -471,12 +1021,12 @@ "@tiptap/suggestion@^2.0.3": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.5.4.tgz#b5aad02c3408cc5bcdc5bc4539fc1f3c8d381671" + resolved "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-2.5.4.tgz" integrity sha512-mf0gC237PFz5l/hFRIetZoXemLMUXtmTPRbHTgBzqkTfaiJhfWsZZ3VeQNh4hoQ5AGYxRHWb9+zgRNGsH4jAEw== "@tiptap/vue-3@^2.0.3": version "2.5.4" - resolved "https://registry.yarnpkg.com/@tiptap/vue-3/-/vue-3-2.5.4.tgz#87f9bb39fed52237e0b5978100da78a951c1d3a1" + resolved "https://registry.npmjs.org/@tiptap/vue-3/-/vue-3-2.5.4.tgz" integrity sha512-7pr1WnWfXiSPIzkGEM/8S10ANAfgZzfQ5MiAtszxKOHJjrndpj5W4OgXxPEht5sMaPj0eRbGIFOkgKqTNut1dQ== dependencies: "@tiptap/extension-bubble-menu" "^2.5.4" @@ -487,6 +1037,20 @@ resolved "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== +"@types/conventional-commits-parser@^5.0.0": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.1.tgz#8cb81cf170853496cbc501a3b32dcf5e46ffb61a" + integrity sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ== + dependencies: + "@types/node" "*" + +"@types/node@*": + version "22.10.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.2.tgz#a485426e6d1fdafc7b0d4c7b24e2c78182ddabb9" + integrity sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ== + dependencies: + undici-types "~6.20.0" + "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz" @@ -494,12 +1058,12 @@ "@types/web-bluetooth@^0.0.20": version "0.0.20" - resolved "https://registry.yarnpkg.com/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz#f066abfcd1cbe66267cdbbf0de010d8a41b41597" + resolved "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz" integrity sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow== "@vueuse/core@^10.11.0", "@vueuse/core@^10.4.1": version "10.11.0" - resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-10.11.0.tgz#b042585a8bf98bb29c177b33999bd0e3fcd9e65d" + resolved "https://registry.npmjs.org/@vueuse/core/-/core-10.11.0.tgz" integrity sha512-x3sD4Mkm7PJ+pcq3HX8PLPBadXCAlSDR/waK87dz0gQE+qJnaaFhc/dZVfJz+IUYzTMVGum2QlR7ImiJQN4s6g== dependencies: "@types/web-bluetooth" "^0.0.20" @@ -509,16 +1073,24 @@ "@vueuse/metadata@10.11.0": version "10.11.0" - resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-10.11.0.tgz#27be47cf115ee98e947a1bfcd0b1b5b35d785fb6" + resolved "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.11.0.tgz" integrity sha512-kQX7l6l8dVWNqlqyN3ePW3KmjCQO3ZMgXuBMddIu83CmucrsBfXlH+JoviYyRBws/yLTQO8g3Pbw+bdIoVm4oQ== "@vueuse/shared@10.11.0", "@vueuse/shared@^10.11.0": version "10.11.0" - resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-10.11.0.tgz#be09262b2c5857069ed3dadd1680f22c4cb6f984" + resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-10.11.0.tgz" integrity sha512-fyNoIXEq3PfX1L3NkNhtVQUSRtqYwJtJg+Bp9rIzculIZWHTkKSysujrOk2J+NrRulLTQH9+3gGSfYLWSEWU1A== dependencies: vue-demi ">=0.14.8" +JSONStream@^1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + acorn-node@^1.6.1: version "1.8.2" resolved "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz" @@ -538,6 +1110,21 @@ acorn@^7.0.0: resolved "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz" integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== +ajv@^8.11.0: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" @@ -545,6 +1132,13 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + ansi-styles@^4.1.0: version "4.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz" @@ -555,7 +1149,7 @@ ansi-styles@^4.1.0: any-promise@^1.0.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz" integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== anymatch@~3.1.2: @@ -573,21 +1167,31 @@ arg@^5.0.1: arg@^5.0.2: version "5.0.2" - resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" + resolved "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz" integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== argparse@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== aria-hidden@^1.2.4: version "1.2.4" - resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.4.tgz#b78e383fdbc04d05762c78b4a25a501e736c4522" + resolved "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz" integrity sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A== dependencies: tslib "^2.0.0" +array-ify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" + integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== + +array-timsort@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-timsort/-/array-timsort-1.0.3.tgz#3c9e4199e54fb2b9c3fe5976396a21614ef0d926" + integrity sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ== + autoprefixer@^10.4.2: version "10.4.2" resolved "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.2.tgz" @@ -615,7 +1219,7 @@ autoprefixer@^9: balanced-match@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== binary-extensions@^2.0.0: @@ -625,15 +1229,15 @@ binary-extensions@^2.0.0: brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^3.0.1, braces@^3.0.2, braces@~3.0.2: +braces@^3.0.3, braces@~3.0.2: version "3.0.3" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: fill-range "^7.1.1" @@ -654,7 +1258,7 @@ bytes@^3.0.0: resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== -callsites@^3.0.0: +callsites@^3.0.0, callsites@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== @@ -669,6 +1273,13 @@ caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001286, caniuse-lite@^1.0.300012 resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001382.tgz" integrity sha512-2rtJwDmSZ716Pxm1wCtbPvHtbDWAreTPxXbkc5RkKglow3Ig/4GNGazDI9/BVnXbG/wnv6r3B5FEbkfg9OcTGg== +chalk-template@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/chalk-template/-/chalk-template-1.1.0.tgz#ffc55db6dd745e9394b85327c8ac8466edb7a7b1" + integrity sha512-T2VJbcDuZQ0Tb2EWwSotMPJjgpy1/tGee1BTpUNsGZ/qgNjV2t7Mvu+d4600U564nbLesN1x2dPL+xii174Ekg== + dependencies: + chalk "^5.2.0" + chalk@^2.0.0, chalk@^2.4.1: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" @@ -686,6 +1297,11 @@ chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^5.2.0, chalk@^5.3.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.4.1.tgz#1b48bf0963ec158dce2aacf69c093ae2dd2092d8" + integrity sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w== + chokidar@^3.5.2, chokidar@^3.5.3: version "3.5.3" resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" @@ -703,9 +1319,26 @@ chokidar@^3.5.2, chokidar@^3.5.3: classnames@^2.2.5: version "2.5.1" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" + resolved "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz" integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== +clear-module@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/clear-module/-/clear-module-4.1.2.tgz#5a58a5c9f8dccf363545ad7284cad3c887352a80" + integrity sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw== + dependencies: + parent-module "^2.0.0" + resolve-from "^5.0.0" + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" @@ -746,9 +1379,14 @@ color@^4.0.1: color-convert "^2.0.1" color-string "^1.6.0" +commander@^12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== + commander@^4.0.0: version "4.1.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== commander@^6.0.0: @@ -758,19 +1396,82 @@ commander@^6.0.0: commander@^9.0.0: version "9.5.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" + resolved "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz" integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== +comment-json@^4.2.5: + version "4.2.5" + resolved "https://registry.yarnpkg.com/comment-json/-/comment-json-4.2.5.tgz#482e085f759c2704b60bc6f97f55b8c01bc41e70" + integrity sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw== + dependencies: + array-timsort "^1.0.3" + core-util-is "^1.0.3" + esprima "^4.0.1" + has-own-prop "^2.0.0" + repeat-string "^1.6.1" + +commitlint@^19.6.1: + version "19.6.1" + resolved "https://registry.yarnpkg.com/commitlint/-/commitlint-19.6.1.tgz#8fbfc2ee8cd62172360923679287841b536ee271" + integrity sha512-tU4or+Y2fDXepCZ44o8guEB9uwrRp4if4VupGH1CR+bsVS2zX6Gia4dndA7UPx8cWWw1tvRRJu5keA7RqfXf3w== + dependencies: + "@commitlint/cli" "^19.6.1" + "@commitlint/types" "^19.5.0" + +compare-func@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" + integrity sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA== + dependencies: + array-ify "^1.0.0" + dot-prop "^5.1.0" + concat-map@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +conventional-changelog-angular@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz#5eec8edbff15aa9b1680a8dcfbd53e2d7eb2ba7a" + integrity sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ== + dependencies: + compare-func "^2.0.0" + +conventional-changelog-conventionalcommits@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz#aa5da0f1b2543094889e8cf7616ebe1a8f5c70d5" + integrity sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w== + dependencies: + compare-func "^2.0.0" + +conventional-commits-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz#57f3594b81ad54d40c1b4280f04554df28627d9a" + integrity sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA== + dependencies: + JSONStream "^1.3.5" + is-text-path "^2.0.0" + meow "^12.0.1" + split2 "^4.0.0" + core-js@^3.1.3: version "3.37.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.37.1.tgz#d21751ddb756518ac5a00e4d66499df981a62db9" + resolved "https://registry.npmjs.org/core-js/-/core-js-3.37.1.tgz" integrity sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw== +core-util-is@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cosmiconfig-typescript-loader@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.1.0.tgz#7f644503e1c2bff90aed2d29a637008f279646bb" + integrity sha512-tJ1w35ZRUiM5FeTzT7DtYWAFFv37ZLqSRkGi2oeCK1gPhvaWjkAtfXvLmvE1pRfxxp9aQo6ba/Pvg1dKj05D4g== + dependencies: + jiti "^2.4.1" + cosmiconfig@^7.0.1: version "7.0.1" resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz" @@ -782,11 +1483,137 @@ cosmiconfig@^7.0.1: path-type "^4.0.0" yaml "^1.10.0" +cosmiconfig@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d" + integrity sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg== + dependencies: + env-paths "^2.2.1" + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" + crelt@^1.0.0: version "1.0.6" - resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72" + resolved "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz" integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g== +cspell-config-lib@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/cspell-config-lib/-/cspell-config-lib-8.17.1.tgz#a87973b91d51bf23a2018042c25aeaaa8a4e69c0" + integrity sha512-x1S7QWprgUcwuwiJB1Ng0ZTBC4G50qP9qQyg/aroMkcdMsHfk26E8jUGRPNt4ftHFzS4YMhwtXuJQ9IgRUuNPA== + dependencies: + "@cspell/cspell-types" "8.17.1" + comment-json "^4.2.5" + yaml "^2.6.1" + +cspell-dictionary@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/cspell-dictionary/-/cspell-dictionary-8.17.1.tgz#bfc9bfdbd3720d1425260a98091acffab7b03dd5" + integrity sha512-zSl9l3wii+x16yc2NVZl/+CMLeLBAiuEd5YoFkOYPcbTJnfPwdjMNcj71u7wBvNJ+qwbF+kGbutEt15yHW3NBw== + dependencies: + "@cspell/cspell-pipe" "8.17.1" + "@cspell/cspell-types" "8.17.1" + cspell-trie-lib "8.17.1" + fast-equals "^5.0.1" + +cspell-gitignore@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/cspell-gitignore/-/cspell-gitignore-8.17.1.tgz#38f3213a40ba86480bb5f66a91198db6e0ef37c0" + integrity sha512-bk727Zf4FBCjm9Mwvyreyhgjwe+YhPQEW7PldkHiinKd+Irfez4s8GXLQb1EgV0UpvViqaqBqLmngjZdS30BTA== + dependencies: + "@cspell/url" "8.17.1" + cspell-glob "8.17.1" + cspell-io "8.17.1" + find-up-simple "^1.0.0" + +cspell-glob@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/cspell-glob/-/cspell-glob-8.17.1.tgz#23d1be46b32fb4933487e4edff347d34db446f5a" + integrity sha512-cUwM5auSt0RvLX7UkP2GEArJRWc85l51B1voArl+3ZIKeMZwcJpJgN3qvImtF8yRTZwYeYCs1sgsihb179q+mg== + dependencies: + "@cspell/url" "8.17.1" + micromatch "^4.0.8" + +cspell-grammar@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/cspell-grammar/-/cspell-grammar-8.17.1.tgz#8f6619fbfaebff6aeee63b13d17898b4d0c09136" + integrity sha512-H5tLcBuW7aUj9L0rR+FSbnWPEsWb8lWppHVidtqw9Ll1CUHWOZC9HTB2RdrhJZrsz/8DJbM2yNbok0Xt0VAfdw== + dependencies: + "@cspell/cspell-pipe" "8.17.1" + "@cspell/cspell-types" "8.17.1" + +cspell-io@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/cspell-io/-/cspell-io-8.17.1.tgz#b91f1cac1c64a6fa2b61a388d0dc67437fcf3ada" + integrity sha512-liIOsblt7oVItifzRAbuxiYrwlgw1VOqKppMxVKtYoAn2VUuuEpjCj6jLWpoTqSszR/38o7ChsHY1LHakhJZmw== + dependencies: + "@cspell/cspell-service-bus" "8.17.1" + "@cspell/url" "8.17.1" + +cspell-lib@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/cspell-lib/-/cspell-lib-8.17.1.tgz#21c76f1ea4e91c90245e55acddbf452d055a6607" + integrity sha512-66n83Q7bK5tnvkDH7869/pBY/65AKmZVfCOAlsbhJn3YMDbNHFCHR0d1oNMlqG+n65Aco89VGwYfXxImZY+/mA== + dependencies: + "@cspell/cspell-bundled-dicts" "8.17.1" + "@cspell/cspell-pipe" "8.17.1" + "@cspell/cspell-resolver" "8.17.1" + "@cspell/cspell-types" "8.17.1" + "@cspell/dynamic-import" "8.17.1" + "@cspell/filetypes" "8.17.1" + "@cspell/strong-weak-map" "8.17.1" + "@cspell/url" "8.17.1" + clear-module "^4.1.2" + comment-json "^4.2.5" + cspell-config-lib "8.17.1" + cspell-dictionary "8.17.1" + cspell-glob "8.17.1" + cspell-grammar "8.17.1" + cspell-io "8.17.1" + cspell-trie-lib "8.17.1" + env-paths "^3.0.0" + fast-equals "^5.0.1" + gensequence "^7.0.0" + import-fresh "^3.3.0" + resolve-from "^5.0.0" + vscode-languageserver-textdocument "^1.0.12" + vscode-uri "^3.0.8" + xdg-basedir "^5.1.0" + +cspell-trie-lib@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/cspell-trie-lib/-/cspell-trie-lib-8.17.1.tgz#618e5cc671b0a24cf7ec27a9a9b834b197e17392" + integrity sha512-13WNa5s75VwOjlGzWprmfNbBFIfXyA7tYYrbV+LugKkznyNZJeJPojHouEudcLq3SYb2Q6tJ7qyWcuT5bR9qPA== + dependencies: + "@cspell/cspell-pipe" "8.17.1" + "@cspell/cspell-types" "8.17.1" + gensequence "^7.0.0" + +cspell@^8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/cspell/-/cspell-8.17.1.tgz#be3c79a5b0b2e374ac0df8f921eb30ddca170110" + integrity sha512-D0lw8XTXrTycNzOn5DkfPJNUT00X53OgvFDm+0SzhBr1r+na8LEh3CnQ6zKYVU0fL0x8vU82vs4jmGjDho9mPg== + dependencies: + "@cspell/cspell-json-reporter" "8.17.1" + "@cspell/cspell-pipe" "8.17.1" + "@cspell/cspell-types" "8.17.1" + "@cspell/dynamic-import" "8.17.1" + "@cspell/url" "8.17.1" + chalk "^5.3.0" + chalk-template "^1.1.0" + commander "^12.1.0" + cspell-dictionary "8.17.1" + cspell-gitignore "8.17.1" + cspell-glob "8.17.1" + cspell-io "8.17.1" + cspell-lib "8.17.1" + fast-json-stable-stringify "^2.1.0" + file-entry-cache "^9.1.0" + get-stdin "^9.0.0" + semver "^7.6.3" + tinyglobby "^0.2.10" + css-color-names@^0.0.4: version "0.0.4" resolved "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz" @@ -802,14 +1629,19 @@ cssesc@^3.0.0: resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== +dargs@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/dargs/-/dargs-8.1.0.tgz#a34859ea509cbce45485e5aa356fef70bfcc7272" + integrity sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw== + dayjs@^1.11.10: version "1.11.10" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0" + resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz" integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ== debug@~4.3.1, debug@~4.3.2: version "4.3.5" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== dependencies: ms "2.1.2" @@ -821,7 +1653,7 @@ defined@^1.0.0: defu@^6.1.4: version "6.1.4" - resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.4.tgz#4e0c9cf9ff68fe5f3d7f2765cc1a012dfdcb0479" + resolved "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz" integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg== detective@^5.2.0: @@ -843,14 +1675,26 @@ dlv@^1.1.3: resolved "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz" integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== +dot-prop@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== + dependencies: + is-obj "^2.0.0" + electron-to-chromium@^1.4.17: version "1.4.65" resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.65.tgz" integrity sha512-0/d8Skk8sW3FxXP0Dd6MnBlrwx7Qo9cqQec3BlIAlvKnrmS3pHsIbaroEi+nd0kZkGpQ6apMEre7xndzjlEnLw== +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + engine.io-client@~6.5.2: version "6.5.4" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.5.4.tgz#b8bc71ed3f25d0d51d587729262486b4b33bd0d0" + resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz" integrity sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ== dependencies: "@socket.io/component-emitter" "~3.1.0" @@ -861,14 +1705,24 @@ engine.io-client@~6.5.2: engine.io-parser@~5.2.1: version "5.2.3" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.3.tgz#00dc5b97b1f233a23c9398d0209504cf5f94d92f" + resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz" integrity sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q== entities@^4.4.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== +env-paths@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + +env-paths@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-3.0.0.tgz#2f1e89c2f6dbd3408e1b1711dd82d62e317f58da" + integrity sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A== + error-ex@^1.3.1: version "1.3.2" resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" @@ -888,14 +1742,24 @@ escape-string-regexp@^1.0.5: escape-string-regexp@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + fast-deep-equal@^3.1.3: version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-equals@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-5.0.1.tgz#a4eefe3c5d1c0d021aeed0bc10ba5e0c12ee405d" + integrity sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ== + fast-glob@^3.2.7: version "3.2.11" resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz" @@ -909,7 +1773,7 @@ fast-glob@^3.2.7: fast-glob@^3.3.0: version "3.3.2" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== dependencies: "@nodelib/fs.stat" "^2.0.2" @@ -918,6 +1782,16 @@ fast-glob@^3.3.0: merge2 "^1.3.0" micromatch "^4.0.4" +fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-uri@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.3.tgz#892a1c91802d5d7860de728f18608a0573142241" + integrity sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw== + fastq@^1.6.0: version "1.6.1" resolved "https://registry.npmjs.org/fastq/-/fastq-1.6.1.tgz" @@ -925,21 +1799,60 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +fdir@^6.4.2: + version "6.4.2" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.2.tgz#ddaa7ce1831b161bc3657bb99cb36e1622702689" + integrity sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ== + feather-icons@^4.28.0: version "4.29.2" - resolved "https://registry.yarnpkg.com/feather-icons/-/feather-icons-4.29.2.tgz#b03a47588a1c400f215e884504db1c18860d89f8" + resolved "https://registry.npmjs.org/feather-icons/-/feather-icons-4.29.2.tgz" integrity sha512-0TaCFTnBTVCz6U+baY2UJNKne5ifGh7sMG4ZC2LoBWCZdIyPa+y6UiR4lEYGws1JOFWdee8KAsAIvu0VcXqiqA== dependencies: classnames "^2.2.5" core-js "^3.1.3" +file-entry-cache@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-9.1.0.tgz#2e66ad98ce93f49aed1b178c57b0b5741591e075" + integrity sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg== + dependencies: + flat-cache "^5.0.0" + fill-range@^7.1.1: version "7.1.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz" integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" +find-up-simple@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/find-up-simple/-/find-up-simple-1.0.0.tgz#21d035fde9fdbd56c8f4d2f63f32fd93a1cfc368" + integrity sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw== + +find-up@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-7.0.0.tgz#e8dec1455f74f78d888ad65bf7ca13dd2b4e66fb" + integrity sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g== + dependencies: + locate-path "^7.2.0" + path-exists "^5.0.0" + unicorn-magic "^0.1.0" + +flat-cache@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-5.0.0.tgz#26c4da7b0f288b408bb2b506b2cb66c240ddf062" + integrity sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ== + dependencies: + flatted "^3.3.1" + keyv "^4.5.4" + +flatted@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" + integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== + fraction.js@^4.1.2: version "4.1.2" resolved "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz" @@ -947,7 +1860,7 @@ fraction.js@^4.1.2: frappe-ui@^0.1.70: version "0.1.70" - resolved "https://registry.yarnpkg.com/frappe-ui/-/frappe-ui-0.1.70.tgz#4cdf705d7f344ac1ab8dff7e579476a4d54ec9a2" + resolved "https://registry.npmjs.org/frappe-ui/-/frappe-ui-0.1.70.tgz" integrity sha512-R8xrRbFm+Htx+GmsWtmfLij9GOojoFGibhqQqSFQb5DgBAjaIcr0JMieXV2Ze36EpzK2PqqUYxGDdQmQowknew== dependencies: "@headlessui/vue" "^1.7.14" @@ -995,9 +1908,9 @@ fs.realpath@^1.0.0: integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== function-bind@^1.1.1: version "1.1.1" @@ -1006,14 +1919,38 @@ function-bind@^1.1.1: function-bind@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== fuse.js@^6.6.2: version "6.6.2" - resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-6.6.2.tgz#fe463fed4b98c0226ac3da2856a415576dc9a111" + resolved "https://registry.npmjs.org/fuse.js/-/fuse.js-6.6.2.tgz" integrity sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA== +gensequence@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/gensequence/-/gensequence-7.0.0.tgz#bb6aedec8ff665e3a6c42f92823121e3a6ea7718" + integrity sha512-47Frx13aZh01afHJTB3zTtKIlFI6vWY+MYCN9Qpew6i52rfKjnhCF/l1YlC8UmEMvvntZZ6z4PiCcmyuedR2aQ== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-stdin@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575" + integrity sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA== + +git-raw-commits@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-4.0.0.tgz#b212fd2bff9726d27c1283a1157e829490593285" + integrity sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ== + dependencies: + dargs "^8.0.0" + meow "^12.0.1" + split2 "^4.0.0" + glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" @@ -1040,6 +1977,13 @@ glob@7.1.6, glob@^7.0.0, glob@^7.1.2, glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +global-directory@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/global-directory/-/global-directory-4.0.1.tgz#4d7ac7cfd2cb73f304c53b8810891748df5e361e" + integrity sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q== + dependencies: + ini "4.1.1" + graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.3" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz" @@ -1055,6 +1999,11 @@ has-flag@^4.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-own-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-own-prop/-/has-own-prop-2.0.0.tgz#f0f95d58f65804f5d218db32563bb85b8e0417af" + integrity sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ== + has@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" @@ -1064,7 +2013,7 @@ has@^1.0.3: hasown@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz" integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== dependencies: function-bind "^1.1.2" @@ -1091,7 +2040,7 @@ html-tags@^3.1.0: idb-keyval@^6.2.0: version "6.2.1" - resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-6.2.1.tgz#94516d625346d16f56f3b33855da11bfded2db33" + resolved "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz" integrity sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg== import-cwd@^3.0.0: @@ -1101,7 +2050,7 @@ import-cwd@^3.0.0: dependencies: import-from "^3.0.0" -import-fresh@^3.2.1: +import-fresh@^3.2.1, import-fresh@^3.3.0: version "3.3.0" resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -1116,6 +2065,11 @@ import-from@^3.0.0: dependencies: resolve-from "^5.0.0" +import-meta-resolve@^4.0.0, import-meta-resolve@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#f9db8bead9fafa61adb811db77a2bf22c5399706" + integrity sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" @@ -1129,6 +2083,11 @@ inherits@2: resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +ini@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.1.tgz#d95b3d843b1e906e56d6747d5447904ff50ce7a1" + integrity sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g== + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" @@ -1160,7 +2119,7 @@ is-color-stop@^1.1.0: is-core-module@^2.13.0: version "2.13.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz" integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== dependencies: hasown "^2.0.0" @@ -1177,6 +2136,11 @@ is-extglob@^2.1.1: resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" @@ -1189,21 +2153,55 @@ is-number@^7.0.0: resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-text-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-2.0.0.tgz#b2484e2b720a633feb2e85b67dc193ff72c75636" + integrity sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw== + dependencies: + text-extensions "^2.0.0" + jiti@^1.19.1: version "1.21.0" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" + resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz" integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== +jiti@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560" + integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A== + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz" @@ -1213,6 +2211,18 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== + +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + libarchive.js@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/libarchive.js/-/libarchive.js-1.3.0.tgz" @@ -1225,12 +2235,12 @@ lilconfig@^2.0.3: lilconfig@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz" integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== lilconfig@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.0.0.tgz#f8067feb033b5b74dab4602a5f5029420be749bc" + resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz" integrity sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g== lines-and-columns@^1.1.6: @@ -1240,16 +2250,28 @@ lines-and-columns@^1.1.6: linkify-it@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-5.0.0.tgz#9ef238bfa6dc70bd8e7f9572b52d369af569b421" + resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz" integrity sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ== dependencies: uc.micro "^2.0.0" linkifyjs@^4.1.0: version "4.1.3" - resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-4.1.3.tgz#0edbc346428a7390a23ea2e5939f76112c9ae07f" + resolved "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.1.3.tgz" integrity sha512-auMesunaJ8yfkHvK4gfg1K0SaKX/6Wn9g2Aac/NwX+l5VdmFZzo/hdPGxEOETj+ryRa4/fiOPjeeKURSAJx1sg== +locate-path@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-7.2.0.tgz#69cb1779bd90b35ab1e771e1f2f89a202c2a8a8a" + integrity sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA== + dependencies: + p-locate "^6.0.0" + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + lodash.castarray@^4.4.0: version "4.4.0" resolved "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz" @@ -1260,16 +2282,46 @@ lodash.isplainobject@^4.0.6: resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz" integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= +lodash.kebabcase@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" + integrity sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.mergewith@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" + integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== + +lodash.snakecase@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d" + integrity sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw== + +lodash.startcase@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.startcase/-/lodash.startcase-4.4.0.tgz#9436e34ed26093ed7ffae1936144350915d9add8" + integrity sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg== + lodash.topath@^4.5.2: version "4.5.2" resolved "https://registry.npmjs.org/lodash.topath/-/lodash.topath-4.5.2.tgz" integrity sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak= +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== + +lodash.upperfirst@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" + integrity sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg== + lodash@^4.17.21: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" @@ -1277,7 +2329,7 @@ lodash@^4.17.21: markdown-it@^14.0.0: version "14.1.0" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.1.0.tgz#3c3c5992883c633db4714ccb4d7b5935d98b7d45" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz" integrity sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg== dependencies: argparse "^2.0.1" @@ -1289,28 +2341,25 @@ markdown-it@^14.0.0: mdurl@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-2.0.0.tgz#80676ec0433025dd3e17ee983d0fe8de5a2237e0" + resolved "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz" integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w== +meow@^12.0.1: + version "12.1.1" + resolved "https://registry.yarnpkg.com/meow/-/meow-12.1.1.tgz#e558dddbab12477b69b2e9a2728c327f191bace6" + integrity sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw== + merge2@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz" integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw== -micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== - dependencies: - braces "^3.0.1" - picomatch "^2.2.3" - -micromatch@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" mini-svg-data-uri@^1.2.3: @@ -1320,15 +2369,15 @@ mini-svg-data-uri@^1.2.3: minimatch@^3.0.4: version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" -minimist@^1.1.1: - version "1.2.6" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" - integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== +minimist@^1.1.1, minimist@^1.2.8: + version "1.2.8" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== modern-normalize@^1.1.0: version "1.1.0" @@ -1337,31 +2386,26 @@ modern-normalize@^1.1.0: ms@2.1.2: version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== mz@^2.7.0: version "2.7.0" - resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + resolved "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz" integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== dependencies: any-promise "^1.0.0" object-assign "^4.0.1" thenify-all "^1.0.0" -nanoid@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz" - integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA== - -nanoid@^3.3.6: - version "3.3.7" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" - integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== +nanoid@^3.3.7: + version "3.3.8" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz" + integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== nanoid@^5.0.7: version "5.0.7" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-5.0.7.tgz#6452e8c5a816861fd9d2b898399f7e5fd6944cc6" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-5.0.7.tgz" integrity sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ== node-emoji@^1.11.0: @@ -1403,7 +2447,7 @@ object-hash@^2.2.0: object-hash@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" + resolved "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz" integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== once@^1.3.0: @@ -1415,9 +2459,23 @@ once@^1.3.0: orderedmap@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/orderedmap/-/orderedmap-2.1.1.tgz#61481269c44031c449915497bf5a4ad273c512d2" + resolved "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz" integrity sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g== +p-limit@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-4.0.0.tgz#914af6544ed32bfa54670b061cafcbd04984b644" + integrity sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ== + dependencies: + yocto-queue "^1.0.0" + +p-locate@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-6.0.0.tgz#3da9a49d4934b901089dca3302fa65dc5a05c04f" + integrity sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw== + dependencies: + p-limit "^4.0.0" + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" @@ -1425,7 +2483,14 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-json@^5.0.0: +parent-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-2.0.0.tgz#fa71f88ff1a50c27e15d8ff74e0e3a9523bf8708" + integrity sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg== + dependencies: + callsites "^3.1.0" + +parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -1435,6 +2500,11 @@ parse-json@^5.0.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" +path-exists@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-5.0.0.tgz#a6aad9489200b21fab31e49cf09277e5116fb9e7" + integrity sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ== + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" @@ -1455,34 +2525,34 @@ picocolors@^0.2.1: resolved "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz" integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.0.0, picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== picomatch@^2.0.4, picomatch@^2.2.1: version "2.2.1" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz" integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA== -picomatch@^2.2.3: - version "2.3.0" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz" - integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== - picomatch@^2.3.1: version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== + pify@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== pirates@^4.0.1: version "4.0.6" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz" integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== postcss-functions@^3: @@ -1497,7 +2567,7 @@ postcss-functions@^3: postcss-import@^15.1.0: version "15.1.0" - resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-15.1.0.tgz#41c64ed8cc0e23735a9698b3249ffdbf704adc70" + resolved "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz" integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew== dependencies: postcss-value-parser "^4.0.0" @@ -1514,7 +2584,7 @@ postcss-js@^2: postcss-js@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2" + resolved "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz" integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw== dependencies: camelcase-css "^2.0.1" @@ -1530,7 +2600,7 @@ postcss-load-config@^3.1.0: postcss-load-config@^4.0.1: version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3" + resolved "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz" integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ== dependencies: lilconfig "^3.0.0" @@ -1546,14 +2616,14 @@ postcss-nested@^4: postcss-nested@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.0.1.tgz#f83dc9846ca16d2f4fa864f16e9d9f7d0961662c" + resolved "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz" integrity sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ== dependencies: postcss-selector-parser "^6.0.11" postcss-selector-parser@6.0.10: version "6.0.10" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d" + resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz" integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w== dependencies: cssesc "^3.0.0" @@ -1561,7 +2631,7 @@ postcss-selector-parser@6.0.10: postcss-selector-parser@^6.0.11: version "6.0.13" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b" + resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz" integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ== dependencies: cssesc "^3.0.0" @@ -1602,27 +2672,18 @@ postcss@^7, postcss@^7.0.18, postcss@^7.0.32: picocolors "^0.2.1" source-map "^0.6.1" -postcss@^8.2.1, postcss@^8.4.6: - version "8.4.6" - resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz" - integrity sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA== - dependencies: - nanoid "^3.2.0" - picocolors "^1.0.0" - source-map-js "^1.0.2" - -postcss@^8.4.23: - version "8.4.31" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" - integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== +postcss@^8.2.1, postcss@^8.4.23, postcss@^8.4.6: + version "8.4.49" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz" + integrity sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA== dependencies: - nanoid "^3.3.6" - picocolors "^1.0.0" - source-map-js "^1.0.2" + nanoid "^3.3.7" + picocolors "^1.1.1" + source-map-js "^1.2.1" prettier@^3.3.2: version "3.3.3" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" + resolved "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz" integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== pretty-hrtime@^1.0.3: @@ -1632,21 +2693,21 @@ pretty-hrtime@^1.0.3: prosemirror-changeset@^2.2.1: version "2.2.1" - resolved "https://registry.yarnpkg.com/prosemirror-changeset/-/prosemirror-changeset-2.2.1.tgz#dae94b63aec618fac7bb9061648e6e2a79988383" + resolved "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.2.1.tgz" integrity sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ== dependencies: prosemirror-transform "^1.0.0" prosemirror-collab@^1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz#0e8c91e76e009b53457eb3b3051fb68dad029a33" + resolved "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz" integrity sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ== dependencies: prosemirror-state "^1.0.0" prosemirror-commands@^1.0.0, prosemirror-commands@^1.5.2: version "1.5.2" - resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.5.2.tgz#e94aeea52286f658cd984270de9b4c3fff580852" + resolved "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.5.2.tgz" integrity sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ== dependencies: prosemirror-model "^1.0.0" @@ -1655,7 +2716,7 @@ prosemirror-commands@^1.0.0, prosemirror-commands@^1.5.2: prosemirror-dropcursor@^1.8.1: version "1.8.1" - resolved "https://registry.yarnpkg.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.1.tgz#49b9fb2f583e0d0f4021ff87db825faa2be2832d" + resolved "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.1.tgz" integrity sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw== dependencies: prosemirror-state "^1.0.0" @@ -1664,7 +2725,7 @@ prosemirror-dropcursor@^1.8.1: prosemirror-gapcursor@^1.3.2: version "1.3.2" - resolved "https://registry.yarnpkg.com/prosemirror-gapcursor/-/prosemirror-gapcursor-1.3.2.tgz#5fa336b83789c6199a7341c9493587e249215cb4" + resolved "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.3.2.tgz" integrity sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ== dependencies: prosemirror-keymap "^1.0.0" @@ -1674,7 +2735,7 @@ prosemirror-gapcursor@^1.3.2: prosemirror-history@^1.0.0, prosemirror-history@^1.4.1: version "1.4.1" - resolved "https://registry.yarnpkg.com/prosemirror-history/-/prosemirror-history-1.4.1.tgz#cc370a46fb629e83a33946a0e12612e934ab8b98" + resolved "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.4.1.tgz" integrity sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ== dependencies: prosemirror-state "^1.2.2" @@ -1684,7 +2745,7 @@ prosemirror-history@^1.0.0, prosemirror-history@^1.4.1: prosemirror-inputrules@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/prosemirror-inputrules/-/prosemirror-inputrules-1.4.0.tgz#ef1519bb2cb0d1e0cec74bad1a97f1c1555068bb" + resolved "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.4.0.tgz" integrity sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg== dependencies: prosemirror-state "^1.0.0" @@ -1692,7 +2753,7 @@ prosemirror-inputrules@^1.4.0: prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.1.2, prosemirror-keymap@^1.2.2: version "1.2.2" - resolved "https://registry.yarnpkg.com/prosemirror-keymap/-/prosemirror-keymap-1.2.2.tgz#14a54763a29c7b2704f561088ccf3384d14eb77e" + resolved "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.2.tgz" integrity sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ== dependencies: prosemirror-state "^1.0.0" @@ -1700,7 +2761,7 @@ prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.1.2, prosemirror-keymap@^1.2.2: prosemirror-markdown@^1.13.0: version "1.13.0" - resolved "https://registry.yarnpkg.com/prosemirror-markdown/-/prosemirror-markdown-1.13.0.tgz#67ebfa40af48a22d1e4ed6cad2e29851eb61e649" + resolved "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.0.tgz" integrity sha512-UziddX3ZYSYibgx8042hfGKmukq5Aljp2qoBiJRejD/8MH70siQNz5RB1TrdTPheqLMy4aCe4GYNF10/3lQS5g== dependencies: markdown-it "^14.0.0" @@ -1708,7 +2769,7 @@ prosemirror-markdown@^1.13.0: prosemirror-menu@^1.2.4: version "1.2.4" - resolved "https://registry.yarnpkg.com/prosemirror-menu/-/prosemirror-menu-1.2.4.tgz#3cfdc7c06d10f9fbd1bce29082c498bd11a0a79a" + resolved "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.2.4.tgz" integrity sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA== dependencies: crelt "^1.0.0" @@ -1718,21 +2779,21 @@ prosemirror-menu@^1.2.4: prosemirror-model@^1.0.0, prosemirror-model@^1.19.0, prosemirror-model@^1.20.0, prosemirror-model@^1.21.0, prosemirror-model@^1.22.1, prosemirror-model@^1.8.1: version "1.22.1" - resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.22.1.tgz#2ed7d7840e710172c559d5a9950e92b870d1e764" + resolved "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.22.1.tgz" integrity sha512-gMrxal+F3higDFxCkBK5iQXckRVYvIu/3dopERJ6b20xfwZ9cbYvQvuldqaN+v/XytNPGyURYUpUU23kBRxWCQ== dependencies: orderedmap "^2.0.0" prosemirror-schema-basic@^1.2.3: version "1.2.3" - resolved "https://registry.yarnpkg.com/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.3.tgz#649c349bb21c61a56febf9deb71ac68fca4cedf2" + resolved "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.3.tgz" integrity sha512-h+H0OQwZVqMon1PNn0AG9cTfx513zgIG2DY00eJ00Yvgb3UD+GQ/VlWW5rcaxacpCGT1Yx8nuhwXk4+QbXUfJA== dependencies: prosemirror-model "^1.19.0" prosemirror-schema-list@^1.4.1: version "1.4.1" - resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.4.1.tgz#78b8d25531db48ca9688836dbde50e13ac19a4a1" + resolved "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.4.1.tgz" integrity sha512-jbDyaP/6AFfDfu70VzySsD75Om2t3sXTOdl5+31Wlxlg62td1haUpty/ybajSfJ1pkGadlOfwQq9kgW5IMo1Rg== dependencies: prosemirror-model "^1.0.0" @@ -1741,7 +2802,7 @@ prosemirror-schema-list@^1.4.1: prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.3.1, prosemirror-state@^1.4.3: version "1.4.3" - resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.4.3.tgz#94aecf3ffd54ec37e87aa7179d13508da181a080" + resolved "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.3.tgz" integrity sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q== dependencies: prosemirror-model "^1.0.0" @@ -1750,7 +2811,7 @@ prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.3.1, pr prosemirror-tables@^1.3.7: version "1.3.7" - resolved "https://registry.yarnpkg.com/prosemirror-tables/-/prosemirror-tables-1.3.7.tgz#9d296bd432d2bc7dca90f14e5c3b5c5f61277f7a" + resolved "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.3.7.tgz" integrity sha512-oEwX1wrziuxMtwFvdDWSFHVUWrFJWt929kVVfHvtTi8yvw+5ppxjXZkMG/fuTdFo+3DXyIPSKfid+Be1npKXDA== dependencies: prosemirror-keymap "^1.1.2" @@ -1761,7 +2822,7 @@ prosemirror-tables@^1.3.7: prosemirror-trailing-node@^2.0.8: version "2.0.9" - resolved "https://registry.yarnpkg.com/prosemirror-trailing-node/-/prosemirror-trailing-node-2.0.9.tgz#a087e6d1372e888cd3e57c977507b6b85dc658e4" + resolved "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-2.0.9.tgz" integrity sha512-YvyIn3/UaLFlFKrlJB6cObvUhmwFNZVhy1Q8OpW/avoTbD/Y7H5EcjK4AZFKhmuS6/N6WkGgt7gWtBWDnmFvHg== dependencies: "@remirror/core-constants" "^2.0.2" @@ -1769,14 +2830,14 @@ prosemirror-trailing-node@^2.0.8: prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.2.1, prosemirror-transform@^1.7.3, prosemirror-transform@^1.9.0: version "1.9.0" - resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.9.0.tgz#81fd1fbd887929a95369e6dd3d240c23c19313f8" + resolved "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.9.0.tgz" integrity sha512-5UXkr1LIRx3jmpXXNKDhv8OyAOeLTGuXNwdVfg8x27uASna/wQkr9p6fD3eupGOi4PLJfbezxTyi/7fSJypXHg== dependencies: prosemirror-model "^1.21.0" prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.27.0, prosemirror-view@^1.31.0, prosemirror-view@^1.33.8: version "1.33.8" - resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.33.8.tgz#cfd76dff421730cbca0b6ea40ce36994daaeda41" + resolved "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.8.tgz" integrity sha512-4PhMr/ufz2cdvFgpUAnZfs+0xij3RsFysreeG9V/utpwX7AJtYCDVyuRxzWoMJIEf4C7wVihuBNMPpFLPCiLQw== dependencies: prosemirror-model "^1.20.0" @@ -1785,7 +2846,7 @@ prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, pros punycode.js@^2.3.1: version "2.3.1" - resolved "https://registry.yarnpkg.com/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7" + resolved "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz" integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA== purgecss@^4.0.3: @@ -1805,7 +2866,7 @@ quick-lru@^5.1.1: radix-vue@^1.5.3: version "1.9.1" - resolved "https://registry.yarnpkg.com/radix-vue/-/radix-vue-1.9.1.tgz#4aebb1fc89ba91709e524e8ddca8ad0965e5ad8f" + resolved "https://registry.npmjs.org/radix-vue/-/radix-vue-1.9.1.tgz" integrity sha512-fObA+9l2ixNWBXRMj5mBZfmVv2znqIUph+0uo7QA/s7pDYSST2vGvxCbrg/xQGxWRwaQ8ejgo1wg2MzhHcbjLw== dependencies: "@floating-ui/dom" "^1.6.7" @@ -1822,7 +2883,7 @@ radix-vue@^1.5.3: read-cache@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" + resolved "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz" integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA== dependencies: pify "^2.3.0" @@ -1842,6 +2903,21 @@ reduce-css-calc@^2.1.8: css-unit-converter "^1.1.1" postcss-value-parser "^3.3.0" +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" @@ -1854,7 +2930,7 @@ resolve-from@^5.0.0: resolve@^1.1.7, resolve@^1.22.2: version "1.22.8" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: is-core-module "^2.13.0" @@ -1894,7 +2970,7 @@ rimraf@^3.0.0: rope-sequence@^1.3.0: version "1.3.4" - resolved "https://registry.yarnpkg.com/rope-sequence/-/rope-sequence-1.3.4.tgz#df85711aaecd32f1e756f76e43a415171235d425" + resolved "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz" integrity sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ== run-parallel@^1.1.9: @@ -1902,9 +2978,14 @@ run-parallel@^1.1.9: resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz" integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== +semver@^7.6.0, semver@^7.6.3: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + showdown@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/showdown/-/showdown-2.1.0.tgz#1251f5ed8f773f0c0c7bfc8e6fd23581f9e545c5" + resolved "https://registry.npmjs.org/showdown/-/showdown-2.1.0.tgz" integrity sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ== dependencies: commander "^9.0.0" @@ -1918,7 +2999,7 @@ simple-swizzle@^0.2.2: socket.io-client@^4.5.1: version "4.7.5" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.7.5.tgz#919be76916989758bdc20eec63f7ee0ae45c05b7" + resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz" integrity sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ== dependencies: "@socket.io/component-emitter" "~3.1.0" @@ -1928,25 +3009,46 @@ socket.io-client@^4.5.1: socket.io-parser@~4.2.4: version "4.2.4" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83" + resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz" integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew== dependencies: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1" -source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== source-map@^0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +split2@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + sucrase@^3.32.0: version "3.34.0" - resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.34.0.tgz#1e0e2d8fcf07f8b9c3569067d92fbd8690fb576f" + resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz" integrity sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw== dependencies: "@jridgewell/gen-mapping" "^0.3.2" @@ -1978,7 +3080,7 @@ supports-preserve-symlinks-flag@^1.0.0: tailwindcss@^3.2: version "3.3.5" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.5.tgz#22a59e2fbe0ecb6660809d9cc5f3976b077be3b8" + resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz" integrity sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA== dependencies: "@alloc/quick-lru" "^5.2.0" @@ -2004,23 +3106,46 @@ tailwindcss@^3.2: resolve "^1.22.2" sucrase "^3.32.0" +text-extensions@^2.0.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-2.4.0.tgz#a1cfcc50cf34da41bfd047cc744f804d1680ea34" + integrity sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g== + thenify-all@^1.0.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + resolved "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz" integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== dependencies: thenify ">= 3.1.0 < 4" "thenify@>= 3.1.0 < 4": version "3.3.1" - resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + resolved "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz" integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== dependencies: any-promise "^1.0.0" +"through@>=2.2.7 <3": + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +tinyexec@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.1.tgz#0ab0daf93b43e2c211212396bdb836b468c97c98" + integrity sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ== + +tinyglobby@^0.2.10: + version "0.2.10" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.10.tgz#e712cf2dc9b95a1f5c5bbd159720e15833977a0f" + integrity sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew== + dependencies: + fdir "^6.4.2" + picomatch "^4.0.2" + tippy.js@^6.3.7: version "6.3.7" - resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.7.tgz#8ccfb651d642010ed9a32ff29b0e9e19c5b8c61c" + resolved "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz" integrity sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ== dependencies: "@popperjs/core" "^2.9.0" @@ -2041,19 +3166,29 @@ to-regex-range@^5.0.1: ts-interface-checker@^0.1.9: version "0.1.13" - resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" + resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz" integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== tslib@^2.0.0, tslib@^2.4.0: version "2.6.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz" integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== uc.micro@^2.0.0, uc.micro@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee" + resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz" integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A== +undici-types@~6.20.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" + integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== + +unicorn-magic@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.1.0.tgz#1bb9a51c823aaf9d73a8bfcd3d1a23dde94b0ce4" + integrity sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ== + universalify@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz" @@ -2064,16 +3199,35 @@ util-deprecate@^1.0.2: resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= +vscode-languageserver-textdocument@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz#457ee04271ab38998a093c68c2342f53f6e4a631" + integrity sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA== + +vscode-uri@^3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.8.tgz#1770938d3e72588659a172d0fd4642780083ff9f" + integrity sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw== + vue-demi@>=0.13.0, vue-demi@>=0.14.8: version "0.14.8" - resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.8.tgz#00335e9317b45e4a68d3528aaf58e0cec3d5640a" + resolved "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.8.tgz" integrity sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q== w3c-keyname@^2.2.0: version "2.2.8" - resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz#7b17c8c6883d4e8b86ac8aba79d39e880f8869c5" + resolved "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz" integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ== +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" @@ -2081,12 +3235,17 @@ wrappy@1: ws@~8.17.1: version "8.17.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + resolved "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz" integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== +xdg-basedir@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-5.1.0.tgz#1efba19425e73be1bc6f2a6ceb52a3d2c884c0c9" + integrity sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ== + xmlhttprequest-ssl@~2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67" + resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz" integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A== xtend@^4.0.2: @@ -2094,6 +3253,11 @@ xtend@^4.0.2: resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + yaml@^1.10.0, yaml@^1.10.2: version "1.10.2" resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" @@ -2101,5 +3265,33 @@ yaml@^1.10.0, yaml@^1.10.2: yaml@^2.3.4: version "2.3.4" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2" + resolved "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz" integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== + +yaml@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.6.1.tgz#42f2b1ba89203f374609572d5349fb8686500773" + integrity sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.0.0: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yocto-queue@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.1.1.tgz#fef65ce3ac9f8a32ceac5a634f74e17e5b232110" + integrity sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==