From cc5e8f2bec0b1f50b770597b5e1226b6d1c846c1 Mon Sep 17 00:00:00 2001 From: JOY <5027251+JOY@users.noreply.github.com> Date: Wed, 2 Sep 2026 15:35:12 +0700 Subject: [PATCH 1/9] chore(deps): upgrade TypeScript to v6.0.3 across frontend and tooling - Update TypeScript from ^5.8.3 to ^6.0.3 in web and flowgram-editor - Ensure compatibility in build-sdk.mjs by safely handling importsNotUsedAsValues - Update pnpm-lock.yaml in web and flowgram-editor --- flowgram-editor/package.json | 2 +- flowgram-editor/pnpm-lock.yaml | 238 +++++++++++++++++---------------- web/package.json | 2 +- web/pnpm-lock.yaml | 114 ++++++++-------- web/scripts/build-sdk.mjs | 2 +- 5 files changed, 185 insertions(+), 173 deletions(-) diff --git a/flowgram-editor/package.json b/flowgram-editor/package.json index e5ced5da..e4eb1846 100644 --- a/flowgram-editor/package.json +++ b/flowgram-editor/package.json @@ -49,7 +49,7 @@ "@types/react": "^18", "@types/react-dom": "^18", "@types/styled-components": "^5", - "typescript": "^5.8.3", + "typescript": "^6.0.3", "eslint": "^9.0.0", "cross-env": "~7.0.3", "@flowgram.ai/eslint-config": "1.0.12", diff --git a/flowgram-editor/pnpm-lock.yaml b/flowgram-editor/pnpm-lock.yaml index f647c230..c4301f17 100644 --- a/flowgram-editor/pnpm-lock.yaml +++ b/flowgram-editor/pnpm-lock.yaml @@ -19,7 +19,7 @@ importers: version: 1.0.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@flowgram.ai/form-materials': specifier: 1.0.12 - version: 1.0.12(@babel/core@8.0.1)(@babel/template@8.0.0)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/merge@6.12.2)(@coze-editor/code-language-shared@0.1.0-alpha.868621(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2))(@floating-ui/dom@1.8.0)(@lezer/common@1.5.2)(@tiptap/suggestion@3.29.0(@floating-ui/dom@1.8.0)(@tiptap/core@3.29.0(@tiptap/pm@3.29.0))(@tiptap/pm@3.29.0))(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@5.3.11(@babel/core@8.0.1)(react-dom@18.3.1(react@18.3.1))(react-is@16.13.1)(react@18.3.1))(vue@3.5.40(typescript@5.9.3)) + version: 1.0.12(@babel/core@8.0.1)(@babel/template@8.0.0)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/merge@6.12.2)(@coze-editor/code-language-shared@0.1.0-alpha.868621(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2))(@floating-ui/dom@1.8.0)(@lezer/common@1.5.2)(@tiptap/suggestion@3.29.0(@floating-ui/dom@1.8.0)(@tiptap/core@3.29.0(@tiptap/pm@3.29.0))(@tiptap/pm@3.29.0))(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@5.3.11(@babel/core@8.0.1)(react-dom@18.3.1(react@18.3.1))(react-is@16.13.1)(react@18.3.1))(vue@3.5.40(typescript@6.0.3)) '@flowgram.ai/free-container-plugin': specifier: 1.0.12 version: 1.0.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@5.3.11(@babel/core@8.0.1)(react-dom@18.3.1(react@18.3.1))(react-is@16.13.1)(react@18.3.1)) @@ -74,7 +74,7 @@ importers: devDependencies: '@flowgram.ai/eslint-config': specifier: 1.0.12 - version: 1.0.12(@types/node@18.19.130)(jiti@2.7.0)(typescript@5.9.3) + version: 1.0.12(@types/node@18.19.130)(jiti@2.7.0)(supports-color@5.5.0)(typescript@6.0.3) '@flowgram.ai/ts-config': specifier: 1.0.12 version: 1.0.12 @@ -107,10 +107,10 @@ importers: version: 7.0.3 eslint: specifier: ^9.0.0 - version: 9.39.5(jiti@2.7.0) + version: 9.39.5(jiti@2.7.0)(supports-color@5.5.0) typescript: - specifier: ^5.8.3 - version: 5.9.3 + specifier: ^6.0.3 + version: 6.0.3 packages: @@ -2803,6 +2803,7 @@ packages: eslint@9.39.5: resolution: {integrity: sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true peerDependencies: jiti: '*' @@ -4213,6 +4214,11 @@ packages: engines: {node: '>=14.17'} hasBin: true + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} + hasBin: true + unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} @@ -4280,10 +4286,12 @@ packages: uuid@10.0.0: resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true v8-compile-cache-lib@3.0.1: @@ -4416,18 +4424,18 @@ snapshots: obug: 2.1.4 semver: 7.8.5 - '@babel/eslint-parser@7.19.1(@babel/core@8.0.1)(eslint@9.39.5(jiti@2.7.0))': + '@babel/eslint-parser@7.19.1(@babel/core@8.0.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))': dependencies: '@babel/core': 8.0.1 '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 - eslint: 9.39.5(jiti@2.7.0) + eslint: 9.39.5(jiti@2.7.0)(supports-color@5.5.0) eslint-visitor-keys: 2.1.0 semver: 6.3.1 - '@babel/eslint-plugin@7.29.7(@babel/eslint-parser@7.19.1(@babel/core@8.0.1)(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0))': + '@babel/eslint-plugin@7.29.7(@babel/eslint-parser@7.19.1(@babel/core@8.0.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))': dependencies: - '@babel/eslint-parser': 7.19.1(@babel/core@8.0.1)(eslint@9.39.5(jiti@2.7.0)) - eslint: 9.39.5(jiti@2.7.0) + '@babel/eslint-parser': 7.19.1(@babel/core@8.0.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)) + eslint: 9.39.5(jiti@2.7.0)(supports-color@5.5.0) eslint-rule-composer: 0.3.0 '@babel/generator@7.29.7': @@ -4487,7 +4495,7 @@ snapshots: regexpu-core: 6.4.0 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.3.3(@babel/core@8.0.1)': + '@babel/helper-define-polyfill-provider@0.3.3(@babel/core@8.0.1)(supports-color@5.5.0)': dependencies: '@babel/core': 8.0.1 '@babel/helper-compilation-targets': 7.29.7 @@ -5041,7 +5049,7 @@ snapshots: '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@8.0.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/preset-env@7.20.2(@babel/core@8.0.1)': + '@babel/preset-env@7.20.2(@babel/core@8.0.1)(supports-color@5.5.0)': dependencies: '@babel/compat-data': 7.29.7 '@babel/core': 8.0.1 @@ -5114,7 +5122,7 @@ snapshots: '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@8.0.1) '@babel/preset-modules': 0.1.6(@babel/core@8.0.1) '@babel/types': 7.29.7 - babel-plugin-polyfill-corejs2: 0.3.3(@babel/core@8.0.1) + babel-plugin-polyfill-corejs2: 0.3.3(@babel/core@8.0.1)(supports-color@5.5.0) babel-plugin-polyfill-corejs3: 0.6.0(@babel/core@8.0.1) babel-plugin-polyfill-regenerator: 0.4.1(@babel/core@8.0.1) core-js-compat: 3.49.0 @@ -5359,7 +5367,7 @@ snapshots: '@codemirror/view': 6.43.6 mitt: 3.0.1 - '@coze-editor/editor@0.1.0-alpha.868621(@babel/core@8.0.1)(@babel/template@8.0.0)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/merge@6.12.2)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2)(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)(vue@3.5.40(typescript@5.9.3))': + '@coze-editor/editor@0.1.0-alpha.868621(@babel/core@8.0.1)(@babel/template@8.0.0)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/merge@6.12.2)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2)(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)(vue@3.5.40(typescript@6.0.3))': dependencies: '@codemirror/commands': 6.10.4 '@codemirror/state': 6.7.1 @@ -5389,8 +5397,8 @@ snapshots: '@coze-editor/react-merge': 0.1.0-alpha.868621(@codemirror/merge@6.12.2)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@coze-editor/react@0.1.0-alpha.868621(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@coze-editor/utils': 0.1.0-alpha.868621(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2) '@coze-editor/vscode': 0.1.0-alpha.868621(@codemirror/state@6.7.1)(@codemirror/view@6.43.6) - '@coze-editor/vue': 0.1.0-alpha.868621(@codemirror/commands@6.10.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2)(vue@3.5.40(typescript@5.9.3)) - '@coze-editor/vue-components': 0.1.0-alpha.868621(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@coze-editor/vue@0.1.0-alpha.868621(@codemirror/commands@6.10.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2)(vue@3.5.40(typescript@5.9.3)))(@lezer/common@1.5.2)(vue@3.5.40(typescript@5.9.3)) + '@coze-editor/vue': 0.1.0-alpha.868621(@codemirror/commands@6.10.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2)(vue@3.5.40(typescript@6.0.3)) + '@coze-editor/vue-components': 0.1.0-alpha.868621(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@coze-editor/vue@0.1.0-alpha.868621(@codemirror/commands@6.10.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2)(vue@3.5.40(typescript@6.0.3)))(@lezer/common@1.5.2)(vue@3.5.40(typescript@6.0.3)) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: @@ -5673,28 +5681,28 @@ snapshots: '@lezer/highlight': 1.2.3 crelt: 1.0.7 - '@coze-editor/vue-components@0.1.0-alpha.868621(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@coze-editor/vue@0.1.0-alpha.868621(@codemirror/commands@6.10.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2)(vue@3.5.40(typescript@5.9.3)))(@lezer/common@1.5.2)(vue@3.5.40(typescript@5.9.3))': + '@coze-editor/vue-components@0.1.0-alpha.868621(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@coze-editor/vue@0.1.0-alpha.868621(@codemirror/commands@6.10.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2)(vue@3.5.40(typescript@6.0.3)))(@lezer/common@1.5.2)(vue@3.5.40(typescript@6.0.3))': dependencies: '@codemirror/state': 6.7.1 '@codemirror/view': 6.43.6 '@coze-editor/extension-placeholder': 0.1.0-alpha.868621(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2) '@coze-editor/extensions': 0.1.0-alpha.868621(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6) '@coze-editor/utils': 0.1.0-alpha.868621(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2) - '@coze-editor/vue': 0.1.0-alpha.868621(@codemirror/commands@6.10.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2)(vue@3.5.40(typescript@5.9.3)) + '@coze-editor/vue': 0.1.0-alpha.868621(@codemirror/commands@6.10.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2)(vue@3.5.40(typescript@6.0.3)) '@floating-ui/dom': 1.8.0 - vue: 3.5.40(typescript@5.9.3) + vue: 3.5.40(typescript@6.0.3) transitivePeerDependencies: - '@codemirror/language' - '@lezer/common' - '@coze-editor/vue@0.1.0-alpha.868621(@codemirror/commands@6.10.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2)(vue@3.5.40(typescript@5.9.3))': + '@coze-editor/vue@0.1.0-alpha.868621(@codemirror/commands@6.10.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2)(vue@3.5.40(typescript@6.0.3))': dependencies: '@codemirror/state': 6.7.1 '@codemirror/view': 6.43.6 '@coze-editor/core': 0.1.0-alpha.868621(@codemirror/state@6.7.1)(@codemirror/view@6.43.6) '@coze-editor/core-plugins': 0.1.0-alpha.868621(@codemirror/commands@6.10.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2) '@coze-editor/extension-placeholder': 0.1.0-alpha.868621(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2) - vue: 3.5.40(typescript@5.9.3) + vue: 3.5.40(typescript@6.0.3) transitivePeerDependencies: - '@codemirror/commands' - '@lezer/common' @@ -5865,14 +5873,14 @@ snapshots: '@emotion/unitless@0.7.5': {} - '@eslint-community/eslint-utils@4.10.1(eslint@9.39.5(jiti@2.7.0))': + '@eslint-community/eslint-utils@4.10.1(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))': dependencies: - eslint: 9.39.5(jiti@2.7.0) + eslint: 9.39.5(jiti@2.7.0)(supports-color@5.5.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.21.2': + '@eslint/config-array@0.21.2(supports-color@5.5.0)': dependencies: '@eslint/object-schema': 2.1.7 debug: 4.4.3(supports-color@5.5.0) @@ -5888,7 +5896,7 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.3': + '@eslint/eslintrc@3.3.3(supports-color@5.5.0)': dependencies: ajv: 6.15.0 debug: 4.4.3(supports-color@5.5.0) @@ -5902,7 +5910,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/eslintrc@3.3.6': + '@eslint/eslintrc@3.3.6(supports-color@5.5.0)': dependencies: ajv: 6.15.0 debug: 4.4.3(supports-color@5.5.0) @@ -5966,10 +5974,10 @@ snapshots: react-dom: 18.3.1(react@18.3.1) reflect-metadata: 0.2.2 - '@flowgram.ai/coze-editor@1.0.12(@babel/core@8.0.1)(@babel/template@8.0.0)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/merge@6.12.2)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@coze-editor/code-language-shared@0.1.0-alpha.868621(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2))(@lezer/common@1.5.2)(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@5.3.11(@babel/core@8.0.1)(react-dom@18.3.1(react@18.3.1))(react-is@16.13.1)(react@18.3.1))(vue@3.5.40(typescript@5.9.3))': + '@flowgram.ai/coze-editor@1.0.12(@babel/core@8.0.1)(@babel/template@8.0.0)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/merge@6.12.2)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@coze-editor/code-language-shared@0.1.0-alpha.868621(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2))(@lezer/common@1.5.2)(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@5.3.11(@babel/core@8.0.1)(react-dom@18.3.1(react@18.3.1))(react-is@16.13.1)(react@18.3.1))(vue@3.5.40(typescript@6.0.3))': dependencies: '@coze-editor/code-language-typescript': 0.1.0-alpha.868621(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@coze-editor/code-language-shared@0.1.0-alpha.868621(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2))(typescript@5.9.3) - '@coze-editor/editor': 0.1.0-alpha.868621(@babel/core@8.0.1)(@babel/template@8.0.0)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/merge@6.12.2)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2)(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)(vue@3.5.40(typescript@5.9.3)) + '@coze-editor/editor': 0.1.0-alpha.868621(@babel/core@8.0.1)(@babel/template@8.0.0)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/merge@6.12.2)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2)(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)(vue@3.5.40(typescript@6.0.3)) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) styled-components: 5.3.11(@babel/core@8.0.1)(react-dom@18.3.1(react@18.3.1))(react-is@16.13.1)(react@18.3.1) @@ -6025,29 +6033,29 @@ snapshots: react-dom: 18.3.1(react@18.3.1) reflect-metadata: 0.2.2 - '@flowgram.ai/eslint-config@1.0.12(@types/node@18.19.130)(jiti@2.7.0)(typescript@5.9.3)': + '@flowgram.ai/eslint-config@1.0.12(@types/node@18.19.130)(jiti@2.7.0)(supports-color@5.5.0)(typescript@6.0.3)': dependencies: '@babel/core': 8.0.1 - '@babel/eslint-parser': 7.19.1(@babel/core@8.0.1)(eslint@9.39.5(jiti@2.7.0)) - '@babel/eslint-plugin': 7.29.7(@babel/eslint-parser@7.19.1(@babel/core@8.0.1)(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0)) - '@babel/preset-env': 7.20.2(@babel/core@8.0.1) + '@babel/eslint-parser': 7.19.1(@babel/core@8.0.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)) + '@babel/eslint-plugin': 7.29.7(@babel/eslint-parser@7.19.1(@babel/core@8.0.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)) + '@babel/preset-env': 7.20.2(@babel/core@8.0.1)(supports-color@5.5.0) '@babel/preset-react': 7.13.13(@babel/core@8.0.1) - '@eslint/eslintrc': 3.3.3 - '@typescript-eslint/eslint-plugin': 8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/parser': 8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) - eslint: 9.39.5(jiti@2.7.0) - eslint-config-prettier: 8.10.2(eslint@9.39.5(jiti@2.7.0)) + '@eslint/eslintrc': 3.3.3(supports-color@5.5.0) + '@typescript-eslint/eslint-plugin': 8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3) + eslint: 9.39.5(jiti@2.7.0)(supports-color@5.5.0) + eslint-config-prettier: 8.10.2(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)) eslint-define-config: 1.12.0 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(jiti@2.7.0)) - eslint-plugin-babel: 5.3.1(eslint@9.39.5(jiti@2.7.0)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.5(jiti@2.7.0)) - eslint-plugin-prettier: 4.2.5(eslint-config-prettier@8.10.2(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0))(prettier@2.8.8) - eslint-plugin-react: 7.37.5(eslint@9.39.5(jiti@2.7.0)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0) + eslint-plugin-babel: 5.3.1(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)) + eslint-plugin-prettier: 4.2.5(eslint-config-prettier@8.10.2(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(prettier@2.8.8) + eslint-plugin-react: 7.37.5(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)) eslint-plugin-tsdoc: 0.2.17 prettier: 2.8.8 prettier-plugin-packagejson: 2.5.22(prettier@2.8.8) - ts-node: 10.9.2(@types/node@18.19.130)(typescript@5.9.3) + ts-node: 10.9.2(@types/node@18.19.130)(typescript@6.0.3) transitivePeerDependencies: - '@swc/core' - '@swc/wasm' @@ -6083,13 +6091,13 @@ snapshots: react-dom: 18.3.1(react@18.3.1) reflect-metadata: 0.2.2 - '@flowgram.ai/form-materials@1.0.12(@babel/core@8.0.1)(@babel/template@8.0.0)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/merge@6.12.2)(@coze-editor/code-language-shared@0.1.0-alpha.868621(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2))(@floating-ui/dom@1.8.0)(@lezer/common@1.5.2)(@tiptap/suggestion@3.29.0(@floating-ui/dom@1.8.0)(@tiptap/core@3.29.0(@tiptap/pm@3.29.0))(@tiptap/pm@3.29.0))(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@5.3.11(@babel/core@8.0.1)(react-dom@18.3.1(react@18.3.1))(react-is@16.13.1)(react@18.3.1))(vue@3.5.40(typescript@5.9.3))': + '@flowgram.ai/form-materials@1.0.12(@babel/core@8.0.1)(@babel/template@8.0.0)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/merge@6.12.2)(@coze-editor/code-language-shared@0.1.0-alpha.868621(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2))(@floating-ui/dom@1.8.0)(@lezer/common@1.5.2)(@tiptap/suggestion@3.29.0(@floating-ui/dom@1.8.0)(@tiptap/core@3.29.0(@tiptap/pm@3.29.0))(@tiptap/pm@3.29.0))(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@5.3.11(@babel/core@8.0.1)(react-dom@18.3.1(react@18.3.1))(react-is@16.13.1)(react@18.3.1))(vue@3.5.40(typescript@6.0.3))': dependencies: '@codemirror/state': 6.7.1 '@codemirror/view': 6.43.6 '@douyinfe/semi-icons': 2.101.1(react@18.3.1) '@douyinfe/semi-ui': 2.101.1(@floating-ui/dom@1.8.0)(@tiptap/suggestion@3.29.0(@floating-ui/dom@1.8.0)(@tiptap/core@3.29.0(@tiptap/pm@3.29.0))(@tiptap/pm@3.29.0))(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@flowgram.ai/coze-editor': 1.0.12(@babel/core@8.0.1)(@babel/template@8.0.0)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/merge@6.12.2)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@coze-editor/code-language-shared@0.1.0-alpha.868621(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2))(@lezer/common@1.5.2)(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@5.3.11(@babel/core@8.0.1)(react-dom@18.3.1(react@18.3.1))(react-is@16.13.1)(react@18.3.1))(vue@3.5.40(typescript@5.9.3)) + '@flowgram.ai/coze-editor': 1.0.12(@babel/core@8.0.1)(@babel/template@8.0.0)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/merge@6.12.2)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@coze-editor/code-language-shared@0.1.0-alpha.868621(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)(@lezer/common@1.5.2))(@lezer/common@1.5.2)(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@5.3.11(@babel/core@8.0.1)(react-dom@18.3.1(react@18.3.1))(react-is@16.13.1)(react@18.3.1))(vue@3.5.40(typescript@6.0.3)) '@flowgram.ai/editor': 1.0.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@flowgram.ai/json-schema': 1.0.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) immer: 10.1.3 @@ -7205,40 +7213,40 @@ snapshots: '@types/uuid@10.0.0': {} - '@typescript-eslint/eslint-plugin@8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3) '@typescript-eslint/scope-manager': 8.65.0 - '@typescript-eslint/type-utils': 8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/utils': 8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.65.0 - eslint: 9.39.5(jiti@2.7.0) + eslint: 9.39.5(jiti@2.7.0)(supports-color@5.5.0) ignore: 7.0.6 natural-compare: 1.4.0 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3)': + '@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.65.0 '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.65.0(supports-color@5.5.0)(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.65.0 debug: 4.4.3(supports-color@5.5.0) - eslint: 9.39.5(jiti@2.7.0) - typescript: 5.9.3 + eslint: 9.39.5(jiti@2.7.0)(supports-color@5.5.0) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.65.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.65.0(supports-color@5.5.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@6.0.3) '@typescript-eslint/types': 8.65.0 debug: 4.4.3(supports-color@5.5.0) - typescript: 5.9.3 + typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -7247,47 +7255,47 @@ snapshots: '@typescript-eslint/types': 8.65.0 '@typescript-eslint/visitor-keys': 8.65.0 - '@typescript-eslint/tsconfig-utils@8.65.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.65.0(typescript@6.0.3)': dependencies: - typescript: 5.9.3 + typescript: 6.0.3 - '@typescript-eslint/type-utils@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.65.0(supports-color@5.5.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(typescript@6.0.3) debug: 4.4.3(supports-color@5.5.0) - eslint: 9.39.5(jiti@2.7.0) - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 + eslint: 9.39.5(jiti@2.7.0)(supports-color@5.5.0) + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color '@typescript-eslint/types@8.65.0': {} - '@typescript-eslint/typescript-estree@8.65.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.65.0(supports-color@5.5.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.65.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.9.3) + '@typescript-eslint/project-service': 8.65.0(supports-color@5.5.0)(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@6.0.3) '@typescript-eslint/types': 8.65.0 '@typescript-eslint/visitor-keys': 8.65.0 debug: 4.4.3(supports-color@5.5.0) minimatch: 10.2.5 semver: 7.8.5 tinyglobby: 0.2.17 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3)': + '@typescript-eslint/utils@8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(jiti@2.7.0)) + '@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)) '@typescript-eslint/scope-manager': 8.65.0 '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3) - eslint: 9.39.5(jiti@2.7.0) - typescript: 5.9.3 + '@typescript-eslint/typescript-estree': 8.65.0(supports-color@5.5.0)(typescript@6.0.3) + eslint: 9.39.5(jiti@2.7.0)(supports-color@5.5.0) + typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -7550,11 +7558,11 @@ snapshots: axobject-query@4.1.0: {} - babel-plugin-polyfill-corejs2@0.3.3(@babel/core@8.0.1): + babel-plugin-polyfill-corejs2@0.3.3(@babel/core@8.0.1)(supports-color@5.5.0): dependencies: '@babel/compat-data': 7.29.7 '@babel/core': 8.0.1 - '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@8.0.1) + '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@8.0.1)(supports-color@5.5.0) semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -7562,7 +7570,7 @@ snapshots: babel-plugin-polyfill-corejs3@0.6.0(@babel/core@8.0.1): dependencies: '@babel/core': 8.0.1 - '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@8.0.1) + '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@8.0.1)(supports-color@5.5.0) core-js-compat: 3.49.0 transitivePeerDependencies: - supports-color @@ -7570,7 +7578,7 @@ snapshots: babel-plugin-polyfill-regenerator@0.4.1(@babel/core@8.0.1): dependencies: '@babel/core': 8.0.1 - '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@8.0.1) + '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@8.0.1)(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -7965,9 +7973,9 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-prettier@8.10.2(eslint@9.39.5(jiti@2.7.0)): + eslint-config-prettier@8.10.2(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)): dependencies: - eslint: 9.39.5(jiti@2.7.0) + eslint: 9.39.5(jiti@2.7.0)(supports-color@5.5.0) eslint-define-config@1.12.0: {} @@ -7979,38 +7987,38 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(jiti@2.7.0)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3(supports-color@5.5.0) - eslint: 9.39.5(jiti@2.7.0) + eslint: 9.39.5(jiti@2.7.0)(supports-color@5.5.0) get-tsconfig: 4.14.0 is-bun-module: 2.0.0 stable-hash: 0.0.5 tinyglobby: 0.2.17 unrs-resolver: 1.12.2 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.14.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)): + eslint-module-utils@2.14.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) - eslint: 9.39.5(jiti@2.7.0) + '@typescript-eslint/parser': 8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3) + eslint: 9.39.5(jiti@2.7.0)(supports-color@5.5.0) eslint-import-resolver-node: 0.3.10 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(jiti@2.7.0)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0) transitivePeerDependencies: - supports-color - eslint-plugin-babel@5.3.1(eslint@9.39.5(jiti@2.7.0)): + eslint-plugin-babel@5.3.1(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)): dependencies: - eslint: 9.39.5(jiti@2.7.0) + eslint: 9.39.5(jiti@2.7.0)(supports-color@5.5.0) eslint-rule-composer: 0.3.0 - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -8019,9 +8027,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.39.5(jiti@2.7.0) + eslint: 9.39.5(jiti@2.7.0)(supports-color@5.5.0) eslint-import-resolver-node: 0.3.10 - eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)) + eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)) hasown: 2.0.4 is-core-module: 2.16.2 is-glob: 4.0.3 @@ -8033,13 +8041,13 @@ snapshots: string.prototype.trimend: 1.0.10 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.65.0(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(supports-color@5.5.0)(typescript@6.0.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.5(jiti@2.7.0)): + eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)): dependencies: aria-query: 5.3.2 array-includes: 3.1.9 @@ -8049,7 +8057,7 @@ snapshots: axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 9.39.5(jiti@2.7.0) + eslint: 9.39.5(jiti@2.7.0)(supports-color@5.5.0) hasown: 2.0.4 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 @@ -8058,15 +8066,15 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 - eslint-plugin-prettier@4.2.5(eslint-config-prettier@8.10.2(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0))(prettier@2.8.8): + eslint-plugin-prettier@4.2.5(eslint-config-prettier@8.10.2(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)))(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0))(prettier@2.8.8): dependencies: - eslint: 9.39.5(jiti@2.7.0) + eslint: 9.39.5(jiti@2.7.0)(supports-color@5.5.0) prettier: 2.8.8 prettier-linter-helpers: 1.0.1 optionalDependencies: - eslint-config-prettier: 8.10.2(eslint@9.39.5(jiti@2.7.0)) + eslint-config-prettier: 8.10.2(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)) - eslint-plugin-react@7.37.5(eslint@9.39.5(jiti@2.7.0)): + eslint-plugin-react@7.37.5(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)): dependencies: array-includes: 3.1.9 array.prototype.findlast: 1.2.5 @@ -8074,7 +8082,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.4.0 - eslint: 9.39.5(jiti@2.7.0) + eslint: 9.39.5(jiti@2.7.0)(supports-color@5.5.0) estraverse: 5.3.0 hasown: 2.0.4 jsx-ast-utils: 3.3.5 @@ -8113,14 +8121,14 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@9.39.5(jiti@2.7.0): + eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0): dependencies: - '@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(jiti@2.7.0)) + '@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(jiti@2.7.0)(supports-color@5.5.0)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.2 + '@eslint/config-array': 0.21.2(supports-color@5.5.0) '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.6 + '@eslint/eslintrc': 3.3.6(supports-color@5.5.0) '@eslint/js': 9.39.5 '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.8 @@ -9942,11 +9950,11 @@ snapshots: trough@2.2.0: {} - ts-api-utils@2.5.0(typescript@5.9.3): + ts-api-utils@2.5.0(typescript@6.0.3): dependencies: - typescript: 5.9.3 + typescript: 6.0.3 - ts-node@10.9.2(@types/node@18.19.130)(typescript@5.9.3): + ts-node@10.9.2(@types/node@18.19.130)(typescript@6.0.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 @@ -9960,7 +9968,7 @@ snapshots: create-require: 1.1.1 diff: 4.0.4 make-error: 1.3.6 - typescript: 5.9.3 + typescript: 6.0.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 @@ -10012,6 +10020,8 @@ snapshots: typescript@5.9.3: {} + typescript@6.0.3: {} + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -10142,7 +10152,7 @@ snapshots: vscode-uri@3.1.0: {} - vue@3.5.40(typescript@5.9.3): + vue@3.5.40(typescript@6.0.3): dependencies: '@vue/compiler-dom': 3.5.40 '@vue/compiler-sfc': 3.5.40 @@ -10150,7 +10160,7 @@ snapshots: '@vue/server-renderer': 3.5.40 '@vue/shared': 3.5.40 optionalDependencies: - typescript: 5.9.3 + typescript: 6.0.3 w3c-keyname@2.2.8: {} diff --git a/web/package.json b/web/package.json index 8fbc66aa..540145e5 100644 --- a/web/package.json +++ b/web/package.json @@ -69,6 +69,6 @@ "sass": "^1.98.0", "tailwindcss": "^4", "terser": "^5.46.2", - "typescript": "^5" + "typescript": "^6.0.3" } } diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 404d95eb..ff9ecc35 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -121,7 +121,7 @@ importers: version: 4.0.1 shadcn: specifier: ^4.18.0 - version: 4.18.0(typescript@5.9.3) + version: 4.18.0(typescript@6.0.3) sonner: specifier: ^2.0.7 version: 2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -167,7 +167,7 @@ importers: version: 9.39.4(jiti@2.6.1) eslint-config-next: specifier: 16.1.6 - version: 16.1.6(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + version: 16.1.6(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) sass: specifier: ^1.98.0 version: 1.98.0 @@ -178,8 +178,8 @@ importers: specifier: ^5.46.2 version: 5.46.2 typescript: - specifier: ^5 - version: 5.9.3 + specifier: ^6.0.3 + version: 6.0.3 packages: @@ -2584,6 +2584,7 @@ packages: eslint@9.39.4: resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true peerDependencies: jiti: '*' @@ -4008,6 +4009,7 @@ packages: recharts@2.15.4: resolution: {integrity: sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==} engines: {node: '>=14'} + deprecated: 1.x and 2.x branches are no longer active. Bump to Recharts v3 to receive latest features and bugfixes. See https://github.com/recharts/recharts/wiki/3.0-migration-guide peerDependencies: react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -4427,8 +4429,8 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} hasBin: true @@ -6254,40 +6256,40 @@ snapshots: '@types/validate-npm-package-name@4.0.2': {} - '@typescript-eslint/eslint-plugin@8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/scope-manager': 8.57.0 - '@typescript-eslint/type-utils': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.57.0 eslint: 9.39.4(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 + ts-api-utils: 2.4.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.57.0 '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.57.0(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.57.0 debug: 4.4.3 eslint: 9.39.4(jiti@2.6.1) - typescript: 5.9.3 + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.57.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.57.0(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@6.0.3) '@typescript-eslint/types': 8.57.0 debug: 4.4.3 - typescript: 5.9.3 + typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -6296,47 +6298,47 @@ snapshots: '@typescript-eslint/types': 8.57.0 '@typescript-eslint/visitor-keys': 8.57.0 - '@typescript-eslint/tsconfig-utils@8.57.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.57.0(typescript@6.0.3)': dependencies: - typescript: 5.9.3 + typescript: 6.0.3 - '@typescript-eslint/type-utils@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.57.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) debug: 4.4.3 eslint: 9.39.4(jiti@2.6.1) - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 + ts-api-utils: 2.4.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color '@typescript-eslint/types@8.57.0': {} - '@typescript-eslint/typescript-estree@8.57.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.57.0(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.57.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@5.9.3) + '@typescript-eslint/project-service': 8.57.0(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@6.0.3) '@typescript-eslint/types': 8.57.0 '@typescript-eslint/visitor-keys': 8.57.0 debug: 4.4.3 minimatch: 10.2.4 semver: 7.7.4 tinyglobby: 0.2.15 - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 + ts-api-utils: 2.4.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) '@typescript-eslint/scope-manager': 8.57.0 '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.57.0(typescript@6.0.3) eslint: 9.39.4(jiti@2.6.1) - typescript: 5.9.3 + typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -6721,14 +6723,14 @@ snapshots: dependencies: layout-base: 2.0.1 - cosmiconfig@9.0.1(typescript@5.9.3): + cosmiconfig@9.0.1(typescript@6.0.3): dependencies: env-paths: 2.2.1 import-fresh: 3.3.1 js-yaml: 4.1.1 parse-json: 5.2.0 optionalDependencies: - typescript: 5.9.3 + typescript: 6.0.3 crelt@1.0.6: {} @@ -7176,20 +7178,20 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-next@16.1.6(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3): + eslint-config-next@16.1.6(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3): dependencies: '@next/eslint-plugin-next': 16.1.6 eslint: 9.39.4(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-react-hooks: 7.0.1(eslint@9.39.4(jiti@2.6.1)) globals: 16.4.0 - typescript-eslint: 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + typescript-eslint: 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) optionalDependencies: - typescript: 5.9.3 + typescript: 6.0.3 transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-webpack @@ -7215,22 +7217,22 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) eslint: 9.39.4(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -7241,7 +7243,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.39.4(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -7253,7 +7255,7 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -9283,7 +9285,7 @@ snapshots: setprototypeof@1.2.0: {} - shadcn@4.18.0(typescript@5.9.3): + shadcn@4.18.0(typescript@6.0.3): dependencies: '@babel/core': 7.29.0 '@babel/parser': 7.29.0 @@ -9294,7 +9296,7 @@ snapshots: '@types/validate-npm-package-name': 4.0.2 browserslist: 4.28.1 commander: 14.0.3 - cosmiconfig: 9.0.1(typescript@5.9.3) + cosmiconfig: 9.0.1(typescript@6.0.3) dedent: 1.7.2 deepmerge: 4.3.1 diff: 8.0.3 @@ -9570,9 +9572,9 @@ snapshots: trough@2.2.0: {} - ts-api-utils@2.4.0(typescript@5.9.3): + ts-api-utils@2.4.0(typescript@6.0.3): dependencies: - typescript: 5.9.3 + typescript: 6.0.3 ts-dedent@2.3.0: {} @@ -9645,18 +9647,18 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript-eslint@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.57.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) eslint: 9.39.4(jiti@2.6.1) - typescript: 5.9.3 + typescript: 6.0.3 transitivePeerDependencies: - supports-color - typescript@5.9.3: {} + typescript@6.0.3: {} uc.micro@2.1.0: {} diff --git a/web/scripts/build-sdk.mjs b/web/scripts/build-sdk.mjs index c36bbd84..b1c07128 100644 --- a/web/scripts/build-sdk.mjs +++ b/web/scripts/build-sdk.mjs @@ -16,7 +16,7 @@ const compiled = ts.transpileModule(sourceCode, { compilerOptions: { target: ts.ScriptTarget.ES2017, module: ts.ModuleKind.ESNext, - importsNotUsedAsValues: ts.ImportsNotUsedAsValues.Remove, + importsNotUsedAsValues: ts.ImportsNotUsedAsValues ? ts.ImportsNotUsedAsValues.Remove : undefined, removeComments: true, }, fileName: source, From e88ccc67003700c4a86d611d818a1e23201281b5 Mon Sep 17 00:00:00 2001 From: JOY <5027251+JOY@users.noreply.github.com> Date: Tue, 8 Sep 2026 10:07:25 +0700 Subject: [PATCH 2/9] chore: remove docs submodule pointing to a private repository The docs submodule points to huabeitech/agent-desk-docs, which is not publicly accessible (GitHub returns 404). Every fork or fresh clone that runs \`git submodule update --init\` fails on it: fatal: repository 'https://github.com/huabeitech/agent-desk-docs.git/' not found Remove the gitlink and its .gitmodules entry. No source code is affected; the qdrant submodule (public) is kept as-is. An alternative fix is to make the docs repository public. --- .gitmodules | 4 +--- docs | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) delete mode 160000 docs diff --git a/.gitmodules b/.gitmodules index 450ea966..1210ecfd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,4 @@ [submodule "qdrant"] path = qdrant url = git@github.com:huabeitech/agent-desk-qdrant.git -[submodule "docs"] - path = docs - url = git@github.com:huabeitech/agent-desk-docs.git + diff --git a/docs b/docs deleted file mode 160000 index 1c433f70..00000000 --- a/docs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1c433f70deb674b3f083fc510b31bb5bedbead81 From cb5ba71011804eb6912bdef0da2e71a21af3a402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=BF=E4=B9=90=E4=B9=90?= <187235069+higenglele@users.noreply.github.com> Date: Wed, 9 Sep 2026 00:08:13 +0800 Subject: [PATCH 3/9] fix(auth): initialize bootstrap admin as employee Set the bootstrap account type explicitly so dashboard authentication accepts it. Add an idempotent migration for existing active bootstrap super admins and cover the repair boundaries in CI. --- .github/workflows/ci.yml | 2 +- internal/migration/000002_init_auth_data.go | 1 + ...000010_repair_bootstrap_admin_user_type.go | 34 +++++ ...0_repair_bootstrap_admin_user_type_test.go | 131 ++++++++++++++++++ 4 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 internal/migration/000010_repair_bootstrap_admin_user_type.go create mode 100644 internal/migration/000010_repair_bootstrap_admin_user_type_test.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e18ca722..355b99b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: - name: Run Go Tests run: | - go test -v -tags dev ./internal/services/... ./internal/repositories/... ./internal/pkg/... ./internal/oidcclient/... + go test -v -tags dev ./internal/services/... ./internal/repositories/... ./internal/pkg/... ./internal/oidcclient/... ./internal/migration/... frontend-typecheck: name: Frontend Typecheck diff --git a/internal/migration/000002_init_auth_data.go b/internal/migration/000002_init_auth_data.go index 177b5379..59380ed9 100644 --- a/internal/migration/000002_init_auth_data.go +++ b/internal/migration/000002_init_auth_data.go @@ -205,6 +205,7 @@ func ensureBootstrapAdmin(tx *gorm.DB, superAdminRole *models.Role) error { Username: username, Nickname: nickname, Password: string(hashedPassword), + UserType: enums.UserTypeEmployee, Status: enums.StatusOk, Remark: "bootstrap super admin", AuditFields: models.AuditFields{ diff --git a/internal/migration/000010_repair_bootstrap_admin_user_type.go b/internal/migration/000010_repair_bootstrap_admin_user_type.go new file mode 100644 index 00000000..4eb65550 --- /dev/null +++ b/internal/migration/000010_repair_bootstrap_admin_user_type.go @@ -0,0 +1,34 @@ +package migration + +import ( + "agent-desk/internal/models" + "agent-desk/internal/pkg/constants" + "agent-desk/internal/pkg/enums" + "time" + + "github.com/mlogclub/simple/sqls" +) + +func init() { + register(10, "repair bootstrap admin user type", func() error { + db := sqls.DB() + superAdmins := db.Table("t_user_role AS ur").Select("ur.user_id"). + Joins("JOIN t_role AS r ON r.id = ur.role_id"). + Where("r.code = ? AND r.status = ?", constants.RoleCodeSuperAdmin, enums.StatusOk) + + // Migration 2 has already run on existing installations. Repair only the + // active bootstrap account that already has the super admin role. + return db.Model(&models.User{}). + Where("username = ?", constants.BootstrapAdminUsername). + Where("user_type = ?", enums.UserTypeUser). + Where("status = ?", enums.StatusOk). + Where("deleted_at IS NULL"). + Where("id IN (?)", superAdmins). + Updates(map[string]any{ + "user_type": enums.UserTypeEmployee, + "updated_at": time.Now(), + "update_user_id": constants.SystemAuditUserID, + "update_user_name": constants.SystemAuditUserName, + }).Error + }) +} diff --git a/internal/migration/000010_repair_bootstrap_admin_user_type_test.go b/internal/migration/000010_repair_bootstrap_admin_user_type_test.go new file mode 100644 index 00000000..f7f436bf --- /dev/null +++ b/internal/migration/000010_repair_bootstrap_admin_user_type_test.go @@ -0,0 +1,131 @@ +package migration + +import ( + "path/filepath" + "testing" + "time" + + "agent-desk/internal/models" + "agent-desk/internal/pkg/constants" + "agent-desk/internal/pkg/enums" + "github.com/glebarez/sqlite" + "github.com/mlogclub/simple/sqls" + "gorm.io/gorm" + "gorm.io/gorm/schema" +) + +func setupBootstrapAdminTestDB(t *testing.T) *gorm.DB { + t.Helper() + db, err := gorm.Open(sqlite.Open(filepath.Join(t.TempDir(), "auth.db")), &gorm.Config{ + NamingStrategy: schema.NamingStrategy{TablePrefix: "t_", SingularTable: true}, + }) + if err != nil { + t.Fatal(err) + } + if err := db.AutoMigrate(&models.User{}, &models.Role{}, &models.UserRole{}); err != nil { + t.Fatal(err) + } + conn, err := db.DB() + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { _ = conn.Close() }) + return db +} + +func TestBootstrapAdminCreatedAsEmployee(t *testing.T) { + db := setupBootstrapAdminTestDB(t) + role := models.Role{Code: constants.RoleCodeSuperAdmin, Status: enums.StatusOk} + if err := db.Create(&role).Error; err != nil { + t.Fatal(err) + } + if err := ensureBootstrapAdmin(db, &role); err != nil { + t.Fatal(err) + } + var user models.User + if err := db.Where("username = ?", constants.BootstrapAdminUsername).First(&user).Error; err != nil { + t.Fatal(err) + } + if user.UserType != enums.UserTypeEmployee { + t.Fatalf("bootstrap admin type = %q, want employee", user.UserType) + } + var count int64 + if err := db.Model(&models.UserRole{}).Where("user_id = ? AND role_id = ?", user.ID, role.ID).Count(&count).Error; err != nil { + t.Fatal(err) + } + if count != 1 { + t.Fatalf("super admin role assignments = %d, want 1", count) + } +} + +func TestRepairBootstrapAdminUserType(t *testing.T) { + repair, ok := migrationFuncs[10] + if !ok { + t.Fatal("bootstrap admin repair migration is not registered") + } + for _, tc := range []struct { + name string + username string + userType enums.UserType + status enums.Status + roleCode string + roleStatus enums.Status + deleted bool + want enums.UserType + }{ + {"legacy admin", "admin", enums.UserTypeUser, enums.StatusOk, constants.RoleCodeSuperAdmin, enums.StatusOk, false, enums.UserTypeEmployee}, + {"already employee", "admin", enums.UserTypeEmployee, enums.StatusOk, constants.RoleCodeSuperAdmin, enums.StatusOk, false, enums.UserTypeEmployee}, + {"ordinary user", "customer", enums.UserTypeUser, enums.StatusOk, "", enums.StatusOk, false, enums.UserTypeUser}, + {"same name without role", "admin", enums.UserTypeUser, enums.StatusOk, "", enums.StatusOk, false, enums.UserTypeUser}, + {"other super admin", "other", enums.UserTypeUser, enums.StatusOk, constants.RoleCodeSuperAdmin, enums.StatusOk, false, enums.UserTypeUser}, + {"disabled admin", "admin", enums.UserTypeUser, enums.StatusDisabled, constants.RoleCodeSuperAdmin, enums.StatusOk, false, enums.UserTypeUser}, + {"disabled role", "admin", enums.UserTypeUser, enums.StatusOk, constants.RoleCodeSuperAdmin, enums.StatusDisabled, false, enums.UserTypeUser}, + {"deleted admin", "admin", enums.UserTypeUser, enums.StatusOk, constants.RoleCodeSuperAdmin, enums.StatusOk, true, enums.UserTypeUser}, + } { + t.Run(tc.name, func(t *testing.T) { + db := setupBootstrapAdminTestDB(t) + sqls.SetDB(db) + t.Cleanup(func() { sqls.SetDB(nil) }) + user := models.User{Username: tc.username, Password: "unchanged-test-value", UserType: tc.userType, Status: tc.status} + if tc.deleted { + now := time.Now() + user.DeletedAt = &now + } + if err := db.Create(&user).Error; err != nil { + t.Fatal(err) + } + if tc.roleCode != "" { + role := models.Role{Code: tc.roleCode, Status: tc.roleStatus} + if err := db.Create(&role).Error; err != nil { + t.Fatal(err) + } + if err := db.Create(&models.UserRole{UserID: user.ID, RoleID: role.ID}).Error; err != nil { + t.Fatal(err) + } + } + if err := repair.Fn(); err != nil { + t.Fatal(err) + } + var got models.User + if err := db.First(&got, user.ID).Error; err != nil { + t.Fatal(err) + } + if got.UserType != tc.want { + t.Fatalf("type = %q, want %q", got.UserType, tc.want) + } + if got.Password != user.Password || got.Status != user.Status { + t.Fatal("repair changed password or account status") + } + updatedAt := got.UpdatedAt + if err := repair.Fn(); err != nil { + t.Fatal(err) + } + if err := db.First(&got, user.ID).Error; err != nil { + t.Fatal(err) + } + if !got.UpdatedAt.Equal(updatedAt) { + t.Fatal("second repair changed updated_at") + } + }) + } +} From 70a83270d4910ba0bb71a4a3d2f815394b785157 Mon Sep 17 00:00:00 2001 From: JOY <5027251+JOY@users.noreply.github.com> Date: Wed, 9 Sep 2026 01:37:25 +0700 Subject: [PATCH 4/9] chore(deps): upgrade flagged dependencies to patched versions - Go: grpc 1.83.1 (critical+high), websocket 1.5.3, excelize 2.11.0, quic-go 0.59.1, gomarkdown 759bbc3e3207 - Frontend: next 16.2.11, eslint-config-next 16.2.11, markdown-it 14.2.0, @tiptap 3.30.4, plus a range-scoped pnpm.overrides block pinning flagged transitive packages (fast-uri, nanoid, js-yaml, brace-expansion, postcss, browserslist, ws, undici, sharp, hono, path-to-regexp, picomatch, lodash, langsmith, uuid, linkify-it, immutable, esbuild, flatted, qs, humanfs, ip-address, body-parser, postcss-selector-parser, babel/core) to their patched versions --- go.mod | 17 +- go.sum | 56 +- web/package.json | 50 +- web/pnpm-lock.yaml | 1749 ++++++++++++++++++++++++-------------------- 4 files changed, 1022 insertions(+), 850 deletions(-) diff --git a/go.mod b/go.mod index e62257c2..34db975d 100644 --- a/go.mod +++ b/go.mod @@ -12,10 +12,10 @@ require ( github.com/glebarez/sqlite v1.11.0 github.com/go-playground/validator/v10 v10.30.1 github.com/golang-jwt/jwt/v5 v5.3.1 - github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 + github.com/gomarkdown/markdown v0.0.0-20260411013819-759bbc3e3207 github.com/google/uuid v1.6.0 github.com/gorilla/schema v1.4.1 - github.com/gorilla/websocket v1.5.1 + github.com/gorilla/websocket v1.5.3 github.com/microcosm-cc/bluemonday v1.0.26 github.com/mlogclub/codegen v1.0.3 github.com/mlogclub/simple v1.2.40 @@ -27,8 +27,9 @@ require ( github.com/silenceper/wechat/v2 v2.1.12 github.com/spf13/cast v1.10.0 github.com/spf13/viper v1.21.0 + github.com/subosito/gotenv v1.6.0 github.com/wk8/go-ordered-map/v2 v2.1.8 - github.com/xuri/excelize/v2 v2.10.1 + github.com/xuri/excelize/v2 v2.11.0 github.com/yuin/goldmark v1.4.13 golang.org/x/crypto v0.53.0 golang.org/x/net v0.56.0 @@ -50,7 +51,6 @@ require ( github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/pflag v1.0.10 // indirect - github.com/subosito/gotenv v1.6.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/text v0.38.0 // indirect ) @@ -105,9 +105,9 @@ require ( github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/quic-go/qpack v0.6.0 // indirect - github.com/quic-go/quic-go v0.59.0 // indirect + github.com/quic-go/quic-go v0.59.1 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/richardlehane/mscfb v1.0.6 // indirect + github.com/richardlehane/mscfb v1.0.7 // indirect github.com/richardlehane/msoleps v1.0.6 // indirect github.com/segmentio/asm v1.2.1 // indirect github.com/segmentio/encoding v0.5.4 // indirect @@ -126,7 +126,6 @@ require ( github.com/yosida95/uritemplate/v3 v3.0.2 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect - go.opentelemetry.io/otel v1.42.0 // indirect golang.org/x/arch v0.28.0 // indirect golang.org/x/exp v0.0.0-20260611194520-c48552f49976 // indirect golang.org/x/mod v0.37.0 // indirect @@ -135,8 +134,8 @@ require ( golang.org/x/telemetry v0.0.0-20260610154732-fb80ec83bdd9 // indirect golang.org/x/time v0.14.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect - google.golang.org/grpc v1.78.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect + google.golang.org/grpc v1.83.1 // indirect google.golang.org/protobuf v1.36.11 // indirect modernc.org/libc v1.41.0 // indirect modernc.org/mathutil v1.6.0 // indirect diff --git a/go.sum b/go.sum index cdf24e50..216e751f 100644 --- a/go.sum +++ b/go.sum @@ -115,8 +115,8 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 h1:4gjrh/PN2MuWCCElk8/I4OCKRKWCCo2zEct3VKCbibU= -github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= +github.com/gomarkdown/markdown v0.0.0-20260411013819-759bbc3e3207 h1:p7t34F7K4OCRQblcDhNJnP46Uaarz3z2cLcvOZYxWn8= +github.com/gomarkdown/markdown v0.0.0-20260411013819-759bbc3e3207/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI= github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -141,8 +141,8 @@ github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E= github.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM= -github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= -github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -248,12 +248,12 @@ github.com/qdrant/go-client v1.17.1 h1:7QmPwDddrHL3hC4NfycwtQlraVKRLcRi++BX6TTm+ github.com/qdrant/go-client v1.17.1/go.mod h1:n1h6GhkdAzcohoXt/5Z19I2yxbCkMA6Jejob3S6NZT8= github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= -github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw= -github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= +github.com/quic-go/quic-go v0.59.1 h1:0Gmua0HW1Tv7ANR7hUYwRyD0MG5OJfgvYSZasGZzBic= +github.com/quic-go/quic-go v0.59.1/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/richardlehane/mscfb v1.0.6 h1:eN3bvvZCp00bs7Zf52bxNwAx5lJDBK1tCuH19qq5aC8= -github.com/richardlehane/mscfb v1.0.6/go.mod h1:pe0+IUIc0AHh0+teNzBlJCtSyZdFOGgV4ZK9bsoV+Jo= +github.com/richardlehane/mscfb v1.0.7 h1:oeoiM0WE79vHwE8RpIYYvIAc8ajTH2mb6UZm55/+EB0= +github.com/richardlehane/mscfb v1.0.7/go.mod h1:pe0+IUIc0AHh0+teNzBlJCtSyZdFOGgV4ZK9bsoV+Jo= github.com/richardlehane/msoleps v1.0.6 h1:9BvkpjvD+iUBalUY4esMwv6uBkfOip/Lzvd93jvR9gg= github.com/richardlehane/msoleps v1.0.6/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= @@ -330,8 +330,8 @@ github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJ github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8= github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= -github.com/xuri/excelize/v2 v2.10.1 h1:V62UlqopMqha3kOpnlHy2CcRVw1V8E63jFoWUmMzxN0= -github.com/xuri/excelize/v2 v2.10.1/go.mod h1:iG5tARpgaEeIhTqt3/fgXCGoBRt4hNXgCp3tfXKoOIc= +github.com/xuri/excelize/v2 v2.11.0 h1:HxaEFl6sRN2+8J5a8HaKq+0M4FsjBGMnWWtjOCPSG88= +github.com/xuri/excelize/v2 v2.11.0/go.mod h1:jxFLbzaIwGQ5ufFNvYfUOHqXhfPaNmP14KWfmNz2Uak= github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 h1:+C0TIdyyYmzadGaL/HBLbf3WdLgC29pgyhTjAT/0nuE= github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= github.com/yargevad/filepathx v1.0.0 h1:SYcT+N3tYGi+NvazubCNlvgIPbzAk7i7y2dwg3I5FYc= @@ -351,16 +351,16 @@ go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho= -go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc= -go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4= -go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI= -go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= -go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= -go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= -go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= -go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY= -go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc= +go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= +go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= +go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= +go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= +go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= +go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= +go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= +go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= +go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= @@ -376,8 +376,8 @@ golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= golang.org/x/exp v0.0.0-20260611194520-c48552f49976 h1:X8Hz2ImujgbmetVuW+w2YkyZChE3cBpZi2P158rTG9M= golang.org/x/exp v0.0.0-20260611194520-c48552f49976/go.mod h1:vnf4pv9iKZXY58sQE1L86zmNWJ4159e1RkcWiLCkeEY= -golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ= -golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs= +golang.org/x/image v0.38.0 h1:5l+q+Y9JDC7mBOMjo4/aPhMDcxEptsX+Tt3GgRQRPuE= +golang.org/x/image v0.38.0/go.mod h1:/3f6vaXC+6CEanU4KJxbcUZyEePbyKbaLoDOe4ehFYY= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= @@ -441,12 +441,12 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= -gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= -google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= -google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.83.1 h1:HIO0+BEtBP6soyqvqC8sNUjZ7bTs+0hFQuFF+RAy++Y= +google.golang.org/grpc v1.83.1/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/web/package.json b/web/package.json index 540145e5..4f197c8f 100644 --- a/web/package.json +++ b/web/package.json @@ -19,12 +19,12 @@ "@hookform/resolvers": "^5.2.2", "@shadcn/react": "^0.3.0", "@tanstack/react-table": "^8.21.3", - "@tiptap/extension-image": "^3.20.2", - "@tiptap/extension-link": "^3.20.2", - "@tiptap/extension-placeholder": "^3.20.2", - "@tiptap/extension-underline": "3.20.2", - "@tiptap/react": "^3.20.2", - "@tiptap/starter-kit": "^3.20.2", + "@tiptap/extension-image": "^3.30.4", + "@tiptap/extension-link": "^3.30.4", + "@tiptap/extension-placeholder": "^3.30.4", + "@tiptap/extension-underline": "3.30.4", + "@tiptap/react": "^3.30.4", + "@tiptap/starter-kit": "^3.30.4", "@uiw/react-json-view": "2.0.0-alpha.41", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -32,10 +32,10 @@ "date-fns": "^4.1.0", "jose": "^6.2.3", "lucide-react": "^0.577.0", - "markdown-it": "^14.1.1", + "markdown-it": "^14.2.0", "md-editor-rt": "^6.4.1", "mermaid": "^11.17.0", - "next": "16.1.6", + "next": "16.2.11", "next-themes": "^0.4.6", "react": "19.2.3", "react-day-picker": "^9.14.0", @@ -65,10 +65,42 @@ "@types/react-dom": "^19", "@types/turndown": "^5.0.6", "eslint": "^9", - "eslint-config-next": "16.1.6", + "eslint-config-next": "16.2.11", "sass": "^1.98.0", "tailwindcss": "^4", "terser": "^5.46.2", "typescript": "^6.0.3" + }, + "pnpm": { + "overrides": { + "fast-uri@>=3.0.0 <3.1.6": "3.1.6", + "nanoid@>=3.0.0 <3.3.18": "3.3.18", + "js-yaml@>=4.0.0 <4.3.1": "4.3.1", + "brace-expansion@<1.1.18": "1.1.18", + "brace-expansion@>=3.0.0 <5.0.9": "5.0.9", + "postcss@<8.5.23": "8.5.23", + "browserslist@<4.28.7": "4.28.7", + "ws@>=8.0.0 <8.21.0": "8.21.0", + "undici@>=6.0.0 <6.28.0": "6.28.0", + "sharp@<0.35.0": "0.35.0", + "hono@>=4.0.0 <4.12.34": "4.12.34", + "@hono/node-server@<1.19.15": "1.19.15", + "path-to-regexp@>=8.0.0 <8.4.0": "8.4.0", + "picomatch@>=2.0.0 <2.3.2": "2.3.2", + "picomatch@>=4.0.0 <4.0.4": "4.0.4", + "lodash@>=4.0.0 <4.18.0": "4.18.0", + "langsmith@<0.6.0": "0.6.0", + "uuid@<11.1.1": "11.1.1", + "linkify-it@>=5.0.0 <5.0.2": "5.0.2", + "immutable@>=5.0.0 <5.1.8": "5.1.8", + "esbuild@>=0.24.0 <0.25.0": "0.25.0", + "flatted@>=3.0.0 <3.4.2": "3.4.2", + "qs@>=6.0.0 <6.16.0": "6.16.0", + "@humanfs/node@<0.16.8": "0.16.8", + "ip-address@<10.3.1": "10.3.1", + "body-parser@>=2.0.0 <2.3.0": "2.3.0", + "postcss-selector-parser@>=7.0.0 <7.1.3": "7.1.3", + "@babel/core@<7.29.6": "7.29.6" + } } } diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index ff9ecc35..a47e97fb 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -4,6 +4,36 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + fast-uri@>=3.0.0 <3.1.6: 3.1.6 + nanoid@>=3.0.0 <3.3.18: 3.3.18 + js-yaml@>=4.0.0 <4.3.1: 4.3.1 + brace-expansion@<1.1.18: 1.1.18 + brace-expansion@>=3.0.0 <5.0.9: 5.0.9 + postcss@<8.5.23: 8.5.23 + browserslist@<4.28.7: 4.28.7 + ws@>=8.0.0 <8.21.0: 8.21.0 + undici@>=6.0.0 <6.28.0: 6.28.0 + sharp@<0.35.0: 0.35.0 + hono@>=4.0.0 <4.12.34: 4.12.34 + '@hono/node-server@<1.19.15': 1.19.15 + path-to-regexp@>=8.0.0 <8.4.0: 8.4.0 + picomatch@>=2.0.0 <2.3.2: 2.3.2 + picomatch@>=4.0.0 <4.0.4: 4.0.4 + lodash@>=4.0.0 <4.18.0: 4.18.0 + langsmith@<0.6.0: 0.6.0 + uuid@<11.1.1: 11.1.1 + linkify-it@>=5.0.0 <5.0.2: 5.0.2 + immutable@>=5.0.0 <5.1.8: 5.1.8 + esbuild@>=0.24.0 <0.25.0: 0.25.0 + flatted@>=3.0.0 <3.4.2: 3.4.2 + qs@>=6.0.0 <6.16.0: 6.16.0 + '@humanfs/node@<0.16.8': 0.16.8 + ip-address@<10.3.1: 10.3.1 + body-parser@>=2.0.0 <2.3.0: 2.3.0 + postcss-selector-parser@>=7.0.0 <7.1.3: 7.1.3 + '@babel/core@<7.29.6': 7.29.6 + importers: .: @@ -33,23 +63,23 @@ importers: specifier: ^8.21.3 version: 8.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@tiptap/extension-image': - specifier: ^3.20.2 - version: 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2)) + specifier: ^3.30.4 + version: 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) '@tiptap/extension-link': - specifier: ^3.20.2 - version: 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2) + specifier: ^3.30.4 + version: 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) '@tiptap/extension-placeholder': - specifier: ^3.20.2 - version: 3.20.2(@tiptap/extensions@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2)) + specifier: ^3.30.4 + version: 3.31.3(@tiptap/extensions@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) '@tiptap/extension-underline': - specifier: 3.20.2 - version: 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2)) + specifier: 3.30.4 + version: 3.30.4(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) '@tiptap/react': - specifier: ^3.20.2 - version: 3.20.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + specifier: ^3.30.4 + version: 3.31.3(@floating-ui/dom@1.7.6)(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@tiptap/starter-kit': - specifier: ^3.20.2 - version: 3.20.2 + specifier: ^3.30.4 + version: 3.31.3 '@uiw/react-json-view': specifier: 2.0.0-alpha.41 version: 2.0.0-alpha.41(@babel/runtime@7.28.6)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -72,8 +102,8 @@ importers: specifier: ^0.577.0 version: 0.577.0(react@19.2.3) markdown-it: - specifier: ^14.1.1 - version: 14.1.1 + specifier: ^14.2.0 + version: 14.3.1 md-editor-rt: specifier: ^6.4.1 version: 6.4.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -81,8 +111,8 @@ importers: specifier: ^11.17.0 version: 11.17.0 next: - specifier: 16.1.6 - version: 16.1.6(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.98.0) + specifier: 16.2.11 + version: 16.2.11(@babel/core@7.29.6(supports-color@7.2.0))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.98.0) next-themes: specifier: ^0.4.6 version: 0.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -100,7 +130,7 @@ importers: version: 7.71.2(react@19.2.3) react-markdown: specifier: ^10.1.0 - version: 10.1.0(@types/react@19.2.14)(react@19.2.3) + version: 10.1.0(@types/react@19.2.14)(react@19.2.3)(supports-color@7.2.0) react-resizable-panels: specifier: ^4.7.6 version: 4.7.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -118,10 +148,10 @@ importers: version: 4.0.0 remark-gfm: specifier: ^4.0.1 - version: 4.0.1 + version: 4.0.1(supports-color@7.2.0) shadcn: specifier: ^4.18.0 - version: 4.18.0(typescript@6.0.3) + version: 4.18.0(supports-color@7.2.0)(typescript@6.0.3) sonner: specifier: ^2.0.7 version: 2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -164,10 +194,10 @@ importers: version: 5.0.6 eslint: specifier: ^9 - version: 9.39.4(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1)(supports-color@7.2.0) eslint-config-next: - specifier: 16.1.6 - version: 16.1.6(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) + specifier: 16.2.11 + version: 16.2.11(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) sass: specifier: ^1.98.0 version: 1.98.0 @@ -194,18 +224,26 @@ packages: resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + '@babel/compat-data@7.29.0': resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} engines: {node: '>=6.9.0'} - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + '@babel/core@7.29.6': + resolution: {integrity: sha512-QdxmAo/ikZqqRGA8s43ww8lcql6naWRvEz0FFrl6MIlc7Gi6TroXnSdWa5U/kq6fzcpqpHesicQxFZIieZbyIA==} engines: {node: '>=6.9.0'} '@babel/generator@7.29.1': resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} + '@babel/generator@7.29.8': + resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==} + engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.27.3': resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} @@ -218,7 +256,7 @@ packages: resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': 7.29.6 '@babel/helper-globals@7.28.0': resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} @@ -236,7 +274,7 @@ packages: resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': 7.29.6 '@babel/helper-optimise-call-expression@7.27.1': resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} @@ -250,7 +288,7 @@ packages: resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': 7.29.6 '@babel/helper-skip-transparent-expression-wrappers@7.27.1': resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} @@ -260,16 +298,24 @@ packages: resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.28.6': - resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} engines: {node: '>=6.9.0'} '@babel/parser@7.29.0': @@ -277,35 +323,40 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.29.8': + resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/plugin-syntax-jsx@7.28.6': resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': 7.29.6 '@babel/plugin-syntax-typescript@7.28.6': resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': 7.29.6 '@babel/plugin-transform-modules-commonjs@7.28.6': resolution: {integrity: sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': 7.29.6 '@babel/plugin-transform-typescript@7.28.6': resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': 7.29.6 '@babel/preset-typescript@7.28.5': resolution: {integrity: sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': 7.29.6 '@babel/runtime@7.28.6': resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} @@ -315,6 +366,10 @@ packages: resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + '@babel/traverse@7.29.0': resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} @@ -323,6 +378,10 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} + engines: {node: '>=6.9.0'} + '@base-ui/react@1.3.0': resolution: {integrity: sha512-FwpKqZbPz14AITp1CVgf4AjhKPe1OeeVKSBMdgD10zbFlj3QSWelmtCMLi2+/PFZZcIm3l87G7rwtCZJwHyXWA==} engines: {node: '>=14.0.0'} @@ -484,6 +543,9 @@ packages: '@emnapi/core@1.9.0': resolution: {integrity: sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==} + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + '@emnapi/runtime@1.9.0': resolution: {integrity: sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==} @@ -543,23 +605,27 @@ packages: '@floating-ui/utils@0.2.11': resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} - '@hono/node-server@1.19.11': - resolution: {integrity: sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==} + '@hono/node-server@1.19.15': + resolution: {integrity: sha512-Za2ai6TLdKjUvnur+eenO6nuYYipVAEhyCAdaV8IRvmU9kK8crOZUSYvIXn72E4f8fJqyAbpcJuTsYYmZp9Deg==} engines: {node: '>=18.14.1'} peerDependencies: - hono: ^4 + hono: 4.12.34 '@hookform/resolvers@5.2.2': resolution: {integrity: sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==} peerDependencies: react-hook-form: ^7.55.0 - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} engines: {node: '>=18.18.0'} - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': @@ -580,152 +646,161 @@ packages: resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} - '@img/sharp-darwin-arm64@0.34.5': - resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-darwin-arm64@0.35.0': + resolution: {integrity: sha512-ZgaYEwaj+lx/5n4W8GmZ2IYz0PQHjN5eqRcfijWGB+2Aq7ZInZGa0qJyAn6DEtyLuWHRSrmWOqT9q3qqTBvmUQ==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.34.5': - resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-darwin-x64@0.35.0': + resolution: {integrity: sha512-c1z9LFpKB0slQW3RchwBE8iSVzGp70TNjUUO9k4BZwwW4HH7JBGHeIy4b+kk4n/kcBASb9evKCE3/7Slmslgiw==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.4': - resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + '@img/sharp-freebsd-wasm32@0.35.0': + resolution: {integrity: sha512-Li2KTev0H90kEtnJHkI9xQojXt1AqWmFBMXiPw5kqd1jQgP7gi5HVK/qC5Rmh/59NuAwUuPzzPITmX22NomYYQ==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-libvips-darwin-arm64@1.3.0': + resolution: {integrity: sha512-EKbmBKtyTH+GPFDRw2TgK2oV6hyxxlJVIar4hoTYSNmIwipgMFdxPQqR392GmfdsPGWga0mCFN1cCKjRb9cljw==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.4': - resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + '@img/sharp-libvips-darwin-x64@1.3.0': + resolution: {integrity: sha512-Pl2OmOvrJ42adUllESxBsG54PfXLo1OYg9i3c5/5Ln/qJ0gZuTM9YMhQJPIbXqwidLRc/c2zuHt4RsrymmNv7A==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.2.4': - resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + '@img/sharp-libvips-linux-arm64@1.3.0': + resolution: {integrity: sha512-C0SqjoFKnszqa44EQ7xoaT48nnO0lOyXEULfXMWi8krrjOPGYkeK30Okzla6ATbBYsyZ0ySinK0FVkpv3DwzfQ==} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-arm@1.2.4': - resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + '@img/sharp-libvips-linux-arm@1.3.0': + resolution: {integrity: sha512-A8UpHoUDW4DwnXoV6+q3C1s7QLRAHtPDEjWuNZjwHMyoCNZnm0GeNN8ls9f/bsEYTRQRW96C/n34XJQHJ2fT7A==} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-ppc64@1.2.4': - resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + '@img/sharp-libvips-linux-ppc64@1.3.0': + resolution: {integrity: sha512-WOpkVxAjFd369iaIzEgNRreFD+gWdUMIGD5zplhNKNeqS6mm5dac3q2AFyCBmzYoAdouzZvRBgxy4z8QHZb4/A==} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-riscv64@1.2.4': - resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + '@img/sharp-libvips-linux-riscv64@1.3.0': + resolution: {integrity: sha512-DRWw0mOHusrCCuw2rqP87oLg6PGlkomVDFqw2hIwsSfwWpu4k3XLcBPaKKl6ct/GtL/cwNkgwjV/tc0Mqht3VA==} cpu: [riscv64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-s390x@1.2.4': - resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + '@img/sharp-libvips-linux-s390x@1.3.0': + resolution: {integrity: sha512-9APy+nFWhHS+kzLgWZfLcyrUd7YqnAQVa4BPOo4xkoHpdoktOAPG4cEr9+Jpl0TtqfVmcMJimNL5qNTyyOHZNA==} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-x64@1.2.4': - resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + '@img/sharp-libvips-linux-x64@1.3.0': + resolution: {integrity: sha512-y9RNUYDe2A1UAdhLyfeOodGRszQdaEoe4nfOpp/sNVPl2CWIcUyFaDoCh4vPLPxu19803j2naLqZup2WxDXCLA==} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + '@img/sharp-libvips-linuxmusl-arm64@1.3.0': + resolution: {integrity: sha512-cC1wkC0Mlucd0KSiGrLkJnB/ZqPvZCntc/Lk7ZnYO5ZSbF2euNek4Xvxafojq+wN1q/W0eprdpUIjUr/EV2PBg==} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + '@img/sharp-libvips-linuxmusl-x64@1.3.0': + resolution: {integrity: sha512-LiYMhUZicB1QG//+RvmYZpXJO8fYRENfp+MZUCnG9aw+AKvGAy9gPaCnuwsPcBFs8EV66M0NNxj9VHcNklE8zw==} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-linux-arm64@0.34.5': - resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-arm64@0.35.0': + resolution: {integrity: sha512-4+4XHLNT5wDT0roYlHTEmH9lDKt0acf9Tv+3hM3iceOirkxrR404/3WjAYZ9F9CkHrxeRcGLJXbi4vluMZ9O+A==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-linux-arm@0.34.5': - resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-arm@0.35.0': + resolution: {integrity: sha512-VVlpEWwizEFIOom0zdoeKuO5nuTswzVE5uHcBNvHzmeHUpNFajY3HFfbQ+zIH4E2kVaZ/yVxmsShW56TtEy4uA==} + engines: {node: '>=20.9.0'} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-linux-ppc64@0.34.5': - resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-ppc64@0.35.0': + resolution: {integrity: sha512-N3hzbEpUTJC8pWpPVJvgzGxM+so/MAXc8O2s/53B0LL9ZGpfXpME7Wizkc5d/8fRBlBtkDjzoZGDCqqNDHqLEw==} + engines: {node: '>=20.9.0'} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-linux-riscv64@0.34.5': - resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-riscv64@0.35.0': + resolution: {integrity: sha512-l6vmKVPnbS0RhVMbyxP5meAARsbhCnBN4fy31qz0+3a6Rv4jEqfzDrT89y6ZPkCi0AJGnwp2En528yXo401Hpw==} + engines: {node: '>=20.9.0'} cpu: [riscv64] os: [linux] libc: [glibc] - '@img/sharp-linux-s390x@0.34.5': - resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-s390x@0.35.0': + resolution: {integrity: sha512-MYlMiPFiv/EKPAHnp3yNZ9AAWFsxga9c5Bkc6wkar6bqzHLlkGVJHRm0u1ei+VXnZxp3Mz9MG9ZIsI8vSOf3sQ==} + engines: {node: '>=20.9.0'} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-linux-x64@0.34.5': - resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-x64@0.35.0': + resolution: {integrity: sha512-TYaItB5oj1ioXjhyn2xrR208vf+YuIIcHptQWRRaBmFhvIvL9D72DXN8w75xup0KXA8UdEAhQ9Qb2S49FD/9Cw==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-linuxmusl-arm64@0.34.5': - resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-arm64@0.35.0': + resolution: {integrity: sha512-DSTb6ijQzqe6DdAaOBVqJ/SYf1vO8EW5bK6X6LRXufEBebf2722VCdvBUtZ3rtV0x2ApfPNDy/p7LrrjaWjiyQ==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-linuxmusl-x64@0.34.5': - resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-x64@0.35.0': + resolution: {integrity: sha512-K7ykQ+26Rt6+4BTU80AuGgTPIYX86UxiAKT4rcXX/WNTo7k1ZxpKz+TguHnwVpCqQK3B5PK0vZ0ZBe6nz/ib1w==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-wasm32@0.34.5': - resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-wasm32@0.35.0': + resolution: {integrity: sha512-9woLIFORERCr+6cWu87dQ22J34EExkhc73U1kZW0c+RclQqWetoodByp4dWZ/hN8/KVmTRAx2HOnUwib8AwZdA==} + engines: {node: '>=20.9.0'} + + '@img/sharp-webcontainers-wasm32@0.35.0': + resolution: {integrity: sha512-t+kie1TOyaDM6Dho+f+y0VqIUNhYQaKCUahuZVi0E0frgdiaOaPsDxDW3wfKacUdaNBCnK/ZDBMg33ydvHj8uA==} + engines: {node: '>=20.9.0'} cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.5': - resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-arm64@0.35.0': + resolution: {integrity: sha512-M5eKxug0dabbaWgFKvPa3odNs2OpaP+81NASfGKkt4GcYXpNhSu7CaeYxWkLNV6vHmUp4hnCxnxrUyhUJhXbKA==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.34.5': - resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-ia32@0.35.0': + resolution: {integrity: sha512-z0+pZ03QCDvdVN0Ez9IX/yjWC19ikMlXrmdYMwYNLTh2BLPx3hXWPvyqWfquZ0BTO9O6GVOjIVoTcyyacMnWlQ==} + engines: {node: ^20.9.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.34.5': - resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-x64@0.35.0': + resolution: {integrity: sha512-feNnlz5ZHKr0MY1LPHvZQyJeBkbo4ctsn0D8FvA53VTw5TC63rfEL2UrWbkSBR19htSE7Mw78xYVwdJqoMWVHw==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [win32] @@ -821,60 +896,60 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@next/env@16.1.6': - resolution: {integrity: sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==} + '@next/env@16.2.11': + resolution: {integrity: sha512-0do5A3BJ2gxWr0ZCMcD6BhW+e595jyxdTl3rXTS6lOtD8ektMiW6CO+EPwt1Eca1DBnm90r/7GdiKWBKxH++DA==} - '@next/eslint-plugin-next@16.1.6': - resolution: {integrity: sha512-/Qq3PTagA6+nYVfryAtQ7/9FEr/6YVyvOtl6rZnGsbReGLf0jZU6gkpr1FuChAQpvV46a78p4cmHOVP8mbfSMQ==} + '@next/eslint-plugin-next@16.2.11': + resolution: {integrity: sha512-vMEf/aXOpzFFdtIvFYOnIDPKb0xBbrXONsz83CcKdRrekfxNdL8PNkq5qHqAHSXVlIifnX68LOMaxr3z5PkeLQ==} - '@next/swc-darwin-arm64@16.1.6': - resolution: {integrity: sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==} + '@next/swc-darwin-arm64@16.2.11': + resolution: {integrity: sha512-wryL4pjKmDwGv2ox6+GZDFxvmtSRLqApBR8kL1j4+vhB7Z5vJC/zAnXpiR9Xkfzl0AS8WLMnsuGV/UKI67/rrw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@16.1.6': - resolution: {integrity: sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==} + '@next/swc-darwin-x64@16.2.11': + resolution: {integrity: sha512-aZl2j4f/fLyjQvOhv0Oe9UaMAQHolYpKhctsoYzplSumKJKPUmgjcf6545aBtysLTcu994TREd0+pSgNE4ohmg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@16.1.6': - resolution: {integrity: sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==} + '@next/swc-linux-arm64-gnu@16.2.11': + resolution: {integrity: sha512-5jEriyEnH/LWFy27L2ZG0XaLlyEJIjhsImEsiS9P563PKEVp2BVups/xfOucIrsvVntp11oNcZwjHvaDPYVB5g==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@next/swc-linux-arm64-musl@16.1.6': - resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==} + '@next/swc-linux-arm64-musl@16.2.11': + resolution: {integrity: sha512-eIjcpx2fnnFSSkZDbTxy74KnokUXDjfoLClpWelfgHLf621aTqswhwXQ7GkD5K5rplrS6LZ/Bj+mVuvzluBOEg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@next/swc-linux-x64-gnu@16.1.6': - resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==} + '@next/swc-linux-x64-gnu@16.2.11': + resolution: {integrity: sha512-8WgzpaWMs46qJT9kiV47cje86L0x/Mu9t8/Gwj+pnbgW3rETVfCnaScPjlYUwNScpOozdcIMHWmAvuZJUonR2w==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@next/swc-linux-x64-musl@16.1.6': - resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==} + '@next/swc-linux-x64-musl@16.2.11': + resolution: {integrity: sha512-I3UgPds7G4ZYnTb/H+5GBGuUT2DhAk6j0mL6A4s63RjFs74wB2hOWP0vaxsK+3NJraExt3eYEPQ/UtT0x/64Nw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@next/swc-win32-arm64-msvc@16.1.6': - resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==} + '@next/swc-win32-arm64-msvc@16.2.11': + resolution: {integrity: sha512-n89CjtcThnjrwgJMAiI5xbqwLY51zvwC9tSlArmVndAJLYVl9T9UAdlkXTmZvE++idoXe8KdglQlhNRdUp1c6g==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@16.1.6': - resolution: {integrity: sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==} + '@next/swc-win32-x64-msvc@16.2.11': + resolution: {integrity: sha512-md8CLNggS1Dx9pUgApzps5uAf+N8GN9xywzmNx9vHAWo94HtBwCCqkSnhIrdfQe83Dhz8Lfo/20Nb1Zxal092w==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1166,9 +1241,6 @@ packages: '@types/react': optional: true - '@remirror/core-constants@3.0.0': - resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==} - '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} @@ -1303,170 +1375,170 @@ packages: resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} engines: {node: '>=12'} - '@tiptap/core@3.20.2': - resolution: {integrity: sha512-zKW4LqZt+aNdvz9o4R0/j+D+gfhwzuFItwh7wbqz8g8bWi0jaV95VybeVFVKeg/KGTc3sAa4mm+hGgvgrY+Gvg==} + '@tiptap/core@3.31.3': + resolution: {integrity: sha512-Cz50pvciQrxdSxgTkHOVz0uD0Yl/8Xt0QatGD6ILm47jW8EzyHR9RkUGs/D5IqzXKuVPntfw1ttaT926vXfiRg==} peerDependencies: - '@tiptap/pm': ^3.20.2 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-blockquote@3.20.2': - resolution: {integrity: sha512-tkzZzBdwu8pP6pRfYjGanyj4aMSdcr4TS/Z9dcFxA8SYhmBXB4FYTbURME8Eg+n5VIOh1/2c4R2mbOkfQd4GtQ==} + '@tiptap/extension-blockquote@3.31.3': + resolution: {integrity: sha512-fyY2XMbyDDDfOTQ1Qdrnqa1qwC9DWE4n7AfE0EKQI0G8MfLV8RaDlLDcOZDJ9JbMPY7/Gx7EjyK4NKxSW9n2hQ==} peerDependencies: - '@tiptap/core': ^3.20.2 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-bold@3.20.2': - resolution: {integrity: sha512-NLqh6ewHcDDPveTCL2f6BQcsDI5lubNjiyzvuYr0ZO9AV5Fqw8TkYwoKNijiYlgGRtm+pZLhMnf45gbLJQoymg==} + '@tiptap/extension-bold@3.31.3': + resolution: {integrity: sha512-dIuYhKk8TitKU/FeDpoTeWZhU42YgDN5npgWNjAmMmRktPdoxnH3/wGSiwXlqZgJWjehN7kPWDePWpJeAImGpQ==} peerDependencies: - '@tiptap/core': ^3.20.2 + '@tiptap/core': 3.31.3 - '@tiptap/extension-bubble-menu@3.20.2': - resolution: {integrity: sha512-Np9jHUBWPnFJMy3Qhup3udARJQnWkbwVxVaHlJdgEy5Hfy/HE/EnItXAxXeFjVZ57cl+kJYamdn1t8VfMOV3mg==} + '@tiptap/extension-bubble-menu@3.31.3': + resolution: {integrity: sha512-EV6ZnwKc++2OM/OcD54n8s1B7C9LP7GKAtdEPwu0t3BYJf3sG8Ueoinf7SgGPO9oMPg96GneOkDNm1urMV167g==} peerDependencies: - '@tiptap/core': ^3.20.2 - '@tiptap/pm': ^3.20.2 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-bullet-list@3.20.2': - resolution: {integrity: sha512-LHmp945at3YYl2VPIg0bopyJioi52xK+YRurOz8A440EgCdnAkFa0UDGHxK/e4Y0R2y3xbPl+VBl3HzZjXPFuw==} + '@tiptap/extension-bullet-list@3.31.3': + resolution: {integrity: sha512-qEyyoPapPef4LO8XKaN83bxtaNzkJ4kFn/IxLnEKd4BJ3Mvi4MH2yJYlyDqwFnMoev4pMA1zBHRAt/C0THRmZw==} peerDependencies: - '@tiptap/extension-list': ^3.20.2 + '@tiptap/extension-list': 3.31.3 - '@tiptap/extension-code-block@3.20.2': - resolution: {integrity: sha512-BpClHuUrOYArL8skifo6RSlBiAVDYkGkq22zVb9lNfrrRqJIlPhwDI8tCZh1sHbgDQPukb4lE5VMPnsEv5M1tw==} + '@tiptap/extension-code-block@3.31.3': + resolution: {integrity: sha512-nvknt4FhyJQjYcvxptmeUlFsIAc8ibua3E5BN4Pim374/9RWepH4cdE9X0/qUTtguHElLx0iKtSIY3rW2qGTFA==} peerDependencies: - '@tiptap/core': ^3.20.2 - '@tiptap/pm': ^3.20.2 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-code@3.20.2': - resolution: {integrity: sha512-4mwWtt88Cl7PT5IbQpwigPBlNmB3JUiOchPXJIfbGu7wUxAk7a37vhn8ptiM2IGKpBFum/1PZFUI+Ik7TLIZLg==} + '@tiptap/extension-code@3.31.3': + resolution: {integrity: sha512-SzxOqchrD2AcN3uT67PjKmRFEMOU3vNNiwNaamZJUbZrI6Hmy+bvdHJrc3jrIddyyCrAtsnAfRI0cmorW1jGfg==} peerDependencies: - '@tiptap/core': ^3.20.2 + '@tiptap/core': 3.31.3 - '@tiptap/extension-document@3.20.2': - resolution: {integrity: sha512-HHlpUs1Y22YwDmJ0cmTGPrFPuHk8Q2wvYZeG5eFOEeBu7t4IiCU114slvIR+yrDZrzpPmwzMb8H71scR+moizg==} + '@tiptap/extension-document@3.31.3': + resolution: {integrity: sha512-EexgmqnyDNyGlISxo7SMrp5MygpJYmqD+0cY5jB6L1U6L4CpKKRWUt8OO1sWzEHDE1+TTvwt+WIFoIWAziOtEA==} peerDependencies: - '@tiptap/core': ^3.20.2 + '@tiptap/core': 3.31.3 - '@tiptap/extension-dropcursor@3.20.2': - resolution: {integrity: sha512-LpBZOOgTrFWkYneOWOd0xyB7HUGIZqrgEhL+Beohzxkx63uNRC3PxFAAXhju6wxcvQ49e/WMg++Z8EDwHb6f2Q==} + '@tiptap/extension-dropcursor@3.31.3': + resolution: {integrity: sha512-NWomSfu5CSC7VacnMSDzKT8qm66SzMfZwVPEtwY5bPpRTJgTiT1rNK0neDrrzfMN27MfylGyKWWf7Q5Qf8w/fg==} peerDependencies: - '@tiptap/extensions': ^3.20.2 + '@tiptap/extensions': 3.31.3 - '@tiptap/extension-floating-menu@3.20.2': - resolution: {integrity: sha512-Ev9QuNmV/A2fMuu+XpEy1W+u8FOu75S7GVPtS+cYRQc/TYTKaxha0+j0eYvJzKLzKRguJNRlmPBDHGN7MnSY/w==} + '@tiptap/extension-floating-menu@3.31.3': + resolution: {integrity: sha512-rd4VJ9PGSP9Eop8ZTEwaLZcMzMXLuJKe3hUNf58rq+zANpwM+9fI+vB7g9MAc3eXwUNDxNDVACFIL2oeBqpQ3A==} peerDependencies: '@floating-ui/dom': ^1.0.0 - '@tiptap/core': ^3.20.2 - '@tiptap/pm': ^3.20.2 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-gapcursor@3.20.2': - resolution: {integrity: sha512-IfQuD5XctZa+Xxy3mdjo9NTYbiMFqGPuzyh2ypHUqyuvIwxOIRhxTFaCijOGVYn1g3BH8nzGMhZ5rnZ48zIb6Q==} + '@tiptap/extension-gapcursor@3.31.3': + resolution: {integrity: sha512-EBXKb1FrVStsNYCcRGtd9jmzveCvR+eqgg1rVqoONrqFK6U7bga6LN+1dMKroP1kliDVgveYkP3vRYxqw+rFqg==} peerDependencies: - '@tiptap/extensions': ^3.20.2 + '@tiptap/extensions': 3.31.3 - '@tiptap/extension-hard-break@3.20.2': - resolution: {integrity: sha512-TdjJ54483D1PsGLOBQBvzTqIKc027hixP/xFul9KfXIpGG+YGqX0U2RO3oUyuv32fbU1ZVLMDfEBzR/ropsyDg==} + '@tiptap/extension-hard-break@3.31.3': + resolution: {integrity: sha512-QAdCvNO4+yW9ATwsrej11NTkDYFqPLIEQr3ARNrKOK1qaiS7A0fia2SEukb/hrkP3A6mbozhoQt2r2RGUf/DpQ==} peerDependencies: - '@tiptap/core': ^3.20.2 + '@tiptap/core': 3.31.3 - '@tiptap/extension-heading@3.20.2': - resolution: {integrity: sha512-XKpSEMcER00yfMXiASPpCHHa4Tw6G78AUELFt2PiS0tTWdxNpXZ8y29glyR4LO5eBxGjF1jncO49T1DzDh48TQ==} + '@tiptap/extension-heading@3.31.3': + resolution: {integrity: sha512-rk5VHMAeQcg06SLauN6EGdD2jc0O2qY8QkZYPd0LxNvLblw2BxBx+lxUQSYwLAT9Ie5914gKIK2YbRyO2Ts3ig==} peerDependencies: - '@tiptap/core': ^3.20.2 + '@tiptap/core': 3.31.3 - '@tiptap/extension-horizontal-rule@3.20.2': - resolution: {integrity: sha512-1Ds1xwl4XKWzXhZ8jG+G04BepExxuwtJuw+xbdMXkTD3YDE8KmbSrUIiLpA60Zq4qZmWIrX57F7mOBGaExyfCw==} + '@tiptap/extension-horizontal-rule@3.31.3': + resolution: {integrity: sha512-YnHGy2KShRwvCseAmmxl9VP7R0qaj8QMp3DA6DJWZqp7r5gLGvDkAqhedxqqefqsE4Y43hjkBdjtB9Ce78LkIw==} peerDependencies: - '@tiptap/core': ^3.20.2 - '@tiptap/pm': ^3.20.2 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-image@3.20.2': - resolution: {integrity: sha512-STo7T3NQ1TcF93NXRQDhb5YkepBRpYHY54yfBUmHl5cygYZzOMaGlM0nh8NeX54mh3wJ6+nxpApuM3Jbmg0I+w==} + '@tiptap/extension-image@3.31.3': + resolution: {integrity: sha512-wWNG9BOtx2Cg4vwxPVGDIJ5DGX+ETkldeoaFJLB1NXUL4OPUiVTf8cHZ+hdYgJWP704BEB7jQgjlpvdi6VigTg==} peerDependencies: - '@tiptap/core': ^3.20.2 + '@tiptap/core': 3.31.3 - '@tiptap/extension-italic@3.20.2': - resolution: {integrity: sha512-VAIXeJMx4g6WKqqNm8PYzoFrJaRNKLzLtqUXqYozKxnJLpF2HjsIrnBJV9PM+1FKK2Tic1UuowF4OI/6d162SA==} + '@tiptap/extension-italic@3.31.3': + resolution: {integrity: sha512-ibGvdvAPyfxBMUVNRI43eb9h2/Jka1MRG5GtnGqbcCX/2+Y/y0EOfFrPQPkuYphiWQYyu9+FzPKMB/pjuaLuKQ==} peerDependencies: - '@tiptap/core': ^3.20.2 + '@tiptap/core': 3.31.3 - '@tiptap/extension-link@3.20.2': - resolution: {integrity: sha512-vnC72CFMUiCJuAt7Hi4T/hKvbY4DqBjqo9G6dkBfNJHXHmqGiGKvkgzm1m7P/R1EX1XYk8nifeCpW6q2uliFRQ==} + '@tiptap/extension-link@3.31.3': + resolution: {integrity: sha512-986wOQzTL9Zr5lf84LCLpm+YOms8A0K39/8DVoqRfebqcOe0/eq4bnztmAlfabOd+kJY92g3AgZERFUx/w+dcw==} peerDependencies: - '@tiptap/core': ^3.20.2 - '@tiptap/pm': ^3.20.2 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-link@3.22.0': - resolution: {integrity: sha512-tGMBUAmni532G6R5gnaRvTb6c7+ST1qCHBV0p5kGGzdHaQTDd1R7S8fnuA3M7+6Sruc82iIY+Ur+6Tusvo/vLA==} + '@tiptap/extension-list-item@3.31.3': + resolution: {integrity: sha512-4QlKOriJJMvg95QJTEsy9BUYPBQ6UvJyb8WURRwdUtQUkkqb8h32lg/eyQUv2FzW9IT1AdUyNZfVaxH64kRfQA==} peerDependencies: - '@tiptap/core': ^3.22.0 - '@tiptap/pm': ^3.22.0 + '@tiptap/extension-list': 3.31.3 - '@tiptap/extension-list-item@3.20.2': - resolution: {integrity: sha512-6L+ZKOqD9jTmE313qFkrIk81jbk8v437zRa5Sa0/hyFMbupsNVKZoZZkzrq5vOkbz2oE0WpsFXIjcYaqAwJhyA==} + '@tiptap/extension-list-keymap@3.31.3': + resolution: {integrity: sha512-If8UOEdDZbPJU6iYTvLtH6DOp2KBy6BKxg9UELL1AevVetGHEF/7lW8hP50Gn1tHMVpPRqmhSzVrJRpEJJgb/Q==} peerDependencies: - '@tiptap/extension-list': ^3.20.2 + '@tiptap/extension-list': 3.31.3 - '@tiptap/extension-list-keymap@3.20.2': - resolution: {integrity: sha512-SKU+w93E9+TdSWeoJzjFLDbO+XC/QIRQ+PJ6Jruz1BJ6VXILmyVOw3jBwmiJjLo+5h4MNV2D/IHx1P7BpEkUhQ==} + '@tiptap/extension-list@3.31.3': + resolution: {integrity: sha512-LoveGnC0FVdCV4jUNBaG1ZA+KWE07+adzV3kGy6uUYFcJEjbVUHTnPDrBOob3IwOSO3sCwIkvQb6EVYeXn/4yg==} peerDependencies: - '@tiptap/extension-list': ^3.20.2 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-list@3.20.2': - resolution: {integrity: sha512-x9h1fDeaLah60WJTb6517nRbAKcbdBsTpmglqxQ9c827PUOUyiVEAu2o2cFEuOMw6Htvty4obOKBUgYi8EAgDA==} + '@tiptap/extension-ordered-list@3.31.3': + resolution: {integrity: sha512-mp3g11NgA/PYu8rj7J7Ez3l4qBy6WfTSmHIG4PZvEGG5w2oUAIkgb9DU7nPPzjmeme27oazFYZw+AtZA0+u4tw==} peerDependencies: - '@tiptap/core': ^3.20.2 - '@tiptap/pm': ^3.20.2 + '@tiptap/extension-list': 3.31.3 - '@tiptap/extension-ordered-list@3.20.2': - resolution: {integrity: sha512-UmPrnvd9/cGcO2QQaESu57kXmkubxmazQmUTgRU2BiLMEWGPPvxnBbJkM/YYmYPFRCs+OTx+XO9ohCD1xqtQcQ==} + '@tiptap/extension-paragraph@3.31.3': + resolution: {integrity: sha512-+iPku7wJfy5hbNDNLX8dveFtYVsZMmh7vztjuq8hT3mipSC4IByDehDbU8fzUCjfXiEzmI7mQn7c8LGmHULuzA==} peerDependencies: - '@tiptap/extension-list': ^3.20.2 + '@tiptap/core': 3.31.3 - '@tiptap/extension-paragraph@3.20.2': - resolution: {integrity: sha512-gTWAUmvCnv7OThFsYdyhacL4TM+sJMC/UeuW+drWaTBbo7dvejzkl4hF5B0ytmF3d/ko1GNr4ldTikYZ2xypMw==} + '@tiptap/extension-placeholder@3.31.3': + resolution: {integrity: sha512-9jYtR8ELEw7GVaruyrm4oFkPcjig9Q+crc+dpmarhBNXUmxagCdlhVzNwCJ2WJRzvBAtx59sEYqNTU38Wx8S3A==} peerDependencies: - '@tiptap/core': ^3.20.2 + '@tiptap/extensions': 3.31.3 - '@tiptap/extension-placeholder@3.20.2': - resolution: {integrity: sha512-QHjY44Hp4tJa1ouXf2LqHCUP+r6Md/xSRmwZ2utSTR3gD/lwe6nAFEfhu/rH+MvwKgIzvL87biOeqO3AlrJNGQ==} + '@tiptap/extension-strike@3.31.3': + resolution: {integrity: sha512-G29bhKttYwcKHT+BI6emWVFol3RO/gUXxQVcmr/iT8LXXy7j8J6HFUnsKM+Kg5YlP1rxMRgsa65dbrQVahZi0A==} peerDependencies: - '@tiptap/extensions': ^3.20.2 + '@tiptap/core': 3.31.3 - '@tiptap/extension-strike@3.20.2': - resolution: {integrity: sha512-Jivcc5Hgw2moIDfVoLEuJumDtw38k2mzEMYt3oZQnvE5d0ttXhWWR0LbLm5LBX3oxlc74I3NSi+Q4ixQHiDtvA==} + '@tiptap/extension-text@3.31.3': + resolution: {integrity: sha512-gdsWtF+taeaCu6V+5Ct10fGo0ACUy1GnYtbb+mcathBt8OqbT+Ws60p/yEmKesBDz2Hn+B5IcWy6+2BBZl5ZTg==} peerDependencies: - '@tiptap/core': ^3.20.2 + '@tiptap/core': 3.31.3 - '@tiptap/extension-text@3.20.2': - resolution: {integrity: sha512-I1rVt6JTi/itgsFqXp+JfxWn9fEewIxiIaaaMUmaCJ6HChQSvYlVWy1B/RixmbCCPaL/FxybEa/Tg9MugyOJYA==} + '@tiptap/extension-underline@3.30.4': + resolution: {integrity: sha512-h6nM3ykKswJLWvJVD1eiUFbanNmNj2SeV+2vuW666/xOy2WPyMnE2NZnsbvCKeK0wlUj7AE3l1m602mFwA4sDg==} peerDependencies: - '@tiptap/core': ^3.20.2 + '@tiptap/core': 3.30.4 - '@tiptap/extension-underline@3.20.2': - resolution: {integrity: sha512-oVszIGkRtg8NLhop/t5kco6suWlDUKW9cqhL6wwd19aLztr+tMU/u8+kPG2cjjYZ+XoMZOoKfkOt7he2iU5/0A==} + '@tiptap/extension-underline@3.31.3': + resolution: {integrity: sha512-HghdJaOwRqYzsAxqSyNyb+IWyOMcdCl8IoiBETA9BZCJAqdXzFLcuWp7CqCqJPam9dgkWosSoHqTCAO4nTBfpw==} peerDependencies: - '@tiptap/core': ^3.20.2 + '@tiptap/core': 3.31.3 - '@tiptap/extensions@3.20.2': - resolution: {integrity: sha512-gzntns6z/kTgwrX89ydc3rNqDsv8D8sAkyl8HE9X+2D9wtdCgNljevIR6MBNcxG7bVm2+XnId1P9YciCZLuefg==} + '@tiptap/extensions@3.31.3': + resolution: {integrity: sha512-8sJNPGGUe8f3aDojcOW5cfVL7I5NrBbE0UWxG08qoi9Tea6qWbvQJsCR9tsrOapr/DaLr3kpbGZ9s1gEEfcNcA==} peerDependencies: - '@tiptap/core': ^3.20.2 - '@tiptap/pm': ^3.20.2 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 - '@tiptap/pm@3.20.2': - resolution: {integrity: sha512-tEMZlLy/6ms41PQtyjmniZ3tTd8elavd8htjYzHLPSHtz11zaYV9YjnmnwHK8gynhcSES1orO9z1U4nT4ZLpqg==} + '@tiptap/pm@3.31.3': + resolution: {integrity: sha512-sZime0SWsz/k62W2WvHx5Ig7G2h7kVhrrmnqy+wEgIHfDwEfOlelRjaWCiBCFlF7dxGUntJusCh9FxlLhni0Ag==} - '@tiptap/react@3.20.2': - resolution: {integrity: sha512-eOfKkbaf9Qvia1xkjRXbJYy8FW7ampMkLt8yVcDhQf2fyip56sY+1ZuOoeXl+/lyDYNoXwoHJZrEcdseDPe0xw==} + '@tiptap/react@3.31.3': + resolution: {integrity: sha512-QiwQqvaLFLm5EMFu5tg7nAgXJxCUiUTLD8EsK+TqVV5P4bqOoMOCM39khbhXTJyahCuYpiFWx5YOSDtC/JiPtg==} peerDependencies: - '@tiptap/core': ^3.20.2 - '@tiptap/pm': ^3.20.2 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 '@types/react-dom': ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tiptap/starter-kit@3.20.2': - resolution: {integrity: sha512-QQ81QpwecXN3Rg0nWYC1nRCcWxlUtEua1X5j1NYUtY39SScuLbs3mMQ54P+u9ZeX31pzu/kuix5GQ0fw+SApOA==} + '@tiptap/starter-kit@3.31.3': + resolution: {integrity: sha512-WKof9RewdmGHvWJ1wn0/HVNG2mV+HOgVRyJkKekuM9fgr6BZAAH/xZsWE1eon+94JnQ+KtK2ThydXQM/qc6b2A==} '@ts-morph/common@0.27.0': resolution: {integrity: sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==} @@ -1930,23 +2002,28 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - body-parser@2.2.2: - resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + baseline-browser-mapping@2.11.21: + resolution: {integrity: sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + body-parser@2.3.0: + resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} engines: {node: '>=18'} - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + brace-expansion@1.1.18: + resolution: {integrity: sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==} - brace-expansion@5.0.4: - resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} - engines: {node: 18 || 20 || >=22} + brace-expansion@5.0.9: + resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==} + engines: {node: 20 || >=22} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + browserslist@4.28.7: + resolution: {integrity: sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -1980,6 +2057,9 @@ packages: caniuse-lite@1.0.30001778: resolution: {integrity: sha512-PN7uxFL+ExFJO61aVmP1aIEG4i9whQd4eoSCebav62UwDyp5OHh06zN4jqKSMePVgxHifCw1QJxdRkA1Pisekg==} + caniuse-lite@1.0.30001810: + resolution: {integrity: sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==} + ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -2077,6 +2157,10 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} + content-type@2.1.0: + resolution: {integrity: sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==} + engines: {node: '>=18'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -2413,8 +2497,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.313: - resolution: {integrity: sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA==} + electron-to-chromium@1.5.422: + resolution: {integrity: sha512-UvA/32XqrLDdZSn7Jllo1AYNcWji/G0d5M0GTViE7KoGBiMunw3a34Sb2KO4ZZyrSEhqsxFoVhWWJshdyfKqJA==} emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} @@ -2491,8 +2575,8 @@ packages: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} - eslint-config-next@16.1.6: - resolution: {integrity: sha512-vKq40io2B0XtkkNDYyleATwblNt8xuh3FWp8SpSz3pt7P01OkBFlKsJZ2mWt5WsCySlDQLckb1zMY9yE9Qy0LA==} + eslint-config-next@16.2.11: + resolution: {integrity: sha512-FIpbK/dUyxUExchDB7eBg3k+VU8R2iR/Cx9/kqTBUTFv2bOIR9aRrpno4rvAQ9VhiPQAyFKNA2NlZwouGWtclA==} peerDependencies: eslint: '>=9.0.0' typescript: '>=3.3.1' @@ -2677,8 +2761,8 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fast-uri@3.1.6: + resolution: {integrity: sha512-7Ical1vFEMr0onbVzEDIreM22I4khW+fzyQPwvAFWBp1iwdshSZRsL4jjRvPG9JP1uiqMHRto+YU6R2/CzDz5Q==} fastdom@1.0.12: resolution: {integrity: sha512-LB+xjSTEbjHE1cWsxu+tN2Xqr1kpi+V9aADI7sVM5ZMaXyYGPHULQMzpJMYqOTULK/73pUkWVzzObFRBkPr+hg==} @@ -2690,7 +2774,7 @@ packages: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} peerDependencies: - picomatch: ^3 || ^4 + picomatch: 4.0.4 peerDependenciesMeta: picomatch: optional: true @@ -2719,8 +2803,8 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - flatted@3.4.1: - resolution: {integrity: sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==} + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} for-each@0.3.5: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} @@ -2873,8 +2957,8 @@ packages: resolution: {integrity: sha512-oaXMACAU0kzOMXBjWpNcX+vlwSBCIAiZ9BHa7gA15NOTtT2L/l8OSZDuqS2XppOhZBPJ7hm4o8ep2kyuip2uEQ==} engines: {node: '>=12.0.0'} - hono@4.12.7: - resolution: {integrity: sha512-jq9l1DM0zVIvsm3lv9Nw9nlJnMNPOcAtsbsgiUhWcFzPE99Gvo6yRTlszSLLYacMeQ6quHD6hMfId8crVHvexw==} + hono@4.12.34: + resolution: {integrity: sha512-GqXJqY/xJkJmuloTrnV1ZEXG3fqte+VjkUqoRNZXcrUidiUOP4fMSIHHY4tsqZBK++kVyWmt/AAfSUuy57/eSA==} engines: {node: '>=16.9.0'} html-url-attributes@3.0.1: @@ -2908,8 +2992,8 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} - immutable@5.1.5: - resolution: {integrity: sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==} + immutable@5.1.8: + resolution: {integrity: sha512-TM5YqrGeTsVIPPpILzeqZ8D2Zc2TvNgSDi88zPF2a4cyqQdWV/wVWBDRDbNzzrLeRWScrFcOX9lW2iX6GOtUDw==} import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} @@ -2939,12 +3023,8 @@ packages: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} engines: {node: '>=12'} - ip-address@10.1.0: - resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} - engines: {node: '>= 12'} - - ip-address@10.5.0: - resolution: {integrity: sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==} + ip-address@10.3.1: + resolution: {integrity: sha512-1e9d3kb97NHJTIJDZW9rKqW2h6+dFa50Dy0fpPSMQp2ADje5gvKsXmdiK6dwY5t76TaTt5+P5N1Y/LoToIxP6g==} engines: {node: '>= 12'} ipaddr.js@1.9.1: @@ -3146,8 +3226,8 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + js-yaml@4.3.1: + resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==} hasBin: true jsesc@3.1.0: @@ -3301,11 +3381,11 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - linkify-it@5.0.0: - resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + linkify-it@5.0.2: + resolution: {integrity: sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==} - linkifyjs@4.3.2: - resolution: {integrity: sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==} + linkifyjs@4.3.3: + resolution: {integrity: sha512-P8aEP5U/D1/IlTY2OeYsErdwh9bGuLE30NcXtKEjgdHcahveQoQwM2yZNsioQHsWFz0P7KKudisbrzCgR0sDHg==} locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} @@ -3317,8 +3397,9 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash@4.17.23: - resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} + lodash@4.18.0: + resolution: {integrity: sha512-l1mfj2atMqndAHI3ls7XqPxEjV2J9ZkcNyHpoZA3r2T1LLwDB69jgkMWh71YKwhBbK0G2f4WSn05ahmQXVxupA==} + deprecated: Bad release. Please use lodash@4.17.21 instead. log-symbols@6.0.0: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} @@ -3366,8 +3447,8 @@ packages: markdown-it-sup@2.0.0: resolution: {integrity: sha512-5VgmdKlkBd8sgXuoDoxMpiU+BiEt3I49GItBzzw7Mxq9CxvnhE/k09HFli09zgfFDRixDQDfDxi0mgBCXtaTvA==} - markdown-it@14.1.1: - resolution: {integrity: sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==} + markdown-it@14.3.1: + resolution: {integrity: sha512-4Ej49aYTDFIQ+uBkfX8GBvJGccoARxxPep+7aWTs55ozbjQJpW9M26Fe53vnGgvLeVzva/amzjQQaQu9w0vMhA==} hasBin: true markdown-table@3.0.4: @@ -3577,8 +3658,8 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + nanoid@3.3.18: + resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -3600,8 +3681,8 @@ packages: react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - next@16.1.6: - resolution: {integrity: sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==} + next@16.2.11: + resolution: {integrity: sha512-B339zaqbyK8cmxhoAvLrcwoabwCP1wz21zSzfqxqXAemTu2BXnH7tQnfcglKv1vnMUIDBc+Hth7XODQriTZiRQ==} engines: {node: '>=20.9.0'} hasBin: true peerDependencies: @@ -3628,8 +3709,9 @@ packages: resolution: {integrity: sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==} engines: {node: '>= 0.4'} - node-releases@2.0.36: - resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} + node-releases@2.0.54: + resolution: {integrity: sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==} + engines: {node: '>=18'} npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} @@ -3760,18 +3842,18 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-to-regexp@8.3.0: - resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + path-to-regexp@8.4.0: + resolution: {integrity: sha512-PuseHIvAnz3bjrM2rGJtSgo1zjgxapTLZ7x2pjhzWwlp4SJQgK3f3iZIQwkpEnBaKz6seKBADpM4B4ySkuYypg==} picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} pkce-challenge@5.0.1: @@ -3788,16 +3870,12 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} - postcss-selector-parser@7.1.1: - resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + postcss-selector-parser@7.1.3: + resolution: {integrity: sha512-ajnd7iZnqjJDkyHNfznl/ZVO0lWqvBmQXfKKENx9/p/bEiF/L3eHwdydNUg9RXZx6xfZWOCmXmBa5oeB+YrAPQ==} engines: {node: '>=4'} - postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} - engines: {node: ^10 || ^12 || >=14} - - postcss@8.5.8: - resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + postcss@8.5.23: + resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} engines: {node: ^10 || ^12 || >=14} powershell-utils@0.1.0: @@ -3822,11 +3900,8 @@ packages: property-information@7.2.0: resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} - prosemirror-changeset@2.4.0: - resolution: {integrity: sha512-LvqH2v7Q2SF6yxatuPP2e8vSUKS/L+xAU7dPDC4RMyHMhZoGDfBC74mYuyYF4gLqOEG758wajtyhNnsTkuhvng==} - - prosemirror-collab@1.3.1: - resolution: {integrity: sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==} + prosemirror-changeset@2.4.2: + resolution: {integrity: sha512-ViYrjMSg3YFiXwIhKaluu+/mi3Yrxt6AR8ri14ulTaGcZtXO1CThl7A2gv79qx5fQnOw8woKwyBU2u+9PVCm3w==} prosemirror-commands@1.7.1: resolution: {integrity: sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==} @@ -3846,18 +3921,12 @@ packages: prosemirror-keymap@1.2.3: resolution: {integrity: sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==} - prosemirror-markdown@1.13.4: - resolution: {integrity: sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw==} - - prosemirror-menu@1.3.0: - resolution: {integrity: sha512-TImyPXCHPcDsSka2/lwJ6WjTASr4re/qWq1yoTTuLOqfXucwF6VcRa2LWCkM/EyTD1UO3CUwiH8qURJoWJRxwg==} + prosemirror-model@1.25.11: + resolution: {integrity: sha512-QWg9RhnpLlogAmp3p96uEFrE5txQpFynd4vhBAELkwgOCWQs/X0yCzB3/hrHqiPwf91RG5KyWq6553zs9JqIOQ==} prosemirror-model@1.25.4: resolution: {integrity: sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==} - prosemirror-schema-basic@1.2.4: - resolution: {integrity: sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==} - prosemirror-schema-list@1.5.1: resolution: {integrity: sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==} @@ -3867,19 +3936,18 @@ packages: prosemirror-tables@1.8.5: resolution: {integrity: sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==} - prosemirror-trailing-node@3.0.0: - resolution: {integrity: sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==} - peerDependencies: - prosemirror-model: ^1.22.1 - prosemirror-state: ^1.4.2 - prosemirror-view: ^1.33.8 - prosemirror-transform@1.11.0: resolution: {integrity: sha512-4I7Ce4KpygXb9bkiPS3hTEk4dSHorfRw8uI0pE8IhxlK2GXsqv5tIA7JUSxtSu7u8APVOTtbUBxTmnHIxVkIJw==} + prosemirror-transform@1.12.1: + resolution: {integrity: sha512-t4F5615FycnCqsX7ShTUs8+jfnwcf46kuFRvSl/3qFx2QTZ4DjgowesLHQXcFP7G//TjesqZG3WtgL7vdyVJyA==} + prosemirror-view@1.41.6: resolution: {integrity: sha512-mxpcDG4hNQa/CPtzxjdlir5bJFDlm0/x5nGBbStB2BWX+XOQ9M8ekEG+ojqB5BcVu2Rc80/jssCMZzSstJuSYg==} + prosemirror-view@1.42.3: + resolution: {integrity: sha512-oTN7EtH+CpwxU9NrwEYWd0UZ4JUx7l048l5A2Xppm4p/60isZYLnth9QVQmC3VRIvdrIWCxwZSd+Uz791G31/w==} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -3892,8 +3960,8 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - qs@6.15.0: - resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} + qs@6.16.0: + resolution: {integrity: sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==} engines: {node: '>=0.6'} queue-microtask@1.2.3: @@ -4127,6 +4195,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + send@1.2.1: resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} @@ -4155,9 +4228,9 @@ packages: engines: {node: '>=20.18.1'} hasBin: true - sharp@0.34.5: - resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + sharp@0.35.0: + resolution: {integrity: sha512-BqvG5XbwPZ4NV0DK90d86leEECMsoa8bO0nqnKWlBDYxri4GJ7c4EDInaF6q20lTh/mATmnDIKWJFfXnoVfH5g==} + engines: {node: '>=20.9.0'} shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -4171,6 +4244,10 @@ packages: resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + side-channel-map@1.0.1: resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} engines: {node: '>= 0.4'} @@ -4183,6 +4260,10 @@ packages: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} + engines: {node: '>= 0.4'} + signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -4406,6 +4487,10 @@ packages: resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} engines: {node: '>= 0.6'} + type-is@2.1.0: + resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} + engines: {node: '>= 18'} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -4488,7 +4573,7 @@ packages: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: - browserslist: '>= 4.21.0' + browserslist: 4.28.7 uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -4521,8 +4606,8 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - uuid@14.0.2: - resolution: {integrity: sha512-xZe/16rV4aa+HGSOCiY2YeLT1OybRLrrkL/Rqaq7p7GMVXjFh+6wN4oMYgjFmnSnhY8t6Xpdl2l9qmnHYuMHwQ==} + uuid@11.1.1: + resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==} hasBin: true validate-npm-package-name@7.0.2: @@ -4657,22 +4742,28 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + '@babel/compat-data@7.29.0': {} - '@babel/core@7.29.0': + '@babel/core@7.29.6(supports-color@7.2.0)': dependencies: '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 + '@babel/generator': 7.29.8 '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.28.6 - '@babel/parser': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.6(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.8 '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) '@babel/types': 7.29.0 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -4687,6 +4778,14 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 + '@babel/generator@7.29.8': + dependencies: + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + '@babel/helper-annotate-as-pure@7.27.3': dependencies: '@babel/types': 7.29.0 @@ -4695,45 +4794,45 @@ snapshots: dependencies: '@babel/compat-data': 7.29.0 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 + browserslist: 4.28.7 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0)': + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.6(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.6(supports-color@7.2.0) '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-member-expression-to-functions': 7.28.5(supports-color@7.2.0) '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.29.0 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.6(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@7.2.0) + '@babel/traverse': 7.29.0(supports-color@7.2.0) semver: 6.3.1 transitivePeerDependencies: - supports-color '@babel/helper-globals@7.28.0': {} - '@babel/helper-member-expression-to-functions@7.28.5': + '@babel/helper-member-expression-to-functions@7.28.5(supports-color@7.2.0)': dependencies: - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-imports@7.28.6': + '@babel/helper-module-imports@7.28.6(supports-color@7.2.0)': dependencies: - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.6(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 + '@babel/core': 7.29.6(supports-color@7.2.0) + '@babel/helper-module-imports': 7.28.6(supports-color@7.2.0) '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -4743,74 +4842,82 @@ snapshots: '@babel/helper-plugin-utils@7.28.6': {} - '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': + '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.6(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/core': 7.29.6(supports-color@7.2.0) + '@babel/helper-member-expression-to-functions': 7.28.5(supports-color@7.2.0) '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + '@babel/helper-skip-transparent-expression-wrappers@7.27.1(supports-color@7.2.0)': dependencies: - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-string-parser@7.29.7': {} + '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-identifier@7.29.7': {} + '@babel/helper-validator-option@7.27.1': {} - '@babel/helpers@7.28.6': + '@babel/helpers@7.29.7': dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 '@babel/parser@7.29.0': dependencies: '@babel/types': 7.29.0 - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + '@babel/parser@7.29.8': + dependencies: + '@babel/types': 7.29.8 + + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.6(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.6(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.6(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.6(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.6(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/core': 7.29.6(supports-color@7.2.0) + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.6(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.6(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.6(supports-color@7.2.0) '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.6(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@7.2.0) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.6(supports-color@7.2.0)) transitivePeerDependencies: - supports-color - '@babel/preset-typescript@7.28.5(@babel/core@7.29.0)': + '@babel/preset-typescript@7.28.5(@babel/core@7.29.6(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.6(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.6(supports-color@7.2.0)) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.6(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.6(supports-color@7.2.0))(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -4822,7 +4929,13 @@ snapshots: '@babel/parser': 7.29.0 '@babel/types': 7.29.0 - '@babel/traverse@7.29.0': + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + + '@babel/traverse@7.29.0(supports-color@7.2.0)': dependencies: '@babel/code-frame': 7.29.0 '@babel/generator': 7.29.1 @@ -4830,7 +4943,7 @@ snapshots: '@babel/parser': 7.29.0 '@babel/template': 7.28.6 '@babel/types': 7.29.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -4839,6 +4952,11 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@babel/types@7.29.8': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@base-ui/react@1.3.0(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@babel/runtime': 7.28.6 @@ -5155,10 +5273,10 @@ snapshots: dotenv: 17.3.1 eciesjs: 0.4.18 execa: 5.1.1 - fdir: 6.5.0(picomatch@4.0.3) + fdir: 6.5.0(picomatch@4.0.4) ignore: 5.3.2 object-treeify: 1.1.33 - picomatch: 4.0.3 + picomatch: 4.0.4 which: 4.0.0 '@ecies/ciphers@0.2.5(@noble/ciphers@1.3.0)': @@ -5171,6 +5289,11 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/runtime@1.11.3': + dependencies: + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.9.0': dependencies: tslib: 2.8.1 @@ -5181,17 +5304,17 @@ snapshots: tslib: 2.8.1 optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))': dependencies: - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.6.1)(supports-color@7.2.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.21.2': + '@eslint/config-array@0.21.2(supports-color@7.2.0)': dependencies: '@eslint/object-schema': 2.1.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) minimatch: 3.1.5 transitivePeerDependencies: - supports-color @@ -5204,15 +5327,15 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.5': + '@eslint/eslintrc@3.3.5(supports-color@7.2.0)': dependencies: ajv: 6.14.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 - js-yaml: 4.1.1 + js-yaml: 4.3.1 minimatch: 3.1.5 strip-json-comments: 3.1.1 transitivePeerDependencies: @@ -5244,22 +5367,27 @@ snapshots: '@floating-ui/utils@0.2.11': {} - '@hono/node-server@1.19.11(hono@4.12.7)': + '@hono/node-server@1.19.15(hono@4.12.34)': dependencies: - hono: 4.12.7 + hono: 4.12.34 '@hookform/resolvers@5.2.2(react-hook-form@7.71.2(react@19.2.3))': dependencies: '@standard-schema/utils': 0.3.0 react-hook-form: 7.71.2(react@19.2.3) - '@humanfs/core@0.19.1': {} + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 - '@humanfs/node@0.16.7': + '@humanfs/node@0.16.8': dependencies: - '@humanfs/core': 0.19.1 + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 '@humanwhocodes/retry': 0.4.3 + '@humanfs/types@0.15.0': {} + '@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/retry@0.4.3': {} @@ -5275,98 +5403,108 @@ snapshots: '@img/colour@1.1.0': optional: true - '@img/sharp-darwin-arm64@0.34.5': + '@img/sharp-darwin-arm64@0.35.0': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-arm64': 1.3.0 optional: true - '@img/sharp-darwin-x64@0.34.5': + '@img/sharp-darwin-x64@0.35.0': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.3.0 + optional: true + + '@img/sharp-freebsd-wasm32@0.35.0': + dependencies: + '@img/sharp-wasm32': 0.35.0 optional: true - '@img/sharp-libvips-darwin-arm64@1.2.4': + '@img/sharp-libvips-darwin-arm64@1.3.0': optional: true - '@img/sharp-libvips-darwin-x64@1.2.4': + '@img/sharp-libvips-darwin-x64@1.3.0': optional: true - '@img/sharp-libvips-linux-arm64@1.2.4': + '@img/sharp-libvips-linux-arm64@1.3.0': optional: true - '@img/sharp-libvips-linux-arm@1.2.4': + '@img/sharp-libvips-linux-arm@1.3.0': optional: true - '@img/sharp-libvips-linux-ppc64@1.2.4': + '@img/sharp-libvips-linux-ppc64@1.3.0': optional: true - '@img/sharp-libvips-linux-riscv64@1.2.4': + '@img/sharp-libvips-linux-riscv64@1.3.0': optional: true - '@img/sharp-libvips-linux-s390x@1.2.4': + '@img/sharp-libvips-linux-s390x@1.3.0': optional: true - '@img/sharp-libvips-linux-x64@1.2.4': + '@img/sharp-libvips-linux-x64@1.3.0': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + '@img/sharp-libvips-linuxmusl-arm64@1.3.0': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.2.4': + '@img/sharp-libvips-linuxmusl-x64@1.3.0': optional: true - '@img/sharp-linux-arm64@0.34.5': + '@img/sharp-linux-arm64@0.35.0': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.3.0 optional: true - '@img/sharp-linux-arm@0.34.5': + '@img/sharp-linux-arm@0.35.0': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.3.0 optional: true - '@img/sharp-linux-ppc64@0.34.5': + '@img/sharp-linux-ppc64@0.35.0': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.3.0 optional: true - '@img/sharp-linux-riscv64@0.34.5': + '@img/sharp-linux-riscv64@0.35.0': optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.3.0 optional: true - '@img/sharp-linux-s390x@0.34.5': + '@img/sharp-linux-s390x@0.35.0': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.3.0 optional: true - '@img/sharp-linux-x64@0.34.5': + '@img/sharp-linux-x64@0.35.0': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.3.0 optional: true - '@img/sharp-linuxmusl-arm64@0.34.5': + '@img/sharp-linuxmusl-arm64@0.35.0': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.0 optional: true - '@img/sharp-linuxmusl-x64@0.34.5': + '@img/sharp-linuxmusl-x64@0.35.0': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.0 optional: true - '@img/sharp-wasm32@0.34.5': + '@img/sharp-wasm32@0.35.0': dependencies: - '@emnapi/runtime': 1.9.0 + '@emnapi/runtime': 1.11.3 + optional: true + + '@img/sharp-webcontainers-wasm32@0.35.0': + dependencies: + '@img/sharp-wasm32': 0.35.0 optional: true - '@img/sharp-win32-arm64@0.34.5': + '@img/sharp-win32-arm64@0.35.0': optional: true - '@img/sharp-win32-ia32@0.34.5': + '@img/sharp-win32-ia32@0.35.0': optional: true - '@img/sharp-win32-x64@0.34.5': + '@img/sharp-win32-x64@0.35.0': optional: true '@jridgewell/gen-mapping@0.3.13': @@ -5494,9 +5632,9 @@ snapshots: '@mixmark-io/domino@2.2.0': {} - '@modelcontextprotocol/sdk@1.27.1(zod@3.25.76)': + '@modelcontextprotocol/sdk@1.27.1(supports-color@7.2.0)(zod@3.25.76)': dependencies: - '@hono/node-server': 1.19.11(hono@4.12.7) + '@hono/node-server': 1.19.15(hono@4.12.34) ajv: 8.18.0 ajv-formats: 3.0.1(ajv@8.18.0) content-type: 1.0.5 @@ -5504,9 +5642,9 @@ snapshots: cross-spawn: 7.0.6 eventsource: 3.0.7 eventsource-parser: 3.0.6 - express: 5.2.1 - express-rate-limit: 8.3.1(express@5.2.1) - hono: 4.12.7 + express: 5.2.1(supports-color@7.2.0) + express-rate-limit: 8.3.1(express@5.2.1(supports-color@7.2.0)) + hono: 4.12.34 jose: 6.2.3 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 @@ -5523,34 +5661,34 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true - '@next/env@16.1.6': {} + '@next/env@16.2.11': {} - '@next/eslint-plugin-next@16.1.6': + '@next/eslint-plugin-next@16.2.11': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@16.1.6': + '@next/swc-darwin-arm64@16.2.11': optional: true - '@next/swc-darwin-x64@16.1.6': + '@next/swc-darwin-x64@16.2.11': optional: true - '@next/swc-linux-arm64-gnu@16.1.6': + '@next/swc-linux-arm64-gnu@16.2.11': optional: true - '@next/swc-linux-arm64-musl@16.1.6': + '@next/swc-linux-arm64-musl@16.2.11': optional: true - '@next/swc-linux-x64-gnu@16.1.6': + '@next/swc-linux-x64-gnu@16.2.11': optional: true - '@next/swc-linux-x64-musl@16.1.6': + '@next/swc-linux-x64-musl@16.2.11': optional: true - '@next/swc-win32-arm64-msvc@16.1.6': + '@next/swc-win32-arm64-msvc@16.2.11': optional: true - '@next/swc-win32-x64-msvc@16.1.6': + '@next/swc-win32-x64-msvc@16.2.11': optional: true '@noble/ciphers@1.3.0': {} @@ -5619,7 +5757,7 @@ snapshots: detect-libc: 2.1.2 is-glob: 4.0.3 node-addon-api: 7.1.1 - picomatch: 4.0.3 + picomatch: 4.0.4 optionalDependencies: '@parcel/watcher-android-arm64': 2.5.6 '@parcel/watcher-darwin-arm64': 2.5.6 @@ -5779,8 +5917,6 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 - '@remirror/core-constants@3.0.0': {} - '@rtsao/scc@1.1.0': {} '@sec-ant/readable-stream@0.4.1': {} @@ -5866,7 +6002,7 @@ snapshots: '@alloc/quick-lru': 5.2.0 '@tailwindcss/node': 4.2.1 '@tailwindcss/oxide': 4.2.1 - postcss: 8.5.8 + postcss: 8.5.23 tailwindcss: 4.2.1 '@tanstack/react-table@8.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': @@ -5877,157 +6013,151 @@ snapshots: '@tanstack/table-core@8.21.3': {} - '@tiptap/core@3.20.2(@tiptap/pm@3.20.2)': + '@tiptap/core@3.31.3(@tiptap/pm@3.31.3)': dependencies: - '@tiptap/pm': 3.20.2 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-blockquote@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))': + '@tiptap/extension-blockquote@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 - '@tiptap/extension-bold@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))': + '@tiptap/extension-bold@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-bubble-menu@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2)': + '@tiptap/extension-bubble-menu@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: '@floating-ui/dom': 1.7.6 - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) - '@tiptap/pm': 3.20.2 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 optional: true - '@tiptap/extension-bullet-list@3.20.2(@tiptap/extension-list@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2))': + '@tiptap/extension-bullet-list@3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extension-list': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2) + '@tiptap/extension-list': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-code-block@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2)': + '@tiptap/extension-code-block@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) - '@tiptap/pm': 3.20.2 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 - '@tiptap/extension-code@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))': + '@tiptap/extension-code@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-document@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))': + '@tiptap/extension-document@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-dropcursor@3.20.2(@tiptap/extensions@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2))': + '@tiptap/extension-dropcursor@3.31.3(@tiptap/extensions@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extensions': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2) + '@tiptap/extensions': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-floating-menu@3.20.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2)': + '@tiptap/extension-floating-menu@3.31.3(@floating-ui/dom@1.7.6)(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: '@floating-ui/dom': 1.7.6 - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) - '@tiptap/pm': 3.20.2 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 optional: true - '@tiptap/extension-gapcursor@3.20.2(@tiptap/extensions@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2))': + '@tiptap/extension-gapcursor@3.31.3(@tiptap/extensions@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extensions': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2) + '@tiptap/extensions': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-hard-break@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))': + '@tiptap/extension-hard-break@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-heading@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))': + '@tiptap/extension-heading@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-horizontal-rule@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2)': + '@tiptap/extension-horizontal-rule@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) - '@tiptap/pm': 3.20.2 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 - '@tiptap/extension-image@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))': + '@tiptap/extension-image@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-italic@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))': + '@tiptap/extension-italic@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-link@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2)': + '@tiptap/extension-link@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) - '@tiptap/pm': 3.20.2 - linkifyjs: 4.3.2 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 + linkifyjs: 4.3.3 - '@tiptap/extension-link@3.22.0(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2)': + '@tiptap/extension-list-item@3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) - '@tiptap/pm': 3.20.2 - linkifyjs: 4.3.2 + '@tiptap/extension-list': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-list-item@3.20.2(@tiptap/extension-list@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2))': + '@tiptap/extension-list-keymap@3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extension-list': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2) + '@tiptap/extension-list': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-list-keymap@3.20.2(@tiptap/extension-list@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2))': + '@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: - '@tiptap/extension-list': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 - '@tiptap/extension-list@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2)': + '@tiptap/extension-ordered-list@3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) - '@tiptap/pm': 3.20.2 + '@tiptap/extension-list': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-ordered-list@3.20.2(@tiptap/extension-list@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2))': + '@tiptap/extension-paragraph@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extension-list': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-paragraph@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))': + '@tiptap/extension-placeholder@3.31.3(@tiptap/extensions@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) + '@tiptap/extensions': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-placeholder@3.20.2(@tiptap/extensions@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2))': + '@tiptap/extension-strike@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extensions': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-strike@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))': + '@tiptap/extension-text@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-text@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))': + '@tiptap/extension-underline@3.30.4(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-underline@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))': + '@tiptap/extension-underline@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extensions@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2)': + '@tiptap/extensions@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) - '@tiptap/pm': 3.20.2 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 - '@tiptap/pm@3.20.2': + '@tiptap/pm@3.31.3': dependencies: - prosemirror-changeset: 2.4.0 - prosemirror-collab: 1.3.1 + prosemirror-changeset: 2.4.2 prosemirror-commands: 1.7.1 prosemirror-dropcursor: 1.8.2 prosemirror-gapcursor: 1.4.1 prosemirror-history: 1.5.0 prosemirror-inputrules: 1.5.1 prosemirror-keymap: 1.2.3 - prosemirror-markdown: 1.13.4 - prosemirror-menu: 1.3.0 - prosemirror-model: 1.25.4 - prosemirror-schema-basic: 1.2.4 + prosemirror-model: 1.25.11 prosemirror-schema-list: 1.5.1 prosemirror-state: 1.4.4 prosemirror-tables: 1.8.5 - prosemirror-trailing-node: 3.0.0(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6) - prosemirror-transform: 1.11.0 - prosemirror-view: 1.41.6 + prosemirror-transform: 1.12.1 + prosemirror-view: 1.42.3 - '@tiptap/react@3.20.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@tiptap/react@3.31.3(@floating-ui/dom@1.7.6)(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) - '@tiptap/pm': 3.20.2 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) '@types/use-sync-external-store': 0.0.6 @@ -6036,37 +6166,37 @@ snapshots: react-dom: 19.2.3(react@19.2.3) use-sync-external-store: 1.6.0(react@19.2.3) optionalDependencies: - '@tiptap/extension-bubble-menu': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2) - '@tiptap/extension-floating-menu': 3.20.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2) + '@tiptap/extension-bubble-menu': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) + '@tiptap/extension-floating-menu': 3.31.3(@floating-ui/dom@1.7.6)(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) transitivePeerDependencies: - '@floating-ui/dom' - '@tiptap/starter-kit@3.20.2': - dependencies: - '@tiptap/core': 3.20.2(@tiptap/pm@3.20.2) - '@tiptap/extension-blockquote': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2)) - '@tiptap/extension-bold': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2)) - '@tiptap/extension-bullet-list': 3.20.2(@tiptap/extension-list@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2)) - '@tiptap/extension-code': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2)) - '@tiptap/extension-code-block': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2) - '@tiptap/extension-document': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2)) - '@tiptap/extension-dropcursor': 3.20.2(@tiptap/extensions@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2)) - '@tiptap/extension-gapcursor': 3.20.2(@tiptap/extensions@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2)) - '@tiptap/extension-hard-break': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2)) - '@tiptap/extension-heading': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2)) - '@tiptap/extension-horizontal-rule': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2) - '@tiptap/extension-italic': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2)) - '@tiptap/extension-link': 3.22.0(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2) - '@tiptap/extension-list': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2) - '@tiptap/extension-list-item': 3.20.2(@tiptap/extension-list@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2)) - '@tiptap/extension-list-keymap': 3.20.2(@tiptap/extension-list@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2)) - '@tiptap/extension-ordered-list': 3.20.2(@tiptap/extension-list@3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2)) - '@tiptap/extension-paragraph': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2)) - '@tiptap/extension-strike': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2)) - '@tiptap/extension-text': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2)) - '@tiptap/extension-underline': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2)) - '@tiptap/extensions': 3.20.2(@tiptap/core@3.20.2(@tiptap/pm@3.20.2))(@tiptap/pm@3.20.2) - '@tiptap/pm': 3.20.2 + '@tiptap/starter-kit@3.31.3': + dependencies: + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/extension-blockquote': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) + '@tiptap/extension-bold': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-bullet-list': 3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) + '@tiptap/extension-code': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-code-block': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) + '@tiptap/extension-document': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-dropcursor': 3.31.3(@tiptap/extensions@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) + '@tiptap/extension-gapcursor': 3.31.3(@tiptap/extensions@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) + '@tiptap/extension-hard-break': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-heading': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-horizontal-rule': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) + '@tiptap/extension-italic': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-link': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) + '@tiptap/extension-list': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) + '@tiptap/extension-list-item': 3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) + '@tiptap/extension-list-keymap': 3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) + '@tiptap/extension-ordered-list': 3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) + '@tiptap/extension-paragraph': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-strike': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-text': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-underline': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extensions': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 '@ts-morph/common@0.27.0': dependencies: @@ -6256,15 +6386,15 @@ snapshots: '@types/validate-npm-package-name@4.0.2': {} - '@typescript-eslint/eslint-plugin@8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3)': + '@typescript-eslint/eslint-plugin@8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/scope-manager': 8.57.0 - '@typescript-eslint/type-utils': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) - '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/type-utils': 8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.57.0 - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.6.1)(supports-color@7.2.0) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.4.0(typescript@6.0.3) @@ -6272,23 +6402,23 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3)': + '@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.57.0 '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/typescript-estree': 8.57.0(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.57.0(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.57.0 - debug: 4.4.3 - eslint: 9.39.4(jiti@2.6.1) + debug: 4.4.3(supports-color@7.2.0) + eslint: 9.39.4(jiti@2.6.1)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.57.0(typescript@6.0.3)': + '@typescript-eslint/project-service@8.57.0(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@6.0.3) '@typescript-eslint/types': 8.57.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -6302,13 +6432,13 @@ snapshots: dependencies: typescript: 6.0.3 - '@typescript-eslint/type-utils@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/typescript-estree': 8.57.0(typescript@6.0.3) - '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) - debug: 4.4.3 - eslint: 9.39.4(jiti@2.6.1) + '@typescript-eslint/typescript-estree': 8.57.0(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + debug: 4.4.3(supports-color@7.2.0) + eslint: 9.39.4(jiti@2.6.1)(supports-color@7.2.0) ts-api-utils: 2.4.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: @@ -6316,13 +6446,13 @@ snapshots: '@typescript-eslint/types@8.57.0': {} - '@typescript-eslint/typescript-estree@8.57.0(typescript@6.0.3)': + '@typescript-eslint/typescript-estree@8.57.0(supports-color@7.2.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.57.0(typescript@6.0.3) + '@typescript-eslint/project-service': 8.57.0(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@6.0.3) '@typescript-eslint/types': 8.57.0 '@typescript-eslint/visitor-keys': 8.57.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) minimatch: 10.2.4 semver: 7.7.4 tinyglobby: 0.2.15 @@ -6331,13 +6461,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3)': + '@typescript-eslint/utils@8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0)) '@typescript-eslint/scope-manager': 8.57.0 '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/typescript-estree': 8.57.0(typescript@6.0.3) - eslint: 9.39.4(jiti@2.6.1) + '@typescript-eslint/typescript-estree': 8.57.0(supports-color@7.2.0)(typescript@6.0.3) + eslint: 9.39.4(jiti@2.6.1)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -6448,7 +6578,7 @@ snapshots: ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 + fast-uri: 3.1.6 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -6557,26 +6687,28 @@ snapshots: baseline-browser-mapping@2.10.7: {} - body-parser@2.2.2: + baseline-browser-mapping@2.11.21: {} + + body-parser@2.3.0(supports-color@7.2.0): dependencies: bytes: 3.1.2 - content-type: 1.0.5 - debug: 4.4.3 + content-type: 2.1.0 + debug: 4.4.3(supports-color@7.2.0) http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 - qs: 6.15.0 + qs: 6.16.0 raw-body: 3.0.2 - type-is: 2.0.1 + type-is: 2.1.0 transitivePeerDependencies: - supports-color - brace-expansion@1.1.12: + brace-expansion@1.1.18: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@5.0.4: + brace-expansion@5.0.9: dependencies: balanced-match: 4.0.4 @@ -6584,13 +6716,13 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.28.1: + browserslist@4.28.7: dependencies: - baseline-browser-mapping: 2.10.7 - caniuse-lite: 1.0.30001778 - electron-to-chromium: 1.5.313 - node-releases: 2.0.36 - update-browserslist-db: 1.2.3(browserslist@4.28.1) + baseline-browser-mapping: 2.11.21 + caniuse-lite: 1.0.30001810 + electron-to-chromium: 1.5.422 + node-releases: 2.0.54 + update-browserslist-db: 1.2.3(browserslist@4.28.7) buffer-from@1.1.2: {} @@ -6621,6 +6753,8 @@ snapshots: caniuse-lite@1.0.30001778: {} + caniuse-lite@1.0.30001810: {} + ccount@2.0.1: {} chalk@4.1.2: @@ -6704,6 +6838,8 @@ snapshots: content-type@1.0.5: {} + content-type@2.1.0: {} + convert-source-map@2.0.0: {} cookie-signature@1.2.2: {} @@ -6727,7 +6863,7 @@ snapshots: dependencies: env-paths: 2.2.1 import-fresh: 3.3.1 - js-yaml: 4.1.1 + js-yaml: 4.3.1 parse-json: 5.2.0 optionalDependencies: typescript: 6.0.3 @@ -6956,13 +7092,17 @@ snapshots: dayjs@1.11.23: {} - debug@3.2.7: + debug@3.2.7(supports-color@7.2.0): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 7.2.0 - debug@4.4.3: + debug@4.4.3(supports-color@7.2.0): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 7.2.0 decimal.js-light@2.5.1: {} @@ -7045,7 +7185,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.313: {} + electron-to-chromium@1.5.422: {} emoji-regex@10.6.0: {} @@ -7178,18 +7318,18 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-next@16.1.6(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3): + eslint-config-next@16.2.11(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3): dependencies: - '@next/eslint-plugin-next': 16.1.6 - eslint: 9.39.4(jiti@2.6.1) - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-react-hooks: 7.0.1(eslint@9.39.4(jiti@2.6.1)) + '@next/eslint-plugin-next': 16.2.11 + eslint: 9.39.4(jiti@2.6.1)(supports-color@7.2.0) + eslint-import-resolver-node: 0.3.9(supports-color@7.2.0) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0)) + eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0)) + eslint-plugin-react-hooks: 7.0.1(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0) globals: 16.4.0 - typescript-eslint: 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) + typescript-eslint: 8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) optionalDependencies: typescript: 6.0.3 transitivePeerDependencies: @@ -7198,52 +7338,52 @@ snapshots: - eslint-plugin-import-x - supports-color - eslint-import-resolver-node@0.3.9: + eslint-import-resolver-node@0.3.9(supports-color@7.2.0): dependencies: - debug: 3.2.7 + debug: 3.2.7(supports-color@7.2.0) is-core-module: 2.16.1 resolve: 1.22.11 transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.6.1)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0): dependencies: '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.3 - eslint: 9.39.4(jiti@2.6.1) + debug: 4.4.3(supports-color@7.2.0) + eslint: 9.39.4(jiti@2.6.1)(supports-color@7.2.0) get-tsconfig: 4.13.6 is-bun-module: 2.0.0 stable-hash: 0.0.5 tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.9(supports-color@7.2.0))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0): dependencies: - debug: 3.2.7 + debug: 3.2.7(supports-color@7.2.0) optionalDependencies: - '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) - eslint: 9.39.4(jiti@2.6.1) - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.6.1)) + '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + eslint: 9.39.4(jiti@2.6.1)(supports-color@7.2.0) + eslint-import-resolver-node: 0.3.9(supports-color@7.2.0) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 array.prototype.findlastindex: 1.2.6 array.prototype.flat: 1.3.3 array.prototype.flatmap: 1.3.3 - debug: 3.2.7 + debug: 3.2.7(supports-color@7.2.0) doctrine: 2.1.0 - eslint: 9.39.4(jiti@2.6.1) - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)) + eslint: 9.39.4(jiti@2.6.1)(supports-color@7.2.0) + eslint-import-resolver-node: 0.3.9(supports-color@7.2.0) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.9(supports-color@7.2.0))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -7255,13 +7395,13 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0)): dependencies: aria-query: 5.3.2 array-includes: 3.1.9 @@ -7271,7 +7411,7 @@ snapshots: axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.6.1)(supports-color@7.2.0) hasown: 2.0.2 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 @@ -7280,18 +7420,18 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 - eslint-plugin-react-hooks@7.0.1(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-react-hooks@7.0.1(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0): dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.6(supports-color@7.2.0) '@babel/parser': 7.29.0 - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.6.1)(supports-color@7.2.0) hermes-parser: 0.25.1 zod: 4.3.6 zod-validation-error: 4.0.2(zod@4.3.6) transitivePeerDependencies: - supports-color - eslint-plugin-react@7.37.5(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-react@7.37.5(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0)): dependencies: array-includes: 3.1.9 array.prototype.findlast: 1.2.5 @@ -7299,7 +7439,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.3.1 - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.6.1)(supports-color@7.2.0) estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -7324,24 +7464,24 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@9.39.4(jiti@2.6.1): + eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.2 + '@eslint/config-array': 0.21.2(supports-color@7.2.0) '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.5 + '@eslint/eslintrc': 3.3.5(supports-color@7.2.0) '@eslint/js': 9.39.4 '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.7 + '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 '@types/estree': 1.0.8 ajv: 6.14.0 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -7424,25 +7564,25 @@ snapshots: strip-final-newline: 4.0.0 yoctocolors: 2.1.2 - express-rate-limit@8.3.1(express@5.2.1): + express-rate-limit@8.3.1(express@5.2.1(supports-color@7.2.0)): dependencies: - express: 5.2.1 - ip-address: 10.1.0 + express: 5.2.1(supports-color@7.2.0) + ip-address: 10.3.1 - express@5.2.1: + express@5.2.1(supports-color@7.2.0): dependencies: accepts: 2.0.0 - body-parser: 2.2.2 + body-parser: 2.3.0(supports-color@7.2.0) content-disposition: 1.0.1 content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 2.1.1 + finalhandler: 2.1.1(supports-color@7.2.0) fresh: 2.0.0 http-errors: 2.0.1 merge-descriptors: 2.0.0 @@ -7451,11 +7591,11 @@ snapshots: once: 1.4.0 parseurl: 1.3.3 proxy-addr: 2.0.7 - qs: 6.15.0 + qs: 6.16.0 range-parser: 1.2.1 - router: 2.2.0 - send: 1.2.1 - serve-static: 2.2.1 + router: 2.2.0(supports-color@7.2.0) + send: 1.2.1(supports-color@7.2.0) + serve-static: 2.2.1(supports-color@7.2.0) statuses: 2.0.2 type-is: 2.0.1 vary: 1.1.2 @@ -7488,7 +7628,7 @@ snapshots: fast-levenshtein@2.0.6: {} - fast-uri@3.1.0: {} + fast-uri@3.1.6: {} fastdom@1.0.12: dependencies: @@ -7498,9 +7638,9 @@ snapshots: dependencies: reusify: 1.1.0 - fdir@6.5.0(picomatch@4.0.3): + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: - picomatch: 4.0.3 + picomatch: 4.0.4 figures@6.1.0: dependencies: @@ -7514,9 +7654,9 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@2.1.1: + finalhandler@2.1.1(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -7532,10 +7672,10 @@ snapshots: flat-cache@4.0.1: dependencies: - flatted: 3.4.1 + flatted: 3.4.2 keyv: 4.5.4 - flatted@3.4.1: {} + flatted@3.4.2: {} for-each@0.3.5: dependencies: @@ -7660,7 +7800,7 @@ snapshots: dependencies: '@types/hast': 3.0.5 - hast-util-to-jsx-runtime@2.3.6: + hast-util-to-jsx-runtime@2.3.6(supports-color@7.2.0): dependencies: '@types/estree': 1.0.8 '@types/hast': 3.0.5 @@ -7669,9 +7809,9 @@ snapshots: devlop: 1.1.0 estree-util-is-identifier-name: 3.0.0 hast-util-whitespace: 3.0.0 - mdast-util-mdx-expression: 2.0.1 - mdast-util-mdx-jsx: 3.2.0 - mdast-util-mdxjs-esm: 2.0.1 + mdast-util-mdx-expression: 2.0.1(supports-color@7.2.0) + mdast-util-mdx-jsx: 3.2.0(supports-color@7.2.0) + mdast-util-mdxjs-esm: 2.0.1(supports-color@7.2.0) property-information: 7.2.0 space-separated-tokens: 2.0.2 style-to-js: 1.1.21 @@ -7699,7 +7839,7 @@ snapshots: highlight.js@11.11.2: {} - hono@4.12.7: {} + hono@4.12.34: {} html-url-attributes@3.0.1: {} @@ -7727,7 +7867,7 @@ snapshots: ignore@7.0.5: {} - immutable@5.1.5: {} + immutable@5.1.8: {} import-fresh@3.3.1: dependencies: @@ -7752,9 +7892,7 @@ snapshots: internmap@2.0.3: {} - ip-address@10.1.0: {} - - ip-address@10.5.0: {} + ip-address@10.3.1: {} ipaddr.js@1.9.1: {} @@ -7934,7 +8072,7 @@ snapshots: js-tokens@4.0.0: {} - js-yaml@4.1.1: + js-yaml@4.3.1: dependencies: argparse: 2.0.1 @@ -8051,11 +8189,11 @@ snapshots: lines-and-columns@1.2.4: {} - linkify-it@5.0.0: + linkify-it@5.0.2: dependencies: uc.micro: 2.1.0 - linkifyjs@4.3.2: {} + linkifyjs@4.3.3: {} locate-path@6.0.0: dependencies: @@ -8065,7 +8203,7 @@ snapshots: lodash.merge@4.6.2: {} - lodash@4.17.23: {} + lodash@4.18.0: {} log-symbols@6.0.0: dependencies: @@ -8102,19 +8240,19 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - markdown-it-image-figures@2.1.1(markdown-it@14.1.1): + markdown-it-image-figures@2.1.1(markdown-it@14.3.1): dependencies: - markdown-it: 14.1.1 + markdown-it: 14.3.1 markdown-it-sub@2.0.0: {} markdown-it-sup@2.0.0: {} - markdown-it@14.1.1: + markdown-it@14.3.1: dependencies: argparse: 2.0.1 entities: 4.5.0 - linkify-it: 5.0.0 + linkify-it: 5.0.2 mdurl: 2.0.0 punycode.js: 2.3.1 uc.micro: 2.1.0 @@ -8142,8 +8280,8 @@ snapshots: codemirror: 6.0.2 lru-cache: 11.2.7 lucide-react: 0.542.0(react@19.2.3) - markdown-it: 14.1.1 - markdown-it-image-figures: 2.1.1(markdown-it@14.1.1) + markdown-it: 14.3.1 + markdown-it-image-figures: 2.1.1(markdown-it@14.3.1) markdown-it-sub: 2.0.0 markdown-it-sup: 2.0.0 medium-zoom: 1.1.0 @@ -8158,14 +8296,14 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 - mdast-util-from-markdown@2.0.3: + mdast-util-from-markdown@2.0.3(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 '@types/unist': 3.0.3 decode-named-character-reference: 1.3.0 devlop: 1.1.0 mdast-util-to-string: 4.0.0 - micromark: 4.0.2 + micromark: 4.0.2(supports-color@7.2.0) micromark-util-decode-numeric-character-reference: 2.0.2 micromark-util-decode-string: 2.0.1 micromark-util-normalize-identifier: 2.0.1 @@ -8183,67 +8321,67 @@ snapshots: mdast-util-find-and-replace: 3.0.2 micromark-util-character: 2.1.1 - mdast-util-gfm-footnote@2.1.0: + mdast-util-gfm-footnote@2.1.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 micromark-util-normalize-identifier: 2.0.1 transitivePeerDependencies: - supports-color - mdast-util-gfm-strikethrough@2.0.0: + mdast-util-gfm-strikethrough@2.0.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-gfm-table@2.0.0: + mdast-util-gfm-table@2.0.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 markdown-table: 3.0.4 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-gfm-task-list-item@2.0.0: + mdast-util-gfm-task-list-item@2.0.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-gfm@3.1.0: + mdast-util-gfm@3.1.0(supports-color@7.2.0): dependencies: - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-gfm-autolink-literal: 2.0.1 - mdast-util-gfm-footnote: 2.1.0 - mdast-util-gfm-strikethrough: 2.0.0 - mdast-util-gfm-table: 2.0.0 - mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-gfm-footnote: 2.1.0(supports-color@7.2.0) + mdast-util-gfm-strikethrough: 2.0.0(supports-color@7.2.0) + mdast-util-gfm-table: 2.0.0(supports-color@7.2.0) + mdast-util-gfm-task-list-item: 2.0.0(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-mdx-expression@2.0.1: + mdast-util-mdx-expression@2.0.1(supports-color@7.2.0): dependencies: '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.5 '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-mdx-jsx@3.2.0: + mdast-util-mdx-jsx@3.2.0(supports-color@7.2.0): dependencies: '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.5 @@ -8251,7 +8389,7 @@ snapshots: '@types/unist': 3.0.3 ccount: 2.0.1 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 parse-entities: 4.0.2 stringify-entities: 4.0.4 @@ -8260,13 +8398,13 @@ snapshots: transitivePeerDependencies: - supports-color - mdast-util-mdxjs-esm@2.0.1: + mdast-util-mdxjs-esm@2.0.1(supports-color@7.2.0): dependencies: '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.5 '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -8344,7 +8482,7 @@ snapshots: roughjs: 4.6.6 stylis: 4.4.0 ts-dedent: 2.3.0 - uuid: 14.0.2 + uuid: 11.1.1 micromark-core-commonmark@2.0.3: dependencies: @@ -8515,10 +8653,10 @@ snapshots: micromark-util-types@2.0.2: {} - micromark@4.0.2: + micromark@4.0.2(supports-color@7.2.0): dependencies: '@types/debug': 4.1.13 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) decode-named-character-reference: 1.3.0 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 @@ -8540,7 +8678,7 @@ snapshots: micromatch@4.0.8: dependencies: braces: 3.0.3 - picomatch: 2.3.1 + picomatch: 2.3.2 mime-db@1.54.0: {} @@ -8554,17 +8692,17 @@ snapshots: minimatch@10.2.4: dependencies: - brace-expansion: 5.0.4 + brace-expansion: 5.0.9 minimatch@3.1.5: dependencies: - brace-expansion: 1.1.12 + brace-expansion: 1.1.18 minimist@1.2.8: {} ms@2.1.3: {} - nanoid@3.3.11: {} + nanoid@3.3.18: {} napi-postinstall@0.3.4: {} @@ -8577,27 +8715,27 @@ snapshots: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - next@16.1.6(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.98.0): + next@16.2.11(@babel/core@7.29.6(supports-color@7.2.0))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.98.0): dependencies: - '@next/env': 16.1.6 + '@next/env': 16.2.11 '@swc/helpers': 0.5.15 baseline-browser-mapping: 2.10.7 caniuse-lite: 1.0.30001778 - postcss: 8.4.31 + postcss: 8.5.23 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.3) + styled-jsx: 5.1.6(@babel/core@7.29.6(supports-color@7.2.0))(react@19.2.3) optionalDependencies: - '@next/swc-darwin-arm64': 16.1.6 - '@next/swc-darwin-x64': 16.1.6 - '@next/swc-linux-arm64-gnu': 16.1.6 - '@next/swc-linux-arm64-musl': 16.1.6 - '@next/swc-linux-x64-gnu': 16.1.6 - '@next/swc-linux-x64-musl': 16.1.6 - '@next/swc-win32-arm64-msvc': 16.1.6 - '@next/swc-win32-x64-msvc': 16.1.6 + '@next/swc-darwin-arm64': 16.2.11 + '@next/swc-darwin-x64': 16.2.11 + '@next/swc-linux-arm64-gnu': 16.2.11 + '@next/swc-linux-arm64-musl': 16.2.11 + '@next/swc-linux-x64-gnu': 16.2.11 + '@next/swc-linux-x64-musl': 16.2.11 + '@next/swc-win32-arm64-msvc': 16.2.11 + '@next/swc-win32-x64-msvc': 16.2.11 sass: 1.98.0 - sharp: 0.34.5 + sharp: 0.35.0 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -8612,7 +8750,7 @@ snapshots: object.entries: 1.1.9 semver: 6.3.1 - node-releases@2.0.36: {} + node-releases@2.0.54: {} npm-run-path@4.0.1: dependencies: @@ -8768,13 +8906,13 @@ snapshots: path-parse@1.0.7: {} - path-to-regexp@8.3.0: {} + path-to-regexp@8.4.0: {} picocolors@1.1.1: {} - picomatch@2.3.1: {} + picomatch@2.3.2: {} - picomatch@4.0.3: {} + picomatch@4.0.4: {} pkce-challenge@5.0.1: {} @@ -8787,20 +8925,14 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-selector-parser@7.1.1: + postcss-selector-parser@7.1.3: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss@8.4.31: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - postcss@8.5.8: + postcss@8.5.23: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.18 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -8825,14 +8957,10 @@ snapshots: property-information@7.2.0: {} - prosemirror-changeset@2.4.0: + prosemirror-changeset@2.4.2: dependencies: prosemirror-transform: 1.11.0 - prosemirror-collab@1.3.1: - dependencies: - prosemirror-state: 1.4.4 - prosemirror-commands@1.7.1: dependencies: prosemirror-model: 1.25.4 @@ -8869,27 +8997,14 @@ snapshots: prosemirror-state: 1.4.4 w3c-keyname: 2.2.8 - prosemirror-markdown@1.13.4: - dependencies: - '@types/markdown-it': 14.1.2 - markdown-it: 14.1.1 - prosemirror-model: 1.25.4 - - prosemirror-menu@1.3.0: + prosemirror-model@1.25.11: dependencies: - crelt: 1.0.6 - prosemirror-commands: 1.7.1 - prosemirror-history: 1.5.0 - prosemirror-state: 1.4.4 + orderedmap: 2.1.1 prosemirror-model@1.25.4: dependencies: orderedmap: 2.1.1 - prosemirror-schema-basic@1.2.4: - dependencies: - prosemirror-model: 1.25.4 - prosemirror-schema-list@1.5.1: dependencies: prosemirror-model: 1.25.4 @@ -8910,15 +9025,11 @@ snapshots: prosemirror-transform: 1.11.0 prosemirror-view: 1.41.6 - prosemirror-trailing-node@3.0.0(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6): + prosemirror-transform@1.11.0: dependencies: - '@remirror/core-constants': 3.0.0 - escape-string-regexp: 4.0.0 prosemirror-model: 1.25.4 - prosemirror-state: 1.4.4 - prosemirror-view: 1.41.6 - prosemirror-transform@1.11.0: + prosemirror-transform@1.12.1: dependencies: prosemirror-model: 1.25.4 @@ -8928,6 +9039,12 @@ snapshots: prosemirror-state: 1.4.4 prosemirror-transform: 1.11.0 + prosemirror-view@1.42.3: + dependencies: + prosemirror-model: 1.25.11 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -8937,9 +9054,10 @@ snapshots: punycode@2.3.1: {} - qs@6.15.0: + qs@6.16.0: dependencies: - side-channel: 1.1.0 + es-define-property: 1.0.1 + side-channel: 1.1.1 queue-microtask@1.2.3: {} @@ -8973,17 +9091,17 @@ snapshots: react-is@18.3.1: {} - react-markdown@10.1.0(@types/react@19.2.14)(react@19.2.3): + react-markdown@10.1.0(@types/react@19.2.14)(react@19.2.3)(supports-color@7.2.0): dependencies: '@types/hast': 3.0.5 '@types/mdast': 4.0.4 '@types/react': 19.2.14 devlop: 1.1.0 - hast-util-to-jsx-runtime: 2.3.6 + hast-util-to-jsx-runtime: 2.3.6(supports-color@7.2.0) html-url-attributes: 3.0.1 mdast-util-to-hast: 13.2.1 react: 19.2.3 - remark-parse: 11.0.0 + remark-parse: 11.0.0(supports-color@7.2.0) remark-rehype: 11.1.2 unified: 11.0.5 unist-util-visit: 5.1.0 @@ -9065,7 +9183,7 @@ snapshots: dependencies: clsx: 2.1.1 eventemitter3: 4.0.7 - lodash: 4.17.23 + lodash: 4.18.0 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) react-is: 18.3.1 @@ -9108,21 +9226,21 @@ snapshots: mdast-util-newline-to-break: 2.0.0 unified: 11.0.5 - remark-gfm@4.0.1: + remark-gfm@4.0.1(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 - mdast-util-gfm: 3.1.0 + mdast-util-gfm: 3.1.0(supports-color@7.2.0) micromark-extension-gfm: 3.0.0 - remark-parse: 11.0.0 + remark-parse: 11.0.0(supports-color@7.2.0) remark-stringify: 11.0.0 unified: 11.0.5 transitivePeerDependencies: - supports-color - remark-parse@11.0.0: + remark-parse@11.0.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) micromark-util-types: 2.0.2 unified: 11.0.5 transitivePeerDependencies: @@ -9183,13 +9301,13 @@ snapshots: points-on-curve: 0.2.0 points-on-path: 0.2.1 - router@2.2.0: + router@2.2.0(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 - path-to-regexp: 8.3.0 + path-to-regexp: 8.4.0 transitivePeerDependencies: - supports-color @@ -9225,7 +9343,7 @@ snapshots: sass@1.98.0: dependencies: chokidar: 4.0.3 - immutable: 5.1.5 + immutable: 5.1.8 source-map-js: 1.2.1 optionalDependencies: '@parcel/watcher': 2.5.6 @@ -9236,9 +9354,12 @@ snapshots: semver@7.7.4: {} - send@1.2.1: + semver@7.8.5: + optional: true + + send@1.2.1(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 @@ -9252,12 +9373,12 @@ snapshots: transitivePeerDependencies: - supports-color - serve-static@2.2.1: + serve-static@2.2.1(supports-color@7.2.0): dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 1.2.1 + send: 1.2.1(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -9285,16 +9406,16 @@ snapshots: setprototypeof@1.2.0: {} - shadcn@4.18.0(typescript@6.0.3): + shadcn@4.18.0(supports-color@7.2.0)(typescript@6.0.3): dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.6(supports-color@7.2.0) '@babel/parser': 7.29.0 - '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) - '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.6(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/preset-typescript': 7.28.5(@babel/core@7.29.6(supports-color@7.2.0))(supports-color@7.2.0) '@dotenvx/dotenvx': 1.55.0 - '@modelcontextprotocol/sdk': 1.27.1(zod@3.25.76) + '@modelcontextprotocol/sdk': 1.27.1(supports-color@7.2.0)(zod@3.25.76) '@types/validate-npm-package-name': 4.0.2 - browserslist: 4.28.1 + browserslist: 4.28.7 commander: 14.0.3 cosmiconfig: 9.0.1(typescript@6.0.3) dedent: 1.7.2 @@ -9307,8 +9428,8 @@ snapshots: kleur: 4.1.5 open: 11.0.0 ora: 8.2.0 - postcss: 8.5.8 - postcss-selector-parser: 7.1.1 + postcss: 8.5.23 + postcss-selector-parser: 7.1.3 prompts: 2.4.2 recast: 0.23.11 socks: 2.8.9 @@ -9326,36 +9447,37 @@ snapshots: - supports-color - typescript - sharp@0.34.5: + sharp@0.35.0: dependencies: '@img/colour': 1.1.0 detect-libc: 2.1.2 - semver: 7.7.4 + semver: 7.8.5 optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.5 - '@img/sharp-darwin-x64': 0.34.5 - '@img/sharp-libvips-darwin-arm64': 1.2.4 - '@img/sharp-libvips-darwin-x64': 1.2.4 - '@img/sharp-libvips-linux-arm': 1.2.4 - '@img/sharp-libvips-linux-arm64': 1.2.4 - '@img/sharp-libvips-linux-ppc64': 1.2.4 - '@img/sharp-libvips-linux-riscv64': 1.2.4 - '@img/sharp-libvips-linux-s390x': 1.2.4 - '@img/sharp-libvips-linux-x64': 1.2.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 - '@img/sharp-linux-arm': 0.34.5 - '@img/sharp-linux-arm64': 0.34.5 - '@img/sharp-linux-ppc64': 0.34.5 - '@img/sharp-linux-riscv64': 0.34.5 - '@img/sharp-linux-s390x': 0.34.5 - '@img/sharp-linux-x64': 0.34.5 - '@img/sharp-linuxmusl-arm64': 0.34.5 - '@img/sharp-linuxmusl-x64': 0.34.5 - '@img/sharp-wasm32': 0.34.5 - '@img/sharp-win32-arm64': 0.34.5 - '@img/sharp-win32-ia32': 0.34.5 - '@img/sharp-win32-x64': 0.34.5 + '@img/sharp-darwin-arm64': 0.35.0 + '@img/sharp-darwin-x64': 0.35.0 + '@img/sharp-freebsd-wasm32': 0.35.0 + '@img/sharp-libvips-darwin-arm64': 1.3.0 + '@img/sharp-libvips-darwin-x64': 1.3.0 + '@img/sharp-libvips-linux-arm': 1.3.0 + '@img/sharp-libvips-linux-arm64': 1.3.0 + '@img/sharp-libvips-linux-ppc64': 1.3.0 + '@img/sharp-libvips-linux-riscv64': 1.3.0 + '@img/sharp-libvips-linux-s390x': 1.3.0 + '@img/sharp-libvips-linux-x64': 1.3.0 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.0 + '@img/sharp-libvips-linuxmusl-x64': 1.3.0 + '@img/sharp-linux-arm': 0.35.0 + '@img/sharp-linux-arm64': 0.35.0 + '@img/sharp-linux-ppc64': 0.35.0 + '@img/sharp-linux-riscv64': 0.35.0 + '@img/sharp-linux-s390x': 0.35.0 + '@img/sharp-linux-x64': 0.35.0 + '@img/sharp-linuxmusl-arm64': 0.35.0 + '@img/sharp-linuxmusl-x64': 0.35.0 + '@img/sharp-webcontainers-wasm32': 0.35.0 + '@img/sharp-win32-arm64': 0.35.0 + '@img/sharp-win32-ia32': 0.35.0 + '@img/sharp-win32-x64': 0.35.0 optional: true shebang-command@2.0.0: @@ -9369,6 +9491,11 @@ snapshots: es-errors: 1.3.0 object-inspect: 1.13.4 + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-map@1.0.1: dependencies: call-bound: 1.0.4 @@ -9392,6 +9519,14 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 + side-channel@1.1.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + signal-exit@3.0.7: {} signal-exit@4.1.0: {} @@ -9402,7 +9537,7 @@ snapshots: socks@2.8.9: dependencies: - ip-address: 10.5.0 + ip-address: 10.3.1 smart-buffer: 4.2.0 sonner@2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3): @@ -9523,12 +9658,12 @@ snapshots: dependencies: inline-style-parser: 0.2.7 - styled-jsx@5.1.6(@babel/core@7.29.0)(react@19.2.3): + styled-jsx@5.1.6(@babel/core@7.29.6(supports-color@7.2.0))(react@19.2.3): dependencies: client-only: 0.0.1 react: 19.2.3 optionalDependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.6(supports-color@7.2.0) stylis@4.4.0: {} @@ -9559,8 +9694,8 @@ snapshots: tinyglobby@0.2.15: dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 to-regex-range@5.0.1: dependencies: @@ -9614,6 +9749,12 @@ snapshots: media-typer: 1.1.0 mime-types: 3.0.2 + type-is@2.1.0: + dependencies: + content-type: 2.1.0 + media-typer: 1.1.0 + mime-types: 3.0.2 + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -9647,13 +9788,13 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript-eslint@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3): + typescript-eslint@8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) - '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) - '@typescript-eslint/typescript-estree': 8.57.0(typescript@6.0.3) - '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3) - eslint: 9.39.4(jiti@2.6.1) + '@typescript-eslint/eslint-plugin': 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.57.0(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@2.6.1)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + eslint: 9.39.4(jiti@2.6.1)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -9741,9 +9882,9 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 - update-browserslist-db@1.2.3(browserslist@4.28.1): + update-browserslist-db@1.2.3(browserslist@4.28.7): dependencies: - browserslist: 4.28.1 + browserslist: 4.28.7 escalade: 3.2.0 picocolors: 1.1.1 @@ -9772,7 +9913,7 @@ snapshots: util-deprecate@1.0.2: {} - uuid@14.0.2: {} + uuid@11.1.1: {} validate-npm-package-name@7.0.2: {} From 0c6b90612c76136e5956790eff0642dee8d3c1be Mon Sep 17 00:00:00 2001 From: JOY <5027251+JOY@users.noreply.github.com> Date: Wed, 9 Sep 2026 02:49:00 +0700 Subject: [PATCH 5/9] fix(security): harden privilege boundaries, ws auth, outbox ordering and env aliasing - user_service: ResetPassword and AssignRoles can no longer touch super_admin targets or grant IsSystem roles unless the operator is a super_admin (was: any admin could escalate to super_admin in one request) - role_service: AssignPermissions refuses to rewrite built-in IsSystem roles (AssignRoles guard) unless the operator is a super_admin - ws_service: canSubscribeConversation now requires the same conversation.view permission the REST conversation endpoints gate with, closing a websocket read bypass of full message content - channel_message_outbox: ListPending only returns rows whose backoff elapsed (next_retry_at) ordered by next_retry_at, so a backlog of not-yet-due retries no longer starves newer pending sends - config: AGENT_DESK_* prefixed aliases are bound first so ambient legacy variables (PORT, DATABASE_URL) cannot silently override the documented configuration --- internal/pkg/config/config.go | 45 ++++++++++--------- .../channel_message_outbox_service.go | 6 +++ internal/services/role_service.go | 4 ++ internal/services/user_service.go | 16 +++++++ internal/services/ws_service.go | 10 ++++- 5 files changed, 59 insertions(+), 22 deletions(-) diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go index cbfff40e..082de4dc 100644 --- a/internal/pkg/config/config.go +++ b/internal/pkg/config/config.go @@ -315,27 +315,30 @@ func bindConfigDefaults(v *viper.Viper) { } func bindEnvironmentAliases(v *viper.Viper) { - _ = v.BindEnv("server.port", "PORT", "SERVER_PORT", "AGENT_DESK_SERVER_PORT") - _ = v.BindEnv("server.companyName", "COMPANY_NAME", "NEXT_PUBLIC_COMPANY_NAME", "BRAND_NAME", "BRAND_COMPANY_NAME", "AGENT_DESK_SERVER_COMPANYNAME") - _ = v.BindEnv("server.companyLogoUrl", "COMPANY_LOGO_URL", "NEXT_PUBLIC_COMPANY_LOGO_URL", "BRAND_LOGO_URL", "AGENT_DESK_SERVER_COMPANYLOGOURL") - _ = v.BindEnv("db.type", "DATABASE_TYPE", "DB_TYPE", "AGENT_DESK_DB_TYPE") - _ = v.BindEnv("db.dsn", "DATABASE_URL", "DB_DSN", "AGENT_DESK_DB_DSN") - _ = v.BindEnv("auth.passwordLoginEnabled", "PASSWORD_LOGIN_ENABLED", "AGENT_DESK_AUTH_PASSWORDLOGINENABLED") - _ = v.BindEnv("auth.tokenTTLHours", "AUTH_TOKEN_TTL_HOURS", "AGENT_DESK_AUTH_TOKENTTLHOURS") - _ = v.BindEnv("customerSession.secret", "CUSTOMER_SESSION_SECRET", "SESSION_SECRET", "JWT_SECRET", "AGENT_DESK_CUSTOMERSESSION_SECRET") - _ = v.BindEnv("storage.default", "STORAGE_DEFAULT", "STORAGE_TYPE", "AGENT_DESK_STORAGE_DEFAULT") - _ = v.BindEnv("storage.local.root", "STORAGE_LOCAL_ROOT", "AGENT_DESK_STORAGE_LOCAL_ROOT") - _ = v.BindEnv("storage.local.baseUrl", "STORAGE_LOCAL_BASE_URL", "AGENT_DESK_STORAGE_LOCAL_BASEURL") - _ = v.BindEnv("vectorDB.type", "VECTOR_DB_TYPE", "AGENT_DESK_VECTORDB_TYPE") - _ = v.BindEnv("vectorDB.qdrant.host", "QDRANT_HOST", "AGENT_DESK_VECTORDB_QDRANT_HOST") - _ = v.BindEnv("vectorDB.qdrant.grpcPort", "QDRANT_GRPC_PORT", "QDRANT_PORT", "AGENT_DESK_VECTORDB_QDRANT_GRPCPORT") - _ = v.BindEnv("vectorDB.qdrant.apiKey", "QDRANT_API_KEY", "AGENT_DESK_VECTORDB_QDRANT_APIKEY") - _ = v.BindEnv("oidc.enabled", "OIDC_ENABLED", "AGENT_DESK_OIDC_ENABLED") - _ = v.BindEnv("oidc.issuer", "OIDC_ISSUER", "AGENT_DESK_OIDC_ISSUER") - _ = v.BindEnv("oidc.clientId", "OIDC_CLIENT_ID", "CUSTOM_OAUTH_CLIENT_ID", "AGENT_DESK_OIDC_CLIENTID") - _ = v.BindEnv("oidc.clientSecret", "OIDC_CLIENT_SECRET", "CUSTOM_OAUTH_CLIENT_SECRET", "AGENT_DESK_OIDC_CLIENTSECRET") - _ = v.BindEnv("oidc.redirectUrl", "OIDC_REDIRECT_URL", "CUSTOM_OAUTH_REDIRECT_URI", "AGENT_DESK_OIDC_REDIRECTURL") - _ = v.BindEnv("webhook.orgSyncSecret", "ORG_SYNC_SECRET", "WEBHOOK_SECRET", "AGENT_DESK_WEBHOOK_ORGSYNCSECRET") + // Prefixed AGENT_DESK_* aliases are listed first so that ambient legacy + // variables (PORT, DATABASE_URL, ...) cannot silently override the + // documented configuration. + _ = v.BindEnv("server.port", "AGENT_DESK_SERVER_PORT", "PORT", "SERVER_PORT") + _ = v.BindEnv("server.companyName", "AGENT_DESK_SERVER_COMPANYNAME", "COMPANY_NAME", "NEXT_PUBLIC_COMPANY_NAME", "BRAND_NAME", "BRAND_COMPANY_NAME") + _ = v.BindEnv("server.companyLogoUrl", "AGENT_DESK_SERVER_COMPANYLOGOURL", "COMPANY_LOGO_URL", "NEXT_PUBLIC_COMPANY_LOGO_URL", "BRAND_LOGO_URL") + _ = v.BindEnv("db.type", "AGENT_DESK_DB_TYPE", "DATABASE_TYPE", "DB_TYPE") + _ = v.BindEnv("db.dsn", "AGENT_DESK_DB_DSN", "DATABASE_URL", "DB_DSN") + _ = v.BindEnv("auth.passwordLoginEnabled", "AGENT_DESK_AUTH_PASSWORDLOGINENABLED", "PASSWORD_LOGIN_ENABLED") + _ = v.BindEnv("auth.tokenTTLHours", "AGENT_DESK_AUTH_TOKENTTLHOURS", "AUTH_TOKEN_TTL_HOURS") + _ = v.BindEnv("customerSession.secret", "AGENT_DESK_CUSTOMERSESSION_SECRET", "CUSTOMER_SESSION_SECRET", "SESSION_SECRET", "JWT_SECRET") + _ = v.BindEnv("storage.default", "AGENT_DESK_STORAGE_DEFAULT", "STORAGE_DEFAULT", "STORAGE_TYPE") + _ = v.BindEnv("storage.local.root", "AGENT_DESK_STORAGE_LOCAL_ROOT", "STORAGE_LOCAL_ROOT") + _ = v.BindEnv("storage.local.baseUrl", "AGENT_DESK_STORAGE_LOCAL_BASEURL", "STORAGE_LOCAL_BASE_URL") + _ = v.BindEnv("vectorDB.type", "AGENT_DESK_VECTORDB_TYPE", "VECTOR_DB_TYPE") + _ = v.BindEnv("vectorDB.qdrant.host", "AGENT_DESK_VECTORDB_QDRANT_HOST", "QDRANT_HOST") + _ = v.BindEnv("vectorDB.qdrant.grpcPort", "AGENT_DESK_VECTORDB_QDRANT_GRPCPORT", "QDRANT_GRPC_PORT", "QDRANT_PORT") + _ = v.BindEnv("vectorDB.qdrant.apiKey", "AGENT_DESK_VECTORDB_QDRANT_APIKEY", "QDRANT_API_KEY") + _ = v.BindEnv("oidc.enabled", "AGENT_DESK_OIDC_ENABLED", "OIDC_ENABLED") + _ = v.BindEnv("oidc.issuer", "AGENT_DESK_OIDC_ISSUER", "OIDC_ISSUER") + _ = v.BindEnv("oidc.clientId", "AGENT_DESK_OIDC_CLIENTID", "OIDC_CLIENT_ID", "CUSTOM_OAUTH_CLIENT_ID") + _ = v.BindEnv("oidc.clientSecret", "AGENT_DESK_OIDC_CLIENTSECRET", "OIDC_CLIENT_SECRET", "CUSTOM_OAUTH_CLIENT_SECRET") + _ = v.BindEnv("oidc.redirectUrl", "AGENT_DESK_OIDC_REDIRECTURL", "OIDC_REDIRECT_URL", "CUSTOM_OAUTH_REDIRECT_URI") + _ = v.BindEnv("webhook.orgSyncSecret", "AGENT_DESK_WEBHOOK_ORGSYNCSECRET", "ORG_SYNC_SECRET", "WEBHOOK_SECRET") } func normalizeLoadedConfig(cfg *Config) { diff --git a/internal/services/channel_message_outbox_service.go b/internal/services/channel_message_outbox_service.go index 2660a8bc..12014241 100644 --- a/internal/services/channel_message_outbox_service.go +++ b/internal/services/channel_message_outbox_service.go @@ -254,12 +254,18 @@ func (s *channelMessageOutboxService) ListPending(channelType string, limit int) if limit <= 0 { limit = 20 } + now := time.Now() cnd := sqls.NewCnd(). Eq("channel_type", strings.TrimSpace(channelType)). In("send_status", []string{ string(enums.ChannelMessageOutboxStatusPending), string(enums.ChannelMessageOutboxStatusFailed), }). + // Only rows whose backoff has elapsed are eligible; ordering by + // next_retry_at keeps a backlog of not-yet-due retries from starving + // newer pending sends. + Lte("next_retry_at", now). + Asc("next_retry_at"). Asc("id"). Limit(limit) return s.Find(cnd) diff --git a/internal/services/role_service.go b/internal/services/role_service.go index cf1046b8..6003f447 100644 --- a/internal/services/role_service.go +++ b/internal/services/role_service.go @@ -2,6 +2,7 @@ package services import ( "agent-desk/internal/models" + "agent-desk/internal/pkg/constants" "agent-desk/internal/pkg/dto" "agent-desk/internal/pkg/dto/request" "agent-desk/internal/pkg/enums" @@ -172,6 +173,9 @@ func (s *roleService) AssignPermissions(roleID int64, permissionIDs []int64, ope if role == nil { return errorsx.InvalidParamI18n("error.e0305") } + if role.IsSystem && (operator == nil || !slices.Contains(operator.Roles, string(constants.RoleCodeSuperAdmin))) { + return errorsx.ForbiddenI18n("error.e0293") + } return s.replaceRolePermissions(roleID, permissionIDs, operator) } diff --git a/internal/services/user_service.go b/internal/services/user_service.go index c0c2f25d..67610673 100644 --- a/internal/services/user_service.go +++ b/internal/services/user_service.go @@ -2,6 +2,7 @@ package services import ( "agent-desk/internal/models" + "agent-desk/internal/pkg/constants" "agent-desk/internal/pkg/dto" "agent-desk/internal/pkg/dto/request" "agent-desk/internal/pkg/enums" @@ -262,6 +263,9 @@ func (s *userService) replaceUserRolesDB(db *gorm.DB, userID int64, roleIDs []in if role.Status != enums.StatusOk { return errorsx.InvalidParamI18n("error.e0291") } + if role.IsSystem && (operator == nil || !slices.Contains(operator.Roles, string(constants.RoleCodeSuperAdmin))) { + return errorsx.ForbiddenI18n("error.e0293") + } relation := &models.UserRole{ UserID: userID, RoleID: roleID, @@ -279,6 +283,18 @@ func (s *userService) changePassword(userID int64, password string, operator *dt if user == nil || user.DeletedAt != nil { return errorsx.InvalidParamI18n("error.e0255") } + if operator != nil && operator.UserID != userID && !slices.Contains(operator.Roles, string(constants.RoleCodeSuperAdmin)) { + var superAdminCount int64 + if err := sqls.DB().Model(&models.UserRole{}). + Joins("JOIN t_role ON t_role.id = t_user_role.role_id"). + Where("t_user_role.user_id = ? AND t_role.code = ?", userID, string(constants.RoleCodeSuperAdmin)). + Count(&superAdminCount).Error; err != nil { + return err + } + if superAdminCount > 0 { + return errorsx.ForbiddenI18n("error.e0293") + } + } if strings.TrimSpace(password) == "" { return errorsx.InvalidParamI18n("error.e0220") } diff --git a/internal/services/ws_service.go b/internal/services/ws_service.go index 2f37acc2..53c07a8b 100644 --- a/internal/services/ws_service.go +++ b/internal/services/ws_service.go @@ -2,6 +2,7 @@ package services import ( "agent-desk/internal/models" + "agent-desk/internal/pkg/constants" "agent-desk/internal/pkg/dto" "agent-desk/internal/pkg/dto/response" "agent-desk/internal/pkg/enums" @@ -13,6 +14,7 @@ import ( "fmt" "log/slog" "net/http" + "slices" "strconv" "strings" "sync/atomic" @@ -626,7 +628,13 @@ func (s *wsService) canSubscribeConversation(session *ClientSession, conversatio return false } if session.Role == realtimeRoleAdmin { - return true + // Staff sessions must hold the same conversation-view permission the + // REST endpoints require; a bare admin-role websocket must not become + // a side channel around RequirePermission. + if session.Principal != nil && slices.Contains(session.Principal.Permissions, constants.PermissionConversationView.Code) { + return true + } + return false } conversation := ConversationService.Get(conversationID) if conversation == nil { From c78f63a6ea99e09dd4cda43c7c71f9164baea9c9 Mon Sep 17 00:00:00 2001 From: JOY <5027251+JOY@users.noreply.github.com> Date: Thu, 10 Sep 2026 20:58:35 +0700 Subject: [PATCH 6/9] fix(storage): stop guest uploads from becoming same-origin script execution Uploaded assets are served from the application's own origin, so the extension stored in the key decides how a browser interprets the bytes. Nothing validated it: /api/message/upload_attachment accepted any file from an authenticated guest and the storage layer wrote whatever extension the client named, so a planted .html file ran against the dashboard origin the moment a staff member opened the attachment link. - Reject browser-active extensions and payloads (HTML, SVG, XML/XSL, scripts, legacy server-side pages) in AssetService.UploadFile and UploadBytes, and sniff the leading bytes instead of trusting the client-declared Content-Type so renaming a page to .png does not smuggle it through - Reduce client filenames to a bare basename within the 255 character column, cut on a rune boundary, and strip control characters - Derive the stored extension from an explicit MIME table. mime.ExtensionsByType consults the Windows registry, where text/html resolved to .ehtml and escaped the block list, and it differs between dev machines and production - Fall back to an inert .bin when no safe extension can be determined, so the server never sniffs the payload to decide its own Content-Type - Serve local assets with X-Content-Type-Options nosniff and force a download for anything that is not previewable media, which also neutralises document types already sitting in an existing storage root - Add error.e0348 to both backend locales for the rejection --- internal/bootstrap/server.go | 22 +- internal/bootstrap/server_route_test.go | 58 +++++ internal/pkg/i18nx/locales/en-US.yml | 1 + internal/pkg/i18nx/locales/zh-CN.yml | 1 + internal/services/asset_service.go | 25 ++- internal/services/storage/safety.go | 218 ++++++++++++++++++ internal/services/storage/safety_test.go | 268 +++++++++++++++++++++++ internal/services/storage/utils.go | 29 +-- 8 files changed, 598 insertions(+), 24 deletions(-) create mode 100644 internal/services/storage/safety.go create mode 100644 internal/services/storage/safety_test.go diff --git a/internal/bootstrap/server.go b/internal/bootstrap/server.go index d5fc669a..30d214a6 100644 --- a/internal/bootstrap/server.go +++ b/internal/bootstrap/server.go @@ -3,6 +3,7 @@ package bootstrap import ( "log/slog" "net/http" + "path" "strconv" "strings" "time" @@ -17,6 +18,7 @@ import ( "agent-desk/internal/pkg/i18nx" "agent-desk/internal/pkg/tracex" "agent-desk/internal/services" + "agent-desk/internal/services/storage" webspa "agent-desk/web" "github.com/gin-gonic/gin" @@ -44,11 +46,29 @@ func NewServer() (*gin.Engine, error) { handleSpa(app) - app.StaticFS(cfg.Storage.Local.BaseURL, ginx.StaticFiles(cfg.Storage.Local.Root)) + storageGroup := app.Group(cfg.Storage.Local.BaseURL, assetResponseHeaders()) + storageGroup.StaticFS("", ginx.StaticFiles(cfg.Storage.Local.Root)) return app, nil } +// assetResponseHeaders guards the locally stored assets. +// +// Those files are user-supplied bytes served from this application's own origin, +// so a response a browser renders inline is same-origin content. nosniff stops a +// browser reinterpreting the payload, and forcing a download for anything that is +// not previewable media means a document type that slipped in before this policy +// existed still cannot run as a page. +func assetResponseHeaders() gin.HandlerFunc { + return func(ctx *gin.Context) { + ctx.Header("X-Content-Type-Options", "nosniff") + if !storage.IsPreviewableExtension(path.Ext(ctx.Request.URL.Path)) { + ctx.Header("Content-Disposition", "attachment") + } + ctx.Next() + } +} + func corsMiddleware() gin.HandlerFunc { allowedOrigins := config.Current().Server.CORS.AllowedOrigins allowHeaders := "Origin, Content-Type, Accept, Authorization, X-Requested-With, X-Guest-Id, X-Channel-Id, X-External-Id, X-External-Name, X-Customer-Session-Token, X-Customer-Session-Expires-At" diff --git a/internal/bootstrap/server_route_test.go b/internal/bootstrap/server_route_test.go index 328b293f..0b2716e4 100644 --- a/internal/bootstrap/server_route_test.go +++ b/internal/bootstrap/server_route_test.go @@ -296,6 +296,64 @@ func TestNewServerSeparatesAPIStaticAndSPA(t *testing.T) { } } +func TestNewServerHardensStoredAssetResponses(t *testing.T) { + root := t.TempDir() + for _, name := range []string{"screenshot.png", "archive.zip", "legacy-page.html"} { + if err := os.WriteFile(filepath.Join(root, name), []byte("payload"), 0o644); err != nil { + t.Fatalf("WriteFile(%s) error = %v", name, err) + } + } + + config.SetCurrent(&config.Config{ + Storage: config.StorageConfig{ + Local: config.LocalStorageConfig{ + Root: root, + BaseURL: "/storage", + }, + }, + }) + + app, err := NewServer() + if err != nil { + t.Fatalf("NewServer() error = %v", err) + } + + tests := []struct { + path string + wantStatus int + contentType string + wantAttachment bool + }{ + {path: "/storage/screenshot.png", wantStatus: http.StatusOK, contentType: "image/png"}, + {path: "/storage/archive.zip", wantStatus: http.StatusOK, wantAttachment: true}, + // A file planted before the upload policy existed must still not render. + {path: "/storage/legacy-page.html", wantStatus: http.StatusOK, wantAttachment: true}, + {path: "/storage/missing.png", wantStatus: http.StatusNotFound}, + } + + for _, tt := range tests { + rec := httptest.NewRecorder() + app.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, tt.path, nil)) + + if rec.Code != tt.wantStatus { + t.Fatalf("%s status=%d want %d", tt.path, rec.Code, tt.wantStatus) + } + if got := rec.Header().Get("X-Content-Type-Options"); got != "nosniff" { + t.Fatalf("%s X-Content-Type-Options=%q want nosniff", tt.path, got) + } + if tt.contentType != "" && !strings.Contains(rec.Header().Get("Content-Type"), tt.contentType) { + t.Fatalf("%s Content-Type=%q want %q", tt.path, rec.Header().Get("Content-Type"), tt.contentType) + } + got := rec.Header().Get("Content-Disposition") + if tt.wantAttachment && got != "attachment" { + t.Fatalf("%s Content-Disposition=%q want attachment", tt.path, got) + } + if !tt.wantAttachment && got != "" { + t.Fatalf("%s Content-Disposition=%q want empty so the asset renders inline", tt.path, got) + } + } +} + func TestNewServerAllowsConfiguredCORSOrigin(t *testing.T) { config.SetCurrent(&config.Config{ Server: config.ServerConfig{ diff --git a/internal/pkg/i18nx/locales/en-US.yml b/internal/pkg/i18nx/locales/en-US.yml index 9fbec600..e74b751b 100644 --- a/internal/pkg/i18nx/locales/en-US.yml +++ b/internal/pkg/i18nx/locales/en-US.yml @@ -345,6 +345,7 @@ error.e0344: "Invalid attachment message payload format." error.e0345: "Attachment message is missing assetId." error.e0346: "Attachment message is missing payload." error.e0347: "Default team queue mode requires at least one agent team." +error.e0348: "This file type cannot be uploaded for security reasons." error.profile.nicknameRequired: "Enter a nickname." error.profile.nicknameTooLong: "Nickname cannot exceed 100 characters." error.profile.avatarTooLong: "Avatar link cannot exceed 255 characters." diff --git a/internal/pkg/i18nx/locales/zh-CN.yml b/internal/pkg/i18nx/locales/zh-CN.yml index 6b3aa8eb..371264f0 100644 --- a/internal/pkg/i18nx/locales/zh-CN.yml +++ b/internal/pkg/i18nx/locales/zh-CN.yml @@ -345,6 +345,7 @@ error.e0344: "附件消息 payload 格式错误" error.e0345: "附件消息缺少 assetId" error.e0346: "附件消息缺少 payload" error.e0347: "默认客服组待接入池模式必须至少选择一个客服组" +error.e0348: "出于安全考虑,此文件类型不支持上传" error.profile.nicknameRequired: "请输入昵称" error.profile.nicknameTooLong: "昵称不能超过 100 个字符" error.profile.avatarTooLong: "头像链接不能超过 255 个字符" diff --git a/internal/services/asset_service.go b/internal/services/asset_service.go index b7596beb..aaf9a71c 100644 --- a/internal/services/asset_service.go +++ b/internal/services/asset_service.go @@ -61,12 +61,16 @@ func (s *assetService) OpenReader(asset *models.Asset) (io.ReadCloser, error) { } func (s *assetService) UploadBytes(data []byte, prefix, filename string, principal *dto.AuthPrincipal) (*models.Asset, error) { - src := bytes.NewReader(data) - return s.Upload(src, storage.UploadInfo{ + filename = storage.SanitizeFilename(filename) + mimeType, err := storage.ValidateUpload(filename, "", http.DetectContentType(data)) + if err != nil { + return nil, err + } + return s.Upload(bytes.NewReader(data), storage.UploadInfo{ Prefix: prefix, Filename: filename, FileSize: int64(len(data)), - MimeType: http.DetectContentType(data), + MimeType: mimeType, Principal: principal, }) } @@ -87,11 +91,22 @@ func (s *assetService) UploadFile(file *multipart.FileHeader, prefix string, pri } defer func() { _ = src.Close() }() + sniffed, err := storage.SniffContentType(src) + if err != nil { + return nil, err + } + + filename := storage.SanitizeFilename(file.Filename) + mimeType, err := storage.ValidateUpload(filename, file.Header.Get("Content-Type"), sniffed) + if err != nil { + return nil, err + } + return s.Upload(src, storage.UploadInfo{ Prefix: prefix, - Filename: file.Filename, + Filename: filename, FileSize: file.Size, - MimeType: file.Header.Get("Content-Type"), + MimeType: mimeType, Principal: principal, }) } diff --git a/internal/services/storage/safety.go b/internal/services/storage/safety.go new file mode 100644 index 00000000..7b9cc342 --- /dev/null +++ b/internal/services/storage/safety.go @@ -0,0 +1,218 @@ +package storage + +import ( + "io" + "mime" + "net/http" + "path" + "strings" + "unicode/utf8" + + "agent-desk/internal/pkg/errorsx" +) + +const ( + // sniffLimit is the number of leading bytes net/http.DetectContentType inspects. + sniffLimit = 512 + // maxFilenameLength keeps a stored filename inside the column that holds it. + maxFilenameLength = 255 +) + +// previewableExtensions are the only stored file types a browser may render +// inline. Every other extension is forced to download. +// +// Assets are served from this application's own origin, so an inline response is +// same-origin content: a browser that navigates to it runs whatever the bytes +// ask for, in the same security context as the dashboard and the public support +// widget. Forcing a download for anything we have not vetted keeps that true +// only for media, which cannot touch the DOM. +var previewableExtensions = map[string]bool{ + ".jpg": true, ".jpeg": true, ".png": true, ".gif": true, ".webp": true, + ".bmp": true, ".ico": true, ".avif": true, ".tif": true, ".tiff": true, + ".heic": true, ".heif": true, + ".mp4": true, ".m4v": true, ".webm": true, ".mov": true, ".ogv": true, + ".mp3": true, ".m4a": true, ".wav": true, ".ogg": true, ".oga": true, + ".aac": true, ".flac": true, + ".pdf": true, +} + +// blockedExtensions are rejected at upload time. Each one names a document a +// browser executes or lays out instead of displaying, so accepting it would let +// an unauthenticated visitor plant a script that runs against this origin the +// moment a staff member opens the attachment link. +var blockedExtensions = map[string]bool{ + ".html": true, ".htm": true, ".shtml": true, ".xhtml": true, ".xht": true, + ".svg": true, ".svgz": true, + ".xml": true, ".xsl": true, ".xslt": true, ".xsd": true, ".wsdl": true, + ".js": true, ".mjs": true, ".cjs": true, + ".swf": true, + ".php": true, ".phtml": true, ".php3": true, ".php4": true, ".php5": true, + ".asp": true, ".aspx": true, ".jsp": true, ".jspx": true, ".cfm": true, + ".hta": true, ".htc": true, ".htaccess": true, +} + +// blockedMediaTypes are the payloads a browser renders as an active document. +// They are rejected regardless of the extension the client chose, so renaming a +// page to .png does not smuggle it past the extension check. +var blockedMediaTypes = map[string]bool{ + "text/html": true, + "application/xhtml+xml": true, + "image/svg+xml": true, + "text/xml": true, + "application/xml": true, + "application/xslt+xml": true, + "text/javascript": true, + "application/javascript": true, + "application/x-javascript": true, +} + +// blockedUploadI18nKey is returned to the uploader whenever the file-safety +// policy rejects a payload. It deliberately does not name the offending type. +const blockedUploadI18nKey = "error.e0348" + +// mediaTypeExtensions maps a MIME type to the extension it should be stored +// under. mime.ExtensionsByType cannot be used here: on Windows it consults the +// registry, so the same type resolves to a different extension than in +// production, and it happily hands back an extension that describes an active +// document. Types that must never become a servable document are absent, which +// leaves the caller with the inert .bin fallback. +var mediaTypeExtensions = map[string]string{ + // images + "image/jpeg": ".jpg", "image/jfif": ".jpg", "image/pjpeg": ".jpg", + "image/png": ".png", "image/gif": ".gif", "image/webp": ".webp", + "image/bmp": ".bmp", "image/tiff": ".tiff", "image/avif": ".avif", + "image/heic": ".heic", "image/heif": ".heif", "image/x-icon": ".ico", + "image/vnd.microsoft.icon": ".ico", + // documents + "application/pdf": ".pdf", "text/plain": ".txt", "text/csv": ".csv", + "text/markdown": ".md", "application/json": ".json", "application/rtf": ".rtf", + "application/msword": ".doc", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document": ".docx", + "application/vnd.ms-excel": ".xls", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": ".xlsx", + "application/vnd.ms-powerpoint": ".ppt", + "application/vnd.openxmlformats-officedocument.presentationml.presentation": ".pptx", + "application/vnd.oasis.opendocument.text": ".odt", + "application/vnd.oasis.opendocument.spreadsheet": ".ods", + "application/vnd.oasis.opendocument.presentation": ".odp", + // archives + "application/zip": ".zip", "application/x-zip-compressed": ".zip", + "application/x-rar-compressed": ".rar", "application/vnd.rar": ".rar", + "application/x-7z-compressed": ".7z", "application/x-tar": ".tar", + "application/gzip": ".gz", "application/x-bzip2": ".bz2", "application/x-xz": ".xz", + // audio + "audio/mpeg": ".mp3", "audio/mp4": ".m4a", "audio/x-m4a": ".m4a", + "audio/wav": ".wav", "audio/x-wav": ".wav", "audio/ogg": ".ogg", + "audio/aac": ".aac", "audio/flac": ".flac", "audio/webm": ".webm", + // video + "video/mp4": ".mp4", "video/webm": ".webm", "video/quicktime": ".mov", + "video/x-msvideo": ".avi", "video/x-matroska": ".mkv", "video/ogg": ".ogv", + "video/mpeg": ".mpeg", +} + +// safeExtensionForMediaType returns the extension a payload of this type should +// be stored under, or "" when the type is not one this origin is willing to +// serve as a document. +func safeExtensionForMediaType(mediaType string) string { + return mediaTypeExtensions[strings.ToLower(strings.TrimSpace(mediaType))] +} + +// IsPreviewableExtension reports whether a stored file may be rendered inline. +func IsPreviewableExtension(ext string) bool { + return previewableExtensions[normalizeExt(ext)] +} + +// IsBlockedExtension reports whether an extension names a browser-active document. +func IsBlockedExtension(ext string) bool { + return blockedExtensions[normalizeExt(ext)] +} + +// IsBlockedMediaType reports whether a MIME type describes a browser-active document. +func IsBlockedMediaType(mediaType string) bool { + parsed, _, err := mime.ParseMediaType(strings.TrimSpace(mediaType)) + if err != nil || parsed == "" { + return false + } + return blockedMediaTypes[strings.ToLower(parsed)] +} + +// SanitizeFilename reduces a client-supplied name to a bare basename. Uploads +// arrive from browsers, mobile SDKs and channel webhooks, all of which are free +// to send a full path, control characters or nothing at all; the result is stored +// on the asset and echoed back into message payloads and download links. +func SanitizeFilename(name string) string { + name = strings.TrimSpace(name) + if name == "" { + return "" + } + name = path.Base(strings.ReplaceAll(name, "\\", "/")) + name = strings.Map(func(r rune) rune { + if r < 0x20 || r == 0x7f { + return -1 + } + return r + }, name) + name = strings.TrimSpace(strings.TrimRight(name, ". ")) + if len(name) > maxFilenameLength { + ext := path.Ext(name) + if len(ext) > maxFilenameLength { + ext = "" + } + stem := strings.TrimSuffix(name, ext) + // Cut on a rune boundary: a partial multibyte character would not survive + // the round trip through a utf8mb4 column. + limit := maxFilenameLength - len(ext) + for limit > 0 && !utf8.RuneStart(stem[limit]) { + limit-- + } + name = stem[:limit] + ext + } + return name +} + +// SniffContentType reports what the leading bytes of a seekable payload actually +// are, then rewinds so the caller can still stream the whole file to storage. +// The Content-Type a client declares is a claim, not evidence. +func SniffContentType(src io.ReadSeeker) (string, error) { + head := make([]byte, sniffLimit) + read, err := io.ReadFull(src, head) + if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF { + return "", err + } + if _, err := src.Seek(0, io.SeekStart); err != nil { + return "", err + } + return http.DetectContentType(head[:read]), nil +} + +// ValidateUpload applies the file-safety policy to an upload and returns the MIME +// type that should be recorded on the asset. +// +// sniffed comes from SniffContentType and wins whenever it identified something +// specific; declared is what the client claimed and is only trusted for the +// formats net/http cannot recognise, such as HEIC and most Office documents. +func ValidateUpload(filename, declared, sniffed string) (string, error) { + if IsBlockedExtension(path.Ext(filename)) { + return "", errorsx.InvalidParamI18n(blockedUploadI18nKey) + } + if IsBlockedMediaType(sniffed) || IsBlockedMediaType(declared) { + return "", errorsx.InvalidParamI18n(blockedUploadI18nKey) + } + + mediaType, _, _ := mime.ParseMediaType(sniffed) + if mediaType != "" && mediaType != "application/octet-stream" && !strings.HasPrefix(mediaType, "text/") { + return sniffed, nil + } + if declared != "" { + return declared, nil + } + return sniffed, nil +} + +func normalizeExt(ext string) string { + ext = strings.ToLower(strings.TrimSpace(ext)) + if ext != "" && !strings.HasPrefix(ext, ".") { + ext = "." + ext + } + return ext +} diff --git a/internal/services/storage/safety_test.go b/internal/services/storage/safety_test.go new file mode 100644 index 00000000..78fafbe6 --- /dev/null +++ b/internal/services/storage/safety_test.go @@ -0,0 +1,268 @@ +package storage + +import ( + "bytes" + "io" + "net/http" + "strings" + "testing" + "unicode/utf8" +) + +var pngSignature = []byte("\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR") + +func TestValidateUploadBlocksBrowserActiveExtensions(t *testing.T) { + names := []string{ + "session-stealer.html", "page.HTM", "vector.svg", "sheet.xml", + "transform.xsl", "bundle.min.js", "app.mjs", "shell.php", + "report.asp", "index.jsp", "legacy.swf", "widget.htc", + } + for _, name := range names { + if _, err := ValidateUpload(name, "application/octet-stream", "application/octet-stream"); err == nil { + t.Errorf("ValidateUpload(%q) accepted a browser-active extension", name) + } + } +} + +func TestValidateUploadBlocksStoredXSSPayload(t *testing.T) { + payload := []byte(`
`) + sniffed, err := SniffContentType(bytes.NewReader(payload)) + if err != nil { + t.Fatalf("SniffContentType() error = %v", err) + } + if !IsBlockedMediaType(sniffed) { + t.Fatalf("expected the payload to sniff as a blocked media type, got %q", sniffed) + } + + if _, err := ValidateUpload("proof.html", "text/html", sniffed); err == nil { + t.Error("expected an honestly named HTML upload to be rejected") + } + // Renaming the payload is the actual attack: the extension looks like an + // image and the declared type agrees, so only the bytes can catch it. + if _, err := ValidateUpload("profile.png", "image/png", sniffed); err == nil { + t.Error("expected an HTML payload disguised as a PNG to be rejected") + } +} + +func TestValidateUploadBlocksSVGRegardlessOfDeclaredType(t *testing.T) { + payload := []byte(``) + sniffed, err := SniffContentType(bytes.NewReader(payload)) + if err != nil { + t.Fatalf("SniffContentType() error = %v", err) + } + if _, err := ValidateUpload("logo.svg", "image/svg+xml", sniffed); err == nil { + t.Error("expected an SVG upload to be rejected") + } + // An SVG that arrives without the .svg extension is still refused, because + // the declared type alone is enough to identify it as an active document. + if _, err := ValidateUpload("logo.png", "image/svg+xml", sniffed); err == nil { + t.Error("expected an SVG declared as an image to be rejected") + } +} + +func TestValidateUploadAcceptsOrdinarySupportFiles(t *testing.T) { + cases := []struct { + filename string + declared string + sniffed string + wantMime string + }{ + {"screenshot.png", "image/png", http.DetectContentType(pngSignature), "image/png"}, + // The client declared a generic type; the payload identified itself. + {"photo.jpg", "application/octet-stream", "image/jpeg", "image/jpeg"}, + // net/http cannot recognise HEIC, so the declared type has to stand in. + {"IMG_0001.heic", "image/heic", "application/octet-stream", "image/heic"}, + {"contract.pdf", "application/pdf", "application/pdf", "application/pdf"}, + {"export.csv", "text/csv", "text/plain; charset=utf-8", "text/csv"}, + {"notes.txt", "text/plain", "text/plain; charset=utf-8", "text/plain"}, + {"logs.zip", "application/zip", "application/zip", "application/zip"}, + {"build.apk", "application/vnd.android.package-archive", "application/octet-stream", "application/vnd.android.package-archive"}, + {"data.json", "application/json", "application/json", "application/json"}, + } + for _, tc := range cases { + got, err := ValidateUpload(tc.filename, tc.declared, tc.sniffed) + if err != nil { + t.Errorf("ValidateUpload(%q) error = %v", tc.filename, err) + continue + } + if got != tc.wantMime { + t.Errorf("ValidateUpload(%q) mime = %q want %q", tc.filename, got, tc.wantMime) + } + } +} + +func TestSanitizeFilename(t *testing.T) { + cases := []struct { + in string + want string + }{ + {"report.pdf", "report.pdf"}, + {"../../etc/passwd", "passwd"}, + {`C:\Users\victim\Desktop\evil.html`, "evil.html"}, + {"/absolute/path/notes.txt", "notes.txt"}, + {"tab\tand\nnewline.log", "tabandnewline.log"}, + {"....", ""}, + {"", ""}, + {" spaced name.pdf ", "spaced name.pdf"}, + } + for _, tc := range cases { + if got := SanitizeFilename(tc.in); got != tc.want { + t.Errorf("SanitizeFilename(%q) = %q want %q", tc.in, got, tc.want) + } + } + + long := strings.Repeat("a", 300) + ".pdf" + got := SanitizeFilename(long) + if len(got) > 255 { + t.Errorf("SanitizeFilename() len = %d want <= 255", len(got)) + } + if !strings.HasSuffix(got, ".pdf") { + t.Errorf("SanitizeFilename() = %q, expected the extension to survive truncation", got) + } + + // A multibyte stem must not be cut in the middle of a rune. + wide := strings.Repeat("附件", 100) + ".pdf" + got = SanitizeFilename(wide) + if len(got) > 255 { + t.Errorf("SanitizeFilename() len = %d want <= 255", len(got)) + } + if !utf8.ValidString(got) { + t.Errorf("SanitizeFilename() = %q is not valid UTF-8", got) + } + if !strings.HasSuffix(got, ".pdf") { + t.Errorf("SanitizeFilename() = %q, expected the extension to survive truncation", got) + } + + // An extension longer than the whole budget cannot be preserved. + got = SanitizeFilename("a." + strings.Repeat("b", 300)) + if len(got) > 255 { + t.Errorf("SanitizeFilename() len = %d want <= 255", len(got)) + } + if !utf8.ValidString(got) { + t.Errorf("SanitizeFilename() = %q is not valid UTF-8", got) + } + + // A name made entirely of dots leaves nothing worth keeping. + if got = SanitizeFilename(strings.Repeat(".", 300)); got != "" { + t.Errorf("SanitizeFilename() of a dot-only name = %q want empty", got) + } +} + +func TestSniffContentTypeRewindsTheReader(t *testing.T) { + src := bytes.NewReader(pngSignature) + got, err := SniffContentType(src) + if err != nil { + t.Fatalf("SniffContentType() error = %v", err) + } + if got != "image/png" { + t.Fatalf("SniffContentType() = %q want image/png", got) + } + + // The caller still streams the whole payload to storage afterwards, so the + // reader must be back at the start. + rest, err := io.ReadAll(src) + if err != nil { + t.Fatalf("ReadAll() error = %v", err) + } + if !bytes.Equal(rest, pngSignature) { + t.Fatalf("reader was not rewound: got %d bytes want %d", len(rest), len(pngSignature)) + } +} + +func TestSniffContentTypeHandlesShortAndEmptyPayloads(t *testing.T) { + short := bytes.NewReader([]byte("hi")) + got, err := SniffContentType(short) + if err != nil { + t.Fatalf("SniffContentType() error = %v", err) + } + if !strings.HasPrefix(got, "text/plain") { + t.Fatalf("SniffContentType() = %q want a text/plain result", got) + } + rest, err := io.ReadAll(short) + if err != nil { + t.Fatalf("ReadAll() error = %v", err) + } + if string(rest) != "hi" { + t.Fatalf("reader was not rewound: got %q", rest) + } + + empty := bytes.NewReader(nil) + if _, err := SniffContentType(empty); err != nil { + t.Fatalf("SniffContentType() on an empty payload error = %v", err) + } +} + +func TestGenerateStorageKeyNeverUsesBlockedExtension(t *testing.T) { + cases := []struct { + info UploadInfo + want string + }{ + {UploadInfo{Filename: "evil.html", MimeType: "text/html"}, ".bin"}, + {UploadInfo{Filename: "evil.svg", MimeType: "image/svg+xml"}, ".bin"}, + // The extension is gone but the MIME type still names an active + // document, so the derived extension must be refused too. + {UploadInfo{Filename: "noext", MimeType: "text/html"}, ".bin"}, + {UploadInfo{Filename: "notes.txt", MimeType: "text/plain"}, ".txt"}, + {UploadInfo{Filename: "photo.png", MimeType: "image/png"}, ".png"}, + {UploadInfo{Filename: "unknown", MimeType: "application/octet-stream"}, ".bin"}, + } + for _, tc := range cases { + _, key := GenerateStorageKey(tc.info) + if !strings.HasSuffix(key, tc.want) { + t.Errorf("GenerateStorageKey(%+v) = %q, expected it to end in %q", tc.info, key, tc.want) + } + if strings.Contains(key, "..") { + t.Errorf("GenerateStorageKey(%+v) = %q contains a traversal segment", tc.info, key) + } + } +} + +func TestGetExtByMimeTypeIsPlatformIndependent(t *testing.T) { + // mime.ExtensionsByType reads the Windows registry, where text/html resolved + // to ".ehtml" and slipped past the block list. The mapping has to come from + // our own table so a storage key is the same on every platform, and so a + // media type that describes an active document maps to nothing at all. + cases := map[string]string{ + "text/html": "", + "application/xhtml+xml": "", + "image/svg+xml": "", + "text/xml": "", + "application/xml": "", + "application/javascript": "", + "text/javascript": "", + "image/jpeg": ".jpg", + "image/jfif": ".jpg", + "image/pjpeg": ".jpg", + "image/png": ".png", + "application/pdf": ".pdf", + "text/csv": ".csv", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": ".xlsx", + } + for mediaType, want := range cases { + if got := getExtByMimeType(mediaType); got != want { + t.Errorf("getExtByMimeType(%q) = %q want %q", mediaType, got, want) + } + } + + for mediaType := range blockedMediaTypes { + if got := getExtByMimeType(mediaType); got != "" { + t.Errorf("getExtByMimeType(%q) = %q, a blocked media type must not yield an extension", mediaType, got) + } + } +} + +func TestIsPreviewableExtension(t *testing.T) { + inline := []string{".png", ".JPG", ".jpeg", ".gif", ".webp", ".avif", ".mp4", ".webm", ".mp3", ".pdf"} + for _, ext := range inline { + if !IsPreviewableExtension(ext) { + t.Errorf("IsPreviewableExtension(%q) = false want true", ext) + } + } + + download := []string{".html", ".svg", ".xml", ".js", ".zip", ".txt", ".csv", ".docx", ".apk", ""} + for _, ext := range download { + if IsPreviewableExtension(ext) { + t.Errorf("IsPreviewableExtension(%q) = true want false", ext) + } + } +} diff --git a/internal/services/storage/utils.go b/internal/services/storage/utils.go index 0aabde2e..16b76999 100644 --- a/internal/services/storage/utils.go +++ b/internal/services/storage/utils.go @@ -30,9 +30,16 @@ func GenerateStorageKey(info UploadInfo) (assetID string, storageKey string) { } func getExt(info UploadInfo) string { - ext := strings.ToLower(filepath.Ext(strings.TrimSpace(info.Filename))) - if ext == "" { - ext = getExtByMimeType(info.MimeType) + ext := normalizeExt(filepath.Ext(strings.TrimSpace(info.Filename))) + if ext == "" || IsBlockedExtension(ext) { + ext = normalizeExt(getExtByMimeType(info.MimeType)) + } + if ext == "" || IsBlockedExtension(ext) { + // The stored extension decides the Content-Type this origin serves. A + // browser-active extension must never reach the key, and no extension at + // all would leave the server to sniff the payload and announce whatever + // it finds, so both cases settle on an inert binary type. + return ".bin" } return ext } @@ -47,21 +54,7 @@ func getExtByMimeType(mimeType string) string { return "" } - // 处理一些非标准的 MIME 类型 - switch mediaType { - case "image/jfif": - return ".jpg" - case "image/pjpeg": - return ".jpg" - case "image/jpeg": - return ".jpg" - default: - exts, _ := mime.ExtensionsByType(mediaType) - if len(exts) > 0 { - return exts[0] - } - } - return "" + return safeExtensionForMediaType(mediaType) } func normalizeAssetPrefix(prefix string) string { From f411969607c770ecf67fdb10069c310a4076123d Mon Sep 17 00:00:00 2001 From: JOY <5027251+JOY@users.noreply.github.com> Date: Sun, 13 Sep 2026 14:37:33 +0700 Subject: [PATCH 7/9] feat(channel): add native Discord channel integration Adds Discord as a sixth channel type, following the same shape as the Telegram and Zalo OA integrations: a client package, an inbound webhook service, an outbound service drained through the channel message outbox, a third-party handler, and the dashboard form fields. Inbound POST /api/third/discord/webhook[/:channel_id] Accepts both a bare interaction/webhook body and one nested under "message". Author, message id, channel id, guild id, attachments and embeds are all read from either level, so the same endpoint works with the payload shapes Discord and common bridges emit. Bot authors and empty messages are dropped. An attachment becomes a readable "[filename] url" line and an embed falls back to its description or title, so a customer who sends only an image or a link still produces a message an agent can act on. Messages map onto the existing conversation model through ExternalSourceDiscord, so a Discord user gets the same identity resolution, assignment, handoff and ticket behaviour as every other channel. Outbound Agent and AI replies are queued by EnqueueDiscordMessage and drained by cron every five seconds, with the same immediate-dispatch goroutine, backoff and retry ceiling as the other channels. Text and HTML go out as content; an image message is sent as an embed with the asset's signed URL; an attachment appends its signed URL to the text. The reply target is the discord_channel_id recorded on the last inbound message, falling back to a DM channel created from the customer's Discord user id, so a conversation that started in a server stays in that server. Guild scoping GuildID and ChannelScope are enforced on the way in. A bot invited to several servers answers only in the guild the channel names, and a channel set to dm_only ignores guild messages. Without this the two fields are stored configuration that silently does nothing, and an operator has no way to tell why a bot is answering somewhere it should not. Credentials A channel may carry its own bot token. When it does not, the deployment-wide token is used, resolved from discord.botToken in config.yaml or DISCORD_BOT_TOKEN in the environment. New DiscordConfig section plus AGENT_DESK_DISCORD_* and DISCORD_* bindings, documented in .env.example. Security The webhook secret is compared with crypto/subtle.ConstantTimeCompare. A byte-wise != leaks how much of the prefix matched through response timing, which matters here because the endpoint is unauthenticated by design. Verification is skipped only when no secret is configured on the channel, matching how the Telegram integration treats its webhook secret. Tests internal/discord/client_test.go client against an httptest stub internal/handlers/third/discord_handler_test.go handler routing and response internal/services/discord_inbound_service_test.go inbound to conversation to outbox, guild scope matrix (matching guild, other guild, DM under a guild-scoped channel, DM and guild message under dm_only, unscoped channel), and rejection of a wrong webhook secret internal/services/discord_integration_test.go full round trip Not included Discord's interactions endpoint signs requests with an Ed25519 signature over the raw body, verified against the application public key. This integration ingests through a shared-secret webhook instead, so the public key field is stored but not yet used to verify anything. Adding Ed25519 verification, and the OAuth flow that provisions a bot without a pasted token, are both worthwhile follow-ups. --- .env.example | 7 + internal/bootstrap/routes.go | 5 + internal/bootstrap/server.go | 1 + internal/discord/client.go | 139 +++++++++ internal/discord/client_test.go | 90 ++++++ internal/discord/types.go | 80 +++++ internal/handlers/third/discord_handler.go | 39 +++ .../handlers/third/discord_handler_test.go | 115 +++++++ internal/pkg/config/config.go | 19 ++ internal/pkg/dto/dto.go | 11 + internal/pkg/enums/external_identity.go | 2 + internal/pkg/enums/wxwork_kf.go | 1 + .../channel_message_outbox_service.go | 62 ++++ internal/services/channel_service.go | 47 ++- internal/services/cronx/cron.go | 4 + internal/services/discord_inbound_service.go | 176 +++++++++++ .../services/discord_inbound_service_test.go | 294 ++++++++++++++++++ internal/services/discord_integration_test.go | 169 ++++++++++ internal/services/discord_outbound_service.go | 231 ++++++++++++++ internal/services/message_service.go | 9 + .../dashboard/channels/_components/edit.tsx | 129 +++++++- .../(dashboard)/dashboard/channels/page.tsx | 8 + web/messages/en-US.json | 7 + web/messages/zh-CN.json | 7 + 24 files changed, 1638 insertions(+), 14 deletions(-) create mode 100644 internal/discord/client.go create mode 100644 internal/discord/client_test.go create mode 100644 internal/discord/types.go create mode 100644 internal/handlers/third/discord_handler.go create mode 100644 internal/handlers/third/discord_handler_test.go create mode 100644 internal/services/discord_inbound_service.go create mode 100644 internal/services/discord_inbound_service_test.go create mode 100644 internal/services/discord_integration_test.go create mode 100644 internal/services/discord_outbound_service.go diff --git a/.env.example b/.env.example index 77623625..12afb717 100644 --- a/.env.example +++ b/.env.example @@ -43,3 +43,10 @@ QDRANT_GRPC_PORT=6334 # Webhook & Organization Sync # ORG_SYNC_SECRET=your-webhook-hmac-secret + +# Discord Bot Channel +# Deployment-wide bot token, used when a Discord channel does not carry its own. +# DISCORD_BOT_TOKEN=your-discord-bot-token +# DISCORD_CLIENT_ID=your-discord-application-id +# DISCORD_CLIENT_SECRET=your-discord-client-secret +# DISCORD_PUBLIC_KEY=your-discord-application-public-key diff --git a/internal/bootstrap/routes.go b/internal/bootstrap/routes.go index e35dff8c..1482e841 100644 --- a/internal/bootstrap/routes.go +++ b/internal/bootstrap/routes.go @@ -435,3 +435,8 @@ func registerThirdZaloRoutes(group *gin.RouterGroup) { group.POST("/webhook", third.ZaloPostWebhook) group.POST("/webhook/:channel_id", third.ZaloPostWebhook) } + +func registerThirdDiscordRoutes(group *gin.RouterGroup) { + group.POST("/webhook", third.DiscordPostWebhook) + group.POST("/webhook/:channel_id", third.DiscordPostWebhook) +} diff --git a/internal/bootstrap/server.go b/internal/bootstrap/server.go index d5fc669a..228f22e1 100644 --- a/internal/bootstrap/server.go +++ b/internal/bootstrap/server.go @@ -197,6 +197,7 @@ func addRouter(app *gin.Engine) { registerThirdWechatRoutes(thirdGroup.Group("/wechat")) registerThirdTelegramRoutes(thirdGroup.Group("/telegram")) registerThirdZaloRoutes(thirdGroup.Group("/zalo")) + registerThirdDiscordRoutes(thirdGroup.Group("/discord")) } type spaShellRewrite struct { diff --git a/internal/discord/client.go b/internal/discord/client.go new file mode 100644 index 00000000..4045ae1c --- /dev/null +++ b/internal/discord/client.go @@ -0,0 +1,139 @@ +package discord + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + "time" +) + +const defaultBaseURL = "https://discord.com/api/v10" + +type Client struct { + botToken string + baseURL string + httpClient *http.Client +} + +func NewClient(botToken string) *Client { + return &Client{ + botToken: strings.TrimSpace(botToken), + baseURL: defaultBaseURL, + httpClient: &http.Client{Timeout: 15 * time.Second}, + } +} + +func (c *Client) SetBaseURL(url string) { + if strings.TrimSpace(url) != "" { + c.baseURL = strings.TrimRight(strings.TrimSpace(url), "/") + } +} + +func (c *Client) GetMe(ctx context.Context) (*User, error) { + var user User + if err := c.doRequest(ctx, http.MethodGet, "/users/@me", nil, &user); err != nil { + return nil, err + } + return &user, nil +} + +func (c *Client) CreateDMChannel(ctx context.Context, recipientID string) (*Channel, error) { + if strings.TrimSpace(recipientID) == "" { + return nil, fmt.Errorf("recipient_id is required") + } + req := CreateDMRequest{RecipientID: strings.TrimSpace(recipientID)} + var channel Channel + if err := c.doRequest(ctx, http.MethodPost, "/users/@me/channels", req, &channel); err != nil { + return nil, err + } + return &channel, nil +} + +func (c *Client) SendMessage(ctx context.Context, channelID string, content string) (*Message, error) { + channelID = strings.TrimSpace(channelID) + if channelID == "" { + return nil, fmt.Errorf("channel_id is required") + } + if strings.TrimSpace(content) == "" { + return nil, fmt.Errorf("content is required") + } + + req := SendMessageRequest{Content: content} + var msg Message + endpoint := fmt.Sprintf("/channels/%s/messages", channelID) + if err := c.doRequest(ctx, http.MethodPost, endpoint, req, &msg); err != nil { + return nil, err + } + return &msg, nil +} + +func (c *Client) SendEmbedMessage(ctx context.Context, channelID string, content string, embeds []Embed) (*Message, error) { + channelID = strings.TrimSpace(channelID) + if channelID == "" { + return nil, fmt.Errorf("channel_id is required") + } + + req := SendMessageRequest{ + Content: content, + Embeds: embeds, + } + var msg Message + endpoint := fmt.Sprintf("/channels/%s/messages", channelID) + if err := c.doRequest(ctx, http.MethodPost, endpoint, req, &msg); err != nil { + return nil, err + } + return &msg, nil +} + +func (c *Client) doRequest(ctx context.Context, method, path string, payload any, result any) error { + if c.botToken == "" { + return fmt.Errorf("discord bot token is required") + } + + endpoint := fmt.Sprintf("%s%s", c.baseURL, path) + + var bodyReader io.Reader + if payload != nil { + bodyBytes, err := json.Marshal(payload) + if err != nil { + return fmt.Errorf("marshal discord request failed: %w", err) + } + bodyReader = bytes.NewBuffer(bodyBytes) + } + + req, err := http.NewRequestWithContext(ctx, method, endpoint, bodyReader) + if err != nil { + return fmt.Errorf("create discord request failed: %w", err) + } + + req.Header.Set("Authorization", "Bot "+c.botToken) + if payload != nil { + req.Header.Set("Content-Type", "application/json") + } + + res, err := c.httpClient.Do(req) + if err != nil { + return fmt.Errorf("discord http request failed: %w", err) + } + defer res.Body.Close() + + bodyBytes, err := io.ReadAll(res.Body) + if err != nil { + return fmt.Errorf("read discord response failed: %w", err) + } + + if res.StatusCode < 200 || res.StatusCode >= 300 { + return fmt.Errorf("discord api error (%d): %s", res.StatusCode, string(bodyBytes)) + } + + if result != nil { + if err := json.Unmarshal(bodyBytes, result); err != nil { + return fmt.Errorf("unmarshal discord response failed: %w (body: %s)", err, string(bodyBytes)) + } + } + return nil +} diff --git a/internal/discord/client_test.go b/internal/discord/client_test.go new file mode 100644 index 00000000..de1b7c85 --- /dev/null +++ b/internal/discord/client_test.go @@ -0,0 +1,90 @@ +package discord + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" +) + +func TestDiscordSendMessage(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Header.Get("Authorization") != "Bot test_token" { + t.Errorf("expected Bot test_token, got %s", r.Header.Get("Authorization")) + } + if r.URL.Path != "/channels/789/messages" { + t.Errorf("expected path /channels/789/messages, got %s", r.URL.Path) + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write([]byte(`{"id":"123456","channel_id":"789","content":"hello"}`)) + })) + defer server.Close() + + client := NewClient("test_token") + client.SetBaseURL(server.URL) + + resp, err := client.SendMessage(context.Background(), "789", "hello") + if err != nil { + t.Fatalf("SendMessage failed: %v", err) + } + if resp.ID != "123456" { + t.Errorf("expected ID 123456, got %s", resp.ID) + } +} + +func TestDiscordSendEmbedMessage(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Header.Get("Authorization") != "Bot test_token" { + t.Errorf("expected Bot test_token, got %s", r.Header.Get("Authorization")) + } + if r.URL.Path != "/channels/789/messages" { + t.Errorf("expected path /channels/789/messages, got %s", r.URL.Path) + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write([]byte(`{"id":"embed_123","channel_id":"789","content":"Check image"}`)) + })) + defer server.Close() + + client := NewClient("test_token") + client.SetBaseURL(server.URL) + + embed := Embed{ + Title: "Screenshot", + Image: &EmbedMedia{URL: "https://example.com/img.png"}, + } + resp, err := client.SendEmbedMessage(context.Background(), "789", "Check image", []Embed{embed}) + if err != nil { + t.Fatalf("SendEmbedMessage failed: %v", err) + } + if resp.ID != "embed_123" { + t.Errorf("expected ID embed_123, got %s", resp.ID) + } +} + +func TestDiscordCreateDMChannel(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Header.Get("Authorization") != "Bot test_token" { + t.Errorf("expected Bot test_token, got %s", r.Header.Get("Authorization")) + } + if r.URL.Path != "/users/@me/channels" { + t.Errorf("expected path /users/@me/channels, got %s", r.URL.Path) + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write([]byte(`{"id":"dm_chan_123","type":1}`)) + })) + defer server.Close() + + client := NewClient("test_token") + client.SetBaseURL(server.URL) + + resp, err := client.CreateDMChannel(context.Background(), "user_999") + if err != nil { + t.Fatalf("CreateDMChannel failed: %v", err) + } + if resp.ID != "dm_chan_123" { + t.Errorf("expected ID dm_chan_123, got %s", resp.ID) + } +} diff --git a/internal/discord/types.go b/internal/discord/types.go new file mode 100644 index 00000000..3363bebd --- /dev/null +++ b/internal/discord/types.go @@ -0,0 +1,80 @@ +package discord + +// User represents a Discord user. +type User struct { + ID string `json:"id"` + Username string `json:"username"` + Discriminator string `json:"discriminator,omitempty"` + GlobalName string `json:"global_name,omitempty"` + Avatar string `json:"avatar,omitempty"` + Bot bool `json:"bot,omitempty"` +} + +// Channel represents a Discord channel (Guild Text, DM, Thread, etc.). +type Channel struct { + ID string `json:"id"` + Type int `json:"type"` + GuildID string `json:"guild_id,omitempty"` + Name string `json:"name,omitempty"` +} + +// Attachment represents a file or image uploaded to Discord. +type Attachment struct { + ID string `json:"id"` + Filename string `json:"filename"` + URL string `json:"url"` + ProxyURL string `json:"proxy_url,omitempty"` + ContentType string `json:"content_type,omitempty"` + Size int64 `json:"size,omitempty"` +} + +// EmbedMedia represents an image/video/thumbnail inside an Embed. +type EmbedMedia struct { + URL string `json:"url"` +} + +// Embed represents a Discord rich embed object. +type Embed struct { + Title string `json:"title,omitempty"` + Description string `json:"description,omitempty"` + URL string `json:"url,omitempty"` + Color int `json:"color,omitempty"` + Image *EmbedMedia `json:"image,omitempty"` +} + +// Message represents a Discord message. +type Message struct { + ID string `json:"id"` + ChannelID string `json:"channel_id"` + GuildID string `json:"guild_id,omitempty"` + Author User `json:"author"` + Content string `json:"content"` + Timestamp string `json:"timestamp"` + Attachments []Attachment `json:"attachments,omitempty"` + Embeds []Embed `json:"embeds,omitempty"` +} + +// SendMessageRequest represents payload for Discord create message API. +type SendMessageRequest struct { + Content string `json:"content,omitempty"` + Embeds []Embed `json:"embeds,omitempty"` +} + +// CreateDMRequest represents payload for Discord create DM channel API. +type CreateDMRequest struct { + RecipientID string `json:"recipient_id"` +} + +// WebhookPayload represents an incoming message/event from Discord Gateway or Webhook. +type WebhookPayload struct { + ID string `json:"id,omitempty"` + Type int `json:"type,omitempty"` + GuildID string `json:"guild_id,omitempty"` + ChannelID string `json:"channel_id,omitempty"` + Author *User `json:"author,omitempty"` + Content string `json:"content,omitempty"` + Timestamp string `json:"timestamp,omitempty"` + Attachments []Attachment `json:"attachments,omitempty"` + Embeds []Embed `json:"embeds,omitempty"` + Message *Message `json:"message,omitempty"` +} diff --git a/internal/handlers/third/discord_handler.go b/internal/handlers/third/discord_handler.go new file mode 100644 index 00000000..e36ba526 --- /dev/null +++ b/internal/handlers/third/discord_handler.go @@ -0,0 +1,39 @@ +package third + +import ( + "bytes" + "io" + "net/http" + "strings" + + "agent-desk/internal/services" + + "github.com/gin-gonic/gin" +) + +// DiscordPostWebhook receives incoming Webhook events from Discord. +func DiscordPostWebhook(ctx *gin.Context) { + channelID := strings.TrimSpace(ctx.Param("channel_id")) + if channelID == "" { + channelID = strings.TrimSpace(ctx.Query("channel_id")) + } + + secretHeader := ctx.GetHeader("X-Discord-Secret-Token") + if secretHeader == "" { + secretHeader = ctx.GetHeader("X-Webhook-Secret") + } + + bodyBytes, err := io.ReadAll(ctx.Request.Body) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"ok": false, "error": "failed to read body"}) + return + } + ctx.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) + + if err := services.DiscordInboundService.HandleWebhook(ctx.Request.Context(), channelID, secretHeader, bodyBytes); err != nil { + ctx.JSON(http.StatusOK, gin.H{"ok": false, "error": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, gin.H{"ok": true}) +} diff --git a/internal/handlers/third/discord_handler_test.go b/internal/handlers/third/discord_handler_test.go new file mode 100644 index 00000000..e3b8e4f5 --- /dev/null +++ b/internal/handlers/third/discord_handler_test.go @@ -0,0 +1,115 @@ +package third + +import ( + "bytes" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + "time" + + "agent-desk/internal/models" + "agent-desk/internal/pkg/dto" + "agent-desk/internal/pkg/dto/request" + "agent-desk/internal/pkg/enums" + "agent-desk/internal/repositories" + "agent-desk/internal/services" + + "github.com/gin-gonic/gin" + "github.com/mlogclub/simple/sqls" +) + +func TestDiscordPostWebhook_Handler(t *testing.T) { + gin.SetMode(gin.TestMode) + db := setupThirdHandlerTestDB(t) + + now := time.Now() + agent := &models.AIAgent{ + Name: "Discord Agent", + ServiceMode: enums.IMConversationServiceModeAIFirst, + PublishedRevisionID: 1, + WelcomeMessage: "Hello Discord!", + Status: enums.StatusOk, + AuditFields: models.AuditFields{CreatedAt: now, UpdatedAt: now}, + } + _ = db.Create(agent) + + discordConfig, _ := json.Marshal(dto.DiscordChannelConfig{ + GuildID: "guild_999", + BotToken: "test_bot_token", + WebhookSecret: "secret_discord_123", + WelcomeMessage: "Welcome!", + }) + + operator := &dto.AuthPrincipal{UserID: 1, Username: "admin"} + channel, err := services.ChannelService.CreateChannel(request.CreateChannelRequest{ + Name: "Discord Community", + ChannelType: enums.ChannelTypeDiscord, + AIAgentID: agent.ID, + AIAgentRolloutPercent: 100, + ConfigJSON: string(discordConfig), + Status: int(enums.StatusOk), + }, operator) + if err != nil { + t.Fatalf("CreateChannel failed: %v", err) + } + + router := gin.New() + router.POST("/api/third/discord/webhook/:channel_id", DiscordPostWebhook) + router.POST("/api/third/discord/webhook", DiscordPostWebhook) + + payload := []byte(`{ + "id": "msg_001", + "channel_id": "ch_777", + "guild_id": "guild_999", + "content": "Need help with setup", + "author": { + "id": "user_456", + "username": "gamer_one", + "global_name": "Gamer One", + "bot": false + } + }`) + + // 1. Invalid secret + req, _ := http.NewRequest(http.MethodPost, "/api/third/discord/webhook/"+channel.ChannelID, bytes.NewBuffer(payload)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("X-Discord-Secret-Token", "wrong_secret") + + rec := httptest.NewRecorder() + router.ServeHTTP(rec, req) + + if rec.Code != http.StatusOK { + t.Fatalf("expected 200 OK wrapper, got: %d", rec.Code) + } + var resp map[string]any + _ = json.Unmarshal(rec.Body.Bytes(), &resp) + if resp["ok"] == true { + t.Fatalf("expected error for invalid secret token") + } + + // 2. Valid secret + req2, _ := http.NewRequest(http.MethodPost, "/api/third/discord/webhook/"+channel.ChannelID, bytes.NewBuffer(payload)) + req2.Header.Set("Content-Type", "application/json") + req2.Header.Set("X-Discord-Secret-Token", "secret_discord_123") + + rec2 := httptest.NewRecorder() + router.ServeHTTP(rec2, req2) + + if rec2.Code != http.StatusOK { + t.Fatalf("expected 200 OK, got %d", rec2.Code) + } + var resp2 map[string]any + _ = json.Unmarshal(rec2.Body.Bytes(), &resp2) + if resp2["ok"] != true { + t.Fatalf("expected ok: true, got: %+v", resp2) + } + + // Verify identity in DB + identity := repositories.CustomerIdentityRepository.FindOne(db, sqls.NewCnd(). + Eq("external_source", enums.ExternalSourceDiscord). + Eq("external_id", "user_456")) + if identity == nil { + t.Fatalf("expected customer identity for user_456") + } +} diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go index 082de4dc..5925d94d 100644 --- a/internal/pkg/config/config.go +++ b/internal/pkg/config/config.go @@ -25,6 +25,7 @@ type Config struct { OIDC OIDCConfig `yaml:"oidc"` CustomerSession CustomerSessionConfig `yaml:"customerSession"` Webhook WebhookConfig `yaml:"webhook"` + Discord DiscordConfig `yaml:"discord"` } func (c Config) LanguageOrDefault() string { @@ -230,6 +231,16 @@ type WebhookConfig struct { DOSOrgSyncSecret string `yaml:"dosOrgSyncSecret"` } +// DiscordConfig holds deployment-wide Discord bot credentials. A channel may +// carry its own bot token, which takes precedence; these are the fallback for a +// single shared bot. +type DiscordConfig struct { + ClientID string `yaml:"clientId"` + ClientSecret string `yaml:"clientSecret"` + BotToken string `yaml:"botToken"` + PublicKey string `yaml:"publicKey"` +} + func Load(path string) (*Config, error) { loadDotEnv(path) @@ -312,6 +323,10 @@ func bindConfigDefaults(v *viper.Viper) { v.SetDefault("vectorDB.qdrant.host", "127.0.0.1") v.SetDefault("vectorDB.qdrant.grpcPort", 6334) v.SetDefault("mcp.enabled", true) + v.SetDefault("discord.clientId", "") + v.SetDefault("discord.clientSecret", "") + v.SetDefault("discord.botToken", "") + v.SetDefault("discord.publicKey", "") } func bindEnvironmentAliases(v *viper.Viper) { @@ -339,6 +354,10 @@ func bindEnvironmentAliases(v *viper.Viper) { _ = v.BindEnv("oidc.clientSecret", "AGENT_DESK_OIDC_CLIENTSECRET", "OIDC_CLIENT_SECRET", "CUSTOM_OAUTH_CLIENT_SECRET") _ = v.BindEnv("oidc.redirectUrl", "AGENT_DESK_OIDC_REDIRECTURL", "OIDC_REDIRECT_URL", "CUSTOM_OAUTH_REDIRECT_URI") _ = v.BindEnv("webhook.orgSyncSecret", "AGENT_DESK_WEBHOOK_ORGSYNCSECRET", "ORG_SYNC_SECRET", "WEBHOOK_SECRET") + _ = v.BindEnv("discord.clientId", "AGENT_DESK_DISCORD_CLIENTID", "DISCORD_CLIENT_ID") + _ = v.BindEnv("discord.clientSecret", "AGENT_DESK_DISCORD_CLIENTSECRET", "DISCORD_CLIENT_SECRET") + _ = v.BindEnv("discord.botToken", "AGENT_DESK_DISCORD_BOTTOKEN", "DISCORD_BOT_TOKEN") + _ = v.BindEnv("discord.publicKey", "AGENT_DESK_DISCORD_PUBLICKEY", "DISCORD_PUBLIC_KEY") } func normalizeLoadedConfig(cfg *Config) { diff --git a/internal/pkg/dto/dto.go b/internal/pkg/dto/dto.go index 276d03a1..5f456c03 100644 --- a/internal/pkg/dto/dto.go +++ b/internal/pkg/dto/dto.go @@ -49,3 +49,14 @@ type ZaloOAChannelConfig struct { WebhookSecret string `json:"webhookSecret,omitempty"` WelcomeMessage string `json:"welcomeMessage,omitempty"` } + +type DiscordChannelConfig struct { + GuildID string `json:"guildId,omitempty"` + GuildName string `json:"guildName,omitempty"` + ChannelScope string `json:"channelScope,omitempty"` // all | dm_only + BotToken string `json:"botToken,omitempty"` + ApplicationID string `json:"applicationId,omitempty"` + PublicKey string `json:"publicKey,omitempty"` + WebhookSecret string `json:"webhookSecret,omitempty"` + WelcomeMessage string `json:"welcomeMessage,omitempty"` +} diff --git a/internal/pkg/enums/external_identity.go b/internal/pkg/enums/external_identity.go index 8135fd56..e9fdf9c0 100644 --- a/internal/pkg/enums/external_identity.go +++ b/internal/pkg/enums/external_identity.go @@ -11,6 +11,7 @@ const ( ExternalSourceUser ExternalSource = "user" // 用户信息 ExternalSourceTelegram ExternalSource = "telegram" // Telegram ExternalSourceZaloOA ExternalSource = "zalo_oa" // Zalo OA + ExternalSourceDiscord ExternalSource = "discord" // Discord ) var externalSourceLabelMap = map[ExternalSource]string{ @@ -19,6 +20,7 @@ var externalSourceLabelMap = map[ExternalSource]string{ ExternalSourceUser: "用户", ExternalSourceTelegram: "Telegram", ExternalSourceZaloOA: "Zalo OA", + ExternalSourceDiscord: "Discord", } func GetExternalSourceLabel(v ExternalSource) string { diff --git a/internal/pkg/enums/wxwork_kf.go b/internal/pkg/enums/wxwork_kf.go index 825f7fa6..33d7fc9b 100644 --- a/internal/pkg/enums/wxwork_kf.go +++ b/internal/pkg/enums/wxwork_kf.go @@ -23,6 +23,7 @@ const ( ChannelTypeWxWorkKF = "wxwork_kf" ChannelTypeTelegram = "telegram" ChannelTypeZaloOA = "zalo_oa" + ChannelTypeDiscord = "discord" ) type WxWorkKFMessageSendStatus string diff --git a/internal/services/channel_message_outbox_service.go b/internal/services/channel_message_outbox_service.go index 12014241..8e40f10d 100644 --- a/internal/services/channel_message_outbox_service.go +++ b/internal/services/channel_message_outbox_service.go @@ -250,6 +250,68 @@ func (s *channelMessageOutboxService) EnqueueZaloOAMessage(conversation *models. return nil } +func (s *channelMessageOutboxService) EnqueueDiscordMessage(conversation *models.Conversation, message *models.Message) error { + if conversation == nil || message == nil { + return nil + } + channel := ChannelService.Get(conversation.ChannelID) + if channel == nil || channel.ChannelType != enums.ChannelTypeDiscord { + return nil + } + if message.SenderType != enums.IMSenderTypeAgent && message.SenderType != enums.IMSenderTypeAI { + return nil + } + if message.MessageType != enums.IMMessageTypeText && message.MessageType != enums.IMMessageTypeHTML && message.MessageType != enums.IMMessageTypeImage && message.MessageType != enums.IMMessageTypeAttachment { + return nil + } + if existing := s.GetByMessageID(enums.ChannelTypeDiscord, message.ID); existing != nil { + return nil + } + + payload, err := json.Marshal(map[string]any{ + "conversationId": conversation.ID, + "messageId": message.ID, + "messageType": message.MessageType, + "content": strings.TrimSpace(message.Content), + "payload": strings.TrimSpace(message.Payload), + "senderId": message.SenderID, + }) + if err != nil { + return err + } + + now := time.Now() + err = s.Create(&models.ChannelMessageOutbox{ + ChannelType: enums.ChannelTypeDiscord, + ConversationID: conversation.ID, + MessageID: message.ID, + Payload: string(payload), + SendStatus: string(enums.ChannelMessageOutboxStatusPending), + AuditFields: models.AuditFields{ + CreatedAt: now, + CreateUserID: message.UpdateUserID, + CreateUserName: message.UpdateUserName, + UpdatedAt: now, + UpdateUserID: message.UpdateUserID, + UpdateUserName: message.UpdateUserName, + }, + }) + if err != nil { + return err + } + + go func() { + defer func() { + if r := recover(); r != nil { + slog.Error("recovered from panic in discord outbound dispatch", "error", r) + } + }() + DiscordOutboundService.DispatchPendingOutbox() + }() + + return nil +} + func (s *channelMessageOutboxService) ListPending(channelType string, limit int) []models.ChannelMessageOutbox { if limit <= 0 { limit = 20 diff --git a/internal/services/channel_service.go b/internal/services/channel_service.go index 6a5399fc..92e2b640 100644 --- a/internal/services/channel_service.go +++ b/internal/services/channel_service.go @@ -333,6 +333,25 @@ func (s *channelService) ParseZaloOAChannelConfig(raw string) (*dto.ZaloOAChanne return cfg, nil } +func (s *channelService) ParseDiscordChannelConfig(raw string) (*dto.DiscordChannelConfig, error) { + raw = strings.TrimSpace(raw) + cfg := &dto.DiscordChannelConfig{} + if raw != "" { + if err := json.Unmarshal([]byte(raw), cfg); err != nil { + return nil, err + } + } + cfg.GuildID = strings.TrimSpace(cfg.GuildID) + cfg.GuildName = strings.TrimSpace(cfg.GuildName) + cfg.ChannelScope = strings.TrimSpace(cfg.ChannelScope) + cfg.BotToken = strings.TrimSpace(cfg.BotToken) + cfg.ApplicationID = strings.TrimSpace(cfg.ApplicationID) + cfg.PublicKey = strings.TrimSpace(cfg.PublicKey) + cfg.WebhookSecret = strings.TrimSpace(cfg.WebhookSecret) + cfg.WelcomeMessage = strings.TrimSpace(cfg.WelcomeMessage) + return cfg, nil +} + func (s *channelService) GetUserTokenSecret(channel *models.Channel) string { if channel == nil { return "" @@ -449,7 +468,7 @@ func (s *channelService) GetEnabledChannel(ctx *gin.Context) *models.Channel { func (s *channelService) buildChannelModel(id int64, req request.CreateChannelRequest) (*models.Channel, error) { channelType := strings.TrimSpace(req.ChannelType) - if channelType != enums.ChannelTypeWeb && channelType != enums.ChannelTypeWechatMP && channelType != enums.ChannelTypeWxWorkKF && channelType != enums.ChannelTypeTelegram && channelType != enums.ChannelTypeZaloOA { + if channelType != enums.ChannelTypeWeb && channelType != enums.ChannelTypeWechatMP && channelType != enums.ChannelTypeWxWorkKF && channelType != enums.ChannelTypeTelegram && channelType != enums.ChannelTypeZaloOA && channelType != enums.ChannelTypeDiscord { return nil, errorsx.InvalidParamI18n("error.e0250") } name := strings.TrimSpace(req.Name) @@ -596,6 +615,32 @@ func (s *channelService) buildChannelModel(id int64, req request.CreateChannelRe return nil, err } configJSON = string(configBytes) + case enums.ChannelTypeDiscord: + if channelID == "" { + channelID = strs.UUID() + } + if exists := s.Take("channel_id = ? AND status <> ? AND id <> ?", channelID, enums.StatusDeleted, id); exists != nil { + return nil, errorsx.InvalidParamI18n("error.e0248") + } + cfg, err := s.ParseDiscordChannelConfig(configJSON) + if err != nil { + return nil, errorsx.InvalidParam("invalid discord configuration") + } + // A channel may rely on the deployment-wide bot token instead of carrying + // its own, so the token is not required here the way Telegram's is. + if cfg.ChannelScope != "" && cfg.ChannelScope != "all" && cfg.ChannelScope != "dm_only" { + return nil, errorsx.InvalidParam("discord channelScope must be all or dm_only") + } + if cfg.WebhookSecret == "" { + if secret, err := generateUserTokenSecret(); err == nil { + cfg.WebhookSecret = secret + } + } + configBytes, err := json.Marshal(cfg) + if err != nil { + return nil, err + } + configJSON = string(configBytes) } return &models.Channel{ diff --git a/internal/services/cronx/cron.go b/internal/services/cronx/cron.go index 52ab00e2..e5c3af47 100644 --- a/internal/services/cronx/cron.go +++ b/internal/services/cronx/cron.go @@ -34,6 +34,10 @@ func Init() { if zaloCount > 0 { slog.Info("zalo oa outbox dispatched", "count", zaloCount) } + discordCount := services.DiscordOutboundService.DispatchPendingOutbox() + if discordCount > 0 { + slog.Info("discord outbox dispatched", "count", discordCount) + } }) c.Start() diff --git a/internal/services/discord_inbound_service.go b/internal/services/discord_inbound_service.go new file mode 100644 index 00000000..93f20eba --- /dev/null +++ b/internal/services/discord_inbound_service.go @@ -0,0 +1,176 @@ +package services + +import ( + "context" + "crypto/subtle" + "encoding/json" + "fmt" + "log/slog" + "strings" + + "agent-desk/internal/discord" + "agent-desk/internal/models" + "agent-desk/internal/pkg/enums" + "agent-desk/internal/pkg/errorsx" + "agent-desk/internal/pkg/openidentity" +) + +var DiscordInboundService = newDiscordInboundService() + +func newDiscordInboundService() *discordInboundService { + return &discordInboundService{} +} + +type discordInboundService struct{} + +// HandleWebhook processes an incoming webhook or gateway payload from Discord. +func (s *discordInboundService) HandleWebhook(ctx context.Context, channelID string, secretHeader string, rawPayload []byte) error { + channelID = strings.TrimSpace(channelID) + var channel *models.Channel + if channelID != "" { + channel = ChannelService.Take("channel_id = ? AND channel_type = ? AND status = ?", channelID, enums.ChannelTypeDiscord, enums.StatusOk) + } + if channel == nil { + channel = ChannelService.Take("channel_type = ? AND status = ?", enums.ChannelTypeDiscord, enums.StatusOk) + } + if channel == nil { + return errorsx.InvalidParam("discord channel not found or disabled") + } + + cfg, err := ChannelService.ParseDiscordChannelConfig(channel.ConfigJSON) + if err != nil || cfg == nil { + return errorsx.InvalidParam("discord channel config invalid") + } + + // Compared in constant time: a byte-wise != leaks how much of the prefix + // matched through response timing. + if cfg.WebhookSecret != "" && + subtle.ConstantTimeCompare([]byte(strings.TrimSpace(secretHeader)), []byte(cfg.WebhookSecret)) != 1 { + return errorsx.UnauthorizedI18n("error.auth.invalidSignature") + } + + var payload discord.WebhookPayload + if err := json.Unmarshal(rawPayload, &payload); err != nil { + return fmt.Errorf("unmarshal discord payload failed: %w", err) + } + + author := payload.Author + text := strings.TrimSpace(payload.Content) + msgID := payload.ID + targetChannelID := payload.ChannelID + guildID := payload.GuildID + attachments := payload.Attachments + embeds := payload.Embeds + + if payload.Message != nil { + if author == nil { + author = &payload.Message.Author + } + if text == "" { + text = strings.TrimSpace(payload.Message.Content) + } + if msgID == "" { + msgID = payload.Message.ID + } + if targetChannelID == "" { + targetChannelID = payload.Message.ChannelID + } + if guildID == "" { + guildID = payload.Message.GuildID + } + if len(attachments) == 0 && len(payload.Message.Attachments) > 0 { + attachments = payload.Message.Attachments + } + if len(embeds) == 0 && len(payload.Message.Embeds) > 0 { + embeds = payload.Message.Embeds + } + } + + if author == nil || author.Bot || strings.TrimSpace(author.ID) == "" { + return nil // Ignore bot messages or invalid authors + } + + // Honour the channel's guild scope. A bot can be invited to several servers, + // and without these checks GuildID and ChannelScope would be stored + // configuration that silently does nothing. + if cfg.GuildID != "" && guildID != cfg.GuildID { + slog.Debug("ignoring discord message from an out-of-scope guild", + "guild_id", guildID, + "channel", channel.ID, + ) + return nil + } + if cfg.ChannelScope == "dm_only" && guildID != "" { + slog.Debug("ignoring discord guild message, channel is dm_only", + "guild_id", guildID, + "channel", channel.ID, + ) + return nil + } + + if text == "" && len(attachments) > 0 { + firstAtt := attachments[0] + if firstAtt.Filename != "" { + text = fmt.Sprintf("[%s] %s", firstAtt.Filename, firstAtt.URL) + } else { + text = firstAtt.URL + } + } + + if text == "" && len(attachments) == 0 && len(embeds) == 0 { + return nil // Ignore empty messages + } + if text == "" && len(embeds) > 0 { + text = embeds[0].Description + if text == "" { + text = embeds[0].Title + } + } + + // 1. Resolve customer identity + externalID := author.ID + name := strings.TrimSpace(author.GlobalName) + if name == "" { + name = strings.TrimSpace(author.Username) + } + if name == "" { + name = fmt.Sprintf("Discord User %s", author.ID) + } + + externalUser := openidentity.ExternalUser{ + ExternalSource: enums.ExternalSourceDiscord, + ExternalID: externalID, + ExternalName: name, + } + + // 2. Create or match Conversation + conversation, err := ConversationService.Create(externalUser, channel.ID, channel.AIAgentID) + if err != nil { + return fmt.Errorf("create discord conversation failed: %w", err) + } + + // 3. Send message through MessageService + clientMsgID := fmt.Sprintf("discord_%s_%s", targetChannelID, msgID) + payloadMap := map[string]any{ + "discord_message_id": msgID, + "discord_channel_id": targetChannelID, + "discord_guild_id": guildID, + "discord_user_id": author.ID, + "discord_attachments": attachments, + } + payloadBytes, _ := json.Marshal(payloadMap) + + _, err = MessageService.SendCustomerMessage( + conversation.ID, + clientMsgID, + enums.IMMessageTypeText, + text, + string(payloadBytes), + externalUser, + ) + if err != nil { + return fmt.Errorf("send customer message failed: %w", err) + } + + return nil +} diff --git a/internal/services/discord_inbound_service_test.go b/internal/services/discord_inbound_service_test.go new file mode 100644 index 00000000..b6c31b24 --- /dev/null +++ b/internal/services/discord_inbound_service_test.go @@ -0,0 +1,294 @@ +package services + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "strings" + "testing" + "time" + + "agent-desk/internal/models" + "agent-desk/internal/pkg/dto" + "agent-desk/internal/pkg/enums" + "agent-desk/internal/repositories" + + "github.com/glebarez/sqlite" + "github.com/mlogclub/simple/sqls" + "gorm.io/gorm" + "gorm.io/gorm/schema" +) + +func setupDiscordTestDB(t *testing.T) *gorm.DB { + t.Helper() + db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{ + NamingStrategy: schema.NamingStrategy{ + TablePrefix: "t_", + SingularTable: true, + }, + }) + if err != nil { + t.Fatalf("open sqlite db: %v", err) + } + if err := db.AutoMigrate( + &models.Channel{}, + &models.ChannelMessageOutbox{}, + &models.Customer{}, + &models.CustomerIdentity{}, + &models.CustomerContact{}, + &models.Conversation{}, + &models.ConversationParticipant{}, + &models.ConversationReadState{}, + &models.ConversationInterrupt{}, + &models.ConversationEventLog{}, + &models.Message{}, + &models.AIAgent{}, + &models.User{}, + &models.Role{}, + &models.UserRole{}, + &models.Permission{}, + &models.RolePermission{}, + &models.UserPermission{}, + ); err != nil { + t.Fatalf("migrate discord test tables: %v", err) + } + sqls.SetDB(db) + return db +} + +func TestDiscordInboundAndOutbound(t *testing.T) { + db := setupDiscordTestDB(t) + + mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write([]byte(`{"id":"out_msg_100","channel_id":"text_chan_1","content":"Agent reply"}`)) + })) + defer mockServer.Close() + + now := time.Now() + aiAgent := &models.AIAgent{ + Name: "Support AI", + Status: enums.StatusOk, + PublishedRevisionID: 1, + AuditFields: models.AuditFields{CreatedAt: now, UpdatedAt: now}, + } + if err := db.Create(aiAgent).Error; err != nil { + t.Fatalf("create ai agent: %v", err) + } + + discordConfig := dto.DiscordChannelConfig{ + GuildID: "guild_12345", + GuildName: "Test Guild", + BotToken: "discord_bot_token", + WebhookSecret: "test_secret", + } + cfgBytes, _ := json.Marshal(discordConfig) + + channel := &models.Channel{ + ChannelType: enums.ChannelTypeDiscord, + ChannelID: "discord_ch_1", + AIAgentID: aiAgent.ID, + AIAgentRolloutPercent: 100, + Name: "Community Support", + ConfigJSON: string(cfgBytes), + Status: enums.StatusOk, + AuditFields: models.AuditFields{CreatedAt: now, UpdatedAt: now}, + } + if err := db.Create(channel).Error; err != nil { + t.Fatalf("create discord channel: %v", err) + } + + payload := `{ + "id": "msg_999", + "channel_id": "text_chan_1", + "guild_id": "guild_12345", + "content": "", + "author": { + "id": "user_888", + "username": "gamer_joy", + "global_name": "Joy Le", + "bot": false + }, + "attachments": [ + { + "id": "att_1", + "filename": "screenshot.png", + "url": "https://cdn.discordapp.com/attachments/1/screenshot.png", + "content_type": "image/png", + "size": 10240 + } + ] + }` + + ctx := context.Background() + err := DiscordInboundService.HandleWebhook(ctx, channel.ChannelID, "test_secret", []byte(payload)) + if err != nil { + t.Fatalf("HandleWebhook failed: %v", err) + } + + // Verify customer identity + identity := repositories.CustomerIdentityRepository.FindOne(sqls.DB(), sqls.NewCnd(). + Eq("external_source", enums.ExternalSourceDiscord). + Eq("external_id", "user_888")) + if identity == nil { + t.Fatalf("expected customer identity to be created") + } + + // Verify conversation + conv := repositories.ConversationRepository.FindOne(sqls.DB(), sqls.NewCnd(). + Eq("customer_id", identity.CustomerID). + Eq("channel_id", channel.ID)) + if conv == nil { + t.Fatalf("expected conversation to be created") + } + + // Verify image message created from attachment + custMsg := repositories.MessageRepository.FindOne(sqls.DB(), sqls.NewCnd(). + Eq("conversation_id", conv.ID). + Eq("sender_type", enums.IMSenderTypeCustomer)) + if custMsg == nil { + t.Fatalf("expected customer message to be created") + } + + operator := &dto.AuthPrincipal{UserID: 1, Nickname: "Agent Joy"} + + // Test Outbound enqueue with Message + replyMsg, err := MessageService.SendAIMessage(conv.ID, aiAgent.ID, "ai_msg_1", enums.IMMessageTypeText, "Here is your response image: https://example.com/response_img.png", "", operator) + if err != nil { + t.Fatalf("MessageService.SendAIMessage failed: %v", err) + } + + outbox := ChannelMessageOutboxService.GetByMessageID(enums.ChannelTypeDiscord, replyMsg.ID) + if outbox == nil { + t.Fatalf("expected outbox entry for discord message") + } + if outbox.SendStatus != string(enums.ChannelMessageOutboxStatusPending) && outbox.SendStatus != string(enums.ChannelMessageOutboxStatusSending) && outbox.SendStatus != string(enums.ChannelMessageOutboxStatusFailed) { + t.Fatalf("unexpected outbox status: %s", outbox.SendStatus) + } +} + +func seedDiscordScopedChannel(t *testing.T, db *gorm.DB, channelID string, cfg dto.DiscordChannelConfig) *models.Channel { + t.Helper() + now := time.Now() + agent := &models.AIAgent{ + Name: "Support AI", + Status: enums.StatusOk, + PublishedRevisionID: 1, + AuditFields: models.AuditFields{CreatedAt: now, UpdatedAt: now}, + } + if err := db.Create(agent).Error; err != nil { + t.Fatalf("create ai agent: %v", err) + } + cfg.BotToken = "discord_bot_token" + cfg.WebhookSecret = "scope_secret" + cfgBytes, err := json.Marshal(cfg) + if err != nil { + t.Fatalf("marshal discord config: %v", err) + } + channel := &models.Channel{ + ChannelType: enums.ChannelTypeDiscord, + ChannelID: channelID, + AIAgentID: agent.ID, + AIAgentRolloutPercent: 100, + Name: "Discord " + channelID, + ConfigJSON: string(cfgBytes), + Status: enums.StatusOk, + AuditFields: models.AuditFields{CreatedAt: now, UpdatedAt: now}, + } + if err := db.Create(channel).Error; err != nil { + t.Fatalf("create discord channel: %v", err) + } + return channel +} + +func discordScopedPayload(t *testing.T, guildID, messageID string) []byte { + t.Helper() + body := map[string]any{ + "id": messageID, + "channel_id": "discord_text_chan", + "content": "hello from discord", + "author": map[string]any{"id": "user_scope", "username": "scoped_user", "bot": false}, + } + if guildID != "" { + body["guild_id"] = guildID + } + raw, err := json.Marshal(body) + if err != nil { + t.Fatalf("marshal payload: %v", err) + } + return raw +} + +// A bot can be invited to several servers, and GuildID and ChannelScope are +// stored on the channel. Messages outside that scope must not create a +// conversation, otherwise the stored scope is configuration that does nothing. +func TestDiscordInboundHonoursGuildScope(t *testing.T) { + db := setupDiscordTestDB(t) + + guildScoped := seedDiscordScopedChannel(t, db, "discord_guild_scoped", dto.DiscordChannelConfig{ + GuildID: "guild_in_scope", + GuildName: "In Scope", + }) + dmOnly := seedDiscordScopedChannel(t, db, "discord_dm_only", dto.DiscordChannelConfig{ + ChannelScope: "dm_only", + }) + unscoped := seedDiscordScopedChannel(t, db, "discord_unscoped", dto.DiscordChannelConfig{}) + + cases := []struct { + name string + channel *models.Channel + guildID string + wantStored bool + }{ + {"matching guild is accepted", guildScoped, "guild_in_scope", true}, + {"another guild is ignored", guildScoped, "guild_elsewhere", false}, + {"a dm is ignored by a guild scoped channel", guildScoped, "", false}, + {"a dm is accepted by a dm_only channel", dmOnly, "", true}, + {"a guild message is ignored by a dm_only channel", dmOnly, "guild_anywhere", false}, + {"an unscoped channel accepts any guild", unscoped, "guild_anywhere", true}, + {"an unscoped channel accepts a dm", unscoped, "", true}, + } + + for _, tc := range cases { + messageID := "scope_" + strings.ReplaceAll(tc.name, " ", "_") + payload := discordScopedPayload(t, tc.guildID, messageID) + + if err := DiscordInboundService.HandleWebhook(context.Background(), tc.channel.ChannelID, "scope_secret", payload); err != nil { + t.Fatalf("%s: HandleWebhook failed: %v", tc.name, err) + } + + var count int64 + if err := db.Table("t_message").Where("client_msg_id LIKE ?", "%"+messageID).Count(&count).Error; err != nil { + t.Fatalf("%s: count messages: %v", tc.name, err) + } + switch { + case tc.wantStored && count == 0: + t.Errorf("%s: expected the message to be stored", tc.name) + case !tc.wantStored && count != 0: + t.Errorf("%s: expected the message to be dropped, found %d", tc.name, count) + } + } +} + +// The webhook secret is compared in constant time, so a wrong secret of the same +// length must be rejected rather than accepted by a prefix match. +func TestDiscordInboundRejectsWrongWebhookSecret(t *testing.T) { + db := setupDiscordTestDB(t) + channel := seedDiscordScopedChannel(t, db, "discord_secret", dto.DiscordChannelConfig{}) + + payload := discordScopedPayload(t, "", "secret_msg_1") + err := DiscordInboundService.HandleWebhook(context.Background(), channel.ChannelID, "wrong_secret_value", payload) + if err == nil { + t.Fatalf("expected a wrong webhook secret to be rejected") + } + + var count int64 + if err := db.Table("t_message").Where("client_msg_id LIKE ?", "%secret_msg_1").Count(&count).Error; err != nil { + t.Fatalf("count messages: %v", err) + } + if count != 0 { + t.Fatalf("a rejected delivery stored %d messages", count) + } +} diff --git a/internal/services/discord_integration_test.go b/internal/services/discord_integration_test.go new file mode 100644 index 00000000..e470bd27 --- /dev/null +++ b/internal/services/discord_integration_test.go @@ -0,0 +1,169 @@ +package services + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + "time" + + "agent-desk/internal/models" + "agent-desk/internal/pkg/dto" + "agent-desk/internal/pkg/dto/request" + "agent-desk/internal/pkg/enums" + "agent-desk/internal/repositories" + + "github.com/glebarez/sqlite" + "github.com/mlogclub/simple/sqls" + "gorm.io/gorm" + "gorm.io/gorm/schema" +) + +func setupDiscordIntegrationTestDB(t *testing.T) *gorm.DB { + t.Helper() + db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{ + NamingStrategy: schema.NamingStrategy{ + TablePrefix: "t_", + SingularTable: true, + }, + }) + if err != nil { + t.Fatalf("open sqlite db: %v", err) + } + if err := db.AutoMigrate( + &models.Channel{}, + &models.ChannelMessageOutbox{}, + &models.Customer{}, + &models.CustomerIdentity{}, + &models.CustomerContact{}, + &models.Conversation{}, + &models.ConversationParticipant{}, + &models.ConversationReadState{}, + &models.ConversationInterrupt{}, + &models.ConversationEventLog{}, + &models.Message{}, + &models.AIAgent{}, + &models.AgentProfile{}, + &models.AgentTeam{}, + &models.User{}, + &models.Role{}, + &models.UserRole{}, + &models.Permission{}, + &models.RolePermission{}, + &models.UserPermission{}, + ); err != nil { + t.Fatalf("migrate discord integration test tables: %v", err) + } + sqls.SetDB(db) + return db +} + +func TestDiscordIntegrationFullFlow(t *testing.T) { + db := setupDiscordIntegrationTestDB(t) + + mockDiscordServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write([]byte(`{"id":"discord_msg_reply_999","channel_id":"ch_discord_general","content":"Cảm ơn bạn! Đội ngũ hỗ trợ sẽ kiểm tra ngay."}`)) + })) + defer mockDiscordServer.Close() + + now := time.Now() + // 1. Create AI Agent + agent := &models.AIAgent{ + Name: "Discord Support AI", + ServiceMode: enums.IMConversationServiceModeAIFirst, + PublishedRevisionID: 1, + WelcomeMessage: "Chào mừng đến với máy chủ Discord Crove Desk!", + Status: enums.StatusOk, + AuditFields: models.AuditFields{ + CreatedAt: now, + UpdatedAt: now, + }, + } + _ = db.Create(agent) + + // 2. Create Discord Channel + discordConfig, _ := json.Marshal(dto.DiscordChannelConfig{ + GuildID: "guild_987654321", + GuildName: "Crove Community Discord", + BotToken: "test-discord-bot-token-xyz", + WebhookSecret: "discord-secret-token-123", + WelcomeMessage: "Welcome to Discord Support!", + }) + + operator := &dto.AuthPrincipal{UserID: 1, Username: "admin"} + channel, err := ChannelService.CreateChannel(request.CreateChannelRequest{ + Name: "Crove Discord Support", + ChannelType: enums.ChannelTypeDiscord, + AIAgentID: agent.ID, + AIAgentRolloutPercent: 100, + ConfigJSON: string(discordConfig), + Status: int(enums.StatusOk), + }, operator) + if err != nil { + t.Fatalf("CreateChannel failed: %v", err) + } + + // 3. Simulate Inbound Discord Webhook / Gateway message from user + inboundPayload := []byte(`{ + "id": "msg_discord_user_001", + "channel_id": "ch_discord_general", + "guild_id": "guild_987654321", + "content": "Tôi muốn hỏi về cách cấu hình Custom Domain cho Email Channel trên Crove Desk", + "author": { + "id": "discord_uid_555", + "username": "gamer_joy", + "global_name": "Anh Le", + "bot": false + } + }`) + + ctx := context.Background() + err = DiscordInboundService.HandleWebhook(ctx, channel.ChannelID, "discord-secret-token-123", inboundPayload) + if err != nil { + t.Fatalf("DiscordInboundService.HandleWebhook failed: %v", err) + } + + // Verify Customer Identity + identity := repositories.CustomerIdentityRepository.FindOne(db, sqls.NewCnd(). + Eq("external_source", enums.ExternalSourceDiscord). + Eq("external_id", "discord_uid_555")) + if identity == nil { + t.Fatalf("expected customer identity for discord_uid_555") + } + + customer := repositories.CustomerRepository.Get(db, identity.CustomerID) + if customer == nil || customer.Name != "Anh Le" { + t.Fatalf("unexpected customer profile: %+v", customer) + } + + // Verify Conversation created + conv := repositories.ConversationRepository.FindOne(db, sqls.NewCnd().Eq("customer_id", customer.ID)) + if conv == nil || conv.ChannelID != channel.ID { + t.Fatalf("unexpected conversation: %+v", conv) + } + + // Verify Customer Message stored + msg := repositories.MessageRepository.FindOne(db, sqls.NewCnd(). + Eq("conversation_id", conv.ID). + Eq("sender_type", enums.IMSenderTypeCustomer)) + if msg == nil || msg.Content != "Tôi muốn hỏi về cách cấu hình Custom Domain cho Email Channel trên Crove Desk" { + t.Fatalf("unexpected stored customer message: %+v", msg) + } + + // 4. Simulate Agent / AI Reply and test Outbox Enqueue & Outbound Dispatch + replyMsg, err := MessageService.SendAIMessage(conv.ID, agent.ID, "ai_reply_001", enums.IMMessageTypeText, "Cảm ơn bạn! Đội ngũ hỗ trợ sẽ kiểm tra ngay.", "", operator) + if err != nil { + t.Fatalf("MessageService.SendAIMessage failed: %v", err) + } + + outbox := ChannelMessageOutboxService.GetByMessageID(enums.ChannelTypeDiscord, replyMsg.ID) + if outbox == nil { + t.Fatalf("expected discord outbox entry for AI message") + } + if outbox.ChannelType != enums.ChannelTypeDiscord { + t.Fatalf("expected outbox channel type 'discord', got '%s'", outbox.ChannelType) + } +} diff --git a/internal/services/discord_outbound_service.go b/internal/services/discord_outbound_service.go new file mode 100644 index 00000000..2024f8af --- /dev/null +++ b/internal/services/discord_outbound_service.go @@ -0,0 +1,231 @@ +package services + +import ( + "context" + "encoding/json" + "log/slog" + "strings" + "time" + + "agent-desk/internal/discord" + "agent-desk/internal/models" + "agent-desk/internal/pkg/config" + "agent-desk/internal/pkg/enums" + "agent-desk/internal/repositories" + "agent-desk/internal/services/storage" + "os" + + "github.com/mlogclub/simple/sqls" +) + +const ( + discordOutboxBatchSize = 20 + discordOutboxMaxRetry = 5 +) + +var DiscordOutboundService = newDiscordOutboundService() + +func newDiscordOutboundService() *discordOutboundService { + return &discordOutboundService{} +} + +type discordOutboundService struct{} + +func (s *discordOutboundService) DispatchPendingOutbox() int { + return s.doDispatchPendingOutbox(discordOutboxBatchSize) +} + +func (s *discordOutboundService) doDispatchPendingOutbox(limit int) int { + if limit <= 0 { + limit = discordOutboxBatchSize + } + items := ChannelMessageOutboxService.ListPending(enums.ChannelTypeDiscord, limit) + if len(items) == 0 { + return 0 + } + + successCount := 0 + for i := range items { + if err := s.processOutbox(items[i].ID); err != nil { + slog.Warn("process discord outbox failed", + "outbox_id", items[i].ID, + "error", err, + ) + continue + } + successCount++ + } + return successCount +} + +func (s *discordOutboundService) processOutbox(outboxID int64) error { + outbox := ChannelMessageOutboxService.Get(outboxID) + if outbox == nil { + return nil + } + if outbox.ChannelType != enums.ChannelTypeDiscord { + return nil + } + if outbox.SendStatus == string(enums.ChannelMessageOutboxStatusSent) { + return nil + } + if outbox.NextRetryAt != nil && outbox.NextRetryAt.After(time.Now()) { + return nil + } + + if err := ChannelMessageOutboxService.Updates(outbox.ID, map[string]any{ + "send_status": string(enums.ChannelMessageOutboxStatusSending), + "updated_at": time.Now(), + }); err != nil { + return err + } + + message := MessageService.Get(outbox.MessageID) + if message == nil { + return s.markOutboxFailed(outbox, "message not found") + } + conversation := ConversationService.Get(outbox.ConversationID) + if conversation == nil { + return s.markOutboxFailed(outbox, "conversation not found") + } + + channel := ChannelService.Get(conversation.ChannelID) + if channel == nil || channel.Status != enums.StatusOk { + return s.markOutboxFailed(outbox, "discord channel not found or disabled") + } + cfg, err := ChannelService.ParseDiscordChannelConfig(channel.ConfigJSON) + if err != nil { + return s.markOutboxFailed(outbox, "invalid discord channel config") + } + botToken := "" + if cfg != nil { + botToken = strings.TrimSpace(cfg.BotToken) + } + if botToken == "" { + botToken = strings.TrimSpace(config.Current().Discord.BotToken) + } + if botToken == "" { + botToken = strings.TrimSpace(os.Getenv("DISCORD_BOT_TOKEN")) + } + if botToken == "" { + return s.markOutboxFailed(outbox, "discord bot token not configured") + } + + // Resolve target Discord User ID and/or Channel ID + var discordUserID string + customerIdentity := repositories.CustomerIdentityRepository.FindOne(sqls.DB(), sqls.NewCnd(). + Eq("customer_id", conversation.CustomerID). + Eq("external_source", enums.ExternalSourceDiscord)) + if customerIdentity != nil { + discordUserID = strings.TrimSpace(customerIdentity.ExternalID) + } + + // Check if there is a discord_channel_id in last message payload + var targetChannelID string + lastCustomerMsg := repositories.MessageRepository.FindOne(sqls.DB(), sqls.NewCnd(). + Eq("conversation_id", conversation.ID). + Eq("sender_type", enums.IMSenderTypeCustomer). + Desc("id")) + if lastCustomerMsg != nil && lastCustomerMsg.Payload != "" { + var payloadMap map[string]any + if err := json.Unmarshal([]byte(lastCustomerMsg.Payload), &payloadMap); err == nil { + if chID, ok := payloadMap["discord_channel_id"].(string); ok && chID != "" { + targetChannelID = chID + } + } + } + + client := discord.NewClient(botToken) + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + + if targetChannelID == "" { + if discordUserID == "" { + return s.markOutboxFailed(outbox, "unable to resolve discord target user or channel") + } + dmChannel, err := client.CreateDMChannel(ctx, discordUserID) + if err != nil { + return s.markOutboxFailed(outbox, "create discord dm channel failed: "+err.Error()) + } + targetChannelID = dmChannel.ID + } + + var sendErr error + if message.MessageType == enums.IMMessageTypeImage { + assetPayload, err := parseIMMessageAssetPayload(message.Payload) + var imageURL string + if err == nil && assetPayload != nil { + assetPayload = hydrateIMMessageAssetPayload(assetPayload) + if assetPayload.Provider != "" && assetPayload.StorageKey != "" { + if provider, err := storage.NewProvider(assetPayload.Provider); err == nil { + imageURL = provider.GetSignedURL(assetPayload.StorageKey) + } + } + } + if imageURL == "" && strings.HasPrefix(strings.TrimSpace(message.Content), "http") { + imageURL = strings.TrimSpace(message.Content) + } + + if imageURL != "" { + embed := discord.Embed{ + Title: "Image Attachment", + Image: &discord.EmbedMedia{URL: imageURL}, + } + _, sendErr = client.SendEmbedMessage(ctx, targetChannelID, message.Content, []discord.Embed{embed}) + } else { + _, sendErr = client.SendMessage(ctx, targetChannelID, message.Content) + } + } else if message.MessageType == enums.IMMessageTypeAttachment { + assetPayload, err := parseIMMessageAssetPayload(message.Payload) + var fileURL string + if err == nil && assetPayload != nil { + assetPayload = hydrateIMMessageAssetPayload(assetPayload) + if assetPayload.Provider != "" && assetPayload.StorageKey != "" { + if provider, err := storage.NewProvider(assetPayload.Provider); err == nil { + fileURL = provider.GetSignedURL(assetPayload.StorageKey) + } + } + } + textToSend := message.Content + if fileURL != "" { + if textToSend != "" { + textToSend += "\n" + fileURL + } else { + textToSend = fileURL + } + } + _, sendErr = client.SendMessage(ctx, targetChannelID, textToSend) + } else { + _, sendErr = client.SendMessage(ctx, targetChannelID, message.Content) + } + + if sendErr != nil { + return s.markOutboxFailed(outbox, sendErr.Error()) + } + + return ChannelMessageOutboxService.Updates(outbox.ID, map[string]any{ + "send_status": string(enums.ChannelMessageOutboxStatusSent), + "sent_at": time.Now(), + "updated_at": time.Now(), + }) +} + +func (s *discordOutboundService) markOutboxFailed(outbox *models.ChannelMessageOutbox, errMsg string) error { + if outbox == nil { + return nil + } + retryCount := outbox.RetryCount + 1 + status := string(enums.ChannelMessageOutboxStatusFailed) + if retryCount >= discordOutboxMaxRetry { + status = string(enums.ChannelMessageOutboxStatusIgnored) + } + nextRetryAt := time.Now().Add(time.Duration(retryCount*30) * time.Second) + + return ChannelMessageOutboxService.Updates(outbox.ID, map[string]any{ + "send_status": status, + "retry_count": retryCount, + "next_retry_at": &nextRetryAt, + "last_error": errMsg, + "updated_at": time.Now(), + }) +} diff --git a/internal/services/message_service.go b/internal/services/message_service.go index 48464472..b892b182 100644 --- a/internal/services/message_service.go +++ b/internal/services/message_service.go @@ -559,6 +559,15 @@ func (s *messageService) sendValidatedMessage(conversation *models.Conversation, ) } + // Discord 渠道消息入队,异步发送 + if enqueueErr := ChannelMessageOutboxService.EnqueueDiscordMessage(conversation, message); enqueueErr != nil { + slog.Error("enqueue discord outbox failed", + "conversation_id", conversation.ID, + "message_id", message.ID, + "error", enqueueErr, + ) + } + // 客户发送消息,触发AI回复 if senderType == enums.IMSenderTypeCustomer { if TriggerAIReplyAsyncHook != nil { diff --git a/web/app/(dashboard)/dashboard/channels/_components/edit.tsx b/web/app/(dashboard)/dashboard/channels/_components/edit.tsx index c5b96168..26ff48b7 100644 --- a/web/app/(dashboard)/dashboard/channels/_components/edit.tsx +++ b/web/app/(dashboard)/dashboard/channels/_components/edit.tsx @@ -73,6 +73,13 @@ type ZaloOAChannelConfig = { webhookSecret?: string } +type DiscordChannelConfig = { + guildId?: string + guildName?: string + botToken?: string + webhookSecret?: string +} + function getDefaultWebChannelConfig(t: Translate): Required