diff --git a/.env.example b/.env.example
index 4fd526f569..e746737ea4 100644
--- a/.env.example
+++ b/.env.example
@@ -47,6 +47,10 @@ TRUST_PROXY=1
# password policies.
# MIN_PASSWORD_LENGTH=8
+# When enabled, the app will continue running after encountering uncaught exceptions
+# instead of exiting the process. Not recommended for production unless necessary.
+# CONTINUE_ON_UNCAUGHT_EXCEPTION=false
+
#===============#
# JSON Logging #
#===============#
@@ -61,6 +65,9 @@ CONSOLE_JSON=false
DEBUG_LOGGING=true
DEBUG_CONSOLE=false
+# Enable memory diagnostics (logs heap/RSS snapshots every 60s, auto-enabled with --inspect)
+# MEM_DIAG=true
+
#=============#
# Permissions #
#=============#
@@ -131,7 +138,7 @@ PROXY=
#============#
ANTHROPIC_API_KEY=user_provided
-# ANTHROPIC_MODELS=claude-opus-4-6,claude-opus-4-20250514,claude-sonnet-4-20250514,claude-3-7-sonnet-20250219,claude-3-5-sonnet-20241022,claude-3-5-haiku-20241022,claude-3-opus-20240229,claude-3-sonnet-20240229,claude-3-haiku-20240307
+# ANTHROPIC_MODELS=claude-sonnet-4-6,claude-opus-4-6,claude-opus-4-20250514,claude-sonnet-4-20250514,claude-3-7-sonnet-20250219,claude-3-5-sonnet-20241022,claude-3-5-haiku-20241022,claude-3-opus-20240229,claude-3-sonnet-20240229,claude-3-haiku-20240307
# ANTHROPIC_REVERSE_PROXY=
# Set to true to use Anthropic models through Google Vertex AI instead of direct API
@@ -166,8 +173,8 @@ ANTHROPIC_API_KEY=user_provided
# BEDROCK_AWS_SESSION_TOKEN=someSessionToken
# Note: This example list is not meant to be exhaustive. If omitted, all known, supported model IDs will be included for you.
-# BEDROCK_AWS_MODELS=anthropic.claude-opus-4-6-v1,anthropic.claude-3-5-sonnet-20240620-v1:0,meta.llama3-1-8b-instruct-v1:0
-# Cross-region inference model IDs: us.anthropic.claude-opus-4-6-v1,global.anthropic.claude-opus-4-6-v1
+# BEDROCK_AWS_MODELS=anthropic.claude-sonnet-4-6,anthropic.claude-opus-4-6-v1,anthropic.claude-3-5-sonnet-20240620-v1:0,meta.llama3-1-8b-instruct-v1:0
+# Cross-region inference model IDs: us.anthropic.claude-sonnet-4-6,us.anthropic.claude-opus-4-6-v1,global.anthropic.claude-opus-4-6-v1
# See all Bedrock model IDs here: https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids.html#model-ids-arns
@@ -189,10 +196,10 @@ GOOGLE_KEY=user_provided
# GOOGLE_AUTH_HEADER=true
# Gemini API (AI Studio)
-# GOOGLE_MODELS=gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite,gemini-2.0-flash,gemini-2.0-flash-lite
+# GOOGLE_MODELS=gemini-3.1-pro-preview,gemini-3.1-pro-preview-customtools,gemini-3.1-flash-lite-preview,gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite,gemini-2.0-flash,gemini-2.0-flash-lite
# Vertex AI
-# GOOGLE_MODELS=gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite,gemini-2.0-flash-001,gemini-2.0-flash-lite-001
+# GOOGLE_MODELS=gemini-3.1-pro-preview,gemini-3.1-pro-preview-customtools,gemini-3.1-flash-lite-preview,gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite,gemini-2.0-flash-001,gemini-2.0-flash-lite-001
# GOOGLE_TITLE_MODEL=gemini-2.0-flash-lite-001
@@ -239,10 +246,6 @@ GOOGLE_KEY=user_provided
# Option A: Use dedicated Gemini API key for image generation
# GEMINI_API_KEY=your-gemini-api-key
-# Option B: Use Vertex AI (no API key needed, uses service account)
-# Set this to enable Vertex AI and allow tool without requiring API keys
-# GEMINI_VERTEX_ENABLED=true
-
# Vertex AI model for image generation (defaults to gemini-2.5-flash-image)
# GEMINI_IMAGE_MODEL=gemini-2.5-flash-image
@@ -510,6 +513,9 @@ OPENID_ADMIN_ROLE_TOKEN_KIND=
OPENID_USERNAME_CLAIM=
# Set to determine which user info property returned from OpenID Provider to store as the User's name
OPENID_NAME_CLAIM=
+# Set to determine which user info claim to use as the email/identifier for user matching (e.g., "upn" for Entra ID)
+# When not set, defaults to: email -> preferred_username -> upn
+OPENID_EMAIL_CLAIM=
# Optional audience parameter for OpenID authorization requests
OPENID_AUDIENCE=
@@ -654,6 +660,9 @@ AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=
AWS_BUCKET_NAME=
+# Required for path-style S3-compatible providers (MinIO, Hetzner, Backblaze B2, etc.)
+# that don't support virtual-hosted-style URLs (bucket.endpoint). Not needed for AWS S3.
+# AWS_FORCE_PATH_STYLE=false
#========================#
# Azure Blob Storage #
@@ -668,7 +677,8 @@ AZURE_CONTAINER_NAME=files
#========================#
ALLOW_SHARED_LINKS=true
-ALLOW_SHARED_LINKS_PUBLIC=true
+# Allows unauthenticated access to shared links. Defaults to false (auth required) if not set.
+ALLOW_SHARED_LINKS_PUBLIC=false
#==============================#
# Static File Cache Control #
@@ -840,3 +850,24 @@ OPENWEATHER_API_KEY=
# Skip code challenge method validation (e.g., for AWS Cognito that supports S256 but doesn't advertise it)
# When set to true, forces S256 code challenge even if not advertised in .well-known/openid-configuration
# MCP_SKIP_CODE_CHALLENGE_CHECK=false
+
+# Circuit breaker: max connect/disconnect cycles before tripping (per server)
+# MCP_CB_MAX_CYCLES=7
+
+# Circuit breaker: sliding window (ms) for counting cycles
+# MCP_CB_CYCLE_WINDOW_MS=45000
+
+# Circuit breaker: cooldown (ms) after the cycle breaker trips
+# MCP_CB_CYCLE_COOLDOWN_MS=15000
+
+# Circuit breaker: max consecutive failed connection rounds before backoff
+# MCP_CB_MAX_FAILED_ROUNDS=3
+
+# Circuit breaker: sliding window (ms) for counting failed rounds
+# MCP_CB_FAILED_WINDOW_MS=120000
+
+# Circuit breaker: base backoff (ms) after failed round threshold is reached
+# MCP_CB_BASE_BACKOFF_MS=30000
+
+# Circuit breaker: max backoff cap (ms) for exponential backoff
+# MCP_CB_MAX_BACKOFF_MS=300000
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index ad0a75ab9b..ae9e6d8e4b 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -26,18 +26,14 @@ Project maintainers have the right and responsibility to remove, edit, or reject
## 1. Development Setup
-1. Use Node.JS 20.x.
-2. Install typescript globally: `npm i -g typescript`.
-3. Run `npm ci` to install dependencies.
-4. Build the data provider: `npm run build:data-provider`.
-5. Build data schemas: `npm run build:data-schemas`.
-6. Build API methods: `npm run build:api`.
-7. Setup and run unit tests:
+1. Use Node.js v20.19.0+ or ^22.12.0 or >= 23.0.0.
+2. Run `npm run smart-reinstall` to install dependencies (uses Turborepo). Use `npm run reinstall` for a clean install, or `npm ci` for a fresh lockfile-based install.
+3. Build all compiled code: `npm run build`.
+4. Setup and run unit tests:
- Copy `.env.test`: `cp api/test/.env.test.example api/test/.env.test`.
- Run backend unit tests: `npm run test:api`.
- Run frontend unit tests: `npm run test:client`.
-8. Setup and run integration tests:
- - Build client: `cd client && npm run build`.
+5. Setup and run integration tests:
- Create `.env`: `cp .env.example .env`.
- Install [MongoDB Community Edition](https://www.mongodb.com/docs/manual/administration/install-community/), ensure that `mongosh` connects to your local instance.
- Run: `npx install playwright`, then `npx playwright install`.
@@ -48,11 +44,11 @@ Project maintainers have the right and responsibility to remove, edit, or reject
## 2. Development Notes
1. Before starting work, make sure your main branch has the latest commits with `npm run update`.
-3. Run linting command to find errors: `npm run lint`. Alternatively, ensure husky pre-commit checks are functioning.
+2. Run linting command to find errors: `npm run lint`. Alternatively, ensure husky pre-commit checks are functioning.
3. After your changes, reinstall packages in your current branch using `npm run reinstall` and ensure everything still works.
- Restart the ESLint server ("ESLint: Restart ESLint Server" in VS Code command bar) and your IDE after reinstalling or updating.
4. Clear web app localStorage and cookies before and after changes.
-5. For frontend changes, compile typescript before and after changes to check for introduced errors: `cd client && npm run build`.
+5. To check for introduced errors, build all compiled code: `npm run build`.
6. Run backend unit tests: `npm run test:api`.
7. Run frontend unit tests: `npm run test:client`.
8. Run integration tests: `npm run e2e`.
@@ -118,50 +114,45 @@ Apply the following naming conventions to branches, labels, and other Git-relate
- **JS/TS:** Directories and file names: Descriptive and camelCase. First letter uppercased for React files (e.g., `helperFunction.ts, ReactComponent.tsx`).
- **Docs:** Directories and file names: Descriptive and snake_case (e.g., `config_files.md`).
-## 7. TypeScript Conversion
+## 7. Coding Standards
+
+For detailed coding conventions, workspace boundaries, and architecture guidance, refer to the [`AGENTS.md`](../AGENTS.md) file at the project root. It covers code style, type safety, import ordering, iteration/performance expectations, frontend rules, testing, and development commands.
+
+## 8. TypeScript Conversion
1. **Original State**: The project was initially developed entirely in JavaScript (JS).
-2. **Frontend Transition**:
- - We are in the process of transitioning the frontend from JS to TypeScript (TS).
- - The transition is nearing completion.
- - This conversion is feasible due to React's capability to intermix JS and TS prior to code compilation. It's standard practice to compile/bundle the code in such scenarios.
+2. **Frontend**: Fully transitioned to TypeScript.
-3. **Backend Considerations**:
- - Transitioning the backend to TypeScript would be a more intricate process, especially for an established Express.js server.
-
- - **Options for Transition**:
- - **Single Phase Overhaul**: This involves converting the entire backend to TypeScript in one go. It's the most straightforward approach but can be disruptive, especially for larger codebases.
-
- - **Incremental Transition**: Convert parts of the backend progressively. This can be done by:
- - Maintaining a separate directory for TypeScript files.
- - Gradually migrating and testing individual modules or routes.
- - Using a build tool like `tsc` to compile TypeScript files independently until the entire transition is complete.
-
- - **Compilation Considerations**:
- - Introducing a compilation step for the server is an option. This would involve using tools like `ts-node` for development and `tsc` for production builds.
- - However, this is not a conventional approach for Express.js servers and could introduce added complexity, especially in terms of build and deployment processes.
-
- - **Current Stance**: At present, this backend transition is of lower priority and might not be pursued.
+3. **Backend**:
+ - The legacy Express.js server remains in `/api` as JavaScript.
+ - All new backend code is written in TypeScript under `/packages/api`, which is compiled and consumed by `/api`.
+ - Shared database logic lives in `/packages/data-schemas` (TypeScript).
+ - Shared frontend/backend API types and services live in `/packages/data-provider` (TypeScript).
+ - Minimize direct changes to `/api`; prefer adding TypeScript code to `/packages/api` and importing it.
-## 8. Module Import Conventions
+## 9. Module Import Conventions
-- `npm` packages first,
- - from longest line (top) to shortest (bottom)
+Imports are organized into three sections (in order):
-- Followed by typescript types (pertains to data-provider and client workspaces)
- - longest line (top) to shortest (bottom)
- - types from package come first
+1. **Package imports** — sorted from shortest to longest line length.
+ - `react` is always the first import.
+ - Multi-line (stacked) imports count their total character length across all lines for sorting.
-- Lastly, local imports
- - longest line (top) to shortest (bottom)
- - imports with alias `~` treated the same as relative import with respect to line length
+2. **`import type` imports** — sorted from longest to shortest line length.
+ - Package type imports come first, then local type imports.
+ - Line length sorting resets between the package and local sub-groups.
+
+3. **Local/project imports** — sorted from longest to shortest line length.
+ - Multi-line (stacked) imports count their total character length across all lines for sorting.
+ - Imports with alias `~` are treated the same as relative imports with respect to line length.
+
+- Consolidate value imports from the same module as much as possible.
+- Always use standalone `import type { ... }` for type imports; never use inline `type` keyword inside value imports (e.g., `import { Foo, type Bar }` is wrong).
**Note:** ESLint will automatically enforce these import conventions when you run `npm run lint --fix` or through pre-commit hooks.
----
-
-Please ensure that you adapt this summary to fit the specific context and nuances of your project.
+For the full set of coding standards, see [`AGENTS.md`](../AGENTS.md).
---
diff --git a/.github/workflows/backend-review.yml b/.github/workflows/backend-review.yml
index 2379b8fee7..038c90627e 100644
--- a/.github/workflows/backend-review.yml
+++ b/.github/workflows/backend-review.yml
@@ -9,48 +9,145 @@ on:
paths:
- 'api/**'
- 'packages/**'
+
+env:
+ NODE_ENV: CI
+ NODE_OPTIONS: '--max-old-space-size=${{ secrets.NODE_MAX_OLD_SPACE_SIZE || 6144 }}'
+
jobs:
- tests_Backend:
- name: Run Backend unit tests
- timeout-minutes: 60
+ build:
+ name: Build packages
runs-on: ubuntu-latest
- env:
- MONGO_URI: ${{ secrets.MONGO_URI }}
- OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
- JWT_SECRET: ${{ secrets.JWT_SECRET }}
- CREDS_KEY: ${{ secrets.CREDS_KEY }}
- CREDS_IV: ${{ secrets.CREDS_IV }}
- BAN_VIOLATIONS: ${{ secrets.BAN_VIOLATIONS }}
- BAN_DURATION: ${{ secrets.BAN_DURATION }}
- BAN_INTERVAL: ${{ secrets.BAN_INTERVAL }}
- NODE_ENV: CI
- NODE_OPTIONS: '--max-old-space-size=${{ secrets.NODE_MAX_OLD_SPACE_SIZE || 6144 }}'
+ timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- - name: Use Node.js 20.x
+
+ - name: Use Node.js 20.19
uses: actions/setup-node@v4
with:
- node-version: 20
- cache: 'npm'
+ node-version: '20.19'
+
+ - name: Restore node_modules cache
+ id: cache-node-modules
+ uses: actions/cache@v4
+ with:
+ path: |
+ node_modules
+ api/node_modules
+ packages/api/node_modules
+ packages/data-provider/node_modules
+ packages/data-schemas/node_modules
+ key: node-modules-backend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }}
- name: Install dependencies
+ if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: npm ci
- - name: Install Data Provider Package
+ - name: Restore data-provider build cache
+ id: cache-data-provider
+ uses: actions/cache@v4
+ with:
+ path: packages/data-provider/dist
+ key: build-data-provider-${{ runner.os }}-${{ hashFiles('packages/data-provider/src/**', 'packages/data-provider/tsconfig*.json', 'packages/data-provider/rollup.config.js', 'packages/data-provider/package.json') }}
+
+ - name: Build data-provider
+ if: steps.cache-data-provider.outputs.cache-hit != 'true'
run: npm run build:data-provider
- - name: Install Data Schemas Package
+ - name: Restore data-schemas build cache
+ id: cache-data-schemas
+ uses: actions/cache@v4
+ with:
+ path: packages/data-schemas/dist
+ key: build-data-schemas-${{ runner.os }}-${{ hashFiles('packages/data-schemas/src/**', 'packages/data-schemas/tsconfig*.json', 'packages/data-schemas/rollup.config.js', 'packages/data-schemas/package.json', 'packages/data-provider/src/**', 'packages/data-provider/tsconfig*.json', 'packages/data-provider/rollup.config.js', 'packages/data-provider/package.json') }}
+
+ - name: Build data-schemas
+ if: steps.cache-data-schemas.outputs.cache-hit != 'true'
run: npm run build:data-schemas
- - name: Install API Package
+ - name: Restore api build cache
+ id: cache-api
+ uses: actions/cache@v4
+ with:
+ path: packages/api/dist
+ key: build-api-${{ runner.os }}-${{ hashFiles('packages/api/src/**', 'packages/api/tsconfig*.json', 'packages/api/server-rollup.config.js', 'packages/api/package.json', 'packages/data-provider/src/**', 'packages/data-provider/tsconfig*.json', 'packages/data-provider/rollup.config.js', 'packages/data-provider/package.json', 'packages/data-schemas/src/**', 'packages/data-schemas/tsconfig*.json', 'packages/data-schemas/rollup.config.js', 'packages/data-schemas/package.json') }}
+
+ - name: Build api
+ if: steps.cache-api.outputs.cache-hit != 'true'
run: npm run build:api
- - name: Create empty auth.json file
- run: |
- mkdir -p api/data
- echo '{}' > api/data/auth.json
+ - name: Upload data-provider build
+ uses: actions/upload-artifact@v4
+ with:
+ name: build-data-provider
+ path: packages/data-provider/dist
+ retention-days: 2
- - name: Check for Circular dependency in rollup
+ - name: Upload data-schemas build
+ uses: actions/upload-artifact@v4
+ with:
+ name: build-data-schemas
+ path: packages/data-schemas/dist
+ retention-days: 2
+
+ - name: Upload api build
+ uses: actions/upload-artifact@v4
+ with:
+ name: build-api
+ path: packages/api/dist
+ retention-days: 2
+
+ circular-deps:
+ name: Circular dependency checks
+ needs: build
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Use Node.js 20.19
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20.19'
+
+ - name: Restore node_modules cache
+ id: cache-node-modules
+ uses: actions/cache@v4
+ with:
+ path: |
+ node_modules
+ api/node_modules
+ packages/api/node_modules
+ packages/data-provider/node_modules
+ packages/data-schemas/node_modules
+ key: node-modules-backend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }}
+
+ - name: Install dependencies
+ if: steps.cache-node-modules.outputs.cache-hit != 'true'
+ run: npm ci
+
+ - name: Download data-provider build
+ uses: actions/download-artifact@v4
+ with:
+ name: build-data-provider
+ path: packages/data-provider/dist
+
+ - name: Download data-schemas build
+ uses: actions/download-artifact@v4
+ with:
+ name: build-data-schemas
+ path: packages/data-schemas/dist
+
+ - name: Rebuild @librechat/api and check for circular dependencies
+ run: |
+ output=$(npm run build:api 2>&1)
+ echo "$output"
+ if echo "$output" | grep -q "Circular depend"; then
+ echo "Error: Circular dependency detected in @librechat/api!"
+ exit 1
+ fi
+
+ - name: Detect circular dependencies in rollup
working-directory: ./packages/data-provider
run: |
output=$(npm run rollup:api)
@@ -60,17 +157,201 @@ jobs:
exit 1
fi
+ test-api:
+ name: 'Tests: api'
+ needs: build
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ env:
+ MONGO_URI: ${{ secrets.MONGO_URI }}
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
+ JWT_SECRET: ${{ secrets.JWT_SECRET }}
+ CREDS_KEY: ${{ secrets.CREDS_KEY }}
+ CREDS_IV: ${{ secrets.CREDS_IV }}
+ BAN_VIOLATIONS: ${{ secrets.BAN_VIOLATIONS }}
+ BAN_DURATION: ${{ secrets.BAN_DURATION }}
+ BAN_INTERVAL: ${{ secrets.BAN_INTERVAL }}
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Use Node.js 20.19
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20.19'
+
+ - name: Restore node_modules cache
+ id: cache-node-modules
+ uses: actions/cache@v4
+ with:
+ path: |
+ node_modules
+ api/node_modules
+ packages/api/node_modules
+ packages/data-provider/node_modules
+ packages/data-schemas/node_modules
+ key: node-modules-backend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }}
+
+ - name: Install dependencies
+ if: steps.cache-node-modules.outputs.cache-hit != 'true'
+ run: npm ci
+
+ - name: Download data-provider build
+ uses: actions/download-artifact@v4
+ with:
+ name: build-data-provider
+ path: packages/data-provider/dist
+
+ - name: Download data-schemas build
+ uses: actions/download-artifact@v4
+ with:
+ name: build-data-schemas
+ path: packages/data-schemas/dist
+
+ - name: Download api build
+ uses: actions/download-artifact@v4
+ with:
+ name: build-api
+ path: packages/api/dist
+
+ - name: Create empty auth.json file
+ run: |
+ mkdir -p api/data
+ echo '{}' > api/data/auth.json
+
- name: Prepare .env.test file
run: cp api/test/.env.test.example api/test/.env.test
- name: Run unit tests
run: cd api && npm run test:ci
- - name: Run librechat-data-provider unit tests
+ test-data-provider:
+ name: 'Tests: data-provider'
+ needs: build
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Use Node.js 20.19
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20.19'
+
+ - name: Restore node_modules cache
+ id: cache-node-modules
+ uses: actions/cache@v4
+ with:
+ path: |
+ node_modules
+ api/node_modules
+ packages/api/node_modules
+ packages/data-provider/node_modules
+ packages/data-schemas/node_modules
+ key: node-modules-backend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }}
+
+ - name: Install dependencies
+ if: steps.cache-node-modules.outputs.cache-hit != 'true'
+ run: npm ci
+
+ - name: Download data-provider build
+ uses: actions/download-artifact@v4
+ with:
+ name: build-data-provider
+ path: packages/data-provider/dist
+
+ - name: Run unit tests
run: cd packages/data-provider && npm run test:ci
- - name: Run @librechat/data-schemas unit tests
+ test-data-schemas:
+ name: 'Tests: data-schemas'
+ needs: build
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Use Node.js 20.19
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20.19'
+
+ - name: Restore node_modules cache
+ id: cache-node-modules
+ uses: actions/cache@v4
+ with:
+ path: |
+ node_modules
+ api/node_modules
+ packages/api/node_modules
+ packages/data-provider/node_modules
+ packages/data-schemas/node_modules
+ key: node-modules-backend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }}
+
+ - name: Install dependencies
+ if: steps.cache-node-modules.outputs.cache-hit != 'true'
+ run: npm ci
+
+ - name: Download data-provider build
+ uses: actions/download-artifact@v4
+ with:
+ name: build-data-provider
+ path: packages/data-provider/dist
+
+ - name: Download data-schemas build
+ uses: actions/download-artifact@v4
+ with:
+ name: build-data-schemas
+ path: packages/data-schemas/dist
+
+ - name: Run unit tests
run: cd packages/data-schemas && npm run test:ci
- - name: Run @librechat/api unit tests
+ test-packages-api:
+ name: 'Tests: @librechat/api'
+ needs: build
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Use Node.js 20.19
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20.19'
+
+ - name: Restore node_modules cache
+ id: cache-node-modules
+ uses: actions/cache@v4
+ with:
+ path: |
+ node_modules
+ api/node_modules
+ packages/api/node_modules
+ packages/data-provider/node_modules
+ packages/data-schemas/node_modules
+ key: node-modules-backend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }}
+
+ - name: Install dependencies
+ if: steps.cache-node-modules.outputs.cache-hit != 'true'
+ run: npm ci
+
+ - name: Download data-provider build
+ uses: actions/download-artifact@v4
+ with:
+ name: build-data-provider
+ path: packages/data-provider/dist
+
+ - name: Download data-schemas build
+ uses: actions/download-artifact@v4
+ with:
+ name: build-data-schemas
+ path: packages/data-schemas/dist
+
+ - name: Download api build
+ uses: actions/download-artifact@v4
+ with:
+ name: build-api
+ path: packages/api/dist
+
+ - name: Run unit tests
run: cd packages/api && npm run test:ci
diff --git a/.github/workflows/frontend-review.yml b/.github/workflows/frontend-review.yml
index 989e2e4abe..9c2d4a37b1 100644
--- a/.github/workflows/frontend-review.yml
+++ b/.github/workflows/frontend-review.yml
@@ -2,7 +2,7 @@ name: Frontend Unit Tests
on:
pull_request:
- branches:
+ branches:
- main
- dev
- dev-staging
@@ -11,51 +11,200 @@ on:
- 'client/**'
- 'packages/data-provider/**'
+env:
+ NODE_OPTIONS: '--max-old-space-size=${{ secrets.NODE_MAX_OLD_SPACE_SIZE || 6144 }}'
+
jobs:
- tests_frontend_ubuntu:
- name: Run frontend unit tests on Ubuntu
- timeout-minutes: 60
+ build:
+ name: Build packages
runs-on: ubuntu-latest
- env:
- NODE_OPTIONS: '--max-old-space-size=${{ secrets.NODE_MAX_OLD_SPACE_SIZE || 6144 }}'
+ timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- - name: Use Node.js 20.x
+
+ - name: Use Node.js 20.19
uses: actions/setup-node@v4
with:
- node-version: 20
- cache: 'npm'
+ node-version: '20.19'
+
+ - name: Restore node_modules cache
+ id: cache-node-modules
+ uses: actions/cache@v4
+ with:
+ path: |
+ node_modules
+ client/node_modules
+ packages/client/node_modules
+ packages/data-provider/node_modules
+ key: node-modules-frontend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }}
- name: Install dependencies
+ if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: npm ci
- - name: Build Client
- run: npm run frontend:ci
+ - name: Restore data-provider build cache
+ id: cache-data-provider
+ uses: actions/cache@v4
+ with:
+ path: packages/data-provider/dist
+ key: build-data-provider-${{ runner.os }}-${{ hashFiles('packages/data-provider/src/**', 'packages/data-provider/tsconfig*.json', 'packages/data-provider/rollup.config.js', 'packages/data-provider/package.json') }}
+
+ - name: Build data-provider
+ if: steps.cache-data-provider.outputs.cache-hit != 'true'
+ run: npm run build:data-provider
+
+ - name: Restore client-package build cache
+ id: cache-client-package
+ uses: actions/cache@v4
+ with:
+ path: packages/client/dist
+ key: build-client-package-${{ runner.os }}-${{ hashFiles('packages/client/src/**', 'packages/client/tsconfig*.json', 'packages/client/rollup.config.js', 'packages/client/package.json', 'packages/data-provider/src/**', 'packages/data-provider/tsconfig*.json', 'packages/data-provider/rollup.config.js', 'packages/data-provider/package.json') }}
+
+ - name: Build client-package
+ if: steps.cache-client-package.outputs.cache-hit != 'true'
+ run: npm run build:client-package
+
+ - name: Upload data-provider build
+ uses: actions/upload-artifact@v4
+ with:
+ name: build-data-provider
+ path: packages/data-provider/dist
+ retention-days: 2
+
+ - name: Upload client-package build
+ uses: actions/upload-artifact@v4
+ with:
+ name: build-client-package
+ path: packages/client/dist
+ retention-days: 2
+
+ test-ubuntu:
+ name: 'Tests: Ubuntu'
+ needs: build
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Use Node.js 20.19
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20.19'
+
+ - name: Restore node_modules cache
+ id: cache-node-modules
+ uses: actions/cache@v4
+ with:
+ path: |
+ node_modules
+ client/node_modules
+ packages/client/node_modules
+ packages/data-provider/node_modules
+ key: node-modules-frontend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }}
+
+ - name: Install dependencies
+ if: steps.cache-node-modules.outputs.cache-hit != 'true'
+ run: npm ci
+
+ - name: Download data-provider build
+ uses: actions/download-artifact@v4
+ with:
+ name: build-data-provider
+ path: packages/data-provider/dist
+
+ - name: Download client-package build
+ uses: actions/download-artifact@v4
+ with:
+ name: build-client-package
+ path: packages/client/dist
- name: Run unit tests
run: npm run test:ci --verbose
working-directory: client
- tests_frontend_windows:
- name: Run frontend unit tests on Windows
- timeout-minutes: 60
+ test-windows:
+ name: 'Tests: Windows'
+ needs: build
runs-on: windows-latest
- env:
- NODE_OPTIONS: '--max-old-space-size=${{ secrets.NODE_MAX_OLD_SPACE_SIZE || 6144 }}'
+ timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- - name: Use Node.js 20.x
+
+ - name: Use Node.js 20.19
uses: actions/setup-node@v4
with:
- node-version: 20
- cache: 'npm'
+ node-version: '20.19'
+
+ - name: Restore node_modules cache
+ id: cache-node-modules
+ uses: actions/cache@v4
+ with:
+ path: |
+ node_modules
+ client/node_modules
+ packages/client/node_modules
+ packages/data-provider/node_modules
+ key: node-modules-frontend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }}
- name: Install dependencies
+ if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: npm ci
- - name: Build Client
- run: npm run frontend:ci
+ - name: Download data-provider build
+ uses: actions/download-artifact@v4
+ with:
+ name: build-data-provider
+ path: packages/data-provider/dist
+
+ - name: Download client-package build
+ uses: actions/download-artifact@v4
+ with:
+ name: build-client-package
+ path: packages/client/dist
- name: Run unit tests
run: npm run test:ci --verbose
- working-directory: client
\ No newline at end of file
+ working-directory: client
+
+ build-verify:
+ name: Vite build verification
+ needs: build
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Use Node.js 20.19
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20.19'
+
+ - name: Restore node_modules cache
+ id: cache-node-modules
+ uses: actions/cache@v4
+ with:
+ path: |
+ node_modules
+ client/node_modules
+ packages/client/node_modules
+ packages/data-provider/node_modules
+ key: node-modules-frontend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }}
+
+ - name: Install dependencies
+ if: steps.cache-node-modules.outputs.cache-hit != 'true'
+ run: npm ci
+
+ - name: Download data-provider build
+ uses: actions/download-artifact@v4
+ with:
+ name: build-data-provider
+ path: packages/data-provider/dist
+
+ - name: Download client-package build
+ uses: actions/download-artifact@v4
+ with:
+ name: build-client-package
+ path: packages/client/dist
+
+ - name: Build client
+ run: cd client && npm run build:ci
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000000..ec44607aa7
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,166 @@
+# LibreChat
+
+## Project Overview
+
+LibreChat is a monorepo with the following key workspaces:
+
+| Workspace | Language | Side | Dependency | Purpose |
+|---|---|---|---|---|
+| `/api` | JS (legacy) | Backend | `packages/api`, `packages/data-schemas`, `packages/data-provider`, `@librechat/agents` | Express server — minimize changes here |
+| `/packages/api` | **TypeScript** | Backend | `packages/data-schemas`, `packages/data-provider` | New backend code lives here (TS only, consumed by `/api`) |
+| `/packages/data-schemas` | TypeScript | Backend | `packages/data-provider` | Database models/schemas, shareable across backend projects |
+| `/packages/data-provider` | TypeScript | Shared | — | Shared API types, endpoints, data-service — used by both frontend and backend |
+| `/client` | TypeScript/React | Frontend | `packages/data-provider`, `packages/client` | Frontend SPA |
+| `/packages/client` | TypeScript | Frontend | `packages/data-provider` | Shared frontend utilities |
+
+The source code for `@librechat/agents` (major backend dependency, same team) is at `/home/danny/agentus`.
+
+---
+
+## Workspace Boundaries
+
+- **All new backend code must be TypeScript** in `/packages/api`.
+- Keep `/api` changes to the absolute minimum (thin JS wrappers calling into `/packages/api`).
+- Database-specific shared logic goes in `/packages/data-schemas`.
+- Frontend/backend shared API logic (endpoints, types, data-service) goes in `/packages/data-provider`.
+- Build data-provider from project root: `npm run build:data-provider`.
+
+---
+
+## Code Style
+
+### Structure and Clarity
+
+- **Never-nesting**: early returns, flat code, minimal indentation. Break complex operations into well-named helpers.
+- **Functional first**: pure functions, immutable data, `map`/`filter`/`reduce` over imperative loops. Only reach for OOP when it clearly improves domain modeling or state encapsulation.
+- **No dynamic imports** unless absolutely necessary.
+
+### DRY
+
+- Extract repeated logic into utility functions.
+- Reusable hooks / higher-order components for UI patterns.
+- Parameterized helpers instead of near-duplicate functions.
+- Constants for repeated values; configuration objects over duplicated init code.
+- Shared validators, centralized error handling, single source of truth for business rules.
+- Shared typing system with interfaces/types extending common base definitions.
+- Abstraction layers for external API interactions.
+
+### Iteration and Performance
+
+- **Minimize looping** — especially over shared data structures like message arrays, which are iterated frequently throughout the codebase. Every additional pass adds up at scale.
+- Consolidate sequential O(n) operations into a single pass whenever possible; never loop over the same collection twice if the work can be combined.
+- Choose data structures that reduce the need to iterate (e.g., `Map`/`Set` for lookups instead of `Array.find`/`Array.includes`).
+- Avoid unnecessary object creation; consider space-time tradeoffs.
+- Prevent memory leaks: careful with closures, dispose resources/event listeners, no circular references.
+
+### Type Safety
+
+- **Never use `any`**. Explicit types for all parameters, return values, and variables.
+- **Limit `unknown`** — avoid `unknown`, `Record`, and `as unknown as T` assertions. A `Record` almost always signals a missing explicit type definition.
+- **Don't duplicate types** — before defining a new type, check whether it already exists in the project (especially `packages/data-provider`). Reuse and extend existing types rather than creating redundant definitions.
+- Use union types, generics, and interfaces appropriately.
+- All TypeScript and ESLint warnings/errors must be addressed — do not leave unresolved diagnostics.
+
+### Comments and Documentation
+
+- Write self-documenting code; no inline comments narrating what code does.
+- JSDoc only for complex/non-obvious logic or intellisense on public APIs.
+- Single-line JSDoc for brief docs, multi-line for complex cases.
+- Avoid standalone `//` comments unless absolutely necessary.
+
+### Import Order
+
+Imports are organized into three sections:
+
+1. **Package imports** — sorted shortest to longest line length (`react` always first).
+2. **`import type` imports** — sorted longest to shortest (package types first, then local types; length resets between sub-groups).
+3. **Local/project imports** — sorted longest to shortest.
+
+Multi-line imports count total character length across all lines. Consolidate value imports from the same module. Always use standalone `import type { ... }` — never inline `type` inside value imports.
+
+### JS/TS Loop Preferences
+
+- **Limit looping as much as possible.** Prefer single-pass transformations and avoid re-iterating the same data.
+- `for (let i = 0; ...)` for performance-critical or index-dependent operations.
+- `for...of` for simple array iteration.
+- `for...in` only for object property enumeration.
+
+---
+
+## Frontend Rules (`client/src/**/*`)
+
+### Localization
+
+- All user-facing text must use `useLocalize()`.
+- Only update English keys in `client/src/locales/en/translation.json` (other languages are automated externally).
+- Semantic key prefixes: `com_ui_`, `com_assistants_`, etc.
+
+### Components
+
+- TypeScript for all React components with proper type imports.
+- Semantic HTML with ARIA labels (`role`, `aria-label`) for accessibility.
+- Group related components in feature directories (e.g., `SidePanel/Memories/`).
+- Use index files for clean exports.
+
+### Data Management
+
+- Feature hooks: `client/src/data-provider/[Feature]/queries.ts` → `[Feature]/index.ts` → `client/src/data-provider/index.ts`.
+- React Query (`@tanstack/react-query`) for all API interactions; proper query invalidation on mutations.
+- QueryKeys and MutationKeys in `packages/data-provider/src/keys.ts`.
+
+### Data-Provider Integration
+
+- Endpoints: `packages/data-provider/src/api-endpoints.ts`
+- Data service: `packages/data-provider/src/data-service.ts`
+- Types: `packages/data-provider/src/types/queries.ts`
+- Use `encodeURIComponent` for dynamic URL parameters.
+
+### Performance
+
+- Prioritize memory and speed efficiency at scale.
+- Cursor pagination for large datasets.
+- Proper dependency arrays to avoid unnecessary re-renders.
+- Leverage React Query caching and background refetching.
+
+---
+
+## Development Commands
+
+| Command | Purpose |
+|---|---|
+| `npm run smart-reinstall` | Install deps (if lockfile changed) + build via Turborepo |
+| `npm run reinstall` | Clean install — wipe `node_modules` and reinstall from scratch |
+| `npm run backend` | Start the backend server |
+| `npm run backend:dev` | Start backend with file watching (development) |
+| `npm run build` | Build all compiled code via Turborepo (parallel, cached) |
+| `npm run frontend` | Build all compiled code sequentially (legacy fallback) |
+| `npm run frontend:dev` | Start frontend dev server with HMR (port 3090, requires backend running) |
+| `npm run build:data-provider` | Rebuild `packages/data-provider` after changes |
+
+- Node.js: v20.19.0+ or ^22.12.0 or >= 23.0.0
+- Database: MongoDB
+- Backend runs on `http://localhost:3080/`; frontend dev server on `http://localhost:3090/`
+
+---
+
+## Testing
+
+- Framework: **Jest**, run per-workspace.
+- Run tests from their workspace directory: `cd api && npx jest `, `cd packages/api && npx jest `, etc.
+- Frontend tests: `__tests__` directories alongside components; use `test/layout-test-utils` for rendering.
+- Cover loading, success, and error states for UI/data flows.
+
+### Philosophy
+
+- **Real logic over mocks.** Exercise actual code paths with real dependencies. Mocking is a last resort.
+- **Spies over mocks.** Assert that real functions are called with expected arguments and frequency without replacing underlying logic.
+- **MongoDB**: use `mongodb-memory-server` for a real in-memory MongoDB instance. Test actual queries and schema validation, not mocked DB calls.
+- **MCP**: use real `@modelcontextprotocol/sdk` exports for servers, transports, and tool definitions. Mirror real scenarios, don't stub SDK internals.
+- Only mock what you cannot control: external HTTP APIs, rate-limited services, non-deterministic system calls.
+- Heavy mocking is a code smell, not a testing strategy.
+
+---
+
+## Formatting
+
+Fix all formatting lint errors (trailing spaces, tabs, newlines, indentation) using auto-fix when available. All TypeScript/ESLint warnings and errors **must** be resolved.
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index a8cb8282bd..0000000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,236 +0,0 @@
-# Changelog
-
-All notable changes to this project will be documented in this file.
-
-
-
-
-
-
-## [Unreleased]
-
-### ✨ New Features
-
-- ✨ feat: implement search parameter updates by **@mawburn** in [#7151](https://github.com/danny-avila/LibreChat/pull/7151)
-- 🎏 feat: Add MCP support for Streamable HTTP Transport by **@benverhees** in [#7353](https://github.com/danny-avila/LibreChat/pull/7353)
-- 🔒 feat: Add Content Security Policy using Helmet middleware by **@rubentalstra** in [#7377](https://github.com/danny-avila/LibreChat/pull/7377)
-- ✨ feat: Add Normalization for MCP Server Names by **@danny-avila** in [#7421](https://github.com/danny-avila/LibreChat/pull/7421)
-- 📊 feat: Improve Helm Chart by **@hofq** in [#3638](https://github.com/danny-avila/LibreChat/pull/3638)
-- 🦾 feat: Claude-4 Support by **@danny-avila** in [#7509](https://github.com/danny-avila/LibreChat/pull/7509)
-- 🪨 feat: Bedrock Support for Claude-4 Reasoning by **@danny-avila** in [#7517](https://github.com/danny-avila/LibreChat/pull/7517)
-
-### 🌍 Internationalization
-
-- 🌍 i18n: Add `Danish` and `Czech` and `Catalan` localization support by **@rubentalstra** in [#7373](https://github.com/danny-avila/LibreChat/pull/7373)
-- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#7375](https://github.com/danny-avila/LibreChat/pull/7375)
-- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#7468](https://github.com/danny-avila/LibreChat/pull/7468)
-
-### 🔧 Fixes
-
-- 💬 fix: update aria-label for accessibility in ConvoLink component by **@berry-13** in [#7320](https://github.com/danny-avila/LibreChat/pull/7320)
-- 🔑 fix: use `apiKey` instead of `openAIApiKey` in OpenAI-like Config by **@danny-avila** in [#7337](https://github.com/danny-avila/LibreChat/pull/7337)
-- 🔄 fix: update navigation logic in `useFocusChatEffect` to ensure correct search parameters are used by **@mawburn** in [#7340](https://github.com/danny-avila/LibreChat/pull/7340)
-- 🔄 fix: Improve MCP Connection Cleanup by **@danny-avila** in [#7400](https://github.com/danny-avila/LibreChat/pull/7400)
-- 🛡️ fix: Preset and Validation Logic for URL Query Params by **@danny-avila** in [#7407](https://github.com/danny-avila/LibreChat/pull/7407)
-- 🌘 fix: artifact of preview text is illegible in dark mode by **@nhtruong** in [#7405](https://github.com/danny-avila/LibreChat/pull/7405)
-- 🛡️ fix: Temporarily Remove CSP until Configurable by **@danny-avila** in [#7419](https://github.com/danny-avila/LibreChat/pull/7419)
-- 💽 fix: Exclude index page `/` from static cache settings by **@sbruel** in [#7382](https://github.com/danny-avila/LibreChat/pull/7382)
-
-### ⚙️ Other Changes
-
-- 📜 docs: CHANGELOG for release v0.7.8 by **@github-actions[bot]** in [#7290](https://github.com/danny-avila/LibreChat/pull/7290)
-- 📦 chore: Update API Package Dependencies by **@danny-avila** in [#7359](https://github.com/danny-avila/LibreChat/pull/7359)
-- 📜 docs: Unreleased Changelog by **@github-actions[bot]** in [#7321](https://github.com/danny-avila/LibreChat/pull/7321)
-- 📜 docs: Unreleased Changelog by **@github-actions[bot]** in [#7434](https://github.com/danny-avila/LibreChat/pull/7434)
-- 🛡️ chore: `multer` v2.0.0 for CVE-2025-47935 and CVE-2025-47944 by **@danny-avila** in [#7454](https://github.com/danny-avila/LibreChat/pull/7454)
-- 📂 refactor: Improve `FileAttachment` & File Form Deletion by **@danny-avila** in [#7471](https://github.com/danny-avila/LibreChat/pull/7471)
-- 📊 chore: Remove Old Helm Chart by **@hofq** in [#7512](https://github.com/danny-avila/LibreChat/pull/7512)
-- 🪖 chore: bump helm app version to v0.7.8 by **@austin-barrington** in [#7524](https://github.com/danny-avila/LibreChat/pull/7524)
-
-
-
----
-## [v0.7.8] -
-
-Changes from v0.7.8-rc1 to v0.7.8.
-
-### ✨ New Features
-
-- ✨ feat: Enhance form submission for touch screens by **@berry-13** in [#7198](https://github.com/danny-avila/LibreChat/pull/7198)
-- 🔍 feat: Additional Tavily API Tool Parameters by **@glowforge-opensource** in [#7232](https://github.com/danny-avila/LibreChat/pull/7232)
-- 🐋 feat: Add python to Dockerfile for increased MCP compatibility by **@technicalpickles** in [#7270](https://github.com/danny-avila/LibreChat/pull/7270)
-
-### 🔧 Fixes
-
-- 🔧 fix: Google Gemma Support & OpenAI Reasoning Instructions by **@danny-avila** in [#7196](https://github.com/danny-avila/LibreChat/pull/7196)
-- 🛠️ fix: Conversation Navigation State by **@danny-avila** in [#7210](https://github.com/danny-avila/LibreChat/pull/7210)
-- 🔄 fix: o-Series Model Regex for System Messages by **@danny-avila** in [#7245](https://github.com/danny-avila/LibreChat/pull/7245)
-- 🔖 fix: Custom Headers for Initial MCP SSE Connection by **@danny-avila** in [#7246](https://github.com/danny-avila/LibreChat/pull/7246)
-- 🛡️ fix: Deep Clone `MCPOptions` for User MCP Connections by **@danny-avila** in [#7247](https://github.com/danny-avila/LibreChat/pull/7247)
-- 🔄 fix: URL Param Race Condition and File Draft Persistence by **@danny-avila** in [#7257](https://github.com/danny-avila/LibreChat/pull/7257)
-- 🔄 fix: Assistants Endpoint & Minor Issues by **@danny-avila** in [#7274](https://github.com/danny-avila/LibreChat/pull/7274)
-- 🔄 fix: Ollama Think Tag Edge Case with Tools by **@danny-avila** in [#7275](https://github.com/danny-avila/LibreChat/pull/7275)
-
-### ⚙️ Other Changes
-
-- 📜 docs: CHANGELOG for release v0.7.8-rc1 by **@github-actions[bot]** in [#7153](https://github.com/danny-avila/LibreChat/pull/7153)
-- 🔄 refactor: Artifact Visibility Management by **@danny-avila** in [#7181](https://github.com/danny-avila/LibreChat/pull/7181)
-- 📦 chore: Bump Package Security by **@danny-avila** in [#7183](https://github.com/danny-avila/LibreChat/pull/7183)
-- 🌿 refactor: Unmount Fork Popover on Hide for Better Performance by **@danny-avila** in [#7189](https://github.com/danny-avila/LibreChat/pull/7189)
-- 🧰 chore: ESLint configuration to enforce Prettier formatting rules by **@mawburn** in [#7186](https://github.com/danny-avila/LibreChat/pull/7186)
-- 🎨 style: Improve KaTeX Rendering for LaTeX Equations by **@andresgit** in [#7223](https://github.com/danny-avila/LibreChat/pull/7223)
-- 📝 docs: Update `.env.example` Google models by **@marlonka** in [#7254](https://github.com/danny-avila/LibreChat/pull/7254)
-- 💬 refactor: MCP Chat Visibility Option, Google Rates, Remove OpenAPI Plugins by **@danny-avila** in [#7286](https://github.com/danny-avila/LibreChat/pull/7286)
-- 📜 docs: Unreleased Changelog by **@github-actions[bot]** in [#7214](https://github.com/danny-avila/LibreChat/pull/7214)
-
-
-
-[See full release details][release-v0.7.8]
-
-[release-v0.7.8]: https://github.com/danny-avila/LibreChat/releases/tag/v0.7.8
-
----
-## [v0.7.8-rc1] -
-
-Changes from v0.7.7 to v0.7.8-rc1.
-
-### ✨ New Features
-
-- 🔍 feat: Mistral OCR API / Upload Files as Text by **@danny-avila** in [#6274](https://github.com/danny-avila/LibreChat/pull/6274)
-- 🤖 feat: Support OpenAI Web Search models by **@danny-avila** in [#6313](https://github.com/danny-avila/LibreChat/pull/6313)
-- 🔗 feat: Agent Chain (Mixture-of-Agents) by **@danny-avila** in [#6374](https://github.com/danny-avila/LibreChat/pull/6374)
-- ⌛ feat: `initTimeout` for Slow Starting MCP Servers by **@perweij** in [#6383](https://github.com/danny-avila/LibreChat/pull/6383)
-- 🚀 feat: `S3` Integration for File handling and Image uploads by **@rubentalstra** in [#6142](https://github.com/danny-avila/LibreChat/pull/6142)
-- 🔒feat: Enable OpenID Auto-Redirect by **@leondape** in [#6066](https://github.com/danny-avila/LibreChat/pull/6066)
-- 🚀 feat: Integrate `Azure Blob Storage` for file handling and image uploads by **@rubentalstra** in [#6153](https://github.com/danny-avila/LibreChat/pull/6153)
-- 🚀 feat: Add support for custom `AWS` endpoint in `S3` by **@rubentalstra** in [#6431](https://github.com/danny-avila/LibreChat/pull/6431)
-- 🚀 feat: Add support for LDAP STARTTLS in LDAP authentication by **@rubentalstra** in [#6438](https://github.com/danny-avila/LibreChat/pull/6438)
-- 🚀 feat: Refactor schema exports and update package version to 0.0.4 by **@rubentalstra** in [#6455](https://github.com/danny-avila/LibreChat/pull/6455)
-- 🔼 feat: Add Auto Submit For URL Query Params by **@mjaverto** in [#6440](https://github.com/danny-avila/LibreChat/pull/6440)
-- 🛠 feat: Enhance Redis Integration, Rate Limiters & Log Headers by **@danny-avila** in [#6462](https://github.com/danny-avila/LibreChat/pull/6462)
-- 💵 feat: Add Automatic Balance Refill by **@rubentalstra** in [#6452](https://github.com/danny-avila/LibreChat/pull/6452)
-- 🗣️ feat: add support for gpt-4o-transcribe models by **@berry-13** in [#6483](https://github.com/danny-avila/LibreChat/pull/6483)
-- 🎨 feat: UI Refresh for Enhanced UX by **@berry-13** in [#6346](https://github.com/danny-avila/LibreChat/pull/6346)
-- 🌍 feat: Add support for Hungarian language localization by **@rubentalstra** in [#6508](https://github.com/danny-avila/LibreChat/pull/6508)
-- 🚀 feat: Add Gemini 2.5 Token/Context Values, Increase Max Possible Output to 64k by **@danny-avila** in [#6563](https://github.com/danny-avila/LibreChat/pull/6563)
-- 🚀 feat: Enhance MCP Connections For Multi-User Support by **@danny-avila** in [#6610](https://github.com/danny-avila/LibreChat/pull/6610)
-- 🚀 feat: Enhance S3 URL Expiry with Refresh; fix: S3 File Deletion by **@danny-avila** in [#6647](https://github.com/danny-avila/LibreChat/pull/6647)
-- 🚀 feat: enhance UI components and refactor settings by **@berry-13** in [#6625](https://github.com/danny-avila/LibreChat/pull/6625)
-- 💬 feat: move TemporaryChat to the Header by **@berry-13** in [#6646](https://github.com/danny-avila/LibreChat/pull/6646)
-- 🚀 feat: Use Model Specs + Specific Endpoints, Limit Providers for Agents by **@danny-avila** in [#6650](https://github.com/danny-avila/LibreChat/pull/6650)
-- 🪙 feat: Sync Balance Config on Login by **@danny-avila** in [#6671](https://github.com/danny-avila/LibreChat/pull/6671)
-- 🔦 feat: MCP Support for Non-Agent Endpoints by **@danny-avila** in [#6775](https://github.com/danny-avila/LibreChat/pull/6775)
-- 🗃️ feat: Code Interpreter File Persistence between Sessions by **@danny-avila** in [#6790](https://github.com/danny-avila/LibreChat/pull/6790)
-- 🖥️ feat: Code Interpreter API for Non-Agent Endpoints by **@danny-avila** in [#6803](https://github.com/danny-avila/LibreChat/pull/6803)
-- ⚡ feat: Self-hosted Artifacts Static Bundler URL by **@danny-avila** in [#6827](https://github.com/danny-avila/LibreChat/pull/6827)
-- 🐳 feat: Add Jemalloc and UV to Docker Builds by **@danny-avila** in [#6836](https://github.com/danny-avila/LibreChat/pull/6836)
-- 🤖 feat: GPT-4.1 by **@danny-avila** in [#6880](https://github.com/danny-avila/LibreChat/pull/6880)
-- 👋 feat: remove Edge TTS by **@berry-13** in [#6885](https://github.com/danny-avila/LibreChat/pull/6885)
-- feat: nav optimization by **@berry-13** in [#5785](https://github.com/danny-avila/LibreChat/pull/5785)
-- 🗺️ feat: Add Parameter Location Mapping for OpenAPI actions by **@peeeteeer** in [#6858](https://github.com/danny-avila/LibreChat/pull/6858)
-- 🤖 feat: Support `o4-mini` and `o3` Models by **@danny-avila** in [#6928](https://github.com/danny-avila/LibreChat/pull/6928)
-- 🎨 feat: OpenAI Image Tools (GPT-Image-1) by **@danny-avila** in [#7079](https://github.com/danny-avila/LibreChat/pull/7079)
-- 🗓️ feat: Add Special Variables for Prompts & Agents, Prompt UI Improvements by **@danny-avila** in [#7123](https://github.com/danny-avila/LibreChat/pull/7123)
-
-### 🌍 Internationalization
-
-- 🌍 i18n: Add Thai Language Support and Update Translations by **@rubentalstra** in [#6219](https://github.com/danny-avila/LibreChat/pull/6219)
-- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6220](https://github.com/danny-avila/LibreChat/pull/6220)
-- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6240](https://github.com/danny-avila/LibreChat/pull/6240)
-- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6241](https://github.com/danny-avila/LibreChat/pull/6241)
-- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6277](https://github.com/danny-avila/LibreChat/pull/6277)
-- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6414](https://github.com/danny-avila/LibreChat/pull/6414)
-- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6505](https://github.com/danny-avila/LibreChat/pull/6505)
-- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6530](https://github.com/danny-avila/LibreChat/pull/6530)
-- 🌍 i18n: Add Persian Localization Support by **@rubentalstra** in [#6669](https://github.com/danny-avila/LibreChat/pull/6669)
-- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#6667](https://github.com/danny-avila/LibreChat/pull/6667)
-- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#7126](https://github.com/danny-avila/LibreChat/pull/7126)
-- 🌍 i18n: Update translation.json with latest translations by **@github-actions[bot]** in [#7148](https://github.com/danny-avila/LibreChat/pull/7148)
-
-### 👐 Accessibility
-
-- 🎨 a11y: Update Model Spec Description Text by **@berry-13** in [#6294](https://github.com/danny-avila/LibreChat/pull/6294)
-- 🗑️ a11y: Add Accessible Name to Button for File Attachment Removal by **@kangabell** in [#6709](https://github.com/danny-avila/LibreChat/pull/6709)
-- ⌨️ a11y: enhance accessibility & visual consistency by **@berry-13** in [#6866](https://github.com/danny-avila/LibreChat/pull/6866)
-- 🙌 a11y: Searchbar/Conversations List Focus by **@danny-avila** in [#7096](https://github.com/danny-avila/LibreChat/pull/7096)
-- 👐 a11y: Improve Fork and SplitText Accessibility by **@danny-avila** in [#7147](https://github.com/danny-avila/LibreChat/pull/7147)
-
-### 🔧 Fixes
-
-- 🐛 fix: Avatar Type Definitions in Agent/Assistant Schemas by **@danny-avila** in [#6235](https://github.com/danny-avila/LibreChat/pull/6235)
-- 🔧 fix: MeiliSearch Field Error and Patch Incorrect Import by #6210 by **@rubentalstra** in [#6245](https://github.com/danny-avila/LibreChat/pull/6245)
-- 🔏 fix: Enhance Two-Factor Authentication by **@rubentalstra** in [#6247](https://github.com/danny-avila/LibreChat/pull/6247)
-- 🐛 fix: Await saveMessage in abortMiddleware to ensure proper execution by **@sh4shii** in [#6248](https://github.com/danny-avila/LibreChat/pull/6248)
-- 🔧 fix: Axios Proxy Usage And Bump `mongoose` by **@danny-avila** in [#6298](https://github.com/danny-avila/LibreChat/pull/6298)
-- 🔧 fix: comment out MCP servers to resolve service run issues by **@KunalScriptz** in [#6316](https://github.com/danny-avila/LibreChat/pull/6316)
-- 🔧 fix: Update Token Calculations and Mapping, MCP `env` Initialization by **@danny-avila** in [#6406](https://github.com/danny-avila/LibreChat/pull/6406)
-- 🐞 fix: Agent "Resend" Message Attachments + Source Icon Styling by **@danny-avila** in [#6408](https://github.com/danny-avila/LibreChat/pull/6408)
-- 🐛 fix: Prevent Crash on Duplicate Message ID by **@Odrec** in [#6392](https://github.com/danny-avila/LibreChat/pull/6392)
-- 🔐 fix: Invalid Key Length in 2FA Encryption by **@rubentalstra** in [#6432](https://github.com/danny-avila/LibreChat/pull/6432)
-- 🏗️ fix: Fix Agents Token Spend Race Conditions, Expand Test Coverage by **@danny-avila** in [#6480](https://github.com/danny-avila/LibreChat/pull/6480)
-- 🔃 fix: Draft Clearing, Claude Titles, Remove Default Vision Max Tokens by **@danny-avila** in [#6501](https://github.com/danny-avila/LibreChat/pull/6501)
-- 🔧 fix: Update username reference to use user.name in greeting display by **@rubentalstra** in [#6534](https://github.com/danny-avila/LibreChat/pull/6534)
-- 🔧 fix: S3 Download Stream with Key Extraction and Blob Storage Encoding for Vision by **@danny-avila** in [#6557](https://github.com/danny-avila/LibreChat/pull/6557)
-- 🔧 fix: Mistral type strictness for `usage` & update token values/windows by **@danny-avila** in [#6562](https://github.com/danny-avila/LibreChat/pull/6562)
-- 🔧 fix: Consolidate Text Parsing and TTS Edge Initialization by **@danny-avila** in [#6582](https://github.com/danny-avila/LibreChat/pull/6582)
-- 🔧 fix: Ensure continuation in image processing on base64 encoding from Blob Storage by **@danny-avila** in [#6619](https://github.com/danny-avila/LibreChat/pull/6619)
-- ✉️ fix: Fallback For User Name In Email Templates by **@danny-avila** in [#6620](https://github.com/danny-avila/LibreChat/pull/6620)
-- 🔧 fix: Azure Blob Integration and File Source References by **@rubentalstra** in [#6575](https://github.com/danny-avila/LibreChat/pull/6575)
-- 🐛 fix: Safeguard against undefined addedEndpoints by **@wipash** in [#6654](https://github.com/danny-avila/LibreChat/pull/6654)
-- 🤖 fix: Gemini 2.5 Vision Support by **@danny-avila** in [#6663](https://github.com/danny-avila/LibreChat/pull/6663)
-- 🔄 fix: Avatar & Error Handling Enhancements by **@danny-avila** in [#6687](https://github.com/danny-avila/LibreChat/pull/6687)
-- 🔧 fix: Chat Middleware, Zod Conversion, Auto-Save and S3 URL Refresh by **@danny-avila** in [#6720](https://github.com/danny-avila/LibreChat/pull/6720)
-- 🔧 fix: Agent Capability Checks & DocumentDB Compatibility for Agent Resource Removal by **@danny-avila** in [#6726](https://github.com/danny-avila/LibreChat/pull/6726)
-- 🔄 fix: Improve audio MIME type detection and handling by **@berry-13** in [#6707](https://github.com/danny-avila/LibreChat/pull/6707)
-- 🪺 fix: Update Role Handling due to New Schema Shape by **@danny-avila** in [#6774](https://github.com/danny-avila/LibreChat/pull/6774)
-- 🗨️ fix: Show ModelSpec Greeting by **@berry-13** in [#6770](https://github.com/danny-avila/LibreChat/pull/6770)
-- 🔧 fix: Keyv and Proxy Issues, and More Memory Optimizations by **@danny-avila** in [#6867](https://github.com/danny-avila/LibreChat/pull/6867)
-- ✨ fix: Implement dynamic text sizing for greeting and name display by **@berry-13** in [#6833](https://github.com/danny-avila/LibreChat/pull/6833)
-- 📝 fix: Mistral OCR Image Support and Azure Agent Titles by **@danny-avila** in [#6901](https://github.com/danny-avila/LibreChat/pull/6901)
-- 📢 fix: Invalid `engineTTS` and Conversation State on Navigation by **@berry-13** in [#6904](https://github.com/danny-avila/LibreChat/pull/6904)
-- 🛠️ fix: Improve Accessibility and Display of Conversation Menu by **@danny-avila** in [#6913](https://github.com/danny-avila/LibreChat/pull/6913)
-- 🔧 fix: Agent Resource Form, Convo Menu Style, Ensure Draft Clears on Submission by **@danny-avila** in [#6925](https://github.com/danny-avila/LibreChat/pull/6925)
-- 🔀 fix: MCP Improvements, Auto-Save Drafts, Artifact Markup by **@danny-avila** in [#7040](https://github.com/danny-avila/LibreChat/pull/7040)
-- 🐋 fix: Improve Deepseek Compatbility by **@danny-avila** in [#7132](https://github.com/danny-avila/LibreChat/pull/7132)
-- 🐙 fix: Add Redis Ping Interval to Prevent Connection Drops by **@peeeteeer** in [#7127](https://github.com/danny-avila/LibreChat/pull/7127)
-
-### ⚙️ Other Changes
-
-- 📦 refactor: Move DB Models to `@librechat/data-schemas` by **@rubentalstra** in [#6210](https://github.com/danny-avila/LibreChat/pull/6210)
-- 📦 chore: Patch `axios` to address CVE-2025-27152 by **@danny-avila** in [#6222](https://github.com/danny-avila/LibreChat/pull/6222)
-- ⚠️ refactor: Use Error Content Part Instead Of Throwing Error for Agents by **@danny-avila** in [#6262](https://github.com/danny-avila/LibreChat/pull/6262)
-- 🏃♂️ refactor: Improve Agent Run Context & Misc. Changes by **@danny-avila** in [#6448](https://github.com/danny-avila/LibreChat/pull/6448)
-- 📝 docs: librechat.example.yaml by **@ineiti** in [#6442](https://github.com/danny-avila/LibreChat/pull/6442)
-- 🏃♂️ refactor: More Agent Context Improvements during Run by **@danny-avila** in [#6477](https://github.com/danny-avila/LibreChat/pull/6477)
-- 🔃 refactor: Allow streaming for `o1` models by **@danny-avila** in [#6509](https://github.com/danny-avila/LibreChat/pull/6509)
-- 🔧 chore: `Vite` Plugin Upgrades & Config Optimizations by **@rubentalstra** in [#6547](https://github.com/danny-avila/LibreChat/pull/6547)
-- 🔧 refactor: Consolidate Logging, Model Selection & Actions Optimizations, Minor Fixes by **@danny-avila** in [#6553](https://github.com/danny-avila/LibreChat/pull/6553)
-- 🎨 style: Address Minor UI Refresh Issues by **@berry-13** in [#6552](https://github.com/danny-avila/LibreChat/pull/6552)
-- 🔧 refactor: Enhance Model & Endpoint Configurations with Global Indicators 🌍 by **@berry-13** in [#6578](https://github.com/danny-avila/LibreChat/pull/6578)
-- 💬 style: Chat UI, Greeting, and Message adjustments by **@berry-13** in [#6612](https://github.com/danny-avila/LibreChat/pull/6612)
-- ⚡ refactor: DocumentDB Compatibility for Balance Updates by **@danny-avila** in [#6673](https://github.com/danny-avila/LibreChat/pull/6673)
-- 🧹 chore: Update ESLint rules for React hooks by **@rubentalstra** in [#6685](https://github.com/danny-avila/LibreChat/pull/6685)
-- 🪙 chore: Update Gemini Pricing by **@RedwindA** in [#6731](https://github.com/danny-avila/LibreChat/pull/6731)
-- 🪺 refactor: Nest Permission fields for Roles by **@rubentalstra** in [#6487](https://github.com/danny-avila/LibreChat/pull/6487)
-- 📦 chore: Update `caniuse-lite` dependency to version 1.0.30001706 by **@rubentalstra** in [#6482](https://github.com/danny-avila/LibreChat/pull/6482)
-- ⚙️ refactor: OAuth Flow Signal, Type Safety, Tool Progress & Updated Packages by **@danny-avila** in [#6752](https://github.com/danny-avila/LibreChat/pull/6752)
-- 📦 chore: bump vite from 6.2.3 to 6.2.5 by **@dependabot[bot]** in [#6745](https://github.com/danny-avila/LibreChat/pull/6745)
-- 💾 chore: Enhance Local Storage Handling and Update MCP SDK by **@danny-avila** in [#6809](https://github.com/danny-avila/LibreChat/pull/6809)
-- 🤖 refactor: Improve Agents Memory Usage, Bump Keyv, Grok 3 by **@danny-avila** in [#6850](https://github.com/danny-avila/LibreChat/pull/6850)
-- 💾 refactor: Enhance Memory In Image Encodings & Client Disposal by **@danny-avila** in [#6852](https://github.com/danny-avila/LibreChat/pull/6852)
-- 🔁 refactor: Token Event Handler and Standardize `maxTokens` Key by **@danny-avila** in [#6886](https://github.com/danny-avila/LibreChat/pull/6886)
-- 🔍 refactor: Search & Message Retrieval by **@berry-13** in [#6903](https://github.com/danny-avila/LibreChat/pull/6903)
-- 🎨 style: standardize dropdown styling & fix z-Index layering by **@berry-13** in [#6939](https://github.com/danny-avila/LibreChat/pull/6939)
-- 📙 docs: CONTRIBUTING.md by **@dblock** in [#6831](https://github.com/danny-avila/LibreChat/pull/6831)
-- 🧭 refactor: Modernize Nav/Header by **@danny-avila** in [#7094](https://github.com/danny-avila/LibreChat/pull/7094)
-- 🪶 refactor: Chat Input Focus for Conversation Navigations & ChatForm Optimizations by **@danny-avila** in [#7100](https://github.com/danny-avila/LibreChat/pull/7100)
-- 🔃 refactor: Streamline Navigation, Message Loading UX by **@danny-avila** in [#7118](https://github.com/danny-avila/LibreChat/pull/7118)
-- 📜 docs: Unreleased changelog by **@github-actions[bot]** in [#6265](https://github.com/danny-avila/LibreChat/pull/6265)
-
-
-
-[See full release details][release-v0.7.8-rc1]
-
-[release-v0.7.8-rc1]: https://github.com/danny-avila/LibreChat/releases/tag/v0.7.8-rc1
-
----
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 120000
index 0000000000..47dc3e3d86
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1 @@
+AGENTS.md
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index 38273bc5eb..02bda8a589 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-# v0.8.2
+# v0.8.4-rc1
# Base node image
FROM node:20-alpine AS node
diff --git a/Dockerfile.multi b/Dockerfile.multi
index 47e00d0fa8..8e7483e378 100644
--- a/Dockerfile.multi
+++ b/Dockerfile.multi
@@ -1,5 +1,5 @@
# Dockerfile.multi
-# v0.8.2
+# v0.8.4-rc1
# Set configurable max-old-space-size with default
ARG NODE_MAX_OLD_SPACE_SIZE=6144
diff --git a/README.md b/README.md
index 6e04396637..e82b3ebc2c 100644
--- a/README.md
+++ b/README.md
@@ -27,8 +27,8 @@
-
-
+
+
diff --git a/api/app/clients/BaseClient.js b/api/app/clients/BaseClient.js
index 7ec1b70711..4ea54f9739 100644
--- a/api/app/clients/BaseClient.js
+++ b/api/app/clients/BaseClient.js
@@ -3,7 +3,9 @@ const fetch = require('node-fetch');
const { logger } = require('@librechat/data-schemas');
const {
countTokens,
+ checkBalance,
getBalanceConfig,
+ buildMessageFiles,
extractFileContext,
encodeAndFormatAudios,
encodeAndFormatVideos,
@@ -20,19 +22,13 @@ const {
isAgentsEndpoint,
isEphemeralAgentId,
supportsBalanceCheck,
+ isBedrockDocumentType,
} = require('librechat-data-provider');
-const {
- updateMessage,
- getMessages,
- saveMessage,
- saveConvo,
- getConvo,
- getFiles,
-} = require('~/models');
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
-const { checkBalance } = require('~/models/balanceMethods');
const { truncateToolCallOutputs } = require('./prompts');
+const { logViolation } = require('~/cache');
const TextStream = require('./TextStream');
+const db = require('~/models');
class BaseClient {
constructor(apiKey, options = {}) {
@@ -122,7 +118,9 @@ class BaseClient {
* @returns {number}
*/
getTokenCountForResponse(responseMessage) {
- logger.debug('[BaseClient] `recordTokenUsage` not implemented.', responseMessage);
+ logger.debug('[BaseClient] `recordTokenUsage` not implemented.', {
+ messageId: responseMessage?.messageId,
+ });
}
/**
@@ -133,12 +131,14 @@ class BaseClient {
* @param {AppConfig['balance']} [balance]
* @param {number} promptTokens
* @param {number} completionTokens
+ * @param {string} [messageId]
* @returns {Promise}
*/
- async recordTokenUsage({ model, balance, promptTokens, completionTokens }) {
+ async recordTokenUsage({ model, balance, promptTokens, completionTokens, messageId }) {
logger.debug('[BaseClient] `recordTokenUsage` not implemented.', {
model,
balance,
+ messageId,
promptTokens,
completionTokens,
});
@@ -659,16 +659,27 @@ class BaseClient {
);
if (tokenCountMap) {
- logger.debug('[BaseClient] tokenCountMap', tokenCountMap);
if (tokenCountMap[userMessage.messageId]) {
userMessage.tokenCount = tokenCountMap[userMessage.messageId];
- logger.debug('[BaseClient] userMessage', userMessage);
+ logger.debug('[BaseClient] userMessage', {
+ messageId: userMessage.messageId,
+ tokenCount: userMessage.tokenCount,
+ conversationId: userMessage.conversationId,
+ });
}
this.handleTokenCountMap(tokenCountMap);
}
if (!isEdited && !this.skipSaveUserMessage) {
+ const reqFiles = this.options.req?.body?.files;
+ if (reqFiles && Array.isArray(this.options.attachments)) {
+ const files = buildMessageFiles(reqFiles, this.options.attachments);
+ if (files.length > 0) {
+ userMessage.files = files;
+ }
+ delete userMessage.image_urls;
+ }
userMessagePromise = this.saveMessageToDatabase(userMessage, saveOptions, user);
this.savedMessageIds.add(userMessage.messageId);
if (typeof opts?.getReqData === 'function') {
@@ -683,18 +694,26 @@ class BaseClient {
balanceConfig?.enabled &&
supportsBalanceCheck[this.options.endpointType ?? this.options.endpoint]
) {
- await checkBalance({
- req: this.options.req,
- res: this.options.res,
- txData: {
- user: this.user,
- tokenType: 'prompt',
- amount: promptTokens,
- endpoint: this.options.endpoint,
- model: this.modelOptions?.model ?? this.model,
- endpointTokenConfig: this.options.endpointTokenConfig,
+ await checkBalance(
+ {
+ req: this.options.req,
+ res: this.options.res,
+ txData: {
+ user: this.user,
+ tokenType: 'prompt',
+ amount: promptTokens,
+ endpoint: this.options.endpoint,
+ model: this.modelOptions?.model ?? this.model,
+ endpointTokenConfig: this.options.endpointTokenConfig,
+ },
},
- });
+ {
+ logViolation,
+ getMultiplier: db.getMultiplier,
+ findBalanceByUser: db.findBalanceByUser,
+ createAutoRefillTransaction: db.createAutoRefillTransaction,
+ },
+ );
}
const { completion, metadata } = await this.sendCompletion(payload, opts);
@@ -780,9 +799,18 @@ class BaseClient {
promptTokens,
completionTokens,
balance: balanceConfig,
- model: responseMessage.model,
+ /** Note: When using agents, responseMessage.model is the agent ID, not the model */
+ model: this.model,
+ messageId: this.responseMessageId,
});
}
+
+ logger.debug('[BaseClient] Response token usage', {
+ messageId: responseMessage.messageId,
+ model: responseMessage.model,
+ promptTokens,
+ completionTokens,
+ });
}
if (userMessagePromise) {
@@ -882,7 +910,7 @@ class BaseClient {
async loadHistory(conversationId, parentMessageId = null) {
logger.debug('[BaseClient] Loading history:', { conversationId, parentMessageId });
- const messages = (await getMessages({ conversationId })) ?? [];
+ const messages = (await db.getMessages({ conversationId })) ?? [];
if (messages.length === 0) {
return [];
@@ -938,8 +966,13 @@ class BaseClient {
}
const hasAddedConvo = this.options?.req?.body?.addedConvo != null;
- const savedMessage = await saveMessage(
- this.options?.req,
+ const reqCtx = {
+ userId: this.options?.req?.user?.id,
+ isTemporary: this.options?.req?.body?.isTemporary,
+ interfaceConfig: this.options?.req?.config?.interfaceConfig,
+ };
+ const savedMessage = await db.saveMessage(
+ reqCtx,
{
...message,
endpoint: this.options.endpoint,
@@ -964,7 +997,7 @@ class BaseClient {
const existingConvo =
this.fetchedConvo === true
? null
- : await getConvo(this.options?.req?.user?.id, message.conversationId);
+ : await db.getConvo(this.options?.req?.user?.id, message.conversationId);
const unsetFields = {};
const exceptions = new Set(['spec', 'iconURL']);
@@ -991,7 +1024,7 @@ class BaseClient {
}
}
- const conversation = await saveConvo(this.options?.req, fieldsToKeep, {
+ const conversation = await db.saveConvo(reqCtx, fieldsToKeep, {
context: 'api/app/clients/BaseClient.js - saveMessageToDatabase #saveConvo',
unsetFields,
});
@@ -1004,7 +1037,7 @@ class BaseClient {
* @param {Partial} message
*/
async updateMessageInDatabase(message) {
- await updateMessage(this.options.req, message);
+ await db.updateMessage(this.options?.req?.user?.id, message);
}
/**
@@ -1299,6 +1332,9 @@ class BaseClient {
const allFiles = [];
+ const provider = this.options.agent?.provider ?? this.options.endpoint;
+ const isBedrock = provider === EModelEndpoint.bedrock;
+
for (const file of attachments) {
/** @type {FileSources} */
const source = file.source ?? FileSources.local;
@@ -1316,6 +1352,9 @@ class BaseClient {
} else if (file.type === 'application/pdf') {
categorizedAttachments.documents.push(file);
allFiles.push(file);
+ } else if (isBedrock && isBedrockDocumentType(file.type)) {
+ categorizedAttachments.documents.push(file);
+ allFiles.push(file);
} else if (file.type.startsWith('video/')) {
categorizedAttachments.videos.push(file);
allFiles.push(file);
@@ -1398,7 +1437,7 @@ class BaseClient {
return message;
}
- const files = await getFiles(
+ const files = await db.getFiles(
{
file_id: { $in: fileIds },
},
diff --git a/api/app/clients/specs/BaseClient.test.js b/api/app/clients/specs/BaseClient.test.js
index fed80de28c..f13c9979ac 100644
--- a/api/app/clients/specs/BaseClient.test.js
+++ b/api/app/clients/specs/BaseClient.test.js
@@ -821,6 +821,56 @@ describe('BaseClient', () => {
});
});
+ describe('recordTokenUsage model assignment', () => {
+ test('should pass this.model to recordTokenUsage, not the agent ID from responseMessage.model', async () => {
+ const actualModel = 'claude-opus-4-5';
+ const agentId = 'agent_p5Z_IU6EIxBoqn1BoqLBp';
+
+ TestClient.model = actualModel;
+ TestClient.options.endpoint = 'agents';
+ TestClient.options.agent = { id: agentId };
+
+ TestClient.getTokenCountForResponse = jest.fn().mockReturnValue(50);
+ TestClient.recordTokenUsage = jest.fn().mockResolvedValue(undefined);
+ TestClient.buildMessages.mockReturnValue({
+ prompt: [],
+ tokenCountMap: { res: 50 },
+ });
+
+ await TestClient.sendMessage('Hello', {});
+
+ expect(TestClient.recordTokenUsage).toHaveBeenCalledWith(
+ expect.objectContaining({
+ model: actualModel,
+ }),
+ );
+
+ const callArgs = TestClient.recordTokenUsage.mock.calls[0][0];
+ expect(callArgs.model).not.toBe(agentId);
+ });
+
+ test('should pass this.model even when this.model differs from modelOptions.model', async () => {
+ const instanceModel = 'gpt-4o';
+ TestClient.model = instanceModel;
+ TestClient.modelOptions = { model: 'gpt-4o-mini' };
+
+ TestClient.getTokenCountForResponse = jest.fn().mockReturnValue(50);
+ TestClient.recordTokenUsage = jest.fn().mockResolvedValue(undefined);
+ TestClient.buildMessages.mockReturnValue({
+ prompt: [],
+ tokenCountMap: { res: 50 },
+ });
+
+ await TestClient.sendMessage('Hello', {});
+
+ expect(TestClient.recordTokenUsage).toHaveBeenCalledWith(
+ expect.objectContaining({
+ model: instanceModel,
+ }),
+ );
+ });
+ });
+
describe('getMessagesWithinTokenLimit with instructions', () => {
test('should always include instructions when present', async () => {
TestClient.maxContextTokens = 50;
@@ -928,4 +978,123 @@ describe('BaseClient', () => {
expect(result.remainingContextTokens).toBe(2); // 25 - 20 - 3(assistant label)
});
});
+
+ describe('sendMessage file population', () => {
+ const attachment = {
+ file_id: 'file-abc',
+ filename: 'image.png',
+ filepath: '/uploads/image.png',
+ type: 'image/png',
+ bytes: 1024,
+ object: 'file',
+ user: 'user-1',
+ embedded: false,
+ usage: 0,
+ text: 'large ocr blob that should be stripped',
+ _id: 'mongo-id-1',
+ };
+
+ beforeEach(() => {
+ TestClient.options.req = { body: { files: [{ file_id: 'file-abc' }] } };
+ TestClient.options.attachments = [attachment];
+ });
+
+ test('populates userMessage.files before saveMessageToDatabase is called', async () => {
+ TestClient.saveMessageToDatabase = jest.fn().mockImplementation((msg) => {
+ return Promise.resolve({ message: msg });
+ });
+
+ await TestClient.sendMessage('Hello');
+
+ const userSave = TestClient.saveMessageToDatabase.mock.calls.find(
+ ([msg]) => msg.isCreatedByUser,
+ );
+ expect(userSave).toBeDefined();
+ expect(userSave[0].files).toBeDefined();
+ expect(userSave[0].files).toHaveLength(1);
+ expect(userSave[0].files[0].file_id).toBe('file-abc');
+ });
+
+ test('strips text and _id from files before saving', async () => {
+ TestClient.saveMessageToDatabase = jest.fn().mockResolvedValue({ message: {} });
+
+ await TestClient.sendMessage('Hello');
+
+ const userSave = TestClient.saveMessageToDatabase.mock.calls.find(
+ ([msg]) => msg.isCreatedByUser,
+ );
+ expect(userSave[0].files[0].text).toBeUndefined();
+ expect(userSave[0].files[0]._id).toBeUndefined();
+ expect(userSave[0].files[0].filename).toBe('image.png');
+ });
+
+ test('deletes image_urls from userMessage when files are present', async () => {
+ TestClient.saveMessageToDatabase = jest.fn().mockResolvedValue({ message: {} });
+ TestClient.options.attachments = [
+ { ...attachment, image_urls: ['data:image/png;base64,...'] },
+ ];
+
+ await TestClient.sendMessage('Hello');
+
+ const userSave = TestClient.saveMessageToDatabase.mock.calls.find(
+ ([msg]) => msg.isCreatedByUser,
+ );
+ expect(userSave[0].image_urls).toBeUndefined();
+ });
+
+ test('does not set files when no attachments match request file IDs', async () => {
+ TestClient.options.req = { body: { files: [{ file_id: 'file-nomatch' }] } };
+ TestClient.saveMessageToDatabase = jest.fn().mockResolvedValue({ message: {} });
+
+ await TestClient.sendMessage('Hello');
+
+ const userSave = TestClient.saveMessageToDatabase.mock.calls.find(
+ ([msg]) => msg.isCreatedByUser,
+ );
+ expect(userSave[0].files).toBeUndefined();
+ });
+
+ test('skips file population when attachments is not an array (Promise case)', async () => {
+ TestClient.options.attachments = Promise.resolve([attachment]);
+ TestClient.saveMessageToDatabase = jest.fn().mockResolvedValue({ message: {} });
+
+ await TestClient.sendMessage('Hello');
+
+ const userSave = TestClient.saveMessageToDatabase.mock.calls.find(
+ ([msg]) => msg.isCreatedByUser,
+ );
+ expect(userSave[0].files).toBeUndefined();
+ });
+
+ test('skips file population when skipSaveUserMessage is true', async () => {
+ TestClient.skipSaveUserMessage = true;
+ TestClient.saveMessageToDatabase = jest.fn().mockResolvedValue({ message: {} });
+
+ await TestClient.sendMessage('Hello');
+
+ const userSave = TestClient.saveMessageToDatabase.mock.calls.find(
+ ([msg]) => msg?.isCreatedByUser,
+ );
+ expect(userSave).toBeUndefined();
+ });
+
+ test('ignores file_id: undefined entries in req.body.files (no set poisoning)', async () => {
+ TestClient.options.req = {
+ body: { files: [{ file_id: undefined }, { file_id: 'file-abc' }] },
+ };
+ TestClient.options.attachments = [
+ { ...attachment, file_id: undefined },
+ { ...attachment, file_id: 'file-abc' },
+ ];
+ TestClient.saveMessageToDatabase = jest.fn().mockResolvedValue({ message: {} });
+
+ await TestClient.sendMessage('Hello');
+
+ const userSave = TestClient.saveMessageToDatabase.mock.calls.find(
+ ([msg]) => msg.isCreatedByUser,
+ );
+ expect(userSave[0].files).toHaveLength(1);
+ expect(userSave[0].files[0].file_id).toBe('file-abc');
+ });
+ });
});
diff --git a/api/app/clients/tools/manifest.json b/api/app/clients/tools/manifest.json
index 7930e67ac9..9637c20867 100644
--- a/api/app/clients/tools/manifest.json
+++ b/api/app/clients/tools/manifest.json
@@ -16,7 +16,7 @@
"name": "Google",
"pluginKey": "google",
"description": "Use Google Search to find information about the weather, news, sports, and more.",
- "icon": "https://i.imgur.com/SMmVkNB.png",
+ "icon": "assets/google-search.svg",
"authConfig": [
{
"authField": "GOOGLE_CSE_ID",
@@ -61,7 +61,7 @@
"name": "DALL-E-3",
"pluginKey": "dalle",
"description": "[DALL-E-3] Create realistic images and art from a description in natural language",
- "icon": "https://i.imgur.com/u2TzXzH.png",
+ "icon": "assets/openai.svg",
"authConfig": [
{
"authField": "DALLE3_API_KEY||DALLE_API_KEY",
@@ -74,7 +74,7 @@
"name": "Tavily Search",
"pluginKey": "tavily_search_results_json",
"description": "Tavily Search is a robust search API tailored for LLM Agents. It seamlessly integrates with diverse data sources to ensure a superior, relevant search experience.",
- "icon": "https://tavily.com/favicon.ico",
+ "icon": "assets/tavily.svg",
"authConfig": [
{
"authField": "TAVILY_API_KEY",
@@ -87,14 +87,14 @@
"name": "Calculator",
"pluginKey": "calculator",
"description": "Perform simple and complex mathematical calculations.",
- "icon": "https://i.imgur.com/RHsSG5h.png",
+ "icon": "assets/calculator.svg",
"authConfig": []
},
{
"name": "Stable Diffusion",
"pluginKey": "stable-diffusion",
"description": "Generate photo-realistic images given any text input.",
- "icon": "https://i.imgur.com/Yr466dp.png",
+ "icon": "assets/stability-ai.svg",
"authConfig": [
{
"authField": "SD_WEBUI_URL",
@@ -107,7 +107,7 @@
"name": "Azure AI Search",
"pluginKey": "azure-ai-search",
"description": "Use Azure AI Search to find information",
- "icon": "https://i.imgur.com/E7crPze.png",
+ "icon": "assets/azure-ai-search.svg",
"authConfig": [
{
"authField": "AZURE_AI_SEARCH_SERVICE_ENDPOINT",
@@ -143,7 +143,7 @@
"name": "Flux",
"pluginKey": "flux",
"description": "Generate images using text with the Flux API.",
- "icon": "https://blackforestlabs.ai/wp-content/uploads/2024/07/bfl_logo_retraced_blk.png",
+ "icon": "assets/bfl-ai.svg",
"isAuthRequired": "true",
"authConfig": [
{
@@ -156,14 +156,14 @@
{
"name": "Gemini Image Tools",
"pluginKey": "gemini_image_gen",
- "toolkit": true,
"description": "Generate high-quality images using Google's Gemini Image Models. Supports Gemini API or Vertex AI.",
"icon": "assets/gemini_image_gen.svg",
"authConfig": [
{
- "authField": "GEMINI_API_KEY||GOOGLE_KEY||GEMINI_VERTEX_ENABLED",
- "label": "Gemini API Key (Optional if Vertex AI is configured)",
- "description": "Your Google Gemini API Key from Google AI Studio . Leave blank if using Vertex AI with service account."
+ "authField": "GEMINI_API_KEY||GOOGLE_KEY||GOOGLE_SERVICE_KEY_FILE",
+ "label": "Gemini API Key (optional)",
+ "description": "Your Google Gemini API Key from Google AI Studio . Leave blank to use Vertex AI with a service account (GOOGLE_SERVICE_KEY_FILE or api/data/auth.json).",
+ "optional": true
}
]
}
diff --git a/api/app/clients/tools/structured/GeminiImageGen.js b/api/app/clients/tools/structured/GeminiImageGen.js
index c0e5a0ce1d..f197f1d41b 100644
--- a/api/app/clients/tools/structured/GeminiImageGen.js
+++ b/api/app/clients/tools/structured/GeminiImageGen.js
@@ -1,4 +1,3 @@
-const fs = require('fs');
const path = require('path');
const sharp = require('sharp');
const { v4 } = require('uuid');
@@ -6,12 +5,7 @@ const { ProxyAgent } = require('undici');
const { GoogleGenAI } = require('@google/genai');
const { tool } = require('@langchain/core/tools');
const { logger } = require('@librechat/data-schemas');
-const {
- FileContext,
- ContentTypes,
- FileSources,
- EImageOutputType,
-} = require('librechat-data-provider');
+const { ContentTypes, EImageOutputType } = require('librechat-data-provider');
const {
geminiToolkit,
loadServiceKey,
@@ -19,8 +13,7 @@ const {
getTransactionsConfig,
} = require('@librechat/api');
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
-const { spendTokens } = require('~/models/spendTokens');
-const { getFiles } = require('~/models/File');
+const { spendTokens, getFiles } = require('~/models');
/**
* Configure proxy support for Google APIs
@@ -59,17 +52,12 @@ const displayMessage =
* @returns {string} - The processed string
*/
function replaceUnwantedChars(inputString) {
- return inputString?.replace(/[^\w\s\-_.,!?()]/g, '') || '';
-}
-
-/**
- * Validate and sanitize image format
- * @param {string} format - The format to validate
- * @returns {string} - Safe format
- */
-function getSafeFormat(format) {
- const allowedFormats = ['png', 'jpg', 'jpeg', 'webp', 'gif'];
- return allowedFormats.includes(format?.toLowerCase()) ? format.toLowerCase() : 'png';
+ return (
+ inputString
+ ?.replace(/\r\n|\r|\n/g, ' ')
+ .replace(/"/g, '')
+ .trim() || ''
+ );
}
/**
@@ -117,11 +105,8 @@ async function initializeGeminiClient(options = {}) {
return new GoogleGenAI({ apiKey: googleKey });
}
- // Fall back to Vertex AI with service account
logger.debug('[GeminiImageGen] Using Vertex AI with service account');
const credentialsPath = getDefaultServiceKeyPath();
-
- // Use loadServiceKey for consistent loading (supports file paths, JSON strings, base64)
const serviceKey = await loadServiceKey(credentialsPath);
if (!serviceKey || !serviceKey.project_id) {
@@ -131,75 +116,14 @@ async function initializeGeminiClient(options = {}) {
);
}
- // Set GOOGLE_APPLICATION_CREDENTIALS for any Google Cloud SDK dependencies
- try {
- await fs.promises.access(credentialsPath);
- process.env.GOOGLE_APPLICATION_CREDENTIALS = credentialsPath;
- } catch {
- // File doesn't exist, skip setting env var
- }
-
return new GoogleGenAI({
vertexai: true,
project: serviceKey.project_id,
location: process.env.GOOGLE_LOC || process.env.GOOGLE_CLOUD_LOCATION || 'global',
+ googleAuthOptions: { credentials: serviceKey },
});
}
-/**
- * Save image to local filesystem
- * @param {string} base64Data - Base64 encoded image data
- * @param {string} format - Image format
- * @param {string} userId - User ID
- * @returns {Promise} - The relative URL
- */
-async function saveImageLocally(base64Data, format, userId) {
- const safeFormat = getSafeFormat(format);
- const safeUserId = userId ? path.basename(userId) : 'default';
- const imageName = `gemini-img-${v4()}.${safeFormat}`;
- const userDir = path.join(process.cwd(), 'client/public/images', safeUserId);
-
- await fs.promises.mkdir(userDir, { recursive: true });
-
- const filePath = path.join(userDir, imageName);
- await fs.promises.writeFile(filePath, Buffer.from(base64Data, 'base64'));
-
- logger.debug('[GeminiImageGen] Image saved locally to:', filePath);
- return `/images/${safeUserId}/${imageName}`;
-}
-
-/**
- * Save image to cloud storage
- * @param {Object} params - Parameters
- * @returns {Promise} - The storage URL or null
- */
-async function saveToCloudStorage({ base64Data, format, processFileURL, fileStrategy, userId }) {
- if (!processFileURL || !fileStrategy || !userId) {
- return null;
- }
-
- try {
- const safeFormat = getSafeFormat(format);
- const safeUserId = path.basename(userId);
- const dataURL = `data:image/${safeFormat};base64,${base64Data}`;
- const imageName = `gemini-img-${v4()}.${safeFormat}`;
-
- const result = await processFileURL({
- URL: dataURL,
- basePath: 'images',
- userId: safeUserId,
- fileName: imageName,
- fileStrategy,
- context: FileContext.image_generation,
- });
-
- return result.filepath;
- } catch (error) {
- logger.error('[GeminiImageGen] Error saving to cloud storage:', error);
- return null;
- }
-}
-
/**
* Convert image files to Gemini inline data format
* @param {Object} params - Parameters
@@ -326,8 +250,9 @@ function checkForSafetyBlock(response) {
* @param {string} params.userId - The user ID
* @param {string} params.conversationId - The conversation ID
* @param {string} params.model - The model name
+ * @param {string} [params.messageId] - The response message ID for transaction correlation
*/
-async function recordTokenUsage({ usageMetadata, req, userId, conversationId, model }) {
+async function recordTokenUsage({ usageMetadata, req, userId, conversationId, model, messageId }) {
if (!usageMetadata) {
logger.debug('[GeminiImageGen] No usage metadata available for balance tracking');
return;
@@ -363,6 +288,7 @@ async function recordTokenUsage({ usageMetadata, req, userId, conversationId, mo
{
user: userId,
model,
+ messageId,
conversationId,
context: 'image_generation',
balance,
@@ -390,34 +316,18 @@ function createGeminiImageTool(fields = {}) {
throw new Error('This tool is only available for agents.');
}
- // Skip validation during tool creation - validation happens at runtime in initializeGeminiClient
- // This allows the tool to be added to agents when using Vertex AI without requiring API keys
- // The actual credentials check happens when the tool is invoked
-
- const {
- req,
- imageFiles = [],
- processFileURL,
- userId,
- fileStrategy,
- GEMINI_API_KEY,
- GOOGLE_KEY,
- // GEMINI_VERTEX_ENABLED is used for auth validation only (not used in code)
- // When set as env var, it signals Vertex AI is configured and bypasses API key requirement
- } = fields;
+ const { req, imageFiles = [], userId, fileStrategy, GEMINI_API_KEY, GOOGLE_KEY } = fields;
const imageOutputType = fields.imageOutputType || EImageOutputType.PNG;
const geminiImageGenTool = tool(
- async ({ prompt, image_ids, aspectRatio, imageSize }, _runnableConfig) => {
+ async ({ prompt, image_ids, aspectRatio, imageSize }, runnableConfig) => {
if (!prompt) {
throw new Error('Missing required field: prompt');
}
- logger.debug('[GeminiImageGen] Generating image with prompt:', prompt?.substring(0, 100));
- logger.debug('[GeminiImageGen] Options:', { aspectRatio, imageSize });
+ logger.debug('[GeminiImageGen] Generating image', { aspectRatio, imageSize });
- // Initialize Gemini client with user-provided credentials
let ai;
try {
ai = await initializeGeminiClient({
@@ -432,10 +342,8 @@ function createGeminiImageTool(fields = {}) {
];
}
- // Build request contents
const contents = [{ text: replaceUnwantedChars(prompt) }];
- // Add context images if provided
if (image_ids?.length > 0) {
const contextImages = await convertImagesToInlineData({
imageFiles,
@@ -447,28 +355,34 @@ function createGeminiImageTool(fields = {}) {
logger.debug('[GeminiImageGen] Added', contextImages.length, 'context images');
}
- // Generate image
let apiResponse;
const geminiModel = process.env.GEMINI_IMAGE_MODEL || 'gemini-2.5-flash-image';
- try {
- // Build config with optional imageConfig
- const config = {
- responseModalities: ['TEXT', 'IMAGE'],
- };
+ const config = {
+ responseModalities: ['TEXT', 'IMAGE'],
+ };
- // Add imageConfig if aspectRatio or imageSize is specified
- // Note: gemini-2.5-flash-image doesn't support imageSize
- const supportsImageSize = !geminiModel.includes('gemini-2.5-flash-image');
- if (aspectRatio || (imageSize && supportsImageSize)) {
- config.imageConfig = {};
- if (aspectRatio) {
- config.imageConfig.aspectRatio = aspectRatio;
- }
- if (imageSize && supportsImageSize) {
- config.imageConfig.imageSize = imageSize;
- }
+ const supportsImageSize = !geminiModel.includes('gemini-2.5-flash-image');
+ if (aspectRatio || (imageSize && supportsImageSize)) {
+ config.imageConfig = {};
+ if (aspectRatio) {
+ config.imageConfig.aspectRatio = aspectRatio;
}
+ if (imageSize && supportsImageSize) {
+ config.imageConfig.imageSize = imageSize;
+ }
+ }
+ let derivedSignal = null;
+ let abortHandler = null;
+
+ if (runnableConfig?.signal) {
+ derivedSignal = AbortSignal.any([runnableConfig.signal]);
+ abortHandler = () => logger.debug('[GeminiImageGen] Image generation aborted');
+ derivedSignal.addEventListener('abort', abortHandler, { once: true });
+ config.abortSignal = derivedSignal;
+ }
+
+ try {
apiResponse = await ai.models.generateContent({
model: geminiModel,
contents,
@@ -480,9 +394,12 @@ function createGeminiImageTool(fields = {}) {
[{ type: ContentTypes.TEXT, text: `Image generation failed: ${error.message}` }],
{ content: [], file_ids: [] },
];
+ } finally {
+ if (abortHandler && derivedSignal) {
+ derivedSignal.removeEventListener('abort', abortHandler);
+ }
}
- // Check for safety blocks
const safetyBlock = checkForSafetyBlock(apiResponse);
if (safetyBlock) {
logger.warn('[GeminiImageGen] Safety block:', safetyBlock);
@@ -509,46 +426,7 @@ function createGeminiImageTool(fields = {}) {
const imageData = convertedBuffer.toString('base64');
const mimeType = outputFormat === 'jpeg' ? 'image/jpeg' : `image/${outputFormat}`;
- logger.debug('[GeminiImageGen] Image format:', { outputFormat, mimeType });
-
- let imageUrl;
- const useLocalStorage = !fileStrategy || fileStrategy === FileSources.local;
-
- if (useLocalStorage) {
- try {
- imageUrl = await saveImageLocally(imageData, outputFormat, userId);
- } catch (error) {
- logger.error('[GeminiImageGen] Local save failed:', error);
- imageUrl = `data:${mimeType};base64,${imageData}`;
- }
- } else {
- const cloudUrl = await saveToCloudStorage({
- base64Data: imageData,
- format: outputFormat,
- processFileURL,
- fileStrategy,
- userId,
- });
-
- if (cloudUrl) {
- imageUrl = cloudUrl;
- } else {
- // Fallback to local
- try {
- imageUrl = await saveImageLocally(imageData, outputFormat, userId);
- } catch (_error) {
- imageUrl = `data:${mimeType};base64,${imageData}`;
- }
- }
- }
-
- logger.debug('[GeminiImageGen] Image URL:', imageUrl);
-
- // For the artifact, we need a data URL (same as OpenAI)
- // The local file save is for persistence, but the response needs a data URL
const dataUrl = `data:${mimeType};base64,${imageData}`;
-
- // Return in content_and_artifact format (same as OpenAI)
const file_ids = [v4()];
const content = [
{
@@ -567,12 +445,15 @@ function createGeminiImageTool(fields = {}) {
},
];
- // Record token usage for balance tracking (don't await to avoid blocking response)
- const conversationId = _runnableConfig?.configurable?.thread_id;
+ const conversationId = runnableConfig?.configurable?.thread_id;
+ const messageId =
+ runnableConfig?.configurable?.run_id ??
+ runnableConfig?.configurable?.requestBody?.messageId;
recordTokenUsage({
usageMetadata: apiResponse.usageMetadata,
req,
userId,
+ messageId,
conversationId,
model: geminiModel,
}).catch((error) => {
diff --git a/api/app/clients/tools/structured/specs/DALLE3-proxy.spec.js b/api/app/clients/tools/structured/specs/DALLE3-proxy.spec.js
index 4481a7d70f..262842b3c2 100644
--- a/api/app/clients/tools/structured/specs/DALLE3-proxy.spec.js
+++ b/api/app/clients/tools/structured/specs/DALLE3-proxy.spec.js
@@ -1,7 +1,6 @@
const DALLE3 = require('../DALLE3');
const { ProxyAgent } = require('undici');
-jest.mock('tiktoken');
const processFileURL = jest.fn();
describe('DALLE3 Proxy Configuration', () => {
diff --git a/api/app/clients/tools/structured/specs/DALLE3.spec.js b/api/app/clients/tools/structured/specs/DALLE3.spec.js
index d2040989f9..6071929bfc 100644
--- a/api/app/clients/tools/structured/specs/DALLE3.spec.js
+++ b/api/app/clients/tools/structured/specs/DALLE3.spec.js
@@ -14,15 +14,6 @@ jest.mock('@librechat/data-schemas', () => {
};
});
-jest.mock('tiktoken', () => {
- return {
- encoding_for_model: jest.fn().mockReturnValue({
- encode: jest.fn(),
- decode: jest.fn(),
- }),
- };
-});
-
const processFileURL = jest.fn();
const generate = jest.fn();
diff --git a/api/app/clients/tools/util/handleTools.js b/api/app/clients/tools/util/handleTools.js
index 65c88ce83f..4b86101425 100644
--- a/api/app/clients/tools/util/handleTools.js
+++ b/api/app/clients/tools/util/handleTools.js
@@ -7,6 +7,7 @@ const {
} = require('@librechat/agents');
const {
checkAccess,
+ toolkitParent,
createSafeUser,
mcpToolPattern,
loadWebSearchAuth,
@@ -44,7 +45,7 @@ const { getUserPluginAuthValue } = require('~/server/services/PluginService');
const { createMCPTool, createMCPTools } = require('~/server/services/MCP');
const { loadAuthValues } = require('~/server/services/Tools/credentials');
const { getMCPServerTools } = require('~/server/services/Config');
-const { getRoleByName } = require('~/models/Role');
+const { getRoleByName } = require('~/models');
/**
* Validates the availability and authentication of tools for a user based on environment variables or user-specific plugin authentication values.
@@ -207,7 +208,7 @@ const loadTools = async ({
},
gemini_image_gen: async (toolContextMap) => {
const authFields = getAuthFields('gemini_image_gen');
- const authValues = await loadAuthValues({ userId: user, authFields });
+ const authValues = await loadAuthValues({ userId: user, authFields, throwError: false });
const imageFiles = options.tool_resources?.[EToolResources.image_edit]?.files ?? [];
const toolContext = buildImageToolContext({
imageFiles,
@@ -222,7 +223,6 @@ const loadTools = async ({
isAgent: !!agent,
req: options.req,
imageFiles,
- processFileURL: options.processFileURL,
userId: user,
fileStrategy,
});
@@ -370,8 +370,16 @@ const loadTools = async ({
continue;
}
- if (customConstructors[tool]) {
- requestedTools[tool] = async () => customConstructors[tool](toolContextMap);
+ const toolKey = customConstructors[tool] ? tool : toolkitParent[tool];
+ if (toolKey && customConstructors[toolKey]) {
+ if (!requestedTools[toolKey]) {
+ let cached;
+ requestedTools[toolKey] = async () => {
+ cached ??= customConstructors[toolKey](toolContextMap);
+ return cached;
+ };
+ }
+ requestedTools[tool] = requestedTools[toolKey];
continue;
}
diff --git a/api/cache/getLogStores.js b/api/cache/getLogStores.js
index 3089192196..70eb681e53 100644
--- a/api/cache/getLogStores.js
+++ b/api/cache/getLogStores.js
@@ -47,7 +47,7 @@ const namespaces = {
[CacheKeys.MODEL_QUERIES]: standardCache(CacheKeys.MODEL_QUERIES),
[CacheKeys.AUDIO_RUNS]: standardCache(CacheKeys.AUDIO_RUNS, Time.TEN_MINUTES),
[CacheKeys.MESSAGES]: standardCache(CacheKeys.MESSAGES, Time.ONE_MINUTE),
- [CacheKeys.FLOWS]: standardCache(CacheKeys.FLOWS, Time.ONE_MINUTE * 3),
+ [CacheKeys.FLOWS]: standardCache(CacheKeys.FLOWS, Time.ONE_MINUTE * 10),
[CacheKeys.OPENID_EXCHANGED_TOKENS]: standardCache(
CacheKeys.OPENID_EXCHANGED_TOKENS,
Time.TEN_MINUTES,
diff --git a/api/db/connect.js b/api/db/connect.js
index 26166ccff8..3534884b57 100644
--- a/api/db/connect.js
+++ b/api/db/connect.js
@@ -40,6 +40,10 @@ if (!cached) {
cached = global.mongoose = { conn: null, promise: null };
}
+mongoose.connection.on('error', (err) => {
+ logger.error('[connectDb] MongoDB connection error:', err);
+});
+
async function connectDb() {
if (cached.conn && cached.conn?._readyState === 1) {
return cached.conn;
diff --git a/api/db/indexSync.js b/api/db/indexSync.js
index 8e8e999d92..130cde77b8 100644
--- a/api/db/indexSync.js
+++ b/api/db/indexSync.js
@@ -236,8 +236,12 @@ async function performSync(flowManager, flowId, flowType) {
const messageCount = messageProgress.totalDocuments;
const messagesIndexed = messageProgress.totalProcessed;
const unindexedMessages = messageCount - messagesIndexed;
+ const noneIndexed = messagesIndexed === 0 && unindexedMessages > 0;
- if (settingsUpdated || unindexedMessages > syncThreshold) {
+ if (settingsUpdated || noneIndexed || unindexedMessages > syncThreshold) {
+ if (noneIndexed && !settingsUpdated) {
+ logger.info('[indexSync] No messages marked as indexed, forcing full sync');
+ }
logger.info(`[indexSync] Starting message sync (${unindexedMessages} unindexed)`);
await Message.syncWithMeili();
messagesSync = true;
@@ -261,9 +265,13 @@ async function performSync(flowManager, flowId, flowType) {
const convoCount = convoProgress.totalDocuments;
const convosIndexed = convoProgress.totalProcessed;
-
const unindexedConvos = convoCount - convosIndexed;
- if (settingsUpdated || unindexedConvos > syncThreshold) {
+ const noneConvosIndexed = convosIndexed === 0 && unindexedConvos > 0;
+
+ if (settingsUpdated || noneConvosIndexed || unindexedConvos > syncThreshold) {
+ if (noneConvosIndexed && !settingsUpdated) {
+ logger.info('[indexSync] No conversations marked as indexed, forcing full sync');
+ }
logger.info(`[indexSync] Starting convos sync (${unindexedConvos} unindexed)`);
await Conversation.syncWithMeili();
convosSync = true;
diff --git a/api/db/indexSync.spec.js b/api/db/indexSync.spec.js
index c2e5901d6a..dbe07c7595 100644
--- a/api/db/indexSync.spec.js
+++ b/api/db/indexSync.spec.js
@@ -462,4 +462,69 @@ describe('performSync() - syncThreshold logic', () => {
);
expect(mockLogger.info).toHaveBeenCalledWith('[indexSync] Starting convos sync (50 unindexed)');
});
+
+ test('forces sync when zero documents indexed (reset scenario) even if below threshold', async () => {
+ Message.getSyncProgress.mockResolvedValue({
+ totalProcessed: 0,
+ totalDocuments: 680,
+ isComplete: false,
+ });
+
+ Conversation.getSyncProgress.mockResolvedValue({
+ totalProcessed: 0,
+ totalDocuments: 76,
+ isComplete: false,
+ });
+
+ Message.syncWithMeili.mockResolvedValue(undefined);
+ Conversation.syncWithMeili.mockResolvedValue(undefined);
+
+ const indexSync = require('./indexSync');
+ await indexSync();
+
+ expect(Message.syncWithMeili).toHaveBeenCalledTimes(1);
+ expect(Conversation.syncWithMeili).toHaveBeenCalledTimes(1);
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] No messages marked as indexed, forcing full sync',
+ );
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] Starting message sync (680 unindexed)',
+ );
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] No conversations marked as indexed, forcing full sync',
+ );
+ expect(mockLogger.info).toHaveBeenCalledWith('[indexSync] Starting convos sync (76 unindexed)');
+ });
+
+ test('does NOT force sync when some documents already indexed and below threshold', async () => {
+ Message.getSyncProgress.mockResolvedValue({
+ totalProcessed: 630,
+ totalDocuments: 680,
+ isComplete: false,
+ });
+
+ Conversation.getSyncProgress.mockResolvedValue({
+ totalProcessed: 70,
+ totalDocuments: 76,
+ isComplete: false,
+ });
+
+ const indexSync = require('./indexSync');
+ await indexSync();
+
+ expect(Message.syncWithMeili).not.toHaveBeenCalled();
+ expect(Conversation.syncWithMeili).not.toHaveBeenCalled();
+ expect(mockLogger.info).not.toHaveBeenCalledWith(
+ '[indexSync] No messages marked as indexed, forcing full sync',
+ );
+ expect(mockLogger.info).not.toHaveBeenCalledWith(
+ '[indexSync] No conversations marked as indexed, forcing full sync',
+ );
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] 50 messages unindexed (below threshold: 1000, skipping)',
+ );
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] 6 convos unindexed (below threshold: 1000, skipping)',
+ );
+ });
});
diff --git a/api/jest.config.js b/api/jest.config.js
index 20ee3c6aed..47f8b7287b 100644
--- a/api/jest.config.js
+++ b/api/jest.config.js
@@ -3,12 +3,13 @@ module.exports = {
clearMocks: true,
roots: [''],
coverageDirectory: 'coverage',
+ maxWorkers: '50%',
testTimeout: 30000, // 30 seconds timeout for all tests
setupFiles: ['./test/jestSetup.js', './test/__mocks__/logger.js'],
moduleNameMapper: {
'~/(.*)': '/$1',
'~/data/auth.json': '/__mocks__/auth.mock.json',
- '^openid-client/passport$': '/test/__mocks__/openid-client-passport.js', // Mock for the passport strategy part
+ '^openid-client/passport$': '/test/__mocks__/openid-client-passport.js',
'^openid-client$': '/test/__mocks__/openid-client.js',
},
transformIgnorePatterns: ['/node_modules/(?!(openid-client|oauth4webapi|jose)/).*/'],
diff --git a/api/models/Action.js b/api/models/Action.js
deleted file mode 100644
index 20aa20a7e4..0000000000
--- a/api/models/Action.js
+++ /dev/null
@@ -1,77 +0,0 @@
-const { Action } = require('~/db/models');
-
-/**
- * Update an action with new data without overwriting existing properties,
- * or create a new action if it doesn't exist.
- *
- * @param {Object} searchParams - The search parameters to find the action to update.
- * @param {string} searchParams.action_id - The ID of the action to update.
- * @param {string} searchParams.user - The user ID of the action's author.
- * @param {Object} updateData - An object containing the properties to update.
- * @returns {Promise} The updated or newly created action document as a plain object.
- */
-const updateAction = async (searchParams, updateData) => {
- const options = { new: true, upsert: true };
- return await Action.findOneAndUpdate(searchParams, updateData, options).lean();
-};
-
-/**
- * Retrieves all actions that match the given search parameters.
- *
- * @param {Object} searchParams - The search parameters to find matching actions.
- * @param {boolean} includeSensitive - Flag to include sensitive data in the metadata.
- * @returns {Promise>} A promise that resolves to an array of action documents as plain objects.
- */
-const getActions = async (searchParams, includeSensitive = false) => {
- const actions = await Action.find(searchParams).lean();
-
- if (!includeSensitive) {
- for (let i = 0; i < actions.length; i++) {
- const metadata = actions[i].metadata;
- if (!metadata) {
- continue;
- }
-
- const sensitiveFields = ['api_key', 'oauth_client_id', 'oauth_client_secret'];
- for (let field of sensitiveFields) {
- if (metadata[field]) {
- delete metadata[field];
- }
- }
- }
- }
-
- return actions;
-};
-
-/**
- * Deletes an action by params.
- *
- * @param {Object} searchParams - The search parameters to find the action to delete.
- * @param {string} searchParams.action_id - The ID of the action to delete.
- * @param {string} searchParams.user - The user ID of the action's author.
- * @returns {Promise} A promise that resolves to the deleted action document as a plain object, or null if no document was found.
- */
-const deleteAction = async (searchParams) => {
- return await Action.findOneAndDelete(searchParams).lean();
-};
-
-/**
- * Deletes actions by params.
- *
- * @param {Object} searchParams - The search parameters to find the actions to delete.
- * @param {string} searchParams.action_id - The ID of the action(s) to delete.
- * @param {string} searchParams.user - The user ID of the action's author.
- * @returns {Promise} A promise that resolves to the number of deleted action documents.
- */
-const deleteActions = async (searchParams) => {
- const result = await Action.deleteMany(searchParams);
- return result.deletedCount;
-};
-
-module.exports = {
- getActions,
- updateAction,
- deleteAction,
- deleteActions,
-};
diff --git a/api/models/Agent.js b/api/models/Agent.js
deleted file mode 100644
index 663285183a..0000000000
--- a/api/models/Agent.js
+++ /dev/null
@@ -1,931 +0,0 @@
-const mongoose = require('mongoose');
-const crypto = require('node:crypto');
-const { logger } = require('@librechat/data-schemas');
-const { getCustomEndpointConfig } = require('@librechat/api');
-const {
- Tools,
- SystemRoles,
- ResourceType,
- actionDelimiter,
- isAgentsEndpoint,
- isEphemeralAgentId,
- encodeEphemeralAgentId,
-} = require('librechat-data-provider');
-const { mcp_all, mcp_delimiter } = require('librechat-data-provider').Constants;
-const {
- removeAgentFromAllProjects,
- removeAgentIdsFromProject,
- addAgentIdsToProject,
-} = require('./Project');
-const { removeAllPermissions } = require('~/server/services/PermissionService');
-const { getMCPServerTools } = require('~/server/services/Config');
-const { Agent, AclEntry, User } = require('~/db/models');
-const { getActions } = require('./Action');
-
-/**
- * Extracts unique MCP server names from tools array
- * Tools format: "toolName_mcp_serverName" or "sys__server__sys_mcp_serverName"
- * @param {string[]} tools - Array of tool identifiers
- * @returns {string[]} Array of unique MCP server names
- */
-const extractMCPServerNames = (tools) => {
- if (!tools || !Array.isArray(tools)) {
- return [];
- }
- const serverNames = new Set();
- for (const tool of tools) {
- if (!tool || !tool.includes(mcp_delimiter)) {
- continue;
- }
- const parts = tool.split(mcp_delimiter);
- if (parts.length >= 2) {
- serverNames.add(parts[parts.length - 1]);
- }
- }
- return Array.from(serverNames);
-};
-
-/**
- * Create an agent with the provided data.
- * @param {Object} agentData - The agent data to create.
- * @returns {Promise} The created agent document as a plain object.
- * @throws {Error} If the agent creation fails.
- */
-const createAgent = async (agentData) => {
- const { author: _author, ...versionData } = agentData;
- const timestamp = new Date();
- const initialAgentData = {
- ...agentData,
- versions: [
- {
- ...versionData,
- createdAt: timestamp,
- updatedAt: timestamp,
- },
- ],
- category: agentData.category || 'general',
- mcpServerNames: extractMCPServerNames(agentData.tools),
- };
-
- return (await Agent.create(initialAgentData)).toObject();
-};
-
-/**
- * Get an agent document based on the provided ID.
- *
- * @param {Object} searchParameter - The search parameters to find the agent to update.
- * @param {string} searchParameter.id - The ID of the agent to update.
- * @param {string} searchParameter.author - The user ID of the agent's author.
- * @returns {Promise} The agent document as a plain object, or null if not found.
- */
-const getAgent = async (searchParameter) => await Agent.findOne(searchParameter).lean();
-
-/**
- * Get multiple agent documents based on the provided search parameters.
- *
- * @param {Object} searchParameter - The search parameters to find agents.
- * @returns {Promise} Array of agent documents as plain objects.
- */
-const getAgents = async (searchParameter) => await Agent.find(searchParameter).lean();
-
-/**
- * Load an agent based on the provided ID
- *
- * @param {Object} params
- * @param {ServerRequest} params.req
- * @param {string} params.spec
- * @param {string} params.agent_id
- * @param {string} params.endpoint
- * @param {import('@librechat/agents').ClientOptions} [params.model_parameters]
- * @returns {Promise} The agent document as a plain object, or null if not found.
- */
-const loadEphemeralAgent = async ({ req, spec, endpoint, model_parameters: _m }) => {
- const { model, ...model_parameters } = _m;
- const modelSpecs = req.config?.modelSpecs?.list;
- /** @type {TModelSpec | null} */
- let modelSpec = null;
- if (spec != null && spec !== '') {
- modelSpec = modelSpecs?.find((s) => s.name === spec) || null;
- }
- /** @type {TEphemeralAgent | null} */
- const ephemeralAgent = req.body.ephemeralAgent;
- const mcpServers = new Set(ephemeralAgent?.mcp);
- const userId = req.user?.id; // note: userId cannot be undefined at runtime
- if (modelSpec?.mcpServers) {
- for (const mcpServer of modelSpec.mcpServers) {
- mcpServers.add(mcpServer);
- }
- }
- /** @type {string[]} */
- const tools = [];
- if (ephemeralAgent?.execute_code === true || modelSpec?.executeCode === true) {
- tools.push(Tools.execute_code);
- }
- if (ephemeralAgent?.file_search === true || modelSpec?.fileSearch === true) {
- tools.push(Tools.file_search);
- }
- if (ephemeralAgent?.web_search === true || modelSpec?.webSearch === true) {
- tools.push(Tools.web_search);
- }
-
- const addedServers = new Set();
- if (mcpServers.size > 0) {
- for (const mcpServer of mcpServers) {
- if (addedServers.has(mcpServer)) {
- continue;
- }
- const serverTools = await getMCPServerTools(userId, mcpServer);
- if (!serverTools) {
- tools.push(`${mcp_all}${mcp_delimiter}${mcpServer}`);
- addedServers.add(mcpServer);
- continue;
- }
- tools.push(...Object.keys(serverTools));
- addedServers.add(mcpServer);
- }
- }
-
- const instructions = req.body.promptPrefix;
-
- // Get endpoint config for modelDisplayLabel fallback
- const appConfig = req.config;
- let endpointConfig = appConfig?.endpoints?.[endpoint];
- if (!isAgentsEndpoint(endpoint) && !endpointConfig) {
- try {
- endpointConfig = getCustomEndpointConfig({ endpoint, appConfig });
- } catch (err) {
- logger.error('[loadEphemeralAgent] Error getting custom endpoint config', err);
- }
- }
-
- // For ephemeral agents, use modelLabel if provided, then model spec's label,
- // then modelDisplayLabel from endpoint config, otherwise empty string to show model name
- const sender =
- model_parameters?.modelLabel ?? modelSpec?.label ?? endpointConfig?.modelDisplayLabel ?? '';
-
- // Encode ephemeral agent ID with endpoint, model, and computed sender for display
- const ephemeralId = encodeEphemeralAgentId({ endpoint, model, sender });
-
- const result = {
- id: ephemeralId,
- instructions,
- provider: endpoint,
- model_parameters,
- model,
- tools,
- };
-
- if (ephemeralAgent?.artifacts != null && ephemeralAgent.artifacts) {
- result.artifacts = ephemeralAgent.artifacts;
- }
- return result;
-};
-
-/**
- * Load an agent based on the provided ID
- *
- * @param {Object} params
- * @param {ServerRequest} params.req
- * @param {string} params.spec
- * @param {string} params.agent_id
- * @param {string} params.endpoint
- * @param {import('@librechat/agents').ClientOptions} [params.model_parameters]
- * @returns {Promise} The agent document as a plain object, or null if not found.
- */
-const loadAgent = async ({ req, spec, agent_id, endpoint, model_parameters }) => {
- if (!agent_id) {
- return null;
- }
- if (isEphemeralAgentId(agent_id)) {
- return await loadEphemeralAgent({ req, spec, endpoint, model_parameters });
- }
- const agent = await getAgent({
- id: agent_id,
- });
-
- if (!agent) {
- return null;
- }
-
- agent.version = agent.versions ? agent.versions.length : 0;
- return agent;
-};
-
-/**
- * Check if a version already exists in the versions array, excluding timestamp and author fields
- * @param {Object} updateData - The update data to compare
- * @param {Object} currentData - The current agent data
- * @param {Array} versions - The existing versions array
- * @param {string} [actionsHash] - Hash of current action metadata
- * @returns {Object|null} - The matching version if found, null otherwise
- */
-const isDuplicateVersion = (updateData, currentData, versions, actionsHash = null) => {
- if (!versions || versions.length === 0) {
- return null;
- }
-
- const excludeFields = [
- '_id',
- 'id',
- 'createdAt',
- 'updatedAt',
- 'author',
- 'updatedBy',
- 'created_at',
- 'updated_at',
- '__v',
- 'versions',
- 'actionsHash', // Exclude actionsHash from direct comparison
- ];
-
- const { $push: _$push, $pull: _$pull, $addToSet: _$addToSet, ...directUpdates } = updateData;
-
- if (Object.keys(directUpdates).length === 0 && !actionsHash) {
- return null;
- }
-
- const wouldBeVersion = { ...currentData, ...directUpdates };
- const lastVersion = versions[versions.length - 1];
-
- if (actionsHash && lastVersion.actionsHash !== actionsHash) {
- return null;
- }
-
- const allFields = new Set([...Object.keys(wouldBeVersion), ...Object.keys(lastVersion)]);
-
- const importantFields = Array.from(allFields).filter((field) => !excludeFields.includes(field));
-
- let isMatch = true;
- for (const field of importantFields) {
- const wouldBeValue = wouldBeVersion[field];
- const lastVersionValue = lastVersion[field];
-
- // Skip if both are undefined/null
- if (!wouldBeValue && !lastVersionValue) {
- continue;
- }
-
- // Handle arrays
- if (Array.isArray(wouldBeValue) || Array.isArray(lastVersionValue)) {
- // Normalize: treat undefined/null as empty array for comparison
- let wouldBeArr;
- if (Array.isArray(wouldBeValue)) {
- wouldBeArr = wouldBeValue;
- } else if (wouldBeValue == null) {
- wouldBeArr = [];
- } else {
- wouldBeArr = [wouldBeValue];
- }
-
- let lastVersionArr;
- if (Array.isArray(lastVersionValue)) {
- lastVersionArr = lastVersionValue;
- } else if (lastVersionValue == null) {
- lastVersionArr = [];
- } else {
- lastVersionArr = [lastVersionValue];
- }
-
- if (wouldBeArr.length !== lastVersionArr.length) {
- isMatch = false;
- break;
- }
-
- // Special handling for projectIds (MongoDB ObjectIds)
- if (field === 'projectIds') {
- const wouldBeIds = wouldBeArr.map((id) => id.toString()).sort();
- const versionIds = lastVersionArr.map((id) => id.toString()).sort();
-
- if (!wouldBeIds.every((id, i) => id === versionIds[i])) {
- isMatch = false;
- break;
- }
- }
- // Handle arrays of objects
- else if (
- wouldBeArr.length > 0 &&
- typeof wouldBeArr[0] === 'object' &&
- wouldBeArr[0] !== null
- ) {
- const sortedWouldBe = [...wouldBeArr].map((item) => JSON.stringify(item)).sort();
- const sortedVersion = [...lastVersionArr].map((item) => JSON.stringify(item)).sort();
-
- if (!sortedWouldBe.every((item, i) => item === sortedVersion[i])) {
- isMatch = false;
- break;
- }
- } else {
- const sortedWouldBe = [...wouldBeArr].sort();
- const sortedVersion = [...lastVersionArr].sort();
-
- if (!sortedWouldBe.every((item, i) => item === sortedVersion[i])) {
- isMatch = false;
- break;
- }
- }
- }
- // Handle objects
- else if (typeof wouldBeValue === 'object' && wouldBeValue !== null) {
- const lastVersionObj =
- typeof lastVersionValue === 'object' && lastVersionValue !== null ? lastVersionValue : {};
-
- // For empty objects, normalize the comparison
- const wouldBeKeys = Object.keys(wouldBeValue);
- const lastVersionKeys = Object.keys(lastVersionObj);
-
- // If both are empty objects, they're equal
- if (wouldBeKeys.length === 0 && lastVersionKeys.length === 0) {
- continue;
- }
-
- // Otherwise do a deep comparison
- if (JSON.stringify(wouldBeValue) !== JSON.stringify(lastVersionObj)) {
- isMatch = false;
- break;
- }
- }
- // Handle primitive values
- else {
- // For primitives, handle the case where one is undefined and the other is a default value
- if (wouldBeValue !== lastVersionValue) {
- // Special handling for boolean false vs undefined
- if (
- typeof wouldBeValue === 'boolean' &&
- wouldBeValue === false &&
- lastVersionValue === undefined
- ) {
- continue;
- }
- // Special handling for empty string vs undefined
- if (
- typeof wouldBeValue === 'string' &&
- wouldBeValue === '' &&
- lastVersionValue === undefined
- ) {
- continue;
- }
- isMatch = false;
- break;
- }
- }
- }
-
- return isMatch ? lastVersion : null;
-};
-
-/**
- * Update an agent with new data without overwriting existing
- * properties, or create a new agent if it doesn't exist.
- * When an agent is updated, a copy of the current state will be saved to the versions array.
- *
- * @param {Object} searchParameter - The search parameters to find the agent to update.
- * @param {string} searchParameter.id - The ID of the agent to update.
- * @param {string} [searchParameter.author] - The user ID of the agent's author.
- * @param {Object} updateData - An object containing the properties to update.
- * @param {Object} [options] - Optional configuration object.
- * @param {string} [options.updatingUserId] - The ID of the user performing the update (used for tracking non-author updates).
- * @param {boolean} [options.forceVersion] - Force creation of a new version even if no fields changed.
- * @param {boolean} [options.skipVersioning] - Skip version creation entirely (useful for isolated operations like sharing).
- * @returns {Promise} The updated or newly created agent document as a plain object.
- * @throws {Error} If the update would create a duplicate version
- */
-const updateAgent = async (searchParameter, updateData, options = {}) => {
- const { updatingUserId = null, forceVersion = false, skipVersioning = false } = options;
- const mongoOptions = { new: true, upsert: false };
-
- const currentAgent = await Agent.findOne(searchParameter);
- if (currentAgent) {
- const {
- __v,
- _id,
- id: __id,
- versions,
- author: _author,
- ...versionData
- } = currentAgent.toObject();
- const { $push, $pull, $addToSet, ...directUpdates } = updateData;
-
- // Sync mcpServerNames when tools are updated
- if (directUpdates.tools !== undefined) {
- const mcpServerNames = extractMCPServerNames(directUpdates.tools);
- directUpdates.mcpServerNames = mcpServerNames;
- updateData.mcpServerNames = mcpServerNames; // Also update the original updateData
- }
-
- let actionsHash = null;
-
- // Generate actions hash if agent has actions
- if (currentAgent.actions && currentAgent.actions.length > 0) {
- // Extract action IDs from the format "domain_action_id"
- const actionIds = currentAgent.actions
- .map((action) => {
- const parts = action.split(actionDelimiter);
- return parts[1]; // Get just the action ID part
- })
- .filter(Boolean);
-
- if (actionIds.length > 0) {
- try {
- const actions = await getActions(
- {
- action_id: { $in: actionIds },
- },
- true,
- ); // Include sensitive data for hash
-
- actionsHash = await generateActionMetadataHash(currentAgent.actions, actions);
- } catch (error) {
- logger.error('Error fetching actions for hash generation:', error);
- }
- }
- }
-
- const shouldCreateVersion =
- !skipVersioning &&
- (forceVersion || Object.keys(directUpdates).length > 0 || $push || $pull || $addToSet);
-
- if (shouldCreateVersion) {
- const duplicateVersion = isDuplicateVersion(updateData, versionData, versions, actionsHash);
- if (duplicateVersion && !forceVersion) {
- // No changes detected, return the current agent without creating a new version
- const agentObj = currentAgent.toObject();
- agentObj.version = versions.length;
- return agentObj;
- }
- }
-
- const versionEntry = {
- ...versionData,
- ...directUpdates,
- updatedAt: new Date(),
- };
-
- // Include actions hash in version if available
- if (actionsHash) {
- versionEntry.actionsHash = actionsHash;
- }
-
- // Always store updatedBy field to track who made the change
- if (updatingUserId) {
- versionEntry.updatedBy = new mongoose.Types.ObjectId(updatingUserId);
- }
-
- if (shouldCreateVersion) {
- updateData.$push = {
- ...($push || {}),
- versions: versionEntry,
- };
- }
- }
-
- return Agent.findOneAndUpdate(searchParameter, updateData, mongoOptions).lean();
-};
-
-/**
- * Modifies an agent with the resource file id.
- * @param {object} params
- * @param {ServerRequest} params.req
- * @param {string} params.agent_id
- * @param {string} params.tool_resource
- * @param {string} params.file_id
- * @returns {Promise} The updated agent.
- */
-const addAgentResourceFile = async ({ req, agent_id, tool_resource, file_id }) => {
- const searchParameter = { id: agent_id };
- let agent = await getAgent(searchParameter);
- if (!agent) {
- throw new Error('Agent not found for adding resource file');
- }
- const fileIdsPath = `tool_resources.${tool_resource}.file_ids`;
- await Agent.updateOne(
- {
- id: agent_id,
- [`${fileIdsPath}`]: { $exists: false },
- },
- {
- $set: {
- [`${fileIdsPath}`]: [],
- },
- },
- );
-
- const updateData = {
- $addToSet: {
- tools: tool_resource,
- [fileIdsPath]: file_id,
- },
- };
-
- const updatedAgent = await updateAgent(searchParameter, updateData, {
- updatingUserId: req?.user?.id,
- });
- if (updatedAgent) {
- return updatedAgent;
- } else {
- throw new Error('Agent not found for adding resource file');
- }
-};
-
-/**
- * Removes multiple resource files from an agent using atomic operations.
- * @param {object} params
- * @param {string} params.agent_id
- * @param {Array<{tool_resource: string, file_id: string}>} params.files
- * @returns {Promise} The updated agent.
- * @throws {Error} If the agent is not found or update fails.
- */
-const removeAgentResourceFiles = async ({ agent_id, files }) => {
- const searchParameter = { id: agent_id };
-
- // Group files to remove by resource
- const filesByResource = files.reduce((acc, { tool_resource, file_id }) => {
- if (!acc[tool_resource]) {
- acc[tool_resource] = [];
- }
- acc[tool_resource].push(file_id);
- return acc;
- }, {});
-
- // Step 1: Atomically remove file IDs using $pull
- const pullOps = {};
- const resourcesToCheck = new Set();
- for (const [resource, fileIds] of Object.entries(filesByResource)) {
- const fileIdsPath = `tool_resources.${resource}.file_ids`;
- pullOps[fileIdsPath] = { $in: fileIds };
- resourcesToCheck.add(resource);
- }
-
- const updatePullData = { $pull: pullOps };
- const agentAfterPull = await Agent.findOneAndUpdate(searchParameter, updatePullData, {
- new: true,
- }).lean();
-
- if (!agentAfterPull) {
- // Agent might have been deleted concurrently, or never existed.
- // Check if it existed before trying to throw.
- const agentExists = await getAgent(searchParameter);
- if (!agentExists) {
- throw new Error('Agent not found for removing resource files');
- }
- // If it existed but findOneAndUpdate returned null, something else went wrong.
- throw new Error('Failed to update agent during file removal (pull step)');
- }
-
- // Return the agent state directly after the $pull operation.
- // Skipping the $unset step for now to simplify and test core $pull atomicity.
- // Empty arrays might remain, but the removal itself should be correct.
- return agentAfterPull;
-};
-
-/**
- * Deletes an agent based on the provided ID.
- *
- * @param {Object} searchParameter - The search parameters to find the agent to delete.
- * @param {string} searchParameter.id - The ID of the agent to delete.
- * @param {string} [searchParameter.author] - The user ID of the agent's author.
- * @returns {Promise} Resolves when the agent has been successfully deleted.
- */
-const deleteAgent = async (searchParameter) => {
- const agent = await Agent.findOneAndDelete(searchParameter);
- if (agent) {
- await removeAgentFromAllProjects(agent.id);
- await Promise.all([
- removeAllPermissions({
- resourceType: ResourceType.AGENT,
- resourceId: agent._id,
- }),
- removeAllPermissions({
- resourceType: ResourceType.REMOTE_AGENT,
- resourceId: agent._id,
- }),
- ]);
- try {
- await Agent.updateMany({ 'edges.to': agent.id }, { $pull: { edges: { to: agent.id } } });
- } catch (error) {
- logger.error('[deleteAgent] Error removing agent from handoff edges', error);
- }
- try {
- await User.updateMany(
- { 'favorites.agentId': agent.id },
- { $pull: { favorites: { agentId: agent.id } } },
- );
- } catch (error) {
- logger.error('[deleteAgent] Error removing agent from user favorites', error);
- }
- }
- return agent;
-};
-
-/**
- * Deletes all agents created by a specific user.
- * @param {string} userId - The ID of the user whose agents should be deleted.
- * @returns {Promise} A promise that resolves when all user agents have been deleted.
- */
-const deleteUserAgents = async (userId) => {
- try {
- const userAgents = await getAgents({ author: userId });
-
- if (userAgents.length === 0) {
- return;
- }
-
- const agentIds = userAgents.map((agent) => agent.id);
- const agentObjectIds = userAgents.map((agent) => agent._id);
-
- for (const agentId of agentIds) {
- await removeAgentFromAllProjects(agentId);
- }
-
- await AclEntry.deleteMany({
- resourceType: { $in: [ResourceType.AGENT, ResourceType.REMOTE_AGENT] },
- resourceId: { $in: agentObjectIds },
- });
-
- try {
- await User.updateMany(
- { 'favorites.agentId': { $in: agentIds } },
- { $pull: { favorites: { agentId: { $in: agentIds } } } },
- );
- } catch (error) {
- logger.error('[deleteUserAgents] Error removing agents from user favorites', error);
- }
-
- await Agent.deleteMany({ author: userId });
- } catch (error) {
- logger.error('[deleteUserAgents] General error:', error);
- }
-};
-
-/**
- * Get agents by accessible IDs with optional cursor-based pagination.
- * @param {Object} params - The parameters for getting accessible agents.
- * @param {Array} [params.accessibleIds] - Array of agent ObjectIds the user has ACL access to.
- * @param {Object} [params.otherParams] - Additional query parameters (including author filter).
- * @param {number} [params.limit] - Number of agents to return (max 100). If not provided, returns all agents.
- * @param {string} [params.after] - Cursor for pagination - get agents after this cursor. // base64 encoded JSON string with updatedAt and _id.
- * @returns {Promise} A promise that resolves to an object containing the agents data and pagination info.
- */
-const getListAgentsByAccess = async ({
- accessibleIds = [],
- otherParams = {},
- limit = null,
- after = null,
-}) => {
- const isPaginated = limit !== null && limit !== undefined;
- const normalizedLimit = isPaginated ? Math.min(Math.max(1, parseInt(limit) || 20), 100) : null;
-
- // Build base query combining ACL accessible agents with other filters
- const baseQuery = { ...otherParams, _id: { $in: accessibleIds } };
-
- // Add cursor condition
- if (after) {
- try {
- const cursor = JSON.parse(Buffer.from(after, 'base64').toString('utf8'));
- const { updatedAt, _id } = cursor;
-
- const cursorCondition = {
- $or: [
- { updatedAt: { $lt: new Date(updatedAt) } },
- { updatedAt: new Date(updatedAt), _id: { $gt: new mongoose.Types.ObjectId(_id) } },
- ],
- };
-
- // Merge cursor condition with base query
- if (Object.keys(baseQuery).length > 0) {
- baseQuery.$and = [{ ...baseQuery }, cursorCondition];
- // Remove the original conditions from baseQuery to avoid duplication
- Object.keys(baseQuery).forEach((key) => {
- if (key !== '$and') delete baseQuery[key];
- });
- } else {
- Object.assign(baseQuery, cursorCondition);
- }
- } catch (error) {
- logger.warn('Invalid cursor:', error.message);
- }
- }
-
- let query = Agent.find(baseQuery, {
- id: 1,
- _id: 1,
- name: 1,
- avatar: 1,
- author: 1,
- projectIds: 1,
- description: 1,
- updatedAt: 1,
- category: 1,
- support_contact: 1,
- is_promoted: 1,
- }).sort({ updatedAt: -1, _id: 1 });
-
- // Only apply limit if pagination is requested
- if (isPaginated) {
- query = query.limit(normalizedLimit + 1);
- }
-
- const agents = await query.lean();
-
- const hasMore = isPaginated ? agents.length > normalizedLimit : false;
- const data = (isPaginated ? agents.slice(0, normalizedLimit) : agents).map((agent) => {
- if (agent.author) {
- agent.author = agent.author.toString();
- }
- return agent;
- });
-
- // Generate next cursor only if paginated
- let nextCursor = null;
- if (isPaginated && hasMore && data.length > 0) {
- const lastAgent = agents[normalizedLimit - 1];
- nextCursor = Buffer.from(
- JSON.stringify({
- updatedAt: lastAgent.updatedAt.toISOString(),
- _id: lastAgent._id.toString(),
- }),
- ).toString('base64');
- }
-
- return {
- object: 'list',
- data,
- first_id: data.length > 0 ? data[0].id : null,
- last_id: data.length > 0 ? data[data.length - 1].id : null,
- has_more: hasMore,
- after: nextCursor,
- };
-};
-
-/**
- * Updates the projects associated with an agent, adding and removing project IDs as specified.
- * This function also updates the corresponding projects to include or exclude the agent ID.
- *
- * @param {Object} params - Parameters for updating the agent's projects.
- * @param {IUser} params.user - Parameters for updating the agent's projects.
- * @param {string} params.agentId - The ID of the agent to update.
- * @param {string[]} [params.projectIds] - Array of project IDs to add to the agent.
- * @param {string[]} [params.removeProjectIds] - Array of project IDs to remove from the agent.
- * @returns {Promise} The updated agent document.
- * @throws {Error} If there's an error updating the agent or projects.
- */
-const updateAgentProjects = async ({ user, agentId, projectIds, removeProjectIds }) => {
- const updateOps = {};
-
- if (removeProjectIds && removeProjectIds.length > 0) {
- for (const projectId of removeProjectIds) {
- await removeAgentIdsFromProject(projectId, [agentId]);
- }
- updateOps.$pull = { projectIds: { $in: removeProjectIds } };
- }
-
- if (projectIds && projectIds.length > 0) {
- for (const projectId of projectIds) {
- await addAgentIdsToProject(projectId, [agentId]);
- }
- updateOps.$addToSet = { projectIds: { $each: projectIds } };
- }
-
- if (Object.keys(updateOps).length === 0) {
- return await getAgent({ id: agentId });
- }
-
- const updateQuery = { id: agentId, author: user.id };
- if (user.role === SystemRoles.ADMIN) {
- delete updateQuery.author;
- }
-
- const updatedAgent = await updateAgent(updateQuery, updateOps, {
- updatingUserId: user.id,
- skipVersioning: true,
- });
- if (updatedAgent) {
- return updatedAgent;
- }
- if (updateOps.$addToSet) {
- for (const projectId of projectIds) {
- await removeAgentIdsFromProject(projectId, [agentId]);
- }
- } else if (updateOps.$pull) {
- for (const projectId of removeProjectIds) {
- await addAgentIdsToProject(projectId, [agentId]);
- }
- }
-
- return await getAgent({ id: agentId });
-};
-
-/**
- * Reverts an agent to a specific version in its version history.
- * @param {Object} searchParameter - The search parameters to find the agent to revert.
- * @param {string} searchParameter.id - The ID of the agent to revert.
- * @param {string} [searchParameter.author] - The user ID of the agent's author.
- * @param {number} versionIndex - The index of the version to revert to in the versions array.
- * @returns {Promise} The updated agent document after reverting.
- * @throws {Error} If the agent is not found or the specified version does not exist.
- */
-const revertAgentVersion = async (searchParameter, versionIndex) => {
- const agent = await Agent.findOne(searchParameter);
- if (!agent) {
- throw new Error('Agent not found');
- }
-
- if (!agent.versions || !agent.versions[versionIndex]) {
- throw new Error(`Version ${versionIndex} not found`);
- }
-
- const revertToVersion = agent.versions[versionIndex];
-
- const updateData = {
- ...revertToVersion,
- };
-
- delete updateData._id;
- delete updateData.id;
- delete updateData.versions;
- delete updateData.author;
- delete updateData.updatedBy;
-
- return Agent.findOneAndUpdate(searchParameter, updateData, { new: true }).lean();
-};
-
-/**
- * Generates a hash of action metadata for version comparison
- * @param {string[]} actionIds - Array of action IDs in format "domain_action_id"
- * @param {Action[]} actions - Array of action documents
- * @returns {Promise} - SHA256 hash of the action metadata
- */
-const generateActionMetadataHash = async (actionIds, actions) => {
- if (!actionIds || actionIds.length === 0) {
- return '';
- }
-
- // Create a map of action_id to metadata for quick lookup
- const actionMap = new Map();
- actions.forEach((action) => {
- actionMap.set(action.action_id, action.metadata);
- });
-
- // Sort action IDs for consistent hashing
- const sortedActionIds = [...actionIds].sort();
-
- // Build a deterministic string representation of all action metadata
- const metadataString = sortedActionIds
- .map((actionFullId) => {
- // Extract just the action_id part (after the delimiter)
- const parts = actionFullId.split(actionDelimiter);
- const actionId = parts[1];
-
- const metadata = actionMap.get(actionId);
- if (!metadata) {
- return `${actionId}:null`;
- }
-
- // Sort metadata keys for deterministic output
- const sortedKeys = Object.keys(metadata).sort();
- const metadataStr = sortedKeys
- .map((key) => `${key}:${JSON.stringify(metadata[key])}`)
- .join(',');
- return `${actionId}:{${metadataStr}}`;
- })
- .join(';');
-
- // Use Web Crypto API to generate hash
- const encoder = new TextEncoder();
- const data = encoder.encode(metadataString);
- const hashBuffer = await crypto.webcrypto.subtle.digest('SHA-256', data);
- const hashArray = Array.from(new Uint8Array(hashBuffer));
- const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
-
- return hashHex;
-};
-/**
- * Counts the number of promoted agents.
- * @returns {Promise} - The count of promoted agents
- */
-const countPromotedAgents = async () => {
- const count = await Agent.countDocuments({ is_promoted: true });
- return count;
-};
-
-/**
- * Load a default agent based on the endpoint
- * @param {string} endpoint
- * @returns {Agent | null}
- */
-
-module.exports = {
- getAgent,
- getAgents,
- loadAgent,
- createAgent,
- updateAgent,
- deleteAgent,
- deleteUserAgents,
- revertAgentVersion,
- updateAgentProjects,
- countPromotedAgents,
- addAgentResourceFile,
- getListAgentsByAccess,
- removeAgentResourceFiles,
- generateActionMetadataHash,
-};
diff --git a/api/models/Assistant.js b/api/models/Assistant.js
deleted file mode 100644
index be94d35d7d..0000000000
--- a/api/models/Assistant.js
+++ /dev/null
@@ -1,62 +0,0 @@
-const { Assistant } = require('~/db/models');
-
-/**
- * Update an assistant with new data without overwriting existing properties,
- * or create a new assistant if it doesn't exist.
- *
- * @param {Object} searchParams - The search parameters to find the assistant to update.
- * @param {string} searchParams.assistant_id - The ID of the assistant to update.
- * @param {string} searchParams.user - The user ID of the assistant's author.
- * @param {Object} updateData - An object containing the properties to update.
- * @returns {Promise} The updated or newly created assistant document as a plain object.
- */
-const updateAssistantDoc = async (searchParams, updateData) => {
- const options = { new: true, upsert: true };
- return await Assistant.findOneAndUpdate(searchParams, updateData, options).lean();
-};
-
-/**
- * Retrieves an assistant document based on the provided ID.
- *
- * @param {Object} searchParams - The search parameters to find the assistant to update.
- * @param {string} searchParams.assistant_id - The ID of the assistant to update.
- * @param {string} searchParams.user - The user ID of the assistant's author.
- * @returns {Promise} The assistant document as a plain object, or null if not found.
- */
-const getAssistant = async (searchParams) => await Assistant.findOne(searchParams).lean();
-
-/**
- * Retrieves all assistants that match the given search parameters.
- *
- * @param {Object} searchParams - The search parameters to find matching assistants.
- * @param {Object} [select] - Optional. Specifies which document fields to include or exclude.
- * @returns {Promise>} A promise that resolves to an array of assistant documents as plain objects.
- */
-const getAssistants = async (searchParams, select = null) => {
- let query = Assistant.find(searchParams);
-
- if (select) {
- query = query.select(select);
- }
-
- return await query.lean();
-};
-
-/**
- * Deletes an assistant based on the provided ID.
- *
- * @param {Object} searchParams - The search parameters to find the assistant to delete.
- * @param {string} searchParams.assistant_id - The ID of the assistant to delete.
- * @param {string} searchParams.user - The user ID of the assistant's author.
- * @returns {Promise} Resolves when the assistant has been successfully deleted.
- */
-const deleteAssistant = async (searchParams) => {
- return await Assistant.findOneAndDelete(searchParams);
-};
-
-module.exports = {
- updateAssistantDoc,
- deleteAssistant,
- getAssistants,
- getAssistant,
-};
diff --git a/api/models/Banner.js b/api/models/Banner.js
deleted file mode 100644
index 42ad1599ed..0000000000
--- a/api/models/Banner.js
+++ /dev/null
@@ -1,28 +0,0 @@
-const { logger } = require('@librechat/data-schemas');
-const { Banner } = require('~/db/models');
-
-/**
- * Retrieves the current active banner.
- * @returns {Promise} The active banner object or null if no active banner is found.
- */
-const getBanner = async (user) => {
- try {
- const now = new Date();
- const banner = await Banner.findOne({
- displayFrom: { $lte: now },
- $or: [{ displayTo: { $gte: now } }, { displayTo: null }],
- type: 'banner',
- }).lean();
-
- if (!banner || banner.isPublic || user) {
- return banner;
- }
-
- return null;
- } catch (error) {
- logger.error('[getBanners] Error getting banners', error);
- throw new Error('Error getting banners');
- }
-};
-
-module.exports = { getBanner };
diff --git a/api/models/Categories.js b/api/models/Categories.js
deleted file mode 100644
index 34bd2d8ed2..0000000000
--- a/api/models/Categories.js
+++ /dev/null
@@ -1,57 +0,0 @@
-const { logger } = require('@librechat/data-schemas');
-
-const options = [
- {
- label: 'com_ui_idea',
- value: 'idea',
- },
- {
- label: 'com_ui_travel',
- value: 'travel',
- },
- {
- label: 'com_ui_teach_or_explain',
- value: 'teach_or_explain',
- },
- {
- label: 'com_ui_write',
- value: 'write',
- },
- {
- label: 'com_ui_shop',
- value: 'shop',
- },
- {
- label: 'com_ui_code',
- value: 'code',
- },
- {
- label: 'com_ui_misc',
- value: 'misc',
- },
- {
- label: 'com_ui_roleplay',
- value: 'roleplay',
- },
- {
- label: 'com_ui_finance',
- value: 'finance',
- },
-];
-
-module.exports = {
- /**
- * Retrieves the categories asynchronously.
- * @returns {Promise} An array of category objects.
- * @throws {Error} If there is an error retrieving the categories.
- */
- getCategories: async () => {
- try {
- // const categories = await Categories.find();
- return options;
- } catch (error) {
- logger.error('Error getting categories', error);
- return [];
- }
- },
-};
diff --git a/api/models/Conversation.js b/api/models/Conversation.js
deleted file mode 100644
index a8f5f9a36c..0000000000
--- a/api/models/Conversation.js
+++ /dev/null
@@ -1,367 +0,0 @@
-const { logger } = require('@librechat/data-schemas');
-const { createTempChatExpirationDate } = require('@librechat/api');
-const { getMessages, deleteMessages } = require('./Message');
-const { Conversation } = require('~/db/models');
-
-/**
- * Searches for a conversation by conversationId and returns a lean document with only conversationId and user.
- * @param {string} conversationId - The conversation's ID.
- * @returns {Promise<{conversationId: string, user: string} | null>} The conversation object with selected fields or null if not found.
- */
-const searchConversation = async (conversationId) => {
- try {
- return await Conversation.findOne({ conversationId }, 'conversationId user').lean();
- } catch (error) {
- logger.error('[searchConversation] Error searching conversation', error);
- throw new Error('Error searching conversation');
- }
-};
-
-/**
- * Retrieves a single conversation for a given user and conversation ID.
- * @param {string} user - The user's ID.
- * @param {string} conversationId - The conversation's ID.
- * @returns {Promise} The conversation object.
- */
-const getConvo = async (user, conversationId) => {
- try {
- return await Conversation.findOne({ user, conversationId }).lean();
- } catch (error) {
- logger.error('[getConvo] Error getting single conversation', error);
- throw new Error('Error getting single conversation');
- }
-};
-
-const deleteNullOrEmptyConversations = async () => {
- try {
- const filter = {
- $or: [
- { conversationId: null },
- { conversationId: '' },
- { conversationId: { $exists: false } },
- ],
- };
-
- const result = await Conversation.deleteMany(filter);
-
- // Delete associated messages
- const messageDeleteResult = await deleteMessages(filter);
-
- logger.info(
- `[deleteNullOrEmptyConversations] Deleted ${result.deletedCount} conversations and ${messageDeleteResult.deletedCount} messages`,
- );
-
- return {
- conversations: result,
- messages: messageDeleteResult,
- };
- } catch (error) {
- logger.error('[deleteNullOrEmptyConversations] Error deleting conversations', error);
- throw new Error('Error deleting conversations with null or empty conversationId');
- }
-};
-
-/**
- * Searches for a conversation by conversationId and returns associated file ids.
- * @param {string} conversationId - The conversation's ID.
- * @returns {Promise}
- */
-const getConvoFiles = async (conversationId) => {
- try {
- return (await Conversation.findOne({ conversationId }, 'files').lean())?.files ?? [];
- } catch (error) {
- logger.error('[getConvoFiles] Error getting conversation files', error);
- throw new Error('Error getting conversation files');
- }
-};
-
-module.exports = {
- getConvoFiles,
- searchConversation,
- deleteNullOrEmptyConversations,
- /**
- * Saves a conversation to the database.
- * @param {Object} req - The request object.
- * @param {string} conversationId - The conversation's ID.
- * @param {Object} metadata - Additional metadata to log for operation.
- * @returns {Promise} The conversation object.
- */
- saveConvo: async (req, { conversationId, newConversationId, ...convo }, metadata) => {
- try {
- if (metadata?.context) {
- logger.debug(`[saveConvo] ${metadata.context}`);
- }
-
- const messages = await getMessages({ conversationId }, '_id');
- const update = { ...convo, messages, user: req.user.id };
-
- if (newConversationId) {
- update.conversationId = newConversationId;
- }
-
- if (req?.body?.isTemporary) {
- try {
- const appConfig = req.config;
- update.expiredAt = createTempChatExpirationDate(appConfig?.interfaceConfig);
- } catch (err) {
- logger.error('Error creating temporary chat expiration date:', err);
- logger.info(`---\`saveConvo\` context: ${metadata?.context}`);
- update.expiredAt = null;
- }
- } else {
- update.expiredAt = null;
- }
-
- /** @type {{ $set: Partial; $unset?: Record }} */
- const updateOperation = { $set: update };
- if (metadata && metadata.unsetFields && Object.keys(metadata.unsetFields).length > 0) {
- updateOperation.$unset = metadata.unsetFields;
- }
-
- /** Note: the resulting Model object is necessary for Meilisearch operations */
- const conversation = await Conversation.findOneAndUpdate(
- { conversationId, user: req.user.id },
- updateOperation,
- {
- new: true,
- upsert: true,
- },
- );
-
- return conversation.toObject();
- } catch (error) {
- logger.error('[saveConvo] Error saving conversation', error);
- if (metadata && metadata?.context) {
- logger.info(`[saveConvo] ${metadata.context}`);
- }
- return { message: 'Error saving conversation' };
- }
- },
- bulkSaveConvos: async (conversations) => {
- try {
- const bulkOps = conversations.map((convo) => ({
- updateOne: {
- filter: { conversationId: convo.conversationId, user: convo.user },
- update: convo,
- upsert: true,
- timestamps: false,
- },
- }));
-
- const result = await Conversation.bulkWrite(bulkOps);
- return result;
- } catch (error) {
- logger.error('[bulkSaveConvos] Error saving conversations in bulk', error);
- throw new Error('Failed to save conversations in bulk.');
- }
- },
- getConvosByCursor: async (
- user,
- {
- cursor,
- limit = 25,
- isArchived = false,
- tags,
- search,
- sortBy = 'updatedAt',
- sortDirection = 'desc',
- } = {},
- ) => {
- const filters = [{ user }];
- if (isArchived) {
- filters.push({ isArchived: true });
- } else {
- filters.push({ $or: [{ isArchived: false }, { isArchived: { $exists: false } }] });
- }
-
- if (Array.isArray(tags) && tags.length > 0) {
- filters.push({ tags: { $in: tags } });
- }
-
- filters.push({ $or: [{ expiredAt: null }, { expiredAt: { $exists: false } }] });
-
- if (search) {
- try {
- const meiliResults = await Conversation.meiliSearch(search, { filter: `user = "${user}"` });
- const matchingIds = Array.isArray(meiliResults.hits)
- ? meiliResults.hits.map((result) => result.conversationId)
- : [];
- if (!matchingIds.length) {
- return { conversations: [], nextCursor: null };
- }
- filters.push({ conversationId: { $in: matchingIds } });
- } catch (error) {
- logger.error('[getConvosByCursor] Error during meiliSearch', error);
- throw new Error('Error during meiliSearch');
- }
- }
-
- const validSortFields = ['title', 'createdAt', 'updatedAt'];
- if (!validSortFields.includes(sortBy)) {
- throw new Error(
- `Invalid sortBy field: ${sortBy}. Must be one of ${validSortFields.join(', ')}`,
- );
- }
- const finalSortBy = sortBy;
- const finalSortDirection = sortDirection === 'asc' ? 'asc' : 'desc';
-
- let cursorFilter = null;
- if (cursor) {
- try {
- const decoded = JSON.parse(Buffer.from(cursor, 'base64').toString());
- const { primary, secondary } = decoded;
- const primaryValue = finalSortBy === 'title' ? primary : new Date(primary);
- const secondaryValue = new Date(secondary);
- const op = finalSortDirection === 'asc' ? '$gt' : '$lt';
-
- cursorFilter = {
- $or: [
- { [finalSortBy]: { [op]: primaryValue } },
- {
- [finalSortBy]: primaryValue,
- updatedAt: { [op]: secondaryValue },
- },
- ],
- };
- } catch (err) {
- logger.warn('[getConvosByCursor] Invalid cursor format, starting from beginning');
- }
- if (cursorFilter) {
- filters.push(cursorFilter);
- }
- }
-
- const query = filters.length === 1 ? filters[0] : { $and: filters };
-
- try {
- const sortOrder = finalSortDirection === 'asc' ? 1 : -1;
- const sortObj = { [finalSortBy]: sortOrder };
-
- if (finalSortBy !== 'updatedAt') {
- sortObj.updatedAt = sortOrder;
- }
-
- const convos = await Conversation.find(query)
- .select(
- 'conversationId endpoint title createdAt updatedAt user model agent_id assistant_id spec iconURL',
- )
- .sort(sortObj)
- .limit(limit + 1)
- .lean();
-
- let nextCursor = null;
- if (convos.length > limit) {
- convos.pop(); // Remove extra item used to detect next page
- // Create cursor from the last RETURNED item (not the popped one)
- const lastReturned = convos[convos.length - 1];
- const primaryValue = lastReturned[finalSortBy];
- const primaryStr = finalSortBy === 'title' ? primaryValue : primaryValue.toISOString();
- const secondaryStr = lastReturned.updatedAt.toISOString();
- const composite = { primary: primaryStr, secondary: secondaryStr };
- nextCursor = Buffer.from(JSON.stringify(composite)).toString('base64');
- }
-
- return { conversations: convos, nextCursor };
- } catch (error) {
- logger.error('[getConvosByCursor] Error getting conversations', error);
- throw new Error('Error getting conversations');
- }
- },
- getConvosQueried: async (user, convoIds, cursor = null, limit = 25) => {
- try {
- if (!convoIds?.length) {
- return { conversations: [], nextCursor: null, convoMap: {} };
- }
-
- const conversationIds = convoIds.map((convo) => convo.conversationId);
-
- const results = await Conversation.find({
- user,
- conversationId: { $in: conversationIds },
- $or: [{ expiredAt: { $exists: false } }, { expiredAt: null }],
- }).lean();
-
- results.sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt));
-
- let filtered = results;
- if (cursor && cursor !== 'start') {
- const cursorDate = new Date(cursor);
- filtered = results.filter((convo) => new Date(convo.updatedAt) < cursorDate);
- }
-
- const limited = filtered.slice(0, limit + 1);
- let nextCursor = null;
- if (limited.length > limit) {
- limited.pop(); // Remove extra item used to detect next page
- // Create cursor from the last RETURNED item (not the popped one)
- nextCursor = limited[limited.length - 1].updatedAt.toISOString();
- }
-
- const convoMap = {};
- limited.forEach((convo) => {
- convoMap[convo.conversationId] = convo;
- });
-
- return { conversations: limited, nextCursor, convoMap };
- } catch (error) {
- logger.error('[getConvosQueried] Error getting conversations', error);
- throw new Error('Error fetching conversations');
- }
- },
- getConvo,
- /* chore: this method is not properly error handled */
- getConvoTitle: async (user, conversationId) => {
- try {
- const convo = await getConvo(user, conversationId);
- /* ChatGPT Browser was triggering error here due to convo being saved later */
- if (convo && !convo.title) {
- return null;
- } else {
- // TypeError: Cannot read properties of null (reading 'title')
- return convo?.title || 'New Chat';
- }
- } catch (error) {
- logger.error('[getConvoTitle] Error getting conversation title', error);
- throw new Error('Error getting conversation title');
- }
- },
- /**
- * Asynchronously deletes conversations and associated messages for a given user and filter.
- *
- * @async
- * @function
- * @param {string|ObjectId} user - The user's ID.
- * @param {Object} filter - Additional filter criteria for the conversations to be deleted.
- * @returns {Promise<{ n: number, ok: number, deletedCount: number, messages: { n: number, ok: number, deletedCount: number } }>}
- * An object containing the count of deleted conversations and associated messages.
- * @throws {Error} Throws an error if there's an issue with the database operations.
- *
- * @example
- * const user = 'someUserId';
- * const filter = { someField: 'someValue' };
- * const result = await deleteConvos(user, filter);
- * logger.error(result); // { n: 5, ok: 1, deletedCount: 5, messages: { n: 10, ok: 1, deletedCount: 10 } }
- */
- deleteConvos: async (user, filter) => {
- try {
- const userFilter = { ...filter, user };
- const conversations = await Conversation.find(userFilter).select('conversationId');
- const conversationIds = conversations.map((c) => c.conversationId);
-
- if (!conversationIds.length) {
- throw new Error('Conversation not found or already deleted.');
- }
-
- const deleteConvoResult = await Conversation.deleteMany(userFilter);
-
- const deleteMessagesResult = await deleteMessages({
- conversationId: { $in: conversationIds },
- });
-
- return { ...deleteConvoResult, messages: deleteMessagesResult };
- } catch (error) {
- logger.error('[deleteConvos] Error deleting conversations and messages', error);
- throw error;
- }
- },
-};
diff --git a/api/models/ConversationTag.js b/api/models/ConversationTag.js
deleted file mode 100644
index 47a6c2bbf5..0000000000
--- a/api/models/ConversationTag.js
+++ /dev/null
@@ -1,284 +0,0 @@
-const { logger } = require('@librechat/data-schemas');
-const { ConversationTag, Conversation } = require('~/db/models');
-
-/**
- * Retrieves all conversation tags for a user.
- * @param {string} user - The user ID.
- * @returns {Promise} An array of conversation tags.
- */
-const getConversationTags = async (user) => {
- try {
- return await ConversationTag.find({ user }).sort({ position: 1 }).lean();
- } catch (error) {
- logger.error('[getConversationTags] Error getting conversation tags', error);
- throw new Error('Error getting conversation tags');
- }
-};
-
-/**
- * Creates a new conversation tag.
- * @param {string} user - The user ID.
- * @param {Object} data - The tag data.
- * @param {string} data.tag - The tag name.
- * @param {string} [data.description] - The tag description.
- * @param {boolean} [data.addToConversation] - Whether to add the tag to a conversation.
- * @param {string} [data.conversationId] - The conversation ID to add the tag to.
- * @returns {Promise} The created tag.
- */
-const createConversationTag = async (user, data) => {
- try {
- const { tag, description, addToConversation, conversationId } = data;
-
- const existingTag = await ConversationTag.findOne({ user, tag }).lean();
- if (existingTag) {
- return existingTag;
- }
-
- const maxPosition = await ConversationTag.findOne({ user }).sort('-position').lean();
- const position = (maxPosition?.position || 0) + 1;
-
- const newTag = await ConversationTag.findOneAndUpdate(
- { tag, user },
- {
- tag,
- user,
- count: addToConversation ? 1 : 0,
- position,
- description,
- $setOnInsert: { createdAt: new Date() },
- },
- {
- new: true,
- upsert: true,
- lean: true,
- },
- );
-
- if (addToConversation && conversationId) {
- await Conversation.findOneAndUpdate(
- { user, conversationId },
- { $addToSet: { tags: tag } },
- { new: true },
- );
- }
-
- return newTag;
- } catch (error) {
- logger.error('[createConversationTag] Error creating conversation tag', error);
- throw new Error('Error creating conversation tag');
- }
-};
-
-/**
- * Updates an existing conversation tag.
- * @param {string} user - The user ID.
- * @param {string} oldTag - The current tag name.
- * @param {Object} data - The updated tag data.
- * @param {string} [data.tag] - The new tag name.
- * @param {string} [data.description] - The updated description.
- * @param {number} [data.position] - The new position.
- * @returns {Promise} The updated tag.
- */
-const updateConversationTag = async (user, oldTag, data) => {
- try {
- const { tag: newTag, description, position } = data;
-
- const existingTag = await ConversationTag.findOne({ user, tag: oldTag }).lean();
- if (!existingTag) {
- return null;
- }
-
- if (newTag && newTag !== oldTag) {
- const tagAlreadyExists = await ConversationTag.findOne({ user, tag: newTag }).lean();
- if (tagAlreadyExists) {
- throw new Error('Tag already exists');
- }
-
- await Conversation.updateMany({ user, tags: oldTag }, { $set: { 'tags.$': newTag } });
- }
-
- const updateData = {};
- if (newTag) {
- updateData.tag = newTag;
- }
- if (description !== undefined) {
- updateData.description = description;
- }
- if (position !== undefined) {
- await adjustPositions(user, existingTag.position, position);
- updateData.position = position;
- }
-
- return await ConversationTag.findOneAndUpdate({ user, tag: oldTag }, updateData, {
- new: true,
- lean: true,
- });
- } catch (error) {
- logger.error('[updateConversationTag] Error updating conversation tag', error);
- throw new Error('Error updating conversation tag');
- }
-};
-
-/**
- * Adjusts positions of tags when a tag's position is changed.
- * @param {string} user - The user ID.
- * @param {number} oldPosition - The old position of the tag.
- * @param {number} newPosition - The new position of the tag.
- * @returns {Promise}
- */
-const adjustPositions = async (user, oldPosition, newPosition) => {
- if (oldPosition === newPosition) {
- return;
- }
-
- const update = oldPosition < newPosition ? { $inc: { position: -1 } } : { $inc: { position: 1 } };
- const position =
- oldPosition < newPosition
- ? {
- $gt: Math.min(oldPosition, newPosition),
- $lte: Math.max(oldPosition, newPosition),
- }
- : {
- $gte: Math.min(oldPosition, newPosition),
- $lt: Math.max(oldPosition, newPosition),
- };
-
- await ConversationTag.updateMany(
- {
- user,
- position,
- },
- update,
- );
-};
-
-/**
- * Deletes a conversation tag.
- * @param {string} user - The user ID.
- * @param {string} tag - The tag to delete.
- * @returns {Promise} The deleted tag.
- */
-const deleteConversationTag = async (user, tag) => {
- try {
- const deletedTag = await ConversationTag.findOneAndDelete({ user, tag }).lean();
- if (!deletedTag) {
- return null;
- }
-
- await Conversation.updateMany({ user, tags: tag }, { $pull: { tags: tag } });
-
- await ConversationTag.updateMany(
- { user, position: { $gt: deletedTag.position } },
- { $inc: { position: -1 } },
- );
-
- return deletedTag;
- } catch (error) {
- logger.error('[deleteConversationTag] Error deleting conversation tag', error);
- throw new Error('Error deleting conversation tag');
- }
-};
-
-/**
- * Updates tags for a specific conversation.
- * @param {string} user - The user ID.
- * @param {string} conversationId - The conversation ID.
- * @param {string[]} tags - The new set of tags for the conversation.
- * @returns {Promise} The updated list of tags for the conversation.
- */
-const updateTagsForConversation = async (user, conversationId, tags) => {
- try {
- const conversation = await Conversation.findOne({ user, conversationId }).lean();
- if (!conversation) {
- throw new Error('Conversation not found');
- }
-
- const oldTags = new Set(conversation.tags);
- const newTags = new Set(tags);
-
- const addedTags = [...newTags].filter((tag) => !oldTags.has(tag));
- const removedTags = [...oldTags].filter((tag) => !newTags.has(tag));
-
- const bulkOps = [];
-
- for (const tag of addedTags) {
- bulkOps.push({
- updateOne: {
- filter: { user, tag },
- update: { $inc: { count: 1 } },
- upsert: true,
- },
- });
- }
-
- for (const tag of removedTags) {
- bulkOps.push({
- updateOne: {
- filter: { user, tag },
- update: { $inc: { count: -1 } },
- },
- });
- }
-
- if (bulkOps.length > 0) {
- await ConversationTag.bulkWrite(bulkOps);
- }
-
- const updatedConversation = (
- await Conversation.findOneAndUpdate(
- { user, conversationId },
- { $set: { tags: [...newTags] } },
- { new: true },
- )
- ).toObject();
-
- return updatedConversation.tags;
- } catch (error) {
- logger.error('[updateTagsForConversation] Error updating tags', error);
- throw new Error('Error updating tags for conversation');
- }
-};
-
-/**
- * Increments tag counts for existing tags only.
- * @param {string} user - The user ID.
- * @param {string[]} tags - Array of tag names to increment
- * @returns {Promise}
- */
-const bulkIncrementTagCounts = async (user, tags) => {
- if (!tags || tags.length === 0) {
- return;
- }
-
- try {
- const uniqueTags = [...new Set(tags.filter(Boolean))];
- if (uniqueTags.length === 0) {
- return;
- }
-
- const bulkOps = uniqueTags.map((tag) => ({
- updateOne: {
- filter: { user, tag },
- update: { $inc: { count: 1 } },
- },
- }));
-
- const result = await ConversationTag.bulkWrite(bulkOps);
- if (result && result.modifiedCount > 0) {
- logger.debug(
- `user: ${user} | Incremented tag counts - modified ${result.modifiedCount} tags`,
- );
- }
- } catch (error) {
- logger.error('[bulkIncrementTagCounts] Error incrementing tag counts', error);
- }
-};
-
-module.exports = {
- getConversationTags,
- createConversationTag,
- updateConversationTag,
- deleteConversationTag,
- bulkIncrementTagCounts,
- updateTagsForConversation,
-};
diff --git a/api/models/File.js b/api/models/File.js
deleted file mode 100644
index 1a01ef12f9..0000000000
--- a/api/models/File.js
+++ /dev/null
@@ -1,250 +0,0 @@
-const { logger } = require('@librechat/data-schemas');
-const { EToolResources, FileContext } = require('librechat-data-provider');
-const { File } = require('~/db/models');
-
-/**
- * Finds a file by its file_id with additional query options.
- * @param {string} file_id - The unique identifier of the file.
- * @param {object} options - Query options for filtering, projection, etc.
- * @returns {Promise} A promise that resolves to the file document or null.
- */
-const findFileById = async (file_id, options = {}) => {
- return await File.findOne({ file_id, ...options }).lean();
-};
-
-/**
- * Retrieves files matching a given filter, sorted by the most recently updated.
- * @param {Object} filter - The filter criteria to apply.
- * @param {Object} [_sortOptions] - Optional sort parameters.
- * @param {Object|String} [selectFields={ text: 0 }] - Fields to include/exclude in the query results.
- * Default excludes the 'text' field.
- * @returns {Promise>} A promise that resolves to an array of file documents.
- */
-const getFiles = async (filter, _sortOptions, selectFields = { text: 0 }) => {
- const sortOptions = { updatedAt: -1, ..._sortOptions };
- return await File.find(filter).select(selectFields).sort(sortOptions).lean();
-};
-
-/**
- * Retrieves tool files (files that are embedded or have a fileIdentifier) from an array of file IDs.
- * Note: execute_code files are handled separately by getCodeGeneratedFiles.
- * @param {string[]} fileIds - Array of file_id strings to search for
- * @param {Set} toolResourceSet - Optional filter for tool resources
- * @returns {Promise>} Files that match the criteria
- */
-const getToolFilesByIds = async (fileIds, toolResourceSet) => {
- if (!fileIds || !fileIds.length || !toolResourceSet?.size) {
- return [];
- }
-
- try {
- const orConditions = [];
-
- if (toolResourceSet.has(EToolResources.context)) {
- orConditions.push({ text: { $exists: true, $ne: null }, context: FileContext.agents });
- }
- if (toolResourceSet.has(EToolResources.file_search)) {
- orConditions.push({ embedded: true });
- }
-
- if (orConditions.length === 0) {
- return [];
- }
-
- const filter = {
- file_id: { $in: fileIds },
- context: { $ne: FileContext.execute_code }, // Exclude code-generated files
- $or: orConditions,
- };
-
- const selectFields = { text: 0 };
- const sortOptions = { updatedAt: -1 };
-
- return await getFiles(filter, sortOptions, selectFields);
- } catch (error) {
- logger.error('[getToolFilesByIds] Error retrieving tool files:', error);
- throw new Error('Error retrieving tool files');
- }
-};
-
-/**
- * Retrieves files generated by code execution for a given conversation.
- * These files are stored locally with fileIdentifier metadata for code env re-upload.
- * @param {string} conversationId - The conversation ID to search for
- * @param {string[]} [messageIds] - Optional array of messageIds to filter by (for linear thread filtering)
- * @returns {Promise>} Files generated by code execution in the conversation
- */
-const getCodeGeneratedFiles = async (conversationId, messageIds) => {
- if (!conversationId) {
- return [];
- }
-
- /** messageIds are required for proper thread filtering of code-generated files */
- if (!messageIds || messageIds.length === 0) {
- return [];
- }
-
- try {
- const filter = {
- conversationId,
- context: FileContext.execute_code,
- messageId: { $exists: true, $in: messageIds },
- 'metadata.fileIdentifier': { $exists: true },
- };
-
- const selectFields = { text: 0 };
- const sortOptions = { createdAt: 1 };
-
- return await getFiles(filter, sortOptions, selectFields);
- } catch (error) {
- logger.error('[getCodeGeneratedFiles] Error retrieving code generated files:', error);
- return [];
- }
-};
-
-/**
- * Retrieves user-uploaded execute_code files (not code-generated) by their file IDs.
- * These are files with fileIdentifier metadata but context is NOT execute_code (e.g., agents or message_attachment).
- * File IDs should be collected from message.files arrays in the current thread.
- * @param {string[]} fileIds - Array of file IDs to fetch (from message.files in the thread)
- * @returns {Promise>} User-uploaded execute_code files
- */
-const getUserCodeFiles = async (fileIds) => {
- if (!fileIds || fileIds.length === 0) {
- return [];
- }
-
- try {
- const filter = {
- file_id: { $in: fileIds },
- context: { $ne: FileContext.execute_code },
- 'metadata.fileIdentifier': { $exists: true },
- };
-
- const selectFields = { text: 0 };
- const sortOptions = { createdAt: 1 };
-
- return await getFiles(filter, sortOptions, selectFields);
- } catch (error) {
- logger.error('[getUserCodeFiles] Error retrieving user code files:', error);
- return [];
- }
-};
-
-/**
- * Creates a new file with a TTL of 1 hour.
- * @param {MongoFile} data - The file data to be created, must contain file_id.
- * @param {boolean} disableTTL - Whether to disable the TTL.
- * @returns {Promise} A promise that resolves to the created file document.
- */
-const createFile = async (data, disableTTL) => {
- const fileData = {
- ...data,
- expiresAt: new Date(Date.now() + 3600 * 1000),
- };
-
- if (disableTTL) {
- delete fileData.expiresAt;
- }
-
- return await File.findOneAndUpdate({ file_id: data.file_id }, fileData, {
- new: true,
- upsert: true,
- }).lean();
-};
-
-/**
- * Updates a file identified by file_id with new data and removes the TTL.
- * @param {MongoFile} data - The data to update, must contain file_id.
- * @returns {Promise} A promise that resolves to the updated file document.
- */
-const updateFile = async (data) => {
- const { file_id, ...update } = data;
- const updateOperation = {
- $set: update,
- $unset: { expiresAt: '' }, // Remove the expiresAt field to prevent TTL
- };
- return await File.findOneAndUpdate({ file_id }, updateOperation, { new: true }).lean();
-};
-
-/**
- * Increments the usage of a file identified by file_id.
- * @param {MongoFile} data - The data to update, must contain file_id and the increment value for usage.
- * @returns {Promise} A promise that resolves to the updated file document.
- */
-const updateFileUsage = async (data) => {
- const { file_id, inc = 1 } = data;
- const updateOperation = {
- $inc: { usage: inc },
- $unset: { expiresAt: '', temp_file_id: '' },
- };
- return await File.findOneAndUpdate({ file_id }, updateOperation, { new: true }).lean();
-};
-
-/**
- * Deletes a file identified by file_id.
- * @param {string} file_id - The unique identifier of the file to delete.
- * @returns {Promise} A promise that resolves to the deleted file document or null.
- */
-const deleteFile = async (file_id) => {
- return await File.findOneAndDelete({ file_id }).lean();
-};
-
-/**
- * Deletes a file identified by a filter.
- * @param {object} filter - The filter criteria to apply.
- * @returns {Promise} A promise that resolves to the deleted file document or null.
- */
-const deleteFileByFilter = async (filter) => {
- return await File.findOneAndDelete(filter).lean();
-};
-
-/**
- * Deletes multiple files identified by an array of file_ids.
- * @param {Array} file_ids - The unique identifiers of the files to delete.
- * @returns {Promise} A promise that resolves to the result of the deletion operation.
- */
-const deleteFiles = async (file_ids, user) => {
- let deleteQuery = { file_id: { $in: file_ids } };
- if (user) {
- deleteQuery = { user: user };
- }
- return await File.deleteMany(deleteQuery);
-};
-
-/**
- * Batch updates files with new signed URLs in MongoDB
- *
- * @param {MongoFile[]} updates - Array of updates in the format { file_id, filepath }
- * @returns {Promise}
- */
-async function batchUpdateFiles(updates) {
- if (!updates || updates.length === 0) {
- return;
- }
-
- const bulkOperations = updates.map((update) => ({
- updateOne: {
- filter: { file_id: update.file_id },
- update: { $set: { filepath: update.filepath } },
- },
- }));
-
- const result = await File.bulkWrite(bulkOperations);
- logger.info(`Updated ${result.modifiedCount} files with new S3 URLs`);
-}
-
-module.exports = {
- findFileById,
- getFiles,
- getToolFilesByIds,
- getCodeGeneratedFiles,
- getUserCodeFiles,
- createFile,
- updateFile,
- updateFileUsage,
- deleteFile,
- deleteFiles,
- deleteFileByFilter,
- batchUpdateFiles,
-};
diff --git a/api/models/File.spec.js b/api/models/File.spec.js
deleted file mode 100644
index 2d4282cff7..0000000000
--- a/api/models/File.spec.js
+++ /dev/null
@@ -1,629 +0,0 @@
-const mongoose = require('mongoose');
-const { v4: uuidv4 } = require('uuid');
-const { MongoMemoryServer } = require('mongodb-memory-server');
-const { createModels, createMethods } = require('@librechat/data-schemas');
-const {
- SystemRoles,
- ResourceType,
- AccessRoleIds,
- PrincipalType,
-} = require('librechat-data-provider');
-const { grantPermission } = require('~/server/services/PermissionService');
-const { createAgent } = require('./Agent');
-
-let File;
-let Agent;
-let AclEntry;
-let User;
-let modelsToCleanup = [];
-let methods;
-let getFiles;
-let createFile;
-let seedDefaultRoles;
-
-describe('File Access Control', () => {
- let mongoServer;
-
- beforeAll(async () => {
- mongoServer = await MongoMemoryServer.create();
- const mongoUri = mongoServer.getUri();
- await mongoose.connect(mongoUri);
-
- // Initialize all models
- const models = createModels(mongoose);
-
- // Track which models we're adding
- modelsToCleanup = Object.keys(models);
-
- // Register models on mongoose.models so methods can access them
- const dbModels = require('~/db/models');
- Object.assign(mongoose.models, dbModels);
-
- File = dbModels.File;
- Agent = dbModels.Agent;
- AclEntry = dbModels.AclEntry;
- User = dbModels.User;
-
- // Create methods from data-schemas (includes file methods)
- methods = createMethods(mongoose);
- getFiles = methods.getFiles;
- createFile = methods.createFile;
- seedDefaultRoles = methods.seedDefaultRoles;
-
- // Seed default roles
- await seedDefaultRoles();
- });
-
- afterAll(async () => {
- // Clean up all collections before disconnecting
- const collections = mongoose.connection.collections;
- for (const key in collections) {
- await collections[key].deleteMany({});
- }
-
- // Clear only the models we added
- for (const modelName of modelsToCleanup) {
- if (mongoose.models[modelName]) {
- delete mongoose.models[modelName];
- }
- }
-
- await mongoose.disconnect();
- await mongoServer.stop();
- });
-
- beforeEach(async () => {
- await File.deleteMany({});
- await Agent.deleteMany({});
- await AclEntry.deleteMany({});
- await User.deleteMany({});
- // Don't delete AccessRole as they are seeded defaults needed for tests
- });
-
- describe('hasAccessToFilesViaAgent', () => {
- it('should efficiently check access for multiple files at once', async () => {
- const userId = new mongoose.Types.ObjectId();
- const authorId = new mongoose.Types.ObjectId();
- const agentId = uuidv4();
- const fileIds = [uuidv4(), uuidv4(), uuidv4(), uuidv4()];
-
- // Create users
- await User.create({
- _id: userId,
- email: 'user@example.com',
- emailVerified: true,
- provider: 'local',
- });
-
- await User.create({
- _id: authorId,
- email: 'author@example.com',
- emailVerified: true,
- provider: 'local',
- });
-
- // Create files
- for (const fileId of fileIds) {
- await createFile({
- user: authorId,
- file_id: fileId,
- filename: `file-${fileId}.txt`,
- filepath: `/uploads/${fileId}`,
- });
- }
-
- // Create agent with only first two files attached
- const agent = await createAgent({
- id: agentId,
- name: 'Test Agent',
- author: authorId,
- model: 'gpt-4',
- provider: 'openai',
- tool_resources: {
- file_search: {
- file_ids: [fileIds[0], fileIds[1]],
- },
- },
- });
-
- // Grant EDIT permission to user on the agent
- await grantPermission({
- principalType: PrincipalType.USER,
- principalId: userId,
- resourceType: ResourceType.AGENT,
- resourceId: agent._id,
- accessRoleId: AccessRoleIds.AGENT_EDITOR,
- grantedBy: authorId,
- });
-
- // Check access for all files
- const { hasAccessToFilesViaAgent } = require('~/server/services/Files/permissions');
- const accessMap = await hasAccessToFilesViaAgent({
- userId: userId,
- role: SystemRoles.USER,
- fileIds,
- agentId: agent.id, // Use agent.id which is the custom UUID
- });
-
- // Should have access only to the first two files
- expect(accessMap.get(fileIds[0])).toBe(true);
- expect(accessMap.get(fileIds[1])).toBe(true);
- expect(accessMap.get(fileIds[2])).toBe(false);
- expect(accessMap.get(fileIds[3])).toBe(false);
- });
-
- it('should grant access to all files when user is the agent author', async () => {
- const authorId = new mongoose.Types.ObjectId();
- const agentId = uuidv4();
- const fileIds = [uuidv4(), uuidv4(), uuidv4()];
-
- // Create author user
- await User.create({
- _id: authorId,
- email: 'author@example.com',
- emailVerified: true,
- provider: 'local',
- });
-
- // Create agent
- await createAgent({
- id: agentId,
- name: 'Test Agent',
- author: authorId,
- model: 'gpt-4',
- provider: 'openai',
- tool_resources: {
- file_search: {
- file_ids: [fileIds[0]], // Only one file attached
- },
- },
- });
-
- // Check access as the author
- const { hasAccessToFilesViaAgent } = require('~/server/services/Files/permissions');
- const accessMap = await hasAccessToFilesViaAgent({
- userId: authorId,
- role: SystemRoles.USER,
- fileIds,
- agentId,
- });
-
- // Author should have access to all files
- expect(accessMap.get(fileIds[0])).toBe(true);
- expect(accessMap.get(fileIds[1])).toBe(true);
- expect(accessMap.get(fileIds[2])).toBe(true);
- });
-
- it('should handle non-existent agent gracefully', async () => {
- const userId = new mongoose.Types.ObjectId();
- const fileIds = [uuidv4(), uuidv4()];
-
- // Create user
- await User.create({
- _id: userId,
- email: 'user@example.com',
- emailVerified: true,
- provider: 'local',
- });
-
- const { hasAccessToFilesViaAgent } = require('~/server/services/Files/permissions');
- const accessMap = await hasAccessToFilesViaAgent({
- userId: userId,
- role: SystemRoles.USER,
- fileIds,
- agentId: 'non-existent-agent',
- });
-
- // Should have no access to any files
- expect(accessMap.get(fileIds[0])).toBe(false);
- expect(accessMap.get(fileIds[1])).toBe(false);
- });
-
- it('should deny access when user only has VIEW permission and needs access for deletion', async () => {
- const userId = new mongoose.Types.ObjectId();
- const authorId = new mongoose.Types.ObjectId();
- const agentId = uuidv4();
- const fileIds = [uuidv4(), uuidv4()];
-
- // Create users
- await User.create({
- _id: userId,
- email: 'user@example.com',
- emailVerified: true,
- provider: 'local',
- });
-
- await User.create({
- _id: authorId,
- email: 'author@example.com',
- emailVerified: true,
- provider: 'local',
- });
-
- // Create agent with files
- const agent = await createAgent({
- id: agentId,
- name: 'View-Only Agent',
- author: authorId,
- model: 'gpt-4',
- provider: 'openai',
- tool_resources: {
- file_search: {
- file_ids: fileIds,
- },
- },
- });
-
- // Grant only VIEW permission to user on the agent
- await grantPermission({
- principalType: PrincipalType.USER,
- principalId: userId,
- resourceType: ResourceType.AGENT,
- resourceId: agent._id,
- accessRoleId: AccessRoleIds.AGENT_VIEWER,
- grantedBy: authorId,
- });
-
- // Check access for files
- const { hasAccessToFilesViaAgent } = require('~/server/services/Files/permissions');
- const accessMap = await hasAccessToFilesViaAgent({
- userId: userId,
- role: SystemRoles.USER,
- fileIds,
- agentId,
- isDelete: true,
- });
-
- // Should have no access to any files when only VIEW permission
- expect(accessMap.get(fileIds[0])).toBe(false);
- expect(accessMap.get(fileIds[1])).toBe(false);
- });
-
- it('should grant access when user has VIEW permission', async () => {
- const userId = new mongoose.Types.ObjectId();
- const authorId = new mongoose.Types.ObjectId();
- const agentId = uuidv4();
- const fileIds = [uuidv4(), uuidv4()];
-
- // Create users
- await User.create({
- _id: userId,
- email: 'user@example.com',
- emailVerified: true,
- provider: 'local',
- });
-
- await User.create({
- _id: authorId,
- email: 'author@example.com',
- emailVerified: true,
- provider: 'local',
- });
-
- // Create agent with files
- const agent = await createAgent({
- id: agentId,
- name: 'View-Only Agent',
- author: authorId,
- model: 'gpt-4',
- provider: 'openai',
- tool_resources: {
- file_search: {
- file_ids: fileIds,
- },
- },
- });
-
- // Grant only VIEW permission to user on the agent
- await grantPermission({
- principalType: PrincipalType.USER,
- principalId: userId,
- resourceType: ResourceType.AGENT,
- resourceId: agent._id,
- accessRoleId: AccessRoleIds.AGENT_VIEWER,
- grantedBy: authorId,
- });
-
- // Check access for files
- const { hasAccessToFilesViaAgent } = require('~/server/services/Files/permissions');
- const accessMap = await hasAccessToFilesViaAgent({
- userId: userId,
- role: SystemRoles.USER,
- fileIds,
- agentId,
- });
-
- expect(accessMap.get(fileIds[0])).toBe(true);
- expect(accessMap.get(fileIds[1])).toBe(true);
- });
- });
-
- describe('getFiles with agent access control', () => {
- test('should return files owned by user and files accessible through agent', async () => {
- const authorId = new mongoose.Types.ObjectId();
- const userId = new mongoose.Types.ObjectId();
- const agentId = `agent_${uuidv4()}`;
- const ownedFileId = `file_${uuidv4()}`;
- const sharedFileId = `file_${uuidv4()}`;
- const inaccessibleFileId = `file_${uuidv4()}`;
-
- // Create users
- await User.create({
- _id: userId,
- email: 'user@example.com',
- emailVerified: true,
- provider: 'local',
- });
-
- await User.create({
- _id: authorId,
- email: 'author@example.com',
- emailVerified: true,
- provider: 'local',
- });
-
- // Create agent with shared file
- const agent = await createAgent({
- id: agentId,
- name: 'Shared Agent',
- provider: 'test',
- model: 'test-model',
- author: authorId,
- tool_resources: {
- file_search: {
- file_ids: [sharedFileId],
- },
- },
- });
-
- // Grant EDIT permission to user on the agent
- await grantPermission({
- principalType: PrincipalType.USER,
- principalId: userId,
- resourceType: ResourceType.AGENT,
- resourceId: agent._id,
- accessRoleId: AccessRoleIds.AGENT_EDITOR,
- grantedBy: authorId,
- });
-
- // Create files
- await createFile({
- file_id: ownedFileId,
- user: userId,
- filename: 'owned.txt',
- filepath: '/uploads/owned.txt',
- type: 'text/plain',
- bytes: 100,
- });
-
- await createFile({
- file_id: sharedFileId,
- user: authorId,
- filename: 'shared.txt',
- filepath: '/uploads/shared.txt',
- type: 'text/plain',
- bytes: 200,
- embedded: true,
- });
-
- await createFile({
- file_id: inaccessibleFileId,
- user: authorId,
- filename: 'inaccessible.txt',
- filepath: '/uploads/inaccessible.txt',
- type: 'text/plain',
- bytes: 300,
- });
-
- // Get all files first
- const allFiles = await getFiles(
- { file_id: { $in: [ownedFileId, sharedFileId, inaccessibleFileId] } },
- null,
- { text: 0 },
- );
-
- // Then filter by access control
- const { filterFilesByAgentAccess } = require('~/server/services/Files/permissions');
- const files = await filterFilesByAgentAccess({
- files: allFiles,
- userId: userId,
- role: SystemRoles.USER,
- agentId,
- });
-
- expect(files).toHaveLength(2);
- expect(files.map((f) => f.file_id)).toContain(ownedFileId);
- expect(files.map((f) => f.file_id)).toContain(sharedFileId);
- expect(files.map((f) => f.file_id)).not.toContain(inaccessibleFileId);
- });
-
- test('should return all files when no userId/agentId provided', async () => {
- const userId = new mongoose.Types.ObjectId();
- const fileId1 = `file_${uuidv4()}`;
- const fileId2 = `file_${uuidv4()}`;
-
- await createFile({
- file_id: fileId1,
- user: userId,
- filename: 'file1.txt',
- filepath: '/uploads/file1.txt',
- type: 'text/plain',
- bytes: 100,
- });
-
- await createFile({
- file_id: fileId2,
- user: new mongoose.Types.ObjectId(),
- filename: 'file2.txt',
- filepath: '/uploads/file2.txt',
- type: 'text/plain',
- bytes: 200,
- });
-
- const files = await getFiles({ file_id: { $in: [fileId1, fileId2] } });
- expect(files).toHaveLength(2);
- });
- });
-
- describe('Role-based file permissions', () => {
- it('should optimize permission checks when role is provided', async () => {
- const userId = new mongoose.Types.ObjectId();
- const authorId = new mongoose.Types.ObjectId();
- const agentId = uuidv4();
- const fileIds = [uuidv4(), uuidv4()];
-
- // Create users
- await User.create({
- _id: userId,
- email: 'user@example.com',
- emailVerified: true,
- provider: 'local',
- role: 'ADMIN', // User has ADMIN role
- });
-
- await User.create({
- _id: authorId,
- email: 'author@example.com',
- emailVerified: true,
- provider: 'local',
- });
-
- // Create files
- for (const fileId of fileIds) {
- await createFile({
- file_id: fileId,
- user: authorId,
- filename: `${fileId}.txt`,
- filepath: `/uploads/${fileId}.txt`,
- type: 'text/plain',
- bytes: 100,
- });
- }
-
- // Create agent with files
- const agent = await createAgent({
- id: agentId,
- name: 'Test Agent',
- author: authorId,
- model: 'gpt-4',
- provider: 'openai',
- tool_resources: {
- file_search: {
- file_ids: fileIds,
- },
- },
- });
-
- // Grant permission to ADMIN role
- await grantPermission({
- principalType: PrincipalType.ROLE,
- principalId: 'ADMIN',
- resourceType: ResourceType.AGENT,
- resourceId: agent._id,
- accessRoleId: AccessRoleIds.AGENT_EDITOR,
- grantedBy: authorId,
- });
-
- // Check access with role provided (should avoid DB query)
- const { hasAccessToFilesViaAgent } = require('~/server/services/Files/permissions');
- const accessMapWithRole = await hasAccessToFilesViaAgent({
- userId: userId,
- role: 'ADMIN',
- fileIds,
- agentId: agent.id,
- });
-
- // User should have access through their ADMIN role
- expect(accessMapWithRole.get(fileIds[0])).toBe(true);
- expect(accessMapWithRole.get(fileIds[1])).toBe(true);
-
- // Check access without role (will query DB to get user's role)
- const accessMapWithoutRole = await hasAccessToFilesViaAgent({
- userId: userId,
- fileIds,
- agentId: agent.id,
- });
-
- // Should have same result
- expect(accessMapWithoutRole.get(fileIds[0])).toBe(true);
- expect(accessMapWithoutRole.get(fileIds[1])).toBe(true);
- });
-
- it('should deny access when user role changes', async () => {
- const userId = new mongoose.Types.ObjectId();
- const authorId = new mongoose.Types.ObjectId();
- const agentId = uuidv4();
- const fileId = uuidv4();
-
- // Create users
- await User.create({
- _id: userId,
- email: 'user@example.com',
- emailVerified: true,
- provider: 'local',
- role: 'EDITOR',
- });
-
- await User.create({
- _id: authorId,
- email: 'author@example.com',
- emailVerified: true,
- provider: 'local',
- });
-
- // Create file
- await createFile({
- file_id: fileId,
- user: authorId,
- filename: 'test.txt',
- filepath: '/uploads/test.txt',
- type: 'text/plain',
- bytes: 100,
- });
-
- // Create agent
- const agent = await createAgent({
- id: agentId,
- name: 'Test Agent',
- author: authorId,
- model: 'gpt-4',
- provider: 'openai',
- tool_resources: {
- file_search: {
- file_ids: [fileId],
- },
- },
- });
-
- // Grant permission to EDITOR role only
- await grantPermission({
- principalType: PrincipalType.ROLE,
- principalId: 'EDITOR',
- resourceType: ResourceType.AGENT,
- resourceId: agent._id,
- accessRoleId: AccessRoleIds.AGENT_EDITOR,
- grantedBy: authorId,
- });
-
- const { hasAccessToFilesViaAgent } = require('~/server/services/Files/permissions');
-
- // Check with EDITOR role - should have access
- const accessAsEditor = await hasAccessToFilesViaAgent({
- userId: userId,
- role: 'EDITOR',
- fileIds: [fileId],
- agentId: agent.id,
- });
- expect(accessAsEditor.get(fileId)).toBe(true);
-
- // Simulate role change to USER - should lose access
- const accessAsUser = await hasAccessToFilesViaAgent({
- userId: userId,
- role: SystemRoles.USER,
- fileIds: [fileId],
- agentId: agent.id,
- });
- expect(accessAsUser.get(fileId)).toBe(false);
- });
- });
-});
diff --git a/api/models/Message.js b/api/models/Message.js
deleted file mode 100644
index 8fe04f6f54..0000000000
--- a/api/models/Message.js
+++ /dev/null
@@ -1,372 +0,0 @@
-const { z } = require('zod');
-const { logger } = require('@librechat/data-schemas');
-const { createTempChatExpirationDate } = require('@librechat/api');
-const { Message } = require('~/db/models');
-
-const idSchema = z.string().uuid();
-
-/**
- * Saves a message in the database.
- *
- * @async
- * @function saveMessage
- * @param {ServerRequest} req - The request object containing user information.
- * @param {Object} params - The message data object.
- * @param {string} params.endpoint - The endpoint where the message originated.
- * @param {string} params.iconURL - The URL of the sender's icon.
- * @param {string} params.messageId - The unique identifier for the message.
- * @param {string} params.newMessageId - The new unique identifier for the message (if applicable).
- * @param {string} params.conversationId - The identifier of the conversation.
- * @param {string} [params.parentMessageId] - The identifier of the parent message, if any.
- * @param {string} params.sender - The identifier of the sender.
- * @param {string} params.text - The text content of the message.
- * @param {boolean} params.isCreatedByUser - Indicates if the message was created by the user.
- * @param {string} [params.error] - Any error associated with the message.
- * @param {boolean} [params.unfinished] - Indicates if the message is unfinished.
- * @param {Object[]} [params.files] - An array of files associated with the message.
- * @param {string} [params.finish_reason] - Reason for finishing the message.
- * @param {number} [params.tokenCount] - The number of tokens in the message.
- * @param {string} [params.plugin] - Plugin associated with the message.
- * @param {string[]} [params.plugins] - An array of plugins associated with the message.
- * @param {string} [params.model] - The model used to generate the message.
- * @param {Object} [metadata] - Additional metadata for this operation
- * @param {string} [metadata.context] - The context of the operation
- * @returns {Promise} The updated or newly inserted message document.
- * @throws {Error} If there is an error in saving the message.
- */
-async function saveMessage(req, params, metadata) {
- if (!req?.user?.id) {
- throw new Error('User not authenticated');
- }
-
- const validConvoId = idSchema.safeParse(params.conversationId);
- if (!validConvoId.success) {
- logger.warn(`Invalid conversation ID: ${params.conversationId}`);
- logger.info(`---\`saveMessage\` context: ${metadata?.context}`);
- logger.info(`---Invalid conversation ID Params: ${JSON.stringify(params, null, 2)}`);
- return;
- }
-
- try {
- const update = {
- ...params,
- user: req.user.id,
- messageId: params.newMessageId || params.messageId,
- };
-
- if (req?.body?.isTemporary) {
- try {
- const appConfig = req.config;
- update.expiredAt = createTempChatExpirationDate(appConfig?.interfaceConfig);
- } catch (err) {
- logger.error('Error creating temporary chat expiration date:', err);
- logger.info(`---\`saveMessage\` context: ${metadata?.context}`);
- update.expiredAt = null;
- }
- } else {
- update.expiredAt = null;
- }
-
- if (update.tokenCount != null && isNaN(update.tokenCount)) {
- logger.warn(
- `Resetting invalid \`tokenCount\` for message \`${params.messageId}\`: ${update.tokenCount}`,
- );
- logger.info(`---\`saveMessage\` context: ${metadata?.context}`);
- update.tokenCount = 0;
- }
- const message = await Message.findOneAndUpdate(
- { messageId: params.messageId, user: req.user.id },
- update,
- { upsert: true, new: true },
- );
-
- return message.toObject();
- } catch (err) {
- logger.error('Error saving message:', err);
- logger.info(`---\`saveMessage\` context: ${metadata?.context}`);
-
- // Check if this is a duplicate key error (MongoDB error code 11000)
- if (err.code === 11000 && err.message.includes('duplicate key error')) {
- // Log the duplicate key error but don't crash the application
- logger.warn(`Duplicate messageId detected: ${params.messageId}. Continuing execution.`);
-
- try {
- // Try to find the existing message with this ID
- const existingMessage = await Message.findOne({
- messageId: params.messageId,
- user: req.user.id,
- });
-
- // If we found it, return it
- if (existingMessage) {
- return existingMessage.toObject();
- }
-
- // If we can't find it (unlikely but possible in race conditions)
- return {
- ...params,
- messageId: params.messageId,
- user: req.user.id,
- };
- } catch (findError) {
- // If the findOne also fails, log it but don't crash
- logger.warn(
- `Could not retrieve existing message with ID ${params.messageId}: ${findError.message}`,
- );
- return {
- ...params,
- messageId: params.messageId,
- user: req.user.id,
- };
- }
- }
-
- throw err; // Re-throw other errors
- }
-}
-
-/**
- * Saves multiple messages in the database in bulk.
- *
- * @async
- * @function bulkSaveMessages
- * @param {Object[]} messages - An array of message objects to save.
- * @param {boolean} [overrideTimestamp=false] - Indicates whether to override the timestamps of the messages. Defaults to false.
- * @returns {Promise} The result of the bulk write operation.
- * @throws {Error} If there is an error in saving messages in bulk.
- */
-async function bulkSaveMessages(messages, overrideTimestamp = false) {
- try {
- const bulkOps = messages.map((message) => ({
- updateOne: {
- filter: { messageId: message.messageId },
- update: message,
- timestamps: !overrideTimestamp,
- upsert: true,
- },
- }));
- const result = await Message.bulkWrite(bulkOps);
- return result;
- } catch (err) {
- logger.error('Error saving messages in bulk:', err);
- throw err;
- }
-}
-
-/**
- * Records a message in the database.
- *
- * @async
- * @function recordMessage
- * @param {Object} params - The message data object.
- * @param {string} params.user - The identifier of the user.
- * @param {string} params.endpoint - The endpoint where the message originated.
- * @param {string} params.messageId - The unique identifier for the message.
- * @param {string} params.conversationId - The identifier of the conversation.
- * @param {string} [params.parentMessageId] - The identifier of the parent message, if any.
- * @param {Partial} rest - Any additional properties from the TMessage typedef not explicitly listed.
- * @returns {Promise} The updated or newly inserted message document.
- * @throws {Error} If there is an error in saving the message.
- */
-async function recordMessage({
- user,
- endpoint,
- messageId,
- conversationId,
- parentMessageId,
- ...rest
-}) {
- try {
- // No parsing of convoId as may use threadId
- const message = {
- user,
- endpoint,
- messageId,
- conversationId,
- parentMessageId,
- ...rest,
- };
-
- return await Message.findOneAndUpdate({ user, messageId }, message, {
- upsert: true,
- new: true,
- });
- } catch (err) {
- logger.error('Error recording message:', err);
- throw err;
- }
-}
-
-/**
- * Updates the text of a message.
- *
- * @async
- * @function updateMessageText
- * @param {Object} params - The update data object.
- * @param {Object} req - The request object.
- * @param {string} params.messageId - The unique identifier for the message.
- * @param {string} params.text - The new text content of the message.
- * @returns {Promise}
- * @throws {Error} If there is an error in updating the message text.
- */
-async function updateMessageText(req, { messageId, text }) {
- try {
- await Message.updateOne({ messageId, user: req.user.id }, { text });
- } catch (err) {
- logger.error('Error updating message text:', err);
- throw err;
- }
-}
-
-/**
- * Updates a message.
- *
- * @async
- * @function updateMessage
- * @param {Object} req - The request object.
- * @param {Object} message - The message object containing update data.
- * @param {string} message.messageId - The unique identifier for the message.
- * @param {string} [message.text] - The new text content of the message.
- * @param {Object[]} [message.files] - The files associated with the message.
- * @param {boolean} [message.isCreatedByUser] - Indicates if the message was created by the user.
- * @param {string} [message.sender] - The identifier of the sender.
- * @param {number} [message.tokenCount] - The number of tokens in the message.
- * @param {Object} [metadata] - The operation metadata
- * @param {string} [metadata.context] - The operation metadata
- * @returns {Promise} The updated message document.
- * @throws {Error} If there is an error in updating the message or if the message is not found.
- */
-async function updateMessage(req, message, metadata) {
- try {
- const { messageId, ...update } = message;
- const updatedMessage = await Message.findOneAndUpdate(
- { messageId, user: req.user.id },
- update,
- {
- new: true,
- },
- );
-
- if (!updatedMessage) {
- throw new Error('Message not found or user not authorized.');
- }
-
- return {
- messageId: updatedMessage.messageId,
- conversationId: updatedMessage.conversationId,
- parentMessageId: updatedMessage.parentMessageId,
- sender: updatedMessage.sender,
- text: updatedMessage.text,
- isCreatedByUser: updatedMessage.isCreatedByUser,
- tokenCount: updatedMessage.tokenCount,
- feedback: updatedMessage.feedback,
- };
- } catch (err) {
- logger.error('Error updating message:', err);
- if (metadata && metadata?.context) {
- logger.info(`---\`updateMessage\` context: ${metadata.context}`);
- }
- throw err;
- }
-}
-
-/**
- * Deletes messages in a conversation since a specific message.
- *
- * @async
- * @function deleteMessagesSince
- * @param {Object} params - The parameters object.
- * @param {Object} req - The request object.
- * @param {string} params.messageId - The unique identifier for the message.
- * @param {string} params.conversationId - The identifier of the conversation.
- * @returns {Promise} The number of deleted messages.
- * @throws {Error} If there is an error in deleting messages.
- */
-async function deleteMessagesSince(req, { messageId, conversationId }) {
- try {
- const message = await Message.findOne({ messageId, user: req.user.id }).lean();
-
- if (message) {
- const query = Message.find({ conversationId, user: req.user.id });
- return await query.deleteMany({
- createdAt: { $gt: message.createdAt },
- });
- }
- return undefined;
- } catch (err) {
- logger.error('Error deleting messages:', err);
- throw err;
- }
-}
-
-/**
- * Retrieves messages from the database.
- * @async
- * @function getMessages
- * @param {Record} filter - The filter criteria.
- * @param {string | undefined} [select] - The fields to select.
- * @returns {Promise} The messages that match the filter criteria.
- * @throws {Error} If there is an error in retrieving messages.
- */
-async function getMessages(filter, select) {
- try {
- if (select) {
- return await Message.find(filter).select(select).sort({ createdAt: 1 }).lean();
- }
-
- return await Message.find(filter).sort({ createdAt: 1 }).lean();
- } catch (err) {
- logger.error('Error getting messages:', err);
- throw err;
- }
-}
-
-/**
- * Retrieves a single message from the database.
- * @async
- * @function getMessage
- * @param {{ user: string, messageId: string }} params - The search parameters
- * @returns {Promise} The message that matches the criteria or null if not found
- * @throws {Error} If there is an error in retrieving the message
- */
-async function getMessage({ user, messageId }) {
- try {
- return await Message.findOne({
- user,
- messageId,
- }).lean();
- } catch (err) {
- logger.error('Error getting message:', err);
- throw err;
- }
-}
-
-/**
- * Deletes messages from the database.
- *
- * @async
- * @function deleteMessages
- * @param {import('mongoose').FilterQuery} filter - The filter criteria to find messages to delete.
- * @returns {Promise} The metadata with count of deleted messages.
- * @throws {Error} If there is an error in deleting messages.
- */
-async function deleteMessages(filter) {
- try {
- return await Message.deleteMany(filter);
- } catch (err) {
- logger.error('Error deleting messages:', err);
- throw err;
- }
-}
-
-module.exports = {
- saveMessage,
- bulkSaveMessages,
- recordMessage,
- updateMessageText,
- updateMessage,
- deleteMessagesSince,
- getMessages,
- getMessage,
- deleteMessages,
-};
diff --git a/api/models/Preset.js b/api/models/Preset.js
deleted file mode 100644
index 4db3d59066..0000000000
--- a/api/models/Preset.js
+++ /dev/null
@@ -1,82 +0,0 @@
-const { logger } = require('@librechat/data-schemas');
-const { Preset } = require('~/db/models');
-
-const getPreset = async (user, presetId) => {
- try {
- return await Preset.findOne({ user, presetId }).lean();
- } catch (error) {
- logger.error('[getPreset] Error getting single preset', error);
- return { message: 'Error getting single preset' };
- }
-};
-
-module.exports = {
- getPreset,
- getPresets: async (user, filter) => {
- try {
- const presets = await Preset.find({ ...filter, user }).lean();
- const defaultValue = 10000;
-
- presets.sort((a, b) => {
- let orderA = a.order !== undefined ? a.order : defaultValue;
- let orderB = b.order !== undefined ? b.order : defaultValue;
-
- if (orderA !== orderB) {
- return orderA - orderB;
- }
-
- return b.updatedAt - a.updatedAt;
- });
-
- return presets;
- } catch (error) {
- logger.error('[getPresets] Error getting presets', error);
- return { message: 'Error retrieving presets' };
- }
- },
- savePreset: async (user, { presetId, newPresetId, defaultPreset, ...preset }) => {
- try {
- const setter = { $set: {} };
- const { user: _, ...cleanPreset } = preset;
- const update = { presetId, ...cleanPreset };
- if (preset.tools && Array.isArray(preset.tools)) {
- update.tools =
- preset.tools
- .map((tool) => tool?.pluginKey ?? tool)
- .filter((toolName) => typeof toolName === 'string') ?? [];
- }
- if (newPresetId) {
- update.presetId = newPresetId;
- }
-
- if (defaultPreset) {
- update.defaultPreset = defaultPreset;
- update.order = 0;
-
- const currentDefault = await Preset.findOne({ defaultPreset: true, user });
-
- if (currentDefault && currentDefault.presetId !== presetId) {
- await Preset.findByIdAndUpdate(currentDefault._id, {
- $unset: { defaultPreset: '', order: '' },
- });
- }
- } else if (defaultPreset === false) {
- update.defaultPreset = undefined;
- update.order = undefined;
- setter['$unset'] = { defaultPreset: '', order: '' };
- }
-
- setter.$set = update;
- return await Preset.findOneAndUpdate({ presetId, user }, setter, { new: true, upsert: true });
- } catch (error) {
- logger.error('[savePreset] Error saving preset', error);
- return { message: 'Error saving preset' };
- }
- },
- deletePresets: async (user, filter) => {
- // let toRemove = await Preset.find({ ...filter, user }).select('presetId');
- // const ids = toRemove.map((instance) => instance.presetId);
- let deleteCount = await Preset.deleteMany({ ...filter, user });
- return deleteCount;
- },
-};
diff --git a/api/models/Project.js b/api/models/Project.js
deleted file mode 100644
index 8fd1e556f9..0000000000
--- a/api/models/Project.js
+++ /dev/null
@@ -1,133 +0,0 @@
-const { GLOBAL_PROJECT_NAME } = require('librechat-data-provider').Constants;
-const { Project } = require('~/db/models');
-
-/**
- * Retrieve a project by ID and convert the found project document to a plain object.
- *
- * @param {string} projectId - The ID of the project to find and return as a plain object.
- * @param {string|string[]} [fieldsToSelect] - The fields to include or exclude in the returned document.
- * @returns {Promise} A plain object representing the project document, or `null` if no project is found.
- */
-const getProjectById = async function (projectId, fieldsToSelect = null) {
- const query = Project.findById(projectId);
-
- if (fieldsToSelect) {
- query.select(fieldsToSelect);
- }
-
- return await query.lean();
-};
-
-/**
- * Retrieve a project by name and convert the found project document to a plain object.
- * If the project with the given name doesn't exist and the name is "instance", create it and return the lean version.
- *
- * @param {string} projectName - The name of the project to find or create.
- * @param {string|string[]} [fieldsToSelect] - The fields to include or exclude in the returned document.
- * @returns {Promise} A plain object representing the project document.
- */
-const getProjectByName = async function (projectName, fieldsToSelect = null) {
- const query = { name: projectName };
- const update = { $setOnInsert: { name: projectName } };
- const options = {
- new: true,
- upsert: projectName === GLOBAL_PROJECT_NAME,
- lean: true,
- select: fieldsToSelect,
- };
-
- return await Project.findOneAndUpdate(query, update, options);
-};
-
-/**
- * Add an array of prompt group IDs to a project's promptGroupIds array, ensuring uniqueness.
- *
- * @param {string} projectId - The ID of the project to update.
- * @param {string[]} promptGroupIds - The array of prompt group IDs to add to the project.
- * @returns {Promise} The updated project document.
- */
-const addGroupIdsToProject = async function (projectId, promptGroupIds) {
- return await Project.findByIdAndUpdate(
- projectId,
- { $addToSet: { promptGroupIds: { $each: promptGroupIds } } },
- { new: true },
- );
-};
-
-/**
- * Remove an array of prompt group IDs from a project's promptGroupIds array.
- *
- * @param {string} projectId - The ID of the project to update.
- * @param {string[]} promptGroupIds - The array of prompt group IDs to remove from the project.
- * @returns {Promise} The updated project document.
- */
-const removeGroupIdsFromProject = async function (projectId, promptGroupIds) {
- return await Project.findByIdAndUpdate(
- projectId,
- { $pull: { promptGroupIds: { $in: promptGroupIds } } },
- { new: true },
- );
-};
-
-/**
- * Remove a prompt group ID from all projects.
- *
- * @param {string} promptGroupId - The ID of the prompt group to remove from projects.
- * @returns {Promise}
- */
-const removeGroupFromAllProjects = async (promptGroupId) => {
- await Project.updateMany({}, { $pull: { promptGroupIds: promptGroupId } });
-};
-
-/**
- * Add an array of agent IDs to a project's agentIds array, ensuring uniqueness.
- *
- * @param {string} projectId - The ID of the project to update.
- * @param {string[]} agentIds - The array of agent IDs to add to the project.
- * @returns {Promise} The updated project document.
- */
-const addAgentIdsToProject = async function (projectId, agentIds) {
- return await Project.findByIdAndUpdate(
- projectId,
- { $addToSet: { agentIds: { $each: agentIds } } },
- { new: true },
- );
-};
-
-/**
- * Remove an array of agent IDs from a project's agentIds array.
- *
- * @param {string} projectId - The ID of the project to update.
- * @param {string[]} agentIds - The array of agent IDs to remove from the project.
- * @returns {Promise} The updated project document.
- */
-const removeAgentIdsFromProject = async function (projectId, agentIds) {
- return await Project.findByIdAndUpdate(
- projectId,
- { $pull: { agentIds: { $in: agentIds } } },
- { new: true },
- );
-};
-
-/**
- * Remove an agent ID from all projects.
- *
- * @param {string} agentId - The ID of the agent to remove from projects.
- * @returns {Promise}
- */
-const removeAgentFromAllProjects = async (agentId) => {
- await Project.updateMany({}, { $pull: { agentIds: agentId } });
-};
-
-module.exports = {
- getProjectById,
- getProjectByName,
- /* prompts */
- addGroupIdsToProject,
- removeGroupIdsFromProject,
- removeGroupFromAllProjects,
- /* agents */
- addAgentIdsToProject,
- removeAgentIdsFromProject,
- removeAgentFromAllProjects,
-};
diff --git a/api/models/Prompt.js b/api/models/Prompt.js
deleted file mode 100644
index bde911b23a..0000000000
--- a/api/models/Prompt.js
+++ /dev/null
@@ -1,708 +0,0 @@
-const { ObjectId } = require('mongodb');
-const { escapeRegExp } = require('@librechat/api');
-const { logger } = require('@librechat/data-schemas');
-const {
- Constants,
- SystemRoles,
- ResourceType,
- SystemCategories,
-} = require('librechat-data-provider');
-const {
- removeGroupFromAllProjects,
- removeGroupIdsFromProject,
- addGroupIdsToProject,
- getProjectByName,
-} = require('./Project');
-const { removeAllPermissions } = require('~/server/services/PermissionService');
-const { PromptGroup, Prompt, AclEntry } = require('~/db/models');
-
-/**
- * Create a pipeline for the aggregation to get prompt groups
- * @param {Object} query
- * @param {number} skip
- * @param {number} limit
- * @returns {[Object]} - The pipeline for the aggregation
- */
-const createGroupPipeline = (query, skip, limit) => {
- return [
- { $match: query },
- { $sort: { createdAt: -1 } },
- { $skip: skip },
- { $limit: limit },
- {
- $lookup: {
- from: 'prompts',
- localField: 'productionId',
- foreignField: '_id',
- as: 'productionPrompt',
- },
- },
- { $unwind: { path: '$productionPrompt', preserveNullAndEmptyArrays: true } },
- {
- $project: {
- name: 1,
- numberOfGenerations: 1,
- oneliner: 1,
- category: 1,
- projectIds: 1,
- productionId: 1,
- author: 1,
- authorName: 1,
- createdAt: 1,
- updatedAt: 1,
- 'productionPrompt.prompt': 1,
- // 'productionPrompt._id': 1,
- // 'productionPrompt.type': 1,
- },
- },
- ];
-};
-
-/**
- * Create a pipeline for the aggregation to get all prompt groups
- * @param {Object} query
- * @param {Partial} $project
- * @returns {[Object]} - The pipeline for the aggregation
- */
-const createAllGroupsPipeline = (
- query,
- $project = {
- name: 1,
- oneliner: 1,
- category: 1,
- author: 1,
- authorName: 1,
- createdAt: 1,
- updatedAt: 1,
- command: 1,
- 'productionPrompt.prompt': 1,
- },
-) => {
- return [
- { $match: query },
- { $sort: { createdAt: -1 } },
- {
- $lookup: {
- from: 'prompts',
- localField: 'productionId',
- foreignField: '_id',
- as: 'productionPrompt',
- },
- },
- { $unwind: { path: '$productionPrompt', preserveNullAndEmptyArrays: true } },
- {
- $project,
- },
- ];
-};
-
-/**
- * Get all prompt groups with filters
- * @param {ServerRequest} req
- * @param {TPromptGroupsWithFilterRequest} filter
- * @returns {Promise}
- */
-const getAllPromptGroups = async (req, filter) => {
- try {
- const { name, ...query } = filter;
-
- let searchShared = true;
- let searchSharedOnly = false;
- if (name) {
- query.name = new RegExp(escapeRegExp(name), 'i');
- }
- if (!query.category) {
- delete query.category;
- } else if (query.category === SystemCategories.MY_PROMPTS) {
- searchShared = false;
- delete query.category;
- } else if (query.category === SystemCategories.NO_CATEGORY) {
- query.category = '';
- } else if (query.category === SystemCategories.SHARED_PROMPTS) {
- searchSharedOnly = true;
- delete query.category;
- }
-
- let combinedQuery = query;
-
- if (searchShared) {
- const project = await getProjectByName(Constants.GLOBAL_PROJECT_NAME, 'promptGroupIds');
- if (project && project.promptGroupIds && project.promptGroupIds.length > 0) {
- const projectQuery = { _id: { $in: project.promptGroupIds }, ...query };
- delete projectQuery.author;
- combinedQuery = searchSharedOnly ? projectQuery : { $or: [projectQuery, query] };
- }
- }
-
- const promptGroupsPipeline = createAllGroupsPipeline(combinedQuery);
- return await PromptGroup.aggregate(promptGroupsPipeline).exec();
- } catch (error) {
- console.error('Error getting all prompt groups', error);
- return { message: 'Error getting all prompt groups' };
- }
-};
-
-/**
- * Get prompt groups with filters
- * @param {ServerRequest} req
- * @param {TPromptGroupsWithFilterRequest} filter
- * @returns {Promise}
- */
-const getPromptGroups = async (req, filter) => {
- try {
- const { pageNumber = 1, pageSize = 10, name, ...query } = filter;
-
- const validatedPageNumber = Math.max(parseInt(pageNumber, 10), 1);
- const validatedPageSize = Math.max(parseInt(pageSize, 10), 1);
-
- let searchShared = true;
- let searchSharedOnly = false;
- if (name) {
- query.name = new RegExp(escapeRegExp(name), 'i');
- }
- if (!query.category) {
- delete query.category;
- } else if (query.category === SystemCategories.MY_PROMPTS) {
- searchShared = false;
- delete query.category;
- } else if (query.category === SystemCategories.NO_CATEGORY) {
- query.category = '';
- } else if (query.category === SystemCategories.SHARED_PROMPTS) {
- searchSharedOnly = true;
- delete query.category;
- }
-
- let combinedQuery = query;
-
- if (searchShared) {
- // const projects = req.user.projects || []; // TODO: handle multiple projects
- const project = await getProjectByName(Constants.GLOBAL_PROJECT_NAME, 'promptGroupIds');
- if (project && project.promptGroupIds && project.promptGroupIds.length > 0) {
- const projectQuery = { _id: { $in: project.promptGroupIds }, ...query };
- delete projectQuery.author;
- combinedQuery = searchSharedOnly ? projectQuery : { $or: [projectQuery, query] };
- }
- }
-
- const skip = (validatedPageNumber - 1) * validatedPageSize;
- const limit = validatedPageSize;
-
- const promptGroupsPipeline = createGroupPipeline(combinedQuery, skip, limit);
- const totalPromptGroupsPipeline = [{ $match: combinedQuery }, { $count: 'total' }];
-
- const [promptGroupsResults, totalPromptGroupsResults] = await Promise.all([
- PromptGroup.aggregate(promptGroupsPipeline).exec(),
- PromptGroup.aggregate(totalPromptGroupsPipeline).exec(),
- ]);
-
- const promptGroups = promptGroupsResults;
- const totalPromptGroups =
- totalPromptGroupsResults.length > 0 ? totalPromptGroupsResults[0].total : 0;
-
- return {
- promptGroups,
- pageNumber: validatedPageNumber.toString(),
- pageSize: validatedPageSize.toString(),
- pages: Math.ceil(totalPromptGroups / validatedPageSize).toString(),
- };
- } catch (error) {
- console.error('Error getting prompt groups', error);
- return { message: 'Error getting prompt groups' };
- }
-};
-
-/**
- * @param {Object} fields
- * @param {string} fields._id
- * @param {string} fields.author
- * @param {string} fields.role
- * @returns {Promise}
- */
-const deletePromptGroup = async ({ _id, author, role }) => {
- // Build query - with ACL, author is optional
- const query = { _id };
- const groupQuery = { groupId: new ObjectId(_id) };
-
- // Legacy: Add author filter if provided (backward compatibility)
- if (author && role !== SystemRoles.ADMIN) {
- query.author = author;
- groupQuery.author = author;
- }
-
- const response = await PromptGroup.deleteOne(query);
-
- if (!response || response.deletedCount === 0) {
- throw new Error('Prompt group not found');
- }
-
- await Prompt.deleteMany(groupQuery);
- await removeGroupFromAllProjects(_id);
-
- try {
- await removeAllPermissions({ resourceType: ResourceType.PROMPTGROUP, resourceId: _id });
- } catch (error) {
- logger.error('Error removing promptGroup permissions:', error);
- }
-
- return { message: 'Prompt group deleted successfully' };
-};
-
-/**
- * Get prompt groups by accessible IDs with optional cursor-based pagination.
- * @param {Object} params - The parameters for getting accessible prompt groups.
- * @param {Array} [params.accessibleIds] - Array of prompt group ObjectIds the user has ACL access to.
- * @param {Object} [params.otherParams] - Additional query parameters (including author filter).
- * @param {number} [params.limit] - Number of prompt groups to return (max 100). If not provided, returns all prompt groups.
- * @param {string} [params.after] - Cursor for pagination - get prompt groups after this cursor. // base64 encoded JSON string with updatedAt and _id.
- * @returns {Promise} A promise that resolves to an object containing the prompt groups data and pagination info.
- */
-async function getListPromptGroupsByAccess({
- accessibleIds = [],
- otherParams = {},
- limit = null,
- after = null,
-}) {
- const isPaginated = limit !== null && limit !== undefined;
- const normalizedLimit = isPaginated ? Math.min(Math.max(1, parseInt(limit) || 20), 100) : null;
-
- // Build base query combining ACL accessible prompt groups with other filters
- const baseQuery = { ...otherParams, _id: { $in: accessibleIds } };
-
- // Add cursor condition
- if (after && typeof after === 'string' && after !== 'undefined' && after !== 'null') {
- try {
- const cursor = JSON.parse(Buffer.from(after, 'base64').toString('utf8'));
- const { updatedAt, _id } = cursor;
-
- const cursorCondition = {
- $or: [
- { updatedAt: { $lt: new Date(updatedAt) } },
- { updatedAt: new Date(updatedAt), _id: { $gt: new ObjectId(_id) } },
- ],
- };
-
- // Merge cursor condition with base query
- if (Object.keys(baseQuery).length > 0) {
- baseQuery.$and = [{ ...baseQuery }, cursorCondition];
- // Remove the original conditions from baseQuery to avoid duplication
- Object.keys(baseQuery).forEach((key) => {
- if (key !== '$and') delete baseQuery[key];
- });
- } else {
- Object.assign(baseQuery, cursorCondition);
- }
- } catch (error) {
- logger.warn('Invalid cursor:', error.message);
- }
- }
-
- // Build aggregation pipeline
- const pipeline = [{ $match: baseQuery }, { $sort: { updatedAt: -1, _id: 1 } }];
-
- // Only apply limit if pagination is requested
- if (isPaginated) {
- pipeline.push({ $limit: normalizedLimit + 1 });
- }
-
- // Add lookup for production prompt
- pipeline.push(
- {
- $lookup: {
- from: 'prompts',
- localField: 'productionId',
- foreignField: '_id',
- as: 'productionPrompt',
- },
- },
- { $unwind: { path: '$productionPrompt', preserveNullAndEmptyArrays: true } },
- {
- $project: {
- name: 1,
- numberOfGenerations: 1,
- oneliner: 1,
- category: 1,
- projectIds: 1,
- productionId: 1,
- author: 1,
- authorName: 1,
- createdAt: 1,
- updatedAt: 1,
- 'productionPrompt.prompt': 1,
- },
- },
- );
-
- const promptGroups = await PromptGroup.aggregate(pipeline).exec();
-
- const hasMore = isPaginated ? promptGroups.length > normalizedLimit : false;
- const data = (isPaginated ? promptGroups.slice(0, normalizedLimit) : promptGroups).map(
- (group) => {
- if (group.author) {
- group.author = group.author.toString();
- }
- return group;
- },
- );
-
- // Generate next cursor only if paginated
- let nextCursor = null;
- if (isPaginated && hasMore && data.length > 0) {
- const lastGroup = promptGroups[normalizedLimit - 1];
- nextCursor = Buffer.from(
- JSON.stringify({
- updatedAt: lastGroup.updatedAt.toISOString(),
- _id: lastGroup._id.toString(),
- }),
- ).toString('base64');
- }
-
- return {
- object: 'list',
- data,
- first_id: data.length > 0 ? data[0]._id.toString() : null,
- last_id: data.length > 0 ? data[data.length - 1]._id.toString() : null,
- has_more: hasMore,
- after: nextCursor,
- };
-}
-
-module.exports = {
- getPromptGroups,
- deletePromptGroup,
- getAllPromptGroups,
- getListPromptGroupsByAccess,
- /**
- * Create a prompt and its respective group
- * @param {TCreatePromptRecord} saveData
- * @returns {Promise}
- */
- createPromptGroup: async (saveData) => {
- try {
- const { prompt, group, author, authorName } = saveData;
-
- let newPromptGroup = await PromptGroup.findOneAndUpdate(
- { ...group, author, authorName, productionId: null },
- { $setOnInsert: { ...group, author, authorName, productionId: null } },
- { new: true, upsert: true },
- )
- .lean()
- .select('-__v')
- .exec();
-
- const newPrompt = await Prompt.findOneAndUpdate(
- { ...prompt, author, groupId: newPromptGroup._id },
- { $setOnInsert: { ...prompt, author, groupId: newPromptGroup._id } },
- { new: true, upsert: true },
- )
- .lean()
- .select('-__v')
- .exec();
-
- newPromptGroup = await PromptGroup.findByIdAndUpdate(
- newPromptGroup._id,
- { productionId: newPrompt._id },
- { new: true },
- )
- .lean()
- .select('-__v')
- .exec();
-
- return {
- prompt: newPrompt,
- group: {
- ...newPromptGroup,
- productionPrompt: { prompt: newPrompt.prompt },
- },
- };
- } catch (error) {
- logger.error('Error saving prompt group', error);
- throw new Error('Error saving prompt group');
- }
- },
- /**
- * Save a prompt
- * @param {TCreatePromptRecord} saveData
- * @returns {Promise}
- */
- savePrompt: async (saveData) => {
- try {
- const { prompt, author } = saveData;
- const newPromptData = {
- ...prompt,
- author,
- };
-
- /** @type {TPrompt} */
- let newPrompt;
- try {
- newPrompt = await Prompt.create(newPromptData);
- } catch (error) {
- if (error?.message?.includes('groupId_1_version_1')) {
- await Prompt.db.collection('prompts').dropIndex('groupId_1_version_1');
- } else {
- throw error;
- }
- newPrompt = await Prompt.create(newPromptData);
- }
-
- return { prompt: newPrompt };
- } catch (error) {
- logger.error('Error saving prompt', error);
- return { message: 'Error saving prompt' };
- }
- },
- getPrompts: async (filter) => {
- try {
- return await Prompt.find(filter).sort({ createdAt: -1 }).lean();
- } catch (error) {
- logger.error('Error getting prompts', error);
- return { message: 'Error getting prompts' };
- }
- },
- getPrompt: async (filter) => {
- try {
- if (filter.groupId) {
- filter.groupId = new ObjectId(filter.groupId);
- }
- return await Prompt.findOne(filter).lean();
- } catch (error) {
- logger.error('Error getting prompt', error);
- return { message: 'Error getting prompt' };
- }
- },
- /**
- * Get prompt groups with filters
- * @param {TGetRandomPromptsRequest} filter
- * @returns {Promise}
- */
- getRandomPromptGroups: async (filter) => {
- try {
- const result = await PromptGroup.aggregate([
- {
- $match: {
- category: { $ne: '' },
- },
- },
- {
- $group: {
- _id: '$category',
- promptGroup: { $first: '$$ROOT' },
- },
- },
- {
- $replaceRoot: { newRoot: '$promptGroup' },
- },
- {
- $sample: { size: +filter.limit + +filter.skip },
- },
- {
- $skip: +filter.skip,
- },
- {
- $limit: +filter.limit,
- },
- ]);
- return { prompts: result };
- } catch (error) {
- logger.error('Error getting prompt groups', error);
- return { message: 'Error getting prompt groups' };
- }
- },
- getPromptGroupsWithPrompts: async (filter) => {
- try {
- return await PromptGroup.findOne(filter)
- .populate({
- path: 'prompts',
- select: '-_id -__v -user',
- })
- .select('-_id -__v -user')
- .lean();
- } catch (error) {
- logger.error('Error getting prompt groups', error);
- return { message: 'Error getting prompt groups' };
- }
- },
- getPromptGroup: async (filter) => {
- try {
- return await PromptGroup.findOne(filter).lean();
- } catch (error) {
- logger.error('Error getting prompt group', error);
- return { message: 'Error getting prompt group' };
- }
- },
- /**
- * Deletes a prompt and its corresponding prompt group if it is the last prompt in the group.
- *
- * @param {Object} options - The options for deleting the prompt.
- * @param {ObjectId|string} options.promptId - The ID of the prompt to delete.
- * @param {ObjectId|string} options.groupId - The ID of the prompt's group.
- * @param {ObjectId|string} options.author - The ID of the prompt's author.
- * @param {string} options.role - The role of the prompt's author.
- * @return {Promise} An object containing the result of the deletion.
- * If the prompt was deleted successfully, the object will have a property 'prompt' with the value 'Prompt deleted successfully'.
- * If the prompt group was deleted successfully, the object will have a property 'promptGroup' with the message 'Prompt group deleted successfully' and id of the deleted group.
- * If there was an error deleting the prompt, the object will have a property 'message' with the value 'Error deleting prompt'.
- */
- deletePrompt: async ({ promptId, groupId, author, role }) => {
- const query = { _id: promptId, groupId, author };
- if (role === SystemRoles.ADMIN) {
- delete query.author;
- }
- const { deletedCount } = await Prompt.deleteOne(query);
- if (deletedCount === 0) {
- throw new Error('Failed to delete the prompt');
- }
-
- const remainingPrompts = await Prompt.find({ groupId })
- .select('_id')
- .sort({ createdAt: 1 })
- .lean();
-
- if (remainingPrompts.length === 0) {
- // Remove all ACL entries for the promptGroup when deleting the last prompt
- try {
- await removeAllPermissions({
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: groupId,
- });
- } catch (error) {
- logger.error('Error removing promptGroup permissions:', error);
- }
-
- await PromptGroup.deleteOne({ _id: groupId });
- await removeGroupFromAllProjects(groupId);
-
- return {
- prompt: 'Prompt deleted successfully',
- promptGroup: {
- message: 'Prompt group deleted successfully',
- id: groupId,
- },
- };
- } else {
- const promptGroup = await PromptGroup.findById(groupId).lean();
- if (promptGroup.productionId.toString() === promptId.toString()) {
- await PromptGroup.updateOne(
- { _id: groupId },
- { productionId: remainingPrompts[remainingPrompts.length - 1]._id },
- );
- }
-
- return { prompt: 'Prompt deleted successfully' };
- }
- },
- /**
- * Delete all prompts and prompt groups created by a specific user.
- * @param {ServerRequest} req - The server request object.
- * @param {string} userId - The ID of the user whose prompts and prompt groups are to be deleted.
- */
- deleteUserPrompts: async (req, userId) => {
- try {
- const promptGroups = await getAllPromptGroups(req, { author: new ObjectId(userId) });
-
- if (promptGroups.length === 0) {
- return;
- }
-
- const groupIds = promptGroups.map((group) => group._id);
-
- for (const groupId of groupIds) {
- await removeGroupFromAllProjects(groupId);
- }
-
- await AclEntry.deleteMany({
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: { $in: groupIds },
- });
-
- await PromptGroup.deleteMany({ author: new ObjectId(userId) });
- await Prompt.deleteMany({ author: new ObjectId(userId) });
- } catch (error) {
- logger.error('[deleteUserPrompts] General error:', error);
- }
- },
- /**
- * Update prompt group
- * @param {Partial} filter - Filter to find prompt group
- * @param {Partial} data - Data to update
- * @returns {Promise}
- */
- updatePromptGroup: async (filter, data) => {
- try {
- const updateOps = {};
- if (data.removeProjectIds) {
- for (const projectId of data.removeProjectIds) {
- await removeGroupIdsFromProject(projectId, [filter._id]);
- }
-
- updateOps.$pull = { projectIds: { $in: data.removeProjectIds } };
- delete data.removeProjectIds;
- }
-
- if (data.projectIds) {
- for (const projectId of data.projectIds) {
- await addGroupIdsToProject(projectId, [filter._id]);
- }
-
- updateOps.$addToSet = { projectIds: { $each: data.projectIds } };
- delete data.projectIds;
- }
-
- const updateData = { ...data, ...updateOps };
- const updatedDoc = await PromptGroup.findOneAndUpdate(filter, updateData, {
- new: true,
- upsert: false,
- });
-
- if (!updatedDoc) {
- throw new Error('Prompt group not found');
- }
-
- return updatedDoc;
- } catch (error) {
- logger.error('Error updating prompt group', error);
- return { message: 'Error updating prompt group' };
- }
- },
- /**
- * Function to make a prompt production based on its ID.
- * @param {String} promptId - The ID of the prompt to make production.
- * @returns {Object} The result of the production operation.
- */
- makePromptProduction: async (promptId) => {
- try {
- const prompt = await Prompt.findById(promptId).lean();
-
- if (!prompt) {
- throw new Error('Prompt not found');
- }
-
- await PromptGroup.findByIdAndUpdate(
- prompt.groupId,
- { productionId: prompt._id },
- { new: true },
- )
- .lean()
- .exec();
-
- return {
- message: 'Prompt production made successfully',
- };
- } catch (error) {
- logger.error('Error making prompt production', error);
- return { message: 'Error making prompt production' };
- }
- },
- updatePromptLabels: async (_id, labels) => {
- try {
- const response = await Prompt.updateOne({ _id }, { $set: { labels } });
- if (response.matchedCount === 0) {
- return { message: 'Prompt not found' };
- }
- return { message: 'Prompt labels updated successfully' };
- } catch (error) {
- logger.error('Error updating prompt labels', error);
- return { message: 'Error updating prompt labels' };
- }
- },
-};
diff --git a/api/models/Prompt.spec.js b/api/models/Prompt.spec.js
deleted file mode 100644
index e00a1a518c..0000000000
--- a/api/models/Prompt.spec.js
+++ /dev/null
@@ -1,564 +0,0 @@
-const mongoose = require('mongoose');
-const { ObjectId } = require('mongodb');
-const { logger } = require('@librechat/data-schemas');
-const { MongoMemoryServer } = require('mongodb-memory-server');
-const {
- SystemRoles,
- ResourceType,
- AccessRoleIds,
- PrincipalType,
- PermissionBits,
-} = require('librechat-data-provider');
-
-// Mock the config/connect module to prevent connection attempts during tests
-jest.mock('../../config/connect', () => jest.fn().mockResolvedValue(true));
-
-const dbModels = require('~/db/models');
-
-// Disable console for tests
-logger.silent = true;
-
-let mongoServer;
-let Prompt, PromptGroup, AclEntry, AccessRole, User, Group, Project;
-let promptFns, permissionService;
-let testUsers, testGroups, testRoles;
-
-beforeAll(async () => {
- // Set up MongoDB memory server
- mongoServer = await MongoMemoryServer.create();
- const mongoUri = mongoServer.getUri();
- await mongoose.connect(mongoUri);
-
- // Initialize models
- Prompt = dbModels.Prompt;
- PromptGroup = dbModels.PromptGroup;
- AclEntry = dbModels.AclEntry;
- AccessRole = dbModels.AccessRole;
- User = dbModels.User;
- Group = dbModels.Group;
- Project = dbModels.Project;
-
- promptFns = require('~/models/Prompt');
- permissionService = require('~/server/services/PermissionService');
-
- // Create test data
- await setupTestData();
-});
-
-afterAll(async () => {
- await mongoose.disconnect();
- await mongoServer.stop();
- jest.clearAllMocks();
-});
-
-async function setupTestData() {
- // Create access roles for promptGroups
- testRoles = {
- viewer: await AccessRole.create({
- accessRoleId: AccessRoleIds.PROMPTGROUP_VIEWER,
- name: 'Viewer',
- description: 'Can view promptGroups',
- resourceType: ResourceType.PROMPTGROUP,
- permBits: PermissionBits.VIEW,
- }),
- editor: await AccessRole.create({
- accessRoleId: AccessRoleIds.PROMPTGROUP_EDITOR,
- name: 'Editor',
- description: 'Can view and edit promptGroups',
- resourceType: ResourceType.PROMPTGROUP,
- permBits: PermissionBits.VIEW | PermissionBits.EDIT,
- }),
- owner: await AccessRole.create({
- accessRoleId: AccessRoleIds.PROMPTGROUP_OWNER,
- name: 'Owner',
- description: 'Full control over promptGroups',
- resourceType: ResourceType.PROMPTGROUP,
- permBits:
- PermissionBits.VIEW | PermissionBits.EDIT | PermissionBits.DELETE | PermissionBits.SHARE,
- }),
- };
-
- // Create test users
- testUsers = {
- owner: await User.create({
- name: 'Prompt Owner',
- email: 'owner@example.com',
- role: SystemRoles.USER,
- }),
- editor: await User.create({
- name: 'Prompt Editor',
- email: 'editor@example.com',
- role: SystemRoles.USER,
- }),
- viewer: await User.create({
- name: 'Prompt Viewer',
- email: 'viewer@example.com',
- role: SystemRoles.USER,
- }),
- admin: await User.create({
- name: 'Admin User',
- email: 'admin@example.com',
- role: SystemRoles.ADMIN,
- }),
- noAccess: await User.create({
- name: 'No Access User',
- email: 'noaccess@example.com',
- role: SystemRoles.USER,
- }),
- };
-
- // Create test groups
- testGroups = {
- editors: await Group.create({
- name: 'Prompt Editors',
- description: 'Group with editor access',
- }),
- viewers: await Group.create({
- name: 'Prompt Viewers',
- description: 'Group with viewer access',
- }),
- };
-
- await Project.create({
- name: 'Global',
- description: 'Global project',
- promptGroupIds: [],
- });
-}
-
-describe('Prompt ACL Permissions', () => {
- describe('Creating Prompts with Permissions', () => {
- it('should grant owner permissions when creating a prompt', async () => {
- // First create a group
- const testGroup = await PromptGroup.create({
- name: 'Test Group',
- category: 'testing',
- author: testUsers.owner._id,
- authorName: testUsers.owner.name,
- productionId: new mongoose.Types.ObjectId(),
- });
-
- const promptData = {
- prompt: {
- prompt: 'Test prompt content',
- name: 'Test Prompt',
- type: 'text',
- groupId: testGroup._id,
- },
- author: testUsers.owner._id,
- };
-
- await promptFns.savePrompt(promptData);
-
- // Manually grant permissions as would happen in the route
- await permissionService.grantPermission({
- principalType: PrincipalType.USER,
- principalId: testUsers.owner._id,
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: testGroup._id,
- accessRoleId: AccessRoleIds.PROMPTGROUP_OWNER,
- grantedBy: testUsers.owner._id,
- });
-
- // Check ACL entry
- const aclEntry = await AclEntry.findOne({
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: testGroup._id,
- principalType: PrincipalType.USER,
- principalId: testUsers.owner._id,
- });
-
- expect(aclEntry).toBeTruthy();
- expect(aclEntry.permBits).toBe(testRoles.owner.permBits);
- });
- });
-
- describe('Accessing Prompts', () => {
- let testPromptGroup;
-
- beforeEach(async () => {
- // Create a prompt group
- testPromptGroup = await PromptGroup.create({
- name: 'Test Group',
- author: testUsers.owner._id,
- authorName: testUsers.owner.name,
- productionId: new ObjectId(),
- });
-
- // Create a prompt
- await Prompt.create({
- prompt: 'Test prompt for access control',
- name: 'Access Test Prompt',
- author: testUsers.owner._id,
- groupId: testPromptGroup._id,
- type: 'text',
- });
-
- // Grant owner permissions
- await permissionService.grantPermission({
- principalType: PrincipalType.USER,
- principalId: testUsers.owner._id,
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: testPromptGroup._id,
- accessRoleId: AccessRoleIds.PROMPTGROUP_OWNER,
- grantedBy: testUsers.owner._id,
- });
- });
-
- afterEach(async () => {
- await Prompt.deleteMany({});
- await PromptGroup.deleteMany({});
- await AclEntry.deleteMany({});
- });
-
- it('owner should have full access to their prompt', async () => {
- const hasAccess = await permissionService.checkPermission({
- userId: testUsers.owner._id,
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: testPromptGroup._id,
- requiredPermission: PermissionBits.VIEW,
- });
-
- expect(hasAccess).toBe(true);
-
- const canEdit = await permissionService.checkPermission({
- userId: testUsers.owner._id,
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: testPromptGroup._id,
- requiredPermission: PermissionBits.EDIT,
- });
-
- expect(canEdit).toBe(true);
- });
-
- it('user with viewer role should only have view access', async () => {
- // Grant viewer permissions
- await permissionService.grantPermission({
- principalType: PrincipalType.USER,
- principalId: testUsers.viewer._id,
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: testPromptGroup._id,
- accessRoleId: AccessRoleIds.PROMPTGROUP_VIEWER,
- grantedBy: testUsers.owner._id,
- });
-
- const canView = await permissionService.checkPermission({
- userId: testUsers.viewer._id,
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: testPromptGroup._id,
- requiredPermission: PermissionBits.VIEW,
- });
-
- const canEdit = await permissionService.checkPermission({
- userId: testUsers.viewer._id,
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: testPromptGroup._id,
- requiredPermission: PermissionBits.EDIT,
- });
-
- expect(canView).toBe(true);
- expect(canEdit).toBe(false);
- });
-
- it('user without permissions should have no access', async () => {
- const hasAccess = await permissionService.checkPermission({
- userId: testUsers.noAccess._id,
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: testPromptGroup._id,
- requiredPermission: PermissionBits.VIEW,
- });
-
- expect(hasAccess).toBe(false);
- });
-
- it('admin should have access regardless of permissions', async () => {
- // Admin users should work through normal permission system
- // The middleware layer handles admin bypass, not the permission service
- const hasAccess = await permissionService.checkPermission({
- userId: testUsers.admin._id,
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: testPromptGroup._id,
- requiredPermission: PermissionBits.VIEW,
- });
-
- // Without explicit permissions, even admin won't have access at this layer
- expect(hasAccess).toBe(false);
-
- // The actual admin bypass happens in the middleware layer (`canAccessPromptViaGroup`/`canAccessPromptGroupResource`)
- // which checks req.user.role === SystemRoles.ADMIN
- });
- });
-
- describe('Group-based Access', () => {
- let testPromptGroup;
-
- beforeEach(async () => {
- // Create a prompt group first
- testPromptGroup = await PromptGroup.create({
- name: 'Group Access Test Group',
- author: testUsers.owner._id,
- authorName: testUsers.owner.name,
- productionId: new ObjectId(),
- });
-
- await Prompt.create({
- prompt: 'Group access test prompt',
- name: 'Group Test',
- author: testUsers.owner._id,
- groupId: testPromptGroup._id,
- type: 'text',
- });
-
- // Add users to groups
- await User.findByIdAndUpdate(testUsers.editor._id, {
- $push: { groups: testGroups.editors._id },
- });
-
- await User.findByIdAndUpdate(testUsers.viewer._id, {
- $push: { groups: testGroups.viewers._id },
- });
- });
-
- afterEach(async () => {
- await Prompt.deleteMany({});
- await AclEntry.deleteMany({});
- await User.updateMany({}, { $set: { groups: [] } });
- });
-
- it('group members should inherit group permissions', async () => {
- // Create a prompt group
- const testPromptGroup = await PromptGroup.create({
- name: 'Group Test Group',
- author: testUsers.owner._id,
- authorName: testUsers.owner.name,
- productionId: new ObjectId(),
- });
-
- const { addUserToGroup } = require('~/models');
- await addUserToGroup(testUsers.editor._id, testGroups.editors._id);
-
- const prompt = await promptFns.savePrompt({
- author: testUsers.owner._id,
- prompt: {
- prompt: 'Group test prompt',
- name: 'Group Test',
- groupId: testPromptGroup._id,
- type: 'text',
- },
- });
-
- // Check if savePrompt returned an error
- if (!prompt || !prompt.prompt) {
- throw new Error(`Failed to save prompt: ${prompt?.message || 'Unknown error'}`);
- }
-
- // Grant edit permissions to the group
- await permissionService.grantPermission({
- principalType: PrincipalType.GROUP,
- principalId: testGroups.editors._id,
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: testPromptGroup._id,
- accessRoleId: AccessRoleIds.PROMPTGROUP_EDITOR,
- grantedBy: testUsers.owner._id,
- });
-
- // Check if group member has access
- const hasAccess = await permissionService.checkPermission({
- userId: testUsers.editor._id,
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: testPromptGroup._id,
- requiredPermission: PermissionBits.EDIT,
- });
-
- expect(hasAccess).toBe(true);
-
- // Check that non-member doesn't have access
- const nonMemberAccess = await permissionService.checkPermission({
- userId: testUsers.viewer._id,
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: testPromptGroup._id,
- requiredPermission: PermissionBits.EDIT,
- });
-
- expect(nonMemberAccess).toBe(false);
- });
- });
-
- describe('Public Access', () => {
- let publicPromptGroup, privatePromptGroup;
-
- beforeEach(async () => {
- // Create separate prompt groups for public and private access
- publicPromptGroup = await PromptGroup.create({
- name: 'Public Access Test Group',
- author: testUsers.owner._id,
- authorName: testUsers.owner.name,
- productionId: new ObjectId(),
- });
-
- privatePromptGroup = await PromptGroup.create({
- name: 'Private Access Test Group',
- author: testUsers.owner._id,
- authorName: testUsers.owner.name,
- productionId: new ObjectId(),
- });
-
- // Create prompts in their respective groups
- await Prompt.create({
- prompt: 'Public prompt',
- name: 'Public',
- author: testUsers.owner._id,
- groupId: publicPromptGroup._id,
- type: 'text',
- });
-
- await Prompt.create({
- prompt: 'Private prompt',
- name: 'Private',
- author: testUsers.owner._id,
- groupId: privatePromptGroup._id,
- type: 'text',
- });
-
- // Grant public view access to publicPromptGroup
- await permissionService.grantPermission({
- principalType: PrincipalType.PUBLIC,
- principalId: null,
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: publicPromptGroup._id,
- accessRoleId: AccessRoleIds.PROMPTGROUP_VIEWER,
- grantedBy: testUsers.owner._id,
- });
-
- // Grant only owner access to privatePromptGroup
- await permissionService.grantPermission({
- principalType: PrincipalType.USER,
- principalId: testUsers.owner._id,
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: privatePromptGroup._id,
- accessRoleId: AccessRoleIds.PROMPTGROUP_OWNER,
- grantedBy: testUsers.owner._id,
- });
- });
-
- afterEach(async () => {
- await Prompt.deleteMany({});
- await PromptGroup.deleteMany({});
- await AclEntry.deleteMany({});
- });
-
- it('public prompt should be accessible to any user', async () => {
- const hasAccess = await permissionService.checkPermission({
- userId: testUsers.noAccess._id,
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: publicPromptGroup._id,
- requiredPermission: PermissionBits.VIEW,
- includePublic: true,
- });
-
- expect(hasAccess).toBe(true);
- });
-
- it('private prompt should not be accessible to unauthorized users', async () => {
- const hasAccess = await permissionService.checkPermission({
- userId: testUsers.noAccess._id,
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: privatePromptGroup._id,
- requiredPermission: PermissionBits.VIEW,
- includePublic: true,
- });
-
- expect(hasAccess).toBe(false);
- });
- });
-
- describe('Prompt Deletion', () => {
- let testPromptGroup;
-
- it('should remove ACL entries when prompt is deleted', async () => {
- testPromptGroup = await PromptGroup.create({
- name: 'Deletion Test Group',
- author: testUsers.owner._id,
- authorName: testUsers.owner.name,
- productionId: new ObjectId(),
- });
-
- const prompt = await promptFns.savePrompt({
- author: testUsers.owner._id,
- prompt: {
- prompt: 'To be deleted',
- name: 'Delete Test',
- groupId: testPromptGroup._id,
- type: 'text',
- },
- });
-
- // Check if savePrompt returned an error
- if (!prompt || !prompt.prompt) {
- throw new Error(`Failed to save prompt: ${prompt?.message || 'Unknown error'}`);
- }
-
- const testPromptId = prompt.prompt._id;
- const promptGroupId = testPromptGroup._id;
-
- // Grant permission
- await permissionService.grantPermission({
- principalType: PrincipalType.USER,
- principalId: testUsers.owner._id,
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: testPromptGroup._id,
- accessRoleId: AccessRoleIds.PROMPTGROUP_OWNER,
- grantedBy: testUsers.owner._id,
- });
-
- // Verify ACL entry exists
- const beforeDelete = await AclEntry.find({
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: testPromptGroup._id,
- });
- expect(beforeDelete).toHaveLength(1);
-
- // Delete the prompt
- await promptFns.deletePrompt({
- promptId: testPromptId,
- groupId: promptGroupId,
- author: testUsers.owner._id,
- role: SystemRoles.USER,
- });
-
- // Verify ACL entries are removed
- const aclEntries = await AclEntry.find({
- resourceType: ResourceType.PROMPTGROUP,
- resourceId: testPromptGroup._id,
- });
-
- expect(aclEntries).toHaveLength(0);
- });
- });
-
- describe('Backwards Compatibility', () => {
- it('should handle prompts without ACL entries gracefully', async () => {
- // Create a prompt group first
- const promptGroup = await PromptGroup.create({
- name: 'Legacy Test Group',
- author: testUsers.owner._id,
- authorName: testUsers.owner.name,
- productionId: new ObjectId(),
- });
-
- // Create a prompt without ACL entries (legacy prompt)
- const legacyPrompt = await Prompt.create({
- prompt: 'Legacy prompt without ACL',
- name: 'Legacy',
- author: testUsers.owner._id,
- groupId: promptGroup._id,
- type: 'text',
- });
-
- // The system should handle this gracefully
- const prompt = await promptFns.getPrompt({ _id: legacyPrompt._id });
- expect(prompt).toBeTruthy();
- expect(prompt._id.toString()).toBe(legacyPrompt._id.toString());
- });
- });
-});
diff --git a/api/models/Role.js b/api/models/Role.js
deleted file mode 100644
index 1766dc9b08..0000000000
--- a/api/models/Role.js
+++ /dev/null
@@ -1,256 +0,0 @@
-const {
- CacheKeys,
- SystemRoles,
- roleDefaults,
- permissionsSchema,
- removeNullishValues,
-} = require('librechat-data-provider');
-const { logger } = require('@librechat/data-schemas');
-const getLogStores = require('~/cache/getLogStores');
-const { Role } = require('~/db/models');
-
-/**
- * Retrieve a role by name and convert the found role document to a plain object.
- * If the role with the given name doesn't exist and the name is a system defined role,
- * create it and return the lean version.
- *
- * @param {string} roleName - The name of the role to find or create.
- * @param {string|string[]} [fieldsToSelect] - The fields to include or exclude in the returned document.
- * @returns {Promise} Role document.
- */
-const getRoleByName = async function (roleName, fieldsToSelect = null) {
- const cache = getLogStores(CacheKeys.ROLES);
- try {
- const cachedRole = await cache.get(roleName);
- if (cachedRole) {
- return cachedRole;
- }
- let query = Role.findOne({ name: roleName });
- if (fieldsToSelect) {
- query = query.select(fieldsToSelect);
- }
- let role = await query.lean().exec();
-
- if (!role && SystemRoles[roleName]) {
- role = await new Role(roleDefaults[roleName]).save();
- await cache.set(roleName, role);
- return role.toObject();
- }
- await cache.set(roleName, role);
- return role;
- } catch (error) {
- throw new Error(`Failed to retrieve or create role: ${error.message}`);
- }
-};
-
-/**
- * Update role values by name.
- *
- * @param {string} roleName - The name of the role to update.
- * @param {Partial} updates - The fields to update.
- * @returns {Promise} Updated role document.
- */
-const updateRoleByName = async function (roleName, updates) {
- const cache = getLogStores(CacheKeys.ROLES);
- try {
- const role = await Role.findOneAndUpdate(
- { name: roleName },
- { $set: updates },
- { new: true, lean: true },
- )
- .select('-__v')
- .lean()
- .exec();
- await cache.set(roleName, role);
- return role;
- } catch (error) {
- throw new Error(`Failed to update role: ${error.message}`);
- }
-};
-
-/**
- * Updates access permissions for a specific role and multiple permission types.
- * @param {string} roleName - The role to update.
- * @param {Object.>} permissionsUpdate - Permissions to update and their values.
- * @param {IRole} [roleData] - Optional role data to use instead of fetching from the database.
- */
-async function updateAccessPermissions(roleName, permissionsUpdate, roleData) {
- // Filter and clean the permission updates based on our schema definition.
- const updates = {};
- for (const [permissionType, permissions] of Object.entries(permissionsUpdate)) {
- if (permissionsSchema.shape && permissionsSchema.shape[permissionType]) {
- updates[permissionType] = removeNullishValues(permissions);
- }
- }
- if (!Object.keys(updates).length) {
- return;
- }
-
- try {
- const role = roleData ?? (await getRoleByName(roleName));
- if (!role) {
- return;
- }
-
- const currentPermissions = role.permissions || {};
- const updatedPermissions = { ...currentPermissions };
- let hasChanges = false;
-
- const unsetFields = {};
- const permissionTypes = Object.keys(permissionsSchema.shape || {});
- for (const permType of permissionTypes) {
- if (role[permType] && typeof role[permType] === 'object') {
- logger.info(
- `Migrating '${roleName}' role from old schema: found '${permType}' at top level`,
- );
-
- updatedPermissions[permType] = {
- ...updatedPermissions[permType],
- ...role[permType],
- };
-
- unsetFields[permType] = 1;
- hasChanges = true;
- }
- }
-
- for (const [permissionType, permissions] of Object.entries(updates)) {
- const currentTypePermissions = currentPermissions[permissionType] || {};
- updatedPermissions[permissionType] = { ...currentTypePermissions };
-
- for (const [permission, value] of Object.entries(permissions)) {
- if (currentTypePermissions[permission] !== value) {
- updatedPermissions[permissionType][permission] = value;
- hasChanges = true;
- logger.info(
- `Updating '${roleName}' role permission '${permissionType}' '${permission}' from ${currentTypePermissions[permission]} to: ${value}`,
- );
- }
- }
- }
-
- if (hasChanges) {
- const updateObj = { permissions: updatedPermissions };
-
- if (Object.keys(unsetFields).length > 0) {
- logger.info(
- `Unsetting old schema fields for '${roleName}' role: ${Object.keys(unsetFields).join(', ')}`,
- );
-
- try {
- await Role.updateOne(
- { name: roleName },
- {
- $set: updateObj,
- $unset: unsetFields,
- },
- );
-
- const cache = getLogStores(CacheKeys.ROLES);
- const updatedRole = await Role.findOne({ name: roleName }).select('-__v').lean().exec();
- await cache.set(roleName, updatedRole);
-
- logger.info(`Updated role '${roleName}' and removed old schema fields`);
- } catch (updateError) {
- logger.error(`Error during role migration update: ${updateError.message}`);
- throw updateError;
- }
- } else {
- // Standard update if no migration needed
- await updateRoleByName(roleName, updateObj);
- }
-
- logger.info(`Updated '${roleName}' role permissions`);
- } else {
- logger.info(`No changes needed for '${roleName}' role permissions`);
- }
- } catch (error) {
- logger.error(`Failed to update ${roleName} role permissions:`, error);
- }
-}
-
-/**
- * Migrates roles from old schema to new schema structure.
- * This can be called directly to fix existing roles.
- *
- * @param {string} [roleName] - Optional specific role to migrate. If not provided, migrates all roles.
- * @returns {Promise} Number of roles migrated.
- */
-const migrateRoleSchema = async function (roleName) {
- try {
- // Get roles to migrate
- let roles;
- if (roleName) {
- const role = await Role.findOne({ name: roleName });
- roles = role ? [role] : [];
- } else {
- roles = await Role.find({});
- }
-
- logger.info(`Migrating ${roles.length} roles to new schema structure`);
- let migratedCount = 0;
-
- for (const role of roles) {
- const permissionTypes = Object.keys(permissionsSchema.shape || {});
- const unsetFields = {};
- let hasOldSchema = false;
-
- // Check for old schema fields
- for (const permType of permissionTypes) {
- if (role[permType] && typeof role[permType] === 'object') {
- hasOldSchema = true;
-
- // Ensure permissions object exists
- role.permissions = role.permissions || {};
-
- // Migrate permissions from old location to new
- role.permissions[permType] = {
- ...role.permissions[permType],
- ...role[permType],
- };
-
- // Mark field for removal
- unsetFields[permType] = 1;
- }
- }
-
- if (hasOldSchema) {
- try {
- logger.info(`Migrating role '${role.name}' from old schema structure`);
-
- // Simple update operation
- await Role.updateOne(
- { _id: role._id },
- {
- $set: { permissions: role.permissions },
- $unset: unsetFields,
- },
- );
-
- // Refresh cache
- const cache = getLogStores(CacheKeys.ROLES);
- const updatedRole = await Role.findById(role._id).lean().exec();
- await cache.set(role.name, updatedRole);
-
- migratedCount++;
- logger.info(`Migrated role '${role.name}'`);
- } catch (error) {
- logger.error(`Failed to migrate role '${role.name}': ${error.message}`);
- }
- }
- }
-
- logger.info(`Migration complete: ${migratedCount} roles migrated`);
- return migratedCount;
- } catch (error) {
- logger.error(`Role schema migration failed: ${error.message}`);
- throw error;
- }
-};
-
-module.exports = {
- getRoleByName,
- updateRoleByName,
- migrateRoleSchema,
- updateAccessPermissions,
-};
diff --git a/api/models/ToolCall.js b/api/models/ToolCall.js
deleted file mode 100644
index 689386114b..0000000000
--- a/api/models/ToolCall.js
+++ /dev/null
@@ -1,96 +0,0 @@
-const { ToolCall } = require('~/db/models');
-
-/**
- * Create a new tool call
- * @param {IToolCallData} toolCallData - The tool call data
- * @returns {Promise} The created tool call document
- */
-async function createToolCall(toolCallData) {
- try {
- return await ToolCall.create(toolCallData);
- } catch (error) {
- throw new Error(`Error creating tool call: ${error.message}`);
- }
-}
-
-/**
- * Get a tool call by ID
- * @param {string} id - The tool call document ID
- * @returns {Promise} The tool call document or null if not found
- */
-async function getToolCallById(id) {
- try {
- return await ToolCall.findById(id).lean();
- } catch (error) {
- throw new Error(`Error fetching tool call: ${error.message}`);
- }
-}
-
-/**
- * Get tool calls by message ID and user
- * @param {string} messageId - The message ID
- * @param {string} userId - The user's ObjectId
- * @returns {Promise} Array of tool call documents
- */
-async function getToolCallsByMessage(messageId, userId) {
- try {
- return await ToolCall.find({ messageId, user: userId }).lean();
- } catch (error) {
- throw new Error(`Error fetching tool calls: ${error.message}`);
- }
-}
-
-/**
- * Get tool calls by conversation ID and user
- * @param {string} conversationId - The conversation ID
- * @param {string} userId - The user's ObjectId
- * @returns {Promise} Array of tool call documents
- */
-async function getToolCallsByConvo(conversationId, userId) {
- try {
- return await ToolCall.find({ conversationId, user: userId }).lean();
- } catch (error) {
- throw new Error(`Error fetching tool calls: ${error.message}`);
- }
-}
-
-/**
- * Update a tool call
- * @param {string} id - The tool call document ID
- * @param {Partial} updateData - The data to update
- * @returns {Promise} The updated tool call document or null if not found
- */
-async function updateToolCall(id, updateData) {
- try {
- return await ToolCall.findByIdAndUpdate(id, updateData, { new: true }).lean();
- } catch (error) {
- throw new Error(`Error updating tool call: ${error.message}`);
- }
-}
-
-/**
- * Delete a tool call
- * @param {string} userId - The related user's ObjectId
- * @param {string} [conversationId] - The tool call conversation ID
- * @returns {Promise<{ ok?: number; n?: number; deletedCount?: number }>} The result of the delete operation
- */
-async function deleteToolCalls(userId, conversationId) {
- try {
- const query = { user: userId };
- if (conversationId) {
- query.conversationId = conversationId;
- }
- return await ToolCall.deleteMany(query);
- } catch (error) {
- throw new Error(`Error deleting tool call: ${error.message}`);
- }
-}
-
-module.exports = {
- createToolCall,
- updateToolCall,
- deleteToolCalls,
- getToolCallById,
- getToolCallsByConvo,
- getToolCallsByMessage,
-};
diff --git a/api/models/Transaction.js b/api/models/Transaction.js
deleted file mode 100644
index e553e2bb3b..0000000000
--- a/api/models/Transaction.js
+++ /dev/null
@@ -1,356 +0,0 @@
-const { logger } = require('@librechat/data-schemas');
-const { getMultiplier, getCacheMultiplier } = require('./tx');
-const { Transaction, Balance } = require('~/db/models');
-
-const cancelRate = 1.15;
-
-/**
- * Updates a user's token balance based on a transaction using optimistic concurrency control
- * without schema changes. Compatible with DocumentDB.
- * @async
- * @function
- * @param {Object} params - The function parameters.
- * @param {string|mongoose.Types.ObjectId} params.user - The user ID.
- * @param {number} params.incrementValue - The value to increment the balance by (can be negative).
- * @param {import('mongoose').UpdateQuery['$set']} [params.setValues] - Optional additional fields to set.
- * @returns {Promise} Returns the updated balance document (lean).
- * @throws {Error} Throws an error if the update fails after multiple retries.
- */
-const updateBalance = async ({ user, incrementValue, setValues }) => {
- let maxRetries = 10; // Number of times to retry on conflict
- let delay = 50; // Initial retry delay in ms
- let lastError = null;
-
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
- let currentBalanceDoc;
- try {
- // 1. Read the current document state
- currentBalanceDoc = await Balance.findOne({ user }).lean();
- const currentCredits = currentBalanceDoc ? currentBalanceDoc.tokenCredits : 0;
-
- // 2. Calculate the desired new state
- const potentialNewCredits = currentCredits + incrementValue;
- const newCredits = Math.max(0, potentialNewCredits); // Ensure balance doesn't go below zero
-
- // 3. Prepare the update payload
- const updatePayload = {
- $set: {
- tokenCredits: newCredits,
- ...(setValues || {}), // Merge other values to set
- },
- };
-
- // 4. Attempt the conditional update or upsert
- let updatedBalance = null;
- if (currentBalanceDoc) {
- // --- Document Exists: Perform Conditional Update ---
- // Try to update only if the tokenCredits match the value we read (currentCredits)
- updatedBalance = await Balance.findOneAndUpdate(
- {
- user: user,
- tokenCredits: currentCredits, // Optimistic lock: condition based on the read value
- },
- updatePayload,
- {
- new: true, // Return the modified document
- // lean: true, // .lean() is applied after query execution in Mongoose >= 6
- },
- ).lean(); // Use lean() for plain JS object
-
- if (updatedBalance) {
- // Success! The update was applied based on the expected current state.
- return updatedBalance;
- }
- // If updatedBalance is null, it means tokenCredits changed between read and write (conflict).
- lastError = new Error(`Concurrency conflict for user ${user} on attempt ${attempt}.`);
- // Proceed to retry logic below.
- } else {
- // --- Document Does Not Exist: Perform Conditional Upsert ---
- // Try to insert the document, but only if it still doesn't exist.
- // Using tokenCredits: {$exists: false} helps prevent race conditions where
- // another process creates the doc between our findOne and findOneAndUpdate.
- try {
- updatedBalance = await Balance.findOneAndUpdate(
- {
- user: user,
- // Attempt to match only if the document doesn't exist OR was just created
- // without tokenCredits (less likely but possible). A simple { user } filter
- // might also work, relying on the retry for conflicts.
- // Let's use a simpler filter and rely on retry for races.
- // tokenCredits: { $exists: false } // This condition might be too strict if doc exists with 0 credits
- },
- updatePayload,
- {
- upsert: true, // Create if doesn't exist
- new: true, // Return the created/updated document
- // setDefaultsOnInsert: true, // Ensure schema defaults are applied on insert
- // lean: true,
- },
- ).lean();
-
- if (updatedBalance) {
- // Upsert succeeded (likely created the document)
- return updatedBalance;
- }
- // If null, potentially a rare race condition during upsert. Retry should handle it.
- lastError = new Error(
- `Upsert race condition suspected for user ${user} on attempt ${attempt}.`,
- );
- } catch (error) {
- if (error.code === 11000) {
- // E11000 duplicate key error on index
- // This means another process created the document *just* before our upsert.
- // It's a concurrency conflict during creation. We should retry.
- lastError = error; // Store the error
- // Proceed to retry logic below.
- } else {
- // Different error, rethrow
- throw error;
- }
- }
- } // End if/else (document exists?)
- } catch (error) {
- // Catch errors from findOne or unexpected findOneAndUpdate errors
- logger.error(`[updateBalance] Error during attempt ${attempt} for user ${user}:`, error);
- lastError = error; // Store the error
- // Consider stopping retries for non-transient errors, but for now, we retry.
- }
-
- // If we reached here, it means the update failed (conflict or error), wait and retry
- if (attempt < maxRetries) {
- const jitter = Math.random() * delay * 0.5; // Add jitter to delay
- await new Promise((resolve) => setTimeout(resolve, delay + jitter));
- delay = Math.min(delay * 2, 2000); // Exponential backoff with cap
- }
- } // End for loop (retries)
-
- // If loop finishes without success, throw the last encountered error or a generic one
- logger.error(
- `[updateBalance] Failed to update balance for user ${user} after ${maxRetries} attempts.`,
- );
- throw (
- lastError ||
- new Error(
- `Failed to update balance for user ${user} after maximum retries due to persistent conflicts.`,
- )
- );
-};
-
-/** Method to calculate and set the tokenValue for a transaction */
-function calculateTokenValue(txn) {
- const { valueKey, tokenType, model, endpointTokenConfig, inputTokenCount } = txn;
- const multiplier = Math.abs(
- getMultiplier({ valueKey, tokenType, model, endpointTokenConfig, inputTokenCount }),
- );
- txn.rate = multiplier;
- txn.tokenValue = txn.rawAmount * multiplier;
- if (txn.context && txn.tokenType === 'completion' && txn.context === 'incomplete') {
- txn.tokenValue = Math.ceil(txn.tokenValue * cancelRate);
- txn.rate *= cancelRate;
- }
-}
-
-/**
- * New static method to create an auto-refill transaction that does NOT trigger a balance update.
- * @param {object} txData - Transaction data.
- * @param {string} txData.user - The user ID.
- * @param {string} txData.tokenType - The type of token.
- * @param {string} txData.context - The context of the transaction.
- * @param {number} txData.rawAmount - The raw amount of tokens.
- * @returns {Promise} - The created transaction.
- */
-async function createAutoRefillTransaction(txData) {
- if (txData.rawAmount != null && isNaN(txData.rawAmount)) {
- return;
- }
- const transaction = new Transaction(txData);
- transaction.endpointTokenConfig = txData.endpointTokenConfig;
- transaction.inputTokenCount = txData.inputTokenCount;
- calculateTokenValue(transaction);
- await transaction.save();
-
- const balanceResponse = await updateBalance({
- user: transaction.user,
- incrementValue: txData.rawAmount,
- setValues: { lastRefill: new Date() },
- });
- const result = {
- rate: transaction.rate,
- user: transaction.user.toString(),
- balance: balanceResponse.tokenCredits,
- };
- logger.debug('[Balance.check] Auto-refill performed', result);
- result.transaction = transaction;
- return result;
-}
-
-/**
- * Static method to create a transaction and update the balance
- * @param {txData} _txData - Transaction data.
- */
-async function createTransaction(_txData) {
- const { balance, transactions, ...txData } = _txData;
- if (txData.rawAmount != null && isNaN(txData.rawAmount)) {
- return;
- }
-
- if (transactions?.enabled === false) {
- return;
- }
-
- const transaction = new Transaction(txData);
- transaction.endpointTokenConfig = txData.endpointTokenConfig;
- transaction.inputTokenCount = txData.inputTokenCount;
- calculateTokenValue(transaction);
-
- await transaction.save();
- if (!balance?.enabled) {
- return;
- }
-
- let incrementValue = transaction.tokenValue;
- const balanceResponse = await updateBalance({
- user: transaction.user,
- incrementValue,
- });
-
- return {
- rate: transaction.rate,
- user: transaction.user.toString(),
- balance: balanceResponse.tokenCredits,
- [transaction.tokenType]: incrementValue,
- };
-}
-
-/**
- * Static method to create a structured transaction and update the balance
- * @param {txData} _txData - Transaction data.
- */
-async function createStructuredTransaction(_txData) {
- const { balance, transactions, ...txData } = _txData;
- if (transactions?.enabled === false) {
- return;
- }
-
- const transaction = new Transaction(txData);
- transaction.endpointTokenConfig = txData.endpointTokenConfig;
- transaction.inputTokenCount = txData.inputTokenCount;
-
- calculateStructuredTokenValue(transaction);
-
- await transaction.save();
-
- if (!balance?.enabled) {
- return;
- }
-
- let incrementValue = transaction.tokenValue;
-
- const balanceResponse = await updateBalance({
- user: transaction.user,
- incrementValue,
- });
-
- return {
- rate: transaction.rate,
- user: transaction.user.toString(),
- balance: balanceResponse.tokenCredits,
- [transaction.tokenType]: incrementValue,
- };
-}
-
-/** Method to calculate token value for structured tokens */
-function calculateStructuredTokenValue(txn) {
- if (!txn.tokenType) {
- txn.tokenValue = txn.rawAmount;
- return;
- }
-
- const { model, endpointTokenConfig, inputTokenCount } = txn;
-
- if (txn.tokenType === 'prompt') {
- const inputMultiplier = getMultiplier({
- tokenType: 'prompt',
- model,
- endpointTokenConfig,
- inputTokenCount,
- });
- const writeMultiplier =
- getCacheMultiplier({ cacheType: 'write', model, endpointTokenConfig }) ?? inputMultiplier;
- const readMultiplier =
- getCacheMultiplier({ cacheType: 'read', model, endpointTokenConfig }) ?? inputMultiplier;
-
- txn.rateDetail = {
- input: inputMultiplier,
- write: writeMultiplier,
- read: readMultiplier,
- };
-
- const totalPromptTokens =
- Math.abs(txn.inputTokens || 0) +
- Math.abs(txn.writeTokens || 0) +
- Math.abs(txn.readTokens || 0);
-
- if (totalPromptTokens > 0) {
- txn.rate =
- (Math.abs(inputMultiplier * (txn.inputTokens || 0)) +
- Math.abs(writeMultiplier * (txn.writeTokens || 0)) +
- Math.abs(readMultiplier * (txn.readTokens || 0))) /
- totalPromptTokens;
- } else {
- txn.rate = Math.abs(inputMultiplier); // Default to input rate if no tokens
- }
-
- txn.tokenValue = -(
- Math.abs(txn.inputTokens || 0) * inputMultiplier +
- Math.abs(txn.writeTokens || 0) * writeMultiplier +
- Math.abs(txn.readTokens || 0) * readMultiplier
- );
-
- txn.rawAmount = -totalPromptTokens;
- } else if (txn.tokenType === 'completion') {
- const multiplier = getMultiplier({
- tokenType: txn.tokenType,
- model,
- endpointTokenConfig,
- inputTokenCount,
- });
- txn.rate = Math.abs(multiplier);
- txn.tokenValue = -Math.abs(txn.rawAmount) * multiplier;
- txn.rawAmount = -Math.abs(txn.rawAmount);
- }
-
- if (txn.context && txn.tokenType === 'completion' && txn.context === 'incomplete') {
- txn.tokenValue = Math.ceil(txn.tokenValue * cancelRate);
- txn.rate *= cancelRate;
- if (txn.rateDetail) {
- txn.rateDetail = Object.fromEntries(
- Object.entries(txn.rateDetail).map(([k, v]) => [k, v * cancelRate]),
- );
- }
- }
-}
-
-/**
- * Queries and retrieves transactions based on a given filter.
- * @async
- * @function getTransactions
- * @param {Object} filter - MongoDB filter object to apply when querying transactions.
- * @returns {Promise} A promise that resolves to an array of matched transactions.
- * @throws {Error} Throws an error if querying the database fails.
- */
-async function getTransactions(filter) {
- try {
- return await Transaction.find(filter).lean();
- } catch (error) {
- logger.error('Error querying transactions:', error);
- throw error;
- }
-}
-
-module.exports = {
- getTransactions,
- createTransaction,
- createAutoRefillTransaction,
- createStructuredTransaction,
-};
diff --git a/api/models/balanceMethods.js b/api/models/balanceMethods.js
deleted file mode 100644
index e614872eac..0000000000
--- a/api/models/balanceMethods.js
+++ /dev/null
@@ -1,156 +0,0 @@
-const { logger } = require('@librechat/data-schemas');
-const { ViolationTypes } = require('librechat-data-provider');
-const { createAutoRefillTransaction } = require('./Transaction');
-const { logViolation } = require('~/cache');
-const { getMultiplier } = require('./tx');
-const { Balance } = require('~/db/models');
-
-function isInvalidDate(date) {
- return isNaN(date);
-}
-
-/**
- * Simple check method that calculates token cost and returns balance info.
- * The auto-refill logic has been moved to balanceMethods.js to prevent circular dependencies.
- */
-const checkBalanceRecord = async function ({
- user,
- model,
- endpoint,
- valueKey,
- tokenType,
- amount,
- endpointTokenConfig,
-}) {
- const multiplier = getMultiplier({ valueKey, tokenType, model, endpoint, endpointTokenConfig });
- const tokenCost = amount * multiplier;
-
- // Retrieve the balance record
- let record = await Balance.findOne({ user }).lean();
- if (!record) {
- logger.debug('[Balance.check] No balance record found for user', { user });
- return {
- canSpend: false,
- balance: 0,
- tokenCost,
- };
- }
- let balance = record.tokenCredits;
-
- logger.debug('[Balance.check] Initial state', {
- user,
- model,
- endpoint,
- valueKey,
- tokenType,
- amount,
- balance,
- multiplier,
- endpointTokenConfig: !!endpointTokenConfig,
- });
-
- // Only perform auto-refill if spending would bring the balance to 0 or below
- if (balance - tokenCost <= 0 && record.autoRefillEnabled && record.refillAmount > 0) {
- const lastRefillDate = new Date(record.lastRefill);
- const now = new Date();
- if (
- isInvalidDate(lastRefillDate) ||
- now >=
- addIntervalToDate(lastRefillDate, record.refillIntervalValue, record.refillIntervalUnit)
- ) {
- try {
- /** @type {{ rate: number, user: string, balance: number, transaction: import('@librechat/data-schemas').ITransaction}} */
- const result = await createAutoRefillTransaction({
- user: user,
- tokenType: 'credits',
- context: 'autoRefill',
- rawAmount: record.refillAmount,
- });
- balance = result.balance;
- } catch (error) {
- logger.error('[Balance.check] Failed to record transaction for auto-refill', error);
- }
- }
- }
-
- logger.debug('[Balance.check] Token cost', { tokenCost });
- return { canSpend: balance >= tokenCost, balance, tokenCost };
-};
-
-/**
- * Adds a time interval to a given date.
- * @param {Date} date - The starting date.
- * @param {number} value - The numeric value of the interval.
- * @param {'seconds'|'minutes'|'hours'|'days'|'weeks'|'months'} unit - The unit of time.
- * @returns {Date} A new Date representing the starting date plus the interval.
- */
-const addIntervalToDate = (date, value, unit) => {
- const result = new Date(date);
- switch (unit) {
- case 'seconds':
- result.setSeconds(result.getSeconds() + value);
- break;
- case 'minutes':
- result.setMinutes(result.getMinutes() + value);
- break;
- case 'hours':
- result.setHours(result.getHours() + value);
- break;
- case 'days':
- result.setDate(result.getDate() + value);
- break;
- case 'weeks':
- result.setDate(result.getDate() + value * 7);
- break;
- case 'months':
- result.setMonth(result.getMonth() + value);
- break;
- default:
- break;
- }
- return result;
-};
-
-/**
- * Checks the balance for a user and determines if they can spend a certain amount.
- * If the user cannot spend the amount, it logs a violation and denies the request.
- *
- * @async
- * @function
- * @param {Object} params - The function parameters.
- * @param {ServerRequest} params.req - The Express request object.
- * @param {Express.Response} params.res - The Express response object.
- * @param {Object} params.txData - The transaction data.
- * @param {string} params.txData.user - The user ID or identifier.
- * @param {('prompt' | 'completion')} params.txData.tokenType - The type of token.
- * @param {number} params.txData.amount - The amount of tokens.
- * @param {string} params.txData.model - The model name or identifier.
- * @param {string} [params.txData.endpointTokenConfig] - The token configuration for the endpoint.
- * @returns {Promise} Throws error if the user cannot spend the amount.
- * @throws {Error} Throws an error if there's an issue with the balance check.
- */
-const checkBalance = async ({ req, res, txData }) => {
- const { canSpend, balance, tokenCost } = await checkBalanceRecord(txData);
- if (canSpend) {
- return true;
- }
-
- const type = ViolationTypes.TOKEN_BALANCE;
- const errorMessage = {
- type,
- balance,
- tokenCost,
- promptTokens: txData.amount,
- };
-
- if (txData.generations && txData.generations.length > 0) {
- errorMessage.generations = txData.generations;
- }
-
- await logViolation(req, res, type, errorMessage, 0);
- throw new Error(JSON.stringify(errorMessage));
-};
-
-module.exports = {
- checkBalance,
-};
diff --git a/api/models/index.js b/api/models/index.js
index d0b10be079..2a1cb222f9 100644
--- a/api/models/index.js
+++ b/api/models/index.js
@@ -1,48 +1,22 @@
const mongoose = require('mongoose');
const { createMethods } = require('@librechat/data-schemas');
-const methods = createMethods(mongoose);
-const { comparePassword } = require('./userMethods');
-const {
- getMessage,
- getMessages,
- saveMessage,
- recordMessage,
- updateMessage,
- deleteMessagesSince,
- deleteMessages,
-} = require('./Message');
-const { getConvoTitle, getConvo, saveConvo, deleteConvos } = require('./Conversation');
-const { getPreset, getPresets, savePreset, deletePresets } = require('./Preset');
-const { File } = require('~/db/models');
+const { matchModelName, findMatchingPattern } = require('@librechat/api');
+const getLogStores = require('~/cache/getLogStores');
+
+const methods = createMethods(mongoose, {
+ matchModelName,
+ findMatchingPattern,
+ getCache: getLogStores,
+});
const seedDatabase = async () => {
await methods.initializeRoles();
await methods.seedDefaultRoles();
await methods.ensureDefaultCategories();
+ await methods.seedSystemGrants();
};
module.exports = {
...methods,
seedDatabase,
- comparePassword,
-
- getMessage,
- getMessages,
- saveMessage,
- recordMessage,
- updateMessage,
- deleteMessagesSince,
- deleteMessages,
-
- getConvoTitle,
- getConvo,
- saveConvo,
- deleteConvos,
-
- getPreset,
- getPresets,
- savePreset,
- deletePresets,
-
- Files: File,
};
diff --git a/api/models/interface.js b/api/models/interface.js
deleted file mode 100644
index a79a8e747f..0000000000
--- a/api/models/interface.js
+++ /dev/null
@@ -1,24 +0,0 @@
-const { logger } = require('@librechat/data-schemas');
-const { updateInterfacePermissions: updateInterfacePerms } = require('@librechat/api');
-const { getRoleByName, updateAccessPermissions } = require('./Role');
-
-/**
- * Update interface permissions based on app configuration.
- * Must be done independently from loading the app config.
- * @param {AppConfig} appConfig
- */
-async function updateInterfacePermissions(appConfig) {
- try {
- await updateInterfacePerms({
- appConfig,
- getRoleByName,
- updateAccessPermissions,
- });
- } catch (error) {
- logger.error('Error updating interface permissions:', error);
- }
-}
-
-module.exports = {
- updateInterfacePermissions,
-};
diff --git a/api/models/inviteUser.js b/api/models/inviteUser.js
deleted file mode 100644
index eda8394225..0000000000
--- a/api/models/inviteUser.js
+++ /dev/null
@@ -1,68 +0,0 @@
-const mongoose = require('mongoose');
-const { logger, hashToken, getRandomValues } = require('@librechat/data-schemas');
-const { createToken, findToken } = require('~/models');
-
-/**
- * @module inviteUser
- * @description This module provides functions to create and get user invites
- */
-
-/**
- * @function createInvite
- * @description This function creates a new user invite
- * @param {string} email - The email of the user to invite
- * @returns {Promise} A promise that resolves to the saved invite document
- * @throws {Error} If there is an error creating the invite
- */
-const createInvite = async (email) => {
- try {
- const token = await getRandomValues(32);
- const hash = await hashToken(token);
- const encodedToken = encodeURIComponent(token);
-
- const fakeUserId = new mongoose.Types.ObjectId();
-
- await createToken({
- userId: fakeUserId,
- email,
- token: hash,
- createdAt: Date.now(),
- expiresIn: 604800,
- });
-
- return encodedToken;
- } catch (error) {
- logger.error('[createInvite] Error creating invite', error);
- return { message: 'Error creating invite' };
- }
-};
-
-/**
- * @function getInvite
- * @description This function retrieves a user invite
- * @param {string} encodedToken - The token of the invite to retrieve
- * @param {string} email - The email of the user to validate
- * @returns {Promise} A promise that resolves to the retrieved invite document
- * @throws {Error} If there is an error retrieving the invite, if the invite does not exist, or if the email does not match
- */
-const getInvite = async (encodedToken, email) => {
- try {
- const token = decodeURIComponent(encodedToken);
- const hash = await hashToken(token);
- const invite = await findToken({ token: hash, email });
-
- if (!invite) {
- throw new Error('Invite not found or email does not match');
- }
-
- return invite;
- } catch (error) {
- logger.error('[getInvite] Error getting invite:', error);
- return { error: true, message: error.message };
- }
-};
-
-module.exports = {
- createInvite,
- getInvite,
-};
diff --git a/api/models/loadAddedAgent.js b/api/models/loadAddedAgent.js
deleted file mode 100644
index aa83375eae..0000000000
--- a/api/models/loadAddedAgent.js
+++ /dev/null
@@ -1,218 +0,0 @@
-const { logger } = require('@librechat/data-schemas');
-const { getCustomEndpointConfig } = require('@librechat/api');
-const {
- Tools,
- Constants,
- isAgentsEndpoint,
- isEphemeralAgentId,
- appendAgentIdSuffix,
- encodeEphemeralAgentId,
-} = require('librechat-data-provider');
-const { getMCPServerTools } = require('~/server/services/Config');
-
-const { mcp_all, mcp_delimiter } = Constants;
-
-/**
- * Constant for added conversation agent ID
- */
-const ADDED_AGENT_ID = 'added_agent';
-
-/**
- * Get an agent document based on the provided ID.
- * @param {Object} searchParameter - The search parameters to find the agent.
- * @param {string} searchParameter.id - The ID of the agent.
- * @returns {Promise}
- */
-let getAgent;
-
-/**
- * Set the getAgent function (dependency injection to avoid circular imports)
- * @param {Function} fn
- */
-const setGetAgent = (fn) => {
- getAgent = fn;
-};
-
-/**
- * Load an agent from an added conversation (TConversation).
- * Used for multi-convo parallel agent execution.
- *
- * @param {Object} params
- * @param {import('express').Request} params.req
- * @param {import('librechat-data-provider').TConversation} params.conversation - The added conversation
- * @param {import('librechat-data-provider').Agent} [params.primaryAgent] - The primary agent (used to duplicate tools when both are ephemeral)
- * @returns {Promise} The agent config as a plain object, or null if invalid.
- */
-const loadAddedAgent = async ({ req, conversation, primaryAgent }) => {
- if (!conversation) {
- return null;
- }
-
- // If there's an agent_id, load the existing agent
- if (conversation.agent_id && !isEphemeralAgentId(conversation.agent_id)) {
- if (!getAgent) {
- throw new Error('getAgent not initialized - call setGetAgent first');
- }
- const agent = await getAgent({
- id: conversation.agent_id,
- });
-
- if (!agent) {
- logger.warn(`[loadAddedAgent] Agent ${conversation.agent_id} not found`);
- return null;
- }
-
- agent.version = agent.versions ? agent.versions.length : 0;
- // Append suffix to distinguish from primary agent (matches ephemeral format)
- // This is needed when both agents have the same ID or for consistent parallel content attribution
- agent.id = appendAgentIdSuffix(agent.id, 1);
- return agent;
- }
-
- // Otherwise, create an ephemeral agent config from the conversation
- const { model, endpoint, promptPrefix, spec, ...rest } = conversation;
-
- if (!endpoint || !model) {
- logger.warn('[loadAddedAgent] Missing required endpoint or model for ephemeral agent');
- return null;
- }
-
- // If both primary and added agents are ephemeral, duplicate tools from primary agent
- const primaryIsEphemeral = primaryAgent && isEphemeralAgentId(primaryAgent.id);
- if (primaryIsEphemeral && Array.isArray(primaryAgent.tools)) {
- // Get endpoint config and model spec for display name fallbacks
- const appConfig = req.config;
- let endpointConfig = appConfig?.endpoints?.[endpoint];
- if (!isAgentsEndpoint(endpoint) && !endpointConfig) {
- try {
- endpointConfig = getCustomEndpointConfig({ endpoint, appConfig });
- } catch (err) {
- logger.error('[loadAddedAgent] Error getting custom endpoint config', err);
- }
- }
-
- // Look up model spec for label fallback
- const modelSpecs = appConfig?.modelSpecs?.list;
- const modelSpec = spec != null && spec !== '' ? modelSpecs?.find((s) => s.name === spec) : null;
-
- // For ephemeral agents, use modelLabel if provided, then model spec's label,
- // then modelDisplayLabel from endpoint config, otherwise empty string to show model name
- const sender = rest.modelLabel ?? modelSpec?.label ?? endpointConfig?.modelDisplayLabel ?? '';
-
- const ephemeralId = encodeEphemeralAgentId({ endpoint, model, sender, index: 1 });
-
- return {
- id: ephemeralId,
- instructions: promptPrefix || '',
- provider: endpoint,
- model_parameters: {},
- model,
- tools: [...primaryAgent.tools],
- };
- }
-
- // Extract ephemeral agent options from conversation if present
- const ephemeralAgent = rest.ephemeralAgent;
- const mcpServers = new Set(ephemeralAgent?.mcp);
- const userId = req.user?.id;
-
- // Check model spec for MCP servers
- const modelSpecs = req.config?.modelSpecs?.list;
- let modelSpec = null;
- if (spec != null && spec !== '') {
- modelSpec = modelSpecs?.find((s) => s.name === spec) || null;
- }
- if (modelSpec?.mcpServers) {
- for (const mcpServer of modelSpec.mcpServers) {
- mcpServers.add(mcpServer);
- }
- }
-
- /** @type {string[]} */
- const tools = [];
- if (ephemeralAgent?.execute_code === true || modelSpec?.executeCode === true) {
- tools.push(Tools.execute_code);
- }
- if (ephemeralAgent?.file_search === true || modelSpec?.fileSearch === true) {
- tools.push(Tools.file_search);
- }
- if (ephemeralAgent?.web_search === true || modelSpec?.webSearch === true) {
- tools.push(Tools.web_search);
- }
-
- const addedServers = new Set();
- if (mcpServers.size > 0) {
- for (const mcpServer of mcpServers) {
- if (addedServers.has(mcpServer)) {
- continue;
- }
- const serverTools = await getMCPServerTools(userId, mcpServer);
- if (!serverTools) {
- tools.push(`${mcp_all}${mcp_delimiter}${mcpServer}`);
- addedServers.add(mcpServer);
- continue;
- }
- tools.push(...Object.keys(serverTools));
- addedServers.add(mcpServer);
- }
- }
-
- // Build model_parameters from conversation fields
- const model_parameters = {};
- const paramKeys = [
- 'temperature',
- 'top_p',
- 'topP',
- 'topK',
- 'presence_penalty',
- 'frequency_penalty',
- 'maxOutputTokens',
- 'maxTokens',
- 'max_tokens',
- ];
-
- for (const key of paramKeys) {
- if (rest[key] != null) {
- model_parameters[key] = rest[key];
- }
- }
-
- // Get endpoint config for modelDisplayLabel fallback
- const appConfig = req.config;
- let endpointConfig = appConfig?.endpoints?.[endpoint];
- if (!isAgentsEndpoint(endpoint) && !endpointConfig) {
- try {
- endpointConfig = getCustomEndpointConfig({ endpoint, appConfig });
- } catch (err) {
- logger.error('[loadAddedAgent] Error getting custom endpoint config', err);
- }
- }
-
- // For ephemeral agents, use modelLabel if provided, then model spec's label,
- // then modelDisplayLabel from endpoint config, otherwise empty string to show model name
- const sender = rest.modelLabel ?? modelSpec?.label ?? endpointConfig?.modelDisplayLabel ?? '';
-
- /** Encoded ephemeral agent ID with endpoint, model, sender, and index=1 to distinguish from primary */
- const ephemeralId = encodeEphemeralAgentId({ endpoint, model, sender, index: 1 });
-
- const result = {
- id: ephemeralId,
- instructions: promptPrefix || '',
- provider: endpoint,
- model_parameters,
- model,
- tools,
- };
-
- if (ephemeralAgent?.artifacts != null && ephemeralAgent.artifacts) {
- result.artifacts = ephemeralAgent.artifacts;
- }
-
- return result;
-};
-
-module.exports = {
- ADDED_AGENT_ID,
- loadAddedAgent,
- setGetAgent,
-};
diff --git a/api/models/spendTokens.js b/api/models/spendTokens.js
deleted file mode 100644
index afe05969d8..0000000000
--- a/api/models/spendTokens.js
+++ /dev/null
@@ -1,140 +0,0 @@
-const { logger } = require('@librechat/data-schemas');
-const { createTransaction, createStructuredTransaction } = require('./Transaction');
-/**
- * Creates up to two transactions to record the spending of tokens.
- *
- * @function
- * @async
- * @param {txData} txData - Transaction data.
- * @param {Object} tokenUsage - The number of tokens used.
- * @param {Number} tokenUsage.promptTokens - The number of prompt tokens used.
- * @param {Number} tokenUsage.completionTokens - The number of completion tokens used.
- * @returns {Promise} - Returns nothing.
- * @throws {Error} - Throws an error if there's an issue creating the transactions.
- */
-const spendTokens = async (txData, tokenUsage) => {
- const { promptTokens, completionTokens } = tokenUsage;
- logger.debug(
- `[spendTokens] conversationId: ${txData.conversationId}${
- txData?.context ? ` | Context: ${txData?.context}` : ''
- } | Token usage: `,
- {
- promptTokens,
- completionTokens,
- },
- );
- let prompt, completion;
- const normalizedPromptTokens = Math.max(promptTokens ?? 0, 0);
- try {
- if (promptTokens !== undefined) {
- prompt = await createTransaction({
- ...txData,
- tokenType: 'prompt',
- rawAmount: promptTokens === 0 ? 0 : -normalizedPromptTokens,
- inputTokenCount: normalizedPromptTokens,
- });
- }
-
- if (completionTokens !== undefined) {
- completion = await createTransaction({
- ...txData,
- tokenType: 'completion',
- rawAmount: completionTokens === 0 ? 0 : -Math.max(completionTokens, 0),
- inputTokenCount: normalizedPromptTokens,
- });
- }
-
- if (prompt || completion) {
- logger.debug('[spendTokens] Transaction data record against balance:', {
- user: txData.user,
- prompt: prompt?.prompt,
- promptRate: prompt?.rate,
- completion: completion?.completion,
- completionRate: completion?.rate,
- balance: completion?.balance ?? prompt?.balance,
- });
- } else {
- logger.debug('[spendTokens] No transactions incurred against balance');
- }
- } catch (err) {
- logger.error('[spendTokens]', err);
- }
-};
-
-/**
- * Creates transactions to record the spending of structured tokens.
- *
- * @function
- * @async
- * @param {txData} txData - Transaction data.
- * @param {Object} tokenUsage - The number of tokens used.
- * @param {Object} tokenUsage.promptTokens - The number of prompt tokens used.
- * @param {Number} tokenUsage.promptTokens.input - The number of input tokens.
- * @param {Number} tokenUsage.promptTokens.write - The number of write tokens.
- * @param {Number} tokenUsage.promptTokens.read - The number of read tokens.
- * @param {Number} tokenUsage.completionTokens - The number of completion tokens used.
- * @returns {Promise} - Returns nothing.
- * @throws {Error} - Throws an error if there's an issue creating the transactions.
- */
-const spendStructuredTokens = async (txData, tokenUsage) => {
- const { promptTokens, completionTokens } = tokenUsage;
- logger.debug(
- `[spendStructuredTokens] conversationId: ${txData.conversationId}${
- txData?.context ? ` | Context: ${txData?.context}` : ''
- } | Token usage: `,
- {
- promptTokens,
- completionTokens,
- },
- );
- let prompt, completion;
- try {
- if (promptTokens) {
- const input = Math.max(promptTokens.input ?? 0, 0);
- const write = Math.max(promptTokens.write ?? 0, 0);
- const read = Math.max(promptTokens.read ?? 0, 0);
- const totalInputTokens = input + write + read;
- prompt = await createStructuredTransaction({
- ...txData,
- tokenType: 'prompt',
- inputTokens: -input,
- writeTokens: -write,
- readTokens: -read,
- inputTokenCount: totalInputTokens,
- });
- }
-
- if (completionTokens) {
- const totalInputTokens = promptTokens
- ? Math.max(promptTokens.input ?? 0, 0) +
- Math.max(promptTokens.write ?? 0, 0) +
- Math.max(promptTokens.read ?? 0, 0)
- : undefined;
- completion = await createTransaction({
- ...txData,
- tokenType: 'completion',
- rawAmount: -Math.max(completionTokens, 0),
- inputTokenCount: totalInputTokens,
- });
- }
-
- if (prompt || completion) {
- logger.debug('[spendStructuredTokens] Transaction data record against balance:', {
- user: txData.user,
- prompt: prompt?.prompt,
- promptRate: prompt?.rate,
- completion: completion?.completion,
- completionRate: completion?.rate,
- balance: completion?.balance ?? prompt?.balance,
- });
- } else {
- logger.debug('[spendStructuredTokens] No transactions incurred against balance');
- }
- } catch (err) {
- logger.error('[spendStructuredTokens]', err);
- }
-
- return { prompt, completion };
-};
-
-module.exports = { spendTokens, spendStructuredTokens };
diff --git a/api/models/userMethods.js b/api/models/userMethods.js
deleted file mode 100644
index b57b24e641..0000000000
--- a/api/models/userMethods.js
+++ /dev/null
@@ -1,31 +0,0 @@
-const bcrypt = require('bcryptjs');
-
-/**
- * Compares the provided password with the user's password.
- *
- * @param {IUser} user - The user to compare the password for.
- * @param {string} candidatePassword - The password to test against the user's password.
- * @returns {Promise} A promise that resolves to a boolean indicating if the password matches.
- */
-const comparePassword = async (user, candidatePassword) => {
- if (!user) {
- throw new Error('No user provided');
- }
-
- if (!user.password) {
- throw new Error('No password, likely an email first registered via Social/OIDC login');
- }
-
- return new Promise((resolve, reject) => {
- bcrypt.compare(candidatePassword, user.password, (err, isMatch) => {
- if (err) {
- reject(err);
- }
- resolve(isMatch);
- });
- });
-};
-
-module.exports = {
- comparePassword,
-};
diff --git a/api/package.json b/api/package.json
index 05755c6020..2255679dae 100644
--- a/api/package.json
+++ b/api/package.json
@@ -1,6 +1,6 @@
{
"name": "@librechat/backend",
- "version": "v0.8.2",
+ "version": "v0.8.4-rc1",
"description": "",
"scripts": {
"start": "echo 'please run this from the root directory'",
@@ -44,13 +44,14 @@
"@google/genai": "^1.19.0",
"@keyv/redis": "^4.3.3",
"@langchain/core": "^0.3.80",
- "@librechat/agents": "^3.1.41",
+ "@librechat/agents": "^3.1.57",
"@librechat/api": "*",
"@librechat/data-schemas": "*",
"@microsoft/microsoft-graph-client": "^3.0.7",
- "@modelcontextprotocol/sdk": "^1.26.0",
+ "@modelcontextprotocol/sdk": "^1.27.1",
"@node-saml/passport-saml": "^5.1.0",
"@smithy/node-http-handler": "^4.4.5",
+ "ai-tokenizer": "^1.0.6",
"axios": "^1.13.5",
"bcryptjs": "^2.4.3",
"compression": "^1.8.1",
@@ -63,10 +64,10 @@
"eventsource": "^3.0.2",
"express": "^5.2.1",
"express-mongo-sanitize": "^2.2.0",
- "express-rate-limit": "^8.2.1",
+ "express-rate-limit": "^8.3.0",
"express-session": "^1.18.2",
"express-static-gzip": "^2.2.0",
- "file-type": "^18.7.0",
+ "file-type": "^21.3.2",
"firebase": "^11.0.2",
"form-data": "^4.0.4",
"handlebars": "^4.7.7",
@@ -80,13 +81,14 @@
"klona": "^2.0.6",
"librechat-data-provider": "*",
"lodash": "^4.17.23",
+ "mammoth": "^1.11.0",
"mathjs": "^15.1.0",
"meilisearch": "^0.38.0",
"memorystore": "^1.6.7",
"mime": "^3.0.0",
"module-alias": "^2.2.3",
"mongoose": "^8.12.1",
- "multer": "^2.0.2",
+ "multer": "^2.1.1",
"nanoid": "^3.3.7",
"node-fetch": "^2.7.0",
"nodemailer": "^7.0.11",
@@ -102,14 +104,15 @@
"passport-jwt": "^4.0.1",
"passport-ldapauth": "^3.0.1",
"passport-local": "^1.0.0",
+ "pdfjs-dist": "^5.4.624",
"rate-limit-redis": "^4.2.0",
"sharp": "^0.33.5",
- "tiktoken": "^1.0.15",
"traverse": "^0.6.7",
"ua-parser-js": "^1.0.36",
- "undici": "^7.18.2",
+ "undici": "^7.24.1",
"winston": "^3.11.0",
"winston-daily-rotate-file": "^5.0.0",
+ "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
"zod": "^3.22.4"
},
"devDependencies": {
diff --git a/api/server/cleanup.js b/api/server/cleanup.js
index c482a2267e..364c02cd8a 100644
--- a/api/server/cleanup.js
+++ b/api/server/cleanup.js
@@ -35,7 +35,6 @@ const graphPropsToClean = [
'tools',
'signal',
'config',
- 'agentContexts',
'messages',
'contentData',
'stepKeyIds',
@@ -277,7 +276,16 @@ function disposeClient(client) {
if (client.run) {
if (client.run.Graph) {
- client.run.Graph.resetValues();
+ if (typeof client.run.Graph.clearHeavyState === 'function') {
+ client.run.Graph.clearHeavyState();
+ } else {
+ client.run.Graph.resetValues();
+ }
+
+ if (client.run.Graph.agentContexts) {
+ client.run.Graph.agentContexts.clear();
+ client.run.Graph.agentContexts = null;
+ }
graphPropsToClean.forEach((prop) => {
if (client.run.Graph[prop] !== undefined) {
diff --git a/api/server/controllers/AuthController.js b/api/server/controllers/AuthController.js
index 22e53dcfc9..eb44feffa4 100644
--- a/api/server/controllers/AuthController.js
+++ b/api/server/controllers/AuthController.js
@@ -18,8 +18,7 @@ const {
findUser,
} = require('~/models');
const { getGraphApiToken } = require('~/server/services/GraphTokenService');
-const { getOAuthReconnectionManager } = require('~/config');
-const { getOpenIdConfig } = require('~/strategies');
+const { getOpenIdConfig, getOpenIdEmail } = require('~/strategies');
const registrationController = async (req, res) => {
try {
@@ -79,11 +78,16 @@ const refreshController = async (req, res) => {
try {
const openIdConfig = getOpenIdConfig();
- const tokenset = await openIdClient.refreshTokenGrant(openIdConfig, refreshToken);
+ const refreshParams = process.env.OPENID_SCOPE ? { scope: process.env.OPENID_SCOPE } : {};
+ const tokenset = await openIdClient.refreshTokenGrant(
+ openIdConfig,
+ refreshToken,
+ refreshParams,
+ );
const claims = tokenset.claims();
const { user, error, migration } = await findOpenIDUser({
findUser,
- email: claims.email,
+ email: getOpenIdEmail(claims),
openidId: claims.sub,
idOnTheSource: claims.oid,
strategyName: 'refreshController',
@@ -115,14 +119,8 @@ const refreshController = async (req, res) => {
const token = setOpenIDAuthTokens(tokenset, req, res, user._id.toString(), refreshToken);
- user.federatedTokens = {
- access_token: tokenset.access_token,
- id_token: tokenset.id_token,
- refresh_token: refreshToken,
- expires_at: claims.exp,
- };
-
- return res.status(200).send({ token, user });
+ const { password: _pw, __v: _v, totpSecret: _ts, backupCodes: _bc, ...safeUser } = user;
+ return res.status(200).send({ token, user: safeUser });
} catch (error) {
logger.error('[refreshController] OpenID token refresh error', error);
return res.status(403).send('Invalid OpenID refresh token');
@@ -161,17 +159,6 @@ const refreshController = async (req, res) => {
if (session && session.expiration > new Date()) {
const token = await setAuthTokens(userId, res, session);
- // trigger OAuth MCP server reconnection asynchronously (best effort)
- try {
- void getOAuthReconnectionManager()
- .reconnectServers(userId)
- .catch((err) => {
- logger.error('[refreshController] Error reconnecting OAuth MCP servers:', err);
- });
- } catch (err) {
- logger.warn(`[refreshController] Cannot attempt OAuth MCP servers reconnection:`, err);
- }
-
res.status(200).send({ token, user });
} else if (req?.query?.retry) {
// Retrying from a refresh token request that failed (401)
@@ -203,15 +190,6 @@ const graphTokenController = async (req, res) => {
});
}
- // Extract access token from Authorization header
- const authHeader = req.headers.authorization;
- if (!authHeader || !authHeader.startsWith('Bearer ')) {
- return res.status(401).json({
- message: 'Valid authorization token required',
- });
- }
-
- // Get scopes from query parameters
const scopes = req.query.scopes;
if (!scopes) {
return res.status(400).json({
@@ -219,7 +197,13 @@ const graphTokenController = async (req, res) => {
});
}
- const accessToken = authHeader.substring(7); // Remove 'Bearer ' prefix
+ const accessToken = req.user.federatedTokens?.access_token;
+ if (!accessToken) {
+ return res.status(401).json({
+ message: 'No federated access token available for token exchange',
+ });
+ }
+
const tokenResponse = await getGraphApiToken(req.user, accessToken, scopes);
res.json(tokenResponse);
diff --git a/api/server/controllers/AuthController.spec.js b/api/server/controllers/AuthController.spec.js
new file mode 100644
index 0000000000..964947def9
--- /dev/null
+++ b/api/server/controllers/AuthController.spec.js
@@ -0,0 +1,318 @@
+jest.mock('@librechat/data-schemas', () => ({
+ logger: { error: jest.fn(), debug: jest.fn(), warn: jest.fn(), info: jest.fn() },
+}));
+jest.mock('~/server/services/GraphTokenService', () => ({
+ getGraphApiToken: jest.fn(),
+}));
+jest.mock('~/server/services/AuthService', () => ({
+ requestPasswordReset: jest.fn(),
+ setOpenIDAuthTokens: jest.fn(),
+ resetPassword: jest.fn(),
+ setAuthTokens: jest.fn(),
+ registerUser: jest.fn(),
+}));
+jest.mock('~/strategies', () => ({ getOpenIdConfig: jest.fn(), getOpenIdEmail: jest.fn() }));
+jest.mock('openid-client', () => ({ refreshTokenGrant: jest.fn() }));
+jest.mock('~/models', () => ({
+ deleteAllUserSessions: jest.fn(),
+ getUserById: jest.fn(),
+ findSession: jest.fn(),
+ updateUser: jest.fn(),
+ findUser: jest.fn(),
+}));
+jest.mock('@librechat/api', () => ({
+ isEnabled: jest.fn(),
+ findOpenIDUser: jest.fn(),
+}));
+
+const openIdClient = require('openid-client');
+const { isEnabled, findOpenIDUser } = require('@librechat/api');
+const { graphTokenController, refreshController } = require('./AuthController');
+const { getGraphApiToken } = require('~/server/services/GraphTokenService');
+const { setOpenIDAuthTokens } = require('~/server/services/AuthService');
+const { getOpenIdConfig, getOpenIdEmail } = require('~/strategies');
+const { updateUser } = require('~/models');
+
+describe('graphTokenController', () => {
+ let req, res;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ isEnabled.mockReturnValue(true);
+
+ req = {
+ user: {
+ openidId: 'oid-123',
+ provider: 'openid',
+ federatedTokens: {
+ access_token: 'federated-access-token',
+ id_token: 'federated-id-token',
+ },
+ },
+ headers: { authorization: 'Bearer app-jwt-which-is-id-token' },
+ query: { scopes: 'https://graph.microsoft.com/.default' },
+ };
+
+ res = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn(),
+ };
+
+ getGraphApiToken.mockResolvedValue({
+ access_token: 'graph-access-token',
+ token_type: 'Bearer',
+ expires_in: 3600,
+ });
+ });
+
+ it('should pass federatedTokens.access_token as OBO assertion, not the auth header bearer token', async () => {
+ await graphTokenController(req, res);
+
+ expect(getGraphApiToken).toHaveBeenCalledWith(
+ req.user,
+ 'federated-access-token',
+ 'https://graph.microsoft.com/.default',
+ );
+ expect(getGraphApiToken).not.toHaveBeenCalledWith(
+ expect.anything(),
+ 'app-jwt-which-is-id-token',
+ expect.anything(),
+ );
+ });
+
+ it('should return the graph token response on success', async () => {
+ await graphTokenController(req, res);
+
+ expect(res.json).toHaveBeenCalledWith({
+ access_token: 'graph-access-token',
+ token_type: 'Bearer',
+ expires_in: 3600,
+ });
+ });
+
+ it('should return 403 when user is not authenticated via Entra ID', async () => {
+ req.user.provider = 'google';
+ req.user.openidId = undefined;
+
+ await graphTokenController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(403);
+ expect(getGraphApiToken).not.toHaveBeenCalled();
+ });
+
+ it('should return 403 when OPENID_REUSE_TOKENS is not enabled', async () => {
+ isEnabled.mockReturnValue(false);
+
+ await graphTokenController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(403);
+ expect(getGraphApiToken).not.toHaveBeenCalled();
+ });
+
+ it('should return 400 when scopes query param is missing', async () => {
+ req.query.scopes = undefined;
+
+ await graphTokenController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(400);
+ expect(getGraphApiToken).not.toHaveBeenCalled();
+ });
+
+ it('should return 401 when federatedTokens.access_token is missing', async () => {
+ req.user.federatedTokens = {};
+
+ await graphTokenController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(401);
+ expect(getGraphApiToken).not.toHaveBeenCalled();
+ });
+
+ it('should return 401 when federatedTokens is absent entirely', async () => {
+ req.user.federatedTokens = undefined;
+
+ await graphTokenController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(401);
+ expect(getGraphApiToken).not.toHaveBeenCalled();
+ });
+
+ it('should return 500 when getGraphApiToken throws', async () => {
+ getGraphApiToken.mockRejectedValue(new Error('OBO exchange failed'));
+
+ await graphTokenController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(500);
+ expect(res.json).toHaveBeenCalledWith({
+ message: 'Failed to obtain Microsoft Graph token',
+ });
+ });
+});
+
+describe('refreshController – OpenID path', () => {
+ const mockTokenset = {
+ claims: jest.fn(),
+ access_token: 'new-access',
+ id_token: 'new-id',
+ refresh_token: 'new-refresh',
+ };
+
+ const baseClaims = {
+ sub: 'oidc-sub-123',
+ oid: 'oid-456',
+ email: 'user@example.com',
+ exp: 9999999999,
+ };
+
+ const defaultUser = {
+ _id: 'user-db-id',
+ email: baseClaims.email,
+ openidId: baseClaims.sub,
+ password: '$2b$10$hashedpassword',
+ __v: 0,
+ totpSecret: 'encrypted-totp-secret',
+ backupCodes: ['hashed-code-1', 'hashed-code-2'],
+ };
+
+ let req, res;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+
+ isEnabled.mockReturnValue(true);
+ getOpenIdConfig.mockReturnValue({ some: 'config' });
+ openIdClient.refreshTokenGrant.mockResolvedValue(mockTokenset);
+ mockTokenset.claims.mockReturnValue(baseClaims);
+ getOpenIdEmail.mockReturnValue(baseClaims.email);
+ setOpenIDAuthTokens.mockReturnValue('new-app-token');
+ findOpenIDUser.mockResolvedValue({ user: { ...defaultUser }, error: null, migration: false });
+ updateUser.mockResolvedValue({});
+
+ req = {
+ headers: { cookie: 'token_provider=openid; refreshToken=stored-refresh' },
+ session: {},
+ };
+
+ res = {
+ status: jest.fn().mockReturnThis(),
+ send: jest.fn().mockReturnThis(),
+ redirect: jest.fn(),
+ };
+ });
+
+ it('should call getOpenIdEmail with token claims and use result for findOpenIDUser', async () => {
+ await refreshController(req, res);
+
+ expect(getOpenIdEmail).toHaveBeenCalledWith(baseClaims);
+ expect(findOpenIDUser).toHaveBeenCalledWith(
+ expect.objectContaining({ email: baseClaims.email }),
+ );
+ expect(res.status).toHaveBeenCalledWith(200);
+ });
+
+ it('should use OPENID_EMAIL_CLAIM-resolved value when claim is present in token', async () => {
+ const claimsWithUpn = { ...baseClaims, upn: 'user@corp.example.com' };
+ mockTokenset.claims.mockReturnValue(claimsWithUpn);
+ getOpenIdEmail.mockReturnValue('user@corp.example.com');
+
+ const user = {
+ _id: 'user-db-id',
+ email: 'user@corp.example.com',
+ openidId: baseClaims.sub,
+ };
+ findOpenIDUser.mockResolvedValue({ user, error: null, migration: false });
+
+ await refreshController(req, res);
+
+ expect(getOpenIdEmail).toHaveBeenCalledWith(claimsWithUpn);
+ expect(findOpenIDUser).toHaveBeenCalledWith(
+ expect.objectContaining({ email: 'user@corp.example.com' }),
+ );
+ expect(res.status).toHaveBeenCalledWith(200);
+ });
+
+ it('should fall back to claims.email when configured claim is absent from token claims', async () => {
+ getOpenIdEmail.mockReturnValue(baseClaims.email);
+
+ await refreshController(req, res);
+
+ expect(findOpenIDUser).toHaveBeenCalledWith(
+ expect.objectContaining({ email: baseClaims.email }),
+ );
+ });
+
+ it('should not expose sensitive fields or federatedTokens in refresh response', async () => {
+ await refreshController(req, res);
+
+ const sentPayload = res.send.mock.calls[0][0];
+ expect(sentPayload).toEqual({
+ token: 'new-app-token',
+ user: expect.objectContaining({
+ _id: 'user-db-id',
+ email: baseClaims.email,
+ openidId: baseClaims.sub,
+ }),
+ });
+ expect(sentPayload.user).not.toHaveProperty('federatedTokens');
+ expect(sentPayload.user).not.toHaveProperty('password');
+ expect(sentPayload.user).not.toHaveProperty('totpSecret');
+ expect(sentPayload.user).not.toHaveProperty('backupCodes');
+ expect(sentPayload.user).not.toHaveProperty('__v');
+ });
+
+ it('should update openidId when migration is triggered on refresh', async () => {
+ const user = { _id: 'user-db-id', email: baseClaims.email, openidId: null };
+ findOpenIDUser.mockResolvedValue({ user, error: null, migration: true });
+
+ await refreshController(req, res);
+
+ expect(updateUser).toHaveBeenCalledWith(
+ 'user-db-id',
+ expect.objectContaining({ provider: 'openid', openidId: baseClaims.sub }),
+ );
+ expect(res.status).toHaveBeenCalledWith(200);
+ });
+
+ it('should return 401 and redirect to /login when findOpenIDUser returns no user', async () => {
+ findOpenIDUser.mockResolvedValue({ user: null, error: null, migration: false });
+
+ await refreshController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(401);
+ expect(res.redirect).toHaveBeenCalledWith('/login');
+ });
+
+ it('should return 401 and redirect when findOpenIDUser returns an error', async () => {
+ findOpenIDUser.mockResolvedValue({ user: null, error: 'AUTH_FAILED', migration: false });
+
+ await refreshController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(401);
+ expect(res.redirect).toHaveBeenCalledWith('/login');
+ });
+
+ it('should skip OpenID path when token_provider is not openid', async () => {
+ req.headers.cookie = 'token_provider=local; refreshToken=some-token';
+
+ await refreshController(req, res);
+
+ expect(openIdClient.refreshTokenGrant).not.toHaveBeenCalled();
+ });
+
+ it('should skip OpenID path when OPENID_REUSE_TOKENS is disabled', async () => {
+ isEnabled.mockReturnValue(false);
+
+ await refreshController(req, res);
+
+ expect(openIdClient.refreshTokenGrant).not.toHaveBeenCalled();
+ });
+
+ it('should return 200 with token not provided when refresh token is absent', async () => {
+ req.headers.cookie = 'token_provider=openid';
+ req.session = {};
+
+ await refreshController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(200);
+ expect(res.send).toHaveBeenCalledWith('Refresh token not provided');
+ });
+});
diff --git a/api/server/controllers/Balance.js b/api/server/controllers/Balance.js
index c892a73b0c..fd9b32e74c 100644
--- a/api/server/controllers/Balance.js
+++ b/api/server/controllers/Balance.js
@@ -1,24 +1,22 @@
-const { Balance } = require('~/db/models');
+const { findBalanceByUser } = require('~/models');
async function balanceController(req, res) {
- const balanceData = await Balance.findOne(
- { user: req.user.id },
- '-_id tokenCredits autoRefillEnabled refillIntervalValue refillIntervalUnit lastRefill refillAmount',
- ).lean();
+ const balanceData = await findBalanceByUser(req.user.id);
if (!balanceData) {
return res.status(404).json({ error: 'Balance not found' });
}
- // If auto-refill is not enabled, remove auto-refill related fields from the response
- if (!balanceData.autoRefillEnabled) {
- delete balanceData.refillIntervalValue;
- delete balanceData.refillIntervalUnit;
- delete balanceData.lastRefill;
- delete balanceData.refillAmount;
+ const { _id: _, ...result } = balanceData;
+
+ if (!result.autoRefillEnabled) {
+ delete result.refillIntervalValue;
+ delete result.refillIntervalUnit;
+ delete result.lastRefill;
+ delete result.refillAmount;
}
- res.status(200).json(balanceData);
+ res.status(200).json(result);
}
module.exports = balanceController;
diff --git a/api/server/controllers/PermissionsController.js b/api/server/controllers/PermissionsController.js
index 51993d083c..1b409ac931 100644
--- a/api/server/controllers/PermissionsController.js
+++ b/api/server/controllers/PermissionsController.js
@@ -9,22 +9,24 @@ const { enrichRemoteAgentPrincipals, backfillRemoteAgentPermissions } = require(
const {
bulkUpdateResourcePermissions,
ensureGroupPrincipalExists,
+ getResourcePermissionsMap,
+ findAccessibleResources,
getEffectivePermissions,
ensurePrincipalExists,
getAvailableRoles,
- findAccessibleResources,
- getResourcePermissionsMap,
} = require('~/server/services/PermissionService');
const {
searchPrincipals: searchLocalPrincipals,
sortPrincipalsByRelevance,
calculateRelevanceScore,
+ findRoleByIdentifier,
+ aggregateAclEntries,
+ bulkWriteAclEntries,
} = require('~/models');
const {
entraIdPrincipalFeatureEnabled,
searchEntraIdPrincipals,
} = require('~/server/services/GraphApiService');
-const { AclEntry, AccessRole } = require('~/db/models');
/**
* Generic controller for resource permission endpoints
@@ -185,8 +187,7 @@ const getResourcePermissions = async (req, res) => {
const { resourceType, resourceId } = req.params;
validateResourceType(resourceType);
- // Use aggregation pipeline for efficient single-query data retrieval
- const results = await AclEntry.aggregate([
+ const results = await aggregateAclEntries([
// Match ACL entries for this resource
{
$match: {
@@ -282,7 +283,12 @@ const getResourcePermissions = async (req, res) => {
}
if (resourceType === ResourceType.REMOTE_AGENT) {
- const enricherDeps = { AclEntry, AccessRole, logger };
+ const enricherDeps = {
+ aggregateAclEntries,
+ bulkWriteAclEntries,
+ findRoleByIdentifier,
+ logger,
+ };
const enrichResult = await enrichRemoteAgentPrincipals(enricherDeps, resourceId, principals);
principals = enrichResult.principals;
backfillRemoteAgentPermissions(enricherDeps, resourceId, enrichResult.entriesToBackfill);
diff --git a/api/server/controllers/TwoFactorController.js b/api/server/controllers/TwoFactorController.js
index fde5965261..18a0ee3f5a 100644
--- a/api/server/controllers/TwoFactorController.js
+++ b/api/server/controllers/TwoFactorController.js
@@ -1,5 +1,6 @@
const { encryptV3, logger } = require('@librechat/data-schemas');
const {
+ verifyOTPOrBackupCode,
generateBackupCodes,
generateTOTPSecret,
verifyBackupCode,
@@ -13,24 +14,42 @@ const safeAppTitle = (process.env.APP_TITLE || 'LibreChat').replace(/\s+/g, '');
/**
* Enable 2FA for the user by generating a new TOTP secret and backup codes.
* The secret is encrypted and stored, and 2FA is marked as disabled until confirmed.
+ * If 2FA is already enabled, requires OTP or backup code verification to re-enroll.
*/
const enable2FA = async (req, res) => {
try {
const userId = req.user.id;
+ const existingUser = await getUserById(
+ userId,
+ '+totpSecret +backupCodes _id twoFactorEnabled email',
+ );
+
+ if (existingUser && existingUser.twoFactorEnabled) {
+ const { token, backupCode } = req.body;
+ const result = await verifyOTPOrBackupCode({
+ user: existingUser,
+ token,
+ backupCode,
+ persistBackupUse: false,
+ });
+
+ if (!result.verified) {
+ const msg = result.message ?? 'TOTP token or backup code is required to re-enroll 2FA';
+ return res.status(result.status ?? 400).json({ message: msg });
+ }
+ }
+
const secret = generateTOTPSecret();
const { plainCodes, codeObjects } = await generateBackupCodes();
-
- // Encrypt the secret with v3 encryption before saving.
const encryptedSecret = encryptV3(secret);
- // Update the user record: store the secret & backup codes and set twoFactorEnabled to false.
const user = await updateUser(userId, {
- totpSecret: encryptedSecret,
- backupCodes: codeObjects,
- twoFactorEnabled: false,
+ pendingTotpSecret: encryptedSecret,
+ pendingBackupCodes: codeObjects,
});
- const otpauthUrl = `otpauth://totp/${safeAppTitle}:${user.email}?secret=${secret}&issuer=${safeAppTitle}`;
+ const email = user.email || (existingUser && existingUser.email) || '';
+ const otpauthUrl = `otpauth://totp/${safeAppTitle}:${email}?secret=${secret}&issuer=${safeAppTitle}`;
return res.status(200).json({ otpauthUrl, backupCodes: plainCodes });
} catch (err) {
@@ -46,13 +65,14 @@ const verify2FA = async (req, res) => {
try {
const userId = req.user.id;
const { token, backupCode } = req.body;
- const user = await getUserById(userId, '_id totpSecret backupCodes');
+ const user = await getUserById(userId, '+totpSecret +pendingTotpSecret +backupCodes _id');
+ const secretSource = user?.pendingTotpSecret ?? user?.totpSecret;
- if (!user || !user.totpSecret) {
+ if (!user || !secretSource) {
return res.status(400).json({ message: '2FA not initiated' });
}
- const secret = await getTOTPSecret(user.totpSecret);
+ const secret = await getTOTPSecret(secretSource);
let isVerified = false;
if (token) {
@@ -78,15 +98,28 @@ const confirm2FA = async (req, res) => {
try {
const userId = req.user.id;
const { token } = req.body;
- const user = await getUserById(userId, '_id totpSecret');
+ const user = await getUserById(
+ userId,
+ '+totpSecret +pendingTotpSecret +pendingBackupCodes _id',
+ );
+ const secretSource = user?.pendingTotpSecret ?? user?.totpSecret;
- if (!user || !user.totpSecret) {
+ if (!user || !secretSource) {
return res.status(400).json({ message: '2FA not initiated' });
}
- const secret = await getTOTPSecret(user.totpSecret);
+ const secret = await getTOTPSecret(secretSource);
if (await verifyTOTP(secret, token)) {
- await updateUser(userId, { twoFactorEnabled: true });
+ const update = {
+ totpSecret: user.pendingTotpSecret ?? user.totpSecret,
+ twoFactorEnabled: true,
+ pendingTotpSecret: null,
+ pendingBackupCodes: [],
+ };
+ if (user.pendingBackupCodes?.length) {
+ update.backupCodes = user.pendingBackupCodes;
+ }
+ await updateUser(userId, update);
return res.status(200).json();
}
return res.status(400).json({ message: 'Invalid token.' });
@@ -104,31 +137,27 @@ const disable2FA = async (req, res) => {
try {
const userId = req.user.id;
const { token, backupCode } = req.body;
- const user = await getUserById(userId, '_id totpSecret backupCodes');
+ const user = await getUserById(userId, '+totpSecret +backupCodes _id twoFactorEnabled');
if (!user || !user.totpSecret) {
return res.status(400).json({ message: '2FA is not setup for this user' });
}
if (user.twoFactorEnabled) {
- const secret = await getTOTPSecret(user.totpSecret);
- let isVerified = false;
+ const result = await verifyOTPOrBackupCode({ user, token, backupCode });
- if (token) {
- isVerified = await verifyTOTP(secret, token);
- } else if (backupCode) {
- isVerified = await verifyBackupCode({ user, backupCode });
- } else {
- return res
- .status(400)
- .json({ message: 'Either token or backup code is required to disable 2FA' });
- }
-
- if (!isVerified) {
- return res.status(401).json({ message: 'Invalid token or backup code' });
+ if (!result.verified) {
+ const msg = result.message ?? 'Either token or backup code is required to disable 2FA';
+ return res.status(result.status ?? 400).json({ message: msg });
}
}
- await updateUser(userId, { totpSecret: null, backupCodes: [], twoFactorEnabled: false });
+ await updateUser(userId, {
+ totpSecret: null,
+ backupCodes: [],
+ twoFactorEnabled: false,
+ pendingTotpSecret: null,
+ pendingBackupCodes: [],
+ });
return res.status(200).json();
} catch (err) {
logger.error('[disable2FA]', err);
@@ -138,10 +167,28 @@ const disable2FA = async (req, res) => {
/**
* Regenerate backup codes for the user.
+ * Requires OTP or backup code verification if 2FA is already enabled.
*/
const regenerateBackupCodes = async (req, res) => {
try {
const userId = req.user.id;
+ const user = await getUserById(userId, '+totpSecret +backupCodes _id twoFactorEnabled');
+
+ if (!user) {
+ return res.status(404).json({ message: 'User not found' });
+ }
+
+ if (user.twoFactorEnabled) {
+ const { token, backupCode } = req.body;
+ const result = await verifyOTPOrBackupCode({ user, token, backupCode });
+
+ if (!result.verified) {
+ const msg =
+ result.message ?? 'TOTP token or backup code is required to regenerate backup codes';
+ return res.status(result.status ?? 400).json({ message: msg });
+ }
+ }
+
const { plainCodes, codeObjects } = await generateBackupCodes();
await updateUser(userId, { backupCodes: codeObjects });
return res.status(200).json({
diff --git a/api/server/controllers/UserController.js b/api/server/controllers/UserController.js
index 7a9dd8125e..34be6192ed 100644
--- a/api/server/controllers/UserController.js
+++ b/api/server/controllers/UserController.js
@@ -1,49 +1,22 @@
const { logger, webSearchKeys } = require('@librechat/data-schemas');
const { Tools, CacheKeys, Constants, FileSources } = require('librechat-data-provider');
const {
+ getNewS3URL,
+ needsRefresh,
MCPOAuthHandler,
MCPTokenStorage,
normalizeHttpError,
extractWebSearchEnvVars,
} = require('@librechat/api');
-const {
- deleteAllUserSessions,
- deleteAllSharedLinks,
- updateUserPlugins,
- deleteUserById,
- deleteMessages,
- deletePresets,
- deleteUserKey,
- deleteConvos,
- deleteFiles,
- updateUser,
- findToken,
- getFiles,
-} = require('~/models');
-const {
- ConversationTag,
- AgentApiKey,
- Transaction,
- MemoryEntry,
- Assistant,
- AclEntry,
- Balance,
- Action,
- Group,
- Token,
- User,
-} = require('~/db/models');
const { updateUserPluginAuth, deleteUserPluginAuth } = require('~/server/services/PluginService');
+const { verifyOTPOrBackupCode } = require('~/server/services/twoFactorService');
const { verifyEmail, resendVerificationEmail } = require('~/server/services/AuthService');
const { getMCPManager, getFlowStateManager, getMCPServersRegistry } = require('~/config');
const { invalidateCachedTools } = require('~/server/services/Config/getCachedTools');
-const { needsRefresh, getNewS3URL } = require('~/server/services/Files/S3/crud');
const { processDeleteRequest } = require('~/server/services/Files/process');
const { getAppConfig } = require('~/server/services/Config');
-const { deleteToolCalls } = require('~/models/ToolCall');
-const { deleteUserPrompts } = require('~/models/Prompt');
-const { deleteUserAgents } = require('~/models/Agent');
const { getLogStores } = require('~/cache');
+const db = require('~/models');
const getUserController = async (req, res) => {
const appConfig = await getAppConfig({ role: req.user?.role });
@@ -64,7 +37,7 @@ const getUserController = async (req, res) => {
const originalAvatar = userData.avatar;
try {
userData.avatar = await getNewS3URL(userData.avatar);
- await updateUser(userData.id, { avatar: userData.avatar });
+ await db.updateUser(userData.id, { avatar: userData.avatar });
} catch (error) {
userData.avatar = originalAvatar;
logger.error('Error getting new S3 URL for avatar:', error);
@@ -75,7 +48,7 @@ const getUserController = async (req, res) => {
const getTermsStatusController = async (req, res) => {
try {
- const user = await User.findById(req.user.id);
+ const user = await db.getUserById(req.user.id, 'termsAccepted');
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
@@ -88,7 +61,7 @@ const getTermsStatusController = async (req, res) => {
const acceptTermsController = async (req, res) => {
try {
- const user = await User.findByIdAndUpdate(req.user.id, { termsAccepted: true }, { new: true });
+ const user = await db.updateUser(req.user.id, { termsAccepted: true });
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
@@ -101,7 +74,7 @@ const acceptTermsController = async (req, res) => {
const deleteUserFiles = async (req) => {
try {
- const userFiles = await getFiles({ user: req.user.id });
+ const userFiles = await db.getFiles({ user: req.user.id });
await processDeleteRequest({
req,
files: userFiles,
@@ -117,7 +90,7 @@ const updateUserPluginsController = async (req, res) => {
const { pluginKey, action, auth, isEntityTool } = req.body;
try {
if (!isEntityTool) {
- await updateUserPlugins(user._id, user.plugins, pluginKey, action);
+ await db.updateUserPlugins(user._id, user.plugins, pluginKey, action);
}
if (auth == null) {
@@ -241,37 +214,49 @@ const deleteUserController = async (req, res) => {
const { user } = req;
try {
- await deleteMessages({ user: user.id }); // delete user messages
- await deleteAllUserSessions({ userId: user.id }); // delete user sessions
- await Transaction.deleteMany({ user: user.id }); // delete user transactions
- await deleteUserKey({ userId: user.id, all: true }); // delete user keys
- await Balance.deleteMany({ user: user._id }); // delete user balances
- await deletePresets(user.id); // delete user presets
+ const existingUser = await db.getUserById(
+ user.id,
+ '+totpSecret +backupCodes _id twoFactorEnabled',
+ );
+ if (existingUser && existingUser.twoFactorEnabled) {
+ const { token, backupCode } = req.body;
+ const result = await verifyOTPOrBackupCode({ user: existingUser, token, backupCode });
+
+ if (!result.verified) {
+ const msg =
+ result.message ??
+ 'TOTP token or backup code is required to delete account with 2FA enabled';
+ return res.status(result.status ?? 400).json({ message: msg });
+ }
+ }
+
+ await db.deleteMessages({ user: user.id });
+ await db.deleteAllUserSessions({ userId: user.id });
+ await db.deleteTransactions({ user: user.id });
+ await db.deleteUserKey({ userId: user.id, all: true });
+ await db.deleteBalances({ user: user._id });
+ await db.deletePresets(user.id);
try {
- await deleteConvos(user.id); // delete user convos
+ await db.deleteConvos(user.id);
} catch (error) {
logger.error('[deleteUserController] Error deleting user convos, likely no convos', error);
}
- await deleteUserPluginAuth(user.id, null, true); // delete user plugin auth
- await deleteUserById(user.id); // delete user
- await deleteAllSharedLinks(user.id); // delete user shared links
- await deleteUserFiles(req); // delete user files
- await deleteFiles(null, user.id); // delete database files in case of orphaned files from previous steps
- await deleteToolCalls(user.id); // delete user tool calls
- await deleteUserAgents(user.id); // delete user agents
- await AgentApiKey.deleteMany({ user: user._id }); // delete user agent API keys
- await Assistant.deleteMany({ user: user.id }); // delete user assistants
- await ConversationTag.deleteMany({ user: user.id }); // delete user conversation tags
- await MemoryEntry.deleteMany({ userId: user.id }); // delete user memory entries
- await deleteUserPrompts(req, user.id); // delete user prompts
- await Action.deleteMany({ user: user.id }); // delete user actions
- await Token.deleteMany({ userId: user.id }); // delete user OAuth tokens
- await Group.updateMany(
- // remove user from all groups
- { memberIds: user.id },
- { $pull: { memberIds: user.id } },
- );
- await AclEntry.deleteMany({ principalId: user._id }); // delete user ACL entries
+ await deleteUserPluginAuth(user.id, null, true);
+ await db.deleteUserById(user.id);
+ await db.deleteAllSharedLinks(user.id);
+ await deleteUserFiles(req);
+ await db.deleteFiles(null, user.id);
+ await db.deleteToolCalls(user.id);
+ await db.deleteUserAgents(user.id);
+ await db.deleteAllAgentApiKeys(user._id);
+ await db.deleteAssistants({ user: user.id });
+ await db.deleteConversationTags({ user: user.id });
+ await db.deleteAllUserMemories(user.id);
+ await db.deleteUserPrompts(user.id);
+ await db.deleteActions({ user: user.id });
+ await db.deleteTokens({ userId: user.id });
+ await db.removeUserFromAllGroups(user.id);
+ await db.deleteAclEntries({ principalId: user._id });
logger.info(`User deleted account. Email: ${user.email} ID: ${user.id}`);
res.status(200).send({ message: 'User deleted' });
} catch (err) {
@@ -331,7 +316,7 @@ const maybeUninstallOAuthMCP = async (userId, pluginKey, appConfig) => {
const clientTokenData = await MCPTokenStorage.getClientInfoAndMetadata({
userId,
serverName,
- findToken,
+ findToken: db.findToken,
});
if (clientTokenData == null) {
return;
@@ -342,7 +327,7 @@ const maybeUninstallOAuthMCP = async (userId, pluginKey, appConfig) => {
const tokens = await MCPTokenStorage.getTokens({
userId,
serverName,
- findToken,
+ findToken: db.findToken,
});
// 3. revoke OAuth tokens at the provider
@@ -352,6 +337,7 @@ const maybeUninstallOAuthMCP = async (userId, pluginKey, appConfig) => {
serverConfig.oauth?.revocation_endpoint_auth_methods_supported ??
clientMetadata.revocation_endpoint_auth_methods_supported;
const oauthHeaders = serverConfig.oauth_headers ?? {};
+ const allowedDomains = getMCPServersRegistry().getAllowedDomains();
if (tokens?.access_token) {
try {
@@ -367,6 +353,7 @@ const maybeUninstallOAuthMCP = async (userId, pluginKey, appConfig) => {
revocationEndpointAuthMethodsSupported,
},
oauthHeaders,
+ allowedDomains,
);
} catch (error) {
logger.error(`Error revoking OAuth access token for ${serverName}:`, error);
@@ -387,6 +374,7 @@ const maybeUninstallOAuthMCP = async (userId, pluginKey, appConfig) => {
revocationEndpointAuthMethodsSupported,
},
oauthHeaders,
+ allowedDomains,
);
} catch (error) {
logger.error(`Error revoking OAuth refresh token for ${serverName}:`, error);
@@ -398,7 +386,7 @@ const maybeUninstallOAuthMCP = async (userId, pluginKey, appConfig) => {
userId,
serverName,
deleteToken: async (filter) => {
- await Token.deleteOne(filter);
+ await db.deleteTokens(filter);
},
});
diff --git a/api/server/controllers/UserController.spec.js b/api/server/controllers/UserController.spec.js
new file mode 100644
index 0000000000..4a96072062
--- /dev/null
+++ b/api/server/controllers/UserController.spec.js
@@ -0,0 +1,225 @@
+const mongoose = require('mongoose');
+const { MongoMemoryServer } = require('mongodb-memory-server');
+
+jest.mock('@librechat/data-schemas', () => {
+ const actual = jest.requireActual('@librechat/data-schemas');
+ return {
+ ...actual,
+ logger: {
+ debug: jest.fn(),
+ error: jest.fn(),
+ warn: jest.fn(),
+ info: jest.fn(),
+ },
+ };
+});
+
+jest.mock('~/models', () => {
+ const _mongoose = require('mongoose');
+ return {
+ deleteAllUserSessions: jest.fn().mockResolvedValue(undefined),
+ deleteAllSharedLinks: jest.fn().mockResolvedValue(undefined),
+ deleteAllAgentApiKeys: jest.fn().mockResolvedValue(undefined),
+ deleteConversationTags: jest.fn().mockResolvedValue(undefined),
+ deleteAllUserMemories: jest.fn().mockResolvedValue(undefined),
+ deleteTransactions: jest.fn().mockResolvedValue(undefined),
+ deleteAclEntries: jest.fn().mockResolvedValue(undefined),
+ updateUserPlugins: jest.fn(),
+ deleteAssistants: jest.fn().mockResolvedValue(undefined),
+ deleteUserById: jest.fn().mockResolvedValue(undefined),
+ deleteUserPrompts: jest.fn().mockResolvedValue(undefined),
+ deleteMessages: jest.fn().mockResolvedValue(undefined),
+ deleteBalances: jest.fn().mockResolvedValue(undefined),
+ deleteActions: jest.fn().mockResolvedValue(undefined),
+ deletePresets: jest.fn().mockResolvedValue(undefined),
+ deleteUserKey: jest.fn().mockResolvedValue(undefined),
+ deleteToolCalls: jest.fn().mockResolvedValue(undefined),
+ deleteUserAgents: jest.fn().mockResolvedValue(undefined),
+ deleteTokens: jest.fn().mockResolvedValue(undefined),
+ deleteConvos: jest.fn().mockResolvedValue(undefined),
+ deleteFiles: jest.fn().mockResolvedValue(undefined),
+ updateUser: jest.fn(),
+ getUserById: jest.fn().mockResolvedValue(null),
+ findToken: jest.fn(),
+ getFiles: jest.fn().mockResolvedValue([]),
+ removeUserFromAllGroups: jest.fn().mockImplementation(async (userId) => {
+ const Group = _mongoose.models.Group;
+ await Group.updateMany({ memberIds: userId }, { $pullAll: { memberIds: [userId] } });
+ }),
+ };
+});
+
+jest.mock('~/server/services/PluginService', () => ({
+ updateUserPluginAuth: jest.fn(),
+ deleteUserPluginAuth: jest.fn().mockResolvedValue(undefined),
+}));
+
+jest.mock('~/server/services/AuthService', () => ({
+ verifyEmail: jest.fn(),
+ resendVerificationEmail: jest.fn(),
+}));
+
+jest.mock('sharp', () =>
+ jest.fn(() => ({
+ metadata: jest.fn().mockResolvedValue({}),
+ toFormat: jest.fn().mockReturnThis(),
+ toBuffer: jest.fn().mockResolvedValue(Buffer.alloc(0)),
+ })),
+);
+
+jest.mock('@librechat/api', () => ({
+ ...jest.requireActual('@librechat/api'),
+ needsRefresh: jest.fn(),
+ getNewS3URL: jest.fn(),
+}));
+
+jest.mock('~/server/services/Files/process', () => ({
+ processDeleteRequest: jest.fn().mockResolvedValue(undefined),
+}));
+
+jest.mock('~/server/services/Config', () => ({
+ getAppConfig: jest.fn().mockResolvedValue({}),
+ getMCPManager: jest.fn(),
+ getFlowStateManager: jest.fn(),
+ getMCPServersRegistry: jest.fn(),
+}));
+
+jest.mock('~/cache', () => ({
+ getLogStores: jest.fn(),
+}));
+
+let mongoServer;
+
+beforeAll(async () => {
+ mongoServer = await MongoMemoryServer.create();
+ await mongoose.connect(mongoServer.getUri());
+});
+
+afterAll(async () => {
+ await mongoose.disconnect();
+ await mongoServer.stop();
+});
+
+afterEach(async () => {
+ const collections = mongoose.connection.collections;
+ for (const key in collections) {
+ await collections[key].deleteMany({});
+ }
+});
+
+const { deleteUserController } = require('./UserController');
+const { Group } = require('~/db/models');
+const { deleteConvos } = require('~/models');
+
+describe('deleteUserController', () => {
+ const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ send: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ };
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('should return 200 on successful deletion', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const req = { user: { id: userId.toString(), _id: userId, email: 'test@test.com' } };
+
+ await deleteUserController(req, mockRes);
+
+ expect(mockRes.status).toHaveBeenCalledWith(200);
+ expect(mockRes.send).toHaveBeenCalledWith({ message: 'User deleted' });
+ });
+
+ it('should remove the user from all groups via $pullAll', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const userIdStr = userId.toString();
+ const otherUser = new mongoose.Types.ObjectId().toString();
+
+ await Group.create([
+ { name: 'Group A', memberIds: [userIdStr, otherUser], source: 'local' },
+ { name: 'Group B', memberIds: [userIdStr], source: 'local' },
+ { name: 'Group C', memberIds: [otherUser], source: 'local' },
+ ]);
+
+ const req = { user: { id: userIdStr, _id: userId, email: 'del@test.com' } };
+ await deleteUserController(req, mockRes);
+
+ const groups = await Group.find({}).sort({ name: 1 }).lean();
+ expect(groups[0].memberIds).toEqual([otherUser]);
+ expect(groups[1].memberIds).toEqual([]);
+ expect(groups[2].memberIds).toEqual([otherUser]);
+ });
+
+ it('should handle user that exists in no groups', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ await Group.create({ name: 'Empty', memberIds: ['someone-else'], source: 'local' });
+
+ const req = { user: { id: userId.toString(), _id: userId, email: 'no-groups@test.com' } };
+ await deleteUserController(req, mockRes);
+
+ expect(mockRes.status).toHaveBeenCalledWith(200);
+ const group = await Group.findOne({ name: 'Empty' }).lean();
+ expect(group.memberIds).toEqual(['someone-else']);
+ });
+
+ it('should remove duplicate memberIds if the user appears more than once', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const userIdStr = userId.toString();
+
+ await Group.create({
+ name: 'Dupes',
+ memberIds: [userIdStr, 'other', userIdStr],
+ source: 'local',
+ });
+
+ const req = { user: { id: userIdStr, _id: userId, email: 'dupe@test.com' } };
+ await deleteUserController(req, mockRes);
+
+ const group = await Group.findOne({ name: 'Dupes' }).lean();
+ expect(group.memberIds).toEqual(['other']);
+ });
+
+ it('should still succeed when deleteConvos throws', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ deleteConvos.mockRejectedValueOnce(new Error('no convos'));
+
+ const req = { user: { id: userId.toString(), _id: userId, email: 'convos@test.com' } };
+ await deleteUserController(req, mockRes);
+
+ expect(mockRes.status).toHaveBeenCalledWith(200);
+ expect(mockRes.send).toHaveBeenCalledWith({ message: 'User deleted' });
+ });
+
+ it('should return 500 when a critical operation fails', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const { deleteMessages } = require('~/models');
+ deleteMessages.mockRejectedValueOnce(new Error('db down'));
+
+ const req = { user: { id: userId.toString(), _id: userId, email: 'fail@test.com' } };
+ await deleteUserController(req, mockRes);
+
+ expect(mockRes.status).toHaveBeenCalledWith(500);
+ expect(mockRes.json).toHaveBeenCalledWith({ message: 'Something went wrong.' });
+ });
+
+ it('should use string user.id (not ObjectId user._id) for memberIds removal', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const userIdStr = userId.toString();
+ const otherUser = 'other-user-id';
+
+ await Group.create({
+ name: 'StringCheck',
+ memberIds: [userIdStr, otherUser],
+ source: 'local',
+ });
+
+ const req = { user: { id: userIdStr, _id: userId, email: 'stringcheck@test.com' } };
+ await deleteUserController(req, mockRes);
+
+ const group = await Group.findOne({ name: 'StringCheck' }).lean();
+ expect(group.memberIds).toEqual([otherUser]);
+ expect(group.memberIds).not.toContain(userIdStr);
+ });
+});
diff --git a/api/server/controllers/__tests__/TwoFactorController.spec.js b/api/server/controllers/__tests__/TwoFactorController.spec.js
new file mode 100644
index 0000000000..62531d94a1
--- /dev/null
+++ b/api/server/controllers/__tests__/TwoFactorController.spec.js
@@ -0,0 +1,264 @@
+const mockGetUserById = jest.fn();
+const mockUpdateUser = jest.fn();
+const mockVerifyOTPOrBackupCode = jest.fn();
+const mockGenerateTOTPSecret = jest.fn();
+const mockGenerateBackupCodes = jest.fn();
+const mockEncryptV3 = jest.fn();
+
+jest.mock('@librechat/data-schemas', () => ({
+ encryptV3: (...args) => mockEncryptV3(...args),
+ logger: { error: jest.fn() },
+}));
+
+jest.mock('~/server/services/twoFactorService', () => ({
+ verifyOTPOrBackupCode: (...args) => mockVerifyOTPOrBackupCode(...args),
+ generateBackupCodes: (...args) => mockGenerateBackupCodes(...args),
+ generateTOTPSecret: (...args) => mockGenerateTOTPSecret(...args),
+ verifyBackupCode: jest.fn(),
+ getTOTPSecret: jest.fn(),
+ verifyTOTP: jest.fn(),
+}));
+
+jest.mock('~/models', () => ({
+ getUserById: (...args) => mockGetUserById(...args),
+ updateUser: (...args) => mockUpdateUser(...args),
+}));
+
+const { enable2FA, regenerateBackupCodes } = require('~/server/controllers/TwoFactorController');
+
+function createRes() {
+ const res = {};
+ res.status = jest.fn().mockReturnValue(res);
+ res.json = jest.fn().mockReturnValue(res);
+ return res;
+}
+
+const PLAIN_CODES = ['code1', 'code2', 'code3'];
+const CODE_OBJECTS = [
+ { codeHash: 'h1', used: false, usedAt: null },
+ { codeHash: 'h2', used: false, usedAt: null },
+ { codeHash: 'h3', used: false, usedAt: null },
+];
+
+beforeEach(() => {
+ jest.clearAllMocks();
+ mockGenerateTOTPSecret.mockReturnValue('NEWSECRET');
+ mockGenerateBackupCodes.mockResolvedValue({ plainCodes: PLAIN_CODES, codeObjects: CODE_OBJECTS });
+ mockEncryptV3.mockReturnValue('encrypted-secret');
+});
+
+describe('enable2FA', () => {
+ it('allows first-time setup without token — writes to pending fields', async () => {
+ const req = { user: { id: 'user1' }, body: {} };
+ const res = createRes();
+ mockGetUserById.mockResolvedValue({ _id: 'user1', twoFactorEnabled: false, email: 'a@b.com' });
+ mockUpdateUser.mockResolvedValue({ email: 'a@b.com' });
+
+ await enable2FA(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(200);
+ expect(res.json).toHaveBeenCalledWith(
+ expect.objectContaining({ otpauthUrl: expect.any(String), backupCodes: PLAIN_CODES }),
+ );
+ expect(mockVerifyOTPOrBackupCode).not.toHaveBeenCalled();
+ const updateCall = mockUpdateUser.mock.calls[0][1];
+ expect(updateCall).toHaveProperty('pendingTotpSecret', 'encrypted-secret');
+ expect(updateCall).toHaveProperty('pendingBackupCodes', CODE_OBJECTS);
+ expect(updateCall).not.toHaveProperty('twoFactorEnabled');
+ expect(updateCall).not.toHaveProperty('totpSecret');
+ expect(updateCall).not.toHaveProperty('backupCodes');
+ });
+
+ it('re-enrollment writes to pending fields, leaving live 2FA intact', async () => {
+ const req = { user: { id: 'user1' }, body: { token: '123456' } };
+ const res = createRes();
+ const existingUser = {
+ _id: 'user1',
+ twoFactorEnabled: true,
+ totpSecret: 'enc-secret',
+ email: 'a@b.com',
+ };
+ mockGetUserById.mockResolvedValue(existingUser);
+ mockVerifyOTPOrBackupCode.mockResolvedValue({ verified: true });
+ mockUpdateUser.mockResolvedValue({ email: 'a@b.com' });
+
+ await enable2FA(req, res);
+
+ expect(mockVerifyOTPOrBackupCode).toHaveBeenCalledWith({
+ user: existingUser,
+ token: '123456',
+ backupCode: undefined,
+ persistBackupUse: false,
+ });
+ expect(res.status).toHaveBeenCalledWith(200);
+ const updateCall = mockUpdateUser.mock.calls[0][1];
+ expect(updateCall).toHaveProperty('pendingTotpSecret', 'encrypted-secret');
+ expect(updateCall).toHaveProperty('pendingBackupCodes', CODE_OBJECTS);
+ expect(updateCall).not.toHaveProperty('twoFactorEnabled');
+ expect(updateCall).not.toHaveProperty('totpSecret');
+ });
+
+ it('allows re-enrollment with valid backup code (persistBackupUse: false)', async () => {
+ const req = { user: { id: 'user1' }, body: { backupCode: 'backup123' } };
+ const res = createRes();
+ const existingUser = {
+ _id: 'user1',
+ twoFactorEnabled: true,
+ totpSecret: 'enc-secret',
+ email: 'a@b.com',
+ };
+ mockGetUserById.mockResolvedValue(existingUser);
+ mockVerifyOTPOrBackupCode.mockResolvedValue({ verified: true });
+ mockUpdateUser.mockResolvedValue({ email: 'a@b.com' });
+
+ await enable2FA(req, res);
+
+ expect(mockVerifyOTPOrBackupCode).toHaveBeenCalledWith(
+ expect.objectContaining({ persistBackupUse: false }),
+ );
+ expect(res.status).toHaveBeenCalledWith(200);
+ });
+
+ it('returns error when no token provided and 2FA is enabled', async () => {
+ const req = { user: { id: 'user1' }, body: {} };
+ const res = createRes();
+ mockGetUserById.mockResolvedValue({
+ _id: 'user1',
+ twoFactorEnabled: true,
+ totpSecret: 'enc-secret',
+ });
+ mockVerifyOTPOrBackupCode.mockResolvedValue({ verified: false, status: 400 });
+
+ await enable2FA(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(400);
+ expect(mockUpdateUser).not.toHaveBeenCalled();
+ });
+
+ it('returns 401 when invalid token provided and 2FA is enabled', async () => {
+ const req = { user: { id: 'user1' }, body: { token: 'wrong' } };
+ const res = createRes();
+ mockGetUserById.mockResolvedValue({
+ _id: 'user1',
+ twoFactorEnabled: true,
+ totpSecret: 'enc-secret',
+ });
+ mockVerifyOTPOrBackupCode.mockResolvedValue({
+ verified: false,
+ status: 401,
+ message: 'Invalid token or backup code',
+ });
+
+ await enable2FA(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(401);
+ expect(res.json).toHaveBeenCalledWith({ message: 'Invalid token or backup code' });
+ expect(mockUpdateUser).not.toHaveBeenCalled();
+ });
+});
+
+describe('regenerateBackupCodes', () => {
+ it('returns 404 when user not found', async () => {
+ const req = { user: { id: 'user1' }, body: {} };
+ const res = createRes();
+ mockGetUserById.mockResolvedValue(null);
+
+ await regenerateBackupCodes(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(404);
+ expect(res.json).toHaveBeenCalledWith({ message: 'User not found' });
+ });
+
+ it('requires OTP when 2FA is enabled', async () => {
+ const req = { user: { id: 'user1' }, body: { token: '123456' } };
+ const res = createRes();
+ mockGetUserById.mockResolvedValue({
+ _id: 'user1',
+ twoFactorEnabled: true,
+ totpSecret: 'enc-secret',
+ });
+ mockVerifyOTPOrBackupCode.mockResolvedValue({ verified: true });
+ mockUpdateUser.mockResolvedValue({});
+
+ await regenerateBackupCodes(req, res);
+
+ expect(mockVerifyOTPOrBackupCode).toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(200);
+ expect(res.json).toHaveBeenCalledWith({
+ backupCodes: PLAIN_CODES,
+ backupCodesHash: CODE_OBJECTS,
+ });
+ });
+
+ it('returns error when no token provided and 2FA is enabled', async () => {
+ const req = { user: { id: 'user1' }, body: {} };
+ const res = createRes();
+ mockGetUserById.mockResolvedValue({
+ _id: 'user1',
+ twoFactorEnabled: true,
+ totpSecret: 'enc-secret',
+ });
+ mockVerifyOTPOrBackupCode.mockResolvedValue({ verified: false, status: 400 });
+
+ await regenerateBackupCodes(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(400);
+ });
+
+ it('returns 401 when invalid token provided and 2FA is enabled', async () => {
+ const req = { user: { id: 'user1' }, body: { token: 'wrong' } };
+ const res = createRes();
+ mockGetUserById.mockResolvedValue({
+ _id: 'user1',
+ twoFactorEnabled: true,
+ totpSecret: 'enc-secret',
+ });
+ mockVerifyOTPOrBackupCode.mockResolvedValue({
+ verified: false,
+ status: 401,
+ message: 'Invalid token or backup code',
+ });
+
+ await regenerateBackupCodes(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(401);
+ expect(res.json).toHaveBeenCalledWith({ message: 'Invalid token or backup code' });
+ });
+
+ it('includes backupCodesHash in response', async () => {
+ const req = { user: { id: 'user1' }, body: { token: '123456' } };
+ const res = createRes();
+ mockGetUserById.mockResolvedValue({
+ _id: 'user1',
+ twoFactorEnabled: true,
+ totpSecret: 'enc-secret',
+ });
+ mockVerifyOTPOrBackupCode.mockResolvedValue({ verified: true });
+ mockUpdateUser.mockResolvedValue({});
+
+ await regenerateBackupCodes(req, res);
+
+ const responseBody = res.json.mock.calls[0][0];
+ expect(responseBody).toHaveProperty('backupCodesHash', CODE_OBJECTS);
+ expect(responseBody).toHaveProperty('backupCodes', PLAIN_CODES);
+ });
+
+ it('allows regeneration without token when 2FA is not enabled', async () => {
+ const req = { user: { id: 'user1' }, body: {} };
+ const res = createRes();
+ mockGetUserById.mockResolvedValue({
+ _id: 'user1',
+ twoFactorEnabled: false,
+ });
+ mockUpdateUser.mockResolvedValue({});
+
+ await regenerateBackupCodes(req, res);
+
+ expect(mockVerifyOTPOrBackupCode).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(200);
+ expect(res.json).toHaveBeenCalledWith({
+ backupCodes: PLAIN_CODES,
+ backupCodesHash: CODE_OBJECTS,
+ });
+ });
+});
diff --git a/api/server/controllers/__tests__/deleteUser.spec.js b/api/server/controllers/__tests__/deleteUser.spec.js
new file mode 100644
index 0000000000..f1e9ae0c90
--- /dev/null
+++ b/api/server/controllers/__tests__/deleteUser.spec.js
@@ -0,0 +1,286 @@
+const mockGetUserById = jest.fn();
+const mockDeleteMessages = jest.fn();
+const mockDeleteAllUserSessions = jest.fn();
+const mockDeleteUserById = jest.fn();
+const mockDeleteAllSharedLinks = jest.fn();
+const mockDeletePresets = jest.fn();
+const mockDeleteUserKey = jest.fn();
+const mockDeleteConvos = jest.fn();
+const mockDeleteFiles = jest.fn();
+const mockGetFiles = jest.fn();
+const mockUpdateUserPlugins = jest.fn();
+const mockUpdateUser = jest.fn();
+const mockFindToken = jest.fn();
+const mockVerifyOTPOrBackupCode = jest.fn();
+const mockDeleteUserPluginAuth = jest.fn();
+const mockProcessDeleteRequest = jest.fn();
+const mockDeleteToolCalls = jest.fn();
+const mockDeleteUserAgents = jest.fn();
+const mockDeleteUserPrompts = jest.fn();
+
+jest.mock('@librechat/data-schemas', () => ({
+ logger: { error: jest.fn(), info: jest.fn() },
+ webSearchKeys: [],
+}));
+
+jest.mock('librechat-data-provider', () => ({
+ Tools: {},
+ CacheKeys: {},
+ Constants: { mcp_delimiter: '::', mcp_prefix: 'mcp_' },
+ FileSources: {},
+}));
+
+jest.mock('@librechat/api', () => ({
+ MCPOAuthHandler: {},
+ MCPTokenStorage: {},
+ normalizeHttpError: jest.fn(),
+ extractWebSearchEnvVars: jest.fn(),
+ needsRefresh: jest.fn(),
+ getNewS3URL: jest.fn(),
+}));
+
+jest.mock('~/models', () => ({
+ deleteAllUserSessions: (...args) => mockDeleteAllUserSessions(...args),
+ deleteAllSharedLinks: (...args) => mockDeleteAllSharedLinks(...args),
+ updateUserPlugins: (...args) => mockUpdateUserPlugins(...args),
+ deleteUserById: (...args) => mockDeleteUserById(...args),
+ deleteMessages: (...args) => mockDeleteMessages(...args),
+ deletePresets: (...args) => mockDeletePresets(...args),
+ deleteUserKey: (...args) => mockDeleteUserKey(...args),
+ getUserById: (...args) => mockGetUserById(...args),
+ deleteConvos: (...args) => mockDeleteConvos(...args),
+ deleteFiles: (...args) => mockDeleteFiles(...args),
+ updateUser: (...args) => mockUpdateUser(...args),
+ findToken: (...args) => mockFindToken(...args),
+ getFiles: (...args) => mockGetFiles(...args),
+ deleteToolCalls: (...args) => mockDeleteToolCalls(...args),
+ deleteUserAgents: (...args) => mockDeleteUserAgents(...args),
+ deleteUserPrompts: (...args) => mockDeleteUserPrompts(...args),
+ deleteTransactions: jest.fn(),
+ deleteBalances: jest.fn(),
+ deleteAllAgentApiKeys: jest.fn(),
+ deleteAssistants: jest.fn(),
+ deleteConversationTags: jest.fn(),
+ deleteAllUserMemories: jest.fn(),
+ deleteActions: jest.fn(),
+ deleteTokens: jest.fn(),
+ removeUserFromAllGroups: jest.fn(),
+ deleteAclEntries: jest.fn(),
+}));
+
+jest.mock('~/server/services/PluginService', () => ({
+ updateUserPluginAuth: jest.fn(),
+ deleteUserPluginAuth: (...args) => mockDeleteUserPluginAuth(...args),
+}));
+
+jest.mock('~/server/services/twoFactorService', () => ({
+ verifyOTPOrBackupCode: (...args) => mockVerifyOTPOrBackupCode(...args),
+}));
+
+jest.mock('~/server/services/AuthService', () => ({
+ verifyEmail: jest.fn(),
+ resendVerificationEmail: jest.fn(),
+}));
+
+jest.mock('~/config', () => ({
+ getMCPManager: jest.fn(),
+ getFlowStateManager: jest.fn(),
+ getMCPServersRegistry: jest.fn(),
+}));
+
+jest.mock('~/server/services/Config/getCachedTools', () => ({
+ invalidateCachedTools: jest.fn(),
+}));
+
+jest.mock('~/server/services/Files/process', () => ({
+ processDeleteRequest: (...args) => mockProcessDeleteRequest(...args),
+}));
+
+jest.mock('~/server/services/Config', () => ({
+ getAppConfig: jest.fn(),
+}));
+
+jest.mock('~/cache', () => ({
+ getLogStores: jest.fn(),
+}));
+
+const { deleteUserController } = require('~/server/controllers/UserController');
+
+function createRes() {
+ const res = {};
+ res.status = jest.fn().mockReturnValue(res);
+ res.json = jest.fn().mockReturnValue(res);
+ res.send = jest.fn().mockReturnValue(res);
+ return res;
+}
+
+function stubDeletionMocks() {
+ mockDeleteMessages.mockResolvedValue();
+ mockDeleteAllUserSessions.mockResolvedValue();
+ mockDeleteUserKey.mockResolvedValue();
+ mockDeletePresets.mockResolvedValue();
+ mockDeleteConvos.mockResolvedValue();
+ mockDeleteUserPluginAuth.mockResolvedValue();
+ mockDeleteUserById.mockResolvedValue();
+ mockDeleteAllSharedLinks.mockResolvedValue();
+ mockGetFiles.mockResolvedValue([]);
+ mockProcessDeleteRequest.mockResolvedValue();
+ mockDeleteFiles.mockResolvedValue();
+ mockDeleteToolCalls.mockResolvedValue();
+ mockDeleteUserAgents.mockResolvedValue();
+ mockDeleteUserPrompts.mockResolvedValue();
+}
+
+beforeEach(() => {
+ jest.clearAllMocks();
+ stubDeletionMocks();
+});
+
+describe('deleteUserController - 2FA enforcement', () => {
+ it('proceeds with deletion when 2FA is not enabled', async () => {
+ const req = { user: { id: 'user1', _id: 'user1', email: 'a@b.com' }, body: {} };
+ const res = createRes();
+ mockGetUserById.mockResolvedValue({ _id: 'user1', twoFactorEnabled: false });
+
+ await deleteUserController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(200);
+ expect(res.send).toHaveBeenCalledWith({ message: 'User deleted' });
+ expect(mockDeleteMessages).toHaveBeenCalled();
+ expect(mockVerifyOTPOrBackupCode).not.toHaveBeenCalled();
+ });
+
+ it('proceeds with deletion when user has no 2FA record', async () => {
+ const req = { user: { id: 'user1', _id: 'user1', email: 'a@b.com' }, body: {} };
+ const res = createRes();
+ mockGetUserById.mockResolvedValue(null);
+
+ await deleteUserController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(200);
+ expect(res.send).toHaveBeenCalledWith({ message: 'User deleted' });
+ });
+
+ it('returns error when 2FA is enabled and verification fails with 400', async () => {
+ const req = { user: { id: 'user1', _id: 'user1' }, body: {} };
+ const res = createRes();
+ mockGetUserById.mockResolvedValue({
+ _id: 'user1',
+ twoFactorEnabled: true,
+ totpSecret: 'enc-secret',
+ });
+ mockVerifyOTPOrBackupCode.mockResolvedValue({ verified: false, status: 400 });
+
+ await deleteUserController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(400);
+ expect(mockDeleteMessages).not.toHaveBeenCalled();
+ });
+
+ it('returns 401 when 2FA is enabled and invalid TOTP token provided', async () => {
+ const existingUser = {
+ _id: 'user1',
+ twoFactorEnabled: true,
+ totpSecret: 'enc-secret',
+ };
+ const req = { user: { id: 'user1', _id: 'user1' }, body: { token: 'wrong' } };
+ const res = createRes();
+ mockGetUserById.mockResolvedValue(existingUser);
+ mockVerifyOTPOrBackupCode.mockResolvedValue({
+ verified: false,
+ status: 401,
+ message: 'Invalid token or backup code',
+ });
+
+ await deleteUserController(req, res);
+
+ expect(mockVerifyOTPOrBackupCode).toHaveBeenCalledWith({
+ user: existingUser,
+ token: 'wrong',
+ backupCode: undefined,
+ });
+ expect(res.status).toHaveBeenCalledWith(401);
+ expect(res.json).toHaveBeenCalledWith({ message: 'Invalid token or backup code' });
+ expect(mockDeleteMessages).not.toHaveBeenCalled();
+ });
+
+ it('returns 401 when 2FA is enabled and invalid backup code provided', async () => {
+ const existingUser = {
+ _id: 'user1',
+ twoFactorEnabled: true,
+ totpSecret: 'enc-secret',
+ backupCodes: [],
+ };
+ const req = { user: { id: 'user1', _id: 'user1' }, body: { backupCode: 'bad-code' } };
+ const res = createRes();
+ mockGetUserById.mockResolvedValue(existingUser);
+ mockVerifyOTPOrBackupCode.mockResolvedValue({
+ verified: false,
+ status: 401,
+ message: 'Invalid token or backup code',
+ });
+
+ await deleteUserController(req, res);
+
+ expect(mockVerifyOTPOrBackupCode).toHaveBeenCalledWith({
+ user: existingUser,
+ token: undefined,
+ backupCode: 'bad-code',
+ });
+ expect(res.status).toHaveBeenCalledWith(401);
+ expect(mockDeleteMessages).not.toHaveBeenCalled();
+ });
+
+ it('deletes account when valid TOTP token provided with 2FA enabled', async () => {
+ const existingUser = {
+ _id: 'user1',
+ twoFactorEnabled: true,
+ totpSecret: 'enc-secret',
+ };
+ const req = {
+ user: { id: 'user1', _id: 'user1', email: 'a@b.com' },
+ body: { token: '123456' },
+ };
+ const res = createRes();
+ mockGetUserById.mockResolvedValue(existingUser);
+ mockVerifyOTPOrBackupCode.mockResolvedValue({ verified: true });
+
+ await deleteUserController(req, res);
+
+ expect(mockVerifyOTPOrBackupCode).toHaveBeenCalledWith({
+ user: existingUser,
+ token: '123456',
+ backupCode: undefined,
+ });
+ expect(res.status).toHaveBeenCalledWith(200);
+ expect(res.send).toHaveBeenCalledWith({ message: 'User deleted' });
+ expect(mockDeleteMessages).toHaveBeenCalled();
+ });
+
+ it('deletes account when valid backup code provided with 2FA enabled', async () => {
+ const existingUser = {
+ _id: 'user1',
+ twoFactorEnabled: true,
+ totpSecret: 'enc-secret',
+ backupCodes: [{ codeHash: 'h1', used: false }],
+ };
+ const req = {
+ user: { id: 'user1', _id: 'user1', email: 'a@b.com' },
+ body: { backupCode: 'valid-code' },
+ };
+ const res = createRes();
+ mockGetUserById.mockResolvedValue(existingUser);
+ mockVerifyOTPOrBackupCode.mockResolvedValue({ verified: true });
+
+ await deleteUserController(req, res);
+
+ expect(mockVerifyOTPOrBackupCode).toHaveBeenCalledWith({
+ user: existingUser,
+ token: undefined,
+ backupCode: 'valid-code',
+ });
+ expect(res.status).toHaveBeenCalledWith(200);
+ expect(res.send).toHaveBeenCalledWith({ message: 'User deleted' });
+ expect(mockDeleteMessages).toHaveBeenCalled();
+ });
+});
diff --git a/api/server/controllers/agents/__tests__/callbacks.spec.js b/api/server/controllers/agents/__tests__/callbacks.spec.js
index 103f9f3236..8bd711f9c6 100644
--- a/api/server/controllers/agents/__tests__/callbacks.spec.js
+++ b/api/server/controllers/agents/__tests__/callbacks.spec.js
@@ -20,7 +20,6 @@ jest.mock('@librechat/agents', () => ({
getMessageId: jest.fn(),
ToolEndHandler: jest.fn(),
handleToolCalls: jest.fn(),
- ChatModelStreamHandler: jest.fn(),
}));
jest.mock('~/server/services/Files/Citations', () => ({
diff --git a/api/server/controllers/agents/__tests__/openai.spec.js b/api/server/controllers/agents/__tests__/openai.spec.js
index 03a280b545..deeb2ec51d 100644
--- a/api/server/controllers/agents/__tests__/openai.spec.js
+++ b/api/server/controllers/agents/__tests__/openai.spec.js
@@ -30,9 +30,6 @@ jest.mock('@librechat/agents', () => ({
messages: [],
indexTokenCountMap: {},
}),
- ChatModelStreamHandler: jest.fn().mockImplementation(() => ({
- handle: jest.fn(),
- })),
}));
jest.mock('@librechat/api', () => ({
@@ -80,10 +77,8 @@ jest.mock('~/server/services/ToolService', () => ({
loadToolsForExecution: jest.fn().mockResolvedValue([]),
}));
-jest.mock('~/models/spendTokens', () => ({
- spendTokens: mockSpendTokens,
- spendStructuredTokens: mockSpendStructuredTokens,
-}));
+const mockGetMultiplier = jest.fn().mockReturnValue(1);
+const mockGetCacheMultiplier = jest.fn().mockReturnValue(null);
jest.mock('~/server/controllers/agents/callbacks', () => ({
createToolEndCallback: jest.fn().mockReturnValue(jest.fn()),
@@ -93,20 +88,11 @@ jest.mock('~/server/services/PermissionService', () => ({
findAccessibleResources: jest.fn().mockResolvedValue([]),
}));
-jest.mock('~/models/Conversation', () => ({
- getConvoFiles: jest.fn().mockResolvedValue([]),
-}));
-
-jest.mock('~/models/Agent', () => ({
- getAgent: jest.fn().mockResolvedValue({
- id: 'agent-123',
- provider: 'openAI',
- model_parameters: { model: 'gpt-4' },
- }),
- getAgents: jest.fn().mockResolvedValue([]),
-}));
+const mockUpdateBalance = jest.fn().mockResolvedValue({});
+const mockBulkInsertTransactions = jest.fn().mockResolvedValue(undefined);
jest.mock('~/models', () => ({
+ getAgent: jest.fn().mockResolvedValue({ id: 'agent-123', name: 'Test Agent' }),
getFiles: jest.fn(),
getUserKey: jest.fn(),
getMessages: jest.fn(),
@@ -115,6 +101,13 @@ jest.mock('~/models', () => ({
getUserCodeFiles: jest.fn(),
getToolFilesByIds: jest.fn(),
getCodeGeneratedFiles: jest.fn(),
+ updateBalance: mockUpdateBalance,
+ bulkInsertTransactions: mockBulkInsertTransactions,
+ spendTokens: mockSpendTokens,
+ spendStructuredTokens: mockSpendStructuredTokens,
+ getMultiplier: mockGetMultiplier,
+ getCacheMultiplier: mockGetCacheMultiplier,
+ getConvoFiles: jest.fn().mockResolvedValue([]),
}));
describe('OpenAIChatCompletionController', () => {
@@ -152,13 +145,92 @@ describe('OpenAIChatCompletionController', () => {
};
});
+ describe('conversation ownership validation', () => {
+ it('should skip ownership check when conversation_id is not provided', async () => {
+ const { getConvo } = require('~/models/Conversation');
+ await OpenAIChatCompletionController(req, res);
+ expect(getConvo).not.toHaveBeenCalled();
+ });
+
+ it('should return 400 when conversation_id is not a string', async () => {
+ const { validateRequest } = require('@librechat/api');
+ validateRequest.mockReturnValueOnce({
+ request: { model: 'agent-123', messages: [], stream: false, conversation_id: { $gt: '' } },
+ });
+
+ await OpenAIChatCompletionController(req, res);
+ expect(res.status).toHaveBeenCalledWith(400);
+ });
+
+ it('should return 404 when conversation is not owned by user', async () => {
+ const { validateRequest } = require('@librechat/api');
+ const { getConvo } = require('~/models/Conversation');
+ validateRequest.mockReturnValueOnce({
+ request: {
+ model: 'agent-123',
+ messages: [],
+ stream: false,
+ conversation_id: 'convo-abc',
+ },
+ });
+ getConvo.mockResolvedValueOnce(null);
+
+ await OpenAIChatCompletionController(req, res);
+ expect(getConvo).toHaveBeenCalledWith('user-123', 'convo-abc');
+ expect(res.status).toHaveBeenCalledWith(404);
+ });
+
+ it('should proceed when conversation is owned by user', async () => {
+ const { validateRequest } = require('@librechat/api');
+ const { getConvo } = require('~/models/Conversation');
+ validateRequest.mockReturnValueOnce({
+ request: {
+ model: 'agent-123',
+ messages: [],
+ stream: false,
+ conversation_id: 'convo-abc',
+ },
+ });
+ getConvo.mockResolvedValueOnce({ conversationId: 'convo-abc', user: 'user-123' });
+
+ await OpenAIChatCompletionController(req, res);
+ expect(getConvo).toHaveBeenCalledWith('user-123', 'convo-abc');
+ expect(res.status).not.toHaveBeenCalledWith(404);
+ });
+
+ it('should return 500 when getConvo throws a DB error', async () => {
+ const { validateRequest } = require('@librechat/api');
+ const { getConvo } = require('~/models/Conversation');
+ validateRequest.mockReturnValueOnce({
+ request: {
+ model: 'agent-123',
+ messages: [],
+ stream: false,
+ conversation_id: 'convo-abc',
+ },
+ });
+ getConvo.mockRejectedValueOnce(new Error('DB connection failed'));
+
+ await OpenAIChatCompletionController(req, res);
+ expect(res.status).toHaveBeenCalledWith(500);
+ });
+ });
+
describe('token usage recording', () => {
it('should call recordCollectedUsage after successful non-streaming completion', async () => {
await OpenAIChatCompletionController(req, res);
expect(mockRecordCollectedUsage).toHaveBeenCalledTimes(1);
expect(mockRecordCollectedUsage).toHaveBeenCalledWith(
- { spendTokens: mockSpendTokens, spendStructuredTokens: mockSpendStructuredTokens },
+ {
+ spendTokens: mockSpendTokens,
+ spendStructuredTokens: mockSpendStructuredTokens,
+ pricing: { getMultiplier: mockGetMultiplier, getCacheMultiplier: mockGetCacheMultiplier },
+ bulkWriteOps: {
+ insertMany: mockBulkInsertTransactions,
+ updateBalance: mockUpdateBalance,
+ },
+ },
expect.objectContaining({
user: 'user-123',
conversationId: expect.any(String),
@@ -185,12 +257,18 @@ describe('OpenAIChatCompletionController', () => {
);
});
- it('should pass spendTokens and spendStructuredTokens as dependencies', async () => {
+ it('should pass spendTokens, spendStructuredTokens, pricing, and bulkWriteOps as dependencies', async () => {
await OpenAIChatCompletionController(req, res);
const [deps] = mockRecordCollectedUsage.mock.calls[0];
expect(deps).toHaveProperty('spendTokens', mockSpendTokens);
expect(deps).toHaveProperty('spendStructuredTokens', mockSpendStructuredTokens);
+ expect(deps).toHaveProperty('pricing');
+ expect(deps.pricing).toHaveProperty('getMultiplier', mockGetMultiplier);
+ expect(deps.pricing).toHaveProperty('getCacheMultiplier', mockGetCacheMultiplier);
+ expect(deps).toHaveProperty('bulkWriteOps');
+ expect(deps.bulkWriteOps).toHaveProperty('insertMany', mockBulkInsertTransactions);
+ expect(deps.bulkWriteOps).toHaveProperty('updateBalance', mockUpdateBalance);
});
it('should include model from primaryConfig in recordCollectedUsage params', async () => {
diff --git a/api/server/controllers/agents/__tests__/responses.unit.spec.js b/api/server/controllers/agents/__tests__/responses.unit.spec.js
index 25e048f2fa..0a63445f24 100644
--- a/api/server/controllers/agents/__tests__/responses.unit.spec.js
+++ b/api/server/controllers/agents/__tests__/responses.unit.spec.js
@@ -34,9 +34,6 @@ jest.mock('@librechat/agents', () => ({
messages: [],
indexTokenCountMap: {},
}),
- ChatModelStreamHandler: jest.fn().mockImplementation(() => ({
- handle: jest.fn(),
- })),
}));
jest.mock('@librechat/api', () => ({
@@ -104,10 +101,8 @@ jest.mock('~/server/services/ToolService', () => ({
loadToolsForExecution: jest.fn().mockResolvedValue([]),
}));
-jest.mock('~/models/spendTokens', () => ({
- spendTokens: mockSpendTokens,
- spendStructuredTokens: mockSpendStructuredTokens,
-}));
+const mockGetMultiplier = jest.fn().mockReturnValue(1);
+const mockGetCacheMultiplier = jest.fn().mockReturnValue(null);
jest.mock('~/server/controllers/agents/callbacks', () => ({
createToolEndCallback: jest.fn().mockReturnValue(jest.fn()),
@@ -118,23 +113,11 @@ jest.mock('~/server/services/PermissionService', () => ({
findAccessibleResources: jest.fn().mockResolvedValue([]),
}));
-jest.mock('~/models/Conversation', () => ({
- getConvoFiles: jest.fn().mockResolvedValue([]),
- saveConvo: jest.fn().mockResolvedValue({}),
- getConvo: jest.fn().mockResolvedValue(null),
-}));
-
-jest.mock('~/models/Agent', () => ({
- getAgent: jest.fn().mockResolvedValue({
- id: 'agent-123',
- name: 'Test Agent',
- provider: 'anthropic',
- model_parameters: { model: 'claude-3' },
- }),
- getAgents: jest.fn().mockResolvedValue([]),
-}));
+const mockUpdateBalance = jest.fn().mockResolvedValue({});
+const mockBulkInsertTransactions = jest.fn().mockResolvedValue(undefined);
jest.mock('~/models', () => ({
+ getAgent: jest.fn().mockResolvedValue({ id: 'agent-123', name: 'Test Agent' }),
getFiles: jest.fn(),
getUserKey: jest.fn(),
getMessages: jest.fn().mockResolvedValue([]),
@@ -144,6 +127,15 @@ jest.mock('~/models', () => ({
getUserCodeFiles: jest.fn(),
getToolFilesByIds: jest.fn(),
getCodeGeneratedFiles: jest.fn(),
+ updateBalance: mockUpdateBalance,
+ bulkInsertTransactions: mockBulkInsertTransactions,
+ spendTokens: mockSpendTokens,
+ spendStructuredTokens: mockSpendStructuredTokens,
+ getMultiplier: mockGetMultiplier,
+ getCacheMultiplier: mockGetCacheMultiplier,
+ getConvoFiles: jest.fn().mockResolvedValue([]),
+ saveConvo: jest.fn().mockResolvedValue({}),
+ getConvo: jest.fn().mockResolvedValue(null),
}));
describe('createResponse controller', () => {
@@ -181,13 +173,117 @@ describe('createResponse controller', () => {
};
});
+ describe('conversation ownership validation', () => {
+ it('should skip ownership check when previous_response_id is not provided', async () => {
+ const { getConvo } = require('~/models/Conversation');
+ await createResponse(req, res);
+ expect(getConvo).not.toHaveBeenCalled();
+ });
+
+ it('should return 400 when previous_response_id is not a string', async () => {
+ const { validateResponseRequest, sendResponsesErrorResponse } = require('@librechat/api');
+ validateResponseRequest.mockReturnValueOnce({
+ request: {
+ model: 'agent-123',
+ input: 'Hello',
+ stream: false,
+ previous_response_id: { $gt: '' },
+ },
+ });
+
+ await createResponse(req, res);
+ expect(sendResponsesErrorResponse).toHaveBeenCalledWith(
+ res,
+ 400,
+ 'previous_response_id must be a string',
+ 'invalid_request',
+ );
+ });
+
+ it('should return 404 when conversation is not owned by user', async () => {
+ const { validateResponseRequest, sendResponsesErrorResponse } = require('@librechat/api');
+ const { getConvo } = require('~/models/Conversation');
+ validateResponseRequest.mockReturnValueOnce({
+ request: {
+ model: 'agent-123',
+ input: 'Hello',
+ stream: false,
+ previous_response_id: 'resp_abc',
+ },
+ });
+ getConvo.mockResolvedValueOnce(null);
+
+ await createResponse(req, res);
+ expect(getConvo).toHaveBeenCalledWith('user-123', 'resp_abc');
+ expect(sendResponsesErrorResponse).toHaveBeenCalledWith(
+ res,
+ 404,
+ 'Conversation not found',
+ 'not_found',
+ );
+ });
+
+ it('should proceed when conversation is owned by user', async () => {
+ const { validateResponseRequest, sendResponsesErrorResponse } = require('@librechat/api');
+ const { getConvo } = require('~/models/Conversation');
+ validateResponseRequest.mockReturnValueOnce({
+ request: {
+ model: 'agent-123',
+ input: 'Hello',
+ stream: false,
+ previous_response_id: 'resp_abc',
+ },
+ });
+ getConvo.mockResolvedValueOnce({ conversationId: 'resp_abc', user: 'user-123' });
+
+ await createResponse(req, res);
+ expect(getConvo).toHaveBeenCalledWith('user-123', 'resp_abc');
+ expect(sendResponsesErrorResponse).not.toHaveBeenCalledWith(
+ res,
+ 404,
+ expect.any(String),
+ expect.any(String),
+ );
+ });
+
+ it('should return 500 when getConvo throws a DB error', async () => {
+ const { validateResponseRequest, sendResponsesErrorResponse } = require('@librechat/api');
+ const { getConvo } = require('~/models/Conversation');
+ validateResponseRequest.mockReturnValueOnce({
+ request: {
+ model: 'agent-123',
+ input: 'Hello',
+ stream: false,
+ previous_response_id: 'resp_abc',
+ },
+ });
+ getConvo.mockRejectedValueOnce(new Error('DB connection failed'));
+
+ await createResponse(req, res);
+ expect(sendResponsesErrorResponse).toHaveBeenCalledWith(
+ res,
+ 500,
+ expect.any(String),
+ expect.any(String),
+ );
+ });
+ });
+
describe('token usage recording - non-streaming', () => {
it('should call recordCollectedUsage after successful non-streaming completion', async () => {
await createResponse(req, res);
expect(mockRecordCollectedUsage).toHaveBeenCalledTimes(1);
expect(mockRecordCollectedUsage).toHaveBeenCalledWith(
- { spendTokens: mockSpendTokens, spendStructuredTokens: mockSpendStructuredTokens },
+ {
+ spendTokens: mockSpendTokens,
+ spendStructuredTokens: mockSpendStructuredTokens,
+ pricing: { getMultiplier: mockGetMultiplier, getCacheMultiplier: mockGetCacheMultiplier },
+ bulkWriteOps: {
+ insertMany: mockBulkInsertTransactions,
+ updateBalance: mockUpdateBalance,
+ },
+ },
expect.objectContaining({
user: 'user-123',
conversationId: expect.any(String),
@@ -212,12 +308,18 @@ describe('createResponse controller', () => {
);
});
- it('should pass spendTokens and spendStructuredTokens as dependencies', async () => {
+ it('should pass spendTokens, spendStructuredTokens, pricing, and bulkWriteOps as dependencies', async () => {
await createResponse(req, res);
const [deps] = mockRecordCollectedUsage.mock.calls[0];
expect(deps).toHaveProperty('spendTokens', mockSpendTokens);
expect(deps).toHaveProperty('spendStructuredTokens', mockSpendStructuredTokens);
+ expect(deps).toHaveProperty('pricing');
+ expect(deps.pricing).toHaveProperty('getMultiplier', mockGetMultiplier);
+ expect(deps.pricing).toHaveProperty('getCacheMultiplier', mockGetCacheMultiplier);
+ expect(deps).toHaveProperty('bulkWriteOps');
+ expect(deps.bulkWriteOps).toHaveProperty('insertMany', mockBulkInsertTransactions);
+ expect(deps.bulkWriteOps).toHaveProperty('updateBalance', mockUpdateBalance);
});
it('should include model from primaryConfig in recordCollectedUsage params', async () => {
@@ -247,7 +349,15 @@ describe('createResponse controller', () => {
expect(mockRecordCollectedUsage).toHaveBeenCalledTimes(1);
expect(mockRecordCollectedUsage).toHaveBeenCalledWith(
- { spendTokens: mockSpendTokens, spendStructuredTokens: mockSpendStructuredTokens },
+ {
+ spendTokens: mockSpendTokens,
+ spendStructuredTokens: mockSpendStructuredTokens,
+ pricing: { getMultiplier: mockGetMultiplier, getCacheMultiplier: mockGetCacheMultiplier },
+ bulkWriteOps: {
+ insertMany: mockBulkInsertTransactions,
+ updateBalance: mockUpdateBalance,
+ },
+ },
expect.objectContaining({
user: 'user-123',
context: 'message',
diff --git a/api/server/controllers/agents/__tests__/v1.duplicate-actions.spec.js b/api/server/controllers/agents/__tests__/v1.duplicate-actions.spec.js
new file mode 100644
index 0000000000..cc298bd03a
--- /dev/null
+++ b/api/server/controllers/agents/__tests__/v1.duplicate-actions.spec.js
@@ -0,0 +1,159 @@
+jest.mock('~/server/services/PermissionService', () => ({
+ findPubliclyAccessibleResources: jest.fn(),
+ findAccessibleResources: jest.fn(),
+ hasPublicPermission: jest.fn(),
+ grantPermission: jest.fn().mockResolvedValue({}),
+}));
+
+jest.mock('~/server/services/Config', () => ({
+ getCachedTools: jest.fn(),
+ getMCPServerTools: jest.fn(),
+}));
+
+const mongoose = require('mongoose');
+const { actionDelimiter } = require('librechat-data-provider');
+const { agentSchema, actionSchema } = require('@librechat/data-schemas');
+const { MongoMemoryServer } = require('mongodb-memory-server');
+const { duplicateAgent } = require('../v1');
+
+let mongoServer;
+
+beforeAll(async () => {
+ mongoServer = await MongoMemoryServer.create();
+ const mongoUri = mongoServer.getUri();
+ if (!mongoose.models.Agent) {
+ mongoose.model('Agent', agentSchema);
+ }
+ if (!mongoose.models.Action) {
+ mongoose.model('Action', actionSchema);
+ }
+ await mongoose.connect(mongoUri);
+}, 20000);
+
+afterAll(async () => {
+ await mongoose.disconnect();
+ await mongoServer.stop();
+});
+
+beforeEach(async () => {
+ await mongoose.models.Agent.deleteMany({});
+ await mongoose.models.Action.deleteMany({});
+});
+
+describe('duplicateAgentHandler — action domain extraction', () => {
+ it('builds duplicated action entries using metadata.domain, not action_id', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const originalAgentId = `agent_original`;
+
+ const agent = await mongoose.models.Agent.create({
+ id: originalAgentId,
+ name: 'Test Agent',
+ author: userId.toString(),
+ provider: 'openai',
+ model: 'gpt-4',
+ tools: [],
+ actions: [`api.example.com${actionDelimiter}act_original`],
+ versions: [{ name: 'Test Agent', createdAt: new Date(), updatedAt: new Date() }],
+ });
+
+ await mongoose.models.Action.create({
+ user: userId,
+ action_id: 'act_original',
+ agent_id: originalAgentId,
+ metadata: { domain: 'api.example.com' },
+ });
+
+ const req = {
+ params: { id: agent.id },
+ user: { id: userId.toString() },
+ };
+ const res = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn(),
+ };
+
+ await duplicateAgent(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(201);
+
+ const { agent: newAgent, actions: newActions } = res.json.mock.calls[0][0];
+
+ expect(newAgent.id).not.toBe(originalAgentId);
+ expect(String(newAgent.author)).toBe(userId.toString());
+ expect(newActions).toHaveLength(1);
+ expect(newActions[0].metadata.domain).toBe('api.example.com');
+ expect(newActions[0].agent_id).toBe(newAgent.id);
+
+ for (const actionEntry of newAgent.actions) {
+ const [domain, actionId] = actionEntry.split(actionDelimiter);
+ expect(domain).toBe('api.example.com');
+ expect(actionId).toBeTruthy();
+ expect(actionId).not.toBe('act_original');
+ }
+
+ const allActions = await mongoose.models.Action.find({}).lean();
+ expect(allActions).toHaveLength(2);
+
+ const originalAction = allActions.find((a) => a.action_id === 'act_original');
+ expect(originalAction.agent_id).toBe(originalAgentId);
+
+ const duplicatedAction = allActions.find((a) => a.action_id !== 'act_original');
+ expect(duplicatedAction.agent_id).toBe(newAgent.id);
+ expect(duplicatedAction.metadata.domain).toBe('api.example.com');
+ });
+
+ it('strips sensitive metadata fields from duplicated actions', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const originalAgentId = 'agent_sensitive';
+
+ await mongoose.models.Agent.create({
+ id: originalAgentId,
+ name: 'Sensitive Agent',
+ author: userId.toString(),
+ provider: 'openai',
+ model: 'gpt-4',
+ tools: [],
+ actions: [`secure.api.com${actionDelimiter}act_secret`],
+ versions: [{ name: 'Sensitive Agent', createdAt: new Date(), updatedAt: new Date() }],
+ });
+
+ await mongoose.models.Action.create({
+ user: userId,
+ action_id: 'act_secret',
+ agent_id: originalAgentId,
+ metadata: {
+ domain: 'secure.api.com',
+ api_key: 'sk-secret-key-12345',
+ oauth_client_id: 'client_id_xyz',
+ oauth_client_secret: 'client_secret_xyz',
+ },
+ });
+
+ const req = {
+ params: { id: originalAgentId },
+ user: { id: userId.toString() },
+ };
+ const res = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn(),
+ };
+
+ await duplicateAgent(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(201);
+
+ const duplicatedAction = await mongoose.models.Action.findOne({
+ agent_id: { $ne: originalAgentId },
+ }).lean();
+
+ expect(duplicatedAction.metadata.domain).toBe('secure.api.com');
+ expect(duplicatedAction.metadata.api_key).toBeUndefined();
+ expect(duplicatedAction.metadata.oauth_client_id).toBeUndefined();
+ expect(duplicatedAction.metadata.oauth_client_secret).toBeUndefined();
+
+ const originalAction = await mongoose.models.Action.findOne({
+ action_id: 'act_secret',
+ }).lean();
+ expect(originalAction.metadata.api_key).toBe('sk-secret-key-12345');
+ });
+});
diff --git a/api/server/controllers/agents/__tests__/v1.spec.js b/api/server/controllers/agents/__tests__/v1.spec.js
index b7e7b67a22..39cf994fef 100644
--- a/api/server/controllers/agents/__tests__/v1.spec.js
+++ b/api/server/controllers/agents/__tests__/v1.spec.js
@@ -1,10 +1,8 @@
const { duplicateAgent } = require('../v1');
-const { getAgent, createAgent } = require('~/models/Agent');
-const { getActions } = require('~/models/Action');
+const { getAgent, createAgent, getActions } = require('~/models');
const { nanoid } = require('nanoid');
-jest.mock('~/models/Agent');
-jest.mock('~/models/Action');
+jest.mock('~/models');
jest.mock('nanoid');
describe('duplicateAgent', () => {
diff --git a/api/server/controllers/agents/callbacks.js b/api/server/controllers/agents/callbacks.js
index 163fc4ebba..0bb935795d 100644
--- a/api/server/controllers/agents/callbacks.js
+++ b/api/server/controllers/agents/callbacks.js
@@ -1,22 +1,13 @@
const { nanoid } = require('nanoid');
-const { Constants } = require('@librechat/agents');
const { logger } = require('@librechat/data-schemas');
+const { Constants, EnvVar, GraphEvents, ToolEndHandler } = require('@librechat/agents');
+const { Tools, StepTypes, FileContext, ErrorTypes } = require('librechat-data-provider');
const {
sendEvent,
GenerationJobManager,
writeAttachmentEvent,
createToolExecuteHandler,
} = require('@librechat/api');
-const { Tools, StepTypes, FileContext, ErrorTypes } = require('librechat-data-provider');
-const {
- EnvVar,
- Providers,
- GraphEvents,
- getMessageId,
- ToolEndHandler,
- handleToolCalls,
- ChatModelStreamHandler,
-} = require('@librechat/agents');
const { processFileCitations } = require('~/server/services/Files/Citations');
const { processCodeOutput } = require('~/server/services/Files/Code/process');
const { loadAuthValues } = require('~/server/services/Tools/credentials');
@@ -57,8 +48,6 @@ class ModelEndHandler {
let errorMessage;
try {
const agentContext = graph.getAgentContext(metadata);
- const isGoogle = agentContext.provider === Providers.GOOGLE;
- const streamingDisabled = !!agentContext.clientOptions?.disableStreaming;
if (data?.output?.additional_kwargs?.stop_reason === 'refusal') {
const info = { ...data.output.additional_kwargs };
errorMessage = JSON.stringify({
@@ -73,21 +62,6 @@ class ModelEndHandler {
});
}
- const toolCalls = data?.output?.tool_calls;
- let hasUnprocessedToolCalls = false;
- if (Array.isArray(toolCalls) && toolCalls.length > 0 && graph?.toolCallStepIds?.has) {
- try {
- hasUnprocessedToolCalls = toolCalls.some(
- (tc) => tc?.id && !graph.toolCallStepIds.has(tc.id),
- );
- } catch {
- hasUnprocessedToolCalls = false;
- }
- }
- if (isGoogle || streamingDisabled || hasUnprocessedToolCalls) {
- await handleToolCalls(toolCalls, metadata, graph);
- }
-
const usage = data?.output?.usage_metadata;
if (!usage) {
return this.finalize(errorMessage);
@@ -98,38 +72,6 @@ class ModelEndHandler {
}
this.collectedUsage.push(usage);
- if (!streamingDisabled) {
- return this.finalize(errorMessage);
- }
- if (!data.output.content) {
- return this.finalize(errorMessage);
- }
- const stepKey = graph.getStepKey(metadata);
- const message_id = getMessageId(stepKey, graph) ?? '';
- if (message_id) {
- await graph.dispatchRunStep(stepKey, {
- type: StepTypes.MESSAGE_CREATION,
- message_creation: {
- message_id,
- },
- });
- }
- const stepId = graph.getStepIdByKey(stepKey);
- const content = data.output.content;
- if (typeof content === 'string') {
- await graph.dispatchMessageDelta(stepId, {
- content: [
- {
- type: 'text',
- text: content,
- },
- ],
- });
- } else if (content.every((c) => c.type?.startsWith('text'))) {
- await graph.dispatchMessageDelta(stepId, {
- content,
- });
- }
} catch (error) {
logger.error('Error handling model end event:', error);
return this.finalize(errorMessage);
@@ -200,7 +142,6 @@ function getDefaultHandlers({
const handlers = {
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(collectedUsage),
[GraphEvents.TOOL_END]: new ToolEndHandler(toolEndCallback, logger),
- [GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
[GraphEvents.ON_RUN_STEP]: {
/**
* Handle ON_RUN_STEP event.
diff --git a/api/server/controllers/agents/client.js b/api/server/controllers/agents/client.js
index d90e9b370e..cbd01b86ec 100644
--- a/api/server/controllers/agents/client.js
+++ b/api/server/controllers/agents/client.js
@@ -6,18 +6,24 @@ const {
Tokenizer,
checkAccess,
buildToolSet,
- logAxiosError,
sanitizeTitle,
+ logToolError,
+ payloadParser,
resolveHeaders,
createSafeUser,
initializeAgent,
getBalanceConfig,
+ omitTitleOptions,
getProviderConfig,
memoryInstructions,
+ createTokenCounter,
applyContextToAgent,
+ recordCollectedUsage,
GenerationJobManager,
getTransactionsConfig,
createMemoryProcessor,
+ loadAgent: loadAgentFn,
+ createMultiAgentMapper,
filterMalformedContentParts,
} = require('@librechat/api');
const {
@@ -25,9 +31,7 @@ const {
Providers,
TitleMethod,
formatMessage,
- labelContentByAgent,
formatAgentMessages,
- getTokenCountForMessage,
createMetadataAggregator,
} = require('@librechat/agents');
const {
@@ -39,195 +43,17 @@ const {
PermissionTypes,
isAgentsEndpoint,
isEphemeralAgentId,
- bedrockInputSchema,
removeNullishValues,
} = require('librechat-data-provider');
-const { spendTokens, spendStructuredTokens } = require('~/models/spendTokens');
+const { filterFilesByAgentAccess } = require('~/server/services/Files/permissions');
const { encodeAndFormat } = require('~/server/services/Files/images/encode');
const { createContextHandlers } = require('~/app/clients/prompts');
-const { getConvoFiles } = require('~/models/Conversation');
+const { getMCPServerTools } = require('~/server/services/Config');
const BaseClient = require('~/app/clients/BaseClient');
-const { getRoleByName } = require('~/models/Role');
-const { loadAgent } = require('~/models/Agent');
const { getMCPManager } = require('~/config');
const db = require('~/models');
-const omitTitleOptions = new Set([
- 'stream',
- 'thinking',
- 'streaming',
- 'clientOptions',
- 'thinkingConfig',
- 'thinkingBudget',
- 'includeThoughts',
- 'maxOutputTokens',
- 'additionalModelRequestFields',
-]);
-
-/**
- * @param {ServerRequest} req
- * @param {Agent} agent
- * @param {string} endpoint
- */
-const payloadParser = ({ req, agent, endpoint }) => {
- if (isAgentsEndpoint(endpoint)) {
- return { model: undefined };
- } else if (endpoint === EModelEndpoint.bedrock) {
- const parsedValues = bedrockInputSchema.parse(agent.model_parameters);
- if (parsedValues.thinking == null) {
- parsedValues.thinking = false;
- }
- return parsedValues;
- }
- return req.body.endpointOption.model_parameters;
-};
-
-function createTokenCounter(encoding) {
- return function (message) {
- const countTokens = (text) => Tokenizer.getTokenCount(text, encoding);
- return getTokenCountForMessage(message, countTokens);
- };
-}
-
-function logToolError(graph, error, toolId) {
- logAxiosError({
- error,
- message: `[api/server/controllers/agents/client.js #chatCompletion] Tool Error "${toolId}"`,
- });
-}
-
-/** Regex pattern to match agent ID suffix (____N) */
-const AGENT_SUFFIX_PATTERN = /____(\d+)$/;
-
-/**
- * Finds the primary agent ID within a set of agent IDs.
- * Primary = no suffix (____N) or lowest suffix number.
- * @param {Set} agentIds
- * @returns {string | null}
- */
-function findPrimaryAgentId(agentIds) {
- let primaryAgentId = null;
- let lowestSuffixIndex = Infinity;
-
- for (const agentId of agentIds) {
- const suffixMatch = agentId.match(AGENT_SUFFIX_PATTERN);
- if (!suffixMatch) {
- return agentId;
- }
- const suffixIndex = parseInt(suffixMatch[1], 10);
- if (suffixIndex < lowestSuffixIndex) {
- lowestSuffixIndex = suffixIndex;
- primaryAgentId = agentId;
- }
- }
-
- return primaryAgentId;
-}
-
-/**
- * Creates a mapMethod for getMessagesForConversation that processes agent content.
- * - Strips agentId/groupId metadata from all content
- * - For parallel agents (addedConvo with groupId): filters each group to its primary agent
- * - For handoffs (agentId without groupId): keeps all content from all agents
- * - For multi-agent: applies agent labels to content
- *
- * The key distinction:
- * - Parallel execution (addedConvo): Parts have both agentId AND groupId
- * - Handoffs: Parts only have agentId, no groupId
- *
- * @param {Agent} primaryAgent - Primary agent configuration
- * @param {Map} [agentConfigs] - Additional agent configurations
- * @returns {(message: TMessage) => TMessage} Map method for processing messages
- */
-function createMultiAgentMapper(primaryAgent, agentConfigs) {
- const hasMultipleAgents = (primaryAgent.edges?.length ?? 0) > 0 || (agentConfigs?.size ?? 0) > 0;
-
- /** @type {Record | null} */
- let agentNames = null;
- if (hasMultipleAgents) {
- agentNames = { [primaryAgent.id]: primaryAgent.name || 'Assistant' };
- if (agentConfigs) {
- for (const [agentId, agentConfig] of agentConfigs.entries()) {
- agentNames[agentId] = agentConfig.name || agentConfig.id;
- }
- }
- }
-
- return (message) => {
- if (message.isCreatedByUser || !Array.isArray(message.content)) {
- return message;
- }
-
- // Check for metadata
- const hasAgentMetadata = message.content.some((part) => part?.agentId || part?.groupId != null);
- if (!hasAgentMetadata) {
- return message;
- }
-
- try {
- // Build a map of groupId -> Set of agentIds, to find primary per group
- /** @type {Map>} */
- const groupAgentMap = new Map();
-
- for (const part of message.content) {
- const groupId = part?.groupId;
- const agentId = part?.agentId;
- if (groupId != null && agentId) {
- if (!groupAgentMap.has(groupId)) {
- groupAgentMap.set(groupId, new Set());
- }
- groupAgentMap.get(groupId).add(agentId);
- }
- }
-
- // For each group, find the primary agent
- /** @type {Map} */
- const groupPrimaryMap = new Map();
- for (const [groupId, agentIds] of groupAgentMap) {
- const primary = findPrimaryAgentId(agentIds);
- if (primary) {
- groupPrimaryMap.set(groupId, primary);
- }
- }
-
- /** @type {Array} */
- const filteredContent = [];
- /** @type {Record} */
- const agentIdMap = {};
-
- for (const part of message.content) {
- const agentId = part?.agentId;
- const groupId = part?.groupId;
-
- // Filtering logic:
- // - No groupId (handoffs): always include
- // - Has groupId (parallel): only include if it's the primary for that group
- const isParallelPart = groupId != null;
- const groupPrimary = isParallelPart ? groupPrimaryMap.get(groupId) : null;
- const shouldInclude = !isParallelPart || !agentId || agentId === groupPrimary;
-
- if (shouldInclude) {
- const newIndex = filteredContent.length;
- const { agentId: _a, groupId: _g, ...cleanPart } = part;
- filteredContent.push(cleanPart);
- if (agentId && hasMultipleAgents) {
- agentIdMap[newIndex] = agentId;
- }
- }
- }
-
- const finalContent =
- Object.keys(agentIdMap).length > 0 && agentNames
- ? labelContentByAgent(filteredContent, agentIdMap, agentNames)
- : filteredContent;
-
- return { ...message, content: finalContent };
- } catch (error) {
- logger.error('[AgentClient] Error processing multi-agent message:', error);
- return message;
- }
- };
-}
+const loadAgent = (params) => loadAgentFn(params, { getAgent: db.getAgent, getMCPServerTools });
class AgentClient extends BaseClient {
constructor(options = {}) {
@@ -296,14 +122,9 @@ class AgentClient extends BaseClient {
checkVisionRequest() {}
getSaveOptions() {
- // TODO:
- // would need to be override settings; otherwise, model needs to be undefined
- // model: this.override.model,
- // instructions: this.override.instructions,
- // additional_instructions: this.override.additional_instructions,
let runOptions = {};
try {
- runOptions = payloadParser(this.options);
+ runOptions = payloadParser(this.options) ?? {};
} catch (error) {
logger.error(
'[api/server/controllers/agents/client.js #getSaveOptions] Error parsing options',
@@ -314,16 +135,16 @@ class AgentClient extends BaseClient {
return removeNullishValues(
Object.assign(
{
+ spec: this.options.spec,
+ iconURL: this.options.iconURL,
endpoint: this.options.endpoint,
endpointType: this.options.endpointType,
model: this.options.agent?.model_parameters?.model,
agent_id: this.options.agent.id,
modelLabel: this.options.modelLabel,
- maxContextTokens: this.options.maxContextTokens,
resendFiles: this.options.resendFiles,
imageDetail: this.options.imageDetail,
- spec: this.options.spec,
- iconURL: this.options.iconURL,
+ maxContextTokens: this.maxContextTokens,
},
// TODO: PARSE OPTIONS BY PROVIDER, MAY CONTAIN SENSITIVE DATA
runOptions,
@@ -592,7 +413,7 @@ class AgentClient extends BaseClient {
user,
permissionType: PermissionTypes.MEMORIES,
permissions: [Permissions.USE],
- getRoleByName,
+ getRoleByName: db.getRoleByName,
});
if (!hasAccess) {
@@ -652,13 +473,14 @@ class AgentClient extends BaseClient {
},
},
{
- getConvoFiles,
getFiles: db.getFiles,
getUserKey: db.getUserKey,
+ getConvoFiles: db.getConvoFiles,
updateFilesUsage: db.updateFilesUsage,
getUserKeyValues: db.getUserKeyValues,
getToolFilesByIds: db.getToolFilesByIds,
getCodeGeneratedFiles: db.getCodeGeneratedFiles,
+ filterFilesByAgentAccess,
},
);
@@ -807,82 +629,29 @@ class AgentClient extends BaseClient {
context = 'message',
collectedUsage = this.collectedUsage,
}) {
- if (!collectedUsage || !collectedUsage.length) {
- return;
- }
- // Use first entry's input_tokens as the base input (represents initial user message context)
- // Support both OpenAI format (input_token_details) and Anthropic format (cache_*_input_tokens)
- const firstUsage = collectedUsage[0];
- const input_tokens =
- (firstUsage?.input_tokens || 0) +
- (Number(firstUsage?.input_token_details?.cache_creation) ||
- Number(firstUsage?.cache_creation_input_tokens) ||
- 0) +
- (Number(firstUsage?.input_token_details?.cache_read) ||
- Number(firstUsage?.cache_read_input_tokens) ||
- 0);
-
- // Sum output_tokens directly from all entries - works for both sequential and parallel execution
- // This avoids the incremental calculation that produced negative values for parallel agents
- let total_output_tokens = 0;
-
- for (const usage of collectedUsage) {
- if (!usage) {
- continue;
- }
-
- // Support both OpenAI format (input_token_details) and Anthropic format (cache_*_input_tokens)
- const cache_creation =
- Number(usage.input_token_details?.cache_creation) ||
- Number(usage.cache_creation_input_tokens) ||
- 0;
- const cache_read =
- Number(usage.input_token_details?.cache_read) || Number(usage.cache_read_input_tokens) || 0;
-
- // Accumulate output tokens for the usage summary
- total_output_tokens += Number(usage.output_tokens) || 0;
-
- const txMetadata = {
+ const result = await recordCollectedUsage(
+ {
+ spendTokens: db.spendTokens,
+ spendStructuredTokens: db.spendStructuredTokens,
+ pricing: { getMultiplier: db.getMultiplier, getCacheMultiplier: db.getCacheMultiplier },
+ bulkWriteOps: { insertMany: db.bulkInsertTransactions, updateBalance: db.updateBalance },
+ },
+ {
+ user: this.user ?? this.options.req.user?.id,
+ conversationId: this.conversationId,
+ collectedUsage,
+ model: model ?? this.model ?? this.options.agent.model_parameters.model,
context,
+ messageId: this.responseMessageId,
balance,
transactions,
- conversationId: this.conversationId,
- user: this.user ?? this.options.req.user?.id,
endpointTokenConfig: this.options.endpointTokenConfig,
- model: usage.model ?? model ?? this.model ?? this.options.agent.model_parameters.model,
- };
+ },
+ );
- if (cache_creation > 0 || cache_read > 0) {
- spendStructuredTokens(txMetadata, {
- promptTokens: {
- input: usage.input_tokens,
- write: cache_creation,
- read: cache_read,
- },
- completionTokens: usage.output_tokens,
- }).catch((err) => {
- logger.error(
- '[api/server/controllers/agents/client.js #recordCollectedUsage] Error spending structured tokens',
- err,
- );
- });
- continue;
- }
- spendTokens(txMetadata, {
- promptTokens: usage.input_tokens,
- completionTokens: usage.output_tokens,
- }).catch((err) => {
- logger.error(
- '[api/server/controllers/agents/client.js #recordCollectedUsage] Error spending tokens',
- err,
- );
- });
+ if (result) {
+ this.usage = result;
}
-
- this.usage = {
- input_tokens,
- output_tokens: total_output_tokens,
- };
}
/**
@@ -1074,9 +843,10 @@ class AgentClient extends BaseClient {
config.signal = null;
};
+ const hideSequentialOutputs = config.configurable.hide_sequential_outputs;
await runAgents(initialMessages);
/** @deprecated Agent Chain */
- if (config.configurable.hide_sequential_outputs) {
+ if (hideSequentialOutputs) {
this.contentParts = this.contentParts.filter((part, index) => {
// Include parts that are either:
// 1. At or after the finalContentStart index
@@ -1330,6 +1100,7 @@ class AgentClient extends BaseClient {
model: clientOptions.model,
balance: balanceConfig,
transactions: transactionsConfig,
+ messageId: this.responseMessageId,
}).catch((err) => {
logger.error(
'[api/server/controllers/agents/client.js #titleConvo] Error recording collected usage',
@@ -1363,11 +1134,12 @@ class AgentClient extends BaseClient {
context = 'message',
}) {
try {
- await spendTokens(
+ await db.spendTokens(
{
model,
context,
balance,
+ messageId: this.responseMessageId,
conversationId: this.conversationId,
user: this.user ?? this.options.req.user?.id,
endpointTokenConfig: this.options.endpointTokenConfig,
@@ -1381,11 +1153,12 @@ class AgentClient extends BaseClient {
'reasoning_tokens' in usage &&
typeof usage.reasoning_tokens === 'number'
) {
- await spendTokens(
+ await db.spendTokens(
{
model,
balance,
context: 'reasoning',
+ messageId: this.responseMessageId,
conversationId: this.conversationId,
user: this.user ?? this.options.req.user?.id,
endpointTokenConfig: this.options.endpointTokenConfig,
@@ -1401,7 +1174,11 @@ class AgentClient extends BaseClient {
}
}
+ /** Anthropic Claude models use a distinct BPE tokenizer; all others default to o200k_base. */
getEncoding() {
+ if (this.model && this.model.toLowerCase().includes('claude')) {
+ return 'claude';
+ }
return 'o200k_base';
}
diff --git a/api/server/controllers/agents/client.test.js b/api/server/controllers/agents/client.test.js
index 9dd3567047..4e3d10e8e6 100644
--- a/api/server/controllers/agents/client.test.js
+++ b/api/server/controllers/agents/client.test.js
@@ -15,13 +15,15 @@ jest.mock('@librechat/api', () => ({
checkAccess: jest.fn(),
initializeAgent: jest.fn(),
createMemoryProcessor: jest.fn(),
-}));
-
-jest.mock('~/models/Agent', () => ({
loadAgent: jest.fn(),
}));
-jest.mock('~/models/Role', () => ({
+jest.mock('~/server/services/Config', () => ({
+ getMCPServerTools: jest.fn(),
+}));
+
+jest.mock('~/models', () => ({
+ getAgent: jest.fn(),
getRoleByName: jest.fn(),
}));
@@ -263,6 +265,7 @@ describe('AgentClient - titleConvo', () => {
transactions: {
enabled: true,
},
+ messageId: 'response-123',
});
});
@@ -2137,7 +2140,7 @@ describe('AgentClient - titleConvo', () => {
};
mockCheckAccess = require('@librechat/api').checkAccess;
- mockLoadAgent = require('~/models/Agent').loadAgent;
+ mockLoadAgent = require('@librechat/api').loadAgent;
mockInitializeAgent = require('@librechat/api').initializeAgent;
mockCreateMemoryProcessor = require('@librechat/api').createMemoryProcessor;
});
@@ -2194,6 +2197,7 @@ describe('AgentClient - titleConvo', () => {
expect.objectContaining({
agent_id: differentAgentId,
}),
+ expect.any(Object),
);
expect(mockInitializeAgent).toHaveBeenCalledWith(
expect.objectContaining({
diff --git a/api/server/controllers/agents/errors.js b/api/server/controllers/agents/errors.js
index 54b296a5d2..b16ce75591 100644
--- a/api/server/controllers/agents/errors.js
+++ b/api/server/controllers/agents/errors.js
@@ -3,8 +3,8 @@ const { logger } = require('@librechat/data-schemas');
const { CacheKeys, ViolationTypes } = require('librechat-data-provider');
const { sendResponse } = require('~/server/middleware/error');
const { recordUsage } = require('~/server/services/Threads');
-const { getConvo } = require('~/models/Conversation');
const getLogStores = require('~/cache/getLogStores');
+const { getConvo } = require('~/models');
/**
* @typedef {Object} ErrorHandlerContext
diff --git a/api/server/controllers/agents/filterAuthorizedTools.spec.js b/api/server/controllers/agents/filterAuthorizedTools.spec.js
new file mode 100644
index 0000000000..e215fdc1fc
--- /dev/null
+++ b/api/server/controllers/agents/filterAuthorizedTools.spec.js
@@ -0,0 +1,668 @@
+const mongoose = require('mongoose');
+const { v4: uuidv4 } = require('uuid');
+const { Constants } = require('librechat-data-provider');
+const { agentSchema } = require('@librechat/data-schemas');
+const { MongoMemoryServer } = require('mongodb-memory-server');
+
+const d = Constants.mcp_delimiter;
+
+const mockGetAllServerConfigs = jest.fn();
+
+jest.mock('~/server/services/Config', () => ({
+ getCachedTools: jest.fn().mockResolvedValue({
+ web_search: true,
+ execute_code: true,
+ file_search: true,
+ }),
+}));
+
+jest.mock('~/config', () => ({
+ getMCPServersRegistry: jest.fn(() => ({
+ getAllServerConfigs: mockGetAllServerConfigs,
+ })),
+}));
+
+jest.mock('~/server/services/Files/strategies', () => ({
+ getStrategyFunctions: jest.fn(),
+}));
+
+jest.mock('~/server/services/Files/images/avatar', () => ({
+ resizeAvatar: jest.fn(),
+}));
+
+jest.mock('~/server/services/Files/process', () => ({
+ filterFile: jest.fn(),
+}));
+
+jest.mock('~/server/services/PermissionService', () => ({
+ findAccessibleResources: jest.fn().mockResolvedValue([]),
+ findPubliclyAccessibleResources: jest.fn().mockResolvedValue([]),
+ grantPermission: jest.fn(),
+ hasPublicPermission: jest.fn().mockResolvedValue(false),
+ checkPermission: jest.fn().mockResolvedValue(true),
+}));
+
+jest.mock('~/models', () => {
+ const mongoose = require('mongoose');
+ const { createModels, createMethods } = require('@librechat/data-schemas');
+ createModels(mongoose);
+ const methods = createMethods(mongoose);
+ return {
+ ...methods,
+ getCategoriesWithCounts: jest.fn(),
+ deleteFileByFilter: jest.fn(),
+ };
+});
+
+jest.mock('~/cache', () => ({
+ getLogStores: jest.fn(() => ({
+ get: jest.fn(),
+ set: jest.fn(),
+ delete: jest.fn(),
+ })),
+}));
+
+const {
+ filterAuthorizedTools,
+ createAgent: createAgentHandler,
+ updateAgent: updateAgentHandler,
+ duplicateAgent: duplicateAgentHandler,
+ revertAgentVersion: revertAgentVersionHandler,
+} = require('./v1');
+
+const { getMCPServersRegistry } = require('~/config');
+
+let Agent;
+
+describe('MCP Tool Authorization', () => {
+ let mongoServer;
+ let mockReq;
+ let mockRes;
+
+ beforeAll(async () => {
+ mongoServer = await MongoMemoryServer.create();
+ const mongoUri = mongoServer.getUri();
+ await mongoose.connect(mongoUri);
+ Agent = mongoose.models.Agent || mongoose.model('Agent', agentSchema);
+ }, 20000);
+
+ afterAll(async () => {
+ await mongoose.disconnect();
+ await mongoServer.stop();
+ });
+
+ beforeEach(async () => {
+ await Agent.deleteMany({});
+ jest.clearAllMocks();
+
+ getMCPServersRegistry.mockImplementation(() => ({
+ getAllServerConfigs: mockGetAllServerConfigs,
+ }));
+ mockGetAllServerConfigs.mockResolvedValue({
+ authorizedServer: { type: 'sse', url: 'https://authorized.example.com' },
+ anotherServer: { type: 'sse', url: 'https://another.example.com' },
+ });
+
+ mockReq = {
+ user: {
+ id: new mongoose.Types.ObjectId().toString(),
+ role: 'USER',
+ },
+ body: {},
+ params: {},
+ query: {},
+ app: { locals: { fileStrategy: 'local' } },
+ };
+
+ mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ };
+ });
+
+ describe('filterAuthorizedTools', () => {
+ const availableTools = { web_search: true, custom_tool: true };
+ const userId = 'test-user-123';
+
+ test('should keep authorized MCP tools and strip unauthorized ones', async () => {
+ const result = await filterAuthorizedTools({
+ tools: [`toolA${d}authorizedServer`, `toolB${d}forbiddenServer`, 'web_search'],
+ userId,
+ availableTools,
+ });
+
+ expect(result).toContain(`toolA${d}authorizedServer`);
+ expect(result).toContain('web_search');
+ expect(result).not.toContain(`toolB${d}forbiddenServer`);
+ });
+
+ test('should keep system tools without querying MCP registry', async () => {
+ const result = await filterAuthorizedTools({
+ tools: ['execute_code', 'file_search', 'web_search'],
+ userId,
+ availableTools: {},
+ });
+
+ expect(result).toEqual(['execute_code', 'file_search', 'web_search']);
+ expect(mockGetAllServerConfigs).not.toHaveBeenCalled();
+ });
+
+ test('should not query MCP registry when no MCP tools are present', async () => {
+ const result = await filterAuthorizedTools({
+ tools: ['web_search', 'custom_tool'],
+ userId,
+ availableTools,
+ });
+
+ expect(result).toEqual(['web_search', 'custom_tool']);
+ expect(mockGetAllServerConfigs).not.toHaveBeenCalled();
+ });
+
+ test('should filter all MCP tools when registry is uninitialized', async () => {
+ getMCPServersRegistry.mockImplementation(() => {
+ throw new Error('MCPServersRegistry has not been initialized.');
+ });
+
+ const result = await filterAuthorizedTools({
+ tools: [`toolA${d}someServer`, 'web_search'],
+ userId,
+ availableTools,
+ });
+
+ expect(result).toEqual(['web_search']);
+ expect(result).not.toContain(`toolA${d}someServer`);
+ });
+
+ test('should handle mixed authorized and unauthorized MCP tools', async () => {
+ const result = await filterAuthorizedTools({
+ tools: [
+ 'web_search',
+ `search${d}authorizedServer`,
+ `attack${d}victimServer`,
+ 'execute_code',
+ `list${d}anotherServer`,
+ `steal${d}nonexistent`,
+ ],
+ userId,
+ availableTools,
+ });
+
+ expect(result).toEqual([
+ 'web_search',
+ `search${d}authorizedServer`,
+ 'execute_code',
+ `list${d}anotherServer`,
+ ]);
+ });
+
+ test('should handle empty tools array', async () => {
+ const result = await filterAuthorizedTools({
+ tools: [],
+ userId,
+ availableTools,
+ });
+
+ expect(result).toEqual([]);
+ expect(mockGetAllServerConfigs).not.toHaveBeenCalled();
+ });
+
+ test('should handle null/undefined tool entries gracefully', async () => {
+ const result = await filterAuthorizedTools({
+ tools: [null, undefined, '', 'web_search'],
+ userId,
+ availableTools,
+ });
+
+ expect(result).toEqual(['web_search']);
+ });
+
+ test('should call getAllServerConfigs with the correct userId', async () => {
+ await filterAuthorizedTools({
+ tools: [`tool${d}authorizedServer`],
+ userId: 'specific-user-id',
+ availableTools,
+ });
+
+ expect(mockGetAllServerConfigs).toHaveBeenCalledWith('specific-user-id');
+ });
+
+ test('should only call getAllServerConfigs once even with multiple MCP tools', async () => {
+ await filterAuthorizedTools({
+ tools: [`tool1${d}authorizedServer`, `tool2${d}anotherServer`, `tool3${d}unknownServer`],
+ userId,
+ availableTools,
+ });
+
+ expect(mockGetAllServerConfigs).toHaveBeenCalledTimes(1);
+ });
+
+ test('should preserve existing MCP tools when registry is unavailable', async () => {
+ getMCPServersRegistry.mockImplementation(() => {
+ throw new Error('MCPServersRegistry has not been initialized.');
+ });
+
+ const existingTools = [`toolA${d}serverA`, `toolB${d}serverB`];
+
+ const result = await filterAuthorizedTools({
+ tools: [...existingTools, `newTool${d}unknownServer`, 'web_search'],
+ userId,
+ availableTools,
+ existingTools,
+ });
+
+ expect(result).toContain(`toolA${d}serverA`);
+ expect(result).toContain(`toolB${d}serverB`);
+ expect(result).toContain('web_search');
+ expect(result).not.toContain(`newTool${d}unknownServer`);
+ });
+
+ test('should still reject all MCP tools when registry is unavailable and no existingTools', async () => {
+ getMCPServersRegistry.mockImplementation(() => {
+ throw new Error('MCPServersRegistry has not been initialized.');
+ });
+
+ const result = await filterAuthorizedTools({
+ tools: [`toolA${d}serverA`, 'web_search'],
+ userId,
+ availableTools,
+ });
+
+ expect(result).toEqual(['web_search']);
+ });
+
+ test('should not preserve malformed existing tools when registry is unavailable', async () => {
+ getMCPServersRegistry.mockImplementation(() => {
+ throw new Error('MCPServersRegistry has not been initialized.');
+ });
+
+ const malformedTool = `a${d}b${d}c`;
+ const result = await filterAuthorizedTools({
+ tools: [malformedTool, `legit${d}serverA`, 'web_search'],
+ userId,
+ availableTools,
+ existingTools: [malformedTool, `legit${d}serverA`],
+ });
+
+ expect(result).toContain(`legit${d}serverA`);
+ expect(result).toContain('web_search');
+ expect(result).not.toContain(malformedTool);
+ });
+
+ test('should reject malformed MCP tool keys with multiple delimiters', async () => {
+ const result = await filterAuthorizedTools({
+ tools: [
+ `attack${d}victimServer${d}authorizedServer`,
+ `legit${d}authorizedServer`,
+ `a${d}b${d}c${d}d`,
+ 'web_search',
+ ],
+ userId,
+ availableTools,
+ });
+
+ expect(result).toEqual([`legit${d}authorizedServer`, 'web_search']);
+ expect(result).not.toContainEqual(expect.stringContaining('victimServer'));
+ expect(result).not.toContainEqual(expect.stringContaining(`a${d}b`));
+ });
+ });
+
+ describe('createAgentHandler - MCP tool authorization', () => {
+ test('should strip unauthorized MCP tools on create', async () => {
+ mockReq.body = {
+ provider: 'openai',
+ model: 'gpt-4',
+ name: 'MCP Test Agent',
+ tools: ['web_search', `validTool${d}authorizedServer`, `attack${d}forbiddenServer`],
+ };
+
+ await createAgentHandler(mockReq, mockRes);
+
+ expect(mockRes.status).toHaveBeenCalledWith(201);
+ const agent = mockRes.json.mock.calls[0][0];
+ expect(agent.tools).toContain('web_search');
+ expect(agent.tools).toContain(`validTool${d}authorizedServer`);
+ expect(agent.tools).not.toContain(`attack${d}forbiddenServer`);
+ });
+
+ test('should not 500 when MCP registry is uninitialized', async () => {
+ getMCPServersRegistry.mockImplementation(() => {
+ throw new Error('MCPServersRegistry has not been initialized.');
+ });
+
+ mockReq.body = {
+ provider: 'openai',
+ model: 'gpt-4',
+ name: 'MCP Uninitialized Test',
+ tools: [`tool${d}someServer`, 'web_search'],
+ };
+
+ await createAgentHandler(mockReq, mockRes);
+
+ expect(mockRes.status).toHaveBeenCalledWith(201);
+ const agent = mockRes.json.mock.calls[0][0];
+ expect(agent.tools).toEqual(['web_search']);
+ });
+
+ test('should store mcpServerNames only for authorized servers', async () => {
+ mockReq.body = {
+ provider: 'openai',
+ model: 'gpt-4',
+ name: 'MCP Names Test',
+ tools: [`toolA${d}authorizedServer`, `toolB${d}forbiddenServer`],
+ };
+
+ await createAgentHandler(mockReq, mockRes);
+
+ expect(mockRes.status).toHaveBeenCalledWith(201);
+ const agent = mockRes.json.mock.calls[0][0];
+ const agentInDb = await Agent.findOne({ id: agent.id });
+ expect(agentInDb.mcpServerNames).toContain('authorizedServer');
+ expect(agentInDb.mcpServerNames).not.toContain('forbiddenServer');
+ });
+ });
+
+ describe('updateAgentHandler - MCP tool authorization', () => {
+ let existingAgentId;
+ let existingAgentAuthorId;
+
+ beforeEach(async () => {
+ existingAgentAuthorId = new mongoose.Types.ObjectId();
+ const agent = await Agent.create({
+ id: `agent_${uuidv4()}`,
+ name: 'Original Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: existingAgentAuthorId,
+ tools: ['web_search', `existingTool${d}authorizedServer`],
+ mcpServerNames: ['authorizedServer'],
+ versions: [
+ {
+ name: 'Original Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ tools: ['web_search', `existingTool${d}authorizedServer`],
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ },
+ ],
+ });
+ existingAgentId = agent.id;
+ });
+
+ test('should preserve existing MCP tools even if editor lacks access', async () => {
+ mockGetAllServerConfigs.mockResolvedValue({});
+
+ mockReq.user.id = existingAgentAuthorId.toString();
+ mockReq.params.id = existingAgentId;
+ mockReq.body = {
+ tools: ['web_search', `existingTool${d}authorizedServer`],
+ };
+
+ await updateAgentHandler(mockReq, mockRes);
+
+ expect(mockRes.json).toHaveBeenCalled();
+ const updatedAgent = mockRes.json.mock.calls[0][0];
+ expect(updatedAgent.tools).toContain(`existingTool${d}authorizedServer`);
+ expect(updatedAgent.tools).toContain('web_search');
+ });
+
+ test('should reject newly added unauthorized MCP tools', async () => {
+ mockReq.user.id = existingAgentAuthorId.toString();
+ mockReq.params.id = existingAgentId;
+ mockReq.body = {
+ tools: ['web_search', `existingTool${d}authorizedServer`, `attack${d}forbiddenServer`],
+ };
+
+ await updateAgentHandler(mockReq, mockRes);
+
+ expect(mockRes.json).toHaveBeenCalled();
+ const updatedAgent = mockRes.json.mock.calls[0][0];
+ expect(updatedAgent.tools).toContain('web_search');
+ expect(updatedAgent.tools).toContain(`existingTool${d}authorizedServer`);
+ expect(updatedAgent.tools).not.toContain(`attack${d}forbiddenServer`);
+ });
+
+ test('should allow adding authorized MCP tools', async () => {
+ mockReq.user.id = existingAgentAuthorId.toString();
+ mockReq.params.id = existingAgentId;
+ mockReq.body = {
+ tools: ['web_search', `existingTool${d}authorizedServer`, `newTool${d}anotherServer`],
+ };
+
+ await updateAgentHandler(mockReq, mockRes);
+
+ expect(mockRes.json).toHaveBeenCalled();
+ const updatedAgent = mockRes.json.mock.calls[0][0];
+ expect(updatedAgent.tools).toContain(`newTool${d}anotherServer`);
+ });
+
+ test('should not query MCP registry when no new MCP tools added', async () => {
+ mockReq.user.id = existingAgentAuthorId.toString();
+ mockReq.params.id = existingAgentId;
+ mockReq.body = {
+ tools: ['web_search', `existingTool${d}authorizedServer`],
+ };
+
+ await updateAgentHandler(mockReq, mockRes);
+
+ expect(mockGetAllServerConfigs).not.toHaveBeenCalled();
+ });
+
+ test('should preserve existing MCP tools when registry unavailable and user edits agent', async () => {
+ getMCPServersRegistry.mockImplementation(() => {
+ throw new Error('MCPServersRegistry has not been initialized.');
+ });
+
+ mockReq.user.id = existingAgentAuthorId.toString();
+ mockReq.params.id = existingAgentId;
+ mockReq.body = {
+ name: 'Renamed After Restart',
+ tools: ['web_search', `existingTool${d}authorizedServer`],
+ };
+
+ await updateAgentHandler(mockReq, mockRes);
+
+ expect(mockRes.json).toHaveBeenCalled();
+ const updatedAgent = mockRes.json.mock.calls[0][0];
+ expect(updatedAgent.tools).toContain(`existingTool${d}authorizedServer`);
+ expect(updatedAgent.tools).toContain('web_search');
+ expect(updatedAgent.name).toBe('Renamed After Restart');
+ });
+
+ test('should preserve existing MCP tools when server not in configs (disconnected)', async () => {
+ mockGetAllServerConfigs.mockResolvedValue({});
+
+ mockReq.user.id = existingAgentAuthorId.toString();
+ mockReq.params.id = existingAgentId;
+ mockReq.body = {
+ name: 'Edited While Disconnected',
+ tools: ['web_search', `existingTool${d}authorizedServer`],
+ };
+
+ await updateAgentHandler(mockReq, mockRes);
+
+ expect(mockRes.json).toHaveBeenCalled();
+ const updatedAgent = mockRes.json.mock.calls[0][0];
+ expect(updatedAgent.tools).toContain(`existingTool${d}authorizedServer`);
+ expect(updatedAgent.name).toBe('Edited While Disconnected');
+ });
+ });
+
+ describe('duplicateAgentHandler - MCP tool authorization', () => {
+ let sourceAgentId;
+ let sourceAgentAuthorId;
+
+ beforeEach(async () => {
+ sourceAgentAuthorId = new mongoose.Types.ObjectId();
+ const agent = await Agent.create({
+ id: `agent_${uuidv4()}`,
+ name: 'Source Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: sourceAgentAuthorId,
+ tools: ['web_search', `tool${d}authorizedServer`, `tool${d}forbiddenServer`],
+ mcpServerNames: ['authorizedServer', 'forbiddenServer'],
+ versions: [
+ {
+ name: 'Source Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ tools: ['web_search', `tool${d}authorizedServer`, `tool${d}forbiddenServer`],
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ },
+ ],
+ });
+ sourceAgentId = agent.id;
+ });
+
+ test('should strip unauthorized MCP tools from duplicated agent', async () => {
+ mockGetAllServerConfigs.mockResolvedValue({
+ authorizedServer: { type: 'sse' },
+ });
+
+ mockReq.user.id = sourceAgentAuthorId.toString();
+ mockReq.params.id = sourceAgentId;
+
+ await duplicateAgentHandler(mockReq, mockRes);
+
+ expect(mockRes.status).toHaveBeenCalledWith(201);
+ const { agent: newAgent } = mockRes.json.mock.calls[0][0];
+ expect(newAgent.id).not.toBe(sourceAgentId);
+ expect(newAgent.tools).toContain('web_search');
+ expect(newAgent.tools).toContain(`tool${d}authorizedServer`);
+ expect(newAgent.tools).not.toContain(`tool${d}forbiddenServer`);
+
+ const agentInDb = await Agent.findOne({ id: newAgent.id });
+ expect(agentInDb.mcpServerNames).toContain('authorizedServer');
+ expect(agentInDb.mcpServerNames).not.toContain('forbiddenServer');
+ });
+
+ test('should preserve source agent MCP tools when registry is unavailable', async () => {
+ getMCPServersRegistry.mockImplementation(() => {
+ throw new Error('MCPServersRegistry has not been initialized.');
+ });
+
+ mockReq.user.id = sourceAgentAuthorId.toString();
+ mockReq.params.id = sourceAgentId;
+
+ await duplicateAgentHandler(mockReq, mockRes);
+
+ expect(mockRes.status).toHaveBeenCalledWith(201);
+ const { agent: newAgent } = mockRes.json.mock.calls[0][0];
+ expect(newAgent.tools).toContain('web_search');
+ expect(newAgent.tools).toContain(`tool${d}authorizedServer`);
+ expect(newAgent.tools).toContain(`tool${d}forbiddenServer`);
+ });
+ });
+
+ describe('revertAgentVersionHandler - MCP tool authorization', () => {
+ let existingAgentId;
+ let existingAgentAuthorId;
+
+ beforeEach(async () => {
+ existingAgentAuthorId = new mongoose.Types.ObjectId();
+ const agent = await Agent.create({
+ id: `agent_${uuidv4()}`,
+ name: 'Reverted Agent V2',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: existingAgentAuthorId,
+ tools: ['web_search'],
+ versions: [
+ {
+ name: 'Reverted Agent V1',
+ provider: 'openai',
+ model: 'gpt-4',
+ tools: ['web_search', `oldTool${d}revokedServer`],
+ createdAt: new Date(Date.now() - 10000),
+ updatedAt: new Date(Date.now() - 10000),
+ },
+ {
+ name: 'Reverted Agent V2',
+ provider: 'openai',
+ model: 'gpt-4',
+ tools: ['web_search'],
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ },
+ ],
+ });
+ existingAgentId = agent.id;
+ });
+
+ test('should strip unauthorized MCP tools after reverting to a previous version', async () => {
+ mockGetAllServerConfigs.mockResolvedValue({
+ authorizedServer: { type: 'sse' },
+ });
+
+ mockReq.user.id = existingAgentAuthorId.toString();
+ mockReq.params.id = existingAgentId;
+ mockReq.body = { version_index: 0 };
+
+ await revertAgentVersionHandler(mockReq, mockRes);
+
+ expect(mockRes.json).toHaveBeenCalled();
+ const result = mockRes.json.mock.calls[0][0];
+ expect(result.tools).toContain('web_search');
+ expect(result.tools).not.toContain(`oldTool${d}revokedServer`);
+
+ const agentInDb = await Agent.findOne({ id: existingAgentId });
+ expect(agentInDb.tools).toContain('web_search');
+ expect(agentInDb.tools).not.toContain(`oldTool${d}revokedServer`);
+ });
+
+ test('should keep authorized MCP tools after revert', async () => {
+ await Agent.updateOne(
+ { id: existingAgentId },
+ { $set: { 'versions.0.tools': ['web_search', `tool${d}authorizedServer`] } },
+ );
+
+ mockReq.user.id = existingAgentAuthorId.toString();
+ mockReq.params.id = existingAgentId;
+ mockReq.body = { version_index: 0 };
+
+ await revertAgentVersionHandler(mockReq, mockRes);
+
+ expect(mockRes.json).toHaveBeenCalled();
+ const result = mockRes.json.mock.calls[0][0];
+ expect(result.tools).toContain('web_search');
+ expect(result.tools).toContain(`tool${d}authorizedServer`);
+ });
+
+ test('should preserve version MCP tools when registry is unavailable on revert', async () => {
+ await Agent.updateOne(
+ { id: existingAgentId },
+ {
+ $set: {
+ 'versions.0.tools': [
+ 'web_search',
+ `validTool${d}authorizedServer`,
+ `otherTool${d}anotherServer`,
+ ],
+ },
+ },
+ );
+
+ getMCPServersRegistry.mockImplementation(() => {
+ throw new Error('MCPServersRegistry has not been initialized.');
+ });
+
+ mockReq.user.id = existingAgentAuthorId.toString();
+ mockReq.params.id = existingAgentId;
+ mockReq.body = { version_index: 0 };
+
+ await revertAgentVersionHandler(mockReq, mockRes);
+
+ expect(mockRes.json).toHaveBeenCalled();
+ const result = mockRes.json.mock.calls[0][0];
+ expect(result.tools).toContain('web_search');
+ expect(result.tools).toContain(`validTool${d}authorizedServer`);
+ expect(result.tools).toContain(`otherTool${d}anotherServer`);
+
+ const agentInDb = await Agent.findOne({ id: existingAgentId });
+ expect(agentInDb.tools).toContain(`validTool${d}authorizedServer`);
+ expect(agentInDb.tools).toContain(`otherTool${d}anotherServer`);
+ });
+ });
+});
diff --git a/api/server/controllers/agents/openai.js b/api/server/controllers/agents/openai.js
index d4dc82174d..ae2e462103 100644
--- a/api/server/controllers/agents/openai.js
+++ b/api/server/controllers/agents/openai.js
@@ -1,12 +1,7 @@
const { nanoid } = require('nanoid');
const { logger } = require('@librechat/data-schemas');
+const { Callback, ToolEndHandler, formatAgentMessages } = require('@librechat/agents');
const { EModelEndpoint, ResourceType, PermissionBits } = require('librechat-data-provider');
-const {
- Callback,
- ToolEndHandler,
- formatAgentMessages,
- ChatModelStreamHandler,
-} = require('@librechat/agents');
const {
writeSSE,
createRun,
@@ -29,9 +24,6 @@ const {
const { loadAgentTools, loadToolsForExecution } = require('~/server/services/ToolService');
const { createToolEndCallback } = require('~/server/controllers/agents/callbacks');
const { findAccessibleResources } = require('~/server/services/PermissionService');
-const { spendTokens, spendStructuredTokens } = require('~/models/spendTokens');
-const { getConvoFiles } = require('~/models/Conversation');
-const { getAgent, getAgents } = require('~/models/Agent');
const db = require('~/models');
/**
@@ -134,7 +126,6 @@ const OpenAIChatCompletionController = async (req, res) => {
const appConfig = req.config;
const requestStartTime = Date.now();
- // Validate request
const validation = validateRequest(req.body);
if (isChatCompletionValidationFailure(validation)) {
return sendErrorResponse(res, 400, validation.error);
@@ -144,7 +135,7 @@ const OpenAIChatCompletionController = async (req, res) => {
const agentId = request.model;
// Look up the agent
- const agent = await getAgent({ id: agentId });
+ const agent = await db.getAgent({ id: agentId });
if (!agent) {
return sendErrorResponse(
res,
@@ -155,20 +146,18 @@ const OpenAIChatCompletionController = async (req, res) => {
);
}
- // Generate IDs
- const requestId = `chatcmpl-${nanoid()}`;
- const conversationId = request.conversation_id ?? nanoid();
- const parentMessageId = request.parent_message_id ?? null;
+ const responseId = `chatcmpl-${nanoid()}`;
const created = Math.floor(Date.now() / 1000);
+ /** @type {import('@librechat/api').OpenAIResponseContext} — key must be `requestId` to match the type used by createChunk/buildNonStreamingResponse */
const context = {
created,
- requestId,
+ requestId: responseId,
model: agentId,
};
logger.debug(
- `[OpenAI API] Request ${requestId} started for agent ${agentId}, stream: ${request.stream}`,
+ `[OpenAI API] Response ${responseId} started for agent ${agentId}, stream: ${request.stream}`,
);
// Set up abort controller
@@ -183,6 +172,23 @@ const OpenAIChatCompletionController = async (req, res) => {
});
try {
+ if (request.conversation_id != null) {
+ if (typeof request.conversation_id !== 'string') {
+ return sendErrorResponse(
+ res,
+ 400,
+ 'conversation_id must be a string',
+ 'invalid_request_error',
+ );
+ }
+ if (!(await getConvo(req.user?.id, request.conversation_id))) {
+ return sendErrorResponse(res, 404, 'Conversation not found', 'invalid_request_error');
+ }
+ }
+
+ const conversationId = request.conversation_id ?? nanoid();
+ const parentMessageId = request.parent_message_id ?? null;
+
// Build allowed providers set
const allowedProviders = new Set(
appConfig?.endpoints?.[EModelEndpoint.agents]?.allowedProviders,
@@ -211,7 +217,7 @@ const OpenAIChatCompletionController = async (req, res) => {
isInitialAgent: true,
},
{
- getConvoFiles,
+ getConvoFiles: db.getConvoFiles,
getFiles: db.getFiles,
getUserKey: db.getUserKey,
getMessages: db.getMessages,
@@ -270,6 +276,7 @@ const OpenAIChatCompletionController = async (req, res) => {
toolRegistry: primaryConfig.toolRegistry,
userMCPAuthMap: primaryConfig.userMCPAuthMap,
tool_resources: primaryConfig.tool_resources,
+ actionsEnabled: primaryConfig.actionsEnabled,
});
},
toolEndCallback,
@@ -325,18 +332,8 @@ const OpenAIChatCompletionController = async (req, res) => {
}
};
- // Built-in handler for processing raw model stream chunks
- const chatModelStreamHandler = new ChatModelStreamHandler();
-
// Event handlers for OpenAI-compatible streaming
const handlers = {
- // Process raw model chunks and dispatch message/reasoning deltas
- on_chat_model_stream: {
- handle: async (event, data, metadata, graph) => {
- await chatModelStreamHandler.handle(event, data, metadata, graph);
- },
- },
-
// Text content streaming
on_message_delta: createHandler((data) => {
const content = data?.delta?.content;
@@ -465,11 +462,11 @@ const OpenAIChatCompletionController = async (req, res) => {
agents: [primaryConfig],
messages: formattedMessages,
indexTokenCountMap,
- runId: requestId,
+ runId: responseId,
signal: abortController.signal,
customHandlers: handlers,
requestBody: {
- messageId: requestId,
+ messageId: responseId,
conversationId,
},
user: { id: userId },
@@ -486,6 +483,10 @@ const OpenAIChatCompletionController = async (req, res) => {
thread_id: conversationId,
user_id: userId,
user: createSafeUser(req.user),
+ requestBody: {
+ messageId: responseId,
+ conversationId,
+ },
...(userMCPAuthMap != null && { userMCPAuthMap }),
},
signal: abortController.signal,
@@ -505,12 +506,18 @@ const OpenAIChatCompletionController = async (req, res) => {
const balanceConfig = getBalanceConfig(appConfig);
const transactionsConfig = getTransactionsConfig(appConfig);
recordCollectedUsage(
- { spendTokens, spendStructuredTokens },
+ {
+ spendTokens: db.spendTokens,
+ spendStructuredTokens: db.spendStructuredTokens,
+ pricing: { getMultiplier: db.getMultiplier, getCacheMultiplier: db.getCacheMultiplier },
+ bulkWriteOps: { insertMany: db.bulkInsertTransactions, updateBalance: db.updateBalance },
+ },
{
user: userId,
conversationId,
collectedUsage,
context: 'message',
+ messageId: responseId,
balance: balanceConfig,
transactions: transactionsConfig,
model: primaryConfig.model || agent.model_parameters?.model,
@@ -524,7 +531,7 @@ const OpenAIChatCompletionController = async (req, res) => {
if (isStreaming) {
sendFinalChunk(handlerConfig);
res.end();
- logger.debug(`[OpenAI API] Request ${requestId} completed in ${duration}ms (streaming)`);
+ logger.debug(`[OpenAI API] Response ${responseId} completed in ${duration}ms (streaming)`);
// Wait for artifact processing after response ends (non-blocking)
if (artifactPromises.length > 0) {
@@ -563,7 +570,9 @@ const OpenAIChatCompletionController = async (req, res) => {
usage,
);
res.json(response);
- logger.debug(`[OpenAI API] Request ${requestId} completed in ${duration}ms (non-streaming)`);
+ logger.debug(
+ `[OpenAI API] Response ${responseId} completed in ${duration}ms (non-streaming)`,
+ );
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'An error occurred';
@@ -577,7 +586,14 @@ const OpenAIChatCompletionController = async (req, res) => {
writeSSE(res, '[DONE]');
res.end();
} else {
- sendErrorResponse(res, 500, errorMessage, 'server_error');
+ // Forward upstream provider status codes (e.g., Anthropic 400s) instead of masking as 500
+ const statusCode =
+ typeof error?.status === 'number' && error.status >= 400 && error.status < 600
+ ? error.status
+ : 500;
+ const errorType =
+ statusCode >= 400 && statusCode < 500 ? 'invalid_request_error' : 'server_error';
+ sendErrorResponse(res, statusCode, errorMessage, errorType);
}
}
};
@@ -607,7 +623,7 @@ const ListModelsController = async (req, res) => {
// Get the accessible agents
let agents = [];
if (accessibleAgentIds.length > 0) {
- agents = await getAgents({ _id: { $in: accessibleAgentIds } });
+ agents = await db.getAgents({ _id: { $in: accessibleAgentIds } });
}
const models = agents.map((agent) => ({
@@ -650,7 +666,7 @@ const GetModelController = async (req, res) => {
return sendErrorResponse(res, 401, 'Authentication required', 'auth_error');
}
- const agent = await getAgent({ id: model });
+ const agent = await db.getAgent({ id: model });
if (!agent) {
return sendErrorResponse(
diff --git a/api/server/controllers/agents/recordCollectedUsage.spec.js b/api/server/controllers/agents/recordCollectedUsage.spec.js
index 6904f2ed39..009c5b262c 100644
--- a/api/server/controllers/agents/recordCollectedUsage.spec.js
+++ b/api/server/controllers/agents/recordCollectedUsage.spec.js
@@ -2,21 +2,29 @@
* Tests for AgentClient.recordCollectedUsage
*
* This is a critical function that handles token spending for agent LLM calls.
- * It must correctly handle:
- * - Sequential execution (single agent with tool calls)
- * - Parallel execution (multiple agents with independent inputs)
- * - Cache token handling (OpenAI and Anthropic formats)
+ * The client now delegates to the TS recordCollectedUsage from @librechat/api,
+ * passing pricing and bulkWriteOps deps.
*/
const { EModelEndpoint } = require('librechat-data-provider');
-// Mock dependencies before requiring the module
const mockSpendTokens = jest.fn().mockResolvedValue();
const mockSpendStructuredTokens = jest.fn().mockResolvedValue();
+const mockGetMultiplier = jest.fn().mockReturnValue(1);
+const mockGetCacheMultiplier = jest.fn().mockReturnValue(null);
+const mockUpdateBalance = jest.fn().mockResolvedValue({});
+const mockBulkInsertTransactions = jest.fn().mockResolvedValue(undefined);
+const mockRecordCollectedUsage = jest
+ .fn()
+ .mockResolvedValue({ input_tokens: 100, output_tokens: 50 });
-jest.mock('~/models/spendTokens', () => ({
+jest.mock('~/models', () => ({
spendTokens: (...args) => mockSpendTokens(...args),
spendStructuredTokens: (...args) => mockSpendStructuredTokens(...args),
+ getMultiplier: mockGetMultiplier,
+ getCacheMultiplier: mockGetCacheMultiplier,
+ updateBalance: mockUpdateBalance,
+ bulkInsertTransactions: mockBulkInsertTransactions,
}));
jest.mock('~/config', () => ({
@@ -39,6 +47,14 @@ jest.mock('@librechat/agents', () => ({
}),
}));
+jest.mock('@librechat/api', () => {
+ const actual = jest.requireActual('@librechat/api');
+ return {
+ ...actual,
+ recordCollectedUsage: (...args) => mockRecordCollectedUsage(...args),
+ };
+});
+
const AgentClient = require('./client');
describe('AgentClient - recordCollectedUsage', () => {
@@ -74,31 +90,66 @@ describe('AgentClient - recordCollectedUsage', () => {
});
describe('basic functionality', () => {
- it('should return early if collectedUsage is empty', async () => {
+ it('should delegate to recordCollectedUsage with full deps', async () => {
+ const collectedUsage = [{ input_tokens: 100, output_tokens: 50, model: 'gpt-4' }];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ expect(mockRecordCollectedUsage).toHaveBeenCalledTimes(1);
+ const [deps, params] = mockRecordCollectedUsage.mock.calls[0];
+
+ expect(deps).toHaveProperty('spendTokens');
+ expect(deps).toHaveProperty('spendStructuredTokens');
+ expect(deps).toHaveProperty('pricing');
+ expect(deps.pricing).toHaveProperty('getMultiplier');
+ expect(deps.pricing).toHaveProperty('getCacheMultiplier');
+ expect(deps).toHaveProperty('bulkWriteOps');
+ expect(deps.bulkWriteOps).toHaveProperty('insertMany');
+ expect(deps.bulkWriteOps).toHaveProperty('updateBalance');
+
+ expect(params).toEqual(
+ expect.objectContaining({
+ user: 'user-123',
+ conversationId: 'convo-123',
+ collectedUsage,
+ context: 'message',
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ }),
+ );
+ });
+
+ it('should not set this.usage if collectedUsage is empty (returns undefined)', async () => {
+ mockRecordCollectedUsage.mockResolvedValue(undefined);
+
await client.recordCollectedUsage({
collectedUsage: [],
balance: { enabled: true },
transactions: { enabled: true },
});
- expect(mockSpendTokens).not.toHaveBeenCalled();
- expect(mockSpendStructuredTokens).not.toHaveBeenCalled();
expect(client.usage).toBeUndefined();
});
- it('should return early if collectedUsage is null', async () => {
+ it('should not set this.usage if collectedUsage is null (returns undefined)', async () => {
+ mockRecordCollectedUsage.mockResolvedValue(undefined);
+
await client.recordCollectedUsage({
collectedUsage: null,
balance: { enabled: true },
transactions: { enabled: true },
});
- expect(mockSpendTokens).not.toHaveBeenCalled();
expect(client.usage).toBeUndefined();
});
- it('should handle single usage entry correctly', async () => {
- const collectedUsage = [{ input_tokens: 100, output_tokens: 50, model: 'gpt-4' }];
+ it('should set this.usage from recordCollectedUsage result', async () => {
+ mockRecordCollectedUsage.mockResolvedValue({ input_tokens: 200, output_tokens: 75 });
+ const collectedUsage = [{ input_tokens: 200, output_tokens: 75, model: 'gpt-4' }];
await client.recordCollectedUsage({
collectedUsage,
@@ -106,521 +157,122 @@ describe('AgentClient - recordCollectedUsage', () => {
transactions: { enabled: true },
});
- expect(mockSpendTokens).toHaveBeenCalledTimes(1);
- expect(mockSpendTokens).toHaveBeenCalledWith(
- expect.objectContaining({
- conversationId: 'convo-123',
- user: 'user-123',
- model: 'gpt-4',
- }),
- { promptTokens: 100, completionTokens: 50 },
- );
- expect(client.usage.input_tokens).toBe(100);
- expect(client.usage.output_tokens).toBe(50);
- });
-
- it('should skip null entries in collectedUsage', async () => {
- const collectedUsage = [
- { input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
- null,
- { input_tokens: 200, output_tokens: 60, model: 'gpt-4' },
- ];
-
- await client.recordCollectedUsage({
- collectedUsage,
- balance: { enabled: true },
- transactions: { enabled: true },
- });
-
- expect(mockSpendTokens).toHaveBeenCalledTimes(2);
+ expect(client.usage).toEqual({ input_tokens: 200, output_tokens: 75 });
});
});
describe('sequential execution (single agent with tool calls)', () => {
- it('should calculate tokens correctly for sequential tool calls', async () => {
- // Sequential flow: output of call N becomes part of input for call N+1
- // Call 1: input=100, output=50
- // Call 2: input=150 (100+50), output=30
- // Call 3: input=180 (150+30), output=20
+ it('should pass all usage entries to recordCollectedUsage', async () => {
const collectedUsage = [
{ input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
{ input_tokens: 150, output_tokens: 30, model: 'gpt-4' },
{ input_tokens: 180, output_tokens: 20, model: 'gpt-4' },
];
+ mockRecordCollectedUsage.mockResolvedValue({ input_tokens: 100, output_tokens: 100 });
+
await client.recordCollectedUsage({
collectedUsage,
balance: { enabled: true },
transactions: { enabled: true },
});
- expect(mockSpendTokens).toHaveBeenCalledTimes(3);
- // Total output should be sum of all output_tokens: 50 + 30 + 20 = 100
+ expect(mockRecordCollectedUsage).toHaveBeenCalledTimes(1);
+ const [, params] = mockRecordCollectedUsage.mock.calls[0];
+ expect(params.collectedUsage).toHaveLength(3);
expect(client.usage.output_tokens).toBe(100);
- expect(client.usage.input_tokens).toBe(100); // First entry's input
+ expect(client.usage.input_tokens).toBe(100);
});
});
describe('parallel execution (multiple agents)', () => {
- it('should handle parallel agents with independent input tokens', async () => {
- // Parallel agents have INDEPENDENT input tokens (not cumulative)
- // Agent A: input=100, output=50
- // Agent B: input=80, output=40 (different context, not 100+50)
+ it('should pass parallel agent usage to recordCollectedUsage', async () => {
const collectedUsage = [
{ input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
{ input_tokens: 80, output_tokens: 40, model: 'gpt-4' },
];
+ mockRecordCollectedUsage.mockResolvedValue({ input_tokens: 100, output_tokens: 90 });
+
await client.recordCollectedUsage({
collectedUsage,
balance: { enabled: true },
transactions: { enabled: true },
});
- expect(mockSpendTokens).toHaveBeenCalledTimes(2);
- // Expected total output: 50 + 40 = 90
- // output_tokens must be positive and should reflect total output
+ expect(mockRecordCollectedUsage).toHaveBeenCalledTimes(1);
+ expect(client.usage.output_tokens).toBe(90);
expect(client.usage.output_tokens).toBeGreaterThan(0);
});
- it('should NOT produce negative output_tokens for parallel execution', async () => {
- // Critical bug scenario: parallel agents where second agent has LOWER input tokens
+ /** Bug regression: parallel agents where second agent has LOWER input tokens produced negative output via incremental calculation. */
+ it('should NOT produce negative output_tokens', async () => {
const collectedUsage = [
{ input_tokens: 200, output_tokens: 100, model: 'gpt-4' },
{ input_tokens: 50, output_tokens: 30, model: 'gpt-4' },
];
+ mockRecordCollectedUsage.mockResolvedValue({ input_tokens: 200, output_tokens: 130 });
+
await client.recordCollectedUsage({
collectedUsage,
balance: { enabled: true },
transactions: { enabled: true },
});
- // output_tokens MUST be positive for proper token tracking
expect(client.usage.output_tokens).toBeGreaterThan(0);
- // Correct value should be 100 + 30 = 130
- });
-
- it('should calculate correct total output for parallel agents', async () => {
- // Three parallel agents with independent contexts
- const collectedUsage = [
- { input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
- { input_tokens: 120, output_tokens: 60, model: 'gpt-4-turbo' },
- { input_tokens: 80, output_tokens: 40, model: 'claude-3' },
- ];
-
- await client.recordCollectedUsage({
- collectedUsage,
- balance: { enabled: true },
- transactions: { enabled: true },
- });
-
- expect(mockSpendTokens).toHaveBeenCalledTimes(3);
- // Total output should be 50 + 60 + 40 = 150
- expect(client.usage.output_tokens).toBe(150);
- });
-
- it('should handle worst-case parallel scenario without negative tokens', async () => {
- // Extreme case: first agent has very high input, subsequent have low
- const collectedUsage = [
- { input_tokens: 1000, output_tokens: 500, model: 'gpt-4' },
- { input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
- { input_tokens: 50, output_tokens: 25, model: 'gpt-4' },
- ];
-
- await client.recordCollectedUsage({
- collectedUsage,
- balance: { enabled: true },
- transactions: { enabled: true },
- });
-
- // Must be positive, should be 500 + 50 + 25 = 575
- expect(client.usage.output_tokens).toBeGreaterThan(0);
- expect(client.usage.output_tokens).toBe(575);
+ expect(client.usage.output_tokens).toBe(130);
});
});
describe('real-world scenarios', () => {
- it('should correctly sum output tokens for sequential tool calls with growing context', async () => {
- // Real production data: Claude Opus with multiple tool calls
- // Context grows as tool results are added, but output_tokens should only count model generations
+ it('should correctly handle sequential tool calls with growing context', async () => {
const collectedUsage = [
- {
- input_tokens: 31596,
- output_tokens: 151,
- total_tokens: 31747,
- input_token_details: { cache_read: 0, cache_creation: 0 },
- model: 'claude-opus-4-5-20251101',
- },
- {
- input_tokens: 35368,
- output_tokens: 150,
- total_tokens: 35518,
- input_token_details: { cache_read: 0, cache_creation: 0 },
- model: 'claude-opus-4-5-20251101',
- },
- {
- input_tokens: 58362,
- output_tokens: 295,
- total_tokens: 58657,
- input_token_details: { cache_read: 0, cache_creation: 0 },
- model: 'claude-opus-4-5-20251101',
- },
- {
- input_tokens: 112604,
- output_tokens: 193,
- total_tokens: 112797,
- input_token_details: { cache_read: 0, cache_creation: 0 },
- model: 'claude-opus-4-5-20251101',
- },
- {
- input_tokens: 257440,
- output_tokens: 2217,
- total_tokens: 259657,
- input_token_details: { cache_read: 0, cache_creation: 0 },
- model: 'claude-opus-4-5-20251101',
- },
+ { input_tokens: 31596, output_tokens: 151, model: 'claude-opus-4-5-20251101' },
+ { input_tokens: 35368, output_tokens: 150, model: 'claude-opus-4-5-20251101' },
+ { input_tokens: 58362, output_tokens: 295, model: 'claude-opus-4-5-20251101' },
+ { input_tokens: 112604, output_tokens: 193, model: 'claude-opus-4-5-20251101' },
+ { input_tokens: 257440, output_tokens: 2217, model: 'claude-opus-4-5-20251101' },
];
+ mockRecordCollectedUsage.mockResolvedValue({ input_tokens: 31596, output_tokens: 3006 });
+
await client.recordCollectedUsage({
collectedUsage,
balance: { enabled: true },
transactions: { enabled: true },
});
- // input_tokens should be first entry's input (initial context)
expect(client.usage.input_tokens).toBe(31596);
-
- // output_tokens should be sum of all model outputs: 151 + 150 + 295 + 193 + 2217 = 3006
- // NOT the inflated value from incremental calculation (338,559)
expect(client.usage.output_tokens).toBe(3006);
-
- // Verify spendTokens was called for each entry with correct values
- expect(mockSpendTokens).toHaveBeenCalledTimes(5);
- expect(mockSpendTokens).toHaveBeenNthCalledWith(
- 1,
- expect.objectContaining({ model: 'claude-opus-4-5-20251101' }),
- { promptTokens: 31596, completionTokens: 151 },
- );
- expect(mockSpendTokens).toHaveBeenNthCalledWith(
- 5,
- expect.objectContaining({ model: 'claude-opus-4-5-20251101' }),
- { promptTokens: 257440, completionTokens: 2217 },
- );
});
- it('should handle single followup message correctly', async () => {
- // Real production data: followup to the above conversation
- const collectedUsage = [
- {
- input_tokens: 263406,
- output_tokens: 257,
- total_tokens: 263663,
- input_token_details: { cache_read: 0, cache_creation: 0 },
- model: 'claude-opus-4-5-20251101',
- },
- ];
-
- await client.recordCollectedUsage({
- collectedUsage,
- balance: { enabled: true },
- transactions: { enabled: true },
- });
-
- expect(client.usage.input_tokens).toBe(263406);
- expect(client.usage.output_tokens).toBe(257);
-
- expect(mockSpendTokens).toHaveBeenCalledTimes(1);
- expect(mockSpendTokens).toHaveBeenCalledWith(
- expect.objectContaining({ model: 'claude-opus-4-5-20251101' }),
- { promptTokens: 263406, completionTokens: 257 },
- );
- });
-
- it('should ensure output_tokens > 0 check passes for BaseClient.sendMessage', async () => {
- // This verifies the fix for the duplicate token spending bug
- // BaseClient.sendMessage checks: if (usage != null && Number(usage[this.outputTokensKey]) > 0)
- const collectedUsage = [
- {
- input_tokens: 31596,
- output_tokens: 151,
- model: 'claude-opus-4-5-20251101',
- },
- {
- input_tokens: 35368,
- output_tokens: 150,
- model: 'claude-opus-4-5-20251101',
- },
- ];
-
- await client.recordCollectedUsage({
- collectedUsage,
- balance: { enabled: true },
- transactions: { enabled: true },
- });
-
- const usage = client.getStreamUsage();
-
- // The check that was failing before the fix
- expect(usage).not.toBeNull();
- expect(Number(usage.output_tokens)).toBeGreaterThan(0);
-
- // Verify correct value
- expect(usage.output_tokens).toBe(301); // 151 + 150
- });
-
- it('should correctly handle cache tokens with multiple tool calls', async () => {
- // Real production data: Claude Opus with cache tokens (prompt caching)
- // First entry has cache_creation, subsequent entries have cache_read
+ it('should correctly handle cache tokens', async () => {
const collectedUsage = [
{
input_tokens: 788,
output_tokens: 163,
- total_tokens: 951,
input_token_details: { cache_read: 0, cache_creation: 30808 },
model: 'claude-opus-4-5-20251101',
},
- {
- input_tokens: 3802,
- output_tokens: 149,
- total_tokens: 3951,
- input_token_details: { cache_read: 30808, cache_creation: 768 },
- model: 'claude-opus-4-5-20251101',
- },
- {
- input_tokens: 26808,
- output_tokens: 225,
- total_tokens: 27033,
- input_token_details: { cache_read: 31576, cache_creation: 0 },
- model: 'claude-opus-4-5-20251101',
- },
- {
- input_tokens: 80912,
- output_tokens: 204,
- total_tokens: 81116,
- input_token_details: { cache_read: 31576, cache_creation: 0 },
- model: 'claude-opus-4-5-20251101',
- },
- {
- input_tokens: 136454,
- output_tokens: 206,
- total_tokens: 136660,
- input_token_details: { cache_read: 31576, cache_creation: 0 },
- model: 'claude-opus-4-5-20251101',
- },
- {
- input_tokens: 146316,
- output_tokens: 224,
- total_tokens: 146540,
- input_token_details: { cache_read: 31576, cache_creation: 0 },
- model: 'claude-opus-4-5-20251101',
- },
- {
- input_tokens: 150402,
- output_tokens: 1248,
- total_tokens: 151650,
- input_token_details: { cache_read: 31576, cache_creation: 0 },
- model: 'claude-opus-4-5-20251101',
- },
- {
- input_tokens: 156268,
- output_tokens: 139,
- total_tokens: 156407,
- input_token_details: { cache_read: 31576, cache_creation: 0 },
- model: 'claude-opus-4-5-20251101',
- },
- {
- input_tokens: 167126,
- output_tokens: 2961,
- total_tokens: 170087,
- input_token_details: { cache_read: 31576, cache_creation: 0 },
- model: 'claude-opus-4-5-20251101',
- },
];
+ mockRecordCollectedUsage.mockResolvedValue({ input_tokens: 31596, output_tokens: 163 });
+
await client.recordCollectedUsage({
collectedUsage,
balance: { enabled: true },
transactions: { enabled: true },
});
- // input_tokens = first entry's input + cache_creation + cache_read
- // = 788 + 30808 + 0 = 31596
expect(client.usage.input_tokens).toBe(31596);
-
- // output_tokens = sum of all output_tokens
- // = 163 + 149 + 225 + 204 + 206 + 224 + 1248 + 139 + 2961 = 5519
- expect(client.usage.output_tokens).toBe(5519);
-
- // First 2 entries have cache tokens, should use spendStructuredTokens
- // Remaining 7 entries have cache_read but no cache_creation, still structured
- expect(mockSpendStructuredTokens).toHaveBeenCalledTimes(9);
- expect(mockSpendTokens).toHaveBeenCalledTimes(0);
-
- // Verify first entry uses structured tokens with cache_creation
- expect(mockSpendStructuredTokens).toHaveBeenNthCalledWith(
- 1,
- expect.objectContaining({ model: 'claude-opus-4-5-20251101' }),
- {
- promptTokens: { input: 788, write: 30808, read: 0 },
- completionTokens: 163,
- },
- );
-
- // Verify second entry uses structured tokens with both cache_creation and cache_read
- expect(mockSpendStructuredTokens).toHaveBeenNthCalledWith(
- 2,
- expect.objectContaining({ model: 'claude-opus-4-5-20251101' }),
- {
- promptTokens: { input: 3802, write: 768, read: 30808 },
- completionTokens: 149,
- },
- );
- });
- });
-
- describe('cache token handling', () => {
- it('should handle OpenAI format cache tokens (input_token_details)', async () => {
- const collectedUsage = [
- {
- input_tokens: 100,
- output_tokens: 50,
- model: 'gpt-4',
- input_token_details: {
- cache_creation: 20,
- cache_read: 10,
- },
- },
- ];
-
- await client.recordCollectedUsage({
- collectedUsage,
- balance: { enabled: true },
- transactions: { enabled: true },
- });
-
- expect(mockSpendStructuredTokens).toHaveBeenCalledTimes(1);
- expect(mockSpendStructuredTokens).toHaveBeenCalledWith(
- expect.objectContaining({ model: 'gpt-4' }),
- {
- promptTokens: {
- input: 100,
- write: 20,
- read: 10,
- },
- completionTokens: 50,
- },
- );
- });
-
- it('should handle Anthropic format cache tokens (cache_*_input_tokens)', async () => {
- const collectedUsage = [
- {
- input_tokens: 100,
- output_tokens: 50,
- model: 'claude-3',
- cache_creation_input_tokens: 25,
- cache_read_input_tokens: 15,
- },
- ];
-
- await client.recordCollectedUsage({
- collectedUsage,
- balance: { enabled: true },
- transactions: { enabled: true },
- });
-
- expect(mockSpendStructuredTokens).toHaveBeenCalledTimes(1);
- expect(mockSpendStructuredTokens).toHaveBeenCalledWith(
- expect.objectContaining({ model: 'claude-3' }),
- {
- promptTokens: {
- input: 100,
- write: 25,
- read: 15,
- },
- completionTokens: 50,
- },
- );
- });
-
- it('should use spendTokens for entries without cache tokens', async () => {
- const collectedUsage = [{ input_tokens: 100, output_tokens: 50, model: 'gpt-4' }];
-
- await client.recordCollectedUsage({
- collectedUsage,
- balance: { enabled: true },
- transactions: { enabled: true },
- });
-
- expect(mockSpendTokens).toHaveBeenCalledTimes(1);
- expect(mockSpendStructuredTokens).not.toHaveBeenCalled();
- });
-
- it('should handle mixed cache and non-cache entries', async () => {
- const collectedUsage = [
- { input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
- {
- input_tokens: 150,
- output_tokens: 30,
- model: 'gpt-4',
- input_token_details: { cache_creation: 10, cache_read: 5 },
- },
- { input_tokens: 200, output_tokens: 20, model: 'gpt-4' },
- ];
-
- await client.recordCollectedUsage({
- collectedUsage,
- balance: { enabled: true },
- transactions: { enabled: true },
- });
-
- expect(mockSpendTokens).toHaveBeenCalledTimes(2);
- expect(mockSpendStructuredTokens).toHaveBeenCalledTimes(1);
- });
-
- it('should include cache tokens in total input calculation', async () => {
- const collectedUsage = [
- {
- input_tokens: 100,
- output_tokens: 50,
- model: 'gpt-4',
- input_token_details: {
- cache_creation: 20,
- cache_read: 10,
- },
- },
- ];
-
- await client.recordCollectedUsage({
- collectedUsage,
- balance: { enabled: true },
- transactions: { enabled: true },
- });
-
- // Total input should include cache tokens: 100 + 20 + 10 = 130
- expect(client.usage.input_tokens).toBe(130);
+ expect(client.usage.output_tokens).toBe(163);
});
});
describe('model fallback', () => {
- it('should use usage.model when available', async () => {
- const collectedUsage = [{ input_tokens: 100, output_tokens: 50, model: 'gpt-4-turbo' }];
-
- await client.recordCollectedUsage({
- model: 'fallback-model',
- collectedUsage,
- balance: { enabled: true },
- transactions: { enabled: true },
- });
-
- expect(mockSpendTokens).toHaveBeenCalledWith(
- expect.objectContaining({ model: 'gpt-4-turbo' }),
- expect.any(Object),
- );
- });
-
- it('should fallback to param model when usage.model is missing', async () => {
+ it('should use param model when available', async () => {
+ mockRecordCollectedUsage.mockResolvedValue({ input_tokens: 100, output_tokens: 50 });
const collectedUsage = [{ input_tokens: 100, output_tokens: 50 }];
await client.recordCollectedUsage({
@@ -630,14 +282,13 @@ describe('AgentClient - recordCollectedUsage', () => {
transactions: { enabled: true },
});
- expect(mockSpendTokens).toHaveBeenCalledWith(
- expect.objectContaining({ model: 'param-model' }),
- expect.any(Object),
- );
+ const [, params] = mockRecordCollectedUsage.mock.calls[0];
+ expect(params.model).toBe('param-model');
});
it('should fallback to client.model when param model is missing', async () => {
client.model = 'client-model';
+ mockRecordCollectedUsage.mockResolvedValue({ input_tokens: 100, output_tokens: 50 });
const collectedUsage = [{ input_tokens: 100, output_tokens: 50 }];
await client.recordCollectedUsage({
@@ -646,13 +297,12 @@ describe('AgentClient - recordCollectedUsage', () => {
transactions: { enabled: true },
});
- expect(mockSpendTokens).toHaveBeenCalledWith(
- expect.objectContaining({ model: 'client-model' }),
- expect.any(Object),
- );
+ const [, params] = mockRecordCollectedUsage.mock.calls[0];
+ expect(params.model).toBe('client-model');
});
it('should fallback to agent model_parameters.model as last resort', async () => {
+ mockRecordCollectedUsage.mockResolvedValue({ input_tokens: 100, output_tokens: 50 });
const collectedUsage = [{ input_tokens: 100, output_tokens: 50 }];
await client.recordCollectedUsage({
@@ -661,15 +311,14 @@ describe('AgentClient - recordCollectedUsage', () => {
transactions: { enabled: true },
});
- expect(mockSpendTokens).toHaveBeenCalledWith(
- expect.objectContaining({ model: 'gpt-4' }),
- expect.any(Object),
- );
+ const [, params] = mockRecordCollectedUsage.mock.calls[0];
+ expect(params.model).toBe('gpt-4');
});
});
describe('getStreamUsage integration', () => {
it('should return the usage object set by recordCollectedUsage', async () => {
+ mockRecordCollectedUsage.mockResolvedValue({ input_tokens: 100, output_tokens: 50 });
const collectedUsage = [{ input_tokens: 100, output_tokens: 50, model: 'gpt-4' }];
await client.recordCollectedUsage({
@@ -679,10 +328,7 @@ describe('AgentClient - recordCollectedUsage', () => {
});
const usage = client.getStreamUsage();
- expect(usage).toEqual({
- input_tokens: 100,
- output_tokens: 50,
- });
+ expect(usage).toEqual({ input_tokens: 100, output_tokens: 50 });
});
it('should return undefined before recordCollectedUsage is called', () => {
@@ -690,9 +336,9 @@ describe('AgentClient - recordCollectedUsage', () => {
expect(usage).toBeUndefined();
});
+ /** Verifies usage passes the check in BaseClient.sendMessage: if (usage != null && Number(usage[this.outputTokensKey]) > 0) */
it('should have output_tokens > 0 for BaseClient.sendMessage check', async () => {
- // This test verifies the usage will pass the check in BaseClient.sendMessage:
- // if (usage != null && Number(usage[this.outputTokensKey]) > 0)
+ mockRecordCollectedUsage.mockResolvedValue({ input_tokens: 200, output_tokens: 130 });
const collectedUsage = [
{ input_tokens: 200, output_tokens: 100, model: 'gpt-4' },
{ input_tokens: 50, output_tokens: 30, model: 'gpt-4' },
diff --git a/api/server/controllers/agents/request.js b/api/server/controllers/agents/request.js
index 79387b6e89..6f7e1b88c1 100644
--- a/api/server/controllers/agents/request.js
+++ b/api/server/controllers/agents/request.js
@@ -3,9 +3,9 @@ const { Constants, ViolationTypes } = require('librechat-data-provider');
const {
sendEvent,
getViolationInfo,
+ buildMessageFiles,
GenerationJobManager,
decrementPendingRequest,
- sanitizeFileForTransmit,
sanitizeMessageForTransmit,
checkAndIncrementPendingRequest,
} = require('@librechat/api');
@@ -131,9 +131,15 @@ const ResumableAgentController = async (req, res, next, initializeClient, addTit
partialMessage.agent_id = req.body.agent_id;
}
- await saveMessage(req, partialMessage, {
- context: 'api/server/controllers/agents/request.js - partial response on disconnect',
- });
+ await saveMessage(
+ {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ },
+ partialMessage,
+ { context: 'api/server/controllers/agents/request.js - partial response on disconnect' },
+ );
logger.debug(
`[ResumableAgentController] Saved partial response for ${streamId}, content parts: ${aggregatedContent.length}`,
@@ -252,13 +258,10 @@ const ResumableAgentController = async (req, res, next, initializeClient, addTit
conversation.title =
conversation && !conversation.title ? null : conversation?.title || 'New Chat';
- if (req.body.files && client.options?.attachments) {
- userMessage.files = [];
- const messageFiles = new Set(req.body.files.map((file) => file.file_id));
- for (const attachment of client.options.attachments) {
- if (messageFiles.has(attachment.file_id)) {
- userMessage.files.push(sanitizeFileForTransmit(attachment));
- }
+ if (req.body.files && Array.isArray(client.options.attachments)) {
+ const files = buildMessageFiles(req.body.files, client.options.attachments);
+ if (files.length > 0) {
+ userMessage.files = files;
}
delete userMessage.image_urls;
}
@@ -274,8 +277,14 @@ const ResumableAgentController = async (req, res, next, initializeClient, addTit
// Save user message BEFORE sending final event to avoid race condition
// where client refetch happens before database is updated
+ const reqCtx = {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ };
+
if (!client.skipSaveUserMessage && userMessage) {
- await saveMessage(req, userMessage, {
+ await saveMessage(reqCtx, userMessage, {
context: 'api/server/controllers/agents/request.js - resumable user message',
});
}
@@ -285,7 +294,7 @@ const ResumableAgentController = async (req, res, next, initializeClient, addTit
// before the response is saved to the database, causing orphaned parentMessageIds.
if (client.savedMessageIds && !client.savedMessageIds.has(messageId)) {
await saveMessage(
- req,
+ reqCtx,
{ ...response, user: userId, unfinished: wasAbortedBeforeComplete },
{ context: 'api/server/controllers/agents/request.js - resumable response end' },
);
@@ -639,14 +648,10 @@ const _LegacyAgentController = async (req, res, next, initializeClient, addTitle
conversation.title =
conversation && !conversation.title ? null : conversation?.title || 'New Chat';
- // Process files if needed (sanitize to remove large text fields before transmission)
- if (req.body.files && client.options?.attachments) {
- userMessage.files = [];
- const messageFiles = new Set(req.body.files.map((file) => file.file_id));
- for (const attachment of client.options.attachments) {
- if (messageFiles.has(attachment.file_id)) {
- userMessage.files.push(sanitizeFileForTransmit(attachment));
- }
+ if (req.body.files && Array.isArray(client.options.attachments)) {
+ const files = buildMessageFiles(req.body.files, client.options.attachments);
+ if (files.length > 0) {
+ userMessage.files = files;
}
delete userMessage.image_urls;
}
@@ -668,7 +673,11 @@ const _LegacyAgentController = async (req, res, next, initializeClient, addTitle
// Save the message if needed
if (client.savedMessageIds && !client.savedMessageIds.has(messageId)) {
await saveMessage(
- req,
+ {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ },
{ ...finalResponse, user: userId },
{ context: 'api/server/controllers/agents/request.js - response end' },
);
@@ -697,9 +706,15 @@ const _LegacyAgentController = async (req, res, next, initializeClient, addTitle
// Save user message if needed
if (!client.skipSaveUserMessage) {
- await saveMessage(req, userMessage, {
- context: "api/server/controllers/agents/request.js - don't skip saving user message",
- });
+ await saveMessage(
+ {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ },
+ userMessage,
+ { context: "api/server/controllers/agents/request.js - don't skip saving user message" },
+ );
}
// Add title if needed - extract minimal data
diff --git a/api/server/controllers/agents/responses.js b/api/server/controllers/agents/responses.js
index 3cd1dff5eb..62cedb14fd 100644
--- a/api/server/controllers/agents/responses.js
+++ b/api/server/controllers/agents/responses.js
@@ -1,13 +1,8 @@
const { nanoid } = require('nanoid');
const { v4: uuidv4 } = require('uuid');
const { logger } = require('@librechat/data-schemas');
+const { Callback, ToolEndHandler, formatAgentMessages } = require('@librechat/agents');
const { EModelEndpoint, ResourceType, PermissionBits } = require('librechat-data-provider');
-const {
- Callback,
- ToolEndHandler,
- formatAgentMessages,
- ChatModelStreamHandler,
-} = require('@librechat/agents');
const {
createRun,
buildToolSet,
@@ -41,9 +36,6 @@ const {
} = require('~/server/controllers/agents/callbacks');
const { loadAgentTools, loadToolsForExecution } = require('~/server/services/ToolService');
const { findAccessibleResources } = require('~/server/services/PermissionService');
-const { getConvoFiles, saveConvo, getConvo } = require('~/models/Conversation');
-const { spendTokens, spendStructuredTokens } = require('~/models/spendTokens');
-const { getAgent, getAgents } = require('~/models/Agent');
const db = require('~/models');
/** @type {import('@librechat/api').AppConfig | null} */
@@ -218,8 +210,12 @@ async function saveResponseOutput(req, conversationId, responseId, response, age
* @returns {Promise}
*/
async function saveConversation(req, conversationId, agentId, agent) {
- await saveConvo(
- req,
+ await db.saveConvo(
+ {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ },
{
conversationId,
endpoint: EModelEndpoint.agents,
@@ -283,7 +279,7 @@ const createResponse = async (req, res) => {
const isStreaming = request.stream === true;
// Look up the agent
- const agent = await getAgent({ id: agentId });
+ const agent = await db.getAgent({ id: agentId });
if (!agent) {
return sendResponsesErrorResponse(
res,
@@ -296,10 +292,6 @@ const createResponse = async (req, res) => {
// Generate IDs
const responseId = generateResponseId();
- const conversationId = request.previous_response_id ?? uuidv4();
- const parentMessageId = null;
-
- // Create response context
const context = createResponseContext(request, responseId);
logger.debug(
@@ -318,6 +310,23 @@ const createResponse = async (req, res) => {
});
try {
+ if (request.previous_response_id != null) {
+ if (typeof request.previous_response_id !== 'string') {
+ return sendResponsesErrorResponse(
+ res,
+ 400,
+ 'previous_response_id must be a string',
+ 'invalid_request',
+ );
+ }
+ if (!(await getConvo(req.user?.id, request.previous_response_id))) {
+ return sendResponsesErrorResponse(res, 404, 'Conversation not found', 'not_found');
+ }
+ }
+
+ const conversationId = request.previous_response_id ?? uuidv4();
+ const parentMessageId = null;
+
// Build allowed providers set
const allowedProviders = new Set(
appConfig?.endpoints?.[EModelEndpoint.agents]?.allowedProviders,
@@ -346,7 +355,7 @@ const createResponse = async (req, res) => {
isInitialAgent: true,
},
{
- getConvoFiles,
+ getConvoFiles: db.getConvoFiles,
getFiles: db.getFiles,
getUserKey: db.getUserKey,
getMessages: db.getMessages,
@@ -410,9 +419,6 @@ const createResponse = async (req, res) => {
// Collect usage for balance tracking
const collectedUsage = [];
- // Built-in handler for processing raw model stream chunks
- const chatModelStreamHandler = new ChatModelStreamHandler();
-
// Artifact promises for processing tool outputs
/** @type {Promise[]} */
const artifactPromises = [];
@@ -436,6 +442,7 @@ const createResponse = async (req, res) => {
toolRegistry: primaryConfig.toolRegistry,
userMCPAuthMap: primaryConfig.userMCPAuthMap,
tool_resources: primaryConfig.tool_resources,
+ actionsEnabled: primaryConfig.actionsEnabled,
});
},
toolEndCallback,
@@ -443,11 +450,6 @@ const createResponse = async (req, res) => {
// Combine handlers
const handlers = {
- on_chat_model_stream: {
- handle: async (event, data, metadata, graph) => {
- await chatModelStreamHandler.handle(event, data, metadata, graph);
- },
- },
on_message_delta: responsesHandlers.on_message_delta,
on_reasoning_delta: responsesHandlers.on_reasoning_delta,
on_run_step: responsesHandlers.on_run_step,
@@ -499,6 +501,10 @@ const createResponse = async (req, res) => {
thread_id: conversationId,
user_id: userId,
user: createSafeUser(req.user),
+ requestBody: {
+ messageId: responseId,
+ conversationId,
+ },
...(userMCPAuthMap != null && { userMCPAuthMap }),
},
signal: abortController.signal,
@@ -518,12 +524,18 @@ const createResponse = async (req, res) => {
const balanceConfig = getBalanceConfig(req.config);
const transactionsConfig = getTransactionsConfig(req.config);
recordCollectedUsage(
- { spendTokens, spendStructuredTokens },
+ {
+ spendTokens: db.spendTokens,
+ spendStructuredTokens: db.spendStructuredTokens,
+ pricing: { getMultiplier: db.getMultiplier, getCacheMultiplier: db.getCacheMultiplier },
+ bulkWriteOps: { insertMany: db.bulkInsertTransactions, updateBalance: db.updateBalance },
+ },
{
user: userId,
conversationId,
collectedUsage,
context: 'message',
+ messageId: responseId,
balance: balanceConfig,
transactions: transactionsConfig,
model: primaryConfig.model || agent.model_parameters?.model,
@@ -570,8 +582,6 @@ const createResponse = async (req, res) => {
} else {
const aggregatorHandlers = createAggregatorEventHandlers(aggregator);
- const chatModelStreamHandler = new ChatModelStreamHandler();
-
// Collect usage for balance tracking
const collectedUsage = [];
@@ -590,17 +600,13 @@ const createResponse = async (req, res) => {
toolRegistry: primaryConfig.toolRegistry,
userMCPAuthMap: primaryConfig.userMCPAuthMap,
tool_resources: primaryConfig.tool_resources,
+ actionsEnabled: primaryConfig.actionsEnabled,
});
},
toolEndCallback,
};
const handlers = {
- on_chat_model_stream: {
- handle: async (event, data, metadata, graph) => {
- await chatModelStreamHandler.handle(event, data, metadata, graph);
- },
- },
on_message_delta: aggregatorHandlers.on_message_delta,
on_reasoning_delta: aggregatorHandlers.on_reasoning_delta,
on_run_step: aggregatorHandlers.on_run_step,
@@ -650,6 +656,10 @@ const createResponse = async (req, res) => {
thread_id: conversationId,
user_id: userId,
user: createSafeUser(req.user),
+ requestBody: {
+ messageId: responseId,
+ conversationId,
+ },
...(userMCPAuthMap != null && { userMCPAuthMap }),
},
signal: abortController.signal,
@@ -669,12 +679,18 @@ const createResponse = async (req, res) => {
const balanceConfig = getBalanceConfig(req.config);
const transactionsConfig = getTransactionsConfig(req.config);
recordCollectedUsage(
- { spendTokens, spendStructuredTokens },
+ {
+ spendTokens: db.spendTokens,
+ spendStructuredTokens: db.spendStructuredTokens,
+ pricing: { getMultiplier: db.getMultiplier, getCacheMultiplier: db.getCacheMultiplier },
+ bulkWriteOps: { insertMany: db.bulkInsertTransactions, updateBalance: db.updateBalance },
+ },
{
user: userId,
conversationId,
collectedUsage,
context: 'message',
+ messageId: responseId,
balance: balanceConfig,
transactions: transactionsConfig,
model: primaryConfig.model || agent.model_parameters?.model,
@@ -727,7 +743,13 @@ const createResponse = async (req, res) => {
writeDone(res);
res.end();
} else {
- sendResponsesErrorResponse(res, 500, errorMessage, 'server_error');
+ // Forward upstream provider status codes (e.g., Anthropic 400s) instead of masking as 500
+ const statusCode =
+ typeof error?.status === 'number' && error.status >= 400 && error.status < 600
+ ? error.status
+ : 500;
+ const errorType = statusCode >= 400 && statusCode < 500 ? 'invalid_request' : 'server_error';
+ sendResponsesErrorResponse(res, statusCode, errorMessage, errorType);
}
}
};
@@ -760,7 +782,7 @@ const listModels = async (req, res) => {
// Get the accessible agents
let agents = [];
if (accessibleAgentIds.length > 0) {
- agents = await getAgents({ _id: { $in: accessibleAgentIds } });
+ agents = await db.getAgents({ _id: { $in: accessibleAgentIds } });
}
// Convert to models format
@@ -810,7 +832,7 @@ const getResponse = async (req, res) => {
// The responseId could be either the response ID or the conversation ID
// Try to find a conversation with this ID
- const conversation = await getConvo(userId, responseId);
+ const conversation = await db.getConvo(userId, responseId);
if (!conversation) {
return sendResponsesErrorResponse(
diff --git a/api/server/controllers/agents/v1.js b/api/server/controllers/agents/v1.js
index 34078b2250..17985f97ce 100644
--- a/api/server/controllers/agents/v1.js
+++ b/api/server/controllers/agents/v1.js
@@ -3,9 +3,11 @@ const fs = require('fs').promises;
const { nanoid } = require('nanoid');
const { logger } = require('@librechat/data-schemas');
const {
+ refreshS3Url,
agentCreateSchema,
agentUpdateSchema,
refreshListAvatars,
+ collectEdgeAgentIds,
mergeAgentOcrConversion,
MAX_AVATAR_REFRESH_AGENTS,
convertOcrToContextInPlace,
@@ -24,30 +26,21 @@ const {
actionDelimiter,
removeNullishValues,
} = require('librechat-data-provider');
-const {
- getListAgentsByAccess,
- countPromotedAgents,
- revertAgentVersion,
- createAgent,
- updateAgent,
- deleteAgent,
- getAgent,
-} = require('~/models/Agent');
const {
findPubliclyAccessibleResources,
+ getResourcePermissionsMap,
findAccessibleResources,
hasPublicPermission,
grantPermission,
} = require('~/server/services/PermissionService');
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
-const { getCategoriesWithCounts, deleteFileByFilter } = require('~/models');
const { resizeAvatar } = require('~/server/services/Files/images/avatar');
const { getFileStrategy } = require('~/server/utils/getFileStrategy');
-const { refreshS3Url } = require('~/server/services/Files/S3/crud');
const { filterFile } = require('~/server/services/Files/process');
-const { updateAction, getActions } = require('~/models/Action');
const { getCachedTools } = require('~/server/services/Config');
+const { getMCPServersRegistry } = require('~/config');
const { getLogStores } = require('~/cache');
+const db = require('~/models');
const systemTools = {
[Tools.execute_code]: true,
@@ -58,6 +51,114 @@ const systemTools = {
const MAX_SEARCH_LEN = 100;
const escapeRegex = (str = '') => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+/**
+ * Validates that the requesting user has VIEW access to every agent referenced in edges.
+ * Agents that do not exist in the database are skipped — at create time, the `from` field
+ * often references the agent being built, which has no DB record yet.
+ * @param {import('librechat-data-provider').GraphEdge[]} edges
+ * @param {string} userId
+ * @param {string} userRole - Used for group/role principal resolution
+ * @returns {Promise} Agent IDs the user cannot VIEW (empty if all accessible)
+ */
+const validateEdgeAgentAccess = async (edges, userId, userRole) => {
+ const edgeAgentIds = collectEdgeAgentIds(edges);
+ if (edgeAgentIds.size === 0) {
+ return [];
+ }
+
+ const agents = await db.getAgents({ id: { $in: [...edgeAgentIds] } });
+
+ if (agents.length === 0) {
+ return [];
+ }
+
+ const permissionsMap = await getResourcePermissionsMap({
+ userId,
+ role: userRole,
+ resourceType: ResourceType.AGENT,
+ resourceIds: agents.map((a) => a._id),
+ });
+
+ return agents
+ .filter((a) => {
+ const bits = permissionsMap.get(a._id.toString()) ?? 0;
+ return (bits & PermissionBits.VIEW) === 0;
+ })
+ .map((a) => a.id);
+};
+
+/**
+ * Filters tools to only include those the user is authorized to use.
+ * MCP tools must match the exact format `{toolName}_mcp_{serverName}` (exactly 2 segments).
+ * Multi-delimiter keys are rejected to prevent authorization/execution mismatch.
+ * Non-MCP tools must appear in availableTools (global tool cache) or systemTools.
+ *
+ * When `existingTools` is provided and the MCP registry is unavailable (e.g. server restart),
+ * tools already present on the agent are preserved rather than stripped — they were validated
+ * when originally added, and we cannot re-verify them without the registry.
+ * @param {object} params
+ * @param {string[]} params.tools - Raw tool strings from the request
+ * @param {string} params.userId - Requesting user ID for MCP server access check
+ * @param {Record} params.availableTools - Global non-MCP tool cache
+ * @param {string[]} [params.existingTools] - Tools already persisted on the agent document
+ * @returns {Promise} Only the authorized subset of tools
+ */
+const filterAuthorizedTools = async ({ tools, userId, availableTools, existingTools }) => {
+ const filteredTools = [];
+ let mcpServerConfigs;
+ let registryUnavailable = false;
+ const existingToolSet = existingTools?.length ? new Set(existingTools) : null;
+
+ for (const tool of tools) {
+ if (availableTools[tool] || systemTools[tool]) {
+ filteredTools.push(tool);
+ continue;
+ }
+
+ if (!tool?.includes(Constants.mcp_delimiter)) {
+ continue;
+ }
+
+ if (mcpServerConfigs === undefined) {
+ try {
+ mcpServerConfigs = (await getMCPServersRegistry().getAllServerConfigs(userId)) ?? {};
+ } catch (e) {
+ logger.warn(
+ '[filterAuthorizedTools] MCP registry unavailable, filtering all MCP tools',
+ e.message,
+ );
+ mcpServerConfigs = {};
+ registryUnavailable = true;
+ }
+ }
+
+ const parts = tool.split(Constants.mcp_delimiter);
+ if (parts.length !== 2) {
+ logger.warn(
+ `[filterAuthorizedTools] Rejected malformed MCP tool key "${tool}" for user ${userId}`,
+ );
+ continue;
+ }
+
+ if (registryUnavailable && existingToolSet?.has(tool)) {
+ filteredTools.push(tool);
+ continue;
+ }
+
+ const [, serverName] = parts;
+ if (!serverName || !Object.hasOwn(mcpServerConfigs, serverName)) {
+ logger.warn(
+ `[filterAuthorizedTools] Rejected MCP tool "${tool}" — server "${serverName}" not accessible to user ${userId}`,
+ );
+ continue;
+ }
+
+ filteredTools.push(tool);
+ }
+
+ return filteredTools;
+};
+
/**
* Creates an Agent.
* @route POST /Agents
@@ -75,24 +176,26 @@ const createAgentHandler = async (req, res) => {
agentData.model_parameters = removeNullishValues(agentData.model_parameters, true);
}
- const { id: userId } = req.user;
+ const { id: userId, role: userRole } = req.user;
+
+ if (agentData.edges?.length) {
+ const unauthorized = await validateEdgeAgentAccess(agentData.edges, userId, userRole);
+ if (unauthorized.length > 0) {
+ return res.status(403).json({
+ error: 'You do not have access to one or more agents referenced in edges',
+ agent_ids: unauthorized,
+ });
+ }
+ }
agentData.id = `agent_${nanoid()}`;
agentData.author = userId;
agentData.tools = [];
const availableTools = (await getCachedTools()) ?? {};
- for (const tool of tools) {
- if (availableTools[tool]) {
- agentData.tools.push(tool);
- } else if (systemTools[tool]) {
- agentData.tools.push(tool);
- } else if (tool.includes(Constants.mcp_delimiter)) {
- agentData.tools.push(tool);
- }
- }
+ agentData.tools = await filterAuthorizedTools({ tools, userId, availableTools });
- const agent = await createAgent(agentData);
+ const agent = await db.createAgent(agentData);
try {
await Promise.all([
@@ -152,7 +255,7 @@ const getAgentHandler = async (req, res, expandProperties = false) => {
// Permissions are validated by middleware before calling this function
// Simply load the agent by ID
- const agent = await getAgent({ id });
+ const agent = await db.getAgent({ id });
if (!agent) {
return res.status(404).json({ error: 'Agent not found' });
@@ -173,9 +276,6 @@ const getAgentHandler = async (req, res, expandProperties = false) => {
agent.author = agent.author.toString();
- // @deprecated - isCollaborative replaced by ACL permissions
- agent.isCollaborative = !!agent.isCollaborative;
-
// Check if agent is public
const isPublic = await hasPublicPermission({
resourceType: ResourceType.AGENT,
@@ -199,9 +299,6 @@ const getAgentHandler = async (req, res, expandProperties = false) => {
author: agent.author,
provider: agent.provider,
model: agent.model,
- projectIds: agent.projectIds,
- // @deprecated - isCollaborative replaced by ACL permissions
- isCollaborative: agent.isCollaborative,
isPublic: agent.isPublic,
version: agent.version,
// Safe metadata
@@ -243,10 +340,21 @@ const updateAgentHandler = async (req, res) => {
updateData.avatar = avatarField;
}
+ if (updateData.edges?.length) {
+ const { id: userId, role: userRole } = req.user;
+ const unauthorized = await validateEdgeAgentAccess(updateData.edges, userId, userRole);
+ if (unauthorized.length > 0) {
+ return res.status(403).json({
+ error: 'You do not have access to one or more agents referenced in edges',
+ agent_ids: unauthorized,
+ });
+ }
+ }
+
// Convert OCR to context in incoming updateData
convertOcrToContextInPlace(updateData);
- const existingAgent = await getAgent({ id });
+ const existingAgent = await db.getAgent({ id });
if (!existingAgent) {
return res.status(404).json({ error: 'Agent not found' });
@@ -261,9 +369,29 @@ const updateAgentHandler = async (req, res) => {
updateData.tools = ocrConversion.tools;
}
+ if (updateData.tools) {
+ const existingToolSet = new Set(existingAgent.tools ?? []);
+ const newMCPTools = updateData.tools.filter(
+ (t) => !existingToolSet.has(t) && t?.includes(Constants.mcp_delimiter),
+ );
+
+ if (newMCPTools.length > 0) {
+ const availableTools = (await getCachedTools()) ?? {};
+ const approvedNew = await filterAuthorizedTools({
+ tools: newMCPTools,
+ userId: req.user.id,
+ availableTools,
+ });
+ const rejectedSet = new Set(newMCPTools.filter((t) => !approvedNew.includes(t)));
+ if (rejectedSet.size > 0) {
+ updateData.tools = updateData.tools.filter((t) => !rejectedSet.has(t));
+ }
+ }
+ }
+
let updatedAgent =
Object.keys(updateData).length > 0
- ? await updateAgent({ id }, updateData, {
+ ? await db.updateAgent({ id }, updateData, {
updatingUserId: req.user.id,
})
: existingAgent;
@@ -313,7 +441,7 @@ const duplicateAgentHandler = async (req, res) => {
const sensitiveFields = ['api_key', 'oauth_client_id', 'oauth_client_secret'];
try {
- const agent = await getAgent({ id });
+ const agent = await db.getAgent({ id });
if (!agent) {
return res.status(404).json({
error: 'Agent not found',
@@ -361,7 +489,7 @@ const duplicateAgentHandler = async (req, res) => {
});
const newActionsList = [];
- const originalActions = (await getActions({ agent_id: id }, true)) ?? [];
+ const originalActions = (await db.getActions({ agent_id: id }, true)) ?? [];
const promises = [];
/**
@@ -371,7 +499,7 @@ const duplicateAgentHandler = async (req, res) => {
*/
const duplicateAction = async (action) => {
const newActionId = nanoid();
- const [domain] = action.action_id.split(actionDelimiter);
+ const { domain } = action.metadata;
const fullActionId = `${domain}${actionDelimiter}${newActionId}`;
// Sanitize sensitive metadata before persisting
@@ -380,8 +508,8 @@ const duplicateAgentHandler = async (req, res) => {
delete filteredMetadata[field];
}
- const newAction = await updateAction(
- { action_id: newActionId },
+ const newAction = await db.updateAction(
+ { action_id: newActionId, agent_id: newAgentId },
{
metadata: filteredMetadata,
agent_id: newAgentId,
@@ -403,7 +531,18 @@ const duplicateAgentHandler = async (req, res) => {
const agentActions = await Promise.all(promises);
newAgentData.actions = agentActions;
- const newAgent = await createAgent(newAgentData);
+
+ if (newAgentData.tools?.length) {
+ const availableTools = (await getCachedTools()) ?? {};
+ newAgentData.tools = await filterAuthorizedTools({
+ tools: newAgentData.tools,
+ userId,
+ availableTools,
+ existingTools: newAgentData.tools,
+ });
+ }
+
+ const newAgent = await db.createAgent(newAgentData);
try {
await Promise.all([
@@ -456,11 +595,11 @@ const duplicateAgentHandler = async (req, res) => {
const deleteAgentHandler = async (req, res) => {
try {
const id = req.params.id;
- const agent = await getAgent({ id });
+ const agent = await db.getAgent({ id });
if (!agent) {
return res.status(404).json({ error: 'Agent not found' });
}
- await deleteAgent({ id });
+ await db.deleteAgent({ id });
return res.json({ message: 'Agent deleted' });
} catch (error) {
logger.error('[/Agents/:id] Error deleting Agent', error);
@@ -530,31 +669,34 @@ const getListAgentsHandler = async (req, res) => {
*/
const cache = getLogStores(CacheKeys.S3_EXPIRY_INTERVAL);
const refreshKey = `${userId}:agents_avatar_refresh`;
- const alreadyChecked = await cache.get(refreshKey);
- if (alreadyChecked) {
- logger.debug('[/Agents] S3 avatar refresh already checked, skipping');
- } else {
+ let cachedRefresh = await cache.get(refreshKey);
+ const isValidCachedRefresh =
+ cachedRefresh != null && typeof cachedRefresh === 'object' && cachedRefresh.urlCache != null;
+ if (!isValidCachedRefresh) {
try {
- const fullList = await getListAgentsByAccess({
+ const fullList = await db.getListAgentsByAccess({
accessibleIds,
otherParams: {},
limit: MAX_AVATAR_REFRESH_AGENTS,
after: null,
});
- await refreshListAvatars({
+ const { urlCache } = await refreshListAvatars({
agents: fullList?.data ?? [],
userId,
refreshS3Url,
- updateAgent,
+ updateAgent: db.updateAgent,
});
- await cache.set(refreshKey, true, Time.THIRTY_MINUTES);
+ cachedRefresh = { urlCache };
+ await cache.set(refreshKey, cachedRefresh, Time.THIRTY_MINUTES);
} catch (err) {
logger.error('[/Agents] Error refreshing avatars for full list: %o', err);
}
+ } else {
+ logger.debug('[/Agents] S3 avatar refresh already checked, skipping');
}
// Use the new ACL-aware function
- const data = await getListAgentsByAccess({
+ const data = await db.getListAgentsByAccess({
accessibleIds,
otherParams: filter,
limit,
@@ -568,11 +710,20 @@ const getListAgentsHandler = async (req, res) => {
const publicSet = new Set(publiclyAccessibleIds.map((oid) => oid.toString()));
+ const urlCache = cachedRefresh?.urlCache;
data.data = agents.map((agent) => {
try {
if (agent?._id && publicSet.has(agent._id.toString())) {
agent.isPublic = true;
}
+ if (
+ urlCache &&
+ agent?.id &&
+ agent?.avatar?.source === FileSources.s3 &&
+ urlCache[agent.id]
+ ) {
+ agent.avatar = { ...agent.avatar, filepath: urlCache[agent.id] };
+ }
} catch (e) {
// Silently ignore mapping errors
void e;
@@ -610,7 +761,7 @@ const uploadAgentAvatarHandler = async (req, res) => {
return res.status(400).json({ message: 'Agent ID is required' });
}
- const existingAgent = await getAgent({ id: agent_id });
+ const existingAgent = await db.getAgent({ id: agent_id });
if (!existingAgent) {
return res.status(404).json({ error: 'Agent not found' });
@@ -642,7 +793,7 @@ const uploadAgentAvatarHandler = async (req, res) => {
const { deleteFile } = getStrategyFunctions(_avatar.source);
try {
await deleteFile(req, { filepath: _avatar.filepath });
- await deleteFileByFilter({ user: req.user.id, filepath: _avatar.filepath });
+ await db.deleteFileByFilter({ user: req.user.id, filepath: _avatar.filepath });
} catch (error) {
logger.error('[/:agent_id/avatar] Error deleting old avatar', error);
}
@@ -655,9 +806,17 @@ const uploadAgentAvatarHandler = async (req, res) => {
},
};
- const updatedAgent = await updateAgent({ id: agent_id }, data, {
+ const updatedAgent = await db.updateAgent({ id: agent_id }, data, {
updatingUserId: req.user.id,
});
+
+ try {
+ const avatarCache = getLogStores(CacheKeys.S3_EXPIRY_INTERVAL);
+ await avatarCache.delete(`${req.user.id}:agents_avatar_refresh`);
+ } catch (cacheErr) {
+ logger.error('[/:agent_id/avatar] Error invalidating avatar refresh cache', cacheErr);
+ }
+
res.status(201).json(updatedAgent);
} catch (error) {
const message = 'An error occurred while updating the Agent Avatar';
@@ -703,7 +862,7 @@ const revertAgentVersionHandler = async (req, res) => {
return res.status(400).json({ error: 'version_index is required' });
}
- const existingAgent = await getAgent({ id });
+ const existingAgent = await db.getAgent({ id });
if (!existingAgent) {
return res.status(404).json({ error: 'Agent not found' });
@@ -711,7 +870,24 @@ const revertAgentVersionHandler = async (req, res) => {
// Permissions are enforced via route middleware (ACL EDIT)
- const updatedAgent = await revertAgentVersion({ id }, version_index);
+ let updatedAgent = await db.revertAgentVersion({ id }, version_index);
+
+ if (updatedAgent.tools?.length) {
+ const availableTools = (await getCachedTools()) ?? {};
+ const filteredTools = await filterAuthorizedTools({
+ tools: updatedAgent.tools,
+ userId: req.user.id,
+ availableTools,
+ existingTools: updatedAgent.tools,
+ });
+ if (filteredTools.length !== updatedAgent.tools.length) {
+ updatedAgent = await db.updateAgent(
+ { id },
+ { tools: filteredTools },
+ { updatingUserId: req.user.id },
+ );
+ }
+ }
if (updatedAgent.author) {
updatedAgent.author = updatedAgent.author.toString();
@@ -735,8 +911,8 @@ const revertAgentVersionHandler = async (req, res) => {
*/
const getAgentCategories = async (_req, res) => {
try {
- const categories = await getCategoriesWithCounts();
- const promotedCount = await countPromotedAgents();
+ const categories = await db.getCategoriesWithCounts();
+ const promotedCount = await db.countPromotedAgents();
const formattedCategories = categories.map((category) => ({
value: category.value,
label: category.label,
@@ -779,4 +955,5 @@ module.exports = {
uploadAgentAvatar: uploadAgentAvatarHandler,
revertAgentVersion: revertAgentVersionHandler,
getAgentCategories,
+ filterAuthorizedTools,
};
diff --git a/api/server/controllers/agents/v1.spec.js b/api/server/controllers/agents/v1.spec.js
index 8b2a57d903..455cea2e7c 100644
--- a/api/server/controllers/agents/v1.spec.js
+++ b/api/server/controllers/agents/v1.spec.js
@@ -2,7 +2,7 @@ const mongoose = require('mongoose');
const { nanoid } = require('nanoid');
const { v4: uuidv4 } = require('uuid');
const { agentSchema } = require('@librechat/data-schemas');
-const { FileSources } = require('librechat-data-provider');
+const { FileSources, PermissionBits } = require('librechat-data-provider');
const { MongoMemoryServer } = require('mongodb-memory-server');
// Only mock the dependencies that are not database-related
@@ -14,10 +14,6 @@ jest.mock('~/server/services/Config', () => ({
}),
}));
-jest.mock('~/models/Project', () => ({
- getProjectByName: jest.fn().mockResolvedValue(null),
-}));
-
jest.mock('~/server/services/Files/strategies', () => ({
getStrategyFunctions: jest.fn(),
}));
@@ -26,7 +22,16 @@ jest.mock('~/server/services/Files/images/avatar', () => ({
resizeAvatar: jest.fn(),
}));
-jest.mock('~/server/services/Files/S3/crud', () => ({
+jest.mock('sharp', () =>
+ jest.fn(() => ({
+ metadata: jest.fn().mockResolvedValue({}),
+ toFormat: jest.fn().mockReturnThis(),
+ toBuffer: jest.fn().mockResolvedValue(Buffer.alloc(0)),
+ })),
+);
+
+jest.mock('@librechat/api', () => ({
+ ...jest.requireActual('@librechat/api'),
refreshS3Url: jest.fn(),
}));
@@ -34,31 +39,32 @@ jest.mock('~/server/services/Files/process', () => ({
filterFile: jest.fn(),
}));
-jest.mock('~/models/Action', () => ({
- updateAction: jest.fn(),
- getActions: jest.fn().mockResolvedValue([]),
-}));
-
-jest.mock('~/models/File', () => ({
- deleteFileByFilter: jest.fn(),
-}));
-
jest.mock('~/server/services/PermissionService', () => ({
findAccessibleResources: jest.fn().mockResolvedValue([]),
findPubliclyAccessibleResources: jest.fn().mockResolvedValue([]),
+ getResourcePermissionsMap: jest.fn().mockResolvedValue(new Map()),
grantPermission: jest.fn(),
hasPublicPermission: jest.fn().mockResolvedValue(false),
- checkPermission: jest.fn().mockResolvedValue(true),
}));
-jest.mock('~/models', () => ({
- getCategoriesWithCounts: jest.fn(),
-}));
+jest.mock('~/models', () => {
+ const mongoose = require('mongoose');
+ const { createMethods } = require('@librechat/data-schemas');
+ const methods = createMethods(mongoose, {
+ removeAllPermissions: jest.fn().mockResolvedValue(undefined),
+ });
+ return {
+ ...methods,
+ getCategoriesWithCounts: jest.fn(),
+ deleteFileByFilter: jest.fn(),
+ };
+});
// Mock cache for S3 avatar refresh tests
const mockCache = {
get: jest.fn(),
set: jest.fn(),
+ delete: jest.fn(),
};
jest.mock('~/cache', () => ({
getLogStores: jest.fn(() => mockCache),
@@ -73,9 +79,10 @@ const {
const {
findAccessibleResources,
findPubliclyAccessibleResources,
+ getResourcePermissionsMap,
} = require('~/server/services/PermissionService');
-const { refreshS3Url } = require('~/server/services/Files/S3/crud');
+const { refreshS3Url } = require('@librechat/api');
/**
* @type {import('mongoose').Model}
@@ -174,7 +181,6 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
// Unauthorized fields that should be stripped
author: new mongoose.Types.ObjectId().toString(), // Should not be able to set author
authorName: 'Hacker', // Should be stripped
- isCollaborative: true, // Should be stripped on creation
versions: [], // Should be stripped
_id: new mongoose.Types.ObjectId(), // Should be stripped
id: 'custom_agent_id', // Should be overridden
@@ -193,7 +199,6 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
// Verify unauthorized fields were not set
expect(createdAgent.author.toString()).toBe(mockReq.user.id); // Should be the request user, not the malicious value
expect(createdAgent.authorName).toBeUndefined();
- expect(createdAgent.isCollaborative).toBeFalsy();
expect(createdAgent.versions).toHaveLength(1); // Should have exactly 1 version from creation
expect(createdAgent.id).not.toBe('custom_agent_id'); // Should have generated ID
expect(createdAgent.id).toMatch(/^agent_/); // Should have proper prefix
@@ -444,7 +449,6 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
model: 'gpt-3.5-turbo',
author: existingAgentAuthorId,
description: 'Original description',
- isCollaborative: false,
versions: [
{
name: 'Original Agent',
@@ -466,7 +470,6 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
name: 'Updated Agent',
description: 'Updated description',
model: 'gpt-4',
- isCollaborative: true, // This IS allowed in updates
};
await updateAgentHandler(mockReq, mockRes);
@@ -479,13 +482,11 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
expect(updatedAgent.name).toBe('Updated Agent');
expect(updatedAgent.description).toBe('Updated description');
expect(updatedAgent.model).toBe('gpt-4');
- expect(updatedAgent.isCollaborative).toBe(true);
expect(updatedAgent.author).toBe(existingAgentAuthorId.toString());
// Verify in database
const agentInDb = await Agent.findOne({ id: existingAgentId });
expect(agentInDb.name).toBe('Updated Agent');
- expect(agentInDb.isCollaborative).toBe(true);
});
test('should reject update with unauthorized fields (mass assignment protection)', async () => {
@@ -540,26 +541,6 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
expect(updatedAgent.name).toBe('Admin Update');
});
- test('should handle projectIds updates', async () => {
- mockReq.user.id = existingAgentAuthorId.toString();
- mockReq.params.id = existingAgentId;
-
- const projectId1 = new mongoose.Types.ObjectId().toString();
- const projectId2 = new mongoose.Types.ObjectId().toString();
-
- mockReq.body = {
- projectIds: [projectId1, projectId2],
- };
-
- await updateAgentHandler(mockReq, mockRes);
-
- expect(mockRes.json).toHaveBeenCalled();
-
- const updatedAgent = mockRes.json.mock.calls[0][0];
- expect(updatedAgent).toBeDefined();
- // Note: updateAgentProjects requires more setup, so we just verify the handler doesn't crash
- });
-
test('should validate tool_resources in updates', async () => {
mockReq.user.id = existingAgentAuthorId.toString();
mockReq.params.id = existingAgentId;
@@ -1309,7 +1290,7 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
});
test('should skip avatar refresh if cache hit', async () => {
- mockCache.get.mockResolvedValue(true);
+ mockCache.get.mockResolvedValue({ urlCache: {} });
findAccessibleResources.mockResolvedValue([agentWithS3Avatar._id]);
findPubliclyAccessibleResources.mockResolvedValue([]);
@@ -1348,8 +1329,12 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
// Verify S3 URL was refreshed
expect(refreshS3Url).toHaveBeenCalled();
- // Verify cache was set
- expect(mockCache.set).toHaveBeenCalled();
+ // Verify cache was set with urlCache map, not a plain boolean
+ expect(mockCache.set).toHaveBeenCalledWith(
+ expect.any(String),
+ expect.objectContaining({ urlCache: expect.any(Object) }),
+ expect.any(Number),
+ );
// Verify response was returned
expect(mockRes.json).toHaveBeenCalled();
@@ -1563,5 +1548,191 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
// Verify that the handler completed successfully
expect(mockRes.json).toHaveBeenCalled();
});
+
+ test('should treat legacy boolean cache entry as a miss and run refresh', async () => {
+ // Simulate a cache entry written by the pre-fix code
+ mockCache.get.mockResolvedValue(true);
+ findAccessibleResources.mockResolvedValue([agentWithS3Avatar._id]);
+ findPubliclyAccessibleResources.mockResolvedValue([]);
+ refreshS3Url.mockResolvedValue('new-s3-path.jpg');
+
+ const mockReq = {
+ user: { id: userA.toString(), role: 'USER' },
+ query: {},
+ };
+ const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ };
+
+ await getListAgentsHandler(mockReq, mockRes);
+
+ // Boolean true fails the shape guard, so refresh must run
+ expect(refreshS3Url).toHaveBeenCalled();
+ // Cache is overwritten with the proper format
+ expect(mockCache.set).toHaveBeenCalledWith(
+ expect.any(String),
+ expect.objectContaining({ urlCache: expect.any(Object) }),
+ expect.any(Number),
+ );
+ });
+
+ test('should apply cached urlCache filepath to paginated response on cache hit', async () => {
+ const agentId = agentWithS3Avatar.id;
+ const cachedUrl = 'cached-presigned-url.jpg';
+
+ mockCache.get.mockResolvedValue({ urlCache: { [agentId]: cachedUrl } });
+ findAccessibleResources.mockResolvedValue([agentWithS3Avatar._id]);
+ findPubliclyAccessibleResources.mockResolvedValue([]);
+
+ const mockReq = {
+ user: { id: userA.toString(), role: 'USER' },
+ query: {},
+ };
+ const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ };
+
+ await getListAgentsHandler(mockReq, mockRes);
+
+ expect(refreshS3Url).not.toHaveBeenCalled();
+
+ const responseData = mockRes.json.mock.calls[0][0];
+ const agent = responseData.data.find((a) => a.id === agentId);
+ // Cached URL is served, not the stale DB value 'old-s3-path.jpg'
+ expect(agent.avatar.filepath).toBe(cachedUrl);
+ });
+
+ test('should preserve DB filepath for agents absent from urlCache on cache hit', async () => {
+ mockCache.get.mockResolvedValue({ urlCache: {} });
+ findAccessibleResources.mockResolvedValue([agentWithS3Avatar._id]);
+ findPubliclyAccessibleResources.mockResolvedValue([]);
+
+ const mockReq = {
+ user: { id: userA.toString(), role: 'USER' },
+ query: {},
+ };
+ const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ };
+
+ await getListAgentsHandler(mockReq, mockRes);
+
+ expect(refreshS3Url).not.toHaveBeenCalled();
+
+ const responseData = mockRes.json.mock.calls[0][0];
+ const agent = responseData.data.find((a) => a.id === agentWithS3Avatar.id);
+ expect(agent.avatar.filepath).toBe('old-s3-path.jpg');
+ });
+ });
+
+ describe('Edge ACL validation', () => {
+ let targetAgent;
+
+ beforeEach(async () => {
+ targetAgent = await Agent.create({
+ id: `agent_${nanoid()}`,
+ author: new mongoose.Types.ObjectId().toString(),
+ name: 'Target Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ tools: [],
+ });
+ });
+
+ test('createAgentHandler should return 403 when user lacks VIEW on an edge-referenced agent', async () => {
+ const permMap = new Map();
+ getResourcePermissionsMap.mockResolvedValueOnce(permMap);
+
+ mockReq.body = {
+ name: 'Attacker Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ edges: [{ from: 'self_placeholder', to: targetAgent.id, edgeType: 'handoff' }],
+ };
+
+ await createAgentHandler(mockReq, mockRes);
+
+ expect(mockRes.status).toHaveBeenCalledWith(403);
+ const response = mockRes.json.mock.calls[0][0];
+ expect(response.agent_ids).toContain(targetAgent.id);
+ });
+
+ test('createAgentHandler should succeed when user has VIEW on all edge-referenced agents', async () => {
+ const permMap = new Map([[targetAgent._id.toString(), 1]]);
+ getResourcePermissionsMap.mockResolvedValueOnce(permMap);
+
+ mockReq.body = {
+ name: 'Legit Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ edges: [{ from: 'self_placeholder', to: targetAgent.id, edgeType: 'handoff' }],
+ };
+
+ await createAgentHandler(mockReq, mockRes);
+
+ expect(mockRes.status).toHaveBeenCalledWith(201);
+ });
+
+ test('createAgentHandler should allow edges referencing non-existent agents (self-reference at create time)', async () => {
+ mockReq.body = {
+ name: 'Self-Ref Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ edges: [{ from: 'agent_does_not_exist_yet', to: 'agent_also_new', edgeType: 'handoff' }],
+ };
+
+ await createAgentHandler(mockReq, mockRes);
+
+ expect(mockRes.status).toHaveBeenCalledWith(201);
+ });
+
+ test('updateAgentHandler should return 403 when user lacks VIEW on an edge-referenced agent', async () => {
+ const ownedAgent = await Agent.create({
+ id: `agent_${nanoid()}`,
+ author: mockReq.user.id,
+ name: 'Owned Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ tools: [],
+ });
+
+ const permMap = new Map([[ownedAgent._id.toString(), PermissionBits.VIEW]]);
+ getResourcePermissionsMap.mockResolvedValueOnce(permMap);
+
+ mockReq.params = { id: ownedAgent.id };
+ mockReq.body = {
+ edges: [{ from: ownedAgent.id, to: targetAgent.id, edgeType: 'handoff' }],
+ };
+
+ await updateAgentHandler(mockReq, mockRes);
+
+ expect(mockRes.status).toHaveBeenCalledWith(403);
+ const response = mockRes.json.mock.calls[0][0];
+ expect(response.agent_ids).toContain(targetAgent.id);
+ expect(response.agent_ids).not.toContain(ownedAgent.id);
+ });
+
+ test('updateAgentHandler should succeed when edges field is absent from payload', async () => {
+ const ownedAgent = await Agent.create({
+ id: `agent_${nanoid()}`,
+ author: mockReq.user.id,
+ name: 'Owned Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ tools: [],
+ });
+
+ mockReq.params = { id: ownedAgent.id };
+ mockReq.body = { name: 'Renamed Agent' };
+
+ await updateAgentHandler(mockReq, mockRes);
+
+ expect(mockRes.status).not.toHaveBeenCalledWith(403);
+ const response = mockRes.json.mock.calls[0][0];
+ expect(response.name).toBe('Renamed Agent');
+ });
});
});
diff --git a/api/server/controllers/assistants/chatV1.js b/api/server/controllers/assistants/chatV1.js
index f6244f0d48..e4a20c2a5e 100644
--- a/api/server/controllers/assistants/chatV1.js
+++ b/api/server/controllers/assistants/chatV1.js
@@ -1,7 +1,13 @@
const { v4 } = require('uuid');
const { sleep } = require('@librechat/agents');
const { logger } = require('@librechat/data-schemas');
-const { sendEvent, getBalanceConfig, countTokens } = require('@librechat/api');
+const {
+ sendEvent,
+ countTokens,
+ checkBalance,
+ getBalanceConfig,
+ getModelMaxTokens,
+} = require('@librechat/api');
const {
Time,
Constants,
@@ -12,7 +18,6 @@ const {
EModelEndpoint,
ViolationTypes,
ImageVisionTool,
- getModelMaxTokens,
checkOpenAIStorage,
AssistantStreamEvents,
} = require('librechat-data-provider');
@@ -32,10 +37,14 @@ const { createRun, StreamRunManager } = require('~/server/services/Runs');
const { addTitle } = require('~/server/services/Endpoints/assistants');
const { createRunBody } = require('~/server/services/createRunBody');
const { sendResponse } = require('~/server/middleware/error');
-const { getTransactions } = require('~/models/Transaction');
-const { checkBalance } = require('~/models/balanceMethods');
-const { getConvo } = require('~/models/Conversation');
-const getLogStores = require('~/cache/getLogStores');
+const {
+ createAutoRefillTransaction,
+ findBalanceByUser,
+ getTransactions,
+ getMultiplier,
+ getConvo,
+} = require('~/models');
+const { logViolation, getLogStores } = require('~/cache');
const { getOpenAIClient } = require('./helpers');
/**
@@ -276,16 +285,19 @@ const chatV1 = async (req, res) => {
// Count tokens up to the current context window
promptTokens = Math.min(promptTokens, getModelMaxTokens(model));
- await checkBalance({
- req,
- res,
- txData: {
- model,
- user: req.user.id,
- tokenType: 'prompt',
- amount: promptTokens,
+ await checkBalance(
+ {
+ req,
+ res,
+ txData: {
+ model,
+ user: req.user.id,
+ tokenType: 'prompt',
+ amount: promptTokens,
+ },
},
- });
+ { findBalanceByUser, getMultiplier, createAutoRefillTransaction, logViolation },
+ );
};
const { openai: _openai } = await getOpenAIClient({
diff --git a/api/server/controllers/assistants/chatV2.js b/api/server/controllers/assistants/chatV2.js
index 365a7ae3ce..559d9d8953 100644
--- a/api/server/controllers/assistants/chatV2.js
+++ b/api/server/controllers/assistants/chatV2.js
@@ -1,7 +1,13 @@
const { v4 } = require('uuid');
const { sleep } = require('@librechat/agents');
const { logger } = require('@librechat/data-schemas');
-const { sendEvent, getBalanceConfig, countTokens } = require('@librechat/api');
+const {
+ sendEvent,
+ countTokens,
+ checkBalance,
+ getBalanceConfig,
+ getModelMaxTokens,
+} = require('@librechat/api');
const {
Time,
Constants,
@@ -10,7 +16,6 @@ const {
ContentTypes,
ToolCallTypes,
EModelEndpoint,
- getModelMaxTokens,
retrievalMimeTypes,
AssistantStreamEvents,
} = require('librechat-data-provider');
@@ -27,10 +32,14 @@ const validateAuthor = require('~/server/middleware/assistants/validateAuthor');
const { createRun, StreamRunManager } = require('~/server/services/Runs');
const { addTitle } = require('~/server/services/Endpoints/assistants');
const { createRunBody } = require('~/server/services/createRunBody');
-const { getTransactions } = require('~/models/Transaction');
-const { checkBalance } = require('~/models/balanceMethods');
-const { getConvo } = require('~/models/Conversation');
-const getLogStores = require('~/cache/getLogStores');
+const {
+ getConvo,
+ getMultiplier,
+ getTransactions,
+ findBalanceByUser,
+ createAutoRefillTransaction,
+} = require('~/models');
+const { logViolation, getLogStores } = require('~/cache');
const { getOpenAIClient } = require('./helpers');
/**
@@ -149,16 +158,19 @@ const chatV2 = async (req, res) => {
// Count tokens up to the current context window
promptTokens = Math.min(promptTokens, getModelMaxTokens(model));
- await checkBalance({
- req,
- res,
- txData: {
- model,
- user: req.user.id,
- tokenType: 'prompt',
- amount: promptTokens,
+ await checkBalance(
+ {
+ req,
+ res,
+ txData: {
+ model,
+ user: req.user.id,
+ tokenType: 'prompt',
+ amount: promptTokens,
+ },
},
- });
+ { findBalanceByUser, getMultiplier, createAutoRefillTransaction, logViolation },
+ );
};
const { openai: _openai } = await getOpenAIClient({
diff --git a/api/server/controllers/assistants/errors.js b/api/server/controllers/assistants/errors.js
index 1ae12ea3d5..f8dcf39f2b 100644
--- a/api/server/controllers/assistants/errors.js
+++ b/api/server/controllers/assistants/errors.js
@@ -3,8 +3,8 @@ const { logger } = require('@librechat/data-schemas');
const { CacheKeys, ViolationTypes, ContentTypes } = require('librechat-data-provider');
const { recordUsage, checkMessageGaps } = require('~/server/services/Threads');
const { sendResponse } = require('~/server/middleware/error');
-const { getConvo } = require('~/models/Conversation');
const getLogStores = require('~/cache/getLogStores');
+const { getConvo } = require('~/models');
/**
* @typedef {Object} ErrorHandlerContext
diff --git a/api/server/controllers/assistants/helpers.js b/api/server/controllers/assistants/helpers.js
index 9183680f1e..6309268770 100644
--- a/api/server/controllers/assistants/helpers.js
+++ b/api/server/controllers/assistants/helpers.js
@@ -1,14 +1,15 @@
const {
- SystemRoles,
EModelEndpoint,
defaultOrderQuery,
defaultAssistantsVersion,
} = require('librechat-data-provider');
+const { logger, SystemCapabilities } = require('@librechat/data-schemas');
const {
initializeClient: initAzureClient,
} = require('~/server/services/Endpoints/azureAssistants');
const { initializeClient } = require('~/server/services/Endpoints/assistants');
const { getEndpointsConfig } = require('~/server/services/Config');
+const { hasCapability } = require('~/server/middleware');
/**
* @param {ServerRequest} req
@@ -236,9 +237,19 @@ const fetchAssistants = async ({ req, res, overrideEndpoint }) => {
body = await listAssistantsForAzure({ req, res, version, azureConfig, query });
}
- if (req.user.role === SystemRoles.ADMIN) {
+ if (!appConfig.endpoints?.[endpoint]) {
return body;
- } else if (!appConfig.endpoints?.[endpoint]) {
+ }
+
+ let canManageAssistants = false;
+ try {
+ canManageAssistants = await hasCapability(req.user, SystemCapabilities.MANAGE_ASSISTANTS);
+ } catch (err) {
+ logger.warn(`[fetchAssistants] capability check failed, denying bypass: ${err.message}`);
+ }
+
+ if (canManageAssistants) {
+ logger.debug(`[fetchAssistants] MANAGE_ASSISTANTS bypass for user ${req.user.id}`);
return body;
}
diff --git a/api/server/controllers/assistants/v1.js b/api/server/controllers/assistants/v1.js
index 5d13d30334..c441b7ec59 100644
--- a/api/server/controllers/assistants/v1.js
+++ b/api/server/controllers/assistants/v1.js
@@ -1,15 +1,14 @@
const fs = require('fs').promises;
const { logger } = require('@librechat/data-schemas');
const { FileContext } = require('librechat-data-provider');
+const { deleteFileByFilter, updateAssistantDoc, getAssistants } = require('~/models');
const { uploadImageBuffer, filterFile } = require('~/server/services/Files/process');
const validateAuthor = require('~/server/middleware/assistants/validateAuthor');
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
const { deleteAssistantActions } = require('~/server/services/ActionService');
-const { updateAssistantDoc, getAssistants } = require('~/models/Assistant');
const { getOpenAIClient, fetchAssistants } = require('./helpers');
const { getCachedTools } = require('~/server/services/Config');
const { manifestToolMap } = require('~/app/clients/tools');
-const { deleteFileByFilter } = require('~/models');
/**
* Create an assistant.
diff --git a/api/server/controllers/assistants/v2.js b/api/server/controllers/assistants/v2.js
index b9c5cd709f..cc0e03916d 100644
--- a/api/server/controllers/assistants/v2.js
+++ b/api/server/controllers/assistants/v2.js
@@ -3,8 +3,8 @@ const { ToolCallTypes } = require('librechat-data-provider');
const validateAuthor = require('~/server/middleware/assistants/validateAuthor');
const { validateAndUpdateTool } = require('~/server/services/ActionService');
const { getCachedTools } = require('~/server/services/Config');
-const { updateAssistantDoc } = require('~/models/Assistant');
const { manifestToolMap } = require('~/app/clients/tools');
+const { updateAssistantDoc } = require('~/models');
const { getOpenAIClient } = require('./helpers');
/**
diff --git a/api/server/controllers/auth/LogoutController.js b/api/server/controllers/auth/LogoutController.js
index 0b3cf262b8..039ed630c2 100644
--- a/api/server/controllers/auth/LogoutController.js
+++ b/api/server/controllers/auth/LogoutController.js
@@ -8,13 +8,16 @@ const logoutController = async (req, res) => {
const parsedCookies = req.headers.cookie ? cookies.parse(req.headers.cookie) : {};
const isOpenIdUser = req.user?.openidId != null && req.user?.provider === 'openid';
- /** For OpenID users, read refresh token from session; for others, use cookie */
+ /** For OpenID users, read tokens from session (with cookie fallback) */
let refreshToken;
+ let idToken;
if (isOpenIdUser && req.session?.openidTokens) {
refreshToken = req.session.openidTokens.refreshToken;
+ idToken = req.session.openidTokens.idToken;
delete req.session.openidTokens;
}
refreshToken = refreshToken || parsedCookies.refreshToken;
+ idToken = idToken || parsedCookies.openid_id_token;
try {
const logout = await logoutUser(req, refreshToken);
@@ -31,21 +34,34 @@ const logoutController = async (req, res) => {
isEnabled(process.env.OPENID_USE_END_SESSION_ENDPOINT) &&
process.env.OPENID_ISSUER
) {
- const openIdConfig = getOpenIdConfig();
- if (!openIdConfig) {
- logger.warn(
- '[logoutController] OpenID config not found. Please verify that the open id configuration and initialization are correct.',
- );
- } else {
- const endSessionEndpoint = openIdConfig
- ? openIdConfig.serverMetadata().end_session_endpoint
- : null;
+ let openIdConfig;
+ try {
+ openIdConfig = getOpenIdConfig();
+ } catch (err) {
+ logger.warn('[logoutController] OpenID config not available:', err.message);
+ }
+ if (openIdConfig) {
+ const endSessionEndpoint = openIdConfig.serverMetadata().end_session_endpoint;
if (endSessionEndpoint) {
const endSessionUrl = new URL(endSessionEndpoint);
/** Redirect back to app's login page after IdP logout */
const postLogoutRedirectUri =
process.env.OPENID_POST_LOGOUT_REDIRECT_URI || `${process.env.DOMAIN_CLIENT}/login`;
endSessionUrl.searchParams.set('post_logout_redirect_uri', postLogoutRedirectUri);
+
+ /** Add id_token_hint (preferred) or client_id for OIDC spec compliance */
+ if (idToken) {
+ endSessionUrl.searchParams.set('id_token_hint', idToken);
+ } else if (process.env.OPENID_CLIENT_ID) {
+ endSessionUrl.searchParams.set('client_id', process.env.OPENID_CLIENT_ID);
+ } else {
+ logger.warn(
+ '[logoutController] Neither id_token_hint nor OPENID_CLIENT_ID is available. ' +
+ 'To enable id_token_hint, set OPENID_REUSE_TOKENS=true. ' +
+ 'The OIDC end-session request may be rejected by the identity provider.',
+ );
+ }
+
response.redirect = endSessionUrl.toString();
} else {
logger.warn(
diff --git a/api/server/controllers/auth/LogoutController.spec.js b/api/server/controllers/auth/LogoutController.spec.js
new file mode 100644
index 0000000000..3f2a2de8e1
--- /dev/null
+++ b/api/server/controllers/auth/LogoutController.spec.js
@@ -0,0 +1,259 @@
+const cookies = require('cookie');
+
+const mockLogoutUser = jest.fn();
+const mockLogger = { warn: jest.fn(), error: jest.fn() };
+const mockIsEnabled = jest.fn();
+const mockGetOpenIdConfig = jest.fn();
+
+jest.mock('cookie');
+jest.mock('@librechat/api', () => ({ isEnabled: (...args) => mockIsEnabled(...args) }));
+jest.mock('@librechat/data-schemas', () => ({ logger: mockLogger }));
+jest.mock('~/server/services/AuthService', () => ({
+ logoutUser: (...args) => mockLogoutUser(...args),
+}));
+jest.mock('~/strategies', () => ({ getOpenIdConfig: () => mockGetOpenIdConfig() }));
+
+const { logoutController } = require('./LogoutController');
+
+function buildReq(overrides = {}) {
+ return {
+ user: { _id: 'user1', openidId: 'oid1', provider: 'openid' },
+ headers: { cookie: 'refreshToken=rt1' },
+ session: {
+ openidTokens: { refreshToken: 'srt', idToken: 'small-id-token' },
+ destroy: jest.fn(),
+ },
+ ...overrides,
+ };
+}
+
+function buildRes() {
+ const res = {
+ status: jest.fn().mockReturnThis(),
+ send: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ clearCookie: jest.fn(),
+ };
+ return res;
+}
+
+const ORIGINAL_ENV = process.env;
+
+beforeEach(() => {
+ jest.clearAllMocks();
+ process.env = {
+ ...ORIGINAL_ENV,
+ OPENID_USE_END_SESSION_ENDPOINT: 'true',
+ OPENID_ISSUER: 'https://idp.example.com',
+ OPENID_CLIENT_ID: 'my-client-id',
+ DOMAIN_CLIENT: 'https://app.example.com',
+ };
+ cookies.parse.mockReturnValue({ refreshToken: 'cookie-rt' });
+ mockLogoutUser.mockResolvedValue({ status: 200, message: 'Logout successful' });
+ mockIsEnabled.mockReturnValue(true);
+ mockGetOpenIdConfig.mockReturnValue({
+ serverMetadata: () => ({
+ end_session_endpoint: 'https://idp.example.com/logout',
+ }),
+ });
+});
+
+afterAll(() => {
+ process.env = ORIGINAL_ENV;
+});
+
+describe('LogoutController', () => {
+ describe('id_token_hint from session', () => {
+ it('sets id_token_hint when session has idToken', async () => {
+ const req = buildReq();
+ const res = buildRes();
+
+ await logoutController(req, res);
+
+ const body = res.send.mock.calls[0][0];
+ expect(body.redirect).toContain('id_token_hint=small-id-token');
+ expect(body.redirect).not.toContain('client_id=');
+ });
+ });
+
+ describe('id_token_hint from cookie fallback', () => {
+ it('uses cookie id_token when session has no tokens', async () => {
+ cookies.parse.mockReturnValue({
+ refreshToken: 'cookie-rt',
+ openid_id_token: 'cookie-id-token',
+ });
+ const req = buildReq({ session: { destroy: jest.fn() } });
+ const res = buildRes();
+
+ await logoutController(req, res);
+
+ const body = res.send.mock.calls[0][0];
+ expect(body.redirect).toContain('id_token_hint=cookie-id-token');
+ });
+ });
+
+ describe('client_id fallback', () => {
+ it('falls back to client_id when no idToken is available', async () => {
+ cookies.parse.mockReturnValue({ refreshToken: 'cookie-rt' });
+ const req = buildReq({ session: { destroy: jest.fn() } });
+ const res = buildRes();
+
+ await logoutController(req, res);
+
+ const body = res.send.mock.calls[0][0];
+ expect(body.redirect).toContain('client_id=my-client-id');
+ expect(body.redirect).not.toContain('id_token_hint=');
+ });
+
+ it('does not produce client_id=undefined when OPENID_CLIENT_ID is unset', async () => {
+ delete process.env.OPENID_CLIENT_ID;
+ cookies.parse.mockReturnValue({ refreshToken: 'cookie-rt' });
+ const req = buildReq({ session: { destroy: jest.fn() } });
+ const res = buildRes();
+
+ await logoutController(req, res);
+
+ const body = res.send.mock.calls[0][0];
+ expect(body.redirect).not.toContain('client_id=');
+ expect(body.redirect).not.toContain('undefined');
+ expect(mockLogger.warn).toHaveBeenCalledWith(
+ expect.stringContaining('Neither id_token_hint nor OPENID_CLIENT_ID'),
+ );
+ });
+ });
+
+ describe('OPENID_USE_END_SESSION_ENDPOINT disabled', () => {
+ it('does not include redirect when disabled', async () => {
+ mockIsEnabled.mockReturnValue(false);
+ const req = buildReq();
+ const res = buildRes();
+
+ await logoutController(req, res);
+
+ const body = res.send.mock.calls[0][0];
+ expect(body.redirect).toBeUndefined();
+ });
+ });
+
+ describe('OPENID_ISSUER unset', () => {
+ it('does not include redirect when OPENID_ISSUER is missing', async () => {
+ delete process.env.OPENID_ISSUER;
+ const req = buildReq();
+ const res = buildRes();
+
+ await logoutController(req, res);
+
+ const body = res.send.mock.calls[0][0];
+ expect(body.redirect).toBeUndefined();
+ });
+ });
+
+ describe('non-OpenID user', () => {
+ it('does not include redirect for non-OpenID users', async () => {
+ const req = buildReq({
+ user: { _id: 'user1', provider: 'local' },
+ });
+ const res = buildRes();
+
+ await logoutController(req, res);
+
+ const body = res.send.mock.calls[0][0];
+ expect(body.redirect).toBeUndefined();
+ });
+ });
+
+ describe('post_logout_redirect_uri', () => {
+ it('uses OPENID_POST_LOGOUT_REDIRECT_URI when set', async () => {
+ process.env.OPENID_POST_LOGOUT_REDIRECT_URI = 'https://custom.example.com/logged-out';
+ const req = buildReq();
+ const res = buildRes();
+
+ await logoutController(req, res);
+
+ const body = res.send.mock.calls[0][0];
+ const url = new URL(body.redirect);
+ expect(url.searchParams.get('post_logout_redirect_uri')).toBe(
+ 'https://custom.example.com/logged-out',
+ );
+ });
+
+ it('defaults to DOMAIN_CLIENT/login when OPENID_POST_LOGOUT_REDIRECT_URI is unset', async () => {
+ delete process.env.OPENID_POST_LOGOUT_REDIRECT_URI;
+ const req = buildReq();
+ const res = buildRes();
+
+ await logoutController(req, res);
+
+ const body = res.send.mock.calls[0][0];
+ const url = new URL(body.redirect);
+ expect(url.searchParams.get('post_logout_redirect_uri')).toBe(
+ 'https://app.example.com/login',
+ );
+ });
+ });
+
+ describe('OpenID config not available', () => {
+ it('warns and returns no redirect when getOpenIdConfig throws', async () => {
+ mockGetOpenIdConfig.mockImplementation(() => {
+ throw new Error('OpenID configuration has not been initialized');
+ });
+ const req = buildReq();
+ const res = buildRes();
+
+ await logoutController(req, res);
+
+ const body = res.send.mock.calls[0][0];
+ expect(body.redirect).toBeUndefined();
+ expect(mockLogger.warn).toHaveBeenCalledWith(
+ expect.stringContaining('OpenID config not available'),
+ 'OpenID configuration has not been initialized',
+ );
+ });
+ });
+
+ describe('end_session_endpoint not in metadata', () => {
+ it('warns and returns no redirect when end_session_endpoint is missing', async () => {
+ mockGetOpenIdConfig.mockReturnValue({
+ serverMetadata: () => ({}),
+ });
+ const req = buildReq();
+ const res = buildRes();
+
+ await logoutController(req, res);
+
+ const body = res.send.mock.calls[0][0];
+ expect(body.redirect).toBeUndefined();
+ expect(mockLogger.warn).toHaveBeenCalledWith(
+ expect.stringContaining('end_session_endpoint not found'),
+ );
+ });
+ });
+
+ describe('error handling', () => {
+ it('returns 500 on logoutUser error', async () => {
+ mockLogoutUser.mockRejectedValue(new Error('session error'));
+ const req = buildReq();
+ const res = buildRes();
+
+ await logoutController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(500);
+ expect(res.json).toHaveBeenCalledWith({ message: 'session error' });
+ });
+ });
+
+ describe('cookie clearing', () => {
+ it('clears all auth cookies on successful logout', async () => {
+ const req = buildReq();
+ const res = buildRes();
+
+ await logoutController(req, res);
+
+ expect(res.clearCookie).toHaveBeenCalledWith('refreshToken');
+ expect(res.clearCookie).toHaveBeenCalledWith('openid_access_token');
+ expect(res.clearCookie).toHaveBeenCalledWith('openid_id_token');
+ expect(res.clearCookie).toHaveBeenCalledWith('openid_user_id');
+ expect(res.clearCookie).toHaveBeenCalledWith('token_provider');
+ });
+ });
+});
diff --git a/api/server/controllers/mcp.js b/api/server/controllers/mcp.js
index e5dfff61ca..729f01da9d 100644
--- a/api/server/controllers/mcp.js
+++ b/api/server/controllers/mcp.js
@@ -7,9 +7,11 @@
*/
const { logger } = require('@librechat/data-schemas');
const {
+ MCPErrorCodes,
+ redactServerSecrets,
+ redactAllServerSecrets,
isMCPDomainNotAllowedError,
isMCPInspectionFailedError,
- MCPErrorCodes,
} = require('@librechat/api');
const { Constants, MCPServerUserInputSchema } = require('librechat-data-provider');
const { cacheMCPServerTools, getMCPServerTools } = require('~/server/services/Config');
@@ -181,10 +183,8 @@ const getMCPServersList = async (req, res) => {
return res.status(401).json({ message: 'Unauthorized' });
}
- // 2. Get all server configs from registry (YAML + DB)
const serverConfigs = await getMCPServersRegistry().getAllServerConfigs(userId);
-
- return res.json(serverConfigs);
+ return res.json(redactAllServerSecrets(serverConfigs));
} catch (error) {
logger.error('[getMCPServersList]', error);
res.status(500).json({ error: error.message });
@@ -215,7 +215,7 @@ const createMCPServerController = async (req, res) => {
);
res.status(201).json({
serverName: result.serverName,
- ...result.config,
+ ...redactServerSecrets(result.config),
});
} catch (error) {
logger.error('[createMCPServer]', error);
@@ -243,7 +243,7 @@ const getMCPServerById = async (req, res) => {
return res.status(404).json({ message: 'MCP server not found' });
}
- res.status(200).json(parsedConfig);
+ res.status(200).json(redactServerSecrets(parsedConfig));
} catch (error) {
logger.error('[getMCPServerById]', error);
res.status(500).json({ message: error.message });
@@ -274,7 +274,7 @@ const updateMCPServerController = async (req, res) => {
userId,
);
- res.status(200).json(parsedConfig);
+ res.status(200).json(redactServerSecrets(parsedConfig));
} catch (error) {
logger.error('[updateMCPServer]', error);
const mcpErrorResponse = handleMCPError(error, res);
diff --git a/api/server/controllers/tools.js b/api/server/controllers/tools.js
index 14a757e2bc..1df11b1059 100644
--- a/api/server/controllers/tools.js
+++ b/api/server/controllers/tools.js
@@ -9,13 +9,11 @@ const {
ToolCallTypes,
PermissionTypes,
} = require('librechat-data-provider');
+const { getRoleByName, createToolCall, getToolCallsByConvo, getMessage } = require('~/models');
const { processFileURL, uploadImageBuffer } = require('~/server/services/Files/process');
const { processCodeOutput } = require('~/server/services/Files/Code/process');
-const { createToolCall, getToolCallsByConvo } = require('~/models/ToolCall');
const { loadAuthValues } = require('~/server/services/Tools/credentials');
const { loadTools } = require('~/app/clients/tools/util');
-const { getRoleByName } = require('~/models/Role');
-const { getMessage } = require('~/models/Message');
const fieldsMap = {
[Tools.execute_code]: [EnvVar.CODE_API_KEY],
diff --git a/api/server/experimental.js b/api/server/experimental.js
index 4a457abf61..8982b69afb 100644
--- a/api/server/experimental.js
+++ b/api/server/experimental.js
@@ -14,6 +14,7 @@ const { logger } = require('@librechat/data-schemas');
const mongoSanitize = require('express-mongo-sanitize');
const {
isEnabled,
+ apiNotFound,
ErrorController,
performStartupChecks,
handleJsonParseError,
@@ -23,14 +24,14 @@ const { connectDb, indexSync } = require('~/db');
const initializeOAuthReconnectManager = require('./services/initializeOAuthReconnectManager');
const createValidateImageRequest = require('./middleware/validateImageRequest');
const { jwtLogin, ldapLogin, passportLogin } = require('~/strategies');
-const { updateInterfacePermissions } = require('~/models/interface');
+const { updateInterfacePermissions: updateInterfacePerms } = require('@librechat/api');
+const { getRoleByName, updateAccessPermissions, seedDatabase } = require('~/models');
const { checkMigrations } = require('./services/start/migration');
const initializeMCPs = require('./services/initializeMCPs');
const configureSocialLogins = require('./socialLogins');
const { getAppConfig } = require('./services/Config');
const staticCache = require('./utils/staticCache');
const noIndex = require('./middleware/noIndex');
-const { seedDatabase } = require('~/models');
const routes = require('./routes');
const { PORT, HOST, ALLOW_SOCIAL_LOGIN, DISABLE_COMPRESSION, TRUST_PROXY } = process.env ?? {};
@@ -221,7 +222,7 @@ if (cluster.isMaster) {
const appConfig = await getAppConfig();
initializeFileStorage(appConfig);
await performStartupChecks(appConfig);
- await updateInterfacePermissions(appConfig);
+ await updateInterfacePerms({ appConfig, getRoleByName, updateAccessPermissions });
/** Load index.html for SPA serving */
const indexPath = path.join(appConfig.paths.dist, 'index.html');
@@ -297,6 +298,7 @@ if (cluster.isMaster) {
/** Routes */
app.use('/oauth', routes.oauth);
app.use('/api/auth', routes.auth);
+ app.use('/api/admin', routes.adminAuth);
app.use('/api/actions', routes.actions);
app.use('/api/keys', routes.keys);
app.use('/api/api-keys', routes.apiKeys);
@@ -310,7 +312,6 @@ if (cluster.isMaster) {
app.use('/api/endpoints', routes.endpoints);
app.use('/api/balance', routes.balance);
app.use('/api/models', routes.models);
- app.use('/api/plugins', routes.plugins);
app.use('/api/config', routes.config);
app.use('/api/assistants', routes.assistants);
app.use('/api/files', await routes.files.initialize());
@@ -324,8 +325,8 @@ if (cluster.isMaster) {
app.use('/api/tags', routes.tags);
app.use('/api/mcp', routes.mcp);
- /** Error handler */
- app.use(ErrorController);
+ /** 404 for unmatched API routes */
+ app.use('/api', apiNotFound);
/** SPA fallback - serve index.html for all unmatched routes */
app.use((req, res) => {
@@ -343,6 +344,9 @@ if (cluster.isMaster) {
res.send(updatedIndexHtml);
});
+ /** Error handler (must be last - Express identifies error middleware by its 4-arg signature) */
+ app.use(ErrorController);
+
/** Start listening on shared port (cluster will distribute connections) */
app.listen(port, host, async (err) => {
if (err) {
diff --git a/api/server/index.js b/api/server/index.js
index fcd0229c9f..ba376ab335 100644
--- a/api/server/index.js
+++ b/api/server/index.js
@@ -12,25 +12,28 @@ const { logger } = require('@librechat/data-schemas');
const mongoSanitize = require('express-mongo-sanitize');
const {
isEnabled,
+ apiNotFound,
ErrorController,
+ memoryDiagnostics,
performStartupChecks,
handleJsonParseError,
- initializeFileStorage,
GenerationJobManager,
createStreamServices,
+ initializeFileStorage,
+ updateInterfacePermissions,
} = require('@librechat/api');
const { connectDb, indexSync } = require('~/db');
const initializeOAuthReconnectManager = require('./services/initializeOAuthReconnectManager');
+const { getRoleByName, updateAccessPermissions, seedDatabase } = require('~/models');
+const { capabilityContextMiddleware } = require('./middleware/roles/capabilities');
const createValidateImageRequest = require('./middleware/validateImageRequest');
const { jwtLogin, ldapLogin, passportLogin } = require('~/strategies');
-const { updateInterfacePermissions } = require('~/models/interface');
const { checkMigrations } = require('./services/start/migration');
const initializeMCPs = require('./services/initializeMCPs');
const configureSocialLogins = require('./socialLogins');
const { getAppConfig } = require('./services/Config');
const staticCache = require('./utils/staticCache');
const noIndex = require('./middleware/noIndex');
-const { seedDatabase } = require('~/models');
const routes = require('./routes');
const { PORT, HOST, ALLOW_SOCIAL_LOGIN, DISABLE_COMPRESSION, TRUST_PROXY } = process.env ?? {};
@@ -60,7 +63,7 @@ const startServer = async () => {
const appConfig = await getAppConfig();
initializeFileStorage(appConfig);
await performStartupChecks(appConfig);
- await updateInterfacePermissions(appConfig);
+ await updateInterfacePermissions({ appConfig, getRoleByName, updateAccessPermissions });
const indexPath = path.join(appConfig.paths.dist, 'index.html');
let indexHTML = fs.readFileSync(indexPath, 'utf8');
@@ -131,6 +134,9 @@ const startServer = async () => {
await configureSocialLogins(app);
}
+ /* Per-request capability cache — must be registered before any route that calls hasCapability */
+ app.use(capabilityContextMiddleware);
+
app.use('/oauth', routes.oauth);
/* API Endpoints */
app.use('/api/auth', routes.auth);
@@ -162,8 +168,10 @@ const startServer = async () => {
app.use('/api/tags', routes.tags);
app.use('/api/mcp', routes.mcp);
- app.use(ErrorController);
+ /** 404 for unmatched API routes */
+ app.use('/api', apiNotFound);
+ /** SPA fallback - serve index.html for all unmatched routes */
app.use((req, res) => {
res.set({
'Cache-Control': process.env.INDEX_CACHE_CONTROL || 'no-cache, no-store, must-revalidate',
@@ -179,6 +187,9 @@ const startServer = async () => {
res.send(updatedIndexHtml);
});
+ /** Error handler (must be last - Express identifies error middleware by its 4-arg signature) */
+ app.use(ErrorController);
+
app.listen(port, host, async (err) => {
if (err) {
logger.error('Failed to start server:', err);
@@ -201,6 +212,11 @@ const startServer = async () => {
const streamServices = createStreamServices();
GenerationJobManager.configure(streamServices);
GenerationJobManager.initialize();
+
+ const inspectFlags = process.execArgv.some((arg) => arg.startsWith('--inspect'));
+ if (inspectFlags || isEnabled(process.env.MEM_DIAG)) {
+ memoryDiagnostics.start();
+ }
});
};
@@ -251,6 +267,15 @@ process.on('uncaughtException', (err) => {
return;
}
+ if (isEnabled(process.env.CONTINUE_ON_UNCAUGHT_EXCEPTION)) {
+ logger.error('Unhandled error encountered. The app will continue running.', {
+ name: err?.name,
+ message: err?.message,
+ stack: err?.stack,
+ });
+ return;
+ }
+
process.exit(1);
});
diff --git a/api/server/index.spec.js b/api/server/index.spec.js
index c73c605518..7b3d062fce 100644
--- a/api/server/index.spec.js
+++ b/api/server/index.spec.js
@@ -100,6 +100,40 @@ describe('Server Configuration', () => {
expect(response.headers['expires']).toBe('0');
});
+ it('should return 404 JSON for undefined API routes', async () => {
+ const response = await request(app).get('/api/nonexistent');
+ expect(response.status).toBe(404);
+ expect(response.body).toEqual({ message: 'Endpoint not found' });
+ });
+
+ it('should return 404 JSON for nested undefined API routes', async () => {
+ const response = await request(app).get('/api/nonexistent/nested/path');
+ expect(response.status).toBe(404);
+ expect(response.body).toEqual({ message: 'Endpoint not found' });
+ });
+
+ it('should return 404 JSON for non-GET methods on undefined API routes', async () => {
+ const post = await request(app).post('/api/nonexistent');
+ expect(post.status).toBe(404);
+ expect(post.body).toEqual({ message: 'Endpoint not found' });
+
+ const del = await request(app).delete('/api/nonexistent');
+ expect(del.status).toBe(404);
+ expect(del.body).toEqual({ message: 'Endpoint not found' });
+ });
+
+ it('should return 404 JSON for the /api root path', async () => {
+ const response = await request(app).get('/api');
+ expect(response.status).toBe(404);
+ expect(response.body).toEqual({ message: 'Endpoint not found' });
+ });
+
+ it('should serve SPA HTML for non-API unmatched routes', async () => {
+ const response = await request(app).get('/this/does/not/exist');
+ expect(response.status).toBe(200);
+ expect(response.headers['content-type']).toMatch(/html/);
+ });
+
it('should return 500 for unknown errors via ErrorController', async () => {
// Testing the error handling here on top of unit tests to ensure the middleware is correctly integrated
diff --git a/api/server/middleware/abortMiddleware.js b/api/server/middleware/abortMiddleware.js
index d07a09682d..e0c5ae0ff0 100644
--- a/api/server/middleware/abortMiddleware.js
+++ b/api/server/middleware/abortMiddleware.js
@@ -1,18 +1,18 @@
const { logger } = require('@librechat/data-schemas');
+const { isAssistantsEndpoint, ErrorTypes } = require('librechat-data-provider');
const {
- countTokens,
isEnabled,
sendEvent,
+ countTokens,
GenerationJobManager,
+ recordCollectedUsage,
sanitizeMessageForTransmit,
} = require('@librechat/api');
-const { isAssistantsEndpoint, ErrorTypes } = require('librechat-data-provider');
-const { spendTokens, spendStructuredTokens } = require('~/models/spendTokens');
const { truncateText, smartTruncateText } = require('~/app/clients/prompts');
const clearPendingReq = require('~/cache/clearPendingReq');
const { sendError } = require('~/server/middleware/error');
-const { saveMessage, getConvo } = require('~/models');
const { abortRun } = require('./abortRun');
+const db = require('~/models');
/**
* Spend tokens for all models from collected usage.
@@ -27,62 +27,35 @@ const { abortRun } = require('./abortRun');
* @param {string} params.conversationId - Conversation ID
* @param {Array} params.collectedUsage - Usage metadata from all models
* @param {string} [params.fallbackModel] - Fallback model name if not in usage
+ * @param {string} [params.messageId] - The response message ID for transaction correlation
*/
-async function spendCollectedUsage({ userId, conversationId, collectedUsage, fallbackModel }) {
+async function spendCollectedUsage({
+ userId,
+ conversationId,
+ collectedUsage,
+ fallbackModel,
+ messageId,
+}) {
if (!collectedUsage || collectedUsage.length === 0) {
return;
}
- const spendPromises = [];
-
- for (const usage of collectedUsage) {
- if (!usage) {
- continue;
- }
-
- // Support both OpenAI format (input_token_details) and Anthropic format (cache_*_input_tokens)
- const cache_creation =
- Number(usage.input_token_details?.cache_creation) ||
- Number(usage.cache_creation_input_tokens) ||
- 0;
- const cache_read =
- Number(usage.input_token_details?.cache_read) || Number(usage.cache_read_input_tokens) || 0;
-
- const txMetadata = {
- context: 'abort',
- conversationId,
+ await recordCollectedUsage(
+ {
+ spendTokens: db.spendTokens,
+ spendStructuredTokens: db.spendStructuredTokens,
+ pricing: { getMultiplier: db.getMultiplier, getCacheMultiplier: db.getCacheMultiplier },
+ bulkWriteOps: { insertMany: db.bulkInsertTransactions, updateBalance: db.updateBalance },
+ },
+ {
user: userId,
- model: usage.model ?? fallbackModel,
- };
-
- if (cache_creation > 0 || cache_read > 0) {
- spendPromises.push(
- spendStructuredTokens(txMetadata, {
- promptTokens: {
- input: usage.input_tokens,
- write: cache_creation,
- read: cache_read,
- },
- completionTokens: usage.output_tokens,
- }).catch((err) => {
- logger.error('[abortMiddleware] Error spending structured tokens for abort', err);
- }),
- );
- continue;
- }
-
- spendPromises.push(
- spendTokens(txMetadata, {
- promptTokens: usage.input_tokens,
- completionTokens: usage.output_tokens,
- }).catch((err) => {
- logger.error('[abortMiddleware] Error spending tokens for abort', err);
- }),
- );
- }
-
- // Wait for all token spending to complete
- await Promise.all(spendPromises);
+ conversationId,
+ collectedUsage,
+ context: 'abort',
+ messageId,
+ model: fallbackModel,
+ },
+ );
// Clear the array to prevent double-spending from the AgentClient finally block.
// The collectedUsage array is shared by reference with AgentClient.collectedUsage,
@@ -144,23 +117,28 @@ async function abortMessage(req, res) {
conversationId: jobData?.conversationId,
collectedUsage,
fallbackModel: jobData?.model,
+ messageId: jobData?.responseMessageId,
});
} else {
// Fallback: no collected usage, use text-based token counting for primary model only
- await spendTokens(
+ await db.spendTokens(
{ ...responseMessage, context: 'incomplete', user: userId },
{ promptTokens, completionTokens },
);
}
- await saveMessage(
- req,
+ await db.saveMessage(
+ {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ },
{ ...responseMessage, user: userId },
{ context: 'api/server/middleware/abortMiddleware.js' },
);
// Get conversation for title
- const conversation = await getConvo(userId, conversationId);
+ const conversation = await db.getConvo(userId, conversationId);
const finalEvent = {
title: conversation && !conversation.title ? null : conversation?.title || 'New Chat',
@@ -292,4 +270,5 @@ const handleAbortError = async (res, req, error, data) => {
module.exports = {
handleAbort,
handleAbortError,
+ spendCollectedUsage,
};
diff --git a/api/server/middleware/abortMiddleware.spec.js b/api/server/middleware/abortMiddleware.spec.js
index 93f2ce558b..a4ce85674b 100644
--- a/api/server/middleware/abortMiddleware.spec.js
+++ b/api/server/middleware/abortMiddleware.spec.js
@@ -4,15 +4,21 @@
* This tests the token spending logic for abort scenarios,
* particularly for parallel agents (addedConvo) where multiple
* models need their tokens spent.
+ *
+ * spendCollectedUsage delegates to recordCollectedUsage from @librechat/api,
+ * passing pricing + bulkWriteOps deps, with context: 'abort'.
+ * After spending, it clears the collectedUsage array to prevent double-spending
+ * from the AgentClient finally block (which shares the same array reference).
*/
const mockSpendTokens = jest.fn().mockResolvedValue();
const mockSpendStructuredTokens = jest.fn().mockResolvedValue();
+const mockRecordCollectedUsage = jest
+ .fn()
+ .mockResolvedValue({ input_tokens: 100, output_tokens: 50 });
-jest.mock('~/models/spendTokens', () => ({
- spendTokens: (...args) => mockSpendTokens(...args),
- spendStructuredTokens: (...args) => mockSpendStructuredTokens(...args),
-}));
+const mockGetMultiplier = jest.fn().mockReturnValue(1);
+const mockGetCacheMultiplier = jest.fn().mockReturnValue(null);
jest.mock('@librechat/data-schemas', () => ({
logger: {
@@ -30,6 +36,7 @@ jest.mock('@librechat/api', () => ({
GenerationJobManager: {
abortJob: jest.fn(),
},
+ recordCollectedUsage: mockRecordCollectedUsage,
sanitizeMessageForTransmit: jest.fn((msg) => msg),
}));
@@ -49,94 +56,31 @@ jest.mock('~/server/middleware/error', () => ({
sendError: jest.fn(),
}));
+const mockUpdateBalance = jest.fn().mockResolvedValue({});
+const mockBulkInsertTransactions = jest.fn().mockResolvedValue(undefined);
jest.mock('~/models', () => ({
saveMessage: jest.fn().mockResolvedValue(),
getConvo: jest.fn().mockResolvedValue({ title: 'Test Chat' }),
+ updateBalance: mockUpdateBalance,
+ bulkInsertTransactions: mockBulkInsertTransactions,
+ spendTokens: (...args) => mockSpendTokens(...args),
+ spendStructuredTokens: (...args) => mockSpendStructuredTokens(...args),
+ getMultiplier: mockGetMultiplier,
+ getCacheMultiplier: mockGetCacheMultiplier,
}));
jest.mock('./abortRun', () => ({
abortRun: jest.fn(),
}));
-// Import the module after mocks are set up
-// We need to extract the spendCollectedUsage function for testing
-// Since it's not exported, we'll test it through the handleAbort flow
+const { spendCollectedUsage } = require('./abortMiddleware');
describe('abortMiddleware - spendCollectedUsage', () => {
beforeEach(() => {
jest.clearAllMocks();
});
- describe('spendCollectedUsage logic', () => {
- // Since spendCollectedUsage is not exported, we test the logic directly
- // by replicating the function here for unit testing
-
- const spendCollectedUsage = async ({
- userId,
- conversationId,
- collectedUsage,
- fallbackModel,
- }) => {
- if (!collectedUsage || collectedUsage.length === 0) {
- return;
- }
-
- const spendPromises = [];
-
- for (const usage of collectedUsage) {
- if (!usage) {
- continue;
- }
-
- const cache_creation =
- Number(usage.input_token_details?.cache_creation) ||
- Number(usage.cache_creation_input_tokens) ||
- 0;
- const cache_read =
- Number(usage.input_token_details?.cache_read) ||
- Number(usage.cache_read_input_tokens) ||
- 0;
-
- const txMetadata = {
- context: 'abort',
- conversationId,
- user: userId,
- model: usage.model ?? fallbackModel,
- };
-
- if (cache_creation > 0 || cache_read > 0) {
- spendPromises.push(
- mockSpendStructuredTokens(txMetadata, {
- promptTokens: {
- input: usage.input_tokens,
- write: cache_creation,
- read: cache_read,
- },
- completionTokens: usage.output_tokens,
- }).catch(() => {
- // Log error but don't throw
- }),
- );
- continue;
- }
-
- spendPromises.push(
- mockSpendTokens(txMetadata, {
- promptTokens: usage.input_tokens,
- completionTokens: usage.output_tokens,
- }).catch(() => {
- // Log error but don't throw
- }),
- );
- }
-
- // Wait for all token spending to complete
- await Promise.all(spendPromises);
-
- // Clear the array to prevent double-spending
- collectedUsage.length = 0;
- };
-
+ describe('spendCollectedUsage delegation', () => {
it('should return early if collectedUsage is empty', async () => {
await spendCollectedUsage({
userId: 'user-123',
@@ -145,8 +89,7 @@ describe('abortMiddleware - spendCollectedUsage', () => {
fallbackModel: 'gpt-4',
});
- expect(mockSpendTokens).not.toHaveBeenCalled();
- expect(mockSpendStructuredTokens).not.toHaveBeenCalled();
+ expect(mockRecordCollectedUsage).not.toHaveBeenCalled();
});
it('should return early if collectedUsage is null', async () => {
@@ -157,28 +100,10 @@ describe('abortMiddleware - spendCollectedUsage', () => {
fallbackModel: 'gpt-4',
});
- expect(mockSpendTokens).not.toHaveBeenCalled();
- expect(mockSpendStructuredTokens).not.toHaveBeenCalled();
+ expect(mockRecordCollectedUsage).not.toHaveBeenCalled();
});
- it('should skip null entries in collectedUsage', async () => {
- const collectedUsage = [
- { input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
- null,
- { input_tokens: 200, output_tokens: 60, model: 'gpt-4' },
- ];
-
- await spendCollectedUsage({
- userId: 'user-123',
- conversationId: 'convo-123',
- collectedUsage,
- fallbackModel: 'gpt-4',
- });
-
- expect(mockSpendTokens).toHaveBeenCalledTimes(2);
- });
-
- it('should spend tokens for single model', async () => {
+ it('should call recordCollectedUsage with abort context and full deps', async () => {
const collectedUsage = [{ input_tokens: 100, output_tokens: 50, model: 'gpt-4' }];
await spendCollectedUsage({
@@ -186,21 +111,35 @@ describe('abortMiddleware - spendCollectedUsage', () => {
conversationId: 'convo-123',
collectedUsage,
fallbackModel: 'gpt-4',
+ messageId: 'msg-123',
});
- expect(mockSpendTokens).toHaveBeenCalledTimes(1);
- expect(mockSpendTokens).toHaveBeenCalledWith(
- expect.objectContaining({
- context: 'abort',
- conversationId: 'convo-123',
+ expect(mockRecordCollectedUsage).toHaveBeenCalledTimes(1);
+ expect(mockRecordCollectedUsage).toHaveBeenCalledWith(
+ {
+ spendTokens: expect.any(Function),
+ spendStructuredTokens: expect.any(Function),
+ pricing: {
+ getMultiplier: mockGetMultiplier,
+ getCacheMultiplier: mockGetCacheMultiplier,
+ },
+ bulkWriteOps: {
+ insertMany: mockBulkInsertTransactions,
+ updateBalance: mockUpdateBalance,
+ },
+ },
+ {
user: 'user-123',
+ conversationId: 'convo-123',
+ collectedUsage,
+ context: 'abort',
+ messageId: 'msg-123',
model: 'gpt-4',
- }),
- { promptTokens: 100, completionTokens: 50 },
+ },
);
});
- it('should spend tokens for multiple models (parallel agents)', async () => {
+ it('should pass context abort for multiple models (parallel agents)', async () => {
const collectedUsage = [
{ input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
{ input_tokens: 80, output_tokens: 40, model: 'claude-3' },
@@ -214,136 +153,17 @@ describe('abortMiddleware - spendCollectedUsage', () => {
fallbackModel: 'gpt-4',
});
- expect(mockSpendTokens).toHaveBeenCalledTimes(3);
-
- // Verify each model was called
- expect(mockSpendTokens).toHaveBeenNthCalledWith(
- 1,
- expect.objectContaining({ model: 'gpt-4' }),
- { promptTokens: 100, completionTokens: 50 },
- );
- expect(mockSpendTokens).toHaveBeenNthCalledWith(
- 2,
- expect.objectContaining({ model: 'claude-3' }),
- { promptTokens: 80, completionTokens: 40 },
- );
- expect(mockSpendTokens).toHaveBeenNthCalledWith(
- 3,
- expect.objectContaining({ model: 'gemini-pro' }),
- { promptTokens: 120, completionTokens: 60 },
- );
- });
-
- it('should use fallbackModel when usage.model is missing', async () => {
- const collectedUsage = [{ input_tokens: 100, output_tokens: 50 }];
-
- await spendCollectedUsage({
- userId: 'user-123',
- conversationId: 'convo-123',
- collectedUsage,
- fallbackModel: 'fallback-model',
- });
-
- expect(mockSpendTokens).toHaveBeenCalledWith(
- expect.objectContaining({ model: 'fallback-model' }),
+ expect(mockRecordCollectedUsage).toHaveBeenCalledTimes(1);
+ expect(mockRecordCollectedUsage).toHaveBeenCalledWith(
expect.any(Object),
+ expect.objectContaining({
+ context: 'abort',
+ collectedUsage,
+ }),
);
});
- it('should use spendStructuredTokens for OpenAI format cache tokens', async () => {
- const collectedUsage = [
- {
- input_tokens: 100,
- output_tokens: 50,
- model: 'gpt-4',
- input_token_details: {
- cache_creation: 20,
- cache_read: 10,
- },
- },
- ];
-
- await spendCollectedUsage({
- userId: 'user-123',
- conversationId: 'convo-123',
- collectedUsage,
- fallbackModel: 'gpt-4',
- });
-
- expect(mockSpendStructuredTokens).toHaveBeenCalledTimes(1);
- expect(mockSpendTokens).not.toHaveBeenCalled();
- expect(mockSpendStructuredTokens).toHaveBeenCalledWith(
- expect.objectContaining({ model: 'gpt-4', context: 'abort' }),
- {
- promptTokens: {
- input: 100,
- write: 20,
- read: 10,
- },
- completionTokens: 50,
- },
- );
- });
-
- it('should use spendStructuredTokens for Anthropic format cache tokens', async () => {
- const collectedUsage = [
- {
- input_tokens: 100,
- output_tokens: 50,
- model: 'claude-3',
- cache_creation_input_tokens: 25,
- cache_read_input_tokens: 15,
- },
- ];
-
- await spendCollectedUsage({
- userId: 'user-123',
- conversationId: 'convo-123',
- collectedUsage,
- fallbackModel: 'claude-3',
- });
-
- expect(mockSpendStructuredTokens).toHaveBeenCalledTimes(1);
- expect(mockSpendTokens).not.toHaveBeenCalled();
- expect(mockSpendStructuredTokens).toHaveBeenCalledWith(
- expect.objectContaining({ model: 'claude-3' }),
- {
- promptTokens: {
- input: 100,
- write: 25,
- read: 15,
- },
- completionTokens: 50,
- },
- );
- });
-
- it('should handle mixed cache and non-cache entries', async () => {
- const collectedUsage = [
- { input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
- {
- input_tokens: 150,
- output_tokens: 30,
- model: 'claude-3',
- cache_creation_input_tokens: 20,
- cache_read_input_tokens: 10,
- },
- { input_tokens: 200, output_tokens: 20, model: 'gemini-pro' },
- ];
-
- await spendCollectedUsage({
- userId: 'user-123',
- conversationId: 'convo-123',
- collectedUsage,
- fallbackModel: 'gpt-4',
- });
-
- expect(mockSpendTokens).toHaveBeenCalledTimes(2);
- expect(mockSpendStructuredTokens).toHaveBeenCalledTimes(1);
- });
-
it('should handle real-world parallel agent abort scenario', async () => {
- // Simulates: Primary agent (gemini) + addedConvo agent (gpt-5) aborted mid-stream
const collectedUsage = [
{ input_tokens: 31596, output_tokens: 151, model: 'gemini-3-flash-preview' },
{ input_tokens: 28000, output_tokens: 120, model: 'gpt-5.2' },
@@ -356,27 +176,24 @@ describe('abortMiddleware - spendCollectedUsage', () => {
fallbackModel: 'gemini-3-flash-preview',
});
- expect(mockSpendTokens).toHaveBeenCalledTimes(2);
-
- // Primary model
- expect(mockSpendTokens).toHaveBeenNthCalledWith(
- 1,
- expect.objectContaining({ model: 'gemini-3-flash-preview' }),
- { promptTokens: 31596, completionTokens: 151 },
- );
-
- // Parallel model (addedConvo)
- expect(mockSpendTokens).toHaveBeenNthCalledWith(
- 2,
- expect.objectContaining({ model: 'gpt-5.2' }),
- { promptTokens: 28000, completionTokens: 120 },
+ expect(mockRecordCollectedUsage).toHaveBeenCalledTimes(1);
+ expect(mockRecordCollectedUsage).toHaveBeenCalledWith(
+ expect.any(Object),
+ expect.objectContaining({
+ user: 'user-123',
+ conversationId: 'convo-123',
+ context: 'abort',
+ model: 'gemini-3-flash-preview',
+ }),
);
});
+ /**
+ * Race condition prevention: after abort middleware spends tokens,
+ * the collectedUsage array is cleared so AgentClient.recordCollectedUsage()
+ * (which shares the same array reference) sees an empty array and returns early.
+ */
it('should clear collectedUsage array after spending to prevent double-spending', async () => {
- // This tests the race condition fix: after abort middleware spends tokens,
- // the collectedUsage array is cleared so AgentClient.recordCollectedUsage()
- // (which shares the same array reference) sees an empty array and returns early.
const collectedUsage = [
{ input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
{ input_tokens: 80, output_tokens: 40, model: 'claude-3' },
@@ -391,19 +208,16 @@ describe('abortMiddleware - spendCollectedUsage', () => {
fallbackModel: 'gpt-4',
});
- expect(mockSpendTokens).toHaveBeenCalledTimes(2);
-
- // The array should be cleared after spending
+ expect(mockRecordCollectedUsage).toHaveBeenCalledTimes(1);
expect(collectedUsage.length).toBe(0);
});
- it('should await all token spending operations before clearing array', async () => {
- // Ensure we don't clear the array before spending completes
- let spendCallCount = 0;
- mockSpendTokens.mockImplementation(async () => {
- spendCallCount++;
- // Simulate async delay
+ it('should await recordCollectedUsage before clearing array', async () => {
+ let resolved = false;
+ mockRecordCollectedUsage.mockImplementation(async () => {
await new Promise((resolve) => setTimeout(resolve, 10));
+ resolved = true;
+ return { input_tokens: 100, output_tokens: 50 };
});
const collectedUsage = [
@@ -418,10 +232,7 @@ describe('abortMiddleware - spendCollectedUsage', () => {
fallbackModel: 'gpt-4',
});
- // Both spend calls should have completed
- expect(spendCallCount).toBe(2);
-
- // Array should be cleared after awaiting
+ expect(resolved).toBe(true);
expect(collectedUsage.length).toBe(0);
});
});
diff --git a/api/server/middleware/abortRun.js b/api/server/middleware/abortRun.js
index 44375f5024..318693fe15 100644
--- a/api/server/middleware/abortRun.js
+++ b/api/server/middleware/abortRun.js
@@ -3,8 +3,7 @@ const { logger } = require('@librechat/data-schemas');
const { CacheKeys, RunStatus, isUUID } = require('librechat-data-provider');
const { initializeClient } = require('~/server/services/Endpoints/assistants');
const { checkMessageGaps, recordUsage } = require('~/server/services/Threads');
-const { deleteMessages } = require('~/models/Message');
-const { getConvo } = require('~/models/Conversation');
+const { deleteMessages, getConvo } = require('~/models');
const getLogStores = require('~/cache/getLogStores');
const three_minutes = 1000 * 60 * 3;
diff --git a/api/server/middleware/accessResources/canAccessAgentFromBody.js b/api/server/middleware/accessResources/canAccessAgentFromBody.js
index f8112af14d..5ade76bb77 100644
--- a/api/server/middleware/accessResources/canAccessAgentFromBody.js
+++ b/api/server/middleware/accessResources/canAccessAgentFromBody.js
@@ -1,42 +1,145 @@
const { logger } = require('@librechat/data-schemas');
const {
Constants,
+ Permissions,
ResourceType,
+ SystemRoles,
+ PermissionTypes,
isAgentsEndpoint,
isEphemeralAgentId,
} = require('librechat-data-provider');
+const { checkPermission } = require('~/server/services/PermissionService');
const { canAccessResource } = require('./canAccessResource');
-const { getAgent } = require('~/models/Agent');
+const db = require('~/models');
+
+const { getRoleByName, getAgent } = db;
/**
- * Agent ID resolver function for agent_id from request body
- * Resolves custom agent ID (e.g., "agent_abc123") to MongoDB ObjectId
- * This is used specifically for chat routes where agent_id comes from request body
- *
+ * Resolves custom agent ID (e.g., "agent_abc123") to a MongoDB document.
* @param {string} agentCustomId - Custom agent ID from request body
- * @returns {Promise} Agent document with _id field, or null if not found
+ * @returns {Promise} Agent document with _id field, or null if ephemeral/not found
*/
const resolveAgentIdFromBody = async (agentCustomId) => {
- // Handle ephemeral agents - they don't need permission checks
- // Real agent IDs always start with "agent_", so anything else is ephemeral
if (isEphemeralAgentId(agentCustomId)) {
- return null; // No permission check needed for ephemeral agents
+ return null;
}
-
- return await getAgent({ id: agentCustomId });
+ return getAgent({ id: agentCustomId });
};
/**
- * Middleware factory that creates middleware to check agent access permissions from request body.
- * This middleware is specifically designed for chat routes where the agent_id comes from req.body
- * instead of route parameters.
+ * Creates a `canAccessResource` middleware for the given agent ID
+ * and chains to the provided continuation on success.
+ *
+ * @param {string} agentId - The agent's custom string ID (e.g., "agent_abc123")
+ * @param {number} requiredPermission - Permission bit(s) required
+ * @param {import('express').Request} req
+ * @param {import('express').Response} res - Written on deny; continuation called on allow
+ * @param {Function} continuation - Called when the permission check passes
+ * @returns {Promise}
+ */
+const checkAgentResourceAccess = (agentId, requiredPermission, req, res, continuation) => {
+ const middleware = canAccessResource({
+ resourceType: ResourceType.AGENT,
+ requiredPermission,
+ resourceIdParam: 'agent_id',
+ idResolver: () => resolveAgentIdFromBody(agentId),
+ });
+
+ const tempReq = {
+ ...req,
+ params: { ...req.params, agent_id: agentId },
+ };
+
+ return middleware(tempReq, res, continuation);
+};
+
+/**
+ * Middleware factory that validates MULTI_CONVO:USE role permission and, when
+ * addedConvo.agent_id is a non-ephemeral agent, the same resource-level permission
+ * required for the primary agent (`requiredPermission`). Caches the resolved agent
+ * document on `req.resolvedAddedAgent` to avoid a duplicate DB fetch in `loadAddedAgent`.
+ *
+ * @param {number} requiredPermission - Permission bit(s) to check on the added agent resource
+ * @returns {(req: import('express').Request, res: import('express').Response, next: Function) => Promise}
+ */
+const checkAddedConvoAccess = (requiredPermission) => async (req, res, next) => {
+ const addedConvo = req.body?.addedConvo;
+ if (!addedConvo || typeof addedConvo !== 'object' || Array.isArray(addedConvo)) {
+ return next();
+ }
+
+ try {
+ if (!req.user?.role) {
+ return res.status(403).json({
+ error: 'Forbidden',
+ message: 'Insufficient permissions for multi-conversation',
+ });
+ }
+
+ if (req.user.role !== SystemRoles.ADMIN) {
+ const role = await getRoleByName(req.user.role);
+ const hasMultiConvo = role?.permissions?.[PermissionTypes.MULTI_CONVO]?.[Permissions.USE];
+ if (!hasMultiConvo) {
+ return res.status(403).json({
+ error: 'Forbidden',
+ message: 'Multi-conversation feature is not enabled',
+ });
+ }
+ }
+
+ const addedAgentId = addedConvo.agent_id;
+ if (!addedAgentId || typeof addedAgentId !== 'string' || isEphemeralAgentId(addedAgentId)) {
+ return next();
+ }
+
+ if (req.user.role === SystemRoles.ADMIN) {
+ return next();
+ }
+
+ const agent = await resolveAgentIdFromBody(addedAgentId);
+ if (!agent) {
+ return res.status(404).json({
+ error: 'Not Found',
+ message: `${ResourceType.AGENT} not found`,
+ });
+ }
+
+ const hasPermission = await checkPermission({
+ userId: req.user.id,
+ role: req.user.role,
+ resourceType: ResourceType.AGENT,
+ resourceId: agent._id,
+ requiredPermission,
+ });
+
+ if (!hasPermission) {
+ return res.status(403).json({
+ error: 'Forbidden',
+ message: `Insufficient permissions to access this ${ResourceType.AGENT}`,
+ });
+ }
+
+ req.resolvedAddedAgent = agent;
+ return next();
+ } catch (error) {
+ logger.error('Failed to validate addedConvo access permissions', error);
+ return res.status(500).json({
+ error: 'Internal Server Error',
+ message: 'Failed to validate addedConvo access permissions',
+ });
+ }
+};
+
+/**
+ * Middleware factory that checks agent access permissions from request body.
+ * Validates both the primary agent_id and, when present, addedConvo.agent_id
+ * (which also requires MULTI_CONVO:USE role permission).
*
* @param {Object} options - Configuration options
* @param {number} options.requiredPermission - The permission bit required (1=view, 2=edit, 4=delete, 8=share)
* @returns {Function} Express middleware function
*
* @example
- * // Basic usage for agent chat (requires VIEW permission)
* router.post('/chat',
* canAccessAgentFromBody({ requiredPermission: PermissionBits.VIEW }),
* buildEndpointOption,
@@ -46,11 +149,12 @@ const resolveAgentIdFromBody = async (agentCustomId) => {
const canAccessAgentFromBody = (options) => {
const { requiredPermission } = options;
- // Validate required options
if (!requiredPermission || typeof requiredPermission !== 'number') {
throw new Error('canAccessAgentFromBody: requiredPermission is required and must be a number');
}
+ const addedConvoMiddleware = checkAddedConvoAccess(requiredPermission);
+
return async (req, res, next) => {
try {
const { endpoint, agent_id } = req.body;
@@ -67,28 +171,13 @@ const canAccessAgentFromBody = (options) => {
});
}
- // Skip permission checks for ephemeral agents
- // Real agent IDs always start with "agent_", so anything else is ephemeral
+ const afterPrimaryCheck = () => addedConvoMiddleware(req, res, next);
+
if (isEphemeralAgentId(agentId)) {
- return next();
+ return afterPrimaryCheck();
}
- const agentAccessMiddleware = canAccessResource({
- resourceType: ResourceType.AGENT,
- requiredPermission,
- resourceIdParam: 'agent_id', // This will be ignored since we use custom resolver
- idResolver: () => resolveAgentIdFromBody(agentId),
- });
-
- const tempReq = {
- ...req,
- params: {
- ...req.params,
- agent_id: agentId,
- },
- };
-
- return agentAccessMiddleware(tempReq, res, next);
+ return checkAgentResourceAccess(agentId, requiredPermission, req, res, afterPrimaryCheck);
} catch (error) {
logger.error('Failed to validate agent access permissions', error);
return res.status(500).json({
diff --git a/api/server/middleware/accessResources/canAccessAgentFromBody.spec.js b/api/server/middleware/accessResources/canAccessAgentFromBody.spec.js
new file mode 100644
index 0000000000..9e5e0b093a
--- /dev/null
+++ b/api/server/middleware/accessResources/canAccessAgentFromBody.spec.js
@@ -0,0 +1,509 @@
+const mongoose = require('mongoose');
+const {
+ ResourceType,
+ SystemRoles,
+ PrincipalType,
+ PrincipalModel,
+} = require('librechat-data-provider');
+const { MongoMemoryServer } = require('mongodb-memory-server');
+const { canAccessAgentFromBody } = require('./canAccessAgentFromBody');
+const { User, Role, AclEntry } = require('~/db/models');
+const { createAgent } = require('~/models');
+
+describe('canAccessAgentFromBody middleware', () => {
+ let mongoServer;
+ let req, res, next;
+ let testUser, otherUser;
+
+ beforeAll(async () => {
+ mongoServer = await MongoMemoryServer.create();
+ await mongoose.connect(mongoServer.getUri());
+ });
+
+ afterAll(async () => {
+ await mongoose.disconnect();
+ await mongoServer.stop();
+ });
+
+ beforeEach(async () => {
+ await mongoose.connection.dropDatabase();
+
+ await Role.create({
+ name: 'test-role',
+ permissions: {
+ AGENTS: { USE: true, CREATE: true, SHARE: true },
+ MULTI_CONVO: { USE: true },
+ },
+ });
+
+ await Role.create({
+ name: 'no-multi-convo',
+ permissions: {
+ AGENTS: { USE: true, CREATE: true, SHARE: true },
+ MULTI_CONVO: { USE: false },
+ },
+ });
+
+ await Role.create({
+ name: SystemRoles.ADMIN,
+ permissions: {
+ AGENTS: { USE: true, CREATE: true, SHARE: true },
+ MULTI_CONVO: { USE: true },
+ },
+ });
+
+ testUser = await User.create({
+ email: 'test@example.com',
+ name: 'Test User',
+ username: 'testuser',
+ role: 'test-role',
+ });
+
+ otherUser = await User.create({
+ email: 'other@example.com',
+ name: 'Other User',
+ username: 'otheruser',
+ role: 'test-role',
+ });
+
+ req = {
+ user: { id: testUser._id, role: testUser.role },
+ params: {},
+ body: {
+ endpoint: 'agents',
+ agent_id: 'ephemeral_primary',
+ },
+ };
+ res = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn(),
+ };
+ next = jest.fn();
+
+ jest.clearAllMocks();
+ });
+
+ describe('middleware factory', () => {
+ test('throws if requiredPermission is missing', () => {
+ expect(() => canAccessAgentFromBody({})).toThrow(
+ 'canAccessAgentFromBody: requiredPermission is required and must be a number',
+ );
+ });
+
+ test('throws if requiredPermission is not a number', () => {
+ expect(() => canAccessAgentFromBody({ requiredPermission: '1' })).toThrow(
+ 'canAccessAgentFromBody: requiredPermission is required and must be a number',
+ );
+ });
+
+ test('returns a middleware function', () => {
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ expect(typeof middleware).toBe('function');
+ expect(middleware.length).toBe(3);
+ });
+ });
+
+ describe('primary agent checks', () => {
+ test('returns 400 when agent_id is missing on agents endpoint', async () => {
+ req.body.agent_id = undefined;
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(400);
+ });
+
+ test('proceeds for ephemeral primary agent without addedConvo', async () => {
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ expect(res.status).not.toHaveBeenCalled();
+ });
+
+ test('proceeds for non-agents endpoint (ephemeral fallback)', async () => {
+ req.body.endpoint = 'openAI';
+ req.body.agent_id = undefined;
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ });
+ });
+
+ describe('addedConvo — absent or invalid shape', () => {
+ test('calls next when addedConvo is absent', async () => {
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ });
+
+ test('calls next when addedConvo is a string', async () => {
+ req.body.addedConvo = 'not-an-object';
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ });
+
+ test('calls next when addedConvo is an array', async () => {
+ req.body.addedConvo = [{ agent_id: 'agent_something' }];
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ });
+ });
+
+ describe('addedConvo — MULTI_CONVO permission gate', () => {
+ test('returns 403 when user lacks MULTI_CONVO:USE', async () => {
+ req.user.role = 'no-multi-convo';
+ req.body.addedConvo = { agent_id: 'agent_x', endpoint: 'agents', model: 'gpt-4' };
+
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(403);
+ expect(res.json).toHaveBeenCalledWith(
+ expect.objectContaining({ message: 'Multi-conversation feature is not enabled' }),
+ );
+ });
+
+ test('returns 403 when user.role is missing', async () => {
+ req.user = { id: testUser._id };
+ req.body.addedConvo = { agent_id: 'agent_x', endpoint: 'agents', model: 'gpt-4' };
+
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(403);
+ });
+
+ test('ADMIN bypasses MULTI_CONVO check', async () => {
+ req.user.role = SystemRoles.ADMIN;
+ req.body.addedConvo = { agent_id: 'ephemeral_x', endpoint: 'agents', model: 'gpt-4' };
+
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ expect(res.status).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('addedConvo — agent_id shape validation', () => {
+ test('calls next when agent_id is ephemeral', async () => {
+ req.body.addedConvo = { agent_id: 'ephemeral_xyz', endpoint: 'agents', model: 'gpt-4' };
+
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ });
+
+ test('calls next when agent_id is absent', async () => {
+ req.body.addedConvo = { endpoint: 'agents', model: 'gpt-4' };
+
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ });
+
+ test('calls next when agent_id is not a string (object injection)', async () => {
+ req.body.addedConvo = { agent_id: { $gt: '' }, endpoint: 'agents', model: 'gpt-4' };
+
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ });
+ });
+
+ describe('addedConvo — agent resource ACL (IDOR prevention)', () => {
+ let addedAgent;
+
+ beforeEach(async () => {
+ addedAgent = await createAgent({
+ id: `agent_added_${Date.now()}`,
+ name: 'Private Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: otherUser._id,
+ });
+
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: otherUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.AGENT,
+ resourceId: addedAgent._id,
+ permBits: 15,
+ grantedBy: otherUser._id,
+ });
+ });
+
+ test('returns 403 when requester has no ACL for the added agent', async () => {
+ req.body.addedConvo = { agent_id: addedAgent.id, endpoint: 'agents', model: 'gpt-4' };
+
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(403);
+ expect(res.json).toHaveBeenCalledWith(
+ expect.objectContaining({
+ message: 'Insufficient permissions to access this agent',
+ }),
+ );
+ });
+
+ test('returns 404 when added agent does not exist', async () => {
+ req.body.addedConvo = {
+ agent_id: 'agent_nonexistent_999',
+ endpoint: 'agents',
+ model: 'gpt-4',
+ };
+
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(404);
+ });
+
+ test('proceeds when requester has ACL for the added agent', async () => {
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: testUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.AGENT,
+ resourceId: addedAgent._id,
+ permBits: 1,
+ grantedBy: otherUser._id,
+ });
+
+ req.body.addedConvo = { agent_id: addedAgent.id, endpoint: 'agents', model: 'gpt-4' };
+
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ expect(res.status).not.toHaveBeenCalled();
+ });
+
+ test('denies when ACL permission bits are insufficient', async () => {
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: testUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.AGENT,
+ resourceId: addedAgent._id,
+ permBits: 1,
+ grantedBy: otherUser._id,
+ });
+
+ req.body.addedConvo = { agent_id: addedAgent.id, endpoint: 'agents', model: 'gpt-4' };
+
+ const middleware = canAccessAgentFromBody({ requiredPermission: 2 });
+ await middleware(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(403);
+ });
+
+ test('caches resolved agent on req.resolvedAddedAgent', async () => {
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: testUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.AGENT,
+ resourceId: addedAgent._id,
+ permBits: 1,
+ grantedBy: otherUser._id,
+ });
+
+ req.body.addedConvo = { agent_id: addedAgent.id, endpoint: 'agents', model: 'gpt-4' };
+
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ expect(req.resolvedAddedAgent).toBeDefined();
+ expect(req.resolvedAddedAgent._id.toString()).toBe(addedAgent._id.toString());
+ });
+
+ test('ADMIN bypasses agent resource ACL for addedConvo', async () => {
+ req.user.role = SystemRoles.ADMIN;
+ req.body.addedConvo = { agent_id: addedAgent.id, endpoint: 'agents', model: 'gpt-4' };
+
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ expect(res.status).not.toHaveBeenCalled();
+ expect(req.resolvedAddedAgent).toBeUndefined();
+ });
+ });
+
+ describe('end-to-end: primary real agent + addedConvo real agent', () => {
+ let primaryAgent, addedAgent;
+
+ beforeEach(async () => {
+ primaryAgent = await createAgent({
+ id: `agent_primary_${Date.now()}`,
+ name: 'Primary Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: testUser._id,
+ });
+
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: testUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.AGENT,
+ resourceId: primaryAgent._id,
+ permBits: 15,
+ grantedBy: testUser._id,
+ });
+
+ addedAgent = await createAgent({
+ id: `agent_added_${Date.now()}`,
+ name: 'Added Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: otherUser._id,
+ });
+
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: otherUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.AGENT,
+ resourceId: addedAgent._id,
+ permBits: 15,
+ grantedBy: otherUser._id,
+ });
+
+ req.body.agent_id = primaryAgent.id;
+ });
+
+ test('both checks pass when user has ACL for both agents', async () => {
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: testUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.AGENT,
+ resourceId: addedAgent._id,
+ permBits: 1,
+ grantedBy: otherUser._id,
+ });
+
+ req.body.addedConvo = { agent_id: addedAgent.id, endpoint: 'agents', model: 'gpt-4' };
+
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ expect(res.status).not.toHaveBeenCalled();
+ expect(req.resolvedAddedAgent).toBeDefined();
+ });
+
+ test('primary passes but addedConvo denied → 403', async () => {
+ req.body.addedConvo = { agent_id: addedAgent.id, endpoint: 'agents', model: 'gpt-4' };
+
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(403);
+ });
+
+ test('primary denied → 403 without reaching addedConvo check', async () => {
+ const foreignAgent = await createAgent({
+ id: `agent_foreign_${Date.now()}`,
+ name: 'Foreign Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: otherUser._id,
+ });
+
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: otherUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.AGENT,
+ resourceId: foreignAgent._id,
+ permBits: 15,
+ grantedBy: otherUser._id,
+ });
+
+ req.body.agent_id = foreignAgent.id;
+ req.body.addedConvo = { agent_id: addedAgent.id, endpoint: 'agents', model: 'gpt-4' };
+
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(403);
+ });
+ });
+
+ describe('ephemeral primary + real addedConvo agent', () => {
+ let addedAgent;
+
+ beforeEach(async () => {
+ addedAgent = await createAgent({
+ id: `agent_added_${Date.now()}`,
+ name: 'Added Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: otherUser._id,
+ });
+
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: otherUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.AGENT,
+ resourceId: addedAgent._id,
+ permBits: 15,
+ grantedBy: otherUser._id,
+ });
+ });
+
+ test('runs full addedConvo ACL check even when primary is ephemeral', async () => {
+ req.body.addedConvo = { agent_id: addedAgent.id, endpoint: 'agents', model: 'gpt-4' };
+
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(403);
+ });
+
+ test('proceeds when user has ACL for added agent (ephemeral primary)', async () => {
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: testUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.AGENT,
+ resourceId: addedAgent._id,
+ permBits: 1,
+ grantedBy: otherUser._id,
+ });
+
+ req.body.addedConvo = { agent_id: addedAgent.id, endpoint: 'agents', model: 'gpt-4' };
+
+ const middleware = canAccessAgentFromBody({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ expect(res.status).not.toHaveBeenCalled();
+ });
+ });
+});
diff --git a/api/server/middleware/accessResources/canAccessAgentResource.js b/api/server/middleware/accessResources/canAccessAgentResource.js
index 62d9f248c0..4c00ab4982 100644
--- a/api/server/middleware/accessResources/canAccessAgentResource.js
+++ b/api/server/middleware/accessResources/canAccessAgentResource.js
@@ -1,6 +1,6 @@
const { ResourceType } = require('librechat-data-provider');
const { canAccessResource } = require('./canAccessResource');
-const { getAgent } = require('~/models/Agent');
+const { getAgent } = require('~/models');
/**
* Agent ID resolver function
diff --git a/api/server/middleware/accessResources/canAccessAgentResource.spec.js b/api/server/middleware/accessResources/canAccessAgentResource.spec.js
index 1106390e72..786636ee74 100644
--- a/api/server/middleware/accessResources/canAccessAgentResource.spec.js
+++ b/api/server/middleware/accessResources/canAccessAgentResource.spec.js
@@ -3,7 +3,7 @@ const { ResourceType, PrincipalType, PrincipalModel } = require('librechat-data-
const { MongoMemoryServer } = require('mongodb-memory-server');
const { canAccessAgentResource } = require('./canAccessAgentResource');
const { User, Role, AclEntry } = require('~/db/models');
-const { createAgent } = require('~/models/Agent');
+const { createAgent } = require('~/models');
describe('canAccessAgentResource middleware', () => {
let mongoServer;
@@ -373,7 +373,7 @@ describe('canAccessAgentResource middleware', () => {
jest.clearAllMocks();
// Update the agent
- const { updateAgent } = require('~/models/Agent');
+ const { updateAgent } = require('~/models');
await updateAgent({ id: agentId }, { description: 'Updated description' });
// Test edit access
diff --git a/api/server/middleware/accessResources/canAccessMCPServerResource.spec.js b/api/server/middleware/accessResources/canAccessMCPServerResource.spec.js
index 77508be2d1..6f7e4ab506 100644
--- a/api/server/middleware/accessResources/canAccessMCPServerResource.spec.js
+++ b/api/server/middleware/accessResources/canAccessMCPServerResource.spec.js
@@ -1,8 +1,9 @@
const mongoose = require('mongoose');
const { ResourceType, PrincipalType, PrincipalModel } = require('librechat-data-provider');
+const { SystemCapabilities } = require('@librechat/data-schemas');
const { MongoMemoryServer } = require('mongodb-memory-server');
const { canAccessMCPServerResource } = require('./canAccessMCPServerResource');
-const { User, Role, AclEntry } = require('~/db/models');
+const { User, Role, AclEntry, SystemGrant } = require('~/db/models');
const { createMCPServer } = require('~/models');
describe('canAccessMCPServerResource middleware', () => {
@@ -511,7 +512,7 @@ describe('canAccessMCPServerResource middleware', () => {
});
});
- test('should allow admin users to bypass permission checks', async () => {
+ test('should allow users with MANAGE_MCP_SERVERS capability to bypass permission checks', async () => {
const { SystemRoles } = require('librechat-data-provider');
// Create an MCP server owned by another user
@@ -531,6 +532,14 @@ describe('canAccessMCPServerResource middleware', () => {
author: otherUser._id,
});
+ // Seed MANAGE_MCP_SERVERS capability for the ADMIN role
+ await SystemGrant.create({
+ principalType: PrincipalType.ROLE,
+ principalId: SystemRoles.ADMIN,
+ capability: SystemCapabilities.MANAGE_MCP_SERVERS,
+ grantedAt: new Date(),
+ });
+
// Set user as admin
req.user = { id: testUser._id, role: SystemRoles.ADMIN };
req.params.serverName = mcpServer.serverName;
diff --git a/api/server/middleware/accessResources/canAccessPromptGroupResource.js b/api/server/middleware/accessResources/canAccessPromptGroupResource.js
index 90aa280772..9da1994a77 100644
--- a/api/server/middleware/accessResources/canAccessPromptGroupResource.js
+++ b/api/server/middleware/accessResources/canAccessPromptGroupResource.js
@@ -1,6 +1,6 @@
const { ResourceType } = require('librechat-data-provider');
const { canAccessResource } = require('./canAccessResource');
-const { getPromptGroup } = require('~/models/Prompt');
+const { getPromptGroup } = require('~/models');
/**
* PromptGroup ID resolver function
diff --git a/api/server/middleware/accessResources/canAccessPromptViaGroup.js b/api/server/middleware/accessResources/canAccessPromptViaGroup.js
index 0bb0a804a9..534db3d6c6 100644
--- a/api/server/middleware/accessResources/canAccessPromptViaGroup.js
+++ b/api/server/middleware/accessResources/canAccessPromptViaGroup.js
@@ -1,6 +1,6 @@
const { ResourceType } = require('librechat-data-provider');
const { canAccessResource } = require('./canAccessResource');
-const { getPrompt } = require('~/models/Prompt');
+const { getPrompt } = require('~/models');
/**
* Prompt to PromptGroup ID resolver function
diff --git a/api/server/middleware/accessResources/canAccessResource.js b/api/server/middleware/accessResources/canAccessResource.js
index c8bd15ffc2..2431971b2f 100644
--- a/api/server/middleware/accessResources/canAccessResource.js
+++ b/api/server/middleware/accessResources/canAccessResource.js
@@ -1,5 +1,5 @@
-const { logger } = require('@librechat/data-schemas');
-const { SystemRoles } = require('librechat-data-provider');
+const { logger, ResourceCapabilityMap } = require('@librechat/data-schemas');
+const { hasCapability } = require('~/server/middleware/roles/capabilities');
const { checkPermission } = require('~/server/services/PermissionService');
/**
@@ -71,8 +71,17 @@ const canAccessResource = (options) => {
message: 'Authentication required',
});
}
- // if system admin let through
- if (req.user.role === SystemRoles.ADMIN) {
+ const cap = ResourceCapabilityMap[resourceType];
+ let hasCap = false;
+ try {
+ hasCap = cap != null && (await hasCapability(req.user, cap));
+ } catch (err) {
+ logger.warn(`[canAccessResource] capability check failed, denying bypass: ${err.message}`);
+ }
+ if (hasCap) {
+ logger.debug(
+ `[canAccessResource] ${cap} bypass for user ${req.user.id} on ${resourceType} ${rawResourceId}`,
+ );
return next();
}
const userId = req.user.id;
diff --git a/api/server/middleware/accessResources/fileAccess.js b/api/server/middleware/accessResources/fileAccess.js
index 25d41e7c02..0f77a61175 100644
--- a/api/server/middleware/accessResources/fileAccess.js
+++ b/api/server/middleware/accessResources/fileAccess.js
@@ -1,8 +1,7 @@
const { logger } = require('@librechat/data-schemas');
const { PermissionBits, hasPermissions, ResourceType } = require('librechat-data-provider');
const { getEffectivePermissions } = require('~/server/services/PermissionService');
-const { getAgents } = require('~/models/Agent');
-const { getFiles } = require('~/models');
+const { getAgents, getFiles } = require('~/models');
/**
* Checks if user has access to a file through agent permissions
diff --git a/api/server/middleware/accessResources/fileAccess.spec.js b/api/server/middleware/accessResources/fileAccess.spec.js
index cc0d57ac48..72896b0629 100644
--- a/api/server/middleware/accessResources/fileAccess.spec.js
+++ b/api/server/middleware/accessResources/fileAccess.spec.js
@@ -3,8 +3,7 @@ const { ResourceType, PrincipalType, PrincipalModel } = require('librechat-data-
const { MongoMemoryServer } = require('mongodb-memory-server');
const { fileAccess } = require('./fileAccess');
const { User, Role, AclEntry } = require('~/db/models');
-const { createAgent } = require('~/models/Agent');
-const { createFile } = require('~/models');
+const { createAgent, createFile } = require('~/models');
describe('fileAccess middleware', () => {
let mongoServer;
diff --git a/api/server/middleware/assistants/validateAuthor.js b/api/server/middleware/assistants/validateAuthor.js
index 03936444e0..3be1642a71 100644
--- a/api/server/middleware/assistants/validateAuthor.js
+++ b/api/server/middleware/assistants/validateAuthor.js
@@ -1,5 +1,6 @@
-const { SystemRoles } = require('librechat-data-provider');
-const { getAssistant } = require('~/models/Assistant');
+const { logger, SystemCapabilities } = require('@librechat/data-schemas');
+const { hasCapability } = require('~/server/middleware');
+const { getAssistant } = require('~/models');
/**
* Checks if the assistant is supported or excluded
@@ -12,10 +13,6 @@ const { getAssistant } = require('~/models/Assistant');
* @returns {Promise}
*/
const validateAuthor = async ({ req, openai, overrideEndpoint, overrideAssistantId }) => {
- if (req.user.role === SystemRoles.ADMIN) {
- return;
- }
-
const endpoint = overrideEndpoint ?? req.body.endpoint ?? req.query.endpoint;
const assistant_id =
overrideAssistantId ?? req.params.id ?? req.body.assistant_id ?? req.query.assistant_id;
@@ -31,6 +28,18 @@ const validateAuthor = async ({ req, openai, overrideEndpoint, overrideAssistant
return;
}
+ let canManageAssistants = false;
+ try {
+ canManageAssistants = await hasCapability(req.user, SystemCapabilities.MANAGE_ASSISTANTS);
+ } catch (err) {
+ logger.warn(`[validateAuthor] capability check failed, denying bypass: ${err.message}`);
+ }
+
+ if (canManageAssistants) {
+ logger.debug(`[validateAuthor] MANAGE_ASSISTANTS bypass for user ${req.user.id}`);
+ return;
+ }
+
const assistantDoc = await getAssistant({ assistant_id, user: req.user.id });
if (assistantDoc) {
return;
diff --git a/api/server/middleware/buildEndpointOption.js b/api/server/middleware/buildEndpointOption.js
index f56d850120..64ed8e7466 100644
--- a/api/server/middleware/buildEndpointOption.js
+++ b/api/server/middleware/buildEndpointOption.js
@@ -5,9 +5,11 @@ const {
EModelEndpoint,
isAgentsEndpoint,
parseCompactConvo,
+ getDefaultParamsEndpoint,
} = require('librechat-data-provider');
const azureAssistants = require('~/server/services/Endpoints/azureAssistants');
const assistants = require('~/server/services/Endpoints/assistants');
+const { getEndpointsConfig } = require('~/server/services/Config');
const agents = require('~/server/services/Endpoints/agents');
const { updateFilesUsage } = require('~/models');
@@ -19,9 +21,24 @@ const buildFunction = {
async function buildEndpointOption(req, res, next) {
const { endpoint, endpointType } = req.body;
+
+ let endpointsConfig;
+ try {
+ endpointsConfig = await getEndpointsConfig(req);
+ } catch (error) {
+ logger.error('Error fetching endpoints config in buildEndpointOption', error);
+ }
+
+ const defaultParamsEndpoint = getDefaultParamsEndpoint(endpointsConfig, endpoint);
+
let parsedBody;
try {
- parsedBody = parseCompactConvo({ endpoint, endpointType, conversation: req.body });
+ parsedBody = parseCompactConvo({
+ endpoint,
+ endpointType,
+ conversation: req.body,
+ defaultParamsEndpoint,
+ });
} catch (error) {
logger.error(`Error parsing compact conversation for endpoint ${endpoint}`, error);
logger.debug({
@@ -55,6 +72,7 @@ async function buildEndpointOption(req, res, next) {
endpoint,
endpointType,
conversation: currentModelSpec.preset,
+ defaultParamsEndpoint,
});
if (currentModelSpec.iconURL != null && currentModelSpec.iconURL !== '') {
parsedBody.iconURL = currentModelSpec.iconURL;
diff --git a/api/server/middleware/buildEndpointOption.spec.js b/api/server/middleware/buildEndpointOption.spec.js
new file mode 100644
index 0000000000..eab5e2666b
--- /dev/null
+++ b/api/server/middleware/buildEndpointOption.spec.js
@@ -0,0 +1,237 @@
+/**
+ * Wrap parseCompactConvo: the REAL function runs, but jest can observe
+ * calls and return values. Must be declared before require('./buildEndpointOption')
+ * so the destructured reference in the middleware captures the wrapper.
+ */
+jest.mock('librechat-data-provider', () => {
+ const actual = jest.requireActual('librechat-data-provider');
+ return {
+ ...actual,
+ parseCompactConvo: jest.fn((...args) => actual.parseCompactConvo(...args)),
+ };
+});
+
+const { EModelEndpoint, parseCompactConvo } = require('librechat-data-provider');
+
+const mockBuildOptions = jest.fn((_endpoint, parsedBody) => ({
+ ...parsedBody,
+ endpoint: _endpoint,
+}));
+
+jest.mock('~/server/services/Endpoints/azureAssistants', () => ({
+ buildOptions: mockBuildOptions,
+}));
+jest.mock('~/server/services/Endpoints/assistants', () => ({
+ buildOptions: mockBuildOptions,
+}));
+jest.mock('~/server/services/Endpoints/agents', () => ({
+ buildOptions: mockBuildOptions,
+}));
+
+jest.mock('~/models', () => ({
+ updateFilesUsage: jest.fn(),
+}));
+
+const mockGetEndpointsConfig = jest.fn();
+jest.mock('~/server/services/Config', () => ({
+ getEndpointsConfig: (...args) => mockGetEndpointsConfig(...args),
+}));
+
+jest.mock('@librechat/api', () => ({
+ handleError: jest.fn(),
+}));
+
+const buildEndpointOption = require('./buildEndpointOption');
+
+const createReq = (body, config = {}) => ({
+ body,
+ config,
+ baseUrl: '/api/chat',
+});
+
+const createRes = () => ({
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+});
+
+describe('buildEndpointOption - defaultParamsEndpoint parsing', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('should pass defaultParamsEndpoint to parseCompactConvo and preserve maxOutputTokens', async () => {
+ mockGetEndpointsConfig.mockResolvedValue({
+ AnthropicClaude: {
+ type: EModelEndpoint.custom,
+ customParams: {
+ defaultParamsEndpoint: EModelEndpoint.anthropic,
+ },
+ },
+ });
+
+ const req = createReq(
+ {
+ endpoint: 'AnthropicClaude',
+ endpointType: EModelEndpoint.custom,
+ model: 'anthropic/claude-opus-4.5',
+ temperature: 0.7,
+ maxOutputTokens: 8192,
+ topP: 0.9,
+ maxContextTokens: 50000,
+ },
+ { modelSpecs: null },
+ );
+
+ await buildEndpointOption(req, createRes(), jest.fn());
+
+ expect(parseCompactConvo).toHaveBeenCalledWith(
+ expect.objectContaining({
+ defaultParamsEndpoint: EModelEndpoint.anthropic,
+ }),
+ );
+
+ const parsedResult = parseCompactConvo.mock.results[0].value;
+ expect(parsedResult.maxOutputTokens).toBe(8192);
+ expect(parsedResult.topP).toBe(0.9);
+ expect(parsedResult.temperature).toBe(0.7);
+ expect(parsedResult.maxContextTokens).toBe(50000);
+ });
+
+ it('should strip maxOutputTokens when no defaultParamsEndpoint is configured', async () => {
+ mockGetEndpointsConfig.mockResolvedValue({
+ MyOpenRouter: {
+ type: EModelEndpoint.custom,
+ },
+ });
+
+ const req = createReq(
+ {
+ endpoint: 'MyOpenRouter',
+ endpointType: EModelEndpoint.custom,
+ model: 'gpt-4o',
+ temperature: 0.7,
+ maxOutputTokens: 8192,
+ max_tokens: 4096,
+ },
+ { modelSpecs: null },
+ );
+
+ await buildEndpointOption(req, createRes(), jest.fn());
+
+ expect(parseCompactConvo).toHaveBeenCalledWith(
+ expect.objectContaining({
+ defaultParamsEndpoint: undefined,
+ }),
+ );
+
+ const parsedResult = parseCompactConvo.mock.results[0].value;
+ expect(parsedResult.maxOutputTokens).toBeUndefined();
+ expect(parsedResult.max_tokens).toBe(4096);
+ expect(parsedResult.temperature).toBe(0.7);
+ });
+
+ it('should strip bedrock region from custom endpoint without defaultParamsEndpoint', async () => {
+ mockGetEndpointsConfig.mockResolvedValue({
+ MyEndpoint: {
+ type: EModelEndpoint.custom,
+ },
+ });
+
+ const req = createReq(
+ {
+ endpoint: 'MyEndpoint',
+ endpointType: EModelEndpoint.custom,
+ model: 'gpt-4o',
+ temperature: 0.7,
+ region: 'us-east-1',
+ },
+ { modelSpecs: null },
+ );
+
+ await buildEndpointOption(req, createRes(), jest.fn());
+
+ const parsedResult = parseCompactConvo.mock.results[0].value;
+ expect(parsedResult.region).toBeUndefined();
+ expect(parsedResult.temperature).toBe(0.7);
+ });
+
+ it('should pass defaultParamsEndpoint when re-parsing enforced model spec', async () => {
+ mockGetEndpointsConfig.mockResolvedValue({
+ AnthropicClaude: {
+ type: EModelEndpoint.custom,
+ customParams: {
+ defaultParamsEndpoint: EModelEndpoint.anthropic,
+ },
+ },
+ });
+
+ const modelSpec = {
+ name: 'claude-opus-4.5',
+ preset: {
+ endpoint: 'AnthropicClaude',
+ endpointType: EModelEndpoint.custom,
+ model: 'anthropic/claude-opus-4.5',
+ temperature: 0.7,
+ maxOutputTokens: 8192,
+ maxContextTokens: 50000,
+ },
+ };
+
+ const req = createReq(
+ {
+ endpoint: 'AnthropicClaude',
+ endpointType: EModelEndpoint.custom,
+ spec: 'claude-opus-4.5',
+ model: 'anthropic/claude-opus-4.5',
+ },
+ {
+ modelSpecs: {
+ enforce: true,
+ list: [modelSpec],
+ },
+ },
+ );
+
+ await buildEndpointOption(req, createRes(), jest.fn());
+
+ const enforcedCall = parseCompactConvo.mock.calls[1];
+ expect(enforcedCall[0]).toEqual(
+ expect.objectContaining({
+ defaultParamsEndpoint: EModelEndpoint.anthropic,
+ }),
+ );
+
+ const enforcedResult = parseCompactConvo.mock.results[1].value;
+ expect(enforcedResult.maxOutputTokens).toBe(8192);
+ expect(enforcedResult.temperature).toBe(0.7);
+ expect(enforcedResult.maxContextTokens).toBe(50000);
+ });
+
+ it('should fall back to OpenAI schema when getEndpointsConfig fails', async () => {
+ mockGetEndpointsConfig.mockRejectedValue(new Error('Config unavailable'));
+
+ const req = createReq(
+ {
+ endpoint: 'AnthropicClaude',
+ endpointType: EModelEndpoint.custom,
+ model: 'anthropic/claude-opus-4.5',
+ temperature: 0.7,
+ maxOutputTokens: 8192,
+ max_tokens: 4096,
+ },
+ { modelSpecs: null },
+ );
+
+ await buildEndpointOption(req, createRes(), jest.fn());
+
+ expect(parseCompactConvo).toHaveBeenCalledWith(
+ expect.objectContaining({
+ defaultParamsEndpoint: undefined,
+ }),
+ );
+
+ const parsedResult = parseCompactConvo.mock.results[0].value;
+ expect(parsedResult.maxOutputTokens).toBeUndefined();
+ expect(parsedResult.max_tokens).toBe(4096);
+ });
+});
diff --git a/api/server/middleware/canDeleteAccount.js b/api/server/middleware/canDeleteAccount.js
index a913495287..3c08745d76 100644
--- a/api/server/middleware/canDeleteAccount.js
+++ b/api/server/middleware/canDeleteAccount.js
@@ -1,6 +1,6 @@
const { isEnabled } = require('@librechat/api');
-const { logger } = require('@librechat/data-schemas');
-const { SystemRoles } = require('librechat-data-provider');
+const { logger, SystemCapabilities } = require('@librechat/data-schemas');
+const { hasCapability } = require('~/server/middleware/roles/capabilities');
/**
* Checks if the user can delete their account
@@ -17,12 +17,29 @@ const { SystemRoles } = require('librechat-data-provider');
const canDeleteAccount = async (req, res, next = () => {}) => {
const { user } = req;
const { ALLOW_ACCOUNT_DELETION = true } = process.env;
- if (user?.role === SystemRoles.ADMIN || isEnabled(ALLOW_ACCOUNT_DELETION)) {
+ if (isEnabled(ALLOW_ACCOUNT_DELETION)) {
return next();
- } else {
- logger.error(`[User] [Delete Account] [User cannot delete account] [User: ${user?.id}]`);
- return res.status(403).send({ message: 'You do not have permission to delete this account' });
}
+ let hasAdminAccess = false;
+ if (user) {
+ try {
+ const id = user.id ?? user._id?.toString();
+ if (id) {
+ hasAdminAccess = await hasCapability(
+ { id, role: user.role ?? '', tenantId: user.tenantId },
+ SystemCapabilities.ACCESS_ADMIN,
+ );
+ }
+ } catch (err) {
+ logger.warn(`[canDeleteAccount] capability check failed, denying: ${err.message}`);
+ }
+ }
+ if (hasAdminAccess) {
+ logger.debug(`[canDeleteAccount] ACCESS_ADMIN bypass for user ${user.id}`);
+ return next();
+ }
+ logger.error(`[User] [Delete Account] [User cannot delete account] [User: ${user?.id}]`);
+ return res.status(403).send({ message: 'You do not have permission to delete this account' });
};
module.exports = canDeleteAccount;
diff --git a/api/server/middleware/canDeleteAccount.spec.js b/api/server/middleware/canDeleteAccount.spec.js
new file mode 100644
index 0000000000..abb888c4a4
--- /dev/null
+++ b/api/server/middleware/canDeleteAccount.spec.js
@@ -0,0 +1,180 @@
+const mongoose = require('mongoose');
+const { MongoMemoryServer } = require('mongodb-memory-server');
+const { SystemRoles, PrincipalType } = require('librechat-data-provider');
+const { SystemCapabilities } = require('@librechat/data-schemas');
+
+jest.mock('@librechat/data-schemas', () => ({
+ ...jest.requireActual('@librechat/data-schemas'),
+ logger: { error: jest.fn(), warn: jest.fn(), debug: jest.fn(), info: jest.fn() },
+}));
+
+jest.mock('~/cache', () => ({
+ getLogStores: jest.fn(() => ({
+ get: jest.fn(),
+ set: jest.fn(),
+ })),
+}));
+
+const { User, SystemGrant } = require('~/db/models');
+const canDeleteAccount = require('./canDeleteAccount');
+
+let mongoServer;
+
+beforeAll(async () => {
+ mongoServer = await MongoMemoryServer.create();
+ await mongoose.connect(mongoServer.getUri());
+});
+
+afterAll(async () => {
+ await mongoose.disconnect();
+ await mongoServer.stop();
+});
+
+beforeEach(async () => {
+ await mongoose.connection.dropDatabase();
+ delete process.env.ALLOW_ACCOUNT_DELETION;
+});
+
+const makeRes = () => {
+ const send = jest.fn();
+ const status = jest.fn().mockReturnValue({ send });
+ return { status, send };
+};
+
+describe('canDeleteAccount', () => {
+ describe('ALLOW_ACCOUNT_DELETION=true (default)', () => {
+ it('calls next without hitting the DB', async () => {
+ process.env.ALLOW_ACCOUNT_DELETION = 'true';
+ const next = jest.fn();
+ const req = { user: { id: 'user-1', role: SystemRoles.USER } };
+
+ await canDeleteAccount(req, makeRes(), next);
+
+ expect(next).toHaveBeenCalled();
+ });
+
+ it('skips capability check entirely when deletion is allowed', async () => {
+ process.env.ALLOW_ACCOUNT_DELETION = 'true';
+ const next = jest.fn();
+ const req = { user: { id: 'user-1', role: SystemRoles.USER } };
+
+ await canDeleteAccount(req, makeRes(), next);
+
+ expect(next).toHaveBeenCalled();
+ const grantCount = await SystemGrant.countDocuments();
+ expect(grantCount).toBe(0);
+ });
+ });
+
+ describe('ALLOW_ACCOUNT_DELETION=false', () => {
+ beforeEach(() => {
+ process.env.ALLOW_ACCOUNT_DELETION = 'false';
+ });
+
+ it('allows admin with ACCESS_ADMIN grant (real DB check)', async () => {
+ const admin = await User.create({
+ name: 'Admin',
+ email: 'admin@test.com',
+ password: 'password123',
+ provider: 'local',
+ role: SystemRoles.ADMIN,
+ });
+
+ await SystemGrant.create({
+ principalType: PrincipalType.ROLE,
+ principalId: SystemRoles.ADMIN,
+ capability: SystemCapabilities.ACCESS_ADMIN,
+ grantedAt: new Date(),
+ });
+
+ const next = jest.fn();
+ const req = { user: { id: admin._id.toString(), role: SystemRoles.ADMIN } };
+
+ await canDeleteAccount(req, makeRes(), next);
+
+ expect(next).toHaveBeenCalled();
+ });
+
+ it('blocks regular user without ACCESS_ADMIN grant', async () => {
+ const user = await User.create({
+ name: 'Regular',
+ email: 'user@test.com',
+ password: 'password123',
+ provider: 'local',
+ role: SystemRoles.USER,
+ });
+
+ const next = jest.fn();
+ const res = makeRes();
+ const req = { user: { id: user._id.toString(), role: SystemRoles.USER } };
+
+ await canDeleteAccount(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(403);
+ });
+
+ it('blocks admin role WITHOUT the ACCESS_ADMIN grant', async () => {
+ const admin = await User.create({
+ name: 'Admin No Grant',
+ email: 'admin2@test.com',
+ password: 'password123',
+ provider: 'local',
+ role: SystemRoles.ADMIN,
+ });
+
+ const next = jest.fn();
+ const res = makeRes();
+ const req = { user: { id: admin._id.toString(), role: SystemRoles.ADMIN } };
+
+ await canDeleteAccount(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(403);
+ });
+
+ it('allows user-level grant (not just role-level)', async () => {
+ const user = await User.create({
+ name: 'Privileged User',
+ email: 'priv@test.com',
+ password: 'password123',
+ provider: 'local',
+ role: SystemRoles.USER,
+ });
+
+ await SystemGrant.create({
+ principalType: PrincipalType.USER,
+ principalId: user._id,
+ capability: SystemCapabilities.ACCESS_ADMIN,
+ grantedAt: new Date(),
+ });
+
+ const next = jest.fn();
+ const req = { user: { id: user._id.toString(), role: SystemRoles.USER } };
+
+ await canDeleteAccount(req, makeRes(), next);
+
+ expect(next).toHaveBeenCalled();
+ });
+
+ it('blocks when user is undefined — does not throw', async () => {
+ const next = jest.fn();
+ const res = makeRes();
+
+ await canDeleteAccount({ user: undefined }, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(403);
+ });
+
+ it('blocks when user is null — does not throw', async () => {
+ const next = jest.fn();
+ const res = makeRes();
+
+ await canDeleteAccount({ user: null }, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(403);
+ });
+ });
+});
diff --git a/api/server/middleware/checkInviteUser.js b/api/server/middleware/checkInviteUser.js
index 42e1faba5b..22f2824ffc 100644
--- a/api/server/middleware/checkInviteUser.js
+++ b/api/server/middleware/checkInviteUser.js
@@ -1,5 +1,8 @@
-const { getInvite } = require('~/models/inviteUser');
-const { deleteTokens } = require('~/models');
+const { getInvite: getInviteFn } = require('@librechat/api');
+const { createToken, findToken, deleteTokens } = require('~/models');
+
+const getInvite = (encodedToken, email) =>
+ getInviteFn(encodedToken, email, { createToken, findToken });
async function checkInviteUser(req, res, next) {
const token = req.body.token;
diff --git a/api/server/middleware/checkPeoplePickerAccess.js b/api/server/middleware/checkPeoplePickerAccess.js
index 0e604272db..50f137285e 100644
--- a/api/server/middleware/checkPeoplePickerAccess.js
+++ b/api/server/middleware/checkPeoplePickerAccess.js
@@ -1,14 +1,21 @@
const { logger } = require('@librechat/data-schemas');
const { PrincipalType, PermissionTypes, Permissions } = require('librechat-data-provider');
-const { getRoleByName } = require('~/models/Role');
+const { getRoleByName } = require('~/models');
+
+const VALID_PRINCIPAL_TYPES = new Set([
+ PrincipalType.USER,
+ PrincipalType.GROUP,
+ PrincipalType.ROLE,
+]);
/**
- * Middleware to check if user has permission to access people picker functionality
- * Checks specific permission based on the 'type' query parameter:
- * - type=user: requires VIEW_USERS permission
- * - type=group: requires VIEW_GROUPS permission
- * - type=role: requires VIEW_ROLES permission
- * - no type (mixed search): requires either VIEW_USERS OR VIEW_GROUPS OR VIEW_ROLES
+ * Middleware to check if user has permission to access people picker functionality.
+ * Validates requested principal types via `type` (singular) and `types` (comma-separated or array)
+ * query parameters against the caller's role permissions:
+ * - user: requires VIEW_USERS permission
+ * - group: requires VIEW_GROUPS permission
+ * - role: requires VIEW_ROLES permission
+ * - no type filter (mixed search): requires at least one of the above
*/
const checkPeoplePickerAccess = async (req, res, next) => {
try {
@@ -28,7 +35,7 @@ const checkPeoplePickerAccess = async (req, res, next) => {
});
}
- const { type } = req.query;
+ const { type, types } = req.query;
const peoplePickerPerms = role.permissions[PermissionTypes.PEOPLE_PICKER] || {};
const canViewUsers = peoplePickerPerms[Permissions.VIEW_USERS] === true;
const canViewGroups = peoplePickerPerms[Permissions.VIEW_GROUPS] === true;
@@ -49,15 +56,32 @@ const checkPeoplePickerAccess = async (req, res, next) => {
},
};
- const check = permissionChecks[type];
- if (check && !check.hasPermission) {
- return res.status(403).json({
- error: 'Forbidden',
- message: check.message,
- });
+ const requestedTypes = new Set();
+
+ if (type && VALID_PRINCIPAL_TYPES.has(type)) {
+ requestedTypes.add(type);
}
- if (!type && !canViewUsers && !canViewGroups && !canViewRoles) {
+ if (types) {
+ const typesArray = Array.isArray(types) ? types : types.split(',');
+ for (const t of typesArray) {
+ if (VALID_PRINCIPAL_TYPES.has(t)) {
+ requestedTypes.add(t);
+ }
+ }
+ }
+
+ for (const requested of requestedTypes) {
+ const check = permissionChecks[requested];
+ if (!check.hasPermission) {
+ return res.status(403).json({
+ error: 'Forbidden',
+ message: check.message,
+ });
+ }
+ }
+
+ if (requestedTypes.size === 0 && !canViewUsers && !canViewGroups && !canViewRoles) {
return res.status(403).json({
error: 'Forbidden',
message: 'Insufficient permissions to search for users, groups, or roles',
@@ -67,7 +91,7 @@ const checkPeoplePickerAccess = async (req, res, next) => {
next();
} catch (error) {
logger.error(
- `[checkPeoplePickerAccess][${req.user?.id}] checkPeoplePickerAccess error for req.query.type = ${req.query.type}`,
+ `[checkPeoplePickerAccess][${req.user?.id}] error for type=${req.query.type}, types=${req.query.types}`,
error,
);
return res.status(500).json({
diff --git a/api/server/middleware/checkPeoplePickerAccess.spec.js b/api/server/middleware/checkPeoplePickerAccess.spec.js
index 52bf0e6724..c394bbae65 100644
--- a/api/server/middleware/checkPeoplePickerAccess.spec.js
+++ b/api/server/middleware/checkPeoplePickerAccess.spec.js
@@ -1,9 +1,9 @@
const { logger } = require('@librechat/data-schemas');
const { PrincipalType, PermissionTypes, Permissions } = require('librechat-data-provider');
const { checkPeoplePickerAccess } = require('./checkPeoplePickerAccess');
-const { getRoleByName } = require('~/models/Role');
+const { getRoleByName } = require('~/models');
-jest.mock('~/models/Role');
+jest.mock('~/models');
jest.mock('@librechat/data-schemas', () => ({
...jest.requireActual('@librechat/data-schemas'),
logger: {
@@ -173,6 +173,171 @@ describe('checkPeoplePickerAccess', () => {
expect(next).not.toHaveBeenCalled();
});
+ it('should deny access when using types param to bypass type-specific check', async () => {
+ req.query.types = PrincipalType.GROUP;
+ getRoleByName.mockResolvedValue({
+ permissions: {
+ [PermissionTypes.PEOPLE_PICKER]: {
+ [Permissions.VIEW_USERS]: true,
+ [Permissions.VIEW_GROUPS]: false,
+ [Permissions.VIEW_ROLES]: false,
+ },
+ },
+ });
+
+ await checkPeoplePickerAccess(req, res, next);
+
+ expect(res.status).toHaveBeenCalledWith(403);
+ expect(res.json).toHaveBeenCalledWith({
+ error: 'Forbidden',
+ message: 'Insufficient permissions to search for groups',
+ });
+ expect(next).not.toHaveBeenCalled();
+ });
+
+ it('should deny access when types contains any unpermitted type', async () => {
+ req.query.types = `${PrincipalType.USER},${PrincipalType.ROLE}`;
+ getRoleByName.mockResolvedValue({
+ permissions: {
+ [PermissionTypes.PEOPLE_PICKER]: {
+ [Permissions.VIEW_USERS]: true,
+ [Permissions.VIEW_GROUPS]: false,
+ [Permissions.VIEW_ROLES]: false,
+ },
+ },
+ });
+
+ await checkPeoplePickerAccess(req, res, next);
+
+ expect(res.status).toHaveBeenCalledWith(403);
+ expect(res.json).toHaveBeenCalledWith({
+ error: 'Forbidden',
+ message: 'Insufficient permissions to search for roles',
+ });
+ expect(next).not.toHaveBeenCalled();
+ });
+
+ it('should allow access when all requested types are permitted', async () => {
+ req.query.types = `${PrincipalType.USER},${PrincipalType.GROUP}`;
+ getRoleByName.mockResolvedValue({
+ permissions: {
+ [PermissionTypes.PEOPLE_PICKER]: {
+ [Permissions.VIEW_USERS]: true,
+ [Permissions.VIEW_GROUPS]: true,
+ [Permissions.VIEW_ROLES]: false,
+ },
+ },
+ });
+
+ await checkPeoplePickerAccess(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ expect(res.status).not.toHaveBeenCalled();
+ });
+
+ it('should validate types when provided as array (Express qs parsing)', async () => {
+ req.query.types = [PrincipalType.GROUP, PrincipalType.ROLE];
+ getRoleByName.mockResolvedValue({
+ permissions: {
+ [PermissionTypes.PEOPLE_PICKER]: {
+ [Permissions.VIEW_USERS]: true,
+ [Permissions.VIEW_GROUPS]: false,
+ [Permissions.VIEW_ROLES]: true,
+ },
+ },
+ });
+
+ await checkPeoplePickerAccess(req, res, next);
+
+ expect(res.status).toHaveBeenCalledWith(403);
+ expect(res.json).toHaveBeenCalledWith({
+ error: 'Forbidden',
+ message: 'Insufficient permissions to search for groups',
+ });
+ expect(next).not.toHaveBeenCalled();
+ });
+
+ it('should enforce permissions for combined type and types params', async () => {
+ req.query.type = PrincipalType.USER;
+ req.query.types = PrincipalType.GROUP;
+ getRoleByName.mockResolvedValue({
+ permissions: {
+ [PermissionTypes.PEOPLE_PICKER]: {
+ [Permissions.VIEW_USERS]: true,
+ [Permissions.VIEW_GROUPS]: false,
+ [Permissions.VIEW_ROLES]: false,
+ },
+ },
+ });
+
+ await checkPeoplePickerAccess(req, res, next);
+
+ expect(res.status).toHaveBeenCalledWith(403);
+ expect(res.json).toHaveBeenCalledWith({
+ error: 'Forbidden',
+ message: 'Insufficient permissions to search for groups',
+ });
+ expect(next).not.toHaveBeenCalled();
+ });
+
+ it('should treat all-invalid types values as mixed search', async () => {
+ req.query.types = 'foobar';
+ getRoleByName.mockResolvedValue({
+ permissions: {
+ [PermissionTypes.PEOPLE_PICKER]: {
+ [Permissions.VIEW_USERS]: true,
+ [Permissions.VIEW_GROUPS]: false,
+ [Permissions.VIEW_ROLES]: false,
+ },
+ },
+ });
+
+ await checkPeoplePickerAccess(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ expect(res.status).not.toHaveBeenCalled();
+ });
+
+ it('should deny when types is empty string and user has no permissions', async () => {
+ req.query.types = '';
+ getRoleByName.mockResolvedValue({
+ permissions: {
+ [PermissionTypes.PEOPLE_PICKER]: {
+ [Permissions.VIEW_USERS]: false,
+ [Permissions.VIEW_GROUPS]: false,
+ [Permissions.VIEW_ROLES]: false,
+ },
+ },
+ });
+
+ await checkPeoplePickerAccess(req, res, next);
+
+ expect(res.status).toHaveBeenCalledWith(403);
+ expect(res.json).toHaveBeenCalledWith({
+ error: 'Forbidden',
+ message: 'Insufficient permissions to search for users, groups, or roles',
+ });
+ expect(next).not.toHaveBeenCalled();
+ });
+
+ it('should treat types=public as mixed search since PUBLIC is not a searchable principal type', async () => {
+ req.query.types = PrincipalType.PUBLIC;
+ getRoleByName.mockResolvedValue({
+ permissions: {
+ [PermissionTypes.PEOPLE_PICKER]: {
+ [Permissions.VIEW_USERS]: true,
+ [Permissions.VIEW_GROUPS]: false,
+ [Permissions.VIEW_ROLES]: false,
+ },
+ },
+ });
+
+ await checkPeoplePickerAccess(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ expect(res.status).not.toHaveBeenCalled();
+ });
+
it('should allow mixed search when user has at least one permission', async () => {
// No type specified = mixed search
req.query.type = undefined;
@@ -222,7 +387,7 @@ describe('checkPeoplePickerAccess', () => {
await checkPeoplePickerAccess(req, res, next);
expect(logger.error).toHaveBeenCalledWith(
- '[checkPeoplePickerAccess][user123] checkPeoplePickerAccess error for req.query.type = undefined',
+ '[checkPeoplePickerAccess][user123] error for type=undefined, types=undefined',
error,
);
expect(res.status).toHaveBeenCalledWith(500);
diff --git a/api/server/middleware/checkSharePublicAccess.js b/api/server/middleware/checkSharePublicAccess.js
index 0e95b9f6f8..c7b65a077e 100644
--- a/api/server/middleware/checkSharePublicAccess.js
+++ b/api/server/middleware/checkSharePublicAccess.js
@@ -1,6 +1,6 @@
const { logger } = require('@librechat/data-schemas');
const { ResourceType, PermissionTypes, Permissions } = require('librechat-data-provider');
-const { getRoleByName } = require('~/models/Role');
+const { getRoleByName } = require('~/models');
/**
* Maps resource types to their corresponding permission types
diff --git a/api/server/middleware/checkSharePublicAccess.spec.js b/api/server/middleware/checkSharePublicAccess.spec.js
index c73e71693b..605de2049e 100644
--- a/api/server/middleware/checkSharePublicAccess.spec.js
+++ b/api/server/middleware/checkSharePublicAccess.spec.js
@@ -1,8 +1,8 @@
const { ResourceType, PermissionTypes, Permissions } = require('librechat-data-provider');
const { checkSharePublicAccess } = require('./checkSharePublicAccess');
-const { getRoleByName } = require('~/models/Role');
+const { getRoleByName } = require('~/models');
-jest.mock('~/models/Role');
+jest.mock('~/models');
describe('checkSharePublicAccess middleware', () => {
let mockReq;
diff --git a/api/server/middleware/denyRequest.js b/api/server/middleware/denyRequest.js
index 20360519cf..86054d0a23 100644
--- a/api/server/middleware/denyRequest.js
+++ b/api/server/middleware/denyRequest.js
@@ -43,7 +43,11 @@ const denyRequest = async (req, res, errorMessage) => {
if (shouldSaveMessage) {
await saveMessage(
- req,
+ {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ },
{ ...userMessage, user: req.user.id },
{ context: `api/server/middleware/denyRequest.js - ${responseText}` },
);
diff --git a/api/server/middleware/error.js b/api/server/middleware/error.js
index fef7e60ef7..5fa3562c30 100644
--- a/api/server/middleware/error.js
+++ b/api/server/middleware/error.js
@@ -2,8 +2,7 @@ const crypto = require('crypto');
const { logger } = require('@librechat/data-schemas');
const { parseConvo } = require('librechat-data-provider');
const { sendEvent, handleError, sanitizeMessageForTransmit } = require('@librechat/api');
-const { saveMessage, getMessages } = require('~/models/Message');
-const { getConvo } = require('~/models/Conversation');
+const { saveMessage, getMessages, getConvo } = require('~/models');
/**
* Processes an error with provided options, saves the error message and sends a corresponding SSE response
@@ -49,7 +48,11 @@ const sendError = async (req, res, options, callback) => {
if (shouldSaveMessage) {
await saveMessage(
- req,
+ {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ },
{ ...errorMessage, user },
{
context: 'api/server/utils/streamResponse.js - sendError',
diff --git a/api/server/middleware/limiters/forkLimiters.js b/api/server/middleware/limiters/forkLimiters.js
index e0aa65700c..f1e9b15f11 100644
--- a/api/server/middleware/limiters/forkLimiters.js
+++ b/api/server/middleware/limiters/forkLimiters.js
@@ -48,7 +48,7 @@ const createForkHandler = (ip = true) => {
};
await logViolation(req, res, type, errorMessage, forkViolationScore);
- res.status(429).json({ message: 'Too many conversation fork requests. Try again later' });
+ res.status(429).json({ message: 'Too many requests. Try again later' });
};
};
diff --git a/api/server/middleware/roles/access.spec.js b/api/server/middleware/roles/access.spec.js
index 9de840819d..16fb6df138 100644
--- a/api/server/middleware/roles/access.spec.js
+++ b/api/server/middleware/roles/access.spec.js
@@ -2,7 +2,7 @@ const mongoose = require('mongoose');
const { MongoMemoryServer } = require('mongodb-memory-server');
const { checkAccess, generateCheckAccess } = require('@librechat/api');
const { PermissionTypes, Permissions } = require('librechat-data-provider');
-const { getRoleByName } = require('~/models/Role');
+const { getRoleByName } = require('~/models');
const { Role } = require('~/db/models');
// Mock the logger from @librechat/data-schemas
diff --git a/api/server/middleware/roles/capabilities.js b/api/server/middleware/roles/capabilities.js
new file mode 100644
index 0000000000..6f2aa43e96
--- /dev/null
+++ b/api/server/middleware/roles/capabilities.js
@@ -0,0 +1,14 @@
+const { generateCapabilityCheck, capabilityContextMiddleware } = require('@librechat/api');
+const { getUserPrincipals, hasCapabilityForPrincipals } = require('~/models');
+
+const { hasCapability, requireCapability, hasConfigCapability } = generateCapabilityCheck({
+ getUserPrincipals,
+ hasCapabilityForPrincipals,
+});
+
+module.exports = {
+ hasCapability,
+ requireCapability,
+ hasConfigCapability,
+ capabilityContextMiddleware,
+};
diff --git a/api/server/middleware/roles/index.js b/api/server/middleware/roles/index.js
index f01b884e5a..e6c315d007 100644
--- a/api/server/middleware/roles/index.js
+++ b/api/server/middleware/roles/index.js
@@ -1,5 +1,15 @@
+const {
+ hasCapability,
+ requireCapability,
+ hasConfigCapability,
+ capabilityContextMiddleware,
+} = require('./capabilities');
const checkAdmin = require('./admin');
module.exports = {
checkAdmin,
+ hasCapability,
+ requireCapability,
+ hasConfigCapability,
+ capabilityContextMiddleware,
};
diff --git a/api/server/middleware/validate/convoAccess.js b/api/server/middleware/validate/convoAccess.js
index 127bfdc530..ef1eea8f37 100644
--- a/api/server/middleware/validate/convoAccess.js
+++ b/api/server/middleware/validate/convoAccess.js
@@ -1,8 +1,8 @@
const { isEnabled } = require('@librechat/api');
const { Constants, ViolationTypes, Time } = require('librechat-data-provider');
-const { searchConversation } = require('~/models/Conversation');
const denyRequest = require('~/server/middleware/denyRequest');
const { logViolation, getLogStores } = require('~/cache');
+const { searchConversation } = require('~/models');
const { USE_REDIS, CONVO_ACCESS_VIOLATION_SCORE: score = 0 } = process.env ?? {};
diff --git a/api/server/routes/__test-utils__/convos-route-mocks.js b/api/server/routes/__test-utils__/convos-route-mocks.js
new file mode 100644
index 0000000000..0929e0759d
--- /dev/null
+++ b/api/server/routes/__test-utils__/convos-route-mocks.js
@@ -0,0 +1,98 @@
+module.exports = {
+ agents: () => ({ sleep: jest.fn() }),
+
+ api: (overrides = {}) => ({
+ isEnabled: jest.fn(),
+ resolveImportMaxFileSize: jest.fn(() => 262144000),
+ createAxiosInstance: jest.fn(() => ({
+ get: jest.fn(),
+ post: jest.fn(),
+ put: jest.fn(),
+ delete: jest.fn(),
+ })),
+ logAxiosError: jest.fn(),
+ ...overrides,
+ }),
+
+ dataSchemas: () => ({
+ logger: {
+ debug: jest.fn(),
+ info: jest.fn(),
+ warn: jest.fn(),
+ error: jest.fn(),
+ },
+ createModels: jest.fn(() => ({
+ User: {},
+ Conversation: {},
+ Message: {},
+ SharedLink: {},
+ })),
+ }),
+
+ dataProvider: (overrides = {}) => ({
+ CacheKeys: { GEN_TITLE: 'GEN_TITLE' },
+ EModelEndpoint: {
+ azureAssistants: 'azureAssistants',
+ assistants: 'assistants',
+ },
+ ...overrides,
+ }),
+
+ conversationModel: () => ({
+ getConvosByCursor: jest.fn(),
+ getConvo: jest.fn(),
+ deleteConvos: jest.fn(),
+ saveConvo: jest.fn(),
+ }),
+
+ toolCallModel: () => ({ deleteToolCalls: jest.fn() }),
+
+ sharedModels: () => ({
+ getConvosByCursor: jest.fn(),
+ getConvo: jest.fn(),
+ deleteConvos: jest.fn(),
+ saveConvo: jest.fn(),
+ deleteAllSharedLinks: jest.fn(),
+ deleteConvoSharedLink: jest.fn(),
+ deleteToolCalls: jest.fn(),
+ }),
+
+ requireJwtAuth: () => (req, res, next) => next(),
+
+ middlewarePassthrough: () => ({
+ createImportLimiters: jest.fn(() => ({
+ importIpLimiter: (req, res, next) => next(),
+ importUserLimiter: (req, res, next) => next(),
+ })),
+ createForkLimiters: jest.fn(() => ({
+ forkIpLimiter: (req, res, next) => next(),
+ forkUserLimiter: (req, res, next) => next(),
+ })),
+ configMiddleware: (req, res, next) => next(),
+ validateConvoAccess: (req, res, next) => next(),
+ }),
+
+ forkUtils: () => ({
+ forkConversation: jest.fn(),
+ duplicateConversation: jest.fn(),
+ }),
+
+ importUtils: () => ({ importConversations: jest.fn() }),
+
+ logStores: () => jest.fn(),
+
+ multerSetup: () => ({
+ storage: {},
+ importFileFilter: jest.fn(),
+ }),
+
+ multerLib: () =>
+ jest.fn(() => ({
+ single: jest.fn(() => (req, res, next) => {
+ req.file = { path: '/tmp/test-file.json' };
+ next();
+ }),
+ })),
+
+ assistantEndpoint: () => ({ initializeClient: jest.fn() }),
+};
diff --git a/api/server/routes/__tests__/convos-duplicate-ratelimit.spec.js b/api/server/routes/__tests__/convos-duplicate-ratelimit.spec.js
new file mode 100644
index 0000000000..a75c11ccba
--- /dev/null
+++ b/api/server/routes/__tests__/convos-duplicate-ratelimit.spec.js
@@ -0,0 +1,137 @@
+const express = require('express');
+const request = require('supertest');
+
+const MOCKS = '../__test-utils__/convos-route-mocks';
+
+jest.mock('@librechat/agents', () => require(MOCKS).agents());
+jest.mock('@librechat/api', () => require(MOCKS).api({ limiterCache: jest.fn(() => undefined) }));
+jest.mock('@librechat/data-schemas', () => require(MOCKS).dataSchemas());
+jest.mock('librechat-data-provider', () =>
+ require(MOCKS).dataProvider({ ViolationTypes: { FILE_UPLOAD_LIMIT: 'file_upload_limit' } }),
+);
+
+jest.mock('~/cache/logViolation', () => jest.fn().mockResolvedValue(undefined));
+jest.mock('~/cache/getLogStores', () => require(MOCKS).logStores());
+jest.mock('~/models', () => ({
+ ...require(MOCKS).sharedModels(),
+ ...require(MOCKS).conversationModel(),
+ ...require(MOCKS).toolCallModel(),
+}));
+jest.mock('~/server/middleware/requireJwtAuth', () => require(MOCKS).requireJwtAuth());
+
+jest.mock('~/server/middleware', () => {
+ const { createForkLimiters } = jest.requireActual('~/server/middleware/limiters/forkLimiters');
+ return {
+ createImportLimiters: jest.fn(() => ({
+ importIpLimiter: (req, res, next) => next(),
+ importUserLimiter: (req, res, next) => next(),
+ })),
+ createForkLimiters,
+ configMiddleware: (req, res, next) => next(),
+ validateConvoAccess: (req, res, next) => next(),
+ };
+});
+
+jest.mock('~/server/utils/import/fork', () => require(MOCKS).forkUtils());
+jest.mock('~/server/utils/import', () => require(MOCKS).importUtils());
+jest.mock('~/server/routes/files/multer', () => require(MOCKS).multerSetup());
+jest.mock('multer', () => require(MOCKS).multerLib());
+jest.mock('~/server/services/Endpoints/azureAssistants', () => require(MOCKS).assistantEndpoint());
+jest.mock('~/server/services/Endpoints/assistants', () => require(MOCKS).assistantEndpoint());
+
+describe('POST /api/convos/duplicate - Rate Limiting', () => {
+ let app;
+ let duplicateConversation;
+ const savedEnv = {};
+
+ beforeAll(() => {
+ savedEnv.FORK_USER_MAX = process.env.FORK_USER_MAX;
+ savedEnv.FORK_USER_WINDOW = process.env.FORK_USER_WINDOW;
+ savedEnv.FORK_IP_MAX = process.env.FORK_IP_MAX;
+ savedEnv.FORK_IP_WINDOW = process.env.FORK_IP_WINDOW;
+ });
+
+ afterAll(() => {
+ for (const key of Object.keys(savedEnv)) {
+ if (savedEnv[key] === undefined) {
+ delete process.env[key];
+ } else {
+ process.env[key] = savedEnv[key];
+ }
+ }
+ });
+
+ const setupApp = () => {
+ jest.clearAllMocks();
+ jest.isolateModules(() => {
+ const convosRouter = require('../convos');
+ ({ duplicateConversation } = require('~/server/utils/import/fork'));
+
+ app = express();
+ app.use(express.json());
+ app.use((req, res, next) => {
+ req.user = { id: 'rate-limit-test-user' };
+ next();
+ });
+ app.use('/api/convos', convosRouter);
+ });
+
+ duplicateConversation.mockResolvedValue({
+ conversation: { conversationId: 'duplicated-conv' },
+ });
+ };
+
+ describe('user limit', () => {
+ beforeEach(() => {
+ process.env.FORK_USER_MAX = '2';
+ process.env.FORK_USER_WINDOW = '1';
+ process.env.FORK_IP_MAX = '100';
+ process.env.FORK_IP_WINDOW = '1';
+ setupApp();
+ });
+
+ it('should return 429 after exceeding the user rate limit', async () => {
+ const userMax = parseInt(process.env.FORK_USER_MAX, 10);
+
+ for (let i = 0; i < userMax; i++) {
+ const res = await request(app)
+ .post('/api/convos/duplicate')
+ .send({ conversationId: 'conv-123' });
+ expect(res.status).toBe(201);
+ }
+
+ const res = await request(app)
+ .post('/api/convos/duplicate')
+ .send({ conversationId: 'conv-123' });
+ expect(res.status).toBe(429);
+ expect(res.body.message).toMatch(/too many/i);
+ });
+ });
+
+ describe('IP limit', () => {
+ beforeEach(() => {
+ process.env.FORK_USER_MAX = '100';
+ process.env.FORK_USER_WINDOW = '1';
+ process.env.FORK_IP_MAX = '2';
+ process.env.FORK_IP_WINDOW = '1';
+ setupApp();
+ });
+
+ it('should return 429 after exceeding the IP rate limit', async () => {
+ const ipMax = parseInt(process.env.FORK_IP_MAX, 10);
+
+ for (let i = 0; i < ipMax; i++) {
+ const res = await request(app)
+ .post('/api/convos/duplicate')
+ .send({ conversationId: 'conv-123' });
+ expect(res.status).toBe(201);
+ }
+
+ const res = await request(app)
+ .post('/api/convos/duplicate')
+ .send({ conversationId: 'conv-123' });
+ expect(res.status).toBe(429);
+ expect(res.body.message).toMatch(/too many/i);
+ });
+ });
+});
diff --git a/api/server/routes/__tests__/convos-import.spec.js b/api/server/routes/__tests__/convos-import.spec.js
new file mode 100644
index 0000000000..c4ea139931
--- /dev/null
+++ b/api/server/routes/__tests__/convos-import.spec.js
@@ -0,0 +1,98 @@
+const express = require('express');
+const request = require('supertest');
+const multer = require('multer');
+
+const importFileFilter = (req, file, cb) => {
+ if (file.mimetype === 'application/json') {
+ cb(null, true);
+ } else {
+ cb(new Error('Only JSON files are allowed'), false);
+ }
+};
+
+/** Proxy app that mirrors the production multer + error-handling pattern */
+function createImportApp(fileSize) {
+ const app = express();
+ const upload = multer({
+ storage: multer.memoryStorage(),
+ fileFilter: importFileFilter,
+ limits: { fileSize },
+ });
+ const uploadSingle = upload.single('file');
+
+ function handleUpload(req, res, next) {
+ uploadSingle(req, res, (err) => {
+ if (err && err.code === 'LIMIT_FILE_SIZE') {
+ return res.status(413).json({ message: 'File exceeds the maximum allowed size' });
+ }
+ if (err) {
+ return next(err);
+ }
+ next();
+ });
+ }
+
+ app.post('/import', handleUpload, (req, res) => {
+ res.status(201).json({ message: 'success', size: req.file.size });
+ });
+
+ app.use((err, _req, res, _next) => {
+ res.status(400).json({ error: err.message });
+ });
+
+ return app;
+}
+
+describe('Conversation Import - Multer File Size Limits', () => {
+ describe('multer rejects files exceeding the configured limit', () => {
+ it('returns 413 for files larger than the limit', async () => {
+ const limit = 1024;
+ const app = createImportApp(limit);
+ const oversized = Buffer.alloc(limit + 512, 'x');
+
+ const res = await request(app)
+ .post('/import')
+ .attach('file', oversized, { filename: 'import.json', contentType: 'application/json' });
+
+ expect(res.status).toBe(413);
+ expect(res.body.message).toBe('File exceeds the maximum allowed size');
+ });
+
+ it('accepts files within the limit', async () => {
+ const limit = 4096;
+ const app = createImportApp(limit);
+ const valid = Buffer.from(JSON.stringify({ title: 'test' }));
+
+ const res = await request(app)
+ .post('/import')
+ .attach('file', valid, { filename: 'import.json', contentType: 'application/json' });
+
+ expect(res.status).toBe(201);
+ expect(res.body.message).toBe('success');
+ });
+
+ it('rejects at the exact boundary (limit + 1 byte)', async () => {
+ const limit = 512;
+ const app = createImportApp(limit);
+ const boundary = Buffer.alloc(limit + 1, 'a');
+
+ const res = await request(app)
+ .post('/import')
+ .attach('file', boundary, { filename: 'import.json', contentType: 'application/json' });
+
+ expect(res.status).toBe(413);
+ });
+
+ it('accepts a file just under the limit', async () => {
+ const limit = 512;
+ const app = createImportApp(limit);
+ const underLimit = Buffer.alloc(limit - 1, 'b');
+
+ const res = await request(app)
+ .post('/import')
+ .attach('file', underLimit, { filename: 'import.json', contentType: 'application/json' });
+
+ expect(res.status).toBe(201);
+ });
+ });
+});
diff --git a/api/server/routes/__tests__/convos.spec.js b/api/server/routes/__tests__/convos.spec.js
index 931ef006d0..23978f28e9 100644
--- a/api/server/routes/__tests__/convos.spec.js
+++ b/api/server/routes/__tests__/convos.spec.js
@@ -1,116 +1,33 @@
const express = require('express');
const request = require('supertest');
-jest.mock('@librechat/agents', () => ({
- sleep: jest.fn(),
-}));
+const MOCKS = '../__test-utils__/convos-route-mocks';
-jest.mock('@librechat/api', () => ({
- isEnabled: jest.fn(),
- createAxiosInstance: jest.fn(() => ({
- get: jest.fn(),
- post: jest.fn(),
- put: jest.fn(),
- delete: jest.fn(),
- })),
- logAxiosError: jest.fn(),
-}));
-
-jest.mock('@librechat/data-schemas', () => ({
- logger: {
- debug: jest.fn(),
- info: jest.fn(),
- warn: jest.fn(),
- error: jest.fn(),
- },
- createModels: jest.fn(() => ({
- User: {},
- Conversation: {},
- Message: {},
- SharedLink: {},
- })),
-}));
-
-jest.mock('~/models/Conversation', () => ({
- getConvosByCursor: jest.fn(),
- getConvo: jest.fn(),
- deleteConvos: jest.fn(),
- saveConvo: jest.fn(),
-}));
-
-jest.mock('~/models/ToolCall', () => ({
- deleteToolCalls: jest.fn(),
-}));
-
-jest.mock('~/models', () => ({
- deleteAllSharedLinks: jest.fn(),
- deleteConvoSharedLink: jest.fn(),
-}));
-
-jest.mock('~/server/middleware/requireJwtAuth', () => (req, res, next) => next());
-
-jest.mock('~/server/middleware', () => ({
- createImportLimiters: jest.fn(() => ({
- importIpLimiter: (req, res, next) => next(),
- importUserLimiter: (req, res, next) => next(),
- })),
- createForkLimiters: jest.fn(() => ({
- forkIpLimiter: (req, res, next) => next(),
- forkUserLimiter: (req, res, next) => next(),
- })),
- configMiddleware: (req, res, next) => next(),
- validateConvoAccess: (req, res, next) => next(),
-}));
-
-jest.mock('~/server/utils/import/fork', () => ({
- forkConversation: jest.fn(),
- duplicateConversation: jest.fn(),
-}));
-
-jest.mock('~/server/utils/import', () => ({
- importConversations: jest.fn(),
-}));
-
-jest.mock('~/cache/getLogStores', () => jest.fn());
-
-jest.mock('~/server/routes/files/multer', () => ({
- storage: {},
- importFileFilter: jest.fn(),
-}));
-
-jest.mock('multer', () => {
- return jest.fn(() => ({
- single: jest.fn(() => (req, res, next) => {
- req.file = { path: '/tmp/test-file.json' };
- next();
- }),
- }));
-});
-
-jest.mock('librechat-data-provider', () => ({
- CacheKeys: {
- GEN_TITLE: 'GEN_TITLE',
- },
- EModelEndpoint: {
- azureAssistants: 'azureAssistants',
- assistants: 'assistants',
- },
-}));
-
-jest.mock('~/server/services/Endpoints/azureAssistants', () => ({
- initializeClient: jest.fn(),
-}));
-
-jest.mock('~/server/services/Endpoints/assistants', () => ({
- initializeClient: jest.fn(),
-}));
+jest.mock('@librechat/agents', () => require(MOCKS).agents());
+jest.mock('@librechat/api', () => require(MOCKS).api());
+jest.mock('@librechat/data-schemas', () => require(MOCKS).dataSchemas());
+jest.mock('librechat-data-provider', () => require(MOCKS).dataProvider());
+jest.mock('~/models', () => require(MOCKS).sharedModels());
+jest.mock('~/server/middleware/requireJwtAuth', () => require(MOCKS).requireJwtAuth());
+jest.mock('~/server/middleware', () => require(MOCKS).middlewarePassthrough());
+jest.mock('~/server/utils/import/fork', () => require(MOCKS).forkUtils());
+jest.mock('~/server/utils/import', () => require(MOCKS).importUtils());
+jest.mock('~/cache/getLogStores', () => require(MOCKS).logStores());
+jest.mock('~/server/routes/files/multer', () => require(MOCKS).multerSetup());
+jest.mock('multer', () => require(MOCKS).multerLib());
+jest.mock('~/server/services/Endpoints/azureAssistants', () => require(MOCKS).assistantEndpoint());
+jest.mock('~/server/services/Endpoints/assistants', () => require(MOCKS).assistantEndpoint());
describe('Convos Routes', () => {
let app;
let convosRouter;
- const { deleteAllSharedLinks, deleteConvoSharedLink } = require('~/models');
- const { deleteConvos, saveConvo } = require('~/models/Conversation');
- const { deleteToolCalls } = require('~/models/ToolCall');
+ const {
+ deleteAllSharedLinks,
+ deleteConvoSharedLink,
+ deleteToolCalls,
+ deleteConvos,
+ saveConvo,
+ } = require('~/models');
beforeAll(() => {
convosRouter = require('../convos');
@@ -520,7 +437,7 @@ describe('Convos Routes', () => {
expect(response.status).toBe(200);
expect(response.body).toEqual(mockArchivedConvo);
expect(saveConvo).toHaveBeenCalledWith(
- expect.objectContaining({ user: { id: 'test-user-123' } }),
+ expect.objectContaining({ userId: 'test-user-123' }),
{ conversationId: mockConversationId, isArchived: true },
{ context: `POST /api/convos/archive ${mockConversationId}` },
);
@@ -549,7 +466,7 @@ describe('Convos Routes', () => {
expect(response.status).toBe(200);
expect(response.body).toEqual(mockUnarchivedConvo);
expect(saveConvo).toHaveBeenCalledWith(
- expect.objectContaining({ user: { id: 'test-user-123' } }),
+ expect.objectContaining({ userId: 'test-user-123' }),
{ conversationId: mockConversationId, isArchived: false },
{ context: `POST /api/convos/archive ${mockConversationId}` },
);
diff --git a/api/server/routes/__tests__/mcp.spec.js b/api/server/routes/__tests__/mcp.spec.js
index e87fcf8f15..1ad8cac087 100644
--- a/api/server/routes/__tests__/mcp.spec.js
+++ b/api/server/routes/__tests__/mcp.spec.js
@@ -32,6 +32,9 @@ jest.mock('@librechat/api', () => {
getFlowState: jest.fn(),
completeOAuthFlow: jest.fn(),
generateFlowId: jest.fn(),
+ resolveStateToFlowId: jest.fn(async (state) => state),
+ storeStateMapping: jest.fn(),
+ deleteStateMapping: jest.fn(),
},
MCPTokenStorage: {
storeTokens: jest.fn(),
@@ -180,7 +183,10 @@ describe('MCP Routes', () => {
MCPOAuthHandler.initiateOAuthFlow.mockResolvedValue({
authorizationUrl: 'https://oauth.example.com/auth',
flowId: 'test-user-id:test-server',
+ flowMetadata: { state: 'random-state-value' },
});
+ MCPOAuthHandler.storeStateMapping.mockResolvedValue();
+ mockFlowManager.initFlow = jest.fn().mockResolvedValue();
const response = await request(app).get('/api/mcp/test-server/oauth/initiate').query({
userId: 'test-user-id',
@@ -367,6 +373,121 @@ describe('MCP Routes', () => {
expect(response.headers.location).toBe(`${basePath}/oauth/error?error=invalid_state`);
});
+ describe('CSRF fallback via active PENDING flow', () => {
+ it('should proceed when a fresh PENDING flow exists and no cookies are present', async () => {
+ const flowId = 'test-user-id:test-server';
+ const mockFlowManager = {
+ getFlowState: jest.fn().mockResolvedValue({
+ status: 'PENDING',
+ createdAt: Date.now(),
+ }),
+ completeFlow: jest.fn().mockResolvedValue(true),
+ deleteFlow: jest.fn().mockResolvedValue(true),
+ };
+ const mockFlowState = {
+ serverName: 'test-server',
+ userId: 'test-user-id',
+ metadata: {},
+ clientInfo: {},
+ codeVerifier: 'test-verifier',
+ };
+
+ getLogStores.mockReturnValue({});
+ require('~/config').getFlowStateManager.mockReturnValue(mockFlowManager);
+ MCPOAuthHandler.getFlowState.mockResolvedValue(mockFlowState);
+ MCPOAuthHandler.completeOAuthFlow.mockResolvedValue({
+ access_token: 'test-token',
+ });
+ MCPTokenStorage.storeTokens.mockResolvedValue();
+ mockRegistryInstance.getServerConfig.mockResolvedValue({});
+
+ const mockMcpManager = {
+ getUserConnection: jest.fn().mockResolvedValue({
+ fetchTools: jest.fn().mockResolvedValue([]),
+ }),
+ };
+ require('~/config').getMCPManager.mockReturnValue(mockMcpManager);
+ require('~/config').getOAuthReconnectionManager.mockReturnValue({
+ clearReconnection: jest.fn(),
+ });
+ require('~/server/services/Config/mcp').updateMCPServerTools.mockResolvedValue();
+
+ const response = await request(app)
+ .get('/api/mcp/test-server/oauth/callback')
+ .query({ code: 'test-code', state: flowId });
+
+ const basePath = getBasePath();
+ expect(response.status).toBe(302);
+ expect(response.headers.location).toContain(`${basePath}/oauth/success`);
+ });
+
+ it('should reject when no PENDING flow exists and no cookies are present', async () => {
+ const flowId = 'test-user-id:test-server';
+ const mockFlowManager = {
+ getFlowState: jest.fn().mockResolvedValue(null),
+ };
+
+ getLogStores.mockReturnValue({});
+ require('~/config').getFlowStateManager.mockReturnValue(mockFlowManager);
+
+ const response = await request(app)
+ .get('/api/mcp/test-server/oauth/callback')
+ .query({ code: 'test-code', state: flowId });
+
+ const basePath = getBasePath();
+ expect(response.status).toBe(302);
+ expect(response.headers.location).toBe(
+ `${basePath}/oauth/error?error=csrf_validation_failed`,
+ );
+ });
+
+ it('should reject when only a COMPLETED flow exists (not PENDING)', async () => {
+ const flowId = 'test-user-id:test-server';
+ const mockFlowManager = {
+ getFlowState: jest.fn().mockResolvedValue({
+ status: 'COMPLETED',
+ createdAt: Date.now(),
+ }),
+ };
+
+ getLogStores.mockReturnValue({});
+ require('~/config').getFlowStateManager.mockReturnValue(mockFlowManager);
+
+ const response = await request(app)
+ .get('/api/mcp/test-server/oauth/callback')
+ .query({ code: 'test-code', state: flowId });
+
+ const basePath = getBasePath();
+ expect(response.status).toBe(302);
+ expect(response.headers.location).toBe(
+ `${basePath}/oauth/error?error=csrf_validation_failed`,
+ );
+ });
+
+ it('should reject when PENDING flow is stale (older than PENDING_STALE_MS)', async () => {
+ const flowId = 'test-user-id:test-server';
+ const mockFlowManager = {
+ getFlowState: jest.fn().mockResolvedValue({
+ status: 'PENDING',
+ createdAt: Date.now() - 3 * 60 * 1000,
+ }),
+ };
+
+ getLogStores.mockReturnValue({});
+ require('~/config').getFlowStateManager.mockReturnValue(mockFlowManager);
+
+ const response = await request(app)
+ .get('/api/mcp/test-server/oauth/callback')
+ .query({ code: 'test-code', state: flowId });
+
+ const basePath = getBasePath();
+ expect(response.status).toBe(302);
+ expect(response.headers.location).toBe(
+ `${basePath}/oauth/error?error=csrf_validation_failed`,
+ );
+ });
+ });
+
it('should handle OAuth callback successfully', async () => {
// mockRegistryInstance is defined at the top of the file
const mockFlowManager = {
@@ -1572,12 +1693,14 @@ describe('MCP Routes', () => {
it('should return all server configs for authenticated user', async () => {
const mockServerConfigs = {
'server-1': {
- endpoint: 'http://server1.com',
- name: 'Server 1',
+ type: 'sse',
+ url: 'http://server1.com/sse',
+ title: 'Server 1',
},
'server-2': {
- endpoint: 'http://server2.com',
- name: 'Server 2',
+ type: 'sse',
+ url: 'http://server2.com/sse',
+ title: 'Server 2',
},
};
@@ -1586,7 +1709,18 @@ describe('MCP Routes', () => {
const response = await request(app).get('/api/mcp/servers');
expect(response.status).toBe(200);
- expect(response.body).toEqual(mockServerConfigs);
+ expect(response.body['server-1']).toMatchObject({
+ type: 'sse',
+ url: 'http://server1.com/sse',
+ title: 'Server 1',
+ });
+ expect(response.body['server-2']).toMatchObject({
+ type: 'sse',
+ url: 'http://server2.com/sse',
+ title: 'Server 2',
+ });
+ expect(response.body['server-1'].headers).toBeUndefined();
+ expect(response.body['server-2'].headers).toBeUndefined();
expect(mockRegistryInstance.getAllServerConfigs).toHaveBeenCalledWith('test-user-id');
});
@@ -1641,10 +1775,10 @@ describe('MCP Routes', () => {
const response = await request(app).post('/api/mcp/servers').send({ config: validConfig });
expect(response.status).toBe(201);
- expect(response.body).toEqual({
- serverName: 'test-sse-server',
- ...validConfig,
- });
+ expect(response.body.serverName).toBe('test-sse-server');
+ expect(response.body.type).toBe('sse');
+ expect(response.body.url).toBe('https://mcp-server.example.com/sse');
+ expect(response.body.title).toBe('Test SSE Server');
expect(mockRegistryInstance.addServer).toHaveBeenCalledWith(
'temp_server_name',
expect.objectContaining({
@@ -1698,6 +1832,78 @@ describe('MCP Routes', () => {
expect(response.body.message).toBe('Invalid configuration');
});
+ it('should reject SSE URL containing env variable references', async () => {
+ const response = await request(app)
+ .post('/api/mcp/servers')
+ .send({
+ config: {
+ type: 'sse',
+ url: 'http://attacker.com/?secret=${JWT_SECRET}',
+ },
+ });
+
+ expect(response.status).toBe(400);
+ expect(response.body.message).toBe('Invalid configuration');
+ expect(mockRegistryInstance.addServer).not.toHaveBeenCalled();
+ });
+
+ it('should reject streamable-http URL containing env variable references', async () => {
+ const response = await request(app)
+ .post('/api/mcp/servers')
+ .send({
+ config: {
+ type: 'streamable-http',
+ url: 'http://attacker.com/?key=${CREDS_KEY}&iv=${CREDS_IV}',
+ },
+ });
+
+ expect(response.status).toBe(400);
+ expect(response.body.message).toBe('Invalid configuration');
+ expect(mockRegistryInstance.addServer).not.toHaveBeenCalled();
+ });
+
+ it('should reject websocket URL containing env variable references', async () => {
+ const response = await request(app)
+ .post('/api/mcp/servers')
+ .send({
+ config: {
+ type: 'websocket',
+ url: 'ws://attacker.com/?secret=${MONGO_URI}',
+ },
+ });
+
+ expect(response.status).toBe(400);
+ expect(response.body.message).toBe('Invalid configuration');
+ expect(mockRegistryInstance.addServer).not.toHaveBeenCalled();
+ });
+
+ it('should redact secrets from create response', async () => {
+ const validConfig = {
+ type: 'sse',
+ url: 'https://mcp-server.example.com/sse',
+ title: 'Test Server',
+ };
+
+ mockRegistryInstance.addServer.mockResolvedValue({
+ serverName: 'test-server',
+ config: {
+ ...validConfig,
+ apiKey: { source: 'admin', authorization_type: 'bearer', key: 'admin-secret-key' },
+ oauth: { client_id: 'cid', client_secret: 'admin-oauth-secret' },
+ headers: { Authorization: 'Bearer leaked-token' },
+ },
+ });
+
+ const response = await request(app).post('/api/mcp/servers').send({ config: validConfig });
+
+ expect(response.status).toBe(201);
+ expect(response.body.apiKey?.key).toBeUndefined();
+ expect(response.body.oauth?.client_secret).toBeUndefined();
+ expect(response.body.headers).toBeUndefined();
+ expect(response.body.apiKey?.source).toBe('admin');
+ expect(response.body.oauth?.client_id).toBe('cid');
+ });
+
it('should return 500 when registry throws error', async () => {
const validConfig = {
type: 'sse',
@@ -1727,7 +1933,9 @@ describe('MCP Routes', () => {
const response = await request(app).get('/api/mcp/servers/test-server');
expect(response.status).toBe(200);
- expect(response.body).toEqual(mockConfig);
+ expect(response.body.type).toBe('sse');
+ expect(response.body.url).toBe('https://mcp-server.example.com/sse');
+ expect(response.body.title).toBe('Test Server');
expect(mockRegistryInstance.getServerConfig).toHaveBeenCalledWith(
'test-server',
'test-user-id',
@@ -1743,6 +1951,29 @@ describe('MCP Routes', () => {
expect(response.body).toEqual({ message: 'MCP server not found' });
});
+ it('should redact secrets from get response', async () => {
+ mockRegistryInstance.getServerConfig.mockResolvedValue({
+ type: 'sse',
+ url: 'https://mcp-server.example.com/sse',
+ title: 'Secret Server',
+ apiKey: { source: 'admin', authorization_type: 'bearer', key: 'decrypted-admin-key' },
+ oauth: { client_id: 'cid', client_secret: 'decrypted-oauth-secret' },
+ headers: { Authorization: 'Bearer internal-token' },
+ oauth_headers: { 'X-OAuth': 'secret-value' },
+ });
+
+ const response = await request(app).get('/api/mcp/servers/secret-server');
+
+ expect(response.status).toBe(200);
+ expect(response.body.title).toBe('Secret Server');
+ expect(response.body.apiKey?.key).toBeUndefined();
+ expect(response.body.apiKey?.source).toBe('admin');
+ expect(response.body.oauth?.client_secret).toBeUndefined();
+ expect(response.body.oauth?.client_id).toBe('cid');
+ expect(response.body.headers).toBeUndefined();
+ expect(response.body.oauth_headers).toBeUndefined();
+ });
+
it('should return 500 when registry throws error', async () => {
mockRegistryInstance.getServerConfig.mockRejectedValue(new Error('Database error'));
@@ -1769,7 +2000,9 @@ describe('MCP Routes', () => {
.send({ config: updatedConfig });
expect(response.status).toBe(200);
- expect(response.body).toEqual(updatedConfig);
+ expect(response.body.type).toBe('sse');
+ expect(response.body.url).toBe('https://updated-mcp-server.example.com/sse');
+ expect(response.body.title).toBe('Updated Server');
expect(mockRegistryInstance.updateServer).toHaveBeenCalledWith(
'test-server',
expect.objectContaining({
@@ -1781,6 +2014,35 @@ describe('MCP Routes', () => {
);
});
+ it('should redact secrets from update response', async () => {
+ const validConfig = {
+ type: 'sse',
+ url: 'https://mcp-server.example.com/sse',
+ title: 'Updated Server',
+ };
+
+ mockRegistryInstance.updateServer.mockResolvedValue({
+ ...validConfig,
+ apiKey: { source: 'admin', authorization_type: 'bearer', key: 'preserved-admin-key' },
+ oauth: { client_id: 'cid', client_secret: 'preserved-oauth-secret' },
+ headers: { Authorization: 'Bearer internal-token' },
+ env: { DATABASE_URL: 'postgres://admin:pass@localhost/db' },
+ });
+
+ const response = await request(app)
+ .patch('/api/mcp/servers/test-server')
+ .send({ config: validConfig });
+
+ expect(response.status).toBe(200);
+ expect(response.body.title).toBe('Updated Server');
+ expect(response.body.apiKey?.key).toBeUndefined();
+ expect(response.body.apiKey?.source).toBe('admin');
+ expect(response.body.oauth?.client_secret).toBeUndefined();
+ expect(response.body.oauth?.client_id).toBe('cid');
+ expect(response.body.headers).toBeUndefined();
+ expect(response.body.env).toBeUndefined();
+ });
+
it('should return 400 for invalid configuration', async () => {
const invalidConfig = {
type: 'sse',
@@ -1797,6 +2059,51 @@ describe('MCP Routes', () => {
expect(response.body.errors).toBeDefined();
});
+ it('should reject SSE URL containing env variable references', async () => {
+ const response = await request(app)
+ .patch('/api/mcp/servers/test-server')
+ .send({
+ config: {
+ type: 'sse',
+ url: 'http://attacker.com/?secret=${JWT_SECRET}',
+ },
+ });
+
+ expect(response.status).toBe(400);
+ expect(response.body.message).toBe('Invalid configuration');
+ expect(mockRegistryInstance.updateServer).not.toHaveBeenCalled();
+ });
+
+ it('should reject streamable-http URL containing env variable references', async () => {
+ const response = await request(app)
+ .patch('/api/mcp/servers/test-server')
+ .send({
+ config: {
+ type: 'streamable-http',
+ url: 'http://attacker.com/?key=${CREDS_KEY}',
+ },
+ });
+
+ expect(response.status).toBe(400);
+ expect(response.body.message).toBe('Invalid configuration');
+ expect(mockRegistryInstance.updateServer).not.toHaveBeenCalled();
+ });
+
+ it('should reject websocket URL containing env variable references', async () => {
+ const response = await request(app)
+ .patch('/api/mcp/servers/test-server')
+ .send({
+ config: {
+ type: 'websocket',
+ url: 'ws://attacker.com/?secret=${MONGO_URI}',
+ },
+ });
+
+ expect(response.status).toBe(400);
+ expect(response.body.message).toBe('Invalid configuration');
+ expect(mockRegistryInstance.updateServer).not.toHaveBeenCalled();
+ });
+
it('should return 500 when registry throws error', async () => {
const validConfig = {
type: 'sse',
diff --git a/api/server/routes/__tests__/messages-delete.spec.js b/api/server/routes/__tests__/messages-delete.spec.js
new file mode 100644
index 0000000000..714d497719
--- /dev/null
+++ b/api/server/routes/__tests__/messages-delete.spec.js
@@ -0,0 +1,199 @@
+const mongoose = require('mongoose');
+const express = require('express');
+const request = require('supertest');
+const { v4: uuidv4 } = require('uuid');
+const { MongoMemoryServer } = require('mongodb-memory-server');
+
+jest.mock('@librechat/agents', () => ({
+ sleep: jest.fn(),
+}));
+
+jest.mock('@librechat/api', () => ({
+ unescapeLaTeX: jest.fn((x) => x),
+ countTokens: jest.fn().mockResolvedValue(10),
+}));
+
+jest.mock('@librechat/data-schemas', () => ({
+ ...jest.requireActual('@librechat/data-schemas'),
+ logger: {
+ debug: jest.fn(),
+ info: jest.fn(),
+ warn: jest.fn(),
+ error: jest.fn(),
+ },
+}));
+
+jest.mock('librechat-data-provider', () => ({
+ ...jest.requireActual('librechat-data-provider'),
+}));
+
+jest.mock('~/models', () => ({
+ saveConvo: jest.fn(),
+ getMessage: jest.fn(),
+ saveMessage: jest.fn(),
+ getMessages: jest.fn(),
+ updateMessage: jest.fn(),
+ deleteMessages: jest.fn(),
+ getConvosQueried: jest.fn(),
+ searchMessages: jest.fn(),
+ getMessagesByCursor: jest.fn(),
+}));
+
+jest.mock('~/server/services/Artifacts/update', () => ({
+ findAllArtifacts: jest.fn(),
+ replaceArtifactContent: jest.fn(),
+}));
+
+jest.mock('~/server/middleware/requireJwtAuth', () => (req, res, next) => next());
+
+jest.mock('~/server/middleware', () => ({
+ requireJwtAuth: (req, res, next) => next(),
+ validateMessageReq: (req, res, next) => next(),
+}));
+
+jest.mock('~/db/models', () => ({
+ Message: {
+ findOne: jest.fn(),
+ find: jest.fn(),
+ meiliSearch: jest.fn(),
+ },
+}));
+
+/* ─── Model-level tests: real MongoDB, proves cross-user deletion is prevented ─── */
+
+const { messageSchema } = require('@librechat/data-schemas');
+
+describe('deleteMessages – model-level IDOR prevention', () => {
+ let mongoServer;
+ let Message;
+
+ const ownerUserId = 'user-owner-111';
+ const attackerUserId = 'user-attacker-222';
+
+ beforeAll(async () => {
+ mongoServer = await MongoMemoryServer.create();
+ Message = mongoose.models.Message || mongoose.model('Message', messageSchema);
+ await mongoose.connect(mongoServer.getUri());
+ });
+
+ afterAll(async () => {
+ await mongoose.disconnect();
+ await mongoServer.stop();
+ });
+
+ beforeEach(async () => {
+ await Message.deleteMany({});
+ });
+
+ it("should NOT delete another user's message when attacker supplies victim messageId", async () => {
+ const conversationId = uuidv4();
+ const victimMsgId = 'victim-msg-001';
+
+ await Message.create({
+ messageId: victimMsgId,
+ conversationId,
+ user: ownerUserId,
+ text: 'Sensitive owner data',
+ });
+
+ await Message.deleteMany({ messageId: victimMsgId, user: attackerUserId });
+
+ const victimMsg = await Message.findOne({ messageId: victimMsgId }).lean();
+ expect(victimMsg).not.toBeNull();
+ expect(victimMsg.user).toBe(ownerUserId);
+ expect(victimMsg.text).toBe('Sensitive owner data');
+ });
+
+ it("should delete the user's own message", async () => {
+ const conversationId = uuidv4();
+ const ownMsgId = 'own-msg-001';
+
+ await Message.create({
+ messageId: ownMsgId,
+ conversationId,
+ user: ownerUserId,
+ text: 'My message',
+ });
+
+ const result = await Message.deleteMany({ messageId: ownMsgId, user: ownerUserId });
+ expect(result.deletedCount).toBe(1);
+
+ const deleted = await Message.findOne({ messageId: ownMsgId }).lean();
+ expect(deleted).toBeNull();
+ });
+
+ it('should scope deletion by conversationId, messageId, and user together', async () => {
+ const convoA = uuidv4();
+ const convoB = uuidv4();
+
+ await Message.create([
+ { messageId: 'msg-a1', conversationId: convoA, user: ownerUserId, text: 'A1' },
+ { messageId: 'msg-b1', conversationId: convoB, user: ownerUserId, text: 'B1' },
+ ]);
+
+ await Message.deleteMany({ messageId: 'msg-a1', conversationId: convoA, user: attackerUserId });
+
+ const remaining = await Message.find({ user: ownerUserId }).lean();
+ expect(remaining).toHaveLength(2);
+ });
+});
+
+/* ─── Route-level tests: supertest + mocked deleteMessages ─── */
+
+describe('DELETE /:conversationId/:messageId – route handler', () => {
+ let app;
+ const { deleteMessages } = require('~/models');
+
+ const authenticatedUserId = 'user-owner-123';
+
+ beforeAll(() => {
+ const messagesRouter = require('../messages');
+
+ app = express();
+ app.use(express.json());
+ app.use((req, res, next) => {
+ req.user = { id: authenticatedUserId };
+ next();
+ });
+ app.use('/api/messages', messagesRouter);
+ });
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('should pass user and conversationId in the deleteMessages filter', async () => {
+ deleteMessages.mockResolvedValue({ deletedCount: 1 });
+
+ await request(app).delete('/api/messages/convo-1/msg-1');
+
+ expect(deleteMessages).toHaveBeenCalledTimes(1);
+ expect(deleteMessages).toHaveBeenCalledWith({
+ messageId: 'msg-1',
+ conversationId: 'convo-1',
+ user: authenticatedUserId,
+ });
+ });
+
+ it('should return 204 on successful deletion', async () => {
+ deleteMessages.mockResolvedValue({ deletedCount: 1 });
+
+ const response = await request(app).delete('/api/messages/convo-1/msg-owned');
+
+ expect(response.status).toBe(204);
+ expect(deleteMessages).toHaveBeenCalledWith({
+ messageId: 'msg-owned',
+ conversationId: 'convo-1',
+ user: authenticatedUserId,
+ });
+ });
+
+ it('should return 500 when deleteMessages throws', async () => {
+ deleteMessages.mockRejectedValue(new Error('DB failure'));
+
+ const response = await request(app).delete('/api/messages/convo-1/msg-1');
+
+ expect(response.status).toBe(500);
+ expect(response.body).toEqual({ error: 'Internal server error' });
+ });
+});
diff --git a/api/server/routes/accessPermissions.test.js b/api/server/routes/accessPermissions.test.js
index 81c21c8667..ddbe702f15 100644
--- a/api/server/routes/accessPermissions.test.js
+++ b/api/server/routes/accessPermissions.test.js
@@ -5,7 +5,7 @@ const { v4: uuidv4 } = require('uuid');
const { createMethods } = require('@librechat/data-schemas');
const { MongoMemoryServer } = require('mongodb-memory-server');
const { ResourceType, PermissionBits } = require('librechat-data-provider');
-const { createAgent } = require('~/models/Agent');
+const { createAgent } = require('~/models');
/**
* Mock the PermissionsController to isolate route testing
diff --git a/api/server/routes/admin/auth.js b/api/server/routes/admin/auth.js
index 291b5eaaf8..e19adf54a9 100644
--- a/api/server/routes/admin/auth.js
+++ b/api/server/routes/admin/auth.js
@@ -3,23 +3,23 @@ const passport = require('passport');
const { randomState } = require('openid-client');
const { logger } = require('@librechat/data-schemas');
const { CacheKeys } = require('librechat-data-provider');
-const {
- requireAdmin,
- getAdminPanelUrl,
- exchangeAdminCode,
- createSetBalanceConfig,
-} = require('@librechat/api');
+const { SystemCapabilities } = require('@librechat/data-schemas');
+const { getAdminPanelUrl, exchangeAdminCode, createSetBalanceConfig } = require('@librechat/api');
const { loginController } = require('~/server/controllers/auth/LoginController');
const { createOAuthHandler } = require('~/server/controllers/auth/oauth');
+const { findBalanceByUser, upsertBalanceFields } = require('~/models');
const { getAppConfig } = require('~/server/services/Config');
+const { requireCapability } = require('~/server/middleware');
const getLogStores = require('~/cache/getLogStores');
const { getOpenIdConfig } = require('~/strategies');
const middleware = require('~/server/middleware');
-const { Balance } = require('~/db/models');
+
+const requireAdminAccess = requireCapability(SystemCapabilities.ACCESS_ADMIN);
const setBalanceConfig = createSetBalanceConfig({
getAppConfig,
- Balance,
+ findBalanceByUser,
+ upsertBalanceFields,
});
const router = express.Router();
@@ -30,12 +30,12 @@ router.post(
middleware.loginLimiter,
middleware.checkBan,
middleware.requireLocalAuth,
- requireAdmin,
+ requireAdminAccess,
setBalanceConfig,
loginController,
);
-router.get('/verify', middleware.requireJwtAuth, requireAdmin, (req, res) => {
+router.get('/verify', middleware.requireJwtAuth, requireAdminAccess, (req, res) => {
const { password: _p, totpSecret: _t, __v, ...user } = req.user;
user.id = user._id.toString();
res.status(200).json({ user });
@@ -66,7 +66,7 @@ router.get(
failureMessage: true,
session: false,
}),
- requireAdmin,
+ requireAdminAccess,
setBalanceConfig,
middleware.checkDomainAllowed,
createOAuthHandler(`${getAdminPanelUrl()}/auth/openid/callback`),
diff --git a/api/server/routes/agents/actions.js b/api/server/routes/agents/actions.js
index 12168ba28a..b3b34f3f1c 100644
--- a/api/server/routes/agents/actions.js
+++ b/api/server/routes/agents/actions.js
@@ -12,19 +12,21 @@ const {
validateActionDomain,
validateAndParseOpenAPISpec,
} = require('librechat-data-provider');
-const { encryptMetadata, domainParser } = require('~/server/services/ActionService');
+const {
+ legacyDomainEncode,
+ encryptMetadata,
+ domainParser,
+} = require('~/server/services/ActionService');
const { findAccessibleResources } = require('~/server/services/PermissionService');
-const { getAgent, updateAgent, getListAgentsByAccess } = require('~/models/Agent');
-const { updateAction, getActions, deleteAction } = require('~/models/Action');
+const db = require('~/models');
const { canAccessAgentResource } = require('~/server/middleware');
-const { getRoleByName } = require('~/models/Role');
const router = express.Router();
const checkAgentCreate = generateCheckAccess({
permissionType: PermissionTypes.AGENTS,
permissions: [Permissions.USE, Permissions.CREATE],
- getRoleByName,
+ getRoleByName: db.getRoleByName,
});
/**
@@ -43,13 +45,15 @@ router.get('/', async (req, res) => {
requiredPermissions: PermissionBits.EDIT,
});
- const agentsResponse = await getListAgentsByAccess({
+ const agentsResponse = await db.getListAgentsByAccess({
accessibleIds: editableAgentObjectIds,
});
const editableAgentIds = agentsResponse.data.map((agent) => agent.id);
const actions =
- editableAgentIds.length > 0 ? await getActions({ agent_id: { $in: editableAgentIds } }) : [];
+ editableAgentIds.length > 0
+ ? await db.getActions({ agent_id: { $in: editableAgentIds } })
+ : [];
res.json(actions);
} catch (error) {
@@ -119,20 +123,21 @@ router.post(
return res.status(400).json({ message: 'Domain not allowed' });
}
- let { domain } = metadata;
- domain = await domainParser(domain, true);
+ const encodedDomain = await domainParser(metadata.domain, true);
- if (!domain) {
+ if (!encodedDomain) {
return res.status(400).json({ message: 'No domain provided' });
}
+ const legacyDomain = legacyDomainEncode(metadata.domain);
+
const action_id = _action_id ?? nanoid();
const initialPromises = [];
// Permissions already validated by middleware - load agent directly
- initialPromises.push(getAgent({ id: agent_id }));
+ initialPromises.push(db.getAgent({ id: agent_id }));
if (_action_id) {
- initialPromises.push(getActions({ action_id }, true));
+ initialPromises.push(db.getActions({ action_id }, true));
}
/** @type {[Agent, [Action|undefined]]} */
@@ -143,6 +148,9 @@ router.post(
if (actions_result && actions_result.length) {
const action = actions_result[0];
+ if (action.agent_id !== agent_id) {
+ return res.status(403).json({ message: 'Action does not belong to this agent' });
+ }
metadata = { ...action.metadata, ...metadata };
}
@@ -157,17 +165,26 @@ router.post(
actions.push(action);
}
- actions.push(`${domain}${actionDelimiter}${action_id}`);
+ actions.push(`${encodedDomain}${actionDelimiter}${action_id}`);
/** @type {string[]}} */
const { tools: _tools = [] } = agent;
+ const shouldRemoveAgentTool = (tool) => {
+ if (!tool) {
+ return false;
+ }
+ return (
+ tool.includes(encodedDomain) || tool.includes(legacyDomain) || tool.includes(action_id)
+ );
+ };
+
const tools = _tools
- .filter((tool) => !(tool && (tool.includes(domain) || tool.includes(action_id))))
- .concat(functions.map((tool) => `${tool.function.name}${actionDelimiter}${domain}`));
+ .filter((tool) => !shouldRemoveAgentTool(tool))
+ .concat(functions.map((tool) => `${tool.function.name}${actionDelimiter}${encodedDomain}`));
// Force version update since actions are changing
- const updatedAgent = await updateAgent(
+ const updatedAgent = await db.updateAgent(
{ id: agent_id },
{ tools, actions },
{
@@ -184,7 +201,7 @@ router.post(
}
/** @type {[Action]} */
- const updatedAction = await updateAction({ action_id }, actionUpdateData);
+ const updatedAction = await db.updateAction({ action_id, agent_id }, actionUpdateData);
const sensitiveFields = ['api_key', 'oauth_client_id', 'oauth_client_secret'];
for (let field of sensitiveFields) {
@@ -221,37 +238,43 @@ router.delete(
const { agent_id, action_id } = req.params;
// Permissions already validated by middleware - load agent directly
- const agent = await getAgent({ id: agent_id });
+ const agent = await db.getAgent({ id: agent_id });
if (!agent) {
return res.status(404).json({ message: 'Agent not found for deleting action' });
}
const { tools = [], actions = [] } = agent;
- let domain = '';
+ let storedDomain = '';
const updatedActions = actions.filter((action) => {
if (action.includes(action_id)) {
- [domain] = action.split(actionDelimiter);
+ [storedDomain] = action.split(actionDelimiter);
return false;
}
return true;
});
- domain = await domainParser(domain, true);
-
- if (!domain) {
+ if (!storedDomain) {
return res.status(400).json({ message: 'No domain provided' });
}
- const updatedTools = tools.filter((tool) => !(tool && tool.includes(domain)));
+ const updatedTools = tools.filter(
+ (tool) => !(tool && (tool.includes(storedDomain) || tool.includes(action_id))),
+ );
// Force version update since actions are being removed
- await updateAgent(
+ await db.updateAgent(
{ id: agent_id },
{ tools: updatedTools, actions: updatedActions },
{ updatingUserId: req.user.id, forceVersion: true },
);
- await deleteAction({ action_id });
+ const deleted = await db.deleteAction({ action_id, agent_id });
+ if (!deleted) {
+ logger.warn('[Agent Action Delete] No matching action document found', {
+ action_id,
+ agent_id,
+ });
+ }
res.status(200).json({ message: 'Action deleted successfully' });
} catch (error) {
const message = 'Trouble deleting the Agent Action';
diff --git a/api/server/routes/agents/chat.js b/api/server/routes/agents/chat.js
index 37b83f4f54..0543b0b1aa 100644
--- a/api/server/routes/agents/chat.js
+++ b/api/server/routes/agents/chat.js
@@ -11,7 +11,7 @@ const {
const { initializeClient } = require('~/server/services/Endpoints/agents');
const AgentController = require('~/server/controllers/agents/request');
const addTitle = require('~/server/services/Endpoints/agents/title');
-const { getRoleByName } = require('~/models/Role');
+const { getRoleByName } = require('~/models');
const router = express.Router();
diff --git a/api/server/routes/agents/index.js b/api/server/routes/agents/index.js
index f8d39cb4d8..86966a3f3e 100644
--- a/api/server/routes/agents/index.js
+++ b/api/server/routes/agents/index.js
@@ -10,8 +10,8 @@ const {
messageUserLimiter,
} = require('~/server/middleware');
const { saveMessage } = require('~/models');
-const openai = require('./openai');
const responses = require('./responses');
+const openai = require('./openai');
const { v1 } = require('./v1');
const chat = require('./chat');
@@ -76,52 +76,62 @@ router.get('/chat/stream/:streamId', async (req, res) => {
logger.debug(`[AgentStream] Client subscribed to ${streamId}, resume: ${isResume}`);
- // Send sync event with resume state for ALL reconnecting clients
- // This supports multi-tab scenarios where each tab needs run step data
- if (isResume) {
- const resumeState = await GenerationJobManager.getResumeState(streamId);
- if (resumeState && !res.writableEnded) {
- // Send sync event with run steps AND aggregatedContent
- // Client will use aggregatedContent to initialize message state
- res.write(`event: message\ndata: ${JSON.stringify({ sync: true, resumeState })}\n\n`);
+ const writeEvent = (event) => {
+ if (!res.writableEnded) {
+ res.write(`event: message\ndata: ${JSON.stringify(event)}\n\n`);
if (typeof res.flush === 'function') {
res.flush();
}
- logger.debug(
- `[AgentStream] Sent sync event for ${streamId} with ${resumeState.runSteps.length} run steps`,
- );
}
- }
+ };
- const result = await GenerationJobManager.subscribe(
- streamId,
- (event) => {
- if (!res.writableEnded) {
- res.write(`event: message\ndata: ${JSON.stringify(event)}\n\n`);
+ const onDone = (event) => {
+ writeEvent(event);
+ res.end();
+ };
+
+ const onError = (error) => {
+ if (!res.writableEnded) {
+ res.write(`event: error\ndata: ${JSON.stringify({ error })}\n\n`);
+ if (typeof res.flush === 'function') {
+ res.flush();
+ }
+ res.end();
+ }
+ };
+
+ let result;
+
+ if (isResume) {
+ const { subscription, resumeState, pendingEvents } =
+ await GenerationJobManager.subscribeWithResume(streamId, writeEvent, onDone, onError);
+
+ if (!res.writableEnded) {
+ if (resumeState) {
+ res.write(
+ `event: message\ndata: ${JSON.stringify({ sync: true, resumeState, pendingEvents })}\n\n`,
+ );
if (typeof res.flush === 'function') {
res.flush();
}
- }
- },
- (event) => {
- if (!res.writableEnded) {
- res.write(`event: message\ndata: ${JSON.stringify(event)}\n\n`);
- if (typeof res.flush === 'function') {
- res.flush();
+ GenerationJobManager.markSyncSent(streamId);
+ logger.debug(
+ `[AgentStream] Sent sync event for ${streamId} with ${resumeState.runSteps.length} run steps, ${pendingEvents.length} pending events`,
+ );
+ } else if (pendingEvents.length > 0) {
+ for (const event of pendingEvents) {
+ writeEvent(event);
}
- res.end();
+ logger.warn(
+ `[AgentStream] Resume state null for ${streamId}, replayed ${pendingEvents.length} gap events directly`,
+ );
}
- },
- (error) => {
- if (!res.writableEnded) {
- res.write(`event: error\ndata: ${JSON.stringify({ error })}\n\n`);
- if (typeof res.flush === 'function') {
- res.flush();
- }
- res.end();
- }
- },
- );
+ }
+
+ result = subscription;
+ } else {
+ result = await GenerationJobManager.subscribe(streamId, writeEvent, onDone, onError);
+ }
if (!result) {
return res.status(404).json({ error: 'Failed to subscribe to stream' });
@@ -253,9 +263,15 @@ router.post('/chat/abort', async (req, res) => {
};
try {
- await saveMessage(req, responseMessage, {
- context: 'api/server/routes/agents/index.js - abort endpoint',
- });
+ await saveMessage(
+ {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ },
+ responseMessage,
+ { context: 'api/server/routes/agents/index.js - abort endpoint' },
+ );
logger.debug(`[AgentStream] Saved partial response for: ${jobStreamId}`);
} catch (saveError) {
logger.error(`[AgentStream] Failed to save partial response: ${saveError.message}`);
diff --git a/api/server/routes/agents/openai.js b/api/server/routes/agents/openai.js
index 9a0d9a3564..72e3da6c5a 100644
--- a/api/server/routes/agents/openai.js
+++ b/api/server/routes/agents/openai.js
@@ -29,26 +29,24 @@ const {
GetModelController,
} = require('~/server/controllers/agents/openai');
const { getEffectivePermissions } = require('~/server/services/PermissionService');
-const { validateAgentApiKey, findUser } = require('~/models');
const { configMiddleware } = require('~/server/middleware');
-const { getRoleByName } = require('~/models/Role');
-const { getAgent } = require('~/models/Agent');
+const db = require('~/models');
const router = express.Router();
const requireApiKeyAuth = createRequireApiKeyAuth({
- validateAgentApiKey,
- findUser,
+ validateAgentApiKey: db.validateAgentApiKey,
+ findUser: db.findUser,
});
const checkRemoteAgentsFeature = generateCheckAccess({
permissionType: PermissionTypes.REMOTE_AGENTS,
permissions: [Permissions.USE],
- getRoleByName,
+ getRoleByName: db.getRoleByName,
});
const checkAgentPermission = createCheckRemoteAgentAccess({
- getAgent,
+ getAgent: db.getAgent,
getEffectivePermissions,
});
diff --git a/api/server/routes/agents/responses.js b/api/server/routes/agents/responses.js
index 431942e921..2c118e0597 100644
--- a/api/server/routes/agents/responses.js
+++ b/api/server/routes/agents/responses.js
@@ -32,26 +32,24 @@ const {
listModels,
} = require('~/server/controllers/agents/responses');
const { getEffectivePermissions } = require('~/server/services/PermissionService');
-const { validateAgentApiKey, findUser } = require('~/models');
const { configMiddleware } = require('~/server/middleware');
-const { getRoleByName } = require('~/models/Role');
-const { getAgent } = require('~/models/Agent');
+const db = require('~/models');
const router = express.Router();
const requireApiKeyAuth = createRequireApiKeyAuth({
- validateAgentApiKey,
- findUser,
+ validateAgentApiKey: db.validateAgentApiKey,
+ findUser: db.findUser,
});
const checkRemoteAgentsFeature = generateCheckAccess({
permissionType: PermissionTypes.REMOTE_AGENTS,
permissions: [Permissions.USE],
- getRoleByName,
+ getRoleByName: db.getRoleByName,
});
const checkAgentPermission = createCheckRemoteAgentAccess({
- getAgent,
+ getAgent: db.getAgent,
getEffectivePermissions,
});
diff --git a/api/server/routes/agents/v1.js b/api/server/routes/agents/v1.js
index 682a9c795f..c4f90d0bd5 100644
--- a/api/server/routes/agents/v1.js
+++ b/api/server/routes/agents/v1.js
@@ -3,7 +3,7 @@ const { generateCheckAccess } = require('@librechat/api');
const { PermissionTypes, Permissions, PermissionBits } = require('librechat-data-provider');
const { requireJwtAuth, configMiddleware, canAccessAgentResource } = require('~/server/middleware');
const v1 = require('~/server/controllers/agents/v1');
-const { getRoleByName } = require('~/models/Role');
+const { getRoleByName } = require('~/models');
const actions = require('./actions');
const tools = require('./tools');
@@ -21,15 +21,6 @@ const checkAgentCreate = generateCheckAccess({
getRoleByName,
});
-const checkGlobalAgentShare = generateCheckAccess({
- permissionType: PermissionTypes.AGENTS,
- permissions: [Permissions.USE, Permissions.CREATE],
- bodyProps: {
- [Permissions.SHARE]: ['projectIds', 'removeProjectIds'],
- },
- getRoleByName,
-});
-
router.use(requireJwtAuth);
/**
@@ -99,7 +90,7 @@ router.get(
*/
router.patch(
'/:id',
- checkGlobalAgentShare,
+ checkAgentCreate,
canAccessAgentResource({
requiredPermission: PermissionBits.EDIT,
resourceIdParam: 'id',
@@ -117,7 +108,7 @@ router.post(
'/:id/duplicate',
checkAgentCreate,
canAccessAgentResource({
- requiredPermission: PermissionBits.VIEW,
+ requiredPermission: PermissionBits.EDIT,
resourceIdParam: 'id',
}),
v1.duplicateAgent,
@@ -148,7 +139,7 @@ router.delete(
*/
router.post(
'/:id/revert',
- checkGlobalAgentShare,
+ checkAgentCreate,
canAccessAgentResource({
requiredPermission: PermissionBits.EDIT,
resourceIdParam: 'id',
diff --git a/api/server/routes/apiKeys.js b/api/server/routes/apiKeys.js
index 29dcc326f5..ee11a8b0dd 100644
--- a/api/server/routes/apiKeys.js
+++ b/api/server/routes/apiKeys.js
@@ -6,9 +6,9 @@ const {
createAgentApiKey,
deleteAgentApiKey,
listAgentApiKeys,
+ getRoleByName,
} = require('~/models');
const { requireJwtAuth } = require('~/server/middleware');
-const { getRoleByName } = require('~/models/Role');
const router = express.Router();
diff --git a/api/server/routes/assistants/actions.js b/api/server/routes/assistants/actions.js
index 57975d32a7..977d3f92a7 100644
--- a/api/server/routes/assistants/actions.js
+++ b/api/server/routes/assistants/actions.js
@@ -3,10 +3,13 @@ const { nanoid } = require('nanoid');
const { logger } = require('@librechat/data-schemas');
const { isActionDomainAllowed } = require('@librechat/api');
const { actionDelimiter, EModelEndpoint, removeNullishValues } = require('librechat-data-provider');
-const { encryptMetadata, domainParser } = require('~/server/services/ActionService');
+const {
+ legacyDomainEncode,
+ encryptMetadata,
+ domainParser,
+} = require('~/server/services/ActionService');
const { getOpenAIClient } = require('~/server/controllers/assistants/helpers');
-const { updateAction, getActions, deleteAction } = require('~/models/Action');
-const { updateAssistantDoc, getAssistant } = require('~/models/Assistant');
+const db = require('~/models');
const router = express.Router();
@@ -39,27 +42,31 @@ router.post('/:assistant_id', async (req, res) => {
return res.status(400).json({ message: 'Domain not allowed' });
}
- let { domain } = metadata;
- domain = await domainParser(domain, true);
+ const encodedDomain = await domainParser(metadata.domain, true);
- if (!domain) {
+ if (!encodedDomain) {
return res.status(400).json({ message: 'No domain provided' });
}
+ const legacyDomain = legacyDomainEncode(metadata.domain);
+
const action_id = _action_id ?? nanoid();
const initialPromises = [];
const { openai } = await getOpenAIClient({ req, res });
- initialPromises.push(getAssistant({ assistant_id }));
+ initialPromises.push(db.getAssistant({ assistant_id }));
initialPromises.push(openai.beta.assistants.retrieve(assistant_id));
- !!_action_id && initialPromises.push(getActions({ action_id }, true));
+ !!_action_id && initialPromises.push(db.getActions({ action_id }, true));
/** @type {[AssistantDocument, Assistant, [Action|undefined]]} */
const [assistant_data, assistant, actions_result] = await Promise.all(initialPromises);
if (actions_result && actions_result.length) {
const action = actions_result[0];
+ if (action.assistant_id !== assistant_id) {
+ return res.status(403).json({ message: 'Action does not belong to this assistant' });
+ }
metadata = { ...action.metadata, ...metadata };
}
@@ -78,25 +85,29 @@ router.post('/:assistant_id', async (req, res) => {
actions.push(action);
}
- actions.push(`${domain}${actionDelimiter}${action_id}`);
+ actions.push(`${encodedDomain}${actionDelimiter}${action_id}`);
/** @type {{ tools: FunctionTool[] | { type: 'code_interpreter'|'retrieval'}[]}} */
const { tools: _tools = [] } = assistant;
+ const shouldRemoveAssistantTool = (tool) => {
+ if (!tool.function) {
+ return false;
+ }
+ const name = tool.function.name;
+ return (
+ name.includes(encodedDomain) || name.includes(legacyDomain) || name.includes(action_id)
+ );
+ };
+
const tools = _tools
- .filter(
- (tool) =>
- !(
- tool.function &&
- (tool.function.name.includes(domain) || tool.function.name.includes(action_id))
- ),
- )
+ .filter((tool) => !shouldRemoveAssistantTool(tool))
.concat(
functions.map((tool) => ({
...tool,
function: {
...tool.function,
- name: `${tool.function.name}${actionDelimiter}${domain}`,
+ name: `${tool.function.name}${actionDelimiter}${encodedDomain}`,
},
})),
);
@@ -109,7 +120,7 @@ router.post('/:assistant_id', async (req, res) => {
if (!assistant_data) {
assistantUpdateData.user = req.user.id;
}
- promises.push(updateAssistantDoc({ assistant_id }, assistantUpdateData));
+ promises.push(db.updateAssistantDoc({ assistant_id }, assistantUpdateData));
// Only update user field for new actions
const actionUpdateData = { metadata, assistant_id };
@@ -117,7 +128,7 @@ router.post('/:assistant_id', async (req, res) => {
// For new actions, use the assistant owner's user ID
actionUpdateData.user = assistant_user || req.user.id;
}
- promises.push(updateAction({ action_id }, actionUpdateData));
+ promises.push(db.updateAction({ action_id, assistant_id }, actionUpdateData));
/** @type {[AssistantDocument, Action]} */
let [assistantDocument, updatedAction] = await Promise.all(promises);
@@ -159,7 +170,7 @@ router.delete('/:assistant_id/:action_id/:model', async (req, res) => {
const { openai } = await getOpenAIClient({ req, res });
const initialPromises = [];
- initialPromises.push(getAssistant({ assistant_id }));
+ initialPromises.push(db.getAssistant({ assistant_id }));
initialPromises.push(openai.beta.assistants.retrieve(assistant_id));
/** @type {[AssistantDocument, Assistant]} */
@@ -168,23 +179,25 @@ router.delete('/:assistant_id/:action_id/:model', async (req, res) => {
const { actions = [] } = assistant_data ?? {};
const { tools = [] } = assistant ?? {};
- let domain = '';
+ let storedDomain = '';
const updatedActions = actions.filter((action) => {
if (action.includes(action_id)) {
- [domain] = action.split(actionDelimiter);
+ [storedDomain] = action.split(actionDelimiter);
return false;
}
return true;
});
- domain = await domainParser(domain, true);
-
- if (!domain) {
+ if (!storedDomain) {
return res.status(400).json({ message: 'No domain provided' });
}
const updatedTools = tools.filter(
- (tool) => !(tool.function && tool.function.name.includes(domain)),
+ (tool) =>
+ !(
+ tool.function &&
+ (tool.function.name.includes(storedDomain) || tool.function.name.includes(action_id))
+ ),
);
await openai.beta.assistants.update(assistant_id, { tools: updatedTools });
@@ -195,10 +208,16 @@ router.delete('/:assistant_id/:action_id/:model', async (req, res) => {
if (!assistant_data) {
assistantUpdateData.user = req.user.id;
}
- promises.push(updateAssistantDoc({ assistant_id }, assistantUpdateData));
- promises.push(deleteAction({ action_id }));
+ promises.push(db.updateAssistantDoc({ assistant_id }, assistantUpdateData));
+ promises.push(db.deleteAction({ action_id, assistant_id }));
- await Promise.all(promises);
+ const [, deletedAction] = await Promise.all(promises);
+ if (!deletedAction) {
+ logger.warn('[Assistant Action Delete] No matching action document found', {
+ action_id,
+ assistant_id,
+ });
+ }
res.status(200).json({ message: 'Action deleted successfully' });
} catch (error) {
const message = 'Trouble deleting the Assistant Action';
diff --git a/api/server/routes/auth.js b/api/server/routes/auth.js
index e84442f65f..c660e6f99d 100644
--- a/api/server/routes/auth.js
+++ b/api/server/routes/auth.js
@@ -17,13 +17,14 @@ const {
const { verify2FAWithTempToken } = require('~/server/controllers/auth/TwoFactorAuthController');
const { logoutController } = require('~/server/controllers/auth/LogoutController');
const { loginController } = require('~/server/controllers/auth/LoginController');
+const { findBalanceByUser, upsertBalanceFields } = require('~/models');
const { getAppConfig } = require('~/server/services/Config');
const middleware = require('~/server/middleware');
-const { Balance } = require('~/db/models');
const setBalanceConfig = createSetBalanceConfig({
getAppConfig,
- Balance,
+ findBalanceByUser,
+ upsertBalanceFields,
});
const router = express.Router();
@@ -63,7 +64,7 @@ router.post(
resetPasswordController,
);
-router.get('/2fa/enable', middleware.requireJwtAuth, enable2FA);
+router.post('/2fa/enable', middleware.requireJwtAuth, enable2FA);
router.post('/2fa/verify', middleware.requireJwtAuth, verify2FA);
router.post('/2fa/verify-temp', middleware.checkBan, verify2FAWithTempToken);
router.post('/2fa/confirm', middleware.requireJwtAuth, confirm2FA);
diff --git a/api/server/routes/banner.js b/api/server/routes/banner.js
index cf7eafd017..ad949fd2ca 100644
--- a/api/server/routes/banner.js
+++ b/api/server/routes/banner.js
@@ -1,13 +1,15 @@
const express = require('express');
-
-const { getBanner } = require('~/models/Banner');
+const { logger } = require('@librechat/data-schemas');
const optionalJwtAuth = require('~/server/middleware/optionalJwtAuth');
+const { getBanner } = require('~/models');
+
const router = express.Router();
router.get('/', optionalJwtAuth, async (req, res) => {
try {
res.status(200).send(await getBanner(req.user));
} catch (error) {
+ logger.error('[getBanner] Error getting banner', error);
res.status(500).json({ message: 'Error getting banner' });
}
});
diff --git a/api/server/routes/categories.js b/api/server/routes/categories.js
index da1828b3ce..612bc37860 100644
--- a/api/server/routes/categories.js
+++ b/api/server/routes/categories.js
@@ -1,7 +1,7 @@
const express = require('express');
const router = express.Router();
const { requireJwtAuth } = require('~/server/middleware');
-const { getCategories } = require('~/models/Categories');
+const { getCategories } = require('~/models');
router.get('/', requireJwtAuth, async (req, res) => {
try {
diff --git a/api/server/routes/config.js b/api/server/routes/config.js
index a2dc5b79d2..bf60f57e08 100644
--- a/api/server/routes/config.js
+++ b/api/server/routes/config.js
@@ -1,10 +1,9 @@
const express = require('express');
const { logger } = require('@librechat/data-schemas');
const { isEnabled, getBalanceConfig } = require('@librechat/api');
-const { Constants, CacheKeys, defaultSocialLogins } = require('librechat-data-provider');
+const { CacheKeys, defaultSocialLogins } = require('librechat-data-provider');
const { getLdapConfig } = require('~/server/services/Config/ldap');
const { getAppConfig } = require('~/server/services/Config/app');
-const { getProjectByName } = require('~/models/Project');
const { getLogStores } = require('~/cache');
const router = express.Router();
@@ -16,9 +15,7 @@ const sharedLinksEnabled =
process.env.ALLOW_SHARED_LINKS === undefined || isEnabled(process.env.ALLOW_SHARED_LINKS);
const publicSharedLinksEnabled =
- sharedLinksEnabled &&
- (process.env.ALLOW_SHARED_LINKS_PUBLIC === undefined ||
- isEnabled(process.env.ALLOW_SHARED_LINKS_PUBLIC));
+ sharedLinksEnabled && isEnabled(process.env.ALLOW_SHARED_LINKS_PUBLIC);
const sharePointFilePickerEnabled = isEnabled(process.env.ENABLE_SHAREPOINT_FILEPICKER);
const openidReuseTokens = isEnabled(process.env.OPENID_REUSE_TOKENS);
@@ -37,8 +34,6 @@ router.get('/', async function (req, res) {
return today.getMonth() === 1 && today.getDate() === 11;
};
- const instanceProject = await getProjectByName(Constants.GLOBAL_PROJECT_NAME, '_id');
-
const ldap = getLdapConfig();
try {
@@ -101,7 +96,6 @@ router.get('/', async function (req, res) {
sharedLinksEnabled,
publicSharedLinksEnabled,
analyticsGtmId: process.env.ANALYTICS_GTM_ID,
- instanceProjectId: instanceProject._id.toString(),
bundlerURL: process.env.SANDPACK_BUNDLER_URL,
staticBundlerURL: process.env.SANDPACK_STATIC_BUNDLER_URL,
sharePointFilePickerEnabled,
diff --git a/api/server/routes/convos.js b/api/server/routes/convos.js
index bb9c4ebea9..1964075ed3 100644
--- a/api/server/routes/convos.js
+++ b/api/server/routes/convos.js
@@ -1,7 +1,7 @@
const multer = require('multer');
const express = require('express');
const { sleep } = require('@librechat/agents');
-const { isEnabled } = require('@librechat/api');
+const { isEnabled, resolveImportMaxFileSize } = require('@librechat/api');
const { logger } = require('@librechat/data-schemas');
const { CacheKeys, EModelEndpoint } = require('librechat-data-provider');
const {
@@ -10,14 +10,12 @@ const {
createForkLimiters,
configMiddleware,
} = require('~/server/middleware');
-const { getConvosByCursor, deleteConvos, getConvo, saveConvo } = require('~/models/Conversation');
const { forkConversation, duplicateConversation } = require('~/server/utils/import/fork');
const { storage, importFileFilter } = require('~/server/routes/files/multer');
-const { deleteAllSharedLinks, deleteConvoSharedLink } = require('~/models');
const requireJwtAuth = require('~/server/middleware/requireJwtAuth');
const { importConversations } = require('~/server/utils/import');
-const { deleteToolCalls } = require('~/models/ToolCall');
const getLogStores = require('~/cache/getLogStores');
+const db = require('~/models');
const assistantClients = {
[EModelEndpoint.azureAssistants]: require('~/server/services/Endpoints/azureAssistants'),
@@ -41,7 +39,7 @@ router.get('/', async (req, res) => {
}
try {
- const result = await getConvosByCursor(req.user.id, {
+ const result = await db.getConvosByCursor(req.user.id, {
cursor,
limit,
isArchived,
@@ -59,7 +57,7 @@ router.get('/', async (req, res) => {
router.get('/:conversationId', async (req, res) => {
const { conversationId } = req.params;
- const convo = await getConvo(req.user.id, conversationId);
+ const convo = await db.getConvo(req.user.id, conversationId);
if (convo) {
res.status(200).json(convo);
@@ -128,10 +126,10 @@ router.delete('/', async (req, res) => {
}
try {
- const dbResponse = await deleteConvos(req.user.id, filter);
+ const dbResponse = await db.deleteConvos(req.user.id, filter);
if (filter.conversationId) {
- await deleteToolCalls(req.user.id, filter.conversationId);
- await deleteConvoSharedLink(req.user.id, filter.conversationId);
+ await db.deleteToolCalls(req.user.id, filter.conversationId);
+ await db.deleteConvoSharedLink(req.user.id, filter.conversationId);
}
res.status(201).json(dbResponse);
} catch (error) {
@@ -142,9 +140,9 @@ router.delete('/', async (req, res) => {
router.delete('/all', async (req, res) => {
try {
- const dbResponse = await deleteConvos(req.user.id, {});
- await deleteToolCalls(req.user.id);
- await deleteAllSharedLinks(req.user.id);
+ const dbResponse = await db.deleteConvos(req.user.id, {});
+ await db.deleteToolCalls(req.user.id);
+ await db.deleteAllSharedLinks(req.user.id);
res.status(201).json(dbResponse);
} catch (error) {
logger.error('Error clearing conversations', error);
@@ -171,8 +169,12 @@ router.post('/archive', validateConvoAccess, async (req, res) => {
}
try {
- const dbResponse = await saveConvo(
- req,
+ const dbResponse = await db.saveConvo(
+ {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ },
{ conversationId, isArchived },
{ context: `POST /api/convos/archive ${conversationId}` },
);
@@ -211,8 +213,12 @@ router.post('/update', validateConvoAccess, async (req, res) => {
const sanitizedTitle = title.trim().slice(0, MAX_CONVO_TITLE_LENGTH);
try {
- const dbResponse = await saveConvo(
- req,
+ const dbResponse = await db.saveConvo(
+ {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ },
{ conversationId, title: sanitizedTitle },
{ context: `POST /api/convos/update ${conversationId}` },
);
@@ -224,8 +230,27 @@ router.post('/update', validateConvoAccess, async (req, res) => {
});
const { importIpLimiter, importUserLimiter } = createImportLimiters();
+/** Fork and duplicate share one rate-limit budget (same "clone" operation class) */
const { forkIpLimiter, forkUserLimiter } = createForkLimiters();
-const upload = multer({ storage: storage, fileFilter: importFileFilter });
+const importMaxFileSize = resolveImportMaxFileSize();
+const upload = multer({
+ storage,
+ fileFilter: importFileFilter,
+ limits: { fileSize: importMaxFileSize },
+});
+const uploadSingle = upload.single('file');
+
+function handleUpload(req, res, next) {
+ uploadSingle(req, res, (err) => {
+ if (err && err.code === 'LIMIT_FILE_SIZE') {
+ return res.status(413).json({ message: 'File exceeds the maximum allowed size' });
+ }
+ if (err) {
+ return next(err);
+ }
+ next();
+ });
+}
/**
* Imports a conversation from a JSON file and saves it to the database.
@@ -238,7 +263,7 @@ router.post(
importIpLimiter,
importUserLimiter,
configMiddleware,
- upload.single('file'),
+ handleUpload,
async (req, res) => {
try {
/* TODO: optimize to return imported conversations and add manually */
@@ -280,7 +305,7 @@ router.post('/fork', forkIpLimiter, forkUserLimiter, async (req, res) => {
}
});
-router.post('/duplicate', async (req, res) => {
+router.post('/duplicate', forkIpLimiter, forkUserLimiter, async (req, res) => {
const { conversationId, title } = req.body;
try {
diff --git a/api/server/routes/files/files.agents.test.js b/api/server/routes/files/files.agents.test.js
index 7c21e95234..5a01df022d 100644
--- a/api/server/routes/files/files.agents.test.js
+++ b/api/server/routes/files/files.agents.test.js
@@ -10,8 +10,8 @@ const {
ResourceType,
PrincipalType,
} = require('librechat-data-provider');
-const { createAgent } = require('~/models/Agent');
-const { createFile } = require('~/models');
+const { SystemCapabilities } = require('@librechat/data-schemas');
+const { createAgent, createFile } = require('~/models');
// Only mock the external dependencies that we don't want to test
jest.mock('~/server/services/Files/process', () => ({
@@ -39,7 +39,16 @@ jest.mock('~/server/services/Tools/credentials', () => ({
loadAuthValues: jest.fn(),
}));
-jest.mock('~/server/services/Files/S3/crud', () => ({
+jest.mock('sharp', () =>
+ jest.fn(() => ({
+ metadata: jest.fn().mockResolvedValue({}),
+ toFormat: jest.fn().mockReturnThis(),
+ toBuffer: jest.fn().mockResolvedValue(Buffer.alloc(0)),
+ })),
+);
+
+jest.mock('@librechat/api', () => ({
+ ...jest.requireActual('@librechat/api'),
refreshS3FileUrls: jest.fn(),
}));
@@ -83,6 +92,7 @@ describe('File Routes - Agent Files Endpoint', () => {
let AclEntry;
// eslint-disable-next-line no-unused-vars
let AccessRole;
+ let SystemGrant;
let modelsToCleanup = [];
beforeAll(async () => {
@@ -109,6 +119,7 @@ describe('File Routes - Agent Files Endpoint', () => {
AclEntry = models.AclEntry;
User = models.User;
AccessRole = models.AccessRole;
+ SystemGrant = models.SystemGrant;
// Seed default roles using our methods
await methods.seedDefaultRoles();
@@ -533,7 +544,7 @@ describe('File Routes - Agent Files Endpoint', () => {
expect(processAgentFileUpload).not.toHaveBeenCalled();
});
- it('should allow file upload for admin user regardless of agent ownership', async () => {
+ it('should allow file upload for user with MANAGE_AGENTS capability regardless of agent ownership', async () => {
// Create an agent owned by authorId
await createAgent({
id: agentCustomId,
@@ -543,6 +554,14 @@ describe('File Routes - Agent Files Endpoint', () => {
author: authorId,
});
+ // Seed MANAGE_AGENTS capability for the ADMIN role
+ await SystemGrant.create({
+ principalType: PrincipalType.ROLE,
+ principalId: SystemRoles.ADMIN,
+ capability: SystemCapabilities.MANAGE_AGENTS,
+ grantedAt: new Date(),
+ });
+
// Create app with admin user (otherUserId as admin)
const testApp = createAppWithUser(otherUserId, SystemRoles.ADMIN);
diff --git a/api/server/routes/files/files.js b/api/server/routes/files/files.js
index 5de2ddb379..bc79a0fb96 100644
--- a/api/server/routes/files/files.js
+++ b/api/server/routes/files/files.js
@@ -2,18 +2,19 @@ const fs = require('fs').promises;
const express = require('express');
const { EnvVar } = require('@librechat/agents');
const { logger } = require('@librechat/data-schemas');
+const { refreshS3FileUrls, verifyAgentUploadPermission } = require('@librechat/api');
const {
Time,
isUUID,
CacheKeys,
FileSources,
- SystemRoles,
ResourceType,
EModelEndpoint,
PermissionBits,
checkOpenAIStorage,
isAssistantsEndpoint,
} = require('librechat-data-provider');
+const { SystemCapabilities } = require('@librechat/data-schemas');
const {
filterFile,
processFileUpload,
@@ -25,27 +26,25 @@ const { getStrategyFunctions } = require('~/server/services/Files/strategies');
const { getOpenAIClient } = require('~/server/controllers/assistants/helpers');
const { checkPermission } = require('~/server/services/PermissionService');
const { loadAuthValues } = require('~/server/services/Tools/credentials');
-const { refreshS3FileUrls } = require('~/server/services/Files/S3/crud');
const { hasAccessToFilesViaAgent } = require('~/server/services/Files');
-const { getFiles, batchUpdateFiles } = require('~/models');
const { cleanFileName } = require('~/server/utils/files');
-const { getAssistant } = require('~/models/Assistant');
-const { getAgent } = require('~/models/Agent');
+const { hasCapability } = require('~/server/middleware');
const { getLogStores } = require('~/cache');
const { Readable } = require('stream');
+const db = require('~/models');
const router = express.Router();
router.get('/', async (req, res) => {
try {
const appConfig = req.config;
- const files = await getFiles({ user: req.user.id });
+ const files = await db.getFiles({ user: req.user.id });
if (appConfig.fileStrategy === FileSources.s3) {
try {
const cache = getLogStores(CacheKeys.S3_EXPIRY_INTERVAL);
const alreadyChecked = await cache.get(req.user.id);
if (!alreadyChecked) {
- await refreshS3FileUrls(files, batchUpdateFiles);
+ await refreshS3FileUrls(files, db.batchUpdateFiles);
await cache.set(req.user.id, true, Time.THIRTY_MINUTES);
}
} catch (error) {
@@ -74,7 +73,7 @@ router.get('/agent/:agent_id', async (req, res) => {
return res.status(400).json({ error: 'Agent ID is required' });
}
- const agent = await getAgent({ id: agent_id });
+ const agent = await db.getAgent({ id: agent_id });
if (!agent) {
return res.status(200).json([]);
}
@@ -106,7 +105,7 @@ router.get('/agent/:agent_id', async (req, res) => {
return res.status(200).json([]);
}
- const files = await getFiles({ file_id: { $in: agentFileIds } }, null, { text: 0 });
+ const files = await db.getFiles({ file_id: { $in: agentFileIds } }, null, { text: 0 });
res.status(200).json(files);
} catch (error) {
@@ -151,7 +150,7 @@ router.delete('/', async (req, res) => {
}
const fileIds = files.map((file) => file.file_id);
- const dbFiles = await getFiles({ file_id: { $in: fileIds } });
+ const dbFiles = await db.getFiles({ file_id: { $in: fileIds } });
const ownedFiles = [];
const nonOwnedFiles = [];
@@ -209,7 +208,7 @@ router.delete('/', async (req, res) => {
/* Handle agent unlinking even if no valid files to delete */
if (req.body.agent_id && req.body.tool_resource && dbFiles.length === 0) {
- const agent = await getAgent({
+ const agent = await db.getAgent({
id: req.body.agent_id,
});
@@ -223,7 +222,7 @@ router.delete('/', async (req, res) => {
/* Handle assistant unlinking even if no valid files to delete */
if (req.body.assistant_id && req.body.tool_resource && dbFiles.length === 0) {
- const assistant = await getAssistant({
+ const assistant = await db.getAssistant({
id: req.body.assistant_id,
});
@@ -381,47 +380,23 @@ router.post('/', async (req, res) => {
return await processFileUpload({ req, res, metadata });
}
- /**
- * Check agent permissions for permanent agent file uploads (not message attachments).
- * Message attachments (message_file=true) are temporary files for a single conversation
- * and should be allowed for users who can chat with the agent.
- * Permanent file uploads to tool_resources require EDIT permission.
- */
- const isMessageAttachment = metadata.message_file === true || metadata.message_file === 'true';
- if (metadata.agent_id && metadata.tool_resource && !isMessageAttachment) {
- const userId = req.user.id;
+ let skipUploadAuth = false;
+ try {
+ skipUploadAuth = await hasCapability(req.user, SystemCapabilities.MANAGE_AGENTS);
+ } catch (err) {
+ logger.warn(`[/files] capability check failed, denying bypass: ${err.message}`);
+ }
- /** Admin users bypass permission checks */
- if (req.user.role !== SystemRoles.ADMIN) {
- const agent = await getAgent({ id: metadata.agent_id });
-
- if (!agent) {
- return res.status(404).json({
- error: 'Not Found',
- message: 'Agent not found',
- });
- }
-
- /** Check if user is the author or has edit permission */
- if (agent.author.toString() !== userId) {
- const hasEditPermission = await checkPermission({
- userId,
- role: req.user.role,
- resourceType: ResourceType.AGENT,
- resourceId: agent._id,
- requiredPermission: PermissionBits.EDIT,
- });
-
- if (!hasEditPermission) {
- logger.warn(
- `[/files] User ${userId} denied upload to agent ${metadata.agent_id} (insufficient permissions)`,
- );
- return res.status(403).json({
- error: 'Forbidden',
- message: 'Insufficient permissions to upload files to this agent',
- });
- }
- }
+ if (!skipUploadAuth) {
+ const denied = await verifyAgentUploadPermission({
+ req,
+ res,
+ metadata,
+ getAgent: db.getAgent,
+ checkPermission,
+ });
+ if (denied) {
+ return;
}
}
diff --git a/api/server/routes/files/files.test.js b/api/server/routes/files/files.test.js
index 1d548b44be..37cbf68b93 100644
--- a/api/server/routes/files/files.test.js
+++ b/api/server/routes/files/files.test.js
@@ -10,8 +10,7 @@ const {
AccessRoleIds,
PrincipalType,
} = require('librechat-data-provider');
-const { createAgent } = require('~/models/Agent');
-const { createFile } = require('~/models');
+const { createAgent, createFile } = require('~/models');
// Only mock the external dependencies that we don't want to test
jest.mock('~/server/services/Files/process', () => ({
@@ -33,7 +32,16 @@ jest.mock('~/server/services/Tools/credentials', () => ({
loadAuthValues: jest.fn(),
}));
-jest.mock('~/server/services/Files/S3/crud', () => ({
+jest.mock('sharp', () =>
+ jest.fn(() => ({
+ metadata: jest.fn().mockResolvedValue({}),
+ toFormat: jest.fn().mockReturnThis(),
+ toBuffer: jest.fn().mockResolvedValue(Buffer.alloc(0)),
+ })),
+);
+
+jest.mock('@librechat/api', () => ({
+ ...jest.requireActual('@librechat/api'),
refreshS3FileUrls: jest.fn(),
}));
diff --git a/api/server/routes/files/images.agents.test.js b/api/server/routes/files/images.agents.test.js
new file mode 100644
index 0000000000..f855a436d4
--- /dev/null
+++ b/api/server/routes/files/images.agents.test.js
@@ -0,0 +1,376 @@
+const express = require('express');
+const request = require('supertest');
+const mongoose = require('mongoose');
+const { v4: uuidv4 } = require('uuid');
+const { createMethods } = require('@librechat/data-schemas');
+const { MongoMemoryServer } = require('mongodb-memory-server');
+const {
+ SystemRoles,
+ AccessRoleIds,
+ ResourceType,
+ PrincipalType,
+} = require('librechat-data-provider');
+const { createAgent } = require('~/models');
+
+jest.mock('~/server/services/Files/process', () => ({
+ processAgentFileUpload: jest.fn().mockImplementation(async ({ res }) => {
+ return res.status(200).json({ message: 'Agent file uploaded', file_id: 'test-file-id' });
+ }),
+ processImageFile: jest.fn().mockImplementation(async ({ res }) => {
+ return res.status(200).json({ message: 'Image processed' });
+ }),
+ filterFile: jest.fn(),
+}));
+
+jest.mock('fs', () => {
+ const actualFs = jest.requireActual('fs');
+ return {
+ ...actualFs,
+ promises: {
+ ...actualFs.promises,
+ unlink: jest.fn().mockResolvedValue(undefined),
+ },
+ };
+});
+
+const fs = require('fs');
+const { processAgentFileUpload } = require('~/server/services/Files/process');
+
+const router = require('~/server/routes/files/images');
+
+describe('POST /images - Agent Upload Permission Check (Integration)', () => {
+ let mongoServer;
+ let authorId;
+ let otherUserId;
+ let agentCustomId;
+ let User;
+ let Agent;
+ let AclEntry;
+ let methods;
+ let modelsToCleanup = [];
+
+ beforeAll(async () => {
+ mongoServer = await MongoMemoryServer.create();
+ const mongoUri = mongoServer.getUri();
+ await mongoose.connect(mongoUri);
+
+ const { createModels } = require('@librechat/data-schemas');
+ const models = createModels(mongoose);
+ modelsToCleanup = Object.keys(models);
+ Object.assign(mongoose.models, models);
+ methods = createMethods(mongoose);
+
+ User = models.User;
+ Agent = models.Agent;
+ AclEntry = models.AclEntry;
+
+ await methods.seedDefaultRoles();
+ });
+
+ afterAll(async () => {
+ const collections = mongoose.connection.collections;
+ for (const key in collections) {
+ await collections[key].deleteMany({});
+ }
+ for (const modelName of modelsToCleanup) {
+ if (mongoose.models[modelName]) {
+ delete mongoose.models[modelName];
+ }
+ }
+ await mongoose.disconnect();
+ await mongoServer.stop();
+ });
+
+ beforeEach(async () => {
+ await Agent.deleteMany({});
+ await User.deleteMany({});
+ await AclEntry.deleteMany({});
+
+ authorId = new mongoose.Types.ObjectId();
+ otherUserId = new mongoose.Types.ObjectId();
+ agentCustomId = `agent_${uuidv4().replace(/-/g, '').substring(0, 21)}`;
+
+ await User.create({ _id: authorId, username: 'author', email: 'author@test.com' });
+ await User.create({ _id: otherUserId, username: 'other', email: 'other@test.com' });
+
+ jest.clearAllMocks();
+ });
+
+ const createAppWithUser = (userId, userRole = SystemRoles.USER) => {
+ const app = express();
+ app.use(express.json());
+ app.use((req, _res, next) => {
+ if (req.method === 'POST') {
+ req.file = {
+ originalname: 'test.png',
+ mimetype: 'image/png',
+ size: 100,
+ path: '/tmp/t.png',
+ filename: 'test.png',
+ };
+ req.file_id = uuidv4();
+ }
+ next();
+ });
+ app.use((req, _res, next) => {
+ req.user = { id: userId.toString(), role: userRole };
+ req.app = { locals: {} };
+ req.config = { fileStrategy: 'local', paths: { imageOutput: '/tmp/images' } };
+ next();
+ });
+ app.use('/images', router);
+ return app;
+ };
+
+ it('should return 403 when user has no permission on agent', async () => {
+ await createAgent({
+ id: agentCustomId,
+ name: 'Test Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+
+ const app = createAppWithUser(otherUserId);
+ const response = await request(app).post('/images').send({
+ endpoint: 'agents',
+ agent_id: agentCustomId,
+ tool_resource: 'context',
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(403);
+ expect(response.body.error).toBe('Forbidden');
+ expect(processAgentFileUpload).not.toHaveBeenCalled();
+ expect(fs.promises.unlink).toHaveBeenCalledWith('/tmp/t.png');
+ });
+
+ it('should allow upload for agent owner', async () => {
+ await createAgent({
+ id: agentCustomId,
+ name: 'Test Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+
+ const app = createAppWithUser(authorId);
+ const response = await request(app).post('/images').send({
+ endpoint: 'agents',
+ agent_id: agentCustomId,
+ tool_resource: 'context',
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(200);
+ expect(processAgentFileUpload).toHaveBeenCalled();
+ });
+
+ it('should allow upload for admin regardless of ownership', async () => {
+ await createAgent({
+ id: agentCustomId,
+ name: 'Test Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+
+ const app = createAppWithUser(otherUserId, SystemRoles.ADMIN);
+ const response = await request(app).post('/images').send({
+ endpoint: 'agents',
+ agent_id: agentCustomId,
+ tool_resource: 'context',
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(200);
+ expect(processAgentFileUpload).toHaveBeenCalled();
+ });
+
+ it('should allow upload for user with EDIT permission', async () => {
+ const agent = await createAgent({
+ id: agentCustomId,
+ name: 'Test Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+
+ const { grantPermission } = require('~/server/services/PermissionService');
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: otherUserId,
+ resourceType: ResourceType.AGENT,
+ resourceId: agent._id,
+ accessRoleId: AccessRoleIds.AGENT_EDITOR,
+ grantedBy: authorId,
+ });
+
+ const app = createAppWithUser(otherUserId);
+ const response = await request(app).post('/images').send({
+ endpoint: 'agents',
+ agent_id: agentCustomId,
+ tool_resource: 'context',
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(200);
+ expect(processAgentFileUpload).toHaveBeenCalled();
+ });
+
+ it('should deny upload for user with only VIEW permission', async () => {
+ const agent = await createAgent({
+ id: agentCustomId,
+ name: 'Test Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+
+ const { grantPermission } = require('~/server/services/PermissionService');
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: otherUserId,
+ resourceType: ResourceType.AGENT,
+ resourceId: agent._id,
+ accessRoleId: AccessRoleIds.AGENT_VIEWER,
+ grantedBy: authorId,
+ });
+
+ const app = createAppWithUser(otherUserId);
+ const response = await request(app).post('/images').send({
+ endpoint: 'agents',
+ agent_id: agentCustomId,
+ tool_resource: 'context',
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(403);
+ expect(response.body.error).toBe('Forbidden');
+ expect(processAgentFileUpload).not.toHaveBeenCalled();
+ expect(fs.promises.unlink).toHaveBeenCalledWith('/tmp/t.png');
+ });
+
+ it('should skip permission check for regular image uploads without agent_id/tool_resource', async () => {
+ const app = createAppWithUser(otherUserId);
+ const response = await request(app).post('/images').send({
+ endpoint: 'agents',
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(200);
+ });
+
+ it('should return 404 for non-existent agent', async () => {
+ const app = createAppWithUser(otherUserId);
+ const response = await request(app).post('/images').send({
+ endpoint: 'agents',
+ agent_id: 'agent_nonexistent123456789',
+ tool_resource: 'context',
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(404);
+ expect(response.body.error).toBe('Not Found');
+ expect(processAgentFileUpload).not.toHaveBeenCalled();
+ expect(fs.promises.unlink).toHaveBeenCalledWith('/tmp/t.png');
+ });
+
+ it('should allow message_file attachment (boolean true) without EDIT permission', async () => {
+ const agent = await createAgent({
+ id: agentCustomId,
+ name: 'Test Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+
+ const { grantPermission } = require('~/server/services/PermissionService');
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: otherUserId,
+ resourceType: ResourceType.AGENT,
+ resourceId: agent._id,
+ accessRoleId: AccessRoleIds.AGENT_VIEWER,
+ grantedBy: authorId,
+ });
+
+ const app = createAppWithUser(otherUserId);
+ const response = await request(app).post('/images').send({
+ endpoint: 'agents',
+ agent_id: agentCustomId,
+ tool_resource: 'context',
+ message_file: true,
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(200);
+ expect(processAgentFileUpload).toHaveBeenCalled();
+ });
+
+ it('should allow message_file attachment (string "true") without EDIT permission', async () => {
+ const agent = await createAgent({
+ id: agentCustomId,
+ name: 'Test Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+
+ const { grantPermission } = require('~/server/services/PermissionService');
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: otherUserId,
+ resourceType: ResourceType.AGENT,
+ resourceId: agent._id,
+ accessRoleId: AccessRoleIds.AGENT_VIEWER,
+ grantedBy: authorId,
+ });
+
+ const app = createAppWithUser(otherUserId);
+ const response = await request(app).post('/images').send({
+ endpoint: 'agents',
+ agent_id: agentCustomId,
+ tool_resource: 'context',
+ message_file: 'true',
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(200);
+ expect(processAgentFileUpload).toHaveBeenCalled();
+ });
+
+ it('should deny upload when message_file is false (not a message attachment)', async () => {
+ const agent = await createAgent({
+ id: agentCustomId,
+ name: 'Test Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+
+ const { grantPermission } = require('~/server/services/PermissionService');
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: otherUserId,
+ resourceType: ResourceType.AGENT,
+ resourceId: agent._id,
+ accessRoleId: AccessRoleIds.AGENT_VIEWER,
+ grantedBy: authorId,
+ });
+
+ const app = createAppWithUser(otherUserId);
+ const response = await request(app).post('/images').send({
+ endpoint: 'agents',
+ agent_id: agentCustomId,
+ tool_resource: 'context',
+ message_file: false,
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(403);
+ expect(response.body.error).toBe('Forbidden');
+ expect(processAgentFileUpload).not.toHaveBeenCalled();
+ expect(fs.promises.unlink).toHaveBeenCalledWith('/tmp/t.png');
+ });
+});
diff --git a/api/server/routes/files/images.js b/api/server/routes/files/images.js
index 8072612a69..c8ebe89473 100644
--- a/api/server/routes/files/images.js
+++ b/api/server/routes/files/images.js
@@ -2,12 +2,15 @@ const path = require('path');
const fs = require('fs').promises;
const express = require('express');
const { logger } = require('@librechat/data-schemas');
+const { verifyAgentUploadPermission } = require('@librechat/api');
const { isAssistantsEndpoint } = require('librechat-data-provider');
const {
processAgentFileUpload,
processImageFile,
filterFile,
} = require('~/server/services/Files/process');
+const { checkPermission } = require('~/server/services/PermissionService');
+const db = require('~/models');
const router = express.Router();
@@ -22,6 +25,16 @@ router.post('/', async (req, res) => {
metadata.file_id = req.file_id;
if (!isAssistantsEndpoint(metadata.endpoint) && metadata.tool_resource != null) {
+ const denied = await verifyAgentUploadPermission({
+ req,
+ res,
+ metadata,
+ getAgent: db.getAgent,
+ checkPermission,
+ });
+ if (denied) {
+ return;
+ }
return await processAgentFileUpload({ req, res, metadata });
}
diff --git a/api/server/routes/mcp.js b/api/server/routes/mcp.js
index 2db8c2c462..d6d7ed5ea0 100644
--- a/api/server/routes/mcp.js
+++ b/api/server/routes/mcp.js
@@ -13,6 +13,7 @@ const {
MCPOAuthHandler,
MCPTokenStorage,
setOAuthSession,
+ PENDING_STALE_MS,
getUserMCPAuthMap,
validateOAuthCsrf,
OAUTH_CSRF_COOKIE,
@@ -37,18 +38,28 @@ const {
} = require('~/config');
const { getMCPSetupData, getServerConnectionStatus } = require('~/server/services/MCP');
const { requireJwtAuth, canAccessMCPServerResource } = require('~/server/middleware');
-const { findToken, updateToken, createToken, deleteTokens } = require('~/models');
const { getUserPluginAuthValue } = require('~/server/services/PluginService');
const { updateMCPServerTools } = require('~/server/services/Config/mcp');
const { reinitMCPServer } = require('~/server/services/Tools/mcp');
-const { findPluginAuthsByKeys } = require('~/models');
-const { getRoleByName } = require('~/models/Role');
const { getLogStores } = require('~/cache');
+const db = require('~/models');
const router = Router();
const OAUTH_CSRF_COOKIE_PATH = '/api/mcp';
+const checkMCPUsePermissions = generateCheckAccess({
+ permissionType: PermissionTypes.MCP_SERVERS,
+ permissions: [Permissions.USE],
+ getRoleByName: db.getRoleByName,
+});
+
+const checkMCPCreate = generateCheckAccess({
+ permissionType: PermissionTypes.MCP_SERVERS,
+ permissions: [Permissions.USE, Permissions.CREATE],
+ getRoleByName: db.getRoleByName,
+});
+
/**
* Get all MCP tools available to the user
* Returns only MCP tools, completely decoupled from regular LibreChat tools
@@ -91,7 +102,11 @@ router.get('/:serverName/oauth/initiate', requireJwtAuth, setOAuthSession, async
}
const oauthHeaders = await getOAuthHeaders(serverName, userId);
- const { authorizationUrl, flowId: oauthFlowId } = await MCPOAuthHandler.initiateOAuthFlow(
+ const {
+ authorizationUrl,
+ flowId: oauthFlowId,
+ flowMetadata,
+ } = await MCPOAuthHandler.initiateOAuthFlow(
serverName,
serverUrl,
userId,
@@ -101,6 +116,7 @@ router.get('/:serverName/oauth/initiate', requireJwtAuth, setOAuthSession, async
logger.debug('[MCP OAuth] OAuth flow initiated', { oauthFlowId, authorizationUrl });
+ await MCPOAuthHandler.storeStateMapping(flowMetadata.state, oauthFlowId, flowManager);
setOAuthCsrfCookie(res, oauthFlowId, OAUTH_CSRF_COOKIE_PATH);
res.redirect(authorizationUrl);
} catch (error) {
@@ -143,30 +159,52 @@ router.get('/:serverName/oauth/callback', async (req, res) => {
return res.redirect(`${basePath}/oauth/error?error=missing_state`);
}
- const flowId = state;
- logger.debug('[MCP OAuth] Using flow ID from state', { flowId });
+ const flowsCache = getLogStores(CacheKeys.FLOWS);
+ const flowManager = getFlowStateManager(flowsCache);
+
+ const flowId = await MCPOAuthHandler.resolveStateToFlowId(state, flowManager);
+ if (!flowId) {
+ logger.error('[MCP OAuth] Could not resolve state to flow ID', { state });
+ return res.redirect(`${basePath}/oauth/error?error=invalid_state`);
+ }
+ logger.debug('[MCP OAuth] Resolved flow ID from state', { flowId });
const flowParts = flowId.split(':');
if (flowParts.length < 2 || !flowParts[0] || !flowParts[1]) {
- logger.error('[MCP OAuth] Invalid flow ID format in state', { flowId });
+ logger.error('[MCP OAuth] Invalid flow ID format', { flowId });
return res.redirect(`${basePath}/oauth/error?error=invalid_state`);
}
const [flowUserId] = flowParts;
- if (
- !validateOAuthCsrf(req, res, flowId, OAUTH_CSRF_COOKIE_PATH) &&
- !validateOAuthSession(req, flowUserId)
- ) {
- logger.error('[MCP OAuth] CSRF validation failed: no valid CSRF or session cookie', {
- flowId,
- hasCsrfCookie: !!req.cookies?.[OAUTH_CSRF_COOKIE],
- hasSessionCookie: !!req.cookies?.[OAUTH_SESSION_COOKIE],
- });
- return res.redirect(`${basePath}/oauth/error?error=csrf_validation_failed`);
+
+ const hasCsrf = validateOAuthCsrf(req, res, flowId, OAUTH_CSRF_COOKIE_PATH);
+ const hasSession = !hasCsrf && validateOAuthSession(req, flowUserId);
+ let hasActiveFlow = false;
+ if (!hasCsrf && !hasSession) {
+ const pendingFlow = await flowManager.getFlowState(flowId, 'mcp_oauth');
+ const pendingAge = pendingFlow?.createdAt ? Date.now() - pendingFlow.createdAt : Infinity;
+ hasActiveFlow = pendingFlow?.status === 'PENDING' && pendingAge < PENDING_STALE_MS;
+ if (hasActiveFlow) {
+ logger.debug(
+ '[MCP OAuth] CSRF/session cookies absent, validating via active PENDING flow',
+ {
+ flowId,
+ },
+ );
+ }
}
- const flowsCache = getLogStores(CacheKeys.FLOWS);
- const flowManager = getFlowStateManager(flowsCache);
+ if (!hasCsrf && !hasSession && !hasActiveFlow) {
+ logger.error(
+ '[MCP OAuth] CSRF validation failed: no valid CSRF cookie, session cookie, or active flow',
+ {
+ flowId,
+ hasCsrfCookie: !!req.cookies?.[OAUTH_CSRF_COOKIE],
+ hasSessionCookie: !!req.cookies?.[OAUTH_SESSION_COOKIE],
+ },
+ );
+ return res.redirect(`${basePath}/oauth/error?error=csrf_validation_failed`);
+ }
logger.debug('[MCP OAuth] Getting flow state for flowId: ' + flowId);
const flowState = await MCPOAuthHandler.getFlowState(flowId, flowManager);
@@ -206,9 +244,9 @@ router.get('/:serverName/oauth/callback', async (req, res) => {
userId: flowState.userId,
serverName,
tokens,
- createToken,
- updateToken,
- findToken,
+ createToken: db.createToken,
+ updateToken: db.updateToken,
+ findToken: db.findToken,
clientInfo: flowState.clientInfo,
metadata: flowState.metadata,
});
@@ -246,10 +284,10 @@ router.get('/:serverName/oauth/callback', async (req, res) => {
serverName,
flowManager,
tokenMethods: {
- findToken,
- updateToken,
- createToken,
- deleteTokens,
+ findToken: db.findToken,
+ updateToken: db.updateToken,
+ createToken: db.createToken,
+ deleteTokens: db.deleteTokens,
},
});
@@ -281,7 +319,13 @@ router.get('/:serverName/oauth/callback', async (req, res) => {
const toolFlowId = flowState.metadata?.toolFlowId;
if (toolFlowId) {
logger.debug('[MCP OAuth] Completing tool flow', { toolFlowId });
- await flowManager.completeFlow(toolFlowId, 'mcp_oauth', tokens);
+ const completed = await flowManager.completeFlow(toolFlowId, 'mcp_oauth', tokens);
+ if (!completed) {
+ logger.warn(
+ '[MCP OAuth] Tool flow state not found during completion — waiter will time out',
+ { toolFlowId },
+ );
+ }
}
/** Redirect to success page with flowId and serverName */
@@ -436,69 +480,75 @@ router.post('/oauth/cancel/:serverName', requireJwtAuth, async (req, res) => {
* Reinitialize MCP server
* This endpoint allows reinitializing a specific MCP server
*/
-router.post('/:serverName/reinitialize', requireJwtAuth, setOAuthSession, async (req, res) => {
- try {
- const { serverName } = req.params;
- const user = createSafeUser(req.user);
+router.post(
+ '/:serverName/reinitialize',
+ requireJwtAuth,
+ checkMCPUsePermissions,
+ setOAuthSession,
+ async (req, res) => {
+ try {
+ const { serverName } = req.params;
+ const user = createSafeUser(req.user);
- if (!user.id) {
- return res.status(401).json({ error: 'User not authenticated' });
- }
+ if (!user.id) {
+ return res.status(401).json({ error: 'User not authenticated' });
+ }
- logger.info(`[MCP Reinitialize] Reinitializing server: ${serverName}`);
+ logger.info(`[MCP Reinitialize] Reinitializing server: ${serverName}`);
- const mcpManager = getMCPManager();
- const serverConfig = await getMCPServersRegistry().getServerConfig(serverName, user.id);
- if (!serverConfig) {
- return res.status(404).json({
- error: `MCP server '${serverName}' not found in configuration`,
+ const mcpManager = getMCPManager();
+ const serverConfig = await getMCPServersRegistry().getServerConfig(serverName, user.id);
+ if (!serverConfig) {
+ return res.status(404).json({
+ error: `MCP server '${serverName}' not found in configuration`,
+ });
+ }
+
+ await mcpManager.disconnectUserConnection(user.id, serverName);
+ logger.info(
+ `[MCP Reinitialize] Disconnected existing user connection for server: ${serverName}`,
+ );
+
+ /** @type {Record> | undefined} */
+ let userMCPAuthMap;
+ if (serverConfig.customUserVars && typeof serverConfig.customUserVars === 'object') {
+ userMCPAuthMap = await getUserMCPAuthMap({
+ userId: user.id,
+ servers: [serverName],
+ findPluginAuthsByKeys: db.findPluginAuthsByKeys,
+ });
+ }
+
+ const result = await reinitMCPServer({
+ user,
+ serverName,
+ userMCPAuthMap,
});
- }
- await mcpManager.disconnectUserConnection(user.id, serverName);
- logger.info(
- `[MCP Reinitialize] Disconnected existing user connection for server: ${serverName}`,
- );
+ if (!result) {
+ return res.status(500).json({ error: 'Failed to reinitialize MCP server for user' });
+ }
- /** @type {Record> | undefined} */
- let userMCPAuthMap;
- if (serverConfig.customUserVars && typeof serverConfig.customUserVars === 'object') {
- userMCPAuthMap = await getUserMCPAuthMap({
- userId: user.id,
- servers: [serverName],
- findPluginAuthsByKeys,
+ const { success, message, oauthRequired, oauthUrl } = result;
+
+ if (oauthRequired) {
+ const flowId = MCPOAuthHandler.generateFlowId(user.id, serverName);
+ setOAuthCsrfCookie(res, flowId, OAUTH_CSRF_COOKIE_PATH);
+ }
+
+ res.json({
+ success,
+ message,
+ oauthUrl,
+ serverName,
+ oauthRequired,
});
+ } catch (error) {
+ logger.error('[MCP Reinitialize] Unexpected error', error);
+ res.status(500).json({ error: 'Internal server error' });
}
-
- const result = await reinitMCPServer({
- user,
- serverName,
- userMCPAuthMap,
- });
-
- if (!result) {
- return res.status(500).json({ error: 'Failed to reinitialize MCP server for user' });
- }
-
- const { success, message, oauthRequired, oauthUrl } = result;
-
- if (oauthRequired) {
- const flowId = MCPOAuthHandler.generateFlowId(user.id, serverName);
- setOAuthCsrfCookie(res, flowId, OAUTH_CSRF_COOKIE_PATH);
- }
-
- res.json({
- success,
- message,
- oauthUrl,
- serverName,
- oauthRequired,
- });
- } catch (error) {
- logger.error('[MCP Reinitialize] Unexpected error', error);
- res.status(500).json({ error: 'Internal server error' });
- }
-});
+ },
+);
/**
* Get connection status for all MCP servers
@@ -605,7 +655,7 @@ router.get('/connection/status/:serverName', requireJwtAuth, async (req, res) =>
* Check which authentication values exist for a specific MCP server
* This endpoint returns only boolean flags indicating if values are set, not the actual values
*/
-router.get('/:serverName/auth-values', requireJwtAuth, async (req, res) => {
+router.get('/:serverName/auth-values', requireJwtAuth, checkMCPUsePermissions, async (req, res) => {
try {
const { serverName } = req.params;
const user = req.user;
@@ -662,19 +712,6 @@ async function getOAuthHeaders(serverName, userId) {
MCP Server CRUD Routes (User-Managed MCP Servers)
*/
-// Permission checkers for MCP server management
-const checkMCPUsePermissions = generateCheckAccess({
- permissionType: PermissionTypes.MCP_SERVERS,
- permissions: [Permissions.USE],
- getRoleByName,
-});
-
-const checkMCPCreate = generateCheckAccess({
- permissionType: PermissionTypes.MCP_SERVERS,
- permissions: [Permissions.USE, Permissions.CREATE],
- getRoleByName,
-});
-
/**
* Get list of accessible MCP servers
* @route GET /api/mcp/servers
diff --git a/api/server/routes/memories.js b/api/server/routes/memories.js
index 58955d8ec4..e71e94f457 100644
--- a/api/server/routes/memories.js
+++ b/api/server/routes/memories.js
@@ -4,12 +4,12 @@ const { PermissionTypes, Permissions } = require('librechat-data-provider');
const {
getAllUserMemories,
toggleUserMemories,
+ getRoleByName,
createMemory,
deleteMemory,
setMemory,
} = require('~/models');
const { requireJwtAuth, configMiddleware } = require('~/server/middleware');
-const { getRoleByName } = require('~/models/Role');
const router = express.Router();
diff --git a/api/server/routes/messages.js b/api/server/routes/messages.js
index c208e9c406..21b2b23fea 100644
--- a/api/server/routes/messages.js
+++ b/api/server/routes/messages.js
@@ -3,18 +3,9 @@ const { v4: uuidv4 } = require('uuid');
const { logger } = require('@librechat/data-schemas');
const { ContentTypes } = require('librechat-data-provider');
const { unescapeLaTeX, countTokens } = require('@librechat/api');
-const {
- saveConvo,
- getMessage,
- saveMessage,
- getMessages,
- updateMessage,
- deleteMessages,
-} = require('~/models');
const { findAllArtifacts, replaceArtifactContent } = require('~/server/services/Artifacts/update');
const { requireJwtAuth, validateMessageReq } = require('~/server/middleware');
-const { getConvosQueried } = require('~/models/Conversation');
-const { Message } = require('~/db/models');
+const db = require('~/models');
const router = express.Router();
router.use(requireJwtAuth);
@@ -40,34 +31,19 @@ router.get('/', async (req, res) => {
const sortOrder = sortDirection === 'asc' ? 1 : -1;
if (conversationId && messageId) {
- const message = await Message.findOne({
- conversationId,
- messageId,
- user: user,
- }).lean();
- response = { messages: message ? [message] : [], nextCursor: null };
+ const messages = await db.getMessages({ conversationId, messageId, user });
+ response = { messages: messages?.length ? [messages[0]] : [], nextCursor: null };
} else if (conversationId) {
- const filter = { conversationId, user: user };
- if (cursor) {
- filter[sortField] = sortOrder === 1 ? { $gt: cursor } : { $lt: cursor };
- }
- const messages = await Message.find(filter)
- .sort({ [sortField]: sortOrder })
- .limit(pageSize + 1)
- .lean();
- let nextCursor = null;
- if (messages.length > pageSize) {
- messages.pop(); // Remove extra item used to detect next page
- // Create cursor from the last RETURNED item (not the popped one)
- nextCursor = messages[messages.length - 1][sortField];
- }
- response = { messages, nextCursor };
+ response = await db.getMessagesByCursor(
+ { conversationId, user },
+ { sortField, sortOrder, limit: pageSize, cursor },
+ );
} else if (search) {
- const searchResults = await Message.meiliSearch(search, { filter: `user = "${user}"` }, true);
+ const searchResults = await db.searchMessages(search, { filter: `user = "${user}"` }, true);
const messages = searchResults.hits || [];
- const result = await getConvosQueried(req.user.id, messages, cursor);
+ const result = await db.getConvosQueried(req.user.id, messages, cursor);
const messageIds = [];
const cleanedMessages = [];
@@ -79,7 +55,7 @@ router.get('/', async (req, res) => {
}
}
- const dbMessages = await getMessages({
+ const dbMessages = await db.getMessages({
user,
messageId: { $in: messageIds },
});
@@ -136,7 +112,7 @@ router.post('/branch', async (req, res) => {
return res.status(400).json({ error: 'messageId and agentId are required' });
}
- const sourceMessage = await getMessage({ user: userId, messageId });
+ const sourceMessage = await db.getMessage({ user: userId, messageId });
if (!sourceMessage) {
return res.status(404).json({ error: 'Source message not found' });
}
@@ -187,9 +163,15 @@ router.post('/branch', async (req, res) => {
user: userId,
};
- const savedMessage = await saveMessage(req, newMessage, {
- context: 'POST /api/messages/branch',
- });
+ const savedMessage = await db.saveMessage(
+ {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ },
+ newMessage,
+ { context: 'POST /api/messages/branch' },
+ );
if (!savedMessage) {
return res.status(500).json({ error: 'Failed to save branch message' });
@@ -211,7 +193,7 @@ router.post('/artifact/:messageId', async (req, res) => {
return res.status(400).json({ error: 'Invalid request parameters' });
}
- const message = await getMessage({ user: req.user.id, messageId });
+ const message = await db.getMessage({ user: req.user.id, messageId });
if (!message) {
return res.status(404).json({ error: 'Message not found' });
}
@@ -256,8 +238,12 @@ router.post('/artifact/:messageId', async (req, res) => {
return res.status(400).json({ error: 'Original content not found in target artifact' });
}
- const savedMessage = await saveMessage(
- req,
+ const savedMessage = await db.saveMessage(
+ {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ },
{
messageId,
conversationId: message.conversationId,
@@ -283,7 +269,7 @@ router.post('/artifact/:messageId', async (req, res) => {
router.get('/:conversationId', validateMessageReq, async (req, res) => {
try {
const { conversationId } = req.params;
- const messages = await getMessages({ conversationId }, '-_id -__v -user');
+ const messages = await db.getMessages({ conversationId }, '-_id -__v -user');
res.status(200).json(messages);
} catch (error) {
logger.error('Error fetching messages:', error);
@@ -294,15 +280,20 @@ router.get('/:conversationId', validateMessageReq, async (req, res) => {
router.post('/:conversationId', validateMessageReq, async (req, res) => {
try {
const message = req.body;
- const savedMessage = await saveMessage(
- req,
+ const reqCtx = {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ };
+ const savedMessage = await db.saveMessage(
+ reqCtx,
{ ...message, user: req.user.id },
{ context: 'POST /api/messages/:conversationId' },
);
if (!savedMessage) {
return res.status(400).json({ error: 'Message not saved' });
}
- await saveConvo(req, savedMessage, { context: 'POST /api/messages/:conversationId' });
+ await db.saveConvo(reqCtx, savedMessage, { context: 'POST /api/messages/:conversationId' });
res.status(201).json(savedMessage);
} catch (error) {
logger.error('Error saving message:', error);
@@ -313,7 +304,7 @@ router.post('/:conversationId', validateMessageReq, async (req, res) => {
router.get('/:conversationId/:messageId', validateMessageReq, async (req, res) => {
try {
const { conversationId, messageId } = req.params;
- const message = await getMessages({ conversationId, messageId }, '-_id -__v -user');
+ const message = await db.getMessages({ conversationId, messageId }, '-_id -__v -user');
if (!message) {
return res.status(404).json({ error: 'Message not found' });
}
@@ -331,7 +322,7 @@ router.put('/:conversationId/:messageId', validateMessageReq, async (req, res) =
if (index === undefined) {
const tokenCount = await countTokens(text, model);
- const result = await updateMessage(req, { messageId, text, tokenCount });
+ const result = await db.updateMessage(req?.user?.id, { messageId, text, tokenCount });
return res.status(200).json(result);
}
@@ -339,7 +330,9 @@ router.put('/:conversationId/:messageId', validateMessageReq, async (req, res) =
return res.status(400).json({ error: 'Invalid index' });
}
- const message = (await getMessages({ conversationId, messageId }, 'content tokenCount'))?.[0];
+ const message = (
+ await db.getMessages({ conversationId, messageId }, 'content tokenCount')
+ )?.[0];
if (!message) {
return res.status(404).json({ error: 'Message not found' });
}
@@ -369,7 +362,11 @@ router.put('/:conversationId/:messageId', validateMessageReq, async (req, res) =
tokenCount = Math.max(0, tokenCount - oldTokenCount) + newTokenCount;
}
- const result = await updateMessage(req, { messageId, content: updatedContent, tokenCount });
+ const result = await db.updateMessage(req?.user?.id, {
+ messageId,
+ content: updatedContent,
+ tokenCount,
+ });
return res.status(200).json(result);
} catch (error) {
logger.error('Error updating message:', error);
@@ -382,8 +379,8 @@ router.put('/:conversationId/:messageId/feedback', validateMessageReq, async (re
const { conversationId, messageId } = req.params;
const { feedback } = req.body;
- const updatedMessage = await updateMessage(
- req,
+ const updatedMessage = await db.updateMessage(
+ req?.user?.id,
{
messageId,
feedback: feedback || null,
@@ -404,8 +401,8 @@ router.put('/:conversationId/:messageId/feedback', validateMessageReq, async (re
router.delete('/:conversationId/:messageId', validateMessageReq, async (req, res) => {
try {
- const { messageId } = req.params;
- await deleteMessages({ messageId });
+ const { conversationId, messageId } = req.params;
+ await db.deleteMessages({ messageId, conversationId, user: req.user.id });
res.status(204).send();
} catch (error) {
logger.error('Error deleting message:', error);
diff --git a/api/server/routes/oauth.js b/api/server/routes/oauth.js
index f4bb5b6026..5302158031 100644
--- a/api/server/routes/oauth.js
+++ b/api/server/routes/oauth.js
@@ -7,12 +7,13 @@ const { ErrorTypes } = require('librechat-data-provider');
const { createSetBalanceConfig } = require('@librechat/api');
const { checkDomainAllowed, loginLimiter, logHeaders } = require('~/server/middleware');
const { createOAuthHandler } = require('~/server/controllers/auth/oauth');
+const { findBalanceByUser, upsertBalanceFields } = require('~/models');
const { getAppConfig } = require('~/server/services/Config');
-const { Balance } = require('~/db/models');
const setBalanceConfig = createSetBalanceConfig({
getAppConfig,
- Balance,
+ findBalanceByUser,
+ upsertBalanceFields,
});
const router = express.Router();
diff --git a/api/server/routes/prompts.js b/api/server/routes/prompts.js
index 037bf04813..c2e15ac6c0 100644
--- a/api/server/routes/prompts.js
+++ b/api/server/routes/prompts.js
@@ -11,13 +11,13 @@ const {
} = require('@librechat/api');
const {
Permissions,
- SystemRoles,
ResourceType,
AccessRoleIds,
PrincipalType,
PermissionBits,
PermissionTypes,
} = require('librechat-data-provider');
+const { SystemCapabilities } = require('@librechat/data-schemas');
const {
getListPromptGroupsByAccess,
makePromptProduction,
@@ -25,12 +25,14 @@ const {
deletePromptGroup,
createPromptGroup,
getPromptGroup,
+ getRoleByName,
deletePrompt,
getPrompts,
savePrompt,
getPrompt,
-} = require('~/models/Prompt');
+} = require('~/models');
const {
+ hasCapability,
canAccessPromptGroupResource,
canAccessPromptViaGroup,
requireJwtAuth,
@@ -41,7 +43,6 @@ const {
findAccessibleResources,
grantPermission,
} = require('~/server/services/PermissionService');
-const { getRoleByName } = require('~/models/Role');
const router = express.Router();
@@ -56,15 +57,6 @@ const checkPromptCreate = generateCheckAccess({
getRoleByName,
});
-const checkGlobalPromptShare = generateCheckAccess({
- permissionType: PermissionTypes.PROMPTS,
- permissions: [Permissions.USE, Permissions.CREATE],
- bodyProps: {
- [Permissions.SHARE]: ['projectIds', 'removeProjectIds'],
- },
- getRoleByName,
-});
-
router.use(requireJwtAuth);
router.use(checkPromptAccess);
@@ -342,7 +334,14 @@ const patchPromptGroup = async (req, res) => {
const { groupId } = req.params;
const author = req.user.id;
const filter = { _id: groupId, author };
- if (req.user.role === SystemRoles.ADMIN) {
+ let canManagePrompts = false;
+ try {
+ canManagePrompts = await hasCapability(req.user, SystemCapabilities.MANAGE_PROMPTS);
+ } catch (err) {
+ logger.warn(`[patchPromptGroup] capability check failed, denying bypass: ${err.message}`);
+ }
+ if (canManagePrompts) {
+ logger.debug(`[patchPromptGroup] MANAGE_PROMPTS bypass for user ${req.user.id}`);
delete filter.author;
}
@@ -364,7 +363,7 @@ const patchPromptGroup = async (req, res) => {
router.patch(
'/groups/:groupId',
- checkGlobalPromptShare,
+ checkPromptCreate,
canAccessPromptGroupResource({
requiredPermission: PermissionBits.EDIT,
}),
@@ -430,7 +429,14 @@ router.get('/', async (req, res) => {
// If no groupId, return user's own prompts
const query = { author };
- if (req.user.role === SystemRoles.ADMIN) {
+ let canReadPrompts = false;
+ try {
+ canReadPrompts = await hasCapability(req.user, SystemCapabilities.READ_PROMPTS);
+ } catch (err) {
+ logger.warn(`[GET /prompts] capability check failed, denying bypass: ${err.message}`);
+ }
+ if (canReadPrompts) {
+ logger.debug(`[GET /prompts] READ_PROMPTS bypass for user ${req.user.id}`);
delete query.author;
}
const prompts = await getPrompts(query);
@@ -454,8 +460,7 @@ const deletePromptController = async (req, res) => {
try {
const { promptId } = req.params;
const { groupId } = req.query;
- const author = req.user.id;
- const query = { promptId, groupId, author, role: req.user.role };
+ const query = { promptId, groupId };
const result = await deletePrompt(query);
res.status(200).send(result);
} catch (error) {
@@ -473,8 +478,8 @@ const deletePromptController = async (req, res) => {
const deletePromptGroupController = async (req, res) => {
try {
const { groupId: _id } = req.params;
- // Don't pass author - permissions are now checked by middleware
- const message = await deletePromptGroup({ _id, role: req.user.role });
+ // Don't pass author or role - permissions are checked by ACL middleware
+ const message = await deletePromptGroup({ _id });
res.send(message);
} catch (error) {
logger.error('Error deleting prompt group', error);
diff --git a/api/server/routes/prompts.test.js b/api/server/routes/prompts.test.js
index caeb90ddfb..ec162ac1fb 100644
--- a/api/server/routes/prompts.test.js
+++ b/api/server/routes/prompts.test.js
@@ -10,18 +10,33 @@ const {
PrincipalType,
PermissionBits,
} = require('librechat-data-provider');
+const { SystemCapabilities } = require('@librechat/data-schemas');
// Mock modules before importing
jest.mock('~/server/services/Config', () => ({
getCachedTools: jest.fn().mockResolvedValue({}),
}));
-jest.mock('~/models/Role', () => ({
- getRoleByName: jest.fn(),
-}));
+jest.mock('~/models', () => {
+ const mongoose = require('mongoose');
+ const { createMethods } = require('@librechat/data-schemas');
+ const methods = createMethods(mongoose, {
+ removeAllPermissions: async ({ resourceType, resourceId }) => {
+ const AclEntry = mongoose.models.AclEntry;
+ if (AclEntry) {
+ await AclEntry.deleteMany({ resourceType, resourceId });
+ }
+ },
+ });
+ return {
+ ...methods,
+ getRoleByName: jest.fn(),
+ };
+});
jest.mock('~/server/middleware', () => ({
requireJwtAuth: (req, res, next) => next(),
+ hasCapability: jest.requireActual('~/server/middleware').hasCapability,
canAccessPromptViaGroup: jest.requireActual('~/server/middleware').canAccessPromptViaGroup,
canAccessPromptGroupResource:
jest.requireActual('~/server/middleware').canAccessPromptGroupResource,
@@ -30,7 +45,7 @@ jest.mock('~/server/middleware', () => ({
let app;
let mongoServer;
let promptRoutes;
-let Prompt, PromptGroup, AclEntry, AccessRole, User;
+let Prompt, PromptGroup, AclEntry, AccessRole, User, SystemGrant;
let testUsers, testRoles;
let grantPermission;
let currentTestUser; // Track current user for middleware
@@ -52,6 +67,7 @@ beforeAll(async () => {
AclEntry = dbModels.AclEntry;
AccessRole = dbModels.AccessRole;
User = dbModels.User;
+ SystemGrant = dbModels.SystemGrant;
// Import permission service
const permissionService = require('~/server/services/PermissionService');
@@ -152,8 +168,24 @@ async function setupTestData() {
}),
};
+ // Seed capabilities for the ADMIN role
+ await SystemGrant.create([
+ {
+ principalType: PrincipalType.ROLE,
+ principalId: SystemRoles.ADMIN,
+ capability: SystemCapabilities.MANAGE_PROMPTS,
+ grantedAt: new Date(),
+ },
+ {
+ principalType: PrincipalType.ROLE,
+ principalId: SystemRoles.ADMIN,
+ capability: SystemCapabilities.READ_PROMPTS,
+ grantedAt: new Date(),
+ },
+ ]);
+
// Mock getRoleByName
- const { getRoleByName } = require('~/models/Role');
+ const { getRoleByName } = require('~/models');
getRoleByName.mockImplementation((roleName) => {
switch (roleName) {
case SystemRoles.USER:
diff --git a/api/server/routes/roles.js b/api/server/routes/roles.js
index 12e18c7624..1b7e4632e3 100644
--- a/api/server/routes/roles.js
+++ b/api/server/routes/roles.js
@@ -1,4 +1,5 @@
const express = require('express');
+const { logger, SystemCapabilities } = require('@librechat/data-schemas');
const {
SystemRoles,
roleDefaults,
@@ -11,11 +12,12 @@ const {
peoplePickerPermissionsSchema,
remoteAgentsPermissionsSchema,
} = require('librechat-data-provider');
-const { checkAdmin, requireJwtAuth } = require('~/server/middleware');
-const { updateRoleByName, getRoleByName } = require('~/models/Role');
+const { hasCapability, requireCapability, requireJwtAuth } = require('~/server/middleware');
+const { updateRoleByName, getRoleByName } = require('~/models');
const router = express.Router();
router.use(requireJwtAuth);
+const manageRoles = requireCapability(SystemCapabilities.MANAGE_ROLES);
/**
* Permission configuration mapping
@@ -111,14 +113,17 @@ router.get('/:roleName', async (req, res) => {
// TODO: TEMP, use a better parsing for roleName
const roleName = _r.toUpperCase();
- if (
- (req.user.role !== SystemRoles.ADMIN && roleName === SystemRoles.ADMIN) ||
- (req.user.role !== SystemRoles.ADMIN && !roleDefaults[roleName])
- ) {
- return res.status(403).send({ message: 'Unauthorized' });
- }
-
try {
+ let hasReadRoles = false;
+ try {
+ hasReadRoles = await hasCapability(req.user, SystemCapabilities.READ_ROLES);
+ } catch (err) {
+ logger.warn(`[GET /roles/:roleName] capability check failed: ${err.message}`);
+ }
+ if (!hasReadRoles && (roleName === SystemRoles.ADMIN || !roleDefaults[roleName])) {
+ return res.status(403).send({ message: 'Unauthorized' });
+ }
+
const role = await getRoleByName(roleName, '-_id -__v');
if (!role) {
return res.status(404).send({ message: 'Role not found' });
@@ -126,7 +131,8 @@ router.get('/:roleName', async (req, res) => {
res.status(200).send(role);
} catch (error) {
- return res.status(500).send({ message: 'Failed to retrieve role', error: error.message });
+ logger.error('[GET /roles/:roleName] Error:', error);
+ return res.status(500).send({ message: 'Failed to retrieve role' });
}
});
@@ -134,42 +140,42 @@ router.get('/:roleName', async (req, res) => {
* PUT /api/roles/:roleName/prompts
* Update prompt permissions for a specific role
*/
-router.put('/:roleName/prompts', checkAdmin, createPermissionUpdateHandler('prompts'));
+router.put('/:roleName/prompts', manageRoles, createPermissionUpdateHandler('prompts'));
/**
* PUT /api/roles/:roleName/agents
* Update agent permissions for a specific role
*/
-router.put('/:roleName/agents', checkAdmin, createPermissionUpdateHandler('agents'));
+router.put('/:roleName/agents', manageRoles, createPermissionUpdateHandler('agents'));
/**
* PUT /api/roles/:roleName/memories
* Update memory permissions for a specific role
*/
-router.put('/:roleName/memories', checkAdmin, createPermissionUpdateHandler('memories'));
+router.put('/:roleName/memories', manageRoles, createPermissionUpdateHandler('memories'));
/**
* PUT /api/roles/:roleName/people-picker
* Update people picker permissions for a specific role
*/
-router.put('/:roleName/people-picker', checkAdmin, createPermissionUpdateHandler('people-picker'));
+router.put('/:roleName/people-picker', manageRoles, createPermissionUpdateHandler('people-picker'));
/**
* PUT /api/roles/:roleName/mcp-servers
* Update MCP servers permissions for a specific role
*/
-router.put('/:roleName/mcp-servers', checkAdmin, createPermissionUpdateHandler('mcp-servers'));
+router.put('/:roleName/mcp-servers', manageRoles, createPermissionUpdateHandler('mcp-servers'));
/**
* PUT /api/roles/:roleName/marketplace
* Update marketplace permissions for a specific role
*/
-router.put('/:roleName/marketplace', checkAdmin, createPermissionUpdateHandler('marketplace'));
+router.put('/:roleName/marketplace', manageRoles, createPermissionUpdateHandler('marketplace'));
/**
* PUT /api/roles/:roleName/remote-agents
* Update remote agents (API) permissions for a specific role
*/
-router.put('/:roleName/remote-agents', checkAdmin, createPermissionUpdateHandler('remote-agents'));
+router.put('/:roleName/remote-agents', manageRoles, createPermissionUpdateHandler('remote-agents'));
module.exports = router;
diff --git a/api/server/routes/share.js b/api/server/routes/share.js
index 6400b8b637..296644afde 100644
--- a/api/server/routes/share.js
+++ b/api/server/routes/share.js
@@ -19,9 +19,7 @@ const allowSharedLinks =
process.env.ALLOW_SHARED_LINKS === undefined || isEnabled(process.env.ALLOW_SHARED_LINKS);
if (allowSharedLinks) {
- const allowSharedLinksPublic =
- process.env.ALLOW_SHARED_LINKS_PUBLIC === undefined ||
- isEnabled(process.env.ALLOW_SHARED_LINKS_PUBLIC);
+ const allowSharedLinksPublic = isEnabled(process.env.ALLOW_SHARED_LINKS_PUBLIC);
router.get(
'/:shareId',
allowSharedLinksPublic ? (req, res, next) => next() : requireJwtAuth,
diff --git a/api/server/routes/tags.js b/api/server/routes/tags.js
index 0a4ee5084c..a1fa1f77bb 100644
--- a/api/server/routes/tags.js
+++ b/api/server/routes/tags.js
@@ -8,9 +8,9 @@ const {
createConversationTag,
deleteConversationTag,
getConversationTags,
-} = require('~/models/ConversationTag');
+ getRoleByName,
+} = require('~/models');
const { requireJwtAuth } = require('~/server/middleware');
-const { getRoleByName } = require('~/models/Role');
const router = express.Router();
diff --git a/api/server/services/ActionService.js b/api/server/services/ActionService.js
index 5e96726a46..c8ed7bebc4 100644
--- a/api/server/services/ActionService.js
+++ b/api/server/services/ActionService.js
@@ -20,14 +20,20 @@ const {
isImageVisionTool,
actionDomainSeparator,
} = require('librechat-data-provider');
-const { findToken, updateToken, createToken } = require('~/models');
-const { getActions, deleteActions } = require('~/models/Action');
-const { deleteAssistant } = require('~/models/Assistant');
+const {
+ findToken,
+ updateToken,
+ createToken,
+ getActions,
+ deleteActions,
+ deleteAssistant,
+} = require('~/models');
const { getFlowStateManager } = require('~/config');
const { getLogStores } = require('~/cache');
const JWT_SECRET = process.env.JWT_SECRET;
const toolNameRegex = /^[a-zA-Z0-9_-]+$/;
+const protocolRegex = /^https?:\/\//;
const replaceSeparatorRegex = new RegExp(actionDomainSeparator, 'g');
/**
@@ -48,7 +54,11 @@ const validateAndUpdateTool = async ({ req, tool, assistant_id }) => {
actions = await getActions({ assistant_id, user: req.user.id }, true);
const matchingActions = actions.filter((action) => {
const metadata = action.metadata;
- return metadata && metadata.domain === domain;
+ if (!metadata) {
+ return false;
+ }
+ const strippedMetaDomain = stripProtocol(metadata.domain);
+ return strippedMetaDomain === domain || metadata.domain === domain;
});
const action = matchingActions[0];
if (!action) {
@@ -66,10 +76,36 @@ const validateAndUpdateTool = async ({ req, tool, assistant_id }) => {
return tool;
};
+/** @param {string} domain */
+function stripProtocol(domain) {
+ const stripped = domain.replace(protocolRegex, '');
+ const pathIdx = stripped.indexOf('/');
+ return pathIdx === -1 ? stripped : stripped.substring(0, pathIdx);
+}
+
+/**
+ * Encodes a domain using the legacy scheme (full URL including protocol).
+ * Used for backward-compatible matching against agents saved before the collision fix.
+ * @param {string} domain
+ * @returns {string}
+ */
+function legacyDomainEncode(domain) {
+ if (!domain) {
+ return '';
+ }
+ if (domain.length <= Constants.ENCODED_DOMAIN_LENGTH) {
+ return domain.replace(/\./g, actionDomainSeparator);
+ }
+ const modifiedDomain = Buffer.from(domain).toString('base64');
+ return modifiedDomain.substring(0, Constants.ENCODED_DOMAIN_LENGTH);
+}
+
/**
* Encodes or decodes a domain name to/from base64, or replacing periods with a custom separator.
*
* Necessary due to `[a-zA-Z0-9_-]*` Regex Validation, limited to a 64-character maximum.
+ * Strips protocol prefix before encoding to prevent base64 collisions
+ * (all `https://` URLs share the same 10-char base64 prefix).
*
* @param {string} domain - The domain name to encode/decode.
* @param {boolean} inverse - False to decode from base64, true to encode to base64.
@@ -79,23 +115,27 @@ async function domainParser(domain, inverse = false) {
if (!domain) {
return;
}
- const domainsCache = getLogStores(CacheKeys.ENCODED_DOMAINS);
- const cachedDomain = await domainsCache.get(domain);
- if (inverse && cachedDomain) {
- return domain;
- }
- if (inverse && domain.length <= Constants.ENCODED_DOMAIN_LENGTH) {
- return domain.replace(/\./g, actionDomainSeparator);
- }
+ const domainsCache = getLogStores(CacheKeys.ENCODED_DOMAINS);
if (inverse) {
- const modifiedDomain = Buffer.from(domain).toString('base64');
+ const hostname = stripProtocol(domain);
+ const cachedDomain = await domainsCache.get(hostname);
+ if (cachedDomain) {
+ return hostname;
+ }
+
+ if (hostname.length <= Constants.ENCODED_DOMAIN_LENGTH) {
+ return hostname.replace(/\./g, actionDomainSeparator);
+ }
+
+ const modifiedDomain = Buffer.from(hostname).toString('base64');
const key = modifiedDomain.substring(0, Constants.ENCODED_DOMAIN_LENGTH);
await domainsCache.set(key, modifiedDomain);
return key;
}
+ const cachedDomain = await domainsCache.get(domain);
if (!cachedDomain) {
return domain.replace(replaceSeparatorRegex, '.');
}
@@ -456,6 +496,7 @@ const deleteAssistantActions = async ({ req, assistant_id }) => {
module.exports = {
deleteAssistantActions,
validateAndUpdateTool,
+ legacyDomainEncode,
createActionTool,
encryptMetadata,
decryptMetadata,
diff --git a/api/server/services/ActionService.spec.js b/api/server/services/ActionService.spec.js
index c60aef7ad1..42def44b4f 100644
--- a/api/server/services/ActionService.spec.js
+++ b/api/server/services/ActionService.spec.js
@@ -1,175 +1,539 @@
-const { Constants, actionDomainSeparator } = require('librechat-data-provider');
-const { domainParser } = require('./ActionService');
+const { Constants, actionDelimiter, actionDomainSeparator } = require('librechat-data-provider');
+const { domainParser, legacyDomainEncode, validateAndUpdateTool } = require('./ActionService');
jest.mock('keyv');
-const globalCache = {};
+jest.mock('~/models/Action', () => ({
+ getActions: jest.fn(),
+ deleteActions: jest.fn(),
+}));
+
+const { getActions } = require('~/models/Action');
+
+let mockDomainCache = {};
jest.mock('~/cache/getLogStores', () => {
- return jest.fn().mockImplementation(() => {
- const EventEmitter = require('events');
- const { CacheKeys } = require('librechat-data-provider');
+ return jest.fn().mockImplementation(() => ({
+ get: async (key) => mockDomainCache[key] ?? null,
+ set: async (key, value) => {
+ mockDomainCache[key] = value;
+ return true;
+ },
+ }));
+});
- class KeyvMongo extends EventEmitter {
- constructor(url = 'mongodb://127.0.0.1:27017', options) {
- super();
- this.ttlSupport = false;
- url = url ?? {};
- if (typeof url === 'string') {
- url = { url };
- }
- if (url.uri) {
- url = { url: url.uri, ...url };
- }
- this.opts = {
- url,
- collection: 'keyv',
- ...url,
- ...options,
- };
- }
+beforeEach(() => {
+ mockDomainCache = {};
+ getActions.mockReset();
+});
- get = async (key) => {
- return new Promise((resolve) => {
- resolve(globalCache[key] || null);
- });
- };
+const SEP = actionDomainSeparator;
+const DELIM = actionDelimiter;
+const MAX = Constants.ENCODED_DOMAIN_LENGTH;
+const domainSepRegex = new RegExp(SEP, 'g');
- set = async (key, value) => {
- return new Promise((resolve) => {
- globalCache[key] = value;
- resolve(true);
- });
- };
- }
+describe('domainParser', () => {
+ describe('nullish input', () => {
+ it.each([null, undefined, ''])('returns undefined for %j', async (input) => {
+ expect(await domainParser(input, true)).toBeUndefined();
+ expect(await domainParser(input, false)).toBeUndefined();
+ });
+ });
- return new KeyvMongo('', {
- namespace: CacheKeys.ENCODED_DOMAINS,
- ttl: 0,
+ describe('short-path encoding (hostname ≤ threshold)', () => {
+ it.each([
+ ['examp.com', `examp${SEP}com`],
+ ['swapi.tech', `swapi${SEP}tech`],
+ ['a.b', `a${SEP}b`],
+ ])('replaces dots in %s → %s', async (domain, expected) => {
+ expect(await domainParser(domain, true)).toBe(expected);
+ });
+
+ it('handles domain exactly at threshold length', async () => {
+ const domain = 'a'.repeat(MAX - 4) + '.com';
+ expect(domain).toHaveLength(MAX);
+ const result = await domainParser(domain, true);
+ expect(result).toBe(domain.replace(/\./g, SEP));
+ });
+ });
+
+ describe('base64-path encoding (hostname > threshold)', () => {
+ it('produces a key of exactly ENCODED_DOMAIN_LENGTH chars', async () => {
+ const result = await domainParser('api.example.com', true);
+ expect(result).toHaveLength(MAX);
+ });
+
+ it('encodes hostname, not full URL', async () => {
+ const hostname = 'api.example.com';
+ const expectedKey = Buffer.from(hostname).toString('base64').substring(0, MAX);
+ expect(await domainParser(hostname, true)).toBe(expectedKey);
+ });
+
+ it('populates decode cache for round-trip', async () => {
+ const hostname = 'longdomainname.com';
+ const key = await domainParser(hostname, true);
+
+ expect(mockDomainCache[key]).toBe(Buffer.from(hostname).toString('base64'));
+ expect(await domainParser(key, false)).toBe(hostname);
+ });
+ });
+
+ describe('protocol stripping', () => {
+ it('https:// URL and bare hostname produce identical encoding', async () => {
+ const encoded = await domainParser('https://swapi.tech', true);
+ expect(encoded).toBe(await domainParser('swapi.tech', true));
+ expect(encoded).toBe(`swapi${SEP}tech`);
+ });
+
+ it('http:// URL and bare hostname produce identical encoding', async () => {
+ const encoded = await domainParser('http://api.example.com', true);
+ expect(encoded).toBe(await domainParser('api.example.com', true));
+ });
+
+ it('different https:// domains produce unique keys', async () => {
+ const keys = await Promise.all([
+ domainParser('https://api.example.com', true),
+ domainParser('https://api.weather.com', true),
+ domainParser('https://data.github.com', true),
+ ]);
+ const unique = new Set(keys);
+ expect(unique.size).toBe(keys.length);
+ });
+
+ it('long hostname after stripping still uses base64 path', async () => {
+ const result = await domainParser('https://api.example.com', true);
+ expect(result).toHaveLength(MAX);
+ expect(result).not.toContain(SEP);
+ });
+
+ it('short hostname after stripping uses dot-replacement path', async () => {
+ const result = await domainParser('https://a.b.c', true);
+ expect(result).toBe(`a${SEP}b${SEP}c`);
+ });
+
+ it('strips path and query from full URL before encoding', async () => {
+ const result = await domainParser('https://api.example.com/v1/endpoint?foo=bar', true);
+ expect(result).toBe(await domainParser('api.example.com', true));
+ });
+ });
+
+ describe('unicode domains', () => {
+ it('encodes unicode hostname via base64 path', async () => {
+ const domain = 'täst.example.com';
+ const result = await domainParser(domain, true);
+ expect(result).toHaveLength(MAX);
+ expect(result).toBe(Buffer.from(domain).toString('base64').substring(0, MAX));
+ });
+
+ it('round-trips unicode hostname through encode then decode', async () => {
+ const domain = 'täst.example.com';
+ const key = await domainParser(domain, true);
+ expect(await domainParser(key, false)).toBe(domain);
+ });
+
+ it('strips protocol before encoding unicode hostname', async () => {
+ const withProto = 'https://täst.example.com';
+ const bare = 'täst.example.com';
+ expect(await domainParser(withProto, true)).toBe(await domainParser(bare, true));
+ });
+ });
+
+ describe('decode path', () => {
+ it('short-path encoded domain decodes via separator replacement', async () => {
+ expect(await domainParser(`examp${SEP}com`, false)).toBe('examp.com');
+ });
+
+ it('base64-path encoded domain decodes via cache lookup', async () => {
+ const hostname = 'api.example.com';
+ const key = await domainParser(hostname, true);
+ expect(await domainParser(key, false)).toBe(hostname);
+ });
+
+ it('returns input unchanged for unknown non-separator strings', async () => {
+ expect(await domainParser('not_base64_encoded', false)).toBe('not_base64_encoded');
+ });
+
+ it('returns a string without throwing for corrupt cache entries', async () => {
+ mockDomainCache['corrupt_key'] = '!!!';
+ const result = await domainParser('corrupt_key', false);
+ expect(typeof result).toBe('string');
});
});
});
-describe('domainParser', () => {
- const TLD = '.com';
-
- // Non-azure request
- it('does not return domain as is if not azure', async () => {
- const domain = `example.com${actionDomainSeparator}test${actionDomainSeparator}`;
- const result1 = await domainParser(domain, false);
- const result2 = await domainParser(domain, true);
- expect(result1).not.toEqual(domain);
- expect(result2).not.toEqual(domain);
+describe('legacyDomainEncode', () => {
+ it.each(['', null, undefined])('returns empty string for %j', (input) => {
+ expect(legacyDomainEncode(input)).toBe('');
});
- // Test for Empty or Null Inputs
- it('returns undefined for null domain input', async () => {
- const result = await domainParser(null, true);
- expect(result).toBeUndefined();
+ it('is synchronous (returns a string, not a Promise)', () => {
+ const result = legacyDomainEncode('examp.com');
+ expect(result).toBe(`examp${SEP}com`);
+ expect(result).not.toBeInstanceOf(Promise);
});
- it('returns undefined for empty domain input', async () => {
- const result = await domainParser('', true);
- expect(result).toBeUndefined();
+ it('uses dot-replacement for short domains', () => {
+ expect(legacyDomainEncode('examp.com')).toBe(`examp${SEP}com`);
});
- // Verify Correct Caching Behavior
- it('caches encoded domain correctly', async () => {
- const domain = 'longdomainname.com';
- const encodedDomain = Buffer.from(domain)
- .toString('base64')
- .substring(0, Constants.ENCODED_DOMAIN_LENGTH);
-
- await domainParser(domain, true);
-
- const cachedValue = await globalCache[encodedDomain];
- expect(cachedValue).toEqual(Buffer.from(domain).toString('base64'));
+ it('uses base64 prefix of full input for long domains', () => {
+ const domain = 'https://swapi.tech';
+ const expected = Buffer.from(domain).toString('base64').substring(0, MAX);
+ expect(legacyDomainEncode(domain)).toBe(expected);
});
- // Test for Edge Cases Around Length Threshold
- it('encodes domain exactly at threshold without modification', async () => {
- const domain = 'a'.repeat(Constants.ENCODED_DOMAIN_LENGTH - TLD.length) + TLD;
- const expected = domain.replace(/\./g, actionDomainSeparator);
- const result = await domainParser(domain, true);
- expect(result).toEqual(expected);
+ it('all https:// URLs collide to the same key', () => {
+ const results = [
+ legacyDomainEncode('https://api.example.com'),
+ legacyDomainEncode('https://api.weather.com'),
+ legacyDomainEncode('https://totally.different.host'),
+ ];
+ expect(new Set(results).size).toBe(1);
});
- it('encodes domain just below threshold without modification', async () => {
- const domain = 'a'.repeat(Constants.ENCODED_DOMAIN_LENGTH - 1 - TLD.length) + TLD;
- const expected = domain.replace(/\./g, actionDomainSeparator);
- const result = await domainParser(domain, true);
- expect(result).toEqual(expected);
+ it('matches what old domainParser would have produced', () => {
+ const domain = 'https://api.example.com';
+ const legacy = legacyDomainEncode(domain);
+ expect(legacy).toBe(Buffer.from(domain).toString('base64').substring(0, MAX));
});
- // Test for Unicode Domain Names
- it('handles unicode characters in domain names correctly when encoding', async () => {
- const unicodeDomain = 'täst.example.com';
- const encodedDomain = Buffer.from(unicodeDomain)
- .toString('base64')
- .substring(0, Constants.ENCODED_DOMAIN_LENGTH);
- const result = await domainParser(unicodeDomain, true);
- expect(result).toEqual(encodedDomain);
- });
-
- it('decodes unicode domain names correctly', async () => {
- const unicodeDomain = 'täst.example.com';
- const encodedDomain = Buffer.from(unicodeDomain).toString('base64');
- globalCache[encodedDomain.substring(0, Constants.ENCODED_DOMAIN_LENGTH)] = encodedDomain; // Simulate caching
-
- const result = await domainParser(
- encodedDomain.substring(0, Constants.ENCODED_DOMAIN_LENGTH),
- false,
- );
- expect(result).toEqual(unicodeDomain);
- });
-
- // Core Functionality Tests
- it('returns domain with replaced separators if no cached domain exists', async () => {
- const domain = 'example.com';
- const withSeparator = domain.replace(/\./g, actionDomainSeparator);
- const result = await domainParser(withSeparator, false);
- expect(result).toEqual(domain);
- });
-
- it('returns domain with replaced separators when inverse is false and under encoding length', async () => {
- const domain = 'examp.com';
- const withSeparator = domain.replace(/\./g, actionDomainSeparator);
- const result = await domainParser(withSeparator, false);
- expect(result).toEqual(domain);
- });
-
- it('replaces periods with actionDomainSeparator when inverse is true and under encoding length', async () => {
- const domain = 'examp.com';
- const expected = domain.replace(/\./g, actionDomainSeparator);
- const result = await domainParser(domain, true);
- expect(result).toEqual(expected);
- });
-
- it('encodes domain when length is above threshold and inverse is true', async () => {
- const domain = 'a'.repeat(Constants.ENCODED_DOMAIN_LENGTH + 1).concat('.com');
- const result = await domainParser(domain, true);
- expect(result).not.toEqual(domain);
- expect(result.length).toBeLessThanOrEqual(Constants.ENCODED_DOMAIN_LENGTH);
- });
-
- it('returns encoded value if no encoded value is cached, and inverse is false', async () => {
- const originalDomain = 'example.com';
- const encodedDomain = Buffer.from(
- originalDomain.replace(/\./g, actionDomainSeparator),
- ).toString('base64');
- const result = await domainParser(encodedDomain, false);
- expect(result).toEqual(encodedDomain);
- });
-
- it('decodes encoded value if cached and encoded value is provided, and inverse is false', async () => {
- const originalDomain = 'example.com';
- const encodedDomain = await domainParser(originalDomain, true);
- const result = await domainParser(encodedDomain, false);
- expect(result).toEqual(originalDomain);
- });
-
- it('handles invalid base64 encoded values gracefully', async () => {
- const invalidBase64Domain = 'not_base64_encoded';
- const result = await domainParser(invalidBase64Domain, false);
- expect(result).toEqual(invalidBase64Domain);
+ it('produces same result as new domainParser for short bare hostnames', async () => {
+ const domain = 'swapi.tech';
+ expect(legacyDomainEncode(domain)).toBe(await domainParser(domain, true));
+ });
+});
+
+describe('validateAndUpdateTool', () => {
+ const mockReq = { user: { id: 'user123' } };
+
+ it('returns tool unchanged when name passes tool-name regex', async () => {
+ const tool = { function: { name: 'getPeople_action_swapi---tech' } };
+ const result = await validateAndUpdateTool({
+ req: mockReq,
+ tool,
+ assistant_id: 'asst_1',
+ });
+ expect(result).toEqual(tool);
+ expect(getActions).not.toHaveBeenCalled();
+ });
+
+ it('matches action when metadata.domain has https:// prefix and tool domain is bare hostname', async () => {
+ getActions.mockResolvedValue([{ metadata: { domain: 'https://api.example.com' } }]);
+
+ const tool = { function: { name: `getPeople${DELIM}api.example.com` } };
+ const result = await validateAndUpdateTool({
+ req: mockReq,
+ tool,
+ assistant_id: 'asst_1',
+ });
+
+ expect(result).not.toBeNull();
+ expect(result.function.name).toMatch(/^getPeople_action_/);
+ expect(result.function.name).not.toContain('.');
+ });
+
+ it('matches action when metadata.domain has no protocol', async () => {
+ getActions.mockResolvedValue([{ metadata: { domain: 'api.example.com' } }]);
+
+ const tool = { function: { name: `getPeople${DELIM}api.example.com` } };
+ const result = await validateAndUpdateTool({
+ req: mockReq,
+ tool,
+ assistant_id: 'asst_1',
+ });
+
+ expect(result).not.toBeNull();
+ expect(result.function.name).toMatch(/^getPeople_action_/);
+ });
+
+ it('returns null when no action matches the domain', async () => {
+ getActions.mockResolvedValue([{ metadata: { domain: 'https://other.domain.com' } }]);
+
+ const tool = { function: { name: `getPeople${DELIM}api.example.com` } };
+ const result = await validateAndUpdateTool({
+ req: mockReq,
+ tool,
+ assistant_id: 'asst_1',
+ });
+
+ expect(result).toBeNull();
+ });
+
+ it('returns null when action has no metadata', async () => {
+ getActions.mockResolvedValue([{ metadata: null }]);
+
+ const tool = { function: { name: `getPeople${DELIM}api.example.com` } };
+ const result = await validateAndUpdateTool({
+ req: mockReq,
+ tool,
+ assistant_id: 'asst_1',
+ });
+
+ expect(result).toBeNull();
+ });
+});
+
+describe('backward-compatible tool name matching', () => {
+ function normalizeToolName(name) {
+ return name.replace(domainSepRegex, '_');
+ }
+
+ function buildToolName(functionName, encodedDomain) {
+ return `${functionName}${DELIM}${encodedDomain}`;
+ }
+
+ describe('definition-phase matching', () => {
+ it('new encoding matches agent tools stored with new encoding', async () => {
+ const metadataDomain = 'https://swapi.tech';
+ const encoded = await domainParser(metadataDomain, true);
+ const normalized = normalizeToolName(encoded);
+
+ const storedTool = buildToolName('getPeople', encoded);
+ const defToolName = `getPeople${DELIM}${normalized}`;
+
+ expect(normalizeToolName(storedTool)).toBe(defToolName);
+ });
+
+ it('legacy encoding matches agent tools stored with legacy encoding', async () => {
+ const metadataDomain = 'https://swapi.tech';
+ const legacy = legacyDomainEncode(metadataDomain);
+ const legacyNormalized = normalizeToolName(legacy);
+
+ const storedTool = buildToolName('getPeople', legacy);
+ const legacyDefName = `getPeople${DELIM}${legacyNormalized}`;
+
+ expect(normalizeToolName(storedTool)).toBe(legacyDefName);
+ });
+
+ it('new definition matches old stored tools via legacy fallback', async () => {
+ const metadataDomain = 'https://swapi.tech';
+ const newDomain = await domainParser(metadataDomain, true);
+ const legacyDomain = legacyDomainEncode(metadataDomain);
+ const newNorm = normalizeToolName(newDomain);
+ const legacyNorm = normalizeToolName(legacyDomain);
+
+ const oldStoredTool = buildToolName('getPeople', legacyDomain);
+ const newToolName = `getPeople${DELIM}${newNorm}`;
+ const legacyToolName = `getPeople${DELIM}${legacyNorm}`;
+
+ const storedNormalized = normalizeToolName(oldStoredTool);
+ const hasMatch = storedNormalized === newToolName || storedNormalized === legacyToolName;
+ expect(hasMatch).toBe(true);
+ });
+
+ it('pre-normalized Set eliminates per-tool normalization', async () => {
+ const metadataDomain = 'https://api.example.com';
+ const domain = await domainParser(metadataDomain, true);
+ const legacyDomain = legacyDomainEncode(metadataDomain);
+ const normalizedDomain = normalizeToolName(domain);
+ const legacyNormalized = normalizeToolName(legacyDomain);
+
+ const storedTools = [
+ buildToolName('getWeather', legacyDomain),
+ buildToolName('getForecast', domain),
+ ];
+
+ const preNormalized = new Set(storedTools.map((t) => normalizeToolName(t)));
+
+ const toolName = `getWeather${DELIM}${normalizedDomain}`;
+ const legacyToolName = `getWeather${DELIM}${legacyNormalized}`;
+ expect(preNormalized.has(toolName) || preNormalized.has(legacyToolName)).toBe(true);
+ });
+ });
+
+ describe('execution-phase tool lookup', () => {
+ it('model-called tool name resolves via normalizedToDomain map (new encoding)', async () => {
+ const metadataDomain = 'https://api.example.com';
+ const domain = await domainParser(metadataDomain, true);
+ const normalized = normalizeToolName(domain);
+
+ const normalizedToDomain = new Map();
+ normalizedToDomain.set(normalized, domain);
+
+ const modelToolName = `getWeather${DELIM}${normalized}`;
+
+ let matched = '';
+ for (const [norm, canonical] of normalizedToDomain.entries()) {
+ if (modelToolName.includes(norm)) {
+ matched = canonical;
+ break;
+ }
+ }
+
+ expect(matched).toBe(domain);
+
+ const functionName = modelToolName.replace(`${DELIM}${normalizeToolName(matched)}`, '');
+ expect(functionName).toBe('getWeather');
+ });
+
+ it('model-called tool name resolves via legacy entry in normalizedToDomain map', async () => {
+ const metadataDomain = 'https://api.example.com';
+ const domain = await domainParser(metadataDomain, true);
+ const legacyDomain = legacyDomainEncode(metadataDomain);
+ const legacyNorm = normalizeToolName(legacyDomain);
+
+ const normalizedToDomain = new Map();
+ normalizedToDomain.set(normalizeToolName(domain), domain);
+ normalizedToDomain.set(legacyNorm, domain);
+
+ const legacyModelToolName = `getWeather${DELIM}${legacyNorm}`;
+
+ let matched = '';
+ for (const [norm, canonical] of normalizedToDomain.entries()) {
+ if (legacyModelToolName.includes(norm)) {
+ matched = canonical;
+ break;
+ }
+ }
+
+ expect(matched).toBe(domain);
+ });
+
+ it('legacy guard skips duplicate map entry for short bare hostnames', async () => {
+ const domain = 'swapi.tech';
+ const newEncoding = await domainParser(domain, true);
+ const legacyEncoding = legacyDomainEncode(domain);
+
+ expect(newEncoding).toBe(legacyEncoding);
+
+ const normalizedToDomain = new Map();
+ normalizedToDomain.set(newEncoding, newEncoding);
+ if (legacyEncoding !== newEncoding) {
+ normalizedToDomain.set(legacyEncoding, newEncoding);
+ }
+ expect(normalizedToDomain.size).toBe(1);
+ });
+ });
+
+ describe('processRequiredActions matching (assistants path)', () => {
+ it('legacy tool from OpenAI matches via normalizedToDomain with both encodings', async () => {
+ const metadataDomain = 'https://swapi.tech';
+ const domain = await domainParser(metadataDomain, true);
+ const legacyDomain = legacyDomainEncode(metadataDomain);
+
+ const normalizedToDomain = new Map();
+ normalizedToDomain.set(domain, domain);
+ if (legacyDomain !== domain) {
+ normalizedToDomain.set(legacyDomain, domain);
+ }
+
+ const legacyToolName = buildToolName('getPeople', legacyDomain);
+
+ let currentDomain = '';
+ let matchedKey = '';
+ for (const [key, canonical] of normalizedToDomain.entries()) {
+ if (legacyToolName.includes(key)) {
+ currentDomain = canonical;
+ matchedKey = key;
+ break;
+ }
+ }
+
+ expect(currentDomain).toBe(domain);
+ expect(matchedKey).toBe(legacyDomain);
+
+ const functionName = legacyToolName.replace(`${DELIM}${matchedKey}`, '');
+ expect(functionName).toBe('getPeople');
+ });
+
+ it('new tool name matches via the canonical domain key', async () => {
+ const metadataDomain = 'https://swapi.tech';
+ const domain = await domainParser(metadataDomain, true);
+ const legacyDomain = legacyDomainEncode(metadataDomain);
+
+ const normalizedToDomain = new Map();
+ normalizedToDomain.set(domain, domain);
+ if (legacyDomain !== domain) {
+ normalizedToDomain.set(legacyDomain, domain);
+ }
+
+ const newToolName = buildToolName('getPeople', domain);
+
+ let currentDomain = '';
+ let matchedKey = '';
+ for (const [key, canonical] of normalizedToDomain.entries()) {
+ if (newToolName.includes(key)) {
+ currentDomain = canonical;
+ matchedKey = key;
+ break;
+ }
+ }
+
+ expect(currentDomain).toBe(domain);
+ expect(matchedKey).toBe(domain);
+
+ const functionName = newToolName.replace(`${DELIM}${matchedKey}`, '');
+ expect(functionName).toBe('getPeople');
+ });
+ });
+
+ describe('save-route cleanup', () => {
+ it('tool filter removes tools matching new encoding', async () => {
+ const metadataDomain = 'https://swapi.tech';
+ const domain = await domainParser(metadataDomain, true);
+ const legacyDomain = legacyDomainEncode(metadataDomain);
+
+ const tools = [
+ buildToolName('getPeople', domain),
+ buildToolName('unrelated', 'other---domain'),
+ ];
+
+ const filtered = tools.filter((t) => !t.includes(domain) && !t.includes(legacyDomain));
+
+ expect(filtered).toEqual([buildToolName('unrelated', 'other---domain')]);
+ });
+
+ it('tool filter removes tools matching legacy encoding', async () => {
+ const metadataDomain = 'https://swapi.tech';
+ const domain = await domainParser(metadataDomain, true);
+ const legacyDomain = legacyDomainEncode(metadataDomain);
+
+ const tools = [
+ buildToolName('getPeople', legacyDomain),
+ buildToolName('unrelated', 'other---domain'),
+ ];
+
+ const filtered = tools.filter((t) => !t.includes(domain) && !t.includes(legacyDomain));
+
+ expect(filtered).toEqual([buildToolName('unrelated', 'other---domain')]);
+ });
+ });
+
+ describe('delete-route domain extraction', () => {
+ it('domain extracted from actions array is usable as-is for tool filtering', async () => {
+ const metadataDomain = 'https://api.example.com';
+ const domain = await domainParser(metadataDomain, true);
+ const actionId = 'abc123';
+ const actionEntry = `${domain}${DELIM}${actionId}`;
+
+ const [storedDomain] = actionEntry.split(DELIM);
+ expect(storedDomain).toBe(domain);
+
+ const tools = [buildToolName('getWeather', domain), buildToolName('getPeople', 'other')];
+
+ const filtered = tools.filter((t) => !t.includes(storedDomain));
+ expect(filtered).toEqual([buildToolName('getPeople', 'other')]);
+ });
+ });
+
+ describe('multi-action agents (collision scenario)', () => {
+ it('two https:// actions now produce distinct tool names', async () => {
+ const domain1 = await domainParser('https://api.weather.com', true);
+ const domain2 = await domainParser('https://api.spacex.com', true);
+
+ const tool1 = buildToolName('getData', domain1);
+ const tool2 = buildToolName('getData', domain2);
+
+ expect(tool1).not.toBe(tool2);
+ });
+
+ it('two https:// actions used to collide in legacy encoding', () => {
+ const legacy1 = legacyDomainEncode('https://api.weather.com');
+ const legacy2 = legacyDomainEncode('https://api.spacex.com');
+
+ const tool1 = buildToolName('getData', legacy1);
+ const tool2 = buildToolName('getData', legacy2);
+
+ expect(tool1).toBe(tool2);
+ });
});
});
diff --git a/api/server/services/AuthService.js b/api/server/services/AuthService.js
index 1b4b653c1a..ef50a365b9 100644
--- a/api/server/services/AuthService.js
+++ b/api/server/services/AuthService.js
@@ -462,6 +462,22 @@ const setOpenIDAuthTokens = (tokenset, req, res, userId, existingRefreshToken) =
*/
const appAuthToken = tokenset.id_token || tokenset.access_token;
+ /**
+ * Always set refresh token cookie so it survives express session expiry.
+ * The session cookie maxAge (SESSION_EXPIRY, default 15 min) is typically shorter
+ * than the OIDC token lifetime (~1 hour). Without this cookie fallback, the refresh
+ * token stored only in the session is lost when the session expires, causing the user
+ * to be signed out on the next token refresh attempt.
+ * The refresh token is small (opaque string) so it doesn't hit the HTTP/2 header
+ * size limits that motivated session storage for the larger access_token/id_token.
+ */
+ res.cookie('refreshToken', refreshToken, {
+ expires: expirationDate,
+ httpOnly: true,
+ secure: shouldUseSecureCookie(),
+ sameSite: 'strict',
+ });
+
/** Store tokens server-side in session to avoid large cookies */
if (req.session) {
req.session.openidTokens = {
@@ -472,12 +488,6 @@ const setOpenIDAuthTokens = (tokenset, req, res, userId, existingRefreshToken) =
};
} else {
logger.warn('[setOpenIDAuthTokens] No session available, falling back to cookies');
- res.cookie('refreshToken', refreshToken, {
- expires: expirationDate,
- httpOnly: true,
- secure: shouldUseSecureCookie(),
- sameSite: 'strict',
- });
res.cookie('openid_access_token', tokenset.access_token, {
expires: expirationDate,
httpOnly: true,
diff --git a/api/server/services/Endpoints/agents/addedConvo.js b/api/server/services/Endpoints/agents/addedConvo.js
index 7e9385267a..7561053f8f 100644
--- a/api/server/services/Endpoints/agents/addedConvo.js
+++ b/api/server/services/Endpoints/agents/addedConvo.js
@@ -1,12 +1,16 @@
const { logger } = require('@librechat/data-schemas');
-const { initializeAgent, validateAgentModel } = require('@librechat/api');
-const { loadAddedAgent, setGetAgent, ADDED_AGENT_ID } = require('~/models/loadAddedAgent');
-const { getConvoFiles } = require('~/models/Conversation');
-const { getAgent } = require('~/models/Agent');
+const {
+ ADDED_AGENT_ID,
+ initializeAgent,
+ validateAgentModel,
+ loadAddedAgent: loadAddedAgentFn,
+} = require('@librechat/api');
+const { filterFilesByAgentAccess } = require('~/server/services/Files/permissions');
+const { getMCPServerTools } = require('~/server/services/Config');
const db = require('~/models');
-// Initialize the getAgent dependency
-setGetAgent(getAgent);
+const loadAddedAgent = (params) =>
+ loadAddedAgentFn(params, { getAgent: db.getAgent, getMCPServerTools });
/**
* Process addedConvo for parallel agent execution.
@@ -55,16 +59,16 @@ const processAddedConvo = async ({
userMCPAuthMap,
}) => {
const addedConvo = endpointOption.addedConvo;
- logger.debug('[processAddedConvo] Called with addedConvo:', {
- hasAddedConvo: addedConvo != null,
- addedConvoEndpoint: addedConvo?.endpoint,
- addedConvoModel: addedConvo?.model,
- addedConvoAgentId: addedConvo?.agent_id,
- });
if (addedConvo == null) {
return { userMCPAuthMap };
}
+ logger.debug('[processAddedConvo] Processing added conversation', {
+ model: addedConvo.model,
+ agentId: addedConvo.agent_id,
+ endpoint: addedConvo.endpoint,
+ });
+
try {
const addedAgent = await loadAddedAgent({ req, conversation: addedConvo, primaryAgent });
if (!addedAgent) {
@@ -99,15 +103,16 @@ const processAddedConvo = async ({
allowedProviders,
},
{
- getConvoFiles,
getFiles: db.getFiles,
getUserKey: db.getUserKey,
getMessages: db.getMessages,
+ getConvoFiles: db.getConvoFiles,
updateFilesUsage: db.updateFilesUsage,
getUserCodeFiles: db.getUserCodeFiles,
getUserKeyValues: db.getUserKeyValues,
getToolFilesByIds: db.getToolFilesByIds,
getCodeGeneratedFiles: db.getCodeGeneratedFiles,
+ filterFilesByAgentAccess,
},
);
diff --git a/api/server/services/Endpoints/agents/build.js b/api/server/services/Endpoints/agents/build.js
index a95640e528..19ae3ab7e8 100644
--- a/api/server/services/Endpoints/agents/build.js
+++ b/api/server/services/Endpoints/agents/build.js
@@ -1,6 +1,10 @@
const { logger } = require('@librechat/data-schemas');
+const { loadAgent: loadAgentFn } = require('@librechat/api');
const { isAgentsEndpoint, removeNullishValues, Constants } = require('librechat-data-provider');
-const { loadAgent } = require('~/models/Agent');
+const { getMCPServerTools } = require('~/server/services/Config');
+const db = require('~/models');
+
+const loadAgent = (params) => loadAgentFn(params, { getAgent: db.getAgent, getMCPServerTools });
const buildOptions = (req, endpoint, parsedBody, endpointType) => {
const { spec, iconURL, agent_id, ...model_parameters } = parsedBody;
diff --git a/api/server/services/Endpoints/agents/initialize.js b/api/server/services/Endpoints/agents/initialize.js
index 0888f23cd5..28282e68ea 100644
--- a/api/server/services/Endpoints/agents/initialize.js
+++ b/api/server/services/Endpoints/agents/initialize.js
@@ -10,6 +10,8 @@ const {
createSequentialChainEdges,
} = require('@librechat/api');
const {
+ ResourceType,
+ PermissionBits,
EModelEndpoint,
isAgentsEndpoint,
getResponseSender,
@@ -20,11 +22,11 @@ const {
getDefaultHandlers,
} = require('~/server/controllers/agents/callbacks');
const { loadAgentTools, loadToolsForExecution } = require('~/server/services/ToolService');
+const { filterFilesByAgentAccess } = require('~/server/services/Files/permissions');
const { getModelsConfig } = require('~/server/controllers/ModelController');
+const { checkPermission } = require('~/server/services/PermissionService');
const AgentClient = require('~/server/controllers/agents/client');
-const { getConvoFiles } = require('~/models/Conversation');
const { processAddedConvo } = require('./addedConvo');
-const { getAgent } = require('~/models/Agent');
const { logViolation } = require('~/cache');
const db = require('~/models');
@@ -125,6 +127,7 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
toolRegistry: ctx.toolRegistry,
userMCPAuthMap: ctx.userMCPAuthMap,
tool_resources: ctx.tool_resources,
+ actionsEnabled: ctx.actionsEnabled,
});
logger.debug(`[ON_TOOL_EXECUTE] loaded ${result.loadedTools?.length ?? 0} tools`);
@@ -191,32 +194,28 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
isInitialAgent: true,
},
{
- getConvoFiles,
getFiles: db.getFiles,
getUserKey: db.getUserKey,
getMessages: db.getMessages,
+ getConvoFiles: db.getConvoFiles,
updateFilesUsage: db.updateFilesUsage,
getUserKeyValues: db.getUserKeyValues,
getUserCodeFiles: db.getUserCodeFiles,
getToolFilesByIds: db.getToolFilesByIds,
getCodeGeneratedFiles: db.getCodeGeneratedFiles,
+ filterFilesByAgentAccess,
},
);
logger.debug(
- `[initializeClient] Tool definitions for primary agent: ${primaryConfig.toolDefinitions?.length ?? 0}`,
- );
-
- /** Store primary agent's tool context for ON_TOOL_EXECUTE callback */
- logger.debug(`[initializeClient] Storing tool context for agentId: ${primaryConfig.id}`);
- logger.debug(
- `[initializeClient] toolRegistry size: ${primaryConfig.toolRegistry?.size ?? 'undefined'}`,
+ `[initializeClient] Storing tool context for ${primaryConfig.id}: ${primaryConfig.toolDefinitions?.length ?? 0} tools, registry size: ${primaryConfig.toolRegistry?.size ?? '0'}`,
);
agentToolContexts.set(primaryConfig.id, {
agent: primaryAgent,
toolRegistry: primaryConfig.toolRegistry,
userMCPAuthMap: primaryConfig.userMCPAuthMap,
tool_resources: primaryConfig.tool_resources,
+ actionsEnabled: primaryConfig.actionsEnabled,
});
const agent_ids = primaryConfig.agent_ids;
@@ -226,7 +225,7 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
const skippedAgentIds = new Set();
async function processAgent(agentId) {
- const agent = await getAgent({ id: agentId });
+ const agent = await db.getAgent({ id: agentId });
if (!agent) {
logger.warn(
`[processAgent] Handoff agent ${agentId} not found, skipping (orphaned reference)`,
@@ -235,6 +234,22 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
return null;
}
+ const hasAccess = await checkPermission({
+ userId: req.user.id,
+ role: req.user.role,
+ resourceType: ResourceType.AGENT,
+ resourceId: agent._id,
+ requiredPermission: PermissionBits.VIEW,
+ });
+
+ if (!hasAccess) {
+ logger.warn(
+ `[processAgent] User ${req.user.id} lacks VIEW access to handoff agent ${agentId}, skipping`,
+ );
+ skippedAgentIds.add(agentId);
+ return null;
+ }
+
const validationResult = await validateAgentModel({
req,
res,
@@ -260,15 +275,16 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
allowedProviders,
},
{
- getConvoFiles,
getFiles: db.getFiles,
getUserKey: db.getUserKey,
getMessages: db.getMessages,
+ getConvoFiles: db.getConvoFiles,
updateFilesUsage: db.updateFilesUsage,
getUserKeyValues: db.getUserKeyValues,
getUserCodeFiles: db.getUserCodeFiles,
getToolFilesByIds: db.getToolFilesByIds,
getCodeGeneratedFiles: db.getCodeGeneratedFiles,
+ filterFilesByAgentAccess,
},
);
@@ -284,6 +300,7 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
toolRegistry: config.toolRegistry,
userMCPAuthMap: config.userMCPAuthMap,
tool_resources: config.tool_resources,
+ actionsEnabled: config.actionsEnabled,
});
agentConfigs.set(agentId, config);
@@ -312,6 +329,7 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
}
} catch (err) {
logger.error(`[initializeClient] Error processing agent ${agentId}:`, err);
+ skippedAgentIds.add(agentId);
}
}
@@ -321,7 +339,12 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
if (checkAgentInit(agentId)) {
continue;
}
- await processAgent(agentId);
+ try {
+ await processAgent(agentId);
+ } catch (err) {
+ logger.error(`[initializeClient] Error processing chain agent ${agentId}:`, err);
+ skippedAgentIds.add(agentId);
+ }
}
const chain = await createSequentialChainEdges([primaryConfig.id].concat(agent_ids), '{convo}');
collectEdges(chain);
@@ -351,6 +374,19 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
userMCPAuthMap = updatedMCPAuthMap;
}
+ for (const [agentId, config] of agentConfigs) {
+ if (agentToolContexts.has(agentId)) {
+ continue;
+ }
+ agentToolContexts.set(agentId, {
+ agent: config,
+ toolRegistry: config.toolRegistry,
+ userMCPAuthMap: config.userMCPAuthMap,
+ tool_resources: config.tool_resources,
+ actionsEnabled: config.actionsEnabled,
+ });
+ }
+
// Ensure edges is an array when we have multiple agents (multi-agent mode)
// MultiAgentGraph.categorizeEdges requires edges to be iterable
if (agentConfigs.size > 0 && !edges) {
diff --git a/api/server/services/Endpoints/agents/initialize.spec.js b/api/server/services/Endpoints/agents/initialize.spec.js
new file mode 100644
index 0000000000..8027744965
--- /dev/null
+++ b/api/server/services/Endpoints/agents/initialize.spec.js
@@ -0,0 +1,201 @@
+const mongoose = require('mongoose');
+const {
+ ResourceType,
+ PermissionBits,
+ PrincipalType,
+ PrincipalModel,
+} = require('librechat-data-provider');
+const { MongoMemoryServer } = require('mongodb-memory-server');
+
+const mockInitializeAgent = jest.fn();
+const mockValidateAgentModel = jest.fn();
+
+jest.mock('@librechat/agents', () => ({
+ ...jest.requireActual('@librechat/agents'),
+ createContentAggregator: jest.fn(() => ({
+ contentParts: [],
+ aggregateContent: jest.fn(),
+ })),
+}));
+
+jest.mock('@librechat/api', () => ({
+ ...jest.requireActual('@librechat/api'),
+ initializeAgent: (...args) => mockInitializeAgent(...args),
+ validateAgentModel: (...args) => mockValidateAgentModel(...args),
+ GenerationJobManager: { setCollectedUsage: jest.fn() },
+ getCustomEndpointConfig: jest.fn(),
+ createSequentialChainEdges: jest.fn(),
+}));
+
+jest.mock('~/server/controllers/agents/callbacks', () => ({
+ createToolEndCallback: jest.fn(() => jest.fn()),
+ getDefaultHandlers: jest.fn(() => ({})),
+}));
+
+jest.mock('~/server/services/ToolService', () => ({
+ loadAgentTools: jest.fn(),
+ loadToolsForExecution: jest.fn(),
+}));
+
+jest.mock('~/server/controllers/ModelController', () => ({
+ getModelsConfig: jest.fn().mockResolvedValue({}),
+}));
+
+let agentClientArgs;
+jest.mock('~/server/controllers/agents/client', () => {
+ return jest.fn().mockImplementation((args) => {
+ agentClientArgs = args;
+ return {};
+ });
+});
+
+jest.mock('./addedConvo', () => ({
+ processAddedConvo: jest.fn().mockResolvedValue({ userMCPAuthMap: undefined }),
+}));
+
+jest.mock('~/cache', () => ({
+ logViolation: jest.fn(),
+}));
+
+const { initializeClient } = require('./initialize');
+const { User, AclEntry } = require('~/db/models');
+const { createAgent } = require('~/models');
+
+const PRIMARY_ID = 'agent_primary';
+const TARGET_ID = 'agent_target';
+const AUTHORIZED_ID = 'agent_authorized';
+
+describe('initializeClient — processAgent ACL gate', () => {
+ let mongoServer;
+ let testUser;
+
+ beforeAll(async () => {
+ mongoServer = await MongoMemoryServer.create();
+ await mongoose.connect(mongoServer.getUri());
+ });
+
+ afterAll(async () => {
+ await mongoose.disconnect();
+ await mongoServer.stop();
+ });
+
+ beforeEach(async () => {
+ await mongoose.connection.dropDatabase();
+ jest.clearAllMocks();
+ agentClientArgs = undefined;
+
+ testUser = await User.create({
+ email: 'test@example.com',
+ name: 'Test User',
+ username: 'testuser',
+ role: 'USER',
+ });
+
+ mockValidateAgentModel.mockResolvedValue({ isValid: true });
+ });
+
+ const makeReq = () => ({
+ user: { id: testUser._id.toString(), role: 'USER' },
+ body: { conversationId: 'conv_1', files: [] },
+ config: { endpoints: {} },
+ _resumableStreamId: null,
+ });
+
+ const makeEndpointOption = () => ({
+ agent: Promise.resolve({
+ id: PRIMARY_ID,
+ name: 'Primary',
+ provider: 'openai',
+ model: 'gpt-4',
+ tools: [],
+ }),
+ model_parameters: { model: 'gpt-4' },
+ endpoint: 'agents',
+ });
+
+ const makePrimaryConfig = (edges) => ({
+ id: PRIMARY_ID,
+ endpoint: 'agents',
+ edges,
+ toolDefinitions: [],
+ toolRegistry: new Map(),
+ userMCPAuthMap: null,
+ tool_resources: {},
+ resendFiles: true,
+ maxContextTokens: 4096,
+ });
+
+ it('should skip handoff agent and filter its edge when user lacks VIEW access', async () => {
+ await createAgent({
+ id: TARGET_ID,
+ name: 'Target Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: new mongoose.Types.ObjectId(),
+ tools: [],
+ });
+
+ const edges = [{ from: PRIMARY_ID, to: TARGET_ID, edgeType: 'handoff' }];
+ mockInitializeAgent.mockResolvedValue(makePrimaryConfig(edges));
+
+ await initializeClient({
+ req: makeReq(),
+ res: {},
+ signal: new AbortController().signal,
+ endpointOption: makeEndpointOption(),
+ });
+
+ expect(mockInitializeAgent).toHaveBeenCalledTimes(1);
+ expect(agentClientArgs.agent.edges).toEqual([]);
+ });
+
+ it('should initialize handoff agent and keep its edge when user has VIEW access', async () => {
+ const authorizedAgent = await createAgent({
+ id: AUTHORIZED_ID,
+ name: 'Authorized Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: new mongoose.Types.ObjectId(),
+ tools: [],
+ });
+
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: testUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.AGENT,
+ resourceId: authorizedAgent._id,
+ permBits: PermissionBits.VIEW,
+ grantedBy: testUser._id,
+ });
+
+ const edges = [{ from: PRIMARY_ID, to: AUTHORIZED_ID, edgeType: 'handoff' }];
+ const handoffConfig = {
+ id: AUTHORIZED_ID,
+ edges: [],
+ toolDefinitions: [],
+ toolRegistry: new Map(),
+ userMCPAuthMap: null,
+ tool_resources: {},
+ };
+
+ let callCount = 0;
+ mockInitializeAgent.mockImplementation(() => {
+ callCount++;
+ return callCount === 1
+ ? Promise.resolve(makePrimaryConfig(edges))
+ : Promise.resolve(handoffConfig);
+ });
+
+ await initializeClient({
+ req: makeReq(),
+ res: {},
+ signal: new AbortController().signal,
+ endpointOption: makeEndpointOption(),
+ });
+
+ expect(mockInitializeAgent).toHaveBeenCalledTimes(2);
+ expect(agentClientArgs.agent.edges).toHaveLength(1);
+ expect(agentClientArgs.agent.edges[0].to).toBe(AUTHORIZED_ID);
+ });
+});
diff --git a/api/server/services/Endpoints/agents/title.js b/api/server/services/Endpoints/agents/title.js
index 1d6d359bd6..b7e1a54e06 100644
--- a/api/server/services/Endpoints/agents/title.js
+++ b/api/server/services/Endpoints/agents/title.js
@@ -66,12 +66,16 @@ const addTitle = async (req, { text, response, client }) => {
await titleCache.set(key, title, 120000);
await saveConvo(
- req,
+ {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ },
{
conversationId: response.conversationId,
title,
},
- { context: 'api/server/services/Endpoints/agents/title.js' },
+ { context: 'api/server/services/Endpoints/agents/title.js', noUpsert: true },
);
} catch (error) {
logger.error('Error generating title:', error);
diff --git a/api/server/services/Endpoints/assistants/build.js b/api/server/services/Endpoints/assistants/build.js
index 00a2abf606..85f7090211 100644
--- a/api/server/services/Endpoints/assistants/build.js
+++ b/api/server/services/Endpoints/assistants/build.js
@@ -1,6 +1,6 @@
const { removeNullishValues } = require('librechat-data-provider');
const generateArtifactsPrompt = require('~/app/clients/prompts/artifacts');
-const { getAssistant } = require('~/models/Assistant');
+const { getAssistant } = require('~/models');
const buildOptions = async (endpoint, parsedBody) => {
const { promptPrefix, assistant_id, iconURL, greeting, spec, artifacts, ...modelOptions } =
diff --git a/api/server/services/Endpoints/assistants/title.js b/api/server/services/Endpoints/assistants/title.js
index a34de4d1af..b31289eb60 100644
--- a/api/server/services/Endpoints/assistants/title.js
+++ b/api/server/services/Endpoints/assistants/title.js
@@ -1,9 +1,9 @@
const { isEnabled, sanitizeTitle } = require('@librechat/api');
const { logger } = require('@librechat/data-schemas');
const { CacheKeys } = require('librechat-data-provider');
-const { saveConvo } = require('~/models/Conversation');
const getLogStores = require('~/cache/getLogStores');
const initializeClient = require('./initalize');
+const { saveConvo } = require('~/models');
/**
* Generates a conversation title using OpenAI SDK
@@ -63,25 +63,34 @@ const addTitle = async (req, { text, responseText, conversationId }) => {
const title = await generateTitle({ openai, text, responseText });
await titleCache.set(key, title, 120000);
+ const reqCtx = {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ };
await saveConvo(
- req,
+ reqCtx,
{
conversationId,
title,
},
- { context: 'api/server/services/Endpoints/assistants/addTitle.js' },
+ { context: 'api/server/services/Endpoints/assistants/addTitle.js', noUpsert: true },
);
} catch (error) {
logger.error('[addTitle] Error generating title:', error);
const fallbackTitle = text.length > 40 ? text.substring(0, 37) + '...' : text;
await titleCache.set(key, fallbackTitle, 120000);
await saveConvo(
- req,
+ {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ },
{
conversationId,
title: fallbackTitle,
},
- { context: 'api/server/services/Endpoints/assistants/addTitle.js' },
+ { context: 'api/server/services/Endpoints/assistants/addTitle.js', noUpsert: true },
);
}
};
diff --git a/api/server/services/Endpoints/azureAssistants/build.js b/api/server/services/Endpoints/azureAssistants/build.js
index 53b1dbeb68..315447ed7f 100644
--- a/api/server/services/Endpoints/azureAssistants/build.js
+++ b/api/server/services/Endpoints/azureAssistants/build.js
@@ -1,6 +1,6 @@
const { removeNullishValues } = require('librechat-data-provider');
const generateArtifactsPrompt = require('~/app/clients/prompts/artifacts');
-const { getAssistant } = require('~/models/Assistant');
+const { getAssistant } = require('~/models');
const buildOptions = async (endpoint, parsedBody) => {
const { promptPrefix, assistant_id, iconURL, greeting, spec, artifacts, ...modelOptions } =
diff --git a/api/server/services/Files/Audio/streamAudio.js b/api/server/services/Files/Audio/streamAudio.js
index a1d7c7a649..c28a96edff 100644
--- a/api/server/services/Files/Audio/streamAudio.js
+++ b/api/server/services/Files/Audio/streamAudio.js
@@ -5,8 +5,8 @@ const {
parseTextParts,
findLastSeparatorIndex,
} = require('librechat-data-provider');
-const { getMessage } = require('~/models/Message');
const { getLogStores } = require('~/cache');
+const { getMessage } = require('~/models');
/**
* @param {string[]} voiceIds - Array of voice IDs
diff --git a/api/server/services/Files/Audio/streamAudio.spec.js b/api/server/services/Files/Audio/streamAudio.spec.js
index e76c0849c7..977d8730aa 100644
--- a/api/server/services/Files/Audio/streamAudio.spec.js
+++ b/api/server/services/Files/Audio/streamAudio.spec.js
@@ -3,7 +3,7 @@ const { createChunkProcessor, splitTextIntoChunks } = require('./streamAudio');
jest.mock('keyv');
const globalCache = {};
-jest.mock('~/models/Message', () => {
+jest.mock('~/models', () => {
return {
getMessage: jest.fn().mockImplementation((messageId) => {
return globalCache[messageId] || null;
diff --git a/api/server/services/Files/Azure/crud.js b/api/server/services/Files/Azure/crud.js
index 25bd749276..8f681bd06c 100644
--- a/api/server/services/Files/Azure/crud.js
+++ b/api/server/services/Files/Azure/crud.js
@@ -4,7 +4,7 @@ const mime = require('mime');
const axios = require('axios');
const fetch = require('node-fetch');
const { logger } = require('@librechat/data-schemas');
-const { getAzureContainerClient } = require('@librechat/api');
+const { getAzureContainerClient, deleteRagFile } = require('@librechat/api');
const defaultBasePath = 'images';
const { AZURE_STORAGE_PUBLIC_ACCESS = 'true', AZURE_CONTAINER_NAME = 'files' } = process.env;
@@ -102,6 +102,8 @@ async function getAzureURL({ fileName, basePath = defaultBasePath, userId, conta
* @param {MongoFile} params.file - The file object.
*/
async function deleteFileFromAzure(req, file) {
+ await deleteRagFile({ userId: req.user.id, file });
+
try {
const containerClient = await getAzureContainerClient(AZURE_CONTAINER_NAME);
const blobPath = file.filepath.split(`${AZURE_CONTAINER_NAME}/`)[1];
diff --git a/api/server/services/Files/Citations/index.js b/api/server/services/Files/Citations/index.js
index 7cb2ee6de0..008e21d7c4 100644
--- a/api/server/services/Files/Citations/index.js
+++ b/api/server/services/Files/Citations/index.js
@@ -8,8 +8,7 @@ const {
EModelEndpoint,
PermissionTypes,
} = require('librechat-data-provider');
-const { getRoleByName } = require('~/models/Role');
-const { Files } = require('~/models');
+const { getRoleByName, getFiles } = require('~/models');
/**
* Process file search results from tool calls
@@ -127,7 +126,7 @@ async function enhanceSourcesWithMetadata(sources, appConfig) {
let fileMetadataMap = {};
try {
- const files = await Files.find({ file_id: { $in: fileIds } });
+ const files = await getFiles({ file_id: { $in: fileIds } });
fileMetadataMap = files.reduce((map, file) => {
map[file.file_id] = file;
return map;
diff --git a/api/server/services/Files/Code/__tests__/process-traversal.spec.js b/api/server/services/Files/Code/__tests__/process-traversal.spec.js
new file mode 100644
index 0000000000..2db366d06b
--- /dev/null
+++ b/api/server/services/Files/Code/__tests__/process-traversal.spec.js
@@ -0,0 +1,124 @@
+jest.mock('uuid', () => ({ v4: jest.fn(() => 'mock-uuid') }));
+
+jest.mock('@librechat/data-schemas', () => ({
+ logger: { warn: jest.fn(), debug: jest.fn(), error: jest.fn() },
+}));
+
+jest.mock('@librechat/agents', () => ({
+ getCodeBaseURL: jest.fn(() => 'http://localhost:8000'),
+}));
+
+const mockSanitizeFilename = jest.fn();
+
+jest.mock('@librechat/api', () => ({
+ logAxiosError: jest.fn(),
+ getBasePath: jest.fn(() => ''),
+ sanitizeFilename: mockSanitizeFilename,
+}));
+
+jest.mock('librechat-data-provider', () => ({
+ ...jest.requireActual('librechat-data-provider'),
+ mergeFileConfig: jest.fn(() => ({ serverFileSizeLimit: 100 * 1024 * 1024 })),
+ getEndpointFileConfig: jest.fn(() => ({
+ fileSizeLimit: 100 * 1024 * 1024,
+ supportedMimeTypes: ['*/*'],
+ })),
+ fileConfig: { checkType: jest.fn(() => true) },
+}));
+
+jest.mock('~/models', () => ({
+ createFile: jest.fn().mockResolvedValue({}),
+ getFiles: jest.fn().mockResolvedValue([]),
+ updateFile: jest.fn(),
+ claimCodeFile: jest.fn().mockResolvedValue({ file_id: 'mock-uuid', usage: 0 }),
+}));
+
+const mockSaveBuffer = jest.fn().mockResolvedValue('/uploads/user123/mock-uuid__output.csv');
+
+jest.mock('~/server/services/Files/strategies', () => ({
+ getStrategyFunctions: jest.fn(() => ({
+ saveBuffer: mockSaveBuffer,
+ })),
+}));
+
+jest.mock('~/server/services/Files/permissions', () => ({
+ filterFilesByAgentAccess: jest.fn().mockResolvedValue([]),
+}));
+
+jest.mock('~/server/services/Files/images/convert', () => ({
+ convertImage: jest.fn(),
+}));
+
+jest.mock('~/server/utils', () => ({
+ determineFileType: jest.fn().mockResolvedValue({ mime: 'text/csv' }),
+}));
+
+jest.mock('axios', () =>
+ jest.fn().mockResolvedValue({
+ data: Buffer.from('file-content'),
+ }),
+);
+
+const { createFile } = require('~/models');
+const { processCodeOutput } = require('../process');
+
+const baseParams = {
+ req: {
+ user: { id: 'user123' },
+ config: {
+ fileStrategy: 'local',
+ imageOutputType: 'webp',
+ fileConfig: {},
+ },
+ },
+ id: 'code-file-id',
+ apiKey: 'test-key',
+ toolCallId: 'tool-1',
+ conversationId: 'conv-1',
+ messageId: 'msg-1',
+ session_id: 'session-1',
+};
+
+describe('processCodeOutput path traversal protection', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ test('sanitizeFilename is called with the raw artifact name', async () => {
+ mockSanitizeFilename.mockReturnValueOnce('output.csv');
+ await processCodeOutput({ ...baseParams, name: 'output.csv' });
+ expect(mockSanitizeFilename).toHaveBeenCalledWith('output.csv');
+ });
+
+ test('sanitized name is used in saveBuffer fileName', async () => {
+ mockSanitizeFilename.mockReturnValueOnce('sanitized-name.txt');
+ await processCodeOutput({ ...baseParams, name: '../../../tmp/poc.txt' });
+
+ expect(mockSanitizeFilename).toHaveBeenCalledWith('../../../tmp/poc.txt');
+ const call = mockSaveBuffer.mock.calls[0][0];
+ expect(call.fileName).toBe('mock-uuid__sanitized-name.txt');
+ });
+
+ test('sanitized name is stored as filename in the file record', async () => {
+ mockSanitizeFilename.mockReturnValueOnce('safe-output.csv');
+ await processCodeOutput({ ...baseParams, name: 'unsafe/../../output.csv' });
+
+ const fileArg = createFile.mock.calls[0][0];
+ expect(fileArg.filename).toBe('safe-output.csv');
+ });
+
+ test('sanitized name is used for image file records', async () => {
+ const { convertImage } = require('~/server/services/Files/images/convert');
+ convertImage.mockResolvedValueOnce({
+ filepath: '/images/user123/mock-uuid.webp',
+ bytes: 100,
+ });
+
+ mockSanitizeFilename.mockReturnValueOnce('safe-chart.png');
+ await processCodeOutput({ ...baseParams, name: '../../../chart.png' });
+
+ expect(mockSanitizeFilename).toHaveBeenCalledWith('../../../chart.png');
+ const fileArg = createFile.mock.calls[0][0];
+ expect(fileArg.filename).toBe('safe-chart.png');
+ });
+});
diff --git a/api/server/services/Files/Code/process.js b/api/server/services/Files/Code/process.js
index 3f0bfcfc87..e878b00255 100644
--- a/api/server/services/Files/Code/process.js
+++ b/api/server/services/Files/Code/process.js
@@ -3,7 +3,7 @@ const { v4 } = require('uuid');
const axios = require('axios');
const { logger } = require('@librechat/data-schemas');
const { getCodeBaseURL } = require('@librechat/agents');
-const { logAxiosError, getBasePath } = require('@librechat/api');
+const { logAxiosError, getBasePath, sanitizeFilename } = require('@librechat/api');
const {
Tools,
megabyte,
@@ -146,6 +146,13 @@ const processCodeOutput = async ({
);
}
+ const safeName = sanitizeFilename(name);
+ if (safeName !== name) {
+ logger.warn(
+ `[processCodeOutput] Filename sanitized: "${name}" -> "${safeName}" | conv=${conversationId}`,
+ );
+ }
+
if (isImage) {
const usage = isUpdate ? (claimed.usage ?? 0) + 1 : 1;
const _file = await convertImage(req, buffer, 'high', `${file_id}${fileExt}`);
@@ -156,7 +163,7 @@ const processCodeOutput = async ({
file_id,
messageId,
usage,
- filename: name,
+ filename: safeName,
conversationId,
user: req.user.id,
type: `image/${appConfig.imageOutputType}`,
@@ -200,7 +207,7 @@ const processCodeOutput = async ({
);
}
- const fileName = `${file_id}__${name}`;
+ const fileName = `${file_id}__${safeName}`;
const filepath = await saveBuffer({
userId: req.user.id,
buffer,
@@ -213,7 +220,7 @@ const processCodeOutput = async ({
filepath,
messageId,
object: 'file',
- filename: name,
+ filename: safeName,
type: mimeType,
conversationId,
user: req.user.id,
@@ -229,6 +236,11 @@ const processCodeOutput = async ({
await createFile(file, true);
return Object.assign(file, { messageId, toolCallId });
} catch (error) {
+ if (error?.message === 'Path traversal detected in filename') {
+ logger.warn(
+ `[processCodeOutput] Path traversal blocked for file "${name}" | conv=${conversationId}`,
+ );
+ }
logAxiosError({
message: 'Error downloading/processing code environment file',
error,
diff --git a/api/server/services/Files/Code/process.spec.js b/api/server/services/Files/Code/process.spec.js
index f01a623f90..b89a6c6307 100644
--- a/api/server/services/Files/Code/process.spec.js
+++ b/api/server/services/Files/Code/process.spec.js
@@ -58,6 +58,7 @@ jest.mock('@librechat/agents', () => ({
jest.mock('@librechat/api', () => ({
logAxiosError: jest.fn(),
getBasePath: jest.fn(() => ''),
+ sanitizeFilename: jest.fn((name) => name),
}));
// Mock models
diff --git a/api/server/services/Files/Firebase/crud.js b/api/server/services/Files/Firebase/crud.js
index 170df45677..d5e5a409bf 100644
--- a/api/server/services/Files/Firebase/crud.js
+++ b/api/server/services/Files/Firebase/crud.js
@@ -3,7 +3,7 @@ const path = require('path');
const axios = require('axios');
const fetch = require('node-fetch');
const { logger } = require('@librechat/data-schemas');
-const { getFirebaseStorage } = require('@librechat/api');
+const { getFirebaseStorage, deleteRagFile } = require('@librechat/api');
const { ref, uploadBytes, getDownloadURL, deleteObject } = require('firebase/storage');
const { getBufferMetadata } = require('~/server/utils');
@@ -167,27 +167,7 @@ function extractFirebaseFilePath(urlString) {
* Throws an error if there is an issue with deletion.
*/
const deleteFirebaseFile = async (req, file) => {
- if (file.embedded && process.env.RAG_API_URL) {
- const jwtToken = req.headers.authorization.split(' ')[1];
- try {
- await axios.delete(`${process.env.RAG_API_URL}/documents`, {
- headers: {
- Authorization: `Bearer ${jwtToken}`,
- 'Content-Type': 'application/json',
- accept: 'application/json',
- },
- data: [file.file_id],
- });
- } catch (error) {
- if (error.response?.status === 404) {
- logger.warn(
- `[deleteFirebaseFile] Document ${file.file_id} not found in RAG API, may have been deleted already`,
- );
- } else {
- logger.error('[deleteFirebaseFile] Error deleting document from RAG API:', error);
- }
- }
- }
+ await deleteRagFile({ userId: req.user.id, file });
const fileName = extractFirebaseFilePath(file.filepath);
if (!fileName.includes(req.user.id)) {
diff --git a/api/server/services/Files/Local/__tests__/crud-traversal.spec.js b/api/server/services/Files/Local/__tests__/crud-traversal.spec.js
new file mode 100644
index 0000000000..57ba221d68
--- /dev/null
+++ b/api/server/services/Files/Local/__tests__/crud-traversal.spec.js
@@ -0,0 +1,69 @@
+jest.mock('@librechat/api', () => ({ deleteRagFile: jest.fn() }));
+jest.mock('@librechat/data-schemas', () => ({
+ logger: { warn: jest.fn(), error: jest.fn() },
+}));
+
+const mockTmpBase = require('fs').mkdtempSync(
+ require('path').join(require('os').tmpdir(), 'crud-traversal-'),
+);
+
+jest.mock('~/config/paths', () => {
+ const path = require('path');
+ return {
+ publicPath: path.join(mockTmpBase, 'public'),
+ uploads: path.join(mockTmpBase, 'uploads'),
+ };
+});
+
+const fs = require('fs');
+const path = require('path');
+const { saveLocalBuffer } = require('../crud');
+
+describe('saveLocalBuffer path containment', () => {
+ beforeAll(() => {
+ fs.mkdirSync(path.join(mockTmpBase, 'public', 'images'), { recursive: true });
+ fs.mkdirSync(path.join(mockTmpBase, 'uploads'), { recursive: true });
+ });
+
+ afterAll(() => {
+ fs.rmSync(mockTmpBase, { recursive: true, force: true });
+ });
+
+ test('rejects filenames with path traversal sequences', async () => {
+ await expect(
+ saveLocalBuffer({
+ userId: 'user1',
+ buffer: Buffer.from('malicious'),
+ fileName: '../../../etc/passwd',
+ basePath: 'uploads',
+ }),
+ ).rejects.toThrow('Path traversal detected in filename');
+ });
+
+ test('rejects prefix-collision traversal (startsWith bypass)', async () => {
+ fs.mkdirSync(path.join(mockTmpBase, 'uploads', 'user10'), { recursive: true });
+ await expect(
+ saveLocalBuffer({
+ userId: 'user1',
+ buffer: Buffer.from('malicious'),
+ fileName: '../user10/evil',
+ basePath: 'uploads',
+ }),
+ ).rejects.toThrow('Path traversal detected in filename');
+ });
+
+ test('allows normal filenames', async () => {
+ const result = await saveLocalBuffer({
+ userId: 'user1',
+ buffer: Buffer.from('safe content'),
+ fileName: 'file-id__output.csv',
+ basePath: 'uploads',
+ });
+
+ expect(result).toBe('/uploads/user1/file-id__output.csv');
+
+ const filePath = path.join(mockTmpBase, 'uploads', 'user1', 'file-id__output.csv');
+ expect(fs.existsSync(filePath)).toBe(true);
+ fs.unlinkSync(filePath);
+ });
+});
diff --git a/api/server/services/Files/Local/crud.js b/api/server/services/Files/Local/crud.js
index b43ab75326..c86774d472 100644
--- a/api/server/services/Files/Local/crud.js
+++ b/api/server/services/Files/Local/crud.js
@@ -1,9 +1,9 @@
const fs = require('fs');
const path = require('path');
const axios = require('axios');
+const { deleteRagFile } = require('@librechat/api');
const { logger } = require('@librechat/data-schemas');
const { EModelEndpoint } = require('librechat-data-provider');
-const { generateShortLivedToken } = require('@librechat/api');
const { resizeImageBuffer } = require('~/server/services/Files/images/resize');
const { getBufferMetadata } = require('~/server/utils');
const paths = require('~/config/paths');
@@ -78,7 +78,13 @@ async function saveLocalBuffer({ userId, buffer, fileName, basePath = 'images' }
fs.mkdirSync(directoryPath, { recursive: true });
}
- fs.writeFileSync(path.join(directoryPath, fileName), buffer);
+ const resolvedDir = path.resolve(directoryPath);
+ const resolvedPath = path.resolve(resolvedDir, fileName);
+ const rel = path.relative(resolvedDir, resolvedPath);
+ if (rel.startsWith('..') || path.isAbsolute(rel) || rel.includes(`..${path.sep}`)) {
+ throw new Error('Path traversal detected in filename');
+ }
+ fs.writeFileSync(resolvedPath, buffer);
const filePath = path.posix.join('/', basePath, userId, fileName);
@@ -165,9 +171,8 @@ async function getLocalFileURL({ fileName, basePath = 'images' }) {
}
/**
- * Validates if a given filepath is within a specified subdirectory under a base path. This function constructs
- * the expected base path using the base, subfolder, and user id from the request, and then checks if the
- * provided filepath starts with this constructed base path.
+ * Validates that a filepath is strictly contained within a subdirectory under a base path,
+ * using path.relative to prevent prefix-collision bypasses.
*
* @param {ServerRequest} req - The request object from Express. It should contain a `user` property with an `id`.
* @param {string} base - The base directory path.
@@ -180,7 +185,8 @@ async function getLocalFileURL({ fileName, basePath = 'images' }) {
const isValidPath = (req, base, subfolder, filepath) => {
const normalizedBase = path.resolve(base, subfolder, req.user.id);
const normalizedFilepath = path.resolve(filepath);
- return normalizedFilepath.startsWith(normalizedBase);
+ const rel = path.relative(normalizedBase, normalizedFilepath);
+ return !rel.startsWith('..') && !path.isAbsolute(rel) && !rel.includes(`..${path.sep}`);
};
/**
@@ -213,27 +219,7 @@ const deleteLocalFile = async (req, file) => {
/** Filepath stripped of query parameters (e.g., ?manual=true) */
const cleanFilepath = file.filepath.split('?')[0];
- if (file.embedded && process.env.RAG_API_URL) {
- const jwtToken = generateShortLivedToken(req.user.id);
- try {
- await axios.delete(`${process.env.RAG_API_URL}/documents`, {
- headers: {
- Authorization: `Bearer ${jwtToken}`,
- 'Content-Type': 'application/json',
- accept: 'application/json',
- },
- data: [file.file_id],
- });
- } catch (error) {
- if (error.response?.status === 404) {
- logger.warn(
- `[deleteLocalFile] Document ${file.file_id} not found in RAG API, may have been deleted already`,
- );
- } else {
- logger.error('[deleteLocalFile] Error deleting document from RAG API:', error);
- }
- }
- }
+ await deleteRagFile({ userId: req.user.id, file });
if (cleanFilepath.startsWith(`/uploads/${req.user.id}`)) {
const userUploadDir = path.join(uploads, req.user.id);
diff --git a/api/server/services/Files/S3/crud.js b/api/server/services/Files/S3/crud.js
deleted file mode 100644
index 8dac767aa2..0000000000
--- a/api/server/services/Files/S3/crud.js
+++ /dev/null
@@ -1,483 +0,0 @@
-const fs = require('fs');
-const fetch = require('node-fetch');
-const { initializeS3 } = require('@librechat/api');
-const { logger } = require('@librechat/data-schemas');
-const { FileSources } = require('librechat-data-provider');
-const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');
-const {
- PutObjectCommand,
- GetObjectCommand,
- HeadObjectCommand,
- DeleteObjectCommand,
-} = require('@aws-sdk/client-s3');
-
-const bucketName = process.env.AWS_BUCKET_NAME;
-const defaultBasePath = 'images';
-
-let s3UrlExpirySeconds = 2 * 60; // 2 minutes
-let s3RefreshExpiryMs = null;
-
-if (process.env.S3_URL_EXPIRY_SECONDS !== undefined) {
- const parsed = parseInt(process.env.S3_URL_EXPIRY_SECONDS, 10);
-
- if (!isNaN(parsed) && parsed > 0) {
- s3UrlExpirySeconds = Math.min(parsed, 7 * 24 * 60 * 60);
- } else {
- logger.warn(
- `[S3] Invalid S3_URL_EXPIRY_SECONDS value: "${process.env.S3_URL_EXPIRY_SECONDS}". Using 2-minute expiry.`,
- );
- }
-}
-
-if (process.env.S3_REFRESH_EXPIRY_MS !== null && process.env.S3_REFRESH_EXPIRY_MS) {
- const parsed = parseInt(process.env.S3_REFRESH_EXPIRY_MS, 10);
-
- if (!isNaN(parsed) && parsed > 0) {
- s3RefreshExpiryMs = parsed;
- logger.info(`[S3] Using custom refresh expiry time: ${s3RefreshExpiryMs}ms`);
- } else {
- logger.warn(
- `[S3] Invalid S3_REFRESH_EXPIRY_MS value: "${process.env.S3_REFRESH_EXPIRY_MS}". Using default refresh logic.`,
- );
- }
-}
-
-/**
- * Constructs the S3 key based on the base path, user ID, and file name.
- */
-const getS3Key = (basePath, userId, fileName) => `${basePath}/${userId}/${fileName}`;
-
-/**
- * Uploads a buffer to S3 and returns a signed URL.
- *
- * @param {Object} params
- * @param {string} params.userId - The user's unique identifier.
- * @param {Buffer} params.buffer - The buffer containing file data.
- * @param {string} params.fileName - The file name to use in S3.
- * @param {string} [params.basePath='images'] - The base path in the bucket.
- * @returns {Promise} Signed URL of the uploaded file.
- */
-async function saveBufferToS3({ userId, buffer, fileName, basePath = defaultBasePath }) {
- const key = getS3Key(basePath, userId, fileName);
- const params = { Bucket: bucketName, Key: key, Body: buffer };
-
- try {
- const s3 = initializeS3();
- await s3.send(new PutObjectCommand(params));
- return await getS3URL({ userId, fileName, basePath });
- } catch (error) {
- logger.error('[saveBufferToS3] Error uploading buffer to S3:', error.message);
- throw error;
- }
-}
-
-/**
- * Retrieves a URL for a file stored in S3.
- * Returns a signed URL with expiration time or a proxy URL based on config
- *
- * @param {Object} params
- * @param {string} params.userId - The user's unique identifier.
- * @param {string} params.fileName - The file name in S3.
- * @param {string} [params.basePath='images'] - The base path in the bucket.
- * @param {string} [params.customFilename] - Custom filename for Content-Disposition header (overrides extracted filename).
- * @param {string} [params.contentType] - Custom content type for the response.
- * @returns {Promise} A URL to access the S3 object
- */
-async function getS3URL({
- userId,
- fileName,
- basePath = defaultBasePath,
- customFilename = null,
- contentType = null,
-}) {
- const key = getS3Key(basePath, userId, fileName);
- const params = { Bucket: bucketName, Key: key };
-
- // Add response headers if specified
- if (customFilename) {
- params.ResponseContentDisposition = `attachment; filename="${customFilename}"`;
- }
-
- if (contentType) {
- params.ResponseContentType = contentType;
- }
-
- try {
- const s3 = initializeS3();
- return await getSignedUrl(s3, new GetObjectCommand(params), { expiresIn: s3UrlExpirySeconds });
- } catch (error) {
- logger.error('[getS3URL] Error getting signed URL from S3:', error.message);
- throw error;
- }
-}
-
-/**
- * Saves a file from a given URL to S3.
- *
- * @param {Object} params
- * @param {string} params.userId - The user's unique identifier.
- * @param {string} params.URL - The source URL of the file.
- * @param {string} params.fileName - The file name to use in S3.
- * @param {string} [params.basePath='images'] - The base path in the bucket.
- * @returns {Promise} Signed URL of the uploaded file.
- */
-async function saveURLToS3({ userId, URL, fileName, basePath = defaultBasePath }) {
- try {
- const response = await fetch(URL);
- const buffer = await response.buffer();
- // Optionally you can call getBufferMetadata(buffer) if needed.
- return await saveBufferToS3({ userId, buffer, fileName, basePath });
- } catch (error) {
- logger.error('[saveURLToS3] Error uploading file from URL to S3:', error.message);
- throw error;
- }
-}
-
-/**
- * Deletes a file from S3.
- *
- * @param {Object} params
- * @param {ServerRequest} params.req
- * @param {MongoFile} params.file - The file object to delete.
- * @returns {Promise}
- */
-async function deleteFileFromS3(req, file) {
- const key = extractKeyFromS3Url(file.filepath);
- const params = { Bucket: bucketName, Key: key };
- if (!key.includes(req.user.id)) {
- const message = `[deleteFileFromS3] User ID mismatch: ${req.user.id} vs ${key}`;
- logger.error(message);
- throw new Error(message);
- }
-
- try {
- const s3 = initializeS3();
-
- try {
- const headCommand = new HeadObjectCommand(params);
- await s3.send(headCommand);
- logger.debug('[deleteFileFromS3] File exists, proceeding with deletion');
- } catch (headErr) {
- if (headErr.name === 'NotFound') {
- logger.warn(`[deleteFileFromS3] File does not exist: ${key}`);
- return;
- }
- }
-
- const deleteResult = await s3.send(new DeleteObjectCommand(params));
- logger.debug('[deleteFileFromS3] Delete command response:', JSON.stringify(deleteResult));
- try {
- await s3.send(new HeadObjectCommand(params));
- logger.error('[deleteFileFromS3] File still exists after deletion!');
- } catch (verifyErr) {
- if (verifyErr.name === 'NotFound') {
- logger.debug(`[deleteFileFromS3] Verified file is deleted: ${key}`);
- } else {
- logger.error('[deleteFileFromS3] Error verifying deletion:', verifyErr);
- }
- }
-
- logger.debug('[deleteFileFromS3] S3 File deletion completed');
- } catch (error) {
- logger.error(`[deleteFileFromS3] Error deleting file from S3: ${error.message}`);
- logger.error(error.stack);
-
- // If the file is not found, we can safely return.
- if (error.code === 'NoSuchKey') {
- return;
- }
- throw error;
- }
-}
-
-/**
- * Uploads a local file to S3 by streaming it directly without loading into memory.
- *
- * @param {Object} params
- * @param {import('express').Request} params.req - The Express request (must include user).
- * @param {Express.Multer.File} params.file - The file object from Multer.
- * @param {string} params.file_id - Unique file identifier.
- * @param {string} [params.basePath='images'] - The base path in the bucket.
- * @returns {Promise<{ filepath: string, bytes: number }>}
- */
-async function uploadFileToS3({ req, file, file_id, basePath = defaultBasePath }) {
- try {
- const inputFilePath = file.path;
- const userId = req.user.id;
- const fileName = `${file_id}__${file.originalname}`;
- const key = getS3Key(basePath, userId, fileName);
-
- const stats = await fs.promises.stat(inputFilePath);
- const bytes = stats.size;
- const fileStream = fs.createReadStream(inputFilePath);
-
- const s3 = initializeS3();
- const uploadParams = {
- Bucket: bucketName,
- Key: key,
- Body: fileStream,
- };
-
- await s3.send(new PutObjectCommand(uploadParams));
- const fileURL = await getS3URL({ userId, fileName, basePath });
- return { filepath: fileURL, bytes };
- } catch (error) {
- logger.error('[uploadFileToS3] Error streaming file to S3:', error);
- try {
- if (file && file.path) {
- await fs.promises.unlink(file.path);
- }
- } catch (unlinkError) {
- logger.error(
- '[uploadFileToS3] Error deleting temporary file, likely already deleted:',
- unlinkError.message,
- );
- }
- throw error;
- }
-}
-
-/**
- * Extracts the S3 key from a URL or returns the key if already properly formatted
- *
- * @param {string} fileUrlOrKey - The file URL or key
- * @returns {string} The S3 key
- */
-function extractKeyFromS3Url(fileUrlOrKey) {
- if (!fileUrlOrKey) {
- throw new Error('Invalid input: URL or key is empty');
- }
-
- try {
- const url = new URL(fileUrlOrKey);
- return url.pathname.substring(1);
- } catch (error) {
- const parts = fileUrlOrKey.split('/');
-
- if (parts.length >= 3 && !fileUrlOrKey.startsWith('http') && !fileUrlOrKey.startsWith('/')) {
- return fileUrlOrKey;
- }
-
- return fileUrlOrKey.startsWith('/') ? fileUrlOrKey.substring(1) : fileUrlOrKey;
- }
-}
-
-/**
- * Retrieves a readable stream for a file stored in S3.
- *
- * @param {ServerRequest} req - Server request object.
- * @param {string} filePath - The S3 key of the file.
- * @returns {Promise}
- */
-async function getS3FileStream(_req, filePath) {
- try {
- const Key = extractKeyFromS3Url(filePath);
- const params = { Bucket: bucketName, Key };
- const s3 = initializeS3();
- const data = await s3.send(new GetObjectCommand(params));
- return data.Body; // Returns a Node.js ReadableStream.
- } catch (error) {
- logger.error('[getS3FileStream] Error retrieving S3 file stream:', error);
- throw error;
- }
-}
-
-/**
- * Determines if a signed S3 URL is close to expiration
- *
- * @param {string} signedUrl - The signed S3 URL
- * @param {number} bufferSeconds - Buffer time in seconds
- * @returns {boolean} True if the URL needs refreshing
- */
-function needsRefresh(signedUrl, bufferSeconds) {
- try {
- // Parse the URL
- const url = new URL(signedUrl);
-
- // Check if it has the signature parameters that indicate it's a signed URL
- // X-Amz-Signature is the most reliable indicator for AWS signed URLs
- if (!url.searchParams.has('X-Amz-Signature')) {
- // Not a signed URL, so no expiration to check (or it's already a proxy URL)
- return false;
- }
-
- // Extract the expiration time from the URL
- const expiresParam = url.searchParams.get('X-Amz-Expires');
- const dateParam = url.searchParams.get('X-Amz-Date');
-
- if (!expiresParam || !dateParam) {
- // Missing expiration information, assume it needs refresh to be safe
- return true;
- }
-
- // Parse the AWS date format (YYYYMMDDTHHMMSSZ)
- const year = dateParam.substring(0, 4);
- const month = dateParam.substring(4, 6);
- const day = dateParam.substring(6, 8);
- const hour = dateParam.substring(9, 11);
- const minute = dateParam.substring(11, 13);
- const second = dateParam.substring(13, 15);
-
- const dateObj = new Date(`${year}-${month}-${day}T${hour}:${minute}:${second}Z`);
- const expiresAtDate = new Date(dateObj.getTime() + parseInt(expiresParam) * 1000);
-
- // Check if it's close to expiration
- const now = new Date();
-
- // If S3_REFRESH_EXPIRY_MS is set, use it to determine if URL is expired
- if (s3RefreshExpiryMs !== null) {
- const urlCreationTime = dateObj.getTime();
- const urlAge = now.getTime() - urlCreationTime;
- return urlAge >= s3RefreshExpiryMs;
- }
-
- // Otherwise use the default buffer-based logic
- const bufferTime = new Date(now.getTime() + bufferSeconds * 1000);
- return expiresAtDate <= bufferTime;
- } catch (error) {
- logger.error('Error checking URL expiration:', error);
- // If we can't determine, assume it needs refresh to be safe
- return true;
- }
-}
-
-/**
- * Generates a new URL for an expired S3 URL
- * @param {string} currentURL - The current file URL
- * @returns {Promise}
- */
-async function getNewS3URL(currentURL) {
- try {
- const s3Key = extractKeyFromS3Url(currentURL);
- if (!s3Key) {
- return;
- }
- const keyParts = s3Key.split('/');
- if (keyParts.length < 3) {
- return;
- }
-
- const basePath = keyParts[0];
- const userId = keyParts[1];
- const fileName = keyParts.slice(2).join('/');
-
- return await getS3URL({
- userId,
- fileName,
- basePath,
- });
- } catch (error) {
- logger.error('Error getting new S3 URL:', error);
- }
-}
-
-/**
- * Refreshes S3 URLs for an array of files if they're expired or close to expiring
- *
- * @param {MongoFile[]} files - Array of file documents
- * @param {(files: MongoFile[]) => Promise} batchUpdateFiles - Function to update files in the database
- * @param {number} [bufferSeconds=3600] - Buffer time in seconds to check for expiration
- * @returns {Promise} The files with refreshed URLs if needed
- */
-async function refreshS3FileUrls(files, batchUpdateFiles, bufferSeconds = 3600) {
- if (!files || !Array.isArray(files) || files.length === 0) {
- return files;
- }
-
- const filesToUpdate = [];
-
- for (let i = 0; i < files.length; i++) {
- const file = files[i];
- if (!file?.file_id) {
- continue;
- }
- if (file.source !== FileSources.s3) {
- continue;
- }
- if (!file.filepath) {
- continue;
- }
- if (!needsRefresh(file.filepath, bufferSeconds)) {
- continue;
- }
- try {
- const newURL = await getNewS3URL(file.filepath);
- if (!newURL) {
- continue;
- }
- filesToUpdate.push({
- file_id: file.file_id,
- filepath: newURL,
- });
- files[i].filepath = newURL;
- } catch (error) {
- logger.error(`Error refreshing S3 URL for file ${file.file_id}:`, error);
- }
- }
-
- if (filesToUpdate.length > 0) {
- await batchUpdateFiles(filesToUpdate);
- }
-
- return files;
-}
-
-/**
- * Refreshes a single S3 URL if it's expired or close to expiring
- *
- * @param {{ filepath: string, source: string }} fileObj - Simple file object containing filepath and source
- * @param {number} [bufferSeconds=3600] - Buffer time in seconds to check for expiration
- * @returns {Promise} The refreshed URL or the original URL if no refresh needed
- */
-async function refreshS3Url(fileObj, bufferSeconds = 3600) {
- if (!fileObj || fileObj.source !== FileSources.s3 || !fileObj.filepath) {
- return fileObj?.filepath || '';
- }
-
- if (!needsRefresh(fileObj.filepath, bufferSeconds)) {
- return fileObj.filepath;
- }
-
- try {
- const s3Key = extractKeyFromS3Url(fileObj.filepath);
- if (!s3Key) {
- logger.warn(`Unable to extract S3 key from URL: ${fileObj.filepath}`);
- return fileObj.filepath;
- }
-
- const keyParts = s3Key.split('/');
- if (keyParts.length < 3) {
- logger.warn(`Invalid S3 key format: ${s3Key}`);
- return fileObj.filepath;
- }
-
- const basePath = keyParts[0];
- const userId = keyParts[1];
- const fileName = keyParts.slice(2).join('/');
-
- const newUrl = await getS3URL({
- userId,
- fileName,
- basePath,
- });
-
- logger.debug(`Refreshed S3 URL for key: ${s3Key}`);
- return newUrl;
- } catch (error) {
- logger.error(`Error refreshing S3 URL: ${error.message}`);
- return fileObj.filepath;
- }
-}
-
-module.exports = {
- saveBufferToS3,
- saveURLToS3,
- getS3URL,
- deleteFileFromS3,
- uploadFileToS3,
- getS3FileStream,
- refreshS3FileUrls,
- refreshS3Url,
- needsRefresh,
- getNewS3URL,
-};
diff --git a/api/server/services/Files/S3/images.js b/api/server/services/Files/S3/images.js
deleted file mode 100644
index 9bdae940c3..0000000000
--- a/api/server/services/Files/S3/images.js
+++ /dev/null
@@ -1,129 +0,0 @@
-const fs = require('fs');
-const path = require('path');
-const sharp = require('sharp');
-const { logger } = require('@librechat/data-schemas');
-const { resizeImageBuffer } = require('../images/resize');
-const { updateUser, updateFile } = require('~/models');
-const { saveBufferToS3 } = require('./crud');
-
-const defaultBasePath = 'images';
-
-/**
- * Resizes, converts, and uploads an image file to S3.
- *
- * @param {Object} params
- * @param {import('express').Request} params.req - Express request (expects `user` and `appConfig.imageOutputType`).
- * @param {Express.Multer.File} params.file - File object from Multer.
- * @param {string} params.file_id - Unique file identifier.
- * @param {any} params.endpoint - Endpoint identifier used in image processing.
- * @param {string} [params.resolution='high'] - Desired image resolution.
- * @param {string} [params.basePath='images'] - Base path in the bucket.
- * @returns {Promise<{ filepath: string, bytes: number, width: number, height: number }>}
- */
-async function uploadImageToS3({
- req,
- file,
- file_id,
- endpoint,
- resolution = 'high',
- basePath = defaultBasePath,
-}) {
- try {
- const appConfig = req.config;
- const inputFilePath = file.path;
- const inputBuffer = await fs.promises.readFile(inputFilePath);
- const {
- buffer: resizedBuffer,
- width,
- height,
- } = await resizeImageBuffer(inputBuffer, resolution, endpoint);
- const extension = path.extname(inputFilePath);
- const userId = req.user.id;
-
- let processedBuffer;
- let fileName = `${file_id}__${path.basename(inputFilePath)}`;
- const targetExtension = `.${appConfig.imageOutputType}`;
-
- if (extension.toLowerCase() === targetExtension) {
- processedBuffer = resizedBuffer;
- } else {
- processedBuffer = await sharp(resizedBuffer).toFormat(appConfig.imageOutputType).toBuffer();
- fileName = fileName.replace(new RegExp(path.extname(fileName) + '$'), targetExtension);
- if (!path.extname(fileName)) {
- fileName += targetExtension;
- }
- }
-
- const downloadURL = await saveBufferToS3({
- userId,
- buffer: processedBuffer,
- fileName,
- basePath,
- });
- await fs.promises.unlink(inputFilePath);
- const bytes = Buffer.byteLength(processedBuffer);
- return { filepath: downloadURL, bytes, width, height };
- } catch (error) {
- logger.error('[uploadImageToS3] Error uploading image to S3:', error.message);
- throw error;
- }
-}
-
-/**
- * Updates a file record and returns its signed URL.
- *
- * @param {import('express').Request} req - Express request.
- * @param {Object} file - File metadata.
- * @returns {Promise<[Promise, string]>}
- */
-async function prepareImageURLS3(req, file) {
- try {
- const updatePromise = updateFile({ file_id: file.file_id });
- return Promise.all([updatePromise, file.filepath]);
- } catch (error) {
- logger.error('[prepareImageURLS3] Error preparing image URL:', error.message);
- throw error;
- }
-}
-
-/**
- * Processes a user's avatar image by uploading it to S3 and updating the user's avatar URL if required.
- *
- * @param {Object} params
- * @param {Buffer} params.buffer - Avatar image buffer.
- * @param {string} params.userId - User's unique identifier.
- * @param {string} params.manual - 'true' or 'false' flag for manual update.
- * @param {string} [params.agentId] - Optional agent ID if this is an agent avatar.
- * @param {string} [params.basePath='images'] - Base path in the bucket.
- * @returns {Promise} Signed URL of the uploaded avatar.
- */
-async function processS3Avatar({ buffer, userId, manual, agentId, basePath = defaultBasePath }) {
- try {
- const metadata = await sharp(buffer).metadata();
- const extension = metadata.format === 'gif' ? 'gif' : 'png';
- const timestamp = new Date().getTime();
-
- /** Unique filename with timestamp and optional agent ID */
- const fileName = agentId
- ? `agent-${agentId}-avatar-${timestamp}.${extension}`
- : `avatar-${timestamp}.${extension}`;
-
- const downloadURL = await saveBufferToS3({ userId, buffer, fileName, basePath });
-
- // Only update user record if this is a user avatar (manual === 'true')
- if (manual === 'true' && !agentId) {
- await updateUser(userId, { avatar: downloadURL });
- }
-
- return downloadURL;
- } catch (error) {
- logger.error('[processS3Avatar] Error processing S3 avatar:', error.message);
- throw error;
- }
-}
-
-module.exports = {
- uploadImageToS3,
- prepareImageURLS3,
- processS3Avatar,
-};
diff --git a/api/server/services/Files/S3/index.js b/api/server/services/Files/S3/index.js
deleted file mode 100644
index 21e2f2ba7d..0000000000
--- a/api/server/services/Files/S3/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-const crud = require('./crud');
-const images = require('./images');
-
-module.exports = {
- ...crud,
- ...images,
-};
diff --git a/api/server/services/Files/permissions.js b/api/server/services/Files/permissions.js
index d909afe25a..ffa8e74799 100644
--- a/api/server/services/Files/permissions.js
+++ b/api/server/services/Files/permissions.js
@@ -1,10 +1,29 @@
const { logger } = require('@librechat/data-schemas');
-const { PermissionBits, ResourceType } = require('librechat-data-provider');
+const { PermissionBits, ResourceType, isEphemeralAgentId } = require('librechat-data-provider');
const { checkPermission } = require('~/server/services/PermissionService');
-const { getAgent } = require('~/models/Agent');
+const { getAgent } = require('~/models');
/**
- * Checks if a user has access to multiple files through a shared agent (batch operation)
+ * @param {Object} agent - The agent document (lean)
+ * @returns {Set} All file IDs attached across all resource types
+ */
+function getAttachedFileIds(agent) {
+ const attachedFileIds = new Set();
+ if (agent.tool_resources) {
+ for (const resource of Object.values(agent.tool_resources)) {
+ if (resource?.file_ids && Array.isArray(resource.file_ids)) {
+ for (const fileId of resource.file_ids) {
+ attachedFileIds.add(fileId);
+ }
+ }
+ }
+ }
+ return attachedFileIds;
+}
+
+/**
+ * Checks if a user has access to multiple files through a shared agent (batch operation).
+ * Access is always scoped to files actually attached to the agent's tool_resources.
* @param {Object} params - Parameters object
* @param {string} params.userId - The user ID to check access for
* @param {string} [params.role] - Optional user role to avoid DB query
@@ -16,7 +35,6 @@ const { getAgent } = require('~/models/Agent');
const hasAccessToFilesViaAgent = async ({ userId, role, fileIds, agentId, isDelete }) => {
const accessMap = new Map();
- // Initialize all files as no access
fileIds.forEach((fileId) => accessMap.set(fileId, false));
try {
@@ -26,13 +44,17 @@ const hasAccessToFilesViaAgent = async ({ userId, role, fileIds, agentId, isDele
return accessMap;
}
- // Check if user is the author - if so, grant access to all files
+ const attachedFileIds = getAttachedFileIds(agent);
+
if (agent.author.toString() === userId.toString()) {
- fileIds.forEach((fileId) => accessMap.set(fileId, true));
+ fileIds.forEach((fileId) => {
+ if (attachedFileIds.has(fileId)) {
+ accessMap.set(fileId, true);
+ }
+ });
return accessMap;
}
- // Check if user has at least VIEW permission on the agent
const hasViewPermission = await checkPermission({
userId,
role,
@@ -46,7 +68,6 @@ const hasAccessToFilesViaAgent = async ({ userId, role, fileIds, agentId, isDele
}
if (isDelete) {
- // Check if user has EDIT permission (which would indicate collaborative access)
const hasEditPermission = await checkPermission({
userId,
role,
@@ -55,23 +76,11 @@ const hasAccessToFilesViaAgent = async ({ userId, role, fileIds, agentId, isDele
requiredPermission: PermissionBits.EDIT,
});
- // If user only has VIEW permission, they can't access files
- // Only users with EDIT permission or higher can access agent files
if (!hasEditPermission) {
return accessMap;
}
}
- const attachedFileIds = new Set();
- if (agent.tool_resources) {
- for (const [_resourceType, resource] of Object.entries(agent.tool_resources)) {
- if (resource?.file_ids && Array.isArray(resource.file_ids)) {
- resource.file_ids.forEach((fileId) => attachedFileIds.add(fileId));
- }
- }
- }
-
- // Grant access only to files that are attached to this agent
fileIds.forEach((fileId) => {
if (attachedFileIds.has(fileId)) {
accessMap.set(fileId, true);
@@ -95,7 +104,7 @@ const hasAccessToFilesViaAgent = async ({ userId, role, fileIds, agentId, isDele
* @returns {Promise>} Filtered array of accessible files
*/
const filterFilesByAgentAccess = async ({ files, userId, role, agentId }) => {
- if (!userId || !agentId || !files || files.length === 0) {
+ if (!userId || !agentId || !files || files.length === 0 || isEphemeralAgentId(agentId)) {
return files;
}
diff --git a/api/server/services/Files/permissions.spec.js b/api/server/services/Files/permissions.spec.js
new file mode 100644
index 0000000000..c926e83464
--- /dev/null
+++ b/api/server/services/Files/permissions.spec.js
@@ -0,0 +1,409 @@
+jest.mock('@librechat/data-schemas', () => ({
+ logger: { error: jest.fn() },
+}));
+
+jest.mock('~/server/services/PermissionService', () => ({
+ checkPermission: jest.fn(),
+}));
+
+jest.mock('~/models', () => ({
+ getAgent: jest.fn(),
+}));
+
+const { logger } = require('@librechat/data-schemas');
+const { Constants, PermissionBits, ResourceType } = require('librechat-data-provider');
+const { checkPermission } = require('~/server/services/PermissionService');
+const { getAgent } = require('~/models');
+const { filterFilesByAgentAccess, hasAccessToFilesViaAgent } = require('./permissions');
+
+const AUTHOR_ID = 'author-user-id';
+const USER_ID = 'viewer-user-id';
+const AGENT_ID = 'agent_test-abc123';
+const AGENT_MONGO_ID = 'mongo-agent-id';
+
+function makeFile(file_id, user) {
+ return { file_id, user, filename: `${file_id}.txt` };
+}
+
+function makeAgent(overrides = {}) {
+ return {
+ _id: AGENT_MONGO_ID,
+ id: AGENT_ID,
+ author: AUTHOR_ID,
+ tool_resources: {
+ file_search: { file_ids: ['attached-1', 'attached-2'] },
+ execute_code: { file_ids: ['attached-3'] },
+ },
+ ...overrides,
+ };
+}
+
+beforeEach(() => {
+ jest.clearAllMocks();
+});
+
+describe('filterFilesByAgentAccess', () => {
+ describe('early returns (no DB calls)', () => {
+ it('should return files unfiltered for ephemeral agentId', async () => {
+ const files = [makeFile('f1', 'other-user')];
+ const result = await filterFilesByAgentAccess({
+ files,
+ userId: USER_ID,
+ agentId: Constants.EPHEMERAL_AGENT_ID,
+ });
+
+ expect(result).toBe(files);
+ expect(getAgent).not.toHaveBeenCalled();
+ });
+
+ it('should return files unfiltered for non-agent_ prefixed agentId', async () => {
+ const files = [makeFile('f1', 'other-user')];
+ const result = await filterFilesByAgentAccess({
+ files,
+ userId: USER_ID,
+ agentId: 'custom-memory-id',
+ });
+
+ expect(result).toBe(files);
+ expect(getAgent).not.toHaveBeenCalled();
+ });
+
+ it('should return files when userId is missing', async () => {
+ const files = [makeFile('f1', 'someone')];
+ const result = await filterFilesByAgentAccess({
+ files,
+ userId: undefined,
+ agentId: AGENT_ID,
+ });
+
+ expect(result).toBe(files);
+ expect(getAgent).not.toHaveBeenCalled();
+ });
+
+ it('should return files when agentId is missing', async () => {
+ const files = [makeFile('f1', 'someone')];
+ const result = await filterFilesByAgentAccess({
+ files,
+ userId: USER_ID,
+ agentId: undefined,
+ });
+
+ expect(result).toBe(files);
+ expect(getAgent).not.toHaveBeenCalled();
+ });
+
+ it('should return empty array when files is empty', async () => {
+ const result = await filterFilesByAgentAccess({
+ files: [],
+ userId: USER_ID,
+ agentId: AGENT_ID,
+ });
+
+ expect(result).toEqual([]);
+ expect(getAgent).not.toHaveBeenCalled();
+ });
+
+ it('should return undefined when files is nullish', async () => {
+ const result = await filterFilesByAgentAccess({
+ files: null,
+ userId: USER_ID,
+ agentId: AGENT_ID,
+ });
+
+ expect(result).toBeNull();
+ expect(getAgent).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('all files owned by userId', () => {
+ it('should return all files without calling getAgent', async () => {
+ const files = [makeFile('f1', USER_ID), makeFile('f2', USER_ID)];
+ const result = await filterFilesByAgentAccess({
+ files,
+ userId: USER_ID,
+ agentId: AGENT_ID,
+ });
+
+ expect(result).toEqual(files);
+ expect(getAgent).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('mixed owned and non-owned files', () => {
+ const ownedFile = makeFile('owned-1', USER_ID);
+ const sharedFile = makeFile('attached-1', AUTHOR_ID);
+ const unattachedFile = makeFile('not-attached', AUTHOR_ID);
+
+ it('should return owned + accessible non-owned files when user has VIEW', async () => {
+ getAgent.mockResolvedValue(makeAgent());
+ checkPermission.mockResolvedValue(true);
+
+ const result = await filterFilesByAgentAccess({
+ files: [ownedFile, sharedFile, unattachedFile],
+ userId: USER_ID,
+ role: 'USER',
+ agentId: AGENT_ID,
+ });
+
+ expect(result).toHaveLength(2);
+ expect(result.map((f) => f.file_id)).toContain('owned-1');
+ expect(result.map((f) => f.file_id)).toContain('attached-1');
+ expect(result.map((f) => f.file_id)).not.toContain('not-attached');
+ });
+
+ it('should return only owned files when user lacks VIEW permission', async () => {
+ getAgent.mockResolvedValue(makeAgent());
+ checkPermission.mockResolvedValue(false);
+
+ const result = await filterFilesByAgentAccess({
+ files: [ownedFile, sharedFile],
+ userId: USER_ID,
+ role: 'USER',
+ agentId: AGENT_ID,
+ });
+
+ expect(result).toEqual([ownedFile]);
+ });
+
+ it('should return only owned files when agent is not found', async () => {
+ getAgent.mockResolvedValue(null);
+
+ const result = await filterFilesByAgentAccess({
+ files: [ownedFile, sharedFile],
+ userId: USER_ID,
+ agentId: AGENT_ID,
+ });
+
+ expect(result).toEqual([ownedFile]);
+ });
+
+ it('should return only owned files on DB error (fail-closed)', async () => {
+ getAgent.mockRejectedValue(new Error('DB connection lost'));
+
+ const result = await filterFilesByAgentAccess({
+ files: [ownedFile, sharedFile],
+ userId: USER_ID,
+ agentId: AGENT_ID,
+ });
+
+ expect(result).toEqual([ownedFile]);
+ expect(logger.error).toHaveBeenCalled();
+ });
+ });
+
+ describe('file with no user field', () => {
+ it('should treat file as non-owned and run through access check', async () => {
+ const noUserFile = makeFile('attached-1', undefined);
+ getAgent.mockResolvedValue(makeAgent());
+ checkPermission.mockResolvedValue(true);
+
+ const result = await filterFilesByAgentAccess({
+ files: [noUserFile],
+ userId: USER_ID,
+ role: 'USER',
+ agentId: AGENT_ID,
+ });
+
+ expect(getAgent).toHaveBeenCalled();
+ expect(result).toEqual([noUserFile]);
+ });
+
+ it('should exclude file with no user field when not attached to agent', async () => {
+ const noUserFile = makeFile('not-attached', null);
+ getAgent.mockResolvedValue(makeAgent());
+ checkPermission.mockResolvedValue(true);
+
+ const result = await filterFilesByAgentAccess({
+ files: [noUserFile],
+ userId: USER_ID,
+ role: 'USER',
+ agentId: AGENT_ID,
+ });
+
+ expect(result).toEqual([]);
+ });
+ });
+
+ describe('no owned files (all non-owned)', () => {
+ const file1 = makeFile('attached-1', AUTHOR_ID);
+ const file2 = makeFile('not-attached', AUTHOR_ID);
+
+ it('should return only attached files when user has VIEW', async () => {
+ getAgent.mockResolvedValue(makeAgent());
+ checkPermission.mockResolvedValue(true);
+
+ const result = await filterFilesByAgentAccess({
+ files: [file1, file2],
+ userId: USER_ID,
+ role: 'USER',
+ agentId: AGENT_ID,
+ });
+
+ expect(result).toEqual([file1]);
+ });
+
+ it('should return empty array when no VIEW permission', async () => {
+ getAgent.mockResolvedValue(makeAgent());
+ checkPermission.mockResolvedValue(false);
+
+ const result = await filterFilesByAgentAccess({
+ files: [file1, file2],
+ userId: USER_ID,
+ agentId: AGENT_ID,
+ });
+
+ expect(result).toEqual([]);
+ });
+
+ it('should return empty array when agent not found', async () => {
+ getAgent.mockResolvedValue(null);
+
+ const result = await filterFilesByAgentAccess({
+ files: [file1],
+ userId: USER_ID,
+ agentId: AGENT_ID,
+ });
+
+ expect(result).toEqual([]);
+ });
+ });
+});
+
+describe('hasAccessToFilesViaAgent', () => {
+ describe('agent not found', () => {
+ it('should return all-false map', async () => {
+ getAgent.mockResolvedValue(null);
+
+ const result = await hasAccessToFilesViaAgent({
+ userId: USER_ID,
+ fileIds: ['f1', 'f2'],
+ agentId: AGENT_ID,
+ });
+
+ expect(result.get('f1')).toBe(false);
+ expect(result.get('f2')).toBe(false);
+ });
+ });
+
+ describe('author path', () => {
+ it('should grant access to attached files for the agent author', async () => {
+ getAgent.mockResolvedValue(makeAgent());
+
+ const result = await hasAccessToFilesViaAgent({
+ userId: AUTHOR_ID,
+ fileIds: ['attached-1', 'not-attached'],
+ agentId: AGENT_ID,
+ });
+
+ expect(result.get('attached-1')).toBe(true);
+ expect(result.get('not-attached')).toBe(false);
+ expect(checkPermission).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('VIEW permission path', () => {
+ it('should grant access to attached files for viewer with VIEW permission', async () => {
+ getAgent.mockResolvedValue(makeAgent());
+ checkPermission.mockResolvedValue(true);
+
+ const result = await hasAccessToFilesViaAgent({
+ userId: USER_ID,
+ role: 'USER',
+ fileIds: ['attached-1', 'attached-3', 'not-attached'],
+ agentId: AGENT_ID,
+ });
+
+ expect(result.get('attached-1')).toBe(true);
+ expect(result.get('attached-3')).toBe(true);
+ expect(result.get('not-attached')).toBe(false);
+
+ expect(checkPermission).toHaveBeenCalledWith({
+ userId: USER_ID,
+ role: 'USER',
+ resourceType: ResourceType.AGENT,
+ resourceId: AGENT_MONGO_ID,
+ requiredPermission: PermissionBits.VIEW,
+ });
+ });
+
+ it('should deny all when VIEW permission is missing', async () => {
+ getAgent.mockResolvedValue(makeAgent());
+ checkPermission.mockResolvedValue(false);
+
+ const result = await hasAccessToFilesViaAgent({
+ userId: USER_ID,
+ fileIds: ['attached-1'],
+ agentId: AGENT_ID,
+ });
+
+ expect(result.get('attached-1')).toBe(false);
+ });
+ });
+
+ describe('delete path (EDIT permission required)', () => {
+ it('should grant access when both VIEW and EDIT pass', async () => {
+ getAgent.mockResolvedValue(makeAgent());
+ checkPermission.mockResolvedValueOnce(true).mockResolvedValueOnce(true);
+
+ const result = await hasAccessToFilesViaAgent({
+ userId: USER_ID,
+ fileIds: ['attached-1'],
+ agentId: AGENT_ID,
+ isDelete: true,
+ });
+
+ expect(result.get('attached-1')).toBe(true);
+ expect(checkPermission).toHaveBeenCalledTimes(2);
+ expect(checkPermission).toHaveBeenLastCalledWith(
+ expect.objectContaining({ requiredPermission: PermissionBits.EDIT }),
+ );
+ });
+
+ it('should deny all when VIEW passes but EDIT fails', async () => {
+ getAgent.mockResolvedValue(makeAgent());
+ checkPermission.mockResolvedValueOnce(true).mockResolvedValueOnce(false);
+
+ const result = await hasAccessToFilesViaAgent({
+ userId: USER_ID,
+ fileIds: ['attached-1'],
+ agentId: AGENT_ID,
+ isDelete: true,
+ });
+
+ expect(result.get('attached-1')).toBe(false);
+ });
+ });
+
+ describe('error handling', () => {
+ it('should return all-false map on DB error (fail-closed)', async () => {
+ getAgent.mockRejectedValue(new Error('connection refused'));
+
+ const result = await hasAccessToFilesViaAgent({
+ userId: USER_ID,
+ fileIds: ['f1', 'f2'],
+ agentId: AGENT_ID,
+ });
+
+ expect(result.get('f1')).toBe(false);
+ expect(result.get('f2')).toBe(false);
+ expect(logger.error).toHaveBeenCalledWith(
+ '[hasAccessToFilesViaAgent] Error checking file access:',
+ expect.any(Error),
+ );
+ });
+ });
+
+ describe('agent with no tool_resources', () => {
+ it('should deny all files even for the author', async () => {
+ getAgent.mockResolvedValue(makeAgent({ tool_resources: undefined }));
+
+ const result = await hasAccessToFilesViaAgent({
+ userId: AUTHOR_ID,
+ fileIds: ['f1'],
+ agentId: AGENT_ID,
+ });
+
+ expect(result.get('f1')).toBe(false);
+ });
+ });
+});
diff --git a/api/server/services/Files/process.js b/api/server/services/Files/process.js
index 30b47f2e52..f7d7731975 100644
--- a/api/server/services/Files/process.js
+++ b/api/server/services/Files/process.js
@@ -16,6 +16,7 @@ const {
removeNullishValues,
isAssistantsEndpoint,
getEndpointFileConfig,
+ documentParserMimeTypes,
} = require('librechat-data-provider');
const { EnvVar } = require('@librechat/agents');
const { logger } = require('@librechat/data-schemas');
@@ -26,16 +27,15 @@ const {
resizeImageBuffer,
} = require('~/server/services/Files/images');
const { addResourceFileId, deleteResourceFileId } = require('~/server/controllers/assistants/v2');
-const { addAgentResourceFile, removeAgentResourceFiles } = require('~/models/Agent');
const { getOpenAIClient } = require('~/server/controllers/assistants/helpers');
const { loadAuthValues } = require('~/server/services/Tools/credentials');
-const { createFile, updateFileUsage, deleteFiles } = require('~/models');
const { getFileStrategy } = require('~/server/utils/getFileStrategy');
const { checkCapability } = require('~/server/services/Config');
const { LB_QueueAsyncCall } = require('~/server/utils/queue');
const { getStrategyFunctions } = require('./strategies');
const { determineFileType } = require('~/server/utils');
const { STTService } = require('./Audio/STTService');
+const db = require('~/models');
/**
* Creates a modular file upload wrapper that ensures filename sanitization
@@ -210,7 +210,7 @@ const processDeleteRequest = async ({ req, files }) => {
if (agentFiles.length > 0) {
promises.push(
- removeAgentResourceFiles({
+ db.removeAgentResourceFiles({
agent_id: req.body.agent_id,
files: agentFiles,
}),
@@ -218,7 +218,7 @@ const processDeleteRequest = async ({ req, files }) => {
}
await Promise.allSettled(promises);
- await deleteFiles(resolvedFileIds);
+ await db.deleteFiles(resolvedFileIds);
};
/**
@@ -250,7 +250,7 @@ const processFileURL = async ({ fileStrategy, userId, URL, fileName, basePath, c
dimensions = {},
} = (await saveURL({ userId, URL, fileName, basePath })) || {};
const filepath = await getFileURL({ fileName: `${userId}/${fileName}`, basePath });
- return await createFile(
+ return await db.createFile(
{
user: userId,
file_id: v4(),
@@ -296,7 +296,7 @@ const processImageFile = async ({ req, res, metadata, returnFile = false }) => {
endpoint,
});
- const result = await createFile(
+ const result = await db.createFile(
{
user: req.user.id,
file_id,
@@ -348,7 +348,7 @@ const uploadImageBuffer = async ({ req, context, metadata = {}, resize = true })
}
const fileName = `${file_id}-${filename}`;
const filepath = await saveBuffer({ userId: req.user.id, fileName, buffer });
- return await createFile(
+ return await db.createFile(
{
user: req.user.id,
file_id,
@@ -434,7 +434,7 @@ const processFileUpload = async ({ req, res, metadata }) => {
filepath = result.filepath;
}
- const result = await createFile(
+ const result = await db.createFile(
{
user: req.user.id,
file_id: id ?? file_id,
@@ -523,6 +523,12 @@ const processAgentFileUpload = async ({ req, res, metadata }) => {
* @return {Promise}
*/
const createTextFile = async ({ text, bytes, filepath, type = 'text/plain' }) => {
+ const textBytes = Buffer.byteLength(text, 'utf8');
+ if (textBytes > 15 * megabyte) {
+ throw new Error(
+ `Extracted text from "${file.originalname}" exceeds the 15MB storage limit (${Math.round(textBytes / megabyte)}MB). Try a shorter document.`,
+ );
+ }
const fileInfo = removeNullishValues({
text,
bytes,
@@ -538,14 +544,14 @@ const processAgentFileUpload = async ({ req, res, metadata }) => {
});
if (!messageAttachment && tool_resource) {
- await addAgentResourceFile({
- req,
+ await db.addAgentResourceFile({
file_id,
agent_id,
tool_resource,
+ updatingUserId: req?.user?.id,
});
}
- const result = await createFile(fileInfo, true);
+ const result = await db.createFile(fileInfo, true);
return res
.status(200)
.json({ message: 'Agent file uploaded and processed successfully', ...result });
@@ -553,29 +559,52 @@ const processAgentFileUpload = async ({ req, res, metadata }) => {
const fileConfig = mergeFileConfig(appConfig.fileConfig);
- const shouldUseOCR =
+ const shouldUseConfiguredOCR =
appConfig?.ocr != null &&
fileConfig.checkType(file.mimetype, fileConfig.ocr?.supportedMimeTypes || []);
- if (shouldUseOCR && !(await checkCapability(req, AgentCapabilities.ocr))) {
- throw new Error('OCR capability is not enabled for Agents');
- } else if (shouldUseOCR) {
+ const shouldUseDocumentParser =
+ !shouldUseConfiguredOCR && documentParserMimeTypes.some((regex) => regex.test(file.mimetype));
+
+ const shouldUseOCR = shouldUseConfiguredOCR || shouldUseDocumentParser;
+
+ const resolveDocumentText = async () => {
+ if (shouldUseConfiguredOCR) {
+ try {
+ const ocrStrategy = appConfig?.ocr?.strategy ?? FileSources.document_parser;
+ const { handleFileUpload } = getStrategyFunctions(ocrStrategy);
+ return await handleFileUpload({ req, file, loadAuthValues });
+ } catch (err) {
+ logger.error(
+ `[processAgentFileUpload] Configured OCR failed for "${file.originalname}", falling back to document_parser:`,
+ err,
+ );
+ }
+ }
try {
- const { handleFileUpload: uploadOCR } = getStrategyFunctions(
- appConfig?.ocr?.strategy ?? FileSources.mistral_ocr,
- );
- const {
- text,
- bytes,
- filepath: ocrFileURL,
- } = await uploadOCR({ req, file, loadAuthValues });
- return await createTextFile({ text, bytes, filepath: ocrFileURL });
- } catch (ocrError) {
+ const { handleFileUpload } = getStrategyFunctions(FileSources.document_parser);
+ return await handleFileUpload({ req, file, loadAuthValues });
+ } catch (err) {
logger.error(
- `[processAgentFileUpload] OCR processing failed for file "${file.originalname}", falling back to text extraction:`,
- ocrError,
+ `[processAgentFileUpload] Document parser failed for "${file.originalname}":`,
+ err,
);
}
+ };
+
+ if (shouldUseConfiguredOCR && !(await checkCapability(req, AgentCapabilities.ocr))) {
+ throw new Error('OCR capability is not enabled for Agents');
+ }
+
+ if (shouldUseOCR) {
+ const ocrResult = await resolveDocumentText();
+ if (ocrResult) {
+ const { text, bytes, filepath: ocrFileURL } = ocrResult;
+ return await createTextFile({ text, bytes, filepath: ocrFileURL });
+ }
+ throw new Error(
+ `Unable to extract text from "${file.originalname}". The document may be image-based and requires an OCR service to process.`,
+ );
}
const shouldUseSTT = fileConfig.checkType(
@@ -655,11 +684,11 @@ const processAgentFileUpload = async ({ req, res, metadata }) => {
let filepath = _filepath;
if (!messageAttachment && tool_resource) {
- await addAgentResourceFile({
- req,
+ await db.addAgentResourceFile({
file_id,
agent_id,
tool_resource,
+ updatingUserId: req?.user?.id,
});
}
@@ -690,7 +719,7 @@ const processAgentFileUpload = async ({ req, res, metadata }) => {
width,
});
- const result = await createFile(fileInfo, true);
+ const result = await db.createFile(fileInfo, true);
res.status(200).json({ message: 'Agent file uploaded and processed successfully', ...result });
};
@@ -736,10 +765,10 @@ const processOpenAIFile = async ({
};
if (saveFile) {
- await createFile(file, true);
+ await db.createFile(file, true);
} else if (updateUsage) {
try {
- await updateFileUsage({ file_id });
+ await db.updateFileUsage({ file_id });
} catch (error) {
logger.error('Error updating file usage', error);
}
@@ -777,7 +806,7 @@ const processOpenAIImageOutput = async ({ req, buffer, file_id, filename, fileEx
file_id,
filename,
};
- createFile(file, true);
+ db.createFile(file, true);
return file;
};
@@ -921,7 +950,7 @@ async function saveBase64Image(
fileName: filename,
buffer: image.buffer,
});
- return await createFile(
+ return await db.createFile(
{
type,
source,
diff --git a/api/server/services/Files/process.spec.js b/api/server/services/Files/process.spec.js
new file mode 100644
index 0000000000..39300161a8
--- /dev/null
+++ b/api/server/services/Files/process.spec.js
@@ -0,0 +1,344 @@
+jest.mock('uuid', () => ({ v4: jest.fn(() => 'mock-uuid') }));
+
+jest.mock('@librechat/data-schemas', () => ({
+ logger: { warn: jest.fn(), debug: jest.fn(), error: jest.fn() },
+}));
+
+jest.mock('@librechat/agents', () => ({
+ EnvVar: { CODE_API_KEY: 'CODE_API_KEY' },
+}));
+
+jest.mock('@librechat/api', () => ({
+ sanitizeFilename: jest.fn((n) => n),
+ parseText: jest.fn().mockResolvedValue({ text: '', bytes: 0 }),
+ processAudioFile: jest.fn(),
+}));
+
+jest.mock('librechat-data-provider', () => ({
+ ...jest.requireActual('librechat-data-provider'),
+ mergeFileConfig: jest.fn(),
+}));
+
+jest.mock('~/server/services/Files/images', () => ({
+ convertImage: jest.fn(),
+ resizeAndConvert: jest.fn(),
+ resizeImageBuffer: jest.fn(),
+}));
+
+jest.mock('~/server/controllers/assistants/v2', () => ({
+ addResourceFileId: jest.fn(),
+ deleteResourceFileId: jest.fn(),
+}));
+
+jest.mock('~/server/controllers/assistants/helpers', () => ({
+ getOpenAIClient: jest.fn(),
+}));
+
+jest.mock('~/server/services/Tools/credentials', () => ({
+ loadAuthValues: jest.fn(),
+}));
+
+jest.mock('~/models', () => ({
+ createFile: jest.fn().mockResolvedValue({ file_id: 'created-file-id' }),
+ updateFileUsage: jest.fn(),
+ deleteFiles: jest.fn(),
+ addAgentResourceFile: jest.fn().mockResolvedValue({}),
+ removeAgentResourceFiles: jest.fn(),
+}));
+
+jest.mock('~/server/utils/getFileStrategy', () => ({
+ getFileStrategy: jest.fn().mockReturnValue('local'),
+}));
+
+jest.mock('~/server/services/Config', () => ({
+ checkCapability: jest.fn().mockResolvedValue(true),
+}));
+
+jest.mock('~/server/utils/queue', () => ({
+ LB_QueueAsyncCall: jest.fn(),
+}));
+
+jest.mock('~/server/services/Files/strategies', () => ({
+ getStrategyFunctions: jest.fn(),
+}));
+
+jest.mock('~/server/utils', () => ({
+ determineFileType: jest.fn(),
+}));
+
+jest.mock('~/server/services/Files/Audio/STTService', () => ({
+ STTService: { getInstance: jest.fn() },
+}));
+
+const { EToolResources, FileSources, AgentCapabilities } = require('librechat-data-provider');
+const { mergeFileConfig } = require('librechat-data-provider');
+const { checkCapability } = require('~/server/services/Config');
+const { getStrategyFunctions } = require('~/server/services/Files/strategies');
+const { processAgentFileUpload } = require('./process');
+
+const PDF_MIME = 'application/pdf';
+const DOCX_MIME = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
+const XLSX_MIME = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
+const XLS_MIME = 'application/vnd.ms-excel';
+const ODS_MIME = 'application/vnd.oasis.opendocument.spreadsheet';
+const ODT_MIME = 'application/vnd.oasis.opendocument.text';
+const ODP_MIME = 'application/vnd.oasis.opendocument.presentation';
+const ODG_MIME = 'application/vnd.oasis.opendocument.graphics';
+
+const makeReq = ({ mimetype = PDF_MIME, ocrConfig = null } = {}) => ({
+ user: { id: 'user-123' },
+ file: {
+ path: '/tmp/upload.bin',
+ originalname: 'upload.bin',
+ filename: 'upload-uuid.bin',
+ mimetype,
+ },
+ body: { model: 'gpt-4o' },
+ config: {
+ fileConfig: {},
+ fileStrategy: 'local',
+ ocr: ocrConfig,
+ },
+});
+
+const makeMetadata = () => ({
+ agent_id: 'agent-abc',
+ tool_resource: EToolResources.context,
+ file_id: 'file-uuid-123',
+});
+
+const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnValue({}),
+};
+
+const makeFileConfig = ({ ocrSupportedMimeTypes = [] } = {}) => ({
+ checkType: (mime, types) => (types ?? []).includes(mime),
+ ocr: { supportedMimeTypes: ocrSupportedMimeTypes },
+ stt: { supportedMimeTypes: [] },
+ text: { supportedMimeTypes: [] },
+});
+
+describe('processAgentFileUpload', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ mockRes.status.mockReturnThis();
+ mockRes.json.mockReturnValue({});
+ checkCapability.mockResolvedValue(true);
+ getStrategyFunctions.mockReturnValue({
+ handleFileUpload: jest
+ .fn()
+ .mockResolvedValue({ text: 'extracted text', bytes: 42, filepath: 'doc://result' }),
+ });
+ mergeFileConfig.mockReturnValue(makeFileConfig());
+ });
+
+ describe('OCR strategy selection', () => {
+ test.each([
+ ['PDF', PDF_MIME],
+ ['DOCX', DOCX_MIME],
+ ['XLSX', XLSX_MIME],
+ ['XLS', XLS_MIME],
+ ['ODS', ODS_MIME],
+ ['Excel variant (msexcel)', 'application/msexcel'],
+ ['Excel variant (x-msexcel)', 'application/x-msexcel'],
+ ])('uses document_parser automatically for %s when no OCR is configured', async (_, mime) => {
+ mergeFileConfig.mockReturnValue(makeFileConfig());
+ const req = makeReq({ mimetype: mime, ocrConfig: null });
+
+ await processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() });
+
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.document_parser);
+ });
+
+ test('does not check OCR capability when using automatic document_parser fallback', async () => {
+ const req = makeReq({ mimetype: PDF_MIME, ocrConfig: null });
+
+ await processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() });
+
+ expect(checkCapability).not.toHaveBeenCalledWith(expect.anything(), AgentCapabilities.ocr);
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.document_parser);
+ });
+
+ test('uses the configured OCR strategy when OCR is set up for the file type', async () => {
+ mergeFileConfig.mockReturnValue(makeFileConfig({ ocrSupportedMimeTypes: [PDF_MIME] }));
+ const req = makeReq({
+ mimetype: PDF_MIME,
+ ocrConfig: { strategy: FileSources.mistral_ocr },
+ });
+
+ await processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() });
+
+ expect(checkCapability).toHaveBeenCalledWith(expect.anything(), AgentCapabilities.ocr);
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.mistral_ocr);
+ });
+
+ test('uses document_parser as default when OCR is configured but no strategy is specified', async () => {
+ mergeFileConfig.mockReturnValue(makeFileConfig({ ocrSupportedMimeTypes: [PDF_MIME] }));
+ const req = makeReq({
+ mimetype: PDF_MIME,
+ ocrConfig: { supportedMimeTypes: [PDF_MIME] },
+ });
+
+ await processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() });
+
+ expect(checkCapability).toHaveBeenCalledWith(expect.anything(), AgentCapabilities.ocr);
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.document_parser);
+ });
+
+ test('throws when configured OCR capability is not enabled for the agent', async () => {
+ mergeFileConfig.mockReturnValue(makeFileConfig({ ocrSupportedMimeTypes: [PDF_MIME] }));
+ checkCapability.mockResolvedValue(false);
+ const req = makeReq({
+ mimetype: PDF_MIME,
+ ocrConfig: { strategy: FileSources.mistral_ocr },
+ });
+
+ await expect(
+ processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() }),
+ ).rejects.toThrow('OCR capability is not enabled for Agents');
+ });
+
+ test('uses document_parser (no capability check) when OCR capability returns false but no OCR config', async () => {
+ checkCapability.mockResolvedValue(false);
+ const req = makeReq({ mimetype: PDF_MIME, ocrConfig: null });
+
+ await processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() });
+
+ expect(checkCapability).not.toHaveBeenCalledWith(expect.anything(), AgentCapabilities.ocr);
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.document_parser);
+ });
+
+ test('uses document_parser when OCR is configured but the file type is not in OCR supported types', async () => {
+ mergeFileConfig.mockReturnValue(makeFileConfig({ ocrSupportedMimeTypes: [PDF_MIME] }));
+ const req = makeReq({
+ mimetype: DOCX_MIME,
+ ocrConfig: { strategy: FileSources.mistral_ocr },
+ });
+
+ await processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() });
+
+ expect(checkCapability).not.toHaveBeenCalledWith(expect.anything(), AgentCapabilities.ocr);
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.document_parser);
+ expect(getStrategyFunctions).not.toHaveBeenCalledWith(FileSources.mistral_ocr);
+ });
+
+ test('does not invoke any OCR strategy for unsupported MIME types without OCR config', async () => {
+ const req = makeReq({ mimetype: 'text/plain', ocrConfig: null });
+
+ await expect(
+ processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() }),
+ ).rejects.toThrow('File type text/plain is not supported for text parsing.');
+
+ expect(getStrategyFunctions).not.toHaveBeenCalled();
+ });
+
+ test.each([
+ ['ODT', ODT_MIME],
+ ['ODP', ODP_MIME],
+ ['ODG', ODG_MIME],
+ ])('routes %s through configured OCR when OCR supports the type', async (_, mime) => {
+ mergeFileConfig.mockReturnValue(makeFileConfig({ ocrSupportedMimeTypes: [mime] }));
+ const req = makeReq({
+ mimetype: mime,
+ ocrConfig: { strategy: FileSources.mistral_ocr },
+ });
+
+ await processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() });
+
+ expect(checkCapability).toHaveBeenCalledWith(expect.anything(), AgentCapabilities.ocr);
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.mistral_ocr);
+ });
+
+ test('throws instead of falling back to parseText when document_parser fails for a document MIME type', async () => {
+ getStrategyFunctions.mockReturnValue({
+ handleFileUpload: jest.fn().mockRejectedValue(new Error('No text found in document')),
+ });
+ const req = makeReq({ mimetype: PDF_MIME, ocrConfig: null });
+ const { parseText } = require('@librechat/api');
+
+ await expect(
+ processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() }),
+ ).rejects.toThrow(/image-based and requires an OCR service/);
+
+ expect(parseText).not.toHaveBeenCalled();
+ });
+
+ test('falls back to document_parser when configured OCR fails for a document MIME type', async () => {
+ mergeFileConfig.mockReturnValue(makeFileConfig({ ocrSupportedMimeTypes: [PDF_MIME] }));
+ const failingUpload = jest.fn().mockRejectedValue(new Error('OCR API returned 500'));
+ const fallbackUpload = jest
+ .fn()
+ .mockResolvedValue({ text: 'parsed text', bytes: 11, filepath: 'doc://result' });
+ getStrategyFunctions
+ .mockReturnValueOnce({ handleFileUpload: failingUpload })
+ .mockReturnValueOnce({ handleFileUpload: fallbackUpload });
+ const req = makeReq({
+ mimetype: PDF_MIME,
+ ocrConfig: { strategy: FileSources.mistral_ocr },
+ });
+
+ await expect(
+ processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() }),
+ ).resolves.not.toThrow();
+
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.mistral_ocr);
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.document_parser);
+ });
+
+ test('throws when both configured OCR and document_parser fallback fail', async () => {
+ mergeFileConfig.mockReturnValue(makeFileConfig({ ocrSupportedMimeTypes: [PDF_MIME] }));
+ getStrategyFunctions.mockReturnValue({
+ handleFileUpload: jest.fn().mockRejectedValue(new Error('failure')),
+ });
+ const req = makeReq({
+ mimetype: PDF_MIME,
+ ocrConfig: { strategy: FileSources.mistral_ocr },
+ });
+ const { parseText } = require('@librechat/api');
+
+ await expect(
+ processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() }),
+ ).rejects.toThrow(/image-based and requires an OCR service/);
+
+ expect(parseText).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('text size guard', () => {
+ test('throws before writing to MongoDB when extracted text exceeds 15MB', async () => {
+ const oversizedText = 'x'.repeat(15 * 1024 * 1024 + 1);
+ getStrategyFunctions.mockReturnValue({
+ handleFileUpload: jest.fn().mockResolvedValue({
+ text: oversizedText,
+ bytes: Buffer.byteLength(oversizedText, 'utf8'),
+ filepath: 'doc://result',
+ }),
+ });
+ const req = makeReq({ mimetype: PDF_MIME, ocrConfig: null });
+ const { createFile } = require('~/models');
+
+ await expect(
+ processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() }),
+ ).rejects.toThrow(/exceeds the 15MB storage limit/);
+
+ expect(createFile).not.toHaveBeenCalled();
+ });
+
+ test('succeeds when extracted text is within the 15MB limit', async () => {
+ const okText = 'x'.repeat(1024);
+ getStrategyFunctions.mockReturnValue({
+ handleFileUpload: jest.fn().mockResolvedValue({
+ text: okText,
+ bytes: Buffer.byteLength(okText, 'utf8'),
+ filepath: 'doc://result',
+ }),
+ });
+ const req = makeReq({ mimetype: PDF_MIME, ocrConfig: null });
+
+ await expect(
+ processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() }),
+ ).resolves.not.toThrow();
+ });
+ });
+});
diff --git a/api/server/services/Files/strategies.js b/api/server/services/Files/strategies.js
index 2ad526194b..47b39cb87b 100644
--- a/api/server/services/Files/strategies.js
+++ b/api/server/services/Files/strategies.js
@@ -1,5 +1,13 @@
const { FileSources } = require('librechat-data-provider');
const {
+ getS3URL,
+ saveURLToS3,
+ parseDocument,
+ uploadFileToS3,
+ S3ImageService,
+ saveBufferToS3,
+ getS3FileStream,
+ deleteFileFromS3,
uploadMistralOCR,
uploadAzureMistralOCR,
uploadGoogleVertexMistralOCR,
@@ -26,17 +34,18 @@ const {
processLocalAvatar,
getLocalFileStream,
} = require('./Local');
-const {
- getS3URL,
- saveURLToS3,
- saveBufferToS3,
- getS3FileStream,
- uploadImageToS3,
- prepareImageURLS3,
- deleteFileFromS3,
- processS3Avatar,
- uploadFileToS3,
-} = require('./S3');
+const { resizeImageBuffer } = require('./images/resize');
+const { updateUser, updateFile } = require('~/models');
+
+const s3ImageService = new S3ImageService({
+ resizeImageBuffer,
+ updateUser,
+ updateFile,
+});
+
+const uploadImageToS3 = (params) => s3ImageService.uploadImageToS3(params);
+const prepareImageURLS3 = (_req, file) => s3ImageService.prepareImageURL(file);
+const processS3Avatar = (params) => s3ImageService.processAvatar(params);
const {
saveBufferToAzure,
saveURLToAzure,
@@ -246,6 +255,26 @@ const vertexMistralOCRStrategy = () => ({
handleFileUpload: uploadGoogleVertexMistralOCR,
});
+const documentParserStrategy = () => ({
+ /** @type {typeof saveFileFromURL | null} */
+ saveURL: null,
+ /** @type {typeof getLocalFileURL | null} */
+ getFileURL: null,
+ /** @type {typeof saveLocalBuffer | null} */
+ saveBuffer: null,
+ /** @type {typeof processLocalAvatar | null} */
+ processAvatar: null,
+ /** @type {typeof uploadLocalImage | null} */
+ handleImageUpload: null,
+ /** @type {typeof prepareImagesLocal | null} */
+ prepareImagePayload: null,
+ /** @type {typeof deleteLocalFile | null} */
+ deleteFile: null,
+ /** @type {typeof getLocalFileStream | null} */
+ getDownloadStream: null,
+ handleFileUpload: parseDocument,
+});
+
// Strategy Selector
const getStrategyFunctions = (fileSource) => {
if (fileSource === FileSources.firebase) {
@@ -270,6 +299,8 @@ const getStrategyFunctions = (fileSource) => {
return azureMistralOCRStrategy();
} else if (fileSource === FileSources.vertexai_mistral_ocr) {
return vertexMistralOCRStrategy();
+ } else if (fileSource === FileSources.document_parser) {
+ return documentParserStrategy();
} else if (fileSource === FileSources.text) {
return localStrategy(); // Text files use local strategy
} else {
diff --git a/api/server/services/GraphTokenService.js b/api/server/services/GraphTokenService.js
index d5cd6a94f2..843adbe5a2 100644
--- a/api/server/services/GraphTokenService.js
+++ b/api/server/services/GraphTokenService.js
@@ -7,7 +7,7 @@ const getLogStores = require('~/cache/getLogStores');
/**
* Get Microsoft Graph API token using existing token exchange mechanism
* @param {Object} user - User object with OpenID information
- * @param {string} accessToken - Current access token from Authorization header
+ * @param {string} accessToken - Federated access token used as OBO assertion
* @param {string} scopes - Graph API scopes for the token
* @param {boolean} fromCache - Whether to try getting token from cache first
* @returns {Promise} Graph API token response with access_token and expires_in
diff --git a/api/server/services/MCP.js b/api/server/services/MCP.js
index ad1f9f5cc3..c66eb0b6ef 100644
--- a/api/server/services/MCP.js
+++ b/api/server/services/MCP.js
@@ -34,6 +34,55 @@ const { reinitMCPServer } = require('./Tools/mcp');
const { getAppConfig } = require('./Config');
const { getLogStores } = require('~/cache');
+const MAX_CACHE_SIZE = 1000;
+const lastReconnectAttempts = new Map();
+const RECONNECT_THROTTLE_MS = 10_000;
+
+const missingToolCache = new Map();
+const MISSING_TOOL_TTL_MS = 10_000;
+
+function evictStale(map, ttl) {
+ if (map.size <= MAX_CACHE_SIZE) {
+ return;
+ }
+ const now = Date.now();
+ for (const [key, timestamp] of map) {
+ if (now - timestamp >= ttl) {
+ map.delete(key);
+ }
+ if (map.size <= MAX_CACHE_SIZE) {
+ return;
+ }
+ }
+}
+
+const unavailableMsg =
+ "This tool's MCP server is temporarily unavailable. Please try again shortly.";
+
+/**
+ * @param {string} toolName
+ * @param {string} serverName
+ */
+function createUnavailableToolStub(toolName, serverName) {
+ const normalizedToolKey = `${toolName}${Constants.mcp_delimiter}${normalizeServerName(serverName)}`;
+ const _call = async () => [unavailableMsg, null];
+ const toolInstance = tool(_call, {
+ schema: {
+ type: 'object',
+ properties: {
+ input: { type: 'string', description: 'Input for the tool' },
+ },
+ required: [],
+ },
+ name: normalizedToolKey,
+ description: unavailableMsg,
+ responseFormat: AgentConstants.CONTENT_AND_ARTIFACT,
+ });
+ toolInstance.mcp = true;
+ toolInstance.mcpRawServerName = serverName;
+ return toolInstance;
+}
+
function isEmptyObjectSchema(jsonSchema) {
return (
jsonSchema != null &&
@@ -211,6 +260,17 @@ async function reconnectServer({
logger.debug(
`[MCP][reconnectServer] serverName: ${serverName}, user: ${user?.id}, hasUserMCPAuthMap: ${!!userMCPAuthMap}`,
);
+
+ const throttleKey = `${user.id}:${serverName}`;
+ const now = Date.now();
+ const lastAttempt = lastReconnectAttempts.get(throttleKey) ?? 0;
+ if (now - lastAttempt < RECONNECT_THROTTLE_MS) {
+ logger.debug(`[MCP][reconnectServer] Throttled reconnect for ${serverName}`);
+ return null;
+ }
+ lastReconnectAttempts.set(throttleKey, now);
+ evictStale(lastReconnectAttempts, RECONNECT_THROTTLE_MS);
+
const runId = Constants.USE_PRELIM_RESPONSE_MESSAGE_ID;
const flowId = `${user.id}:${serverName}:${Date.now()}`;
const flowManager = getFlowStateManager(getLogStores(CacheKeys.FLOWS));
@@ -267,7 +327,7 @@ async function reconnectServer({
userMCPAuthMap,
forceNew: true,
returnOnOAuth: false,
- connectionTimeout: Time.TWO_MINUTES,
+ connectionTimeout: Time.THIRTY_SECONDS,
});
} finally {
// Clean up abort handler to prevent memory leaks
@@ -330,9 +390,13 @@ async function createMCPTools({
userMCPAuthMap,
streamId,
});
+ if (result === null) {
+ logger.debug(`[MCP][${serverName}] Reconnect throttled, skipping tool creation.`);
+ return [];
+ }
if (!result || !result.tools) {
logger.warn(`[MCP][${serverName}] Failed to reinitialize MCP server.`);
- return;
+ return [];
}
const serverTools = [];
@@ -402,6 +466,14 @@ async function createMCPTool({
/** @type {LCTool | undefined} */
let toolDefinition = availableTools?.[toolKey]?.function;
if (!toolDefinition) {
+ const cachedAt = missingToolCache.get(toolKey);
+ if (cachedAt && Date.now() - cachedAt < MISSING_TOOL_TTL_MS) {
+ logger.debug(
+ `[MCP][${serverName}][${toolName}] Tool in negative cache, returning unavailable stub.`,
+ );
+ return createUnavailableToolStub(toolName, serverName);
+ }
+
logger.warn(
`[MCP][${serverName}][${toolName}] Requested tool not found in available tools, re-initializing MCP server.`,
);
@@ -415,11 +487,18 @@ async function createMCPTool({
streamId,
});
toolDefinition = result?.availableTools?.[toolKey]?.function;
+
+ if (!toolDefinition) {
+ missingToolCache.set(toolKey, Date.now());
+ evictStale(missingToolCache, MISSING_TOOL_TTL_MS);
+ }
}
if (!toolDefinition) {
- logger.warn(`[MCP][${serverName}][${toolName}] Tool definition not found, cannot create tool.`);
- return;
+ logger.warn(
+ `[MCP][${serverName}][${toolName}] Tool definition not found, returning unavailable stub.`,
+ );
+ return createUnavailableToolStub(toolName, serverName);
}
return createToolInstance({
@@ -720,4 +799,5 @@ module.exports = {
getMCPSetupData,
checkOAuthFlowStatus,
getServerConnectionStatus,
+ createUnavailableToolStub,
};
diff --git a/api/server/services/MCP.spec.js b/api/server/services/MCP.spec.js
index b2caebc91e..14a9ef90ed 100644
--- a/api/server/services/MCP.spec.js
+++ b/api/server/services/MCP.spec.js
@@ -45,6 +45,7 @@ const {
getMCPSetupData,
checkOAuthFlowStatus,
getServerConnectionStatus,
+ createUnavailableToolStub,
} = require('./MCP');
jest.mock('./Config', () => ({
@@ -1098,6 +1099,188 @@ describe('User parameter passing tests', () => {
});
});
+ describe('createUnavailableToolStub', () => {
+ it('should return a tool whose _call returns a valid CONTENT_AND_ARTIFACT two-tuple', async () => {
+ const stub = createUnavailableToolStub('myTool', 'myServer');
+ // invoke() goes through langchain's base tool, which checks responseFormat.
+ // CONTENT_AND_ARTIFACT requires [content, artifact] — a bare string would throw:
+ // "Tool response format is "content_and_artifact" but the output was not a two-tuple"
+ const result = await stub.invoke({});
+ // If we reach here without throwing, the two-tuple format is correct.
+ // invoke() returns the content portion of [content, artifact] as a string.
+ expect(result).toContain('temporarily unavailable');
+ });
+ });
+
+ describe('negative tool cache and throttle interaction', () => {
+ it('should cache tool as missing even when throttled (cross-user dedup)', async () => {
+ const mockUser = { id: 'throttle-test-user' };
+ const mockRes = { write: jest.fn(), flush: jest.fn() };
+
+ // First call: reconnect succeeds but tool not found
+ mockReinitMCPServer.mockResolvedValueOnce({
+ availableTools: {},
+ });
+
+ await createMCPTool({
+ res: mockRes,
+ user: mockUser,
+ toolKey: `missing-tool${D}cache-dedup-server`,
+ provider: 'openai',
+ userMCPAuthMap: {},
+ availableTools: undefined,
+ });
+
+ // Second call within 10s for DIFFERENT tool on same server:
+ // reconnect is throttled (returns null), tool is still cached as missing.
+ // This is intentional: the cache acts as cross-user dedup since the
+ // throttle is per-user-per-server and can't prevent N different users
+ // from each triggering their own reconnect.
+ const result2 = await createMCPTool({
+ res: mockRes,
+ user: mockUser,
+ toolKey: `other-tool${D}cache-dedup-server`,
+ provider: 'openai',
+ userMCPAuthMap: {},
+ availableTools: undefined,
+ });
+
+ expect(result2).toBeDefined();
+ expect(result2.name).toContain('other-tool');
+ expect(mockReinitMCPServer).toHaveBeenCalledTimes(1);
+ });
+
+ it('should prevent user B from triggering reconnect when user A already cached the tool', async () => {
+ const userA = { id: 'cache-user-A' };
+ const userB = { id: 'cache-user-B' };
+ const mockRes = { write: jest.fn(), flush: jest.fn() };
+
+ // User A: real reconnect, tool not found → cached
+ mockReinitMCPServer.mockResolvedValueOnce({
+ availableTools: {},
+ });
+
+ await createMCPTool({
+ res: mockRes,
+ user: userA,
+ toolKey: `shared-tool${D}cross-user-server`,
+ provider: 'openai',
+ userMCPAuthMap: {},
+ availableTools: undefined,
+ });
+
+ expect(mockReinitMCPServer).toHaveBeenCalledTimes(1);
+
+ // User B requests the SAME tool within 10s.
+ // The negative cache is keyed by toolKey (no user prefix), so user B
+ // gets a cache hit and no reconnect fires. This is the cross-user
+ // storm protection: without this, user B's unthrottled first request
+ // would trigger a second reconnect to the same server.
+ const result = await createMCPTool({
+ res: mockRes,
+ user: userB,
+ toolKey: `shared-tool${D}cross-user-server`,
+ provider: 'openai',
+ userMCPAuthMap: {},
+ availableTools: undefined,
+ });
+
+ expect(result).toBeDefined();
+ expect(result.name).toContain('shared-tool');
+ // reinitMCPServer still called only once — user B hit the cache
+ expect(mockReinitMCPServer).toHaveBeenCalledTimes(1);
+ });
+
+ it('should prevent user B from triggering reconnect for throttle-cached tools', async () => {
+ const userA = { id: 'storm-user-A' };
+ const userB = { id: 'storm-user-B' };
+ const mockRes = { write: jest.fn(), flush: jest.fn() };
+
+ // User A: real reconnect for tool-1, tool not found → cached
+ mockReinitMCPServer.mockResolvedValueOnce({
+ availableTools: {},
+ });
+
+ await createMCPTool({
+ res: mockRes,
+ user: userA,
+ toolKey: `tool-1${D}storm-server`,
+ provider: 'openai',
+ userMCPAuthMap: {},
+ availableTools: undefined,
+ });
+
+ // User A: tool-2 on same server within 10s → throttled → cached from throttle
+ await createMCPTool({
+ res: mockRes,
+ user: userA,
+ toolKey: `tool-2${D}storm-server`,
+ provider: 'openai',
+ userMCPAuthMap: {},
+ availableTools: undefined,
+ });
+
+ expect(mockReinitMCPServer).toHaveBeenCalledTimes(1);
+
+ // User B requests tool-2 — gets cache hit from the throttle-cached entry.
+ // Without this caching, user B would trigger a real reconnect since
+ // user B has their own throttle key and hasn't reconnected yet.
+ const result = await createMCPTool({
+ res: mockRes,
+ user: userB,
+ toolKey: `tool-2${D}storm-server`,
+ provider: 'openai',
+ userMCPAuthMap: {},
+ availableTools: undefined,
+ });
+
+ expect(result).toBeDefined();
+ expect(result.name).toContain('tool-2');
+ // Still only 1 real reconnect — user B was protected by the cache
+ expect(mockReinitMCPServer).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('createMCPTools throttle handling', () => {
+ it('should return empty array with debug log when reconnect is throttled', async () => {
+ const mockUser = { id: 'throttle-tools-user' };
+ const mockRes = { write: jest.fn(), flush: jest.fn() };
+
+ // First call: real reconnect
+ mockReinitMCPServer.mockResolvedValueOnce({
+ tools: [{ name: 'tool1' }],
+ availableTools: {
+ [`tool1${D}throttle-tools-server`]: {
+ function: { description: 'Tool 1', parameters: {} },
+ },
+ },
+ });
+
+ await createMCPTools({
+ res: mockRes,
+ user: mockUser,
+ serverName: 'throttle-tools-server',
+ provider: 'openai',
+ userMCPAuthMap: {},
+ });
+
+ // Second call within 10s — throttled
+ const result = await createMCPTools({
+ res: mockRes,
+ user: mockUser,
+ serverName: 'throttle-tools-server',
+ provider: 'openai',
+ userMCPAuthMap: {},
+ });
+
+ expect(result).toEqual([]);
+ // reinitMCPServer called only once — second was throttled
+ expect(mockReinitMCPServer).toHaveBeenCalledTimes(1);
+ // Should log at debug level (not warn) for throttled case
+ expect(logger.debug).toHaveBeenCalledWith(expect.stringContaining('Reconnect throttled'));
+ });
+ });
+
describe('User parameter integrity', () => {
it('should preserve user object properties through the call chain', async () => {
const complexUser = {
diff --git a/api/server/services/PermissionService.js b/api/server/services/PermissionService.js
index a843f48f6f..2ac00f3afa 100644
--- a/api/server/services/PermissionService.js
+++ b/api/server/services/PermissionService.js
@@ -15,16 +15,22 @@ const {
getEffectivePermissionsForResources: getEffectivePermissionsForResourcesACL,
grantPermission: grantPermissionACL,
findEntriesByPrincipalsAndResource,
+ findRolesByResourceType,
+ findPublicResourceIds,
+ bulkWriteAclEntries,
findGroupByExternalId,
findRoleByIdentifier,
+ deleteAclEntries,
getUserPrincipals,
+ findGroupByQuery,
+ updateGroupById,
+ bulkUpdateGroups,
hasPermission,
createGroup,
createUser,
updateUser,
findUser,
} = require('~/models');
-const { AclEntry, AccessRole, Group } = require('~/db/models');
/** @type {boolean|null} */
let transactionSupportCache = null;
@@ -275,17 +281,9 @@ const findPubliclyAccessibleResources = async ({ resourceType, requiredPermissio
validateResourceType(resourceType);
- // Find all public ACL entries where the public principal has at least the required permission bits
- const entries = await AclEntry.find({
- principalType: PrincipalType.PUBLIC,
- resourceType,
- permBits: { $bitsAllSet: requiredPermissions },
- }).distinct('resourceId');
-
- return entries;
+ return await findPublicResourceIds(resourceType, requiredPermissions);
} catch (error) {
logger.error(`[PermissionService.findPubliclyAccessibleResources] Error: ${error.message}`);
- // Re-throw validation errors
if (error.message.includes('requiredPermissions must be')) {
throw error;
}
@@ -302,7 +300,7 @@ const findPubliclyAccessibleResources = async ({ resourceType, requiredPermissio
const getAvailableRoles = async ({ resourceType }) => {
validateResourceType(resourceType);
- return await AccessRole.find({ resourceType }).lean();
+ return await findRolesByResourceType(resourceType);
};
/**
@@ -423,7 +421,7 @@ const ensureGroupPrincipalExists = async function (principal, authContext = null
let existingGroup = await findGroupByExternalId(principal.idOnTheSource, 'entra');
if (!existingGroup && principal.email) {
- existingGroup = await Group.findOne({ email: principal.email.toLowerCase() }).lean();
+ existingGroup = await findGroupByQuery({ email: principal.email.toLowerCase() });
}
if (existingGroup) {
@@ -452,7 +450,7 @@ const ensureGroupPrincipalExists = async function (principal, authContext = null
}
if (needsUpdate) {
- await Group.findByIdAndUpdate(existingGroup._id, { $set: updateData }, { new: true });
+ await updateGroupById(existingGroup._id, updateData);
}
return existingGroup._id.toString();
@@ -520,7 +518,7 @@ const syncUserEntraGroupMemberships = async (user, accessToken, session = null)
const sessionOptions = session ? { session } : {};
- await Group.updateMany(
+ await bulkUpdateGroups(
{
idOnTheSource: { $in: allGroupIds },
source: 'entra',
@@ -530,13 +528,13 @@ const syncUserEntraGroupMemberships = async (user, accessToken, session = null)
sessionOptions,
);
- await Group.updateMany(
+ await bulkUpdateGroups(
{
source: 'entra',
memberIds: user.idOnTheSource,
idOnTheSource: { $nin: allGroupIds },
},
- { $pull: { memberIds: user.idOnTheSource } },
+ { $pullAll: { memberIds: [user.idOnTheSource] } },
sessionOptions,
);
} catch (error) {
@@ -628,7 +626,7 @@ const bulkUpdateResourcePermissions = async ({
const sessionOptions = localSession ? { session: localSession } : {};
- const roles = await AccessRole.find({ resourceType }).lean();
+ const roles = await findRolesByResourceType(resourceType);
const rolesMap = new Map();
roles.forEach((role) => {
rolesMap.set(role.accessRoleId, role);
@@ -732,7 +730,7 @@ const bulkUpdateResourcePermissions = async ({
}
if (bulkWrites.length > 0) {
- await AclEntry.bulkWrite(bulkWrites, sessionOptions);
+ await bulkWriteAclEntries(bulkWrites, sessionOptions);
}
const deleteQueries = [];
@@ -773,12 +771,7 @@ const bulkUpdateResourcePermissions = async ({
}
if (deleteQueries.length > 0) {
- await AclEntry.deleteMany(
- {
- $or: deleteQueries,
- },
- sessionOptions,
- );
+ await deleteAclEntries({ $or: deleteQueries }, sessionOptions);
}
if (shouldEndSession && supportsTransactions) {
@@ -788,7 +781,15 @@ const bulkUpdateResourcePermissions = async ({
return results;
} catch (error) {
if (shouldEndSession && supportsTransactions) {
- await localSession.abortTransaction();
+ try {
+ await localSession.abortTransaction();
+ } catch (transactionError) {
+ /** best-effort abort; may fail if commit already succeeded */
+ logger.error(
+ `[PermissionService.bulkUpdateResourcePermissions] Error aborting transaction:`,
+ transactionError,
+ );
+ }
}
logger.error(`[PermissionService.bulkUpdateResourcePermissions] Error: ${error.message}`);
throw error;
@@ -814,7 +815,7 @@ const removeAllPermissions = async ({ resourceType, resourceId }) => {
throw new Error(`Invalid resource ID: ${resourceId}`);
}
- const result = await AclEntry.deleteMany({
+ const result = await deleteAclEntries({
resourceType,
resourceId,
});
diff --git a/api/server/services/PermissionService.spec.js b/api/server/services/PermissionService.spec.js
index b41780f345..477b0702b9 100644
--- a/api/server/services/PermissionService.spec.js
+++ b/api/server/services/PermissionService.spec.js
@@ -9,6 +9,7 @@ const {
} = require('librechat-data-provider');
const {
bulkUpdateResourcePermissions,
+ syncUserEntraGroupMemberships,
getEffectivePermissions,
findAccessibleResources,
getAvailableRoles,
@@ -26,7 +27,11 @@ jest.mock('@librechat/data-schemas', () => ({
// Mock GraphApiService to prevent config loading issues
jest.mock('~/server/services/GraphApiService', () => ({
+ entraIdPrincipalFeatureEnabled: jest.fn().mockReturnValue(false),
+ getUserOwnedEntraGroups: jest.fn().mockResolvedValue([]),
+ getUserEntraGroups: jest.fn().mockResolvedValue([]),
getGroupMembers: jest.fn().mockResolvedValue([]),
+ getGroupOwners: jest.fn().mockResolvedValue([]),
}));
// Mock the logger
@@ -1933,3 +1938,134 @@ describe('PermissionService', () => {
});
});
});
+
+describe('syncUserEntraGroupMemberships - $pullAll on Group.memberIds', () => {
+ const {
+ entraIdPrincipalFeatureEnabled,
+ getUserEntraGroups,
+ } = require('~/server/services/GraphApiService');
+ const { Group } = require('~/db/models');
+
+ const userEntraId = 'entra-user-001';
+ const user = {
+ openidId: 'openid-sub-001',
+ idOnTheSource: userEntraId,
+ provider: 'openid',
+ };
+
+ beforeEach(async () => {
+ await Group.deleteMany({});
+ entraIdPrincipalFeatureEnabled.mockReturnValue(true);
+ });
+
+ afterEach(() => {
+ entraIdPrincipalFeatureEnabled.mockReturnValue(false);
+ getUserEntraGroups.mockResolvedValue([]);
+ });
+
+ it('should add user to matching Entra groups and remove from non-matching ones', async () => {
+ await Group.create([
+ { name: 'Group A', source: 'entra', idOnTheSource: 'entra-group-a', memberIds: [] },
+ {
+ name: 'Group B',
+ source: 'entra',
+ idOnTheSource: 'entra-group-b',
+ memberIds: [userEntraId],
+ },
+ {
+ name: 'Group C',
+ source: 'entra',
+ idOnTheSource: 'entra-group-c',
+ memberIds: [userEntraId],
+ },
+ ]);
+
+ getUserEntraGroups.mockResolvedValue(['entra-group-a', 'entra-group-c']);
+
+ await syncUserEntraGroupMemberships(user, 'fake-access-token');
+
+ const groups = await Group.find({ source: 'entra' }).sort({ name: 1 }).lean();
+ expect(groups[0].memberIds).toContain(userEntraId);
+ expect(groups[1].memberIds).not.toContain(userEntraId);
+ expect(groups[2].memberIds).toContain(userEntraId);
+ });
+
+ it('should not modify groups when API returns empty list (early return)', async () => {
+ await Group.create([
+ {
+ name: 'Group X',
+ source: 'entra',
+ idOnTheSource: 'entra-x',
+ memberIds: [userEntraId, 'other-user'],
+ },
+ { name: 'Group Y', source: 'entra', idOnTheSource: 'entra-y', memberIds: [userEntraId] },
+ ]);
+
+ getUserEntraGroups.mockResolvedValue([]);
+
+ await syncUserEntraGroupMemberships(user, 'fake-token');
+
+ const groups = await Group.find({ source: 'entra' }).sort({ name: 1 }).lean();
+ expect(groups[0].memberIds).toContain(userEntraId);
+ expect(groups[0].memberIds).toContain('other-user');
+ expect(groups[1].memberIds).toContain(userEntraId);
+ });
+
+ it('should remove user from groups not in the API response via $pullAll', async () => {
+ await Group.create([
+ { name: 'Keep', source: 'entra', idOnTheSource: 'entra-keep', memberIds: [userEntraId] },
+ {
+ name: 'Remove',
+ source: 'entra',
+ idOnTheSource: 'entra-remove',
+ memberIds: [userEntraId, 'other-user'],
+ },
+ ]);
+
+ getUserEntraGroups.mockResolvedValue(['entra-keep']);
+
+ await syncUserEntraGroupMemberships(user, 'fake-token');
+
+ const keep = await Group.findOne({ idOnTheSource: 'entra-keep' }).lean();
+ const remove = await Group.findOne({ idOnTheSource: 'entra-remove' }).lean();
+ expect(keep.memberIds).toContain(userEntraId);
+ expect(remove.memberIds).not.toContain(userEntraId);
+ expect(remove.memberIds).toContain('other-user');
+ });
+
+ it('should not modify local groups', async () => {
+ await Group.create([
+ { name: 'Local Group', source: 'local', memberIds: [userEntraId] },
+ {
+ name: 'Entra Group',
+ source: 'entra',
+ idOnTheSource: 'entra-only',
+ memberIds: [userEntraId],
+ },
+ ]);
+
+ getUserEntraGroups.mockResolvedValue([]);
+
+ await syncUserEntraGroupMemberships(user, 'fake-token');
+
+ const localGroup = await Group.findOne({ source: 'local' }).lean();
+ expect(localGroup.memberIds).toContain(userEntraId);
+ });
+
+ it('should early-return when feature is disabled', async () => {
+ entraIdPrincipalFeatureEnabled.mockReturnValue(false);
+
+ await Group.create({
+ name: 'Should Not Touch',
+ source: 'entra',
+ idOnTheSource: 'entra-safe',
+ memberIds: [userEntraId],
+ });
+
+ getUserEntraGroups.mockResolvedValue([]);
+ await syncUserEntraGroupMemberships(user, 'fake-token');
+
+ const group = await Group.findOne({ idOnTheSource: 'entra-safe' }).lean();
+ expect(group.memberIds).toContain(userEntraId);
+ });
+});
diff --git a/api/server/services/Threads/manage.js b/api/server/services/Threads/manage.js
index 627dba1a35..27520f38a5 100644
--- a/api/server/services/Threads/manage.js
+++ b/api/server/services/Threads/manage.js
@@ -1,16 +1,15 @@
const path = require('path');
const { v4 } = require('uuid');
-const { countTokens, escapeRegExp } = require('@librechat/api');
+const { countTokens } = require('@librechat/api');
+const { escapeRegExp } = require('@librechat/data-schemas');
const {
Constants,
ContentTypes,
AnnotationTypes,
defaultOrderQuery,
} = require('librechat-data-provider');
+const { recordMessage, getMessages, spendTokens, saveConvo } = require('~/models');
const { retrieveAndProcessFile } = require('~/server/services/Files/process');
-const { recordMessage, getMessages } = require('~/models/Message');
-const { spendTokens } = require('~/models/spendTokens');
-const { saveConvo } = require('~/models/Conversation');
/**
* Initializes a new thread or adds messages to an existing thread.
@@ -62,24 +61,6 @@ async function initThread({ openai, body, thread_id: _thread_id }) {
async function saveUserMessage(req, params) {
const tokenCount = await countTokens(params.text);
- // todo: do this on the frontend
- // const { file_ids = [] } = params;
- // let content;
- // if (file_ids.length) {
- // content = [
- // {
- // value: params.text,
- // },
- // ...(
- // file_ids
- // .filter(f => f)
- // .map((file_id) => ({
- // file_id,
- // }))
- // ),
- // ];
- // }
-
const userMessage = {
user: params.user,
endpoint: params.endpoint,
@@ -110,9 +91,15 @@ async function saveUserMessage(req, params) {
}
const message = await recordMessage(userMessage);
- await saveConvo(req, convo, {
- context: 'api/server/services/Threads/manage.js #saveUserMessage',
- });
+ await saveConvo(
+ {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ },
+ convo,
+ { context: 'api/server/services/Threads/manage.js #saveUserMessage' },
+ );
return message;
}
@@ -161,7 +148,11 @@ async function saveAssistantMessage(req, params) {
});
await saveConvo(
- req,
+ {
+ userId: req?.user?.id,
+ isTemporary: req?.body?.isTemporary,
+ interfaceConfig: req?.config?.interfaceConfig,
+ },
{
endpoint: params.endpoint,
conversationId: params.conversationId,
@@ -353,7 +344,11 @@ async function syncMessages({
await Promise.all(recordPromises);
await saveConvo(
- openai.req,
+ {
+ userId: openai.req?.user?.id,
+ isTemporary: openai.req?.body?.isTemporary,
+ interfaceConfig: openai.req?.config?.interfaceConfig,
+ },
{
conversationId,
file_ids: attached_file_ids,
diff --git a/api/server/services/ToolService.js b/api/server/services/ToolService.js
index eedb95bd4d..ca75e7eb4f 100644
--- a/api/server/services/ToolService.js
+++ b/api/server/services/ToolService.js
@@ -12,7 +12,6 @@ const {
const {
sendEvent,
getToolkitKey,
- hasCustomUserVars,
getUserMCPAuthMap,
loadToolDefinitions,
GenerationJobManager,
@@ -43,6 +42,7 @@ const {
} = require('librechat-data-provider');
const {
createActionTool,
+ legacyDomainEncode,
decryptMetadata,
loadActionSets,
domainParser,
@@ -65,6 +65,28 @@ const { redactMessage } = require('~/config/parsers');
const { findPluginAuthsByKeys } = require('~/models');
const { getFlowStateManager } = require('~/config');
const { getLogStores } = require('~/cache');
+
+const domainSeparatorRegex = new RegExp(actionDomainSeparator, 'g');
+
+/**
+ * Resolves the set of enabled agent capabilities from endpoints config,
+ * falling back to app-level or default capabilities for ephemeral agents.
+ * @param {ServerRequest} req
+ * @param {Object} appConfig
+ * @param {string} agentId
+ * @returns {Promise>}
+ */
+async function resolveAgentCapabilities(req, appConfig, agentId) {
+ const endpointsConfig = await getEndpointsConfig(req);
+ let capabilities = new Set(endpointsConfig?.[EModelEndpoint.agents]?.capabilities ?? []);
+ if (capabilities.size === 0 && isEphemeralAgentId(agentId)) {
+ capabilities = new Set(
+ appConfig.endpoints?.[EModelEndpoint.agents]?.capabilities ?? defaultAgentCapabilities,
+ );
+ }
+ return capabilities;
+}
+
/**
* Processes the required actions by calling the appropriate tools and returning the outputs.
* @param {OpenAIClient} client - OpenAI or StreamRunManager Client.
@@ -153,8 +175,7 @@ async function processRequiredActions(client, requiredActions) {
const promises = [];
- /** @type {Action[]} */
- let actionSets = [];
+ let actionSetsData = null;
let isActionTool = false;
const ActionToolMap = {};
const ActionBuildersMap = {};
@@ -240,9 +261,9 @@ async function processRequiredActions(client, requiredActions) {
if (!tool) {
// throw new Error(`Tool ${currentAction.tool} not found.`);
- // Load all action sets once if not already loaded
- if (!actionSets.length) {
- actionSets =
+ if (!actionSetsData) {
+ /** @type {Action[]} */
+ const actionSets =
(await loadActionSets({
assistant_id: client.req.body.assistant_id,
})) ?? [];
@@ -250,11 +271,16 @@ async function processRequiredActions(client, requiredActions) {
// Process all action sets once
// Map domains to their processed action sets
const processedDomains = new Map();
- const domainMap = new Map();
+ const domainLookupMap = new Map();
for (const action of actionSets) {
const domain = await domainParser(action.metadata.domain, true);
- domainMap.set(domain, action);
+ domainLookupMap.set(domain, domain);
+
+ const legacyDomain = legacyDomainEncode(action.metadata.domain);
+ if (legacyDomain !== domain) {
+ domainLookupMap.set(legacyDomain, domain);
+ }
const isDomainAllowed = await isActionDomainAllowed(
action.metadata.domain,
@@ -309,27 +335,26 @@ async function processRequiredActions(client, requiredActions) {
ActionBuildersMap[action.metadata.domain] = requestBuilders;
}
- // Update actionSets reference to use the domain map
- actionSets = { domainMap, processedDomains };
+ actionSetsData = { domainLookupMap, processedDomains };
}
- // Find the matching domain for this tool
let currentDomain = '';
- for (const domain of actionSets.domainMap.keys()) {
- if (currentAction.tool.includes(domain)) {
- currentDomain = domain;
+ let matchedKey = '';
+ for (const [key, canonical] of actionSetsData.domainLookupMap.entries()) {
+ if (currentAction.tool.includes(key)) {
+ currentDomain = canonical;
+ matchedKey = key;
break;
}
}
- if (!currentDomain || !actionSets.processedDomains.has(currentDomain)) {
- // TODO: try `function` if no action set is found
- // throw new Error(`Tool ${currentAction.tool} not found.`);
+ if (!currentDomain || !actionSetsData.processedDomains.has(currentDomain)) {
continue;
}
- const { action, requestBuilders, encrypted } = actionSets.processedDomains.get(currentDomain);
- const functionName = currentAction.tool.replace(`${actionDelimiter}${currentDomain}`, '');
+ const { action, requestBuilders, encrypted } =
+ actionSetsData.processedDomains.get(currentDomain);
+ const functionName = currentAction.tool.replace(`${actionDelimiter}${matchedKey}`, '');
const requestBuilder = requestBuilders[functionName];
if (!requestBuilder) {
@@ -446,17 +471,11 @@ async function loadToolDefinitionsWrapper({ req, res, agent, streamId = null, to
}
const appConfig = req.config;
- const endpointsConfig = await getEndpointsConfig(req);
- let enabledCapabilities = new Set(endpointsConfig?.[EModelEndpoint.agents]?.capabilities ?? []);
-
- if (enabledCapabilities.size === 0 && isEphemeralAgentId(agent.id)) {
- enabledCapabilities = new Set(
- appConfig.endpoints?.[EModelEndpoint.agents]?.capabilities ?? defaultAgentCapabilities,
- );
- }
+ const enabledCapabilities = await resolveAgentCapabilities(req, appConfig, agent.id);
const checkCapability = (capability) => enabledCapabilities.has(capability);
const areToolsEnabled = checkCapability(AgentCapabilities.tools);
+ const actionsEnabled = checkCapability(AgentCapabilities.actions);
const deferredToolsEnabled = checkCapability(AgentCapabilities.deferred_tools);
const filteredTools = agent.tools?.filter((tool) => {
@@ -469,7 +488,10 @@ async function loadToolDefinitionsWrapper({ req, res, agent, streamId = null, to
if (tool === Tools.web_search) {
return checkCapability(AgentCapabilities.web_search);
}
- if (!areToolsEnabled && !tool.includes(actionDelimiter)) {
+ if (tool.includes(actionDelimiter)) {
+ return actionsEnabled;
+ }
+ if (!areToolsEnabled) {
return false;
}
return true;
@@ -481,7 +503,7 @@ async function loadToolDefinitionsWrapper({ req, res, agent, streamId = null, to
/** @type {Record>} */
let userMCPAuthMap;
- if (hasCustomUserVars(req.config)) {
+ if (agent.tools?.some((t) => t.includes(Constants.mcp_delimiter))) {
userMCPAuthMap = await getUserMCPAuthMap({
tools: agent.tools,
userId: req.user.id,
@@ -570,12 +592,17 @@ async function loadToolDefinitionsWrapper({ req, res, agent, streamId = null, to
const definitions = [];
const allowedDomains = appConfig?.actions?.allowedDomains;
- const domainSeparatorRegex = new RegExp(actionDomainSeparator, 'g');
+ const normalizedToolNames = new Set(
+ actionToolNames.map((n) => n.replace(domainSeparatorRegex, '_')),
+ );
for (const action of actionSets) {
const domain = await domainParser(action.metadata.domain, true);
const normalizedDomain = domain.replace(domainSeparatorRegex, '_');
+ const legacyDomain = legacyDomainEncode(action.metadata.domain);
+ const legacyNormalized = legacyDomain.replace(domainSeparatorRegex, '_');
+
const isDomainAllowed = await isActionDomainAllowed(action.metadata.domain, allowedDomains);
if (!isDomainAllowed) {
logger.warn(
@@ -595,7 +622,8 @@ async function loadToolDefinitionsWrapper({ req, res, agent, streamId = null, to
for (const sig of functionSignatures) {
const toolName = `${sig.name}${actionDelimiter}${normalizedDomain}`;
- if (!actionToolNames.some((name) => name.replace(domainSeparatorRegex, '_') === toolName)) {
+ const legacyToolName = `${sig.name}${actionDelimiter}${legacyNormalized}`;
+ if (!normalizedToolNames.has(toolName) && !normalizedToolNames.has(legacyToolName)) {
continue;
}
@@ -766,6 +794,7 @@ async function loadToolDefinitionsWrapper({ req, res, agent, streamId = null, to
toolContextMap,
toolDefinitions,
hasDeferredTools,
+ actionsEnabled,
};
}
@@ -809,14 +838,7 @@ async function loadAgentTools({
}
const appConfig = req.config;
- const endpointsConfig = await getEndpointsConfig(req);
- let enabledCapabilities = new Set(endpointsConfig?.[EModelEndpoint.agents]?.capabilities ?? []);
- /** Edge case: use defined/fallback capabilities when the "agents" endpoint is not enabled */
- if (enabledCapabilities.size === 0 && isEphemeralAgentId(agent.id)) {
- enabledCapabilities = new Set(
- appConfig.endpoints?.[EModelEndpoint.agents]?.capabilities ?? defaultAgentCapabilities,
- );
- }
+ const enabledCapabilities = await resolveAgentCapabilities(req, appConfig, agent.id);
const checkCapability = (capability) => {
const enabled = enabledCapabilities.has(capability);
if (!enabled) {
@@ -833,6 +855,7 @@ async function loadAgentTools({
return enabled;
};
const areToolsEnabled = checkCapability(AgentCapabilities.tools);
+ const actionsEnabled = checkCapability(AgentCapabilities.actions);
let includesWebSearch = false;
const _agentTools = agent.tools?.filter((tool) => {
@@ -843,7 +866,9 @@ async function loadAgentTools({
} else if (tool === Tools.web_search) {
includesWebSearch = checkCapability(AgentCapabilities.web_search);
return includesWebSearch;
- } else if (!areToolsEnabled && !tool.includes(actionDelimiter)) {
+ } else if (tool.includes(actionDelimiter)) {
+ return actionsEnabled;
+ } else if (!areToolsEnabled) {
return false;
}
return true;
@@ -860,8 +885,7 @@ async function loadAgentTools({
/** @type {Record>} */
let userMCPAuthMap;
- //TODO pass config from registry
- if (hasCustomUserVars(req.config)) {
+ if (agent.tools?.some((t) => t.includes(Constants.mcp_delimiter))) {
userMCPAuthMap = await getUserMCPAuthMap({
tools: agent.tools,
userId: req.user.id,
@@ -949,13 +973,15 @@ async function loadAgentTools({
agentTools.push(...additionalTools);
- if (!checkCapability(AgentCapabilities.actions)) {
+ const hasActionTools = _agentTools.some((t) => t.includes(actionDelimiter));
+ if (!hasActionTools) {
return {
toolRegistry,
userMCPAuthMap,
toolContextMap,
toolDefinitions,
hasDeferredTools,
+ actionsEnabled,
tools: agentTools,
};
}
@@ -971,19 +997,22 @@ async function loadAgentTools({
toolContextMap,
toolDefinitions,
hasDeferredTools,
+ actionsEnabled,
tools: agentTools,
};
}
- // Process each action set once (validate spec, decrypt metadata)
const processedActionSets = new Map();
- const domainMap = new Map();
+ const domainLookupMap = new Map();
for (const action of actionSets) {
const domain = await domainParser(action.metadata.domain, true);
- domainMap.set(domain, action);
+ domainLookupMap.set(domain, domain);
- // Check if domain is allowed (do this once per action set)
+ const legacyDomain = legacyDomainEncode(action.metadata.domain);
+ if (legacyDomain !== domain) {
+ domainLookupMap.set(legacyDomain, domain);
+ }
const isDomainAllowed = await isActionDomainAllowed(
action.metadata.domain,
appConfig?.actions?.allowedDomains,
@@ -1045,11 +1074,12 @@ async function loadAgentTools({
continue;
}
- // Find the matching domain for this tool
let currentDomain = '';
- for (const domain of domainMap.keys()) {
- if (toolName.includes(domain)) {
- currentDomain = domain;
+ let matchedKey = '';
+ for (const [key, canonical] of domainLookupMap.entries()) {
+ if (toolName.includes(key)) {
+ currentDomain = canonical;
+ matchedKey = key;
break;
}
}
@@ -1060,7 +1090,7 @@ async function loadAgentTools({
const { action, encrypted, zodSchemas, requestBuilders, functionSignatures } =
processedActionSets.get(currentDomain);
- const functionName = toolName.replace(`${actionDelimiter}${currentDomain}`, '');
+ const functionName = toolName.replace(`${actionDelimiter}${matchedKey}`, '');
const functionSig = functionSignatures.find((sig) => sig.name === functionName);
const requestBuilder = requestBuilders[functionName];
const zodSchema = zodSchemas[functionName];
@@ -1103,6 +1133,7 @@ async function loadAgentTools({
userMCPAuthMap,
toolDefinitions,
hasDeferredTools,
+ actionsEnabled,
tools: agentTools,
};
}
@@ -1120,9 +1151,11 @@ async function loadAgentTools({
* @param {AbortSignal} [params.signal] - Abort signal
* @param {Object} params.agent - The agent object
* @param {string[]} params.toolNames - Names of tools to load
+ * @param {Map} [params.toolRegistry] - Tool registry
* @param {Record>} [params.userMCPAuthMap] - User MCP auth map
* @param {Object} [params.tool_resources] - Tool resources
* @param {string|null} [params.streamId] - Stream ID for web search callbacks
+ * @param {boolean} [params.actionsEnabled] - Whether the actions capability is enabled
* @returns {Promise<{ loadedTools: Array, configurable: Object }>}
*/
async function loadToolsForExecution({
@@ -1135,11 +1168,17 @@ async function loadToolsForExecution({
userMCPAuthMap,
tool_resources,
streamId = null,
+ actionsEnabled,
}) {
const appConfig = req.config;
const allLoadedTools = [];
const configurable = { userMCPAuthMap };
+ if (actionsEnabled === undefined) {
+ const enabledCapabilities = await resolveAgentCapabilities(req, appConfig, agent?.id);
+ actionsEnabled = enabledCapabilities.has(AgentCapabilities.actions);
+ }
+
const isToolSearch = toolNames.includes(AgentConstants.TOOL_SEARCH);
const isPTC = toolNames.includes(AgentConstants.PROGRAMMATIC_TOOL_CALLING);
@@ -1196,7 +1235,6 @@ async function loadToolsForExecution({
const actionToolNames = allToolNamesToLoad.filter((name) => name.includes(actionDelimiter));
const regularToolNames = allToolNamesToLoad.filter((name) => !name.includes(actionDelimiter));
- /** @type {Record} */
if (regularToolNames.length > 0) {
const includesWebSearch = regularToolNames.includes(Tools.web_search);
const webSearchCallbacks = includesWebSearch ? createOnSearchResults(res, streamId) : undefined;
@@ -1227,7 +1265,7 @@ async function loadToolsForExecution({
}
}
- if (actionToolNames.length > 0 && agent) {
+ if (actionToolNames.length > 0 && agent && actionsEnabled) {
const actionTools = await loadActionToolsForExecution({
req,
res,
@@ -1237,6 +1275,11 @@ async function loadToolsForExecution({
actionToolNames,
});
allLoadedTools.push(...actionTools);
+ } else if (actionToolNames.length > 0 && agent && !actionsEnabled) {
+ logger.warn(
+ `[loadToolsForExecution] Capability "${AgentCapabilities.actions}" disabled. ` +
+ `Skipping action tool execution. User: ${req.user.id} | Agent: ${agent.id} | Tools: ${actionToolNames.join(', ')}`,
+ );
}
if (isPTC && allLoadedTools.length > 0) {
@@ -1282,12 +1325,20 @@ async function loadActionToolsForExecution({
}
const processedActionSets = new Map();
- const domainMap = new Map();
+ /** Maps both new and legacy normalized domains to their canonical (new) domain key */
+ const normalizedToDomain = new Map();
const allowedDomains = appConfig?.actions?.allowedDomains;
for (const action of actionSets) {
const domain = await domainParser(action.metadata.domain, true);
- domainMap.set(domain, action);
+ const normalizedDomain = domain.replace(domainSeparatorRegex, '_');
+ normalizedToDomain.set(normalizedDomain, domain);
+
+ const legacyDomain = legacyDomainEncode(action.metadata.domain);
+ const legacyNormalized = legacyDomain.replace(domainSeparatorRegex, '_');
+ if (legacyNormalized !== normalizedDomain) {
+ normalizedToDomain.set(legacyNormalized, domain);
+ }
const isDomainAllowed = await isActionDomainAllowed(action.metadata.domain, allowedDomains);
if (!isDomainAllowed) {
@@ -1336,16 +1387,15 @@ async function loadActionToolsForExecution({
functionSignatures,
zodSchemas,
encrypted,
+ legacyNormalized,
});
}
- const domainSeparatorRegex = new RegExp(actionDomainSeparator, 'g');
for (const toolName of actionToolNames) {
let currentDomain = '';
- for (const domain of domainMap.keys()) {
- const normalizedDomain = domain.replace(domainSeparatorRegex, '_');
+ for (const [normalizedDomain, canonicalDomain] of normalizedToDomain.entries()) {
if (toolName.includes(normalizedDomain)) {
- currentDomain = domain;
+ currentDomain = canonicalDomain;
break;
}
}
@@ -1354,7 +1404,7 @@ async function loadActionToolsForExecution({
continue;
}
- const { action, encrypted, zodSchemas, requestBuilders, functionSignatures } =
+ const { action, encrypted, zodSchemas, requestBuilders, functionSignatures, legacyNormalized } =
processedActionSets.get(currentDomain);
const normalizedDomain = currentDomain.replace(domainSeparatorRegex, '_');
const functionName = toolName.replace(`${actionDelimiter}${normalizedDomain}`, '');
@@ -1363,6 +1413,25 @@ async function loadActionToolsForExecution({
const zodSchema = zodSchemas[functionName];
if (!requestBuilder) {
+ const legacyFnName = toolName.replace(`${actionDelimiter}${legacyNormalized}`, '');
+ if (legacyFnName !== toolName && requestBuilders[legacyFnName]) {
+ const legacyTool = await createActionTool({
+ userId: req.user.id,
+ res,
+ action,
+ streamId,
+ encrypted,
+ requestBuilder: requestBuilders[legacyFnName],
+ zodSchema: zodSchemas[legacyFnName],
+ name: toolName,
+ description:
+ functionSignatures.find((sig) => sig.name === legacyFnName)?.description ?? '',
+ useSSRFProtection: !Array.isArray(allowedDomains) || allowedDomains.length === 0,
+ });
+ if (legacyTool) {
+ loadedActionTools.push(legacyTool);
+ }
+ }
continue;
}
@@ -1397,4 +1466,5 @@ module.exports = {
loadAgentTools,
loadToolsForExecution,
processRequiredActions,
+ resolveAgentCapabilities,
};
diff --git a/api/server/services/Tools/mcp.js b/api/server/services/Tools/mcp.js
index 10f2d71a18..7589043e10 100644
--- a/api/server/services/Tools/mcp.js
+++ b/api/server/services/Tools/mcp.js
@@ -1,8 +1,8 @@
const { logger } = require('@librechat/data-schemas');
const { CacheKeys, Constants } = require('librechat-data-provider');
+const { getMCPManager, getMCPServersRegistry, getFlowStateManager } = require('~/config');
const { findToken, createToken, updateToken, deleteTokens } = require('~/models');
const { updateMCPServerTools } = require('~/server/services/Config');
-const { getMCPManager, getFlowStateManager } = require('~/config');
const { getLogStores } = require('~/cache');
/**
@@ -41,6 +41,33 @@ async function reinitMCPServer({
let oauthUrl = null;
try {
+ const registry = getMCPServersRegistry();
+ const serverConfig = await registry.getServerConfig(serverName, user?.id);
+ if (serverConfig?.inspectionFailed) {
+ logger.info(
+ `[MCP Reinitialize] Server ${serverName} had failed inspection, attempting reinspection`,
+ );
+ try {
+ const storageLocation = serverConfig.dbId ? 'DB' : 'CACHE';
+ await registry.reinspectServer(serverName, storageLocation, user?.id);
+ logger.info(`[MCP Reinitialize] Reinspection succeeded for server: ${serverName}`);
+ } catch (reinspectError) {
+ logger.error(
+ `[MCP Reinitialize] Reinspection failed for server ${serverName}:`,
+ reinspectError,
+ );
+ return {
+ availableTools: null,
+ success: false,
+ message: `MCP server '${serverName}' is still unreachable`,
+ oauthRequired: false,
+ serverName,
+ oauthUrl: null,
+ tools: null,
+ };
+ }
+ }
+
const customUserVars = userMCPAuthMap?.[`${Constants.mcp_prefix}${serverName}`];
const flowManager = _flowManager ?? getFlowStateManager(getLogStores(CacheKeys.FLOWS));
const mcpManager = getMCPManager();
diff --git a/api/server/services/__tests__/ToolService.spec.js b/api/server/services/__tests__/ToolService.spec.js
index 2f00bbc3d6..a468a88eb3 100644
--- a/api/server/services/__tests__/ToolService.spec.js
+++ b/api/server/services/__tests__/ToolService.spec.js
@@ -1,15 +1,304 @@
-const { AgentCapabilities, defaultAgentCapabilities } = require('librechat-data-provider');
+const {
+ Tools,
+ Constants,
+ EModelEndpoint,
+ actionDelimiter,
+ AgentCapabilities,
+ defaultAgentCapabilities,
+} = require('librechat-data-provider');
+
+const mockGetEndpointsConfig = jest.fn();
+const mockGetMCPServerTools = jest.fn();
+const mockGetCachedTools = jest.fn();
+jest.mock('~/server/services/Config', () => ({
+ getEndpointsConfig: (...args) => mockGetEndpointsConfig(...args),
+ getMCPServerTools: (...args) => mockGetMCPServerTools(...args),
+ getCachedTools: (...args) => mockGetCachedTools(...args),
+}));
+
+const mockLoadToolDefinitions = jest.fn();
+const mockGetUserMCPAuthMap = jest.fn();
+jest.mock('@librechat/api', () => ({
+ ...jest.requireActual('@librechat/api'),
+ loadToolDefinitions: (...args) => mockLoadToolDefinitions(...args),
+ getUserMCPAuthMap: (...args) => mockGetUserMCPAuthMap(...args),
+}));
+
+const mockLoadToolsUtil = jest.fn();
+jest.mock('~/app/clients/tools/util', () => ({
+ loadTools: (...args) => mockLoadToolsUtil(...args),
+}));
+
+const mockLoadActionSets = jest.fn();
+jest.mock('~/server/services/Tools/credentials', () => ({
+ loadAuthValues: jest.fn().mockResolvedValue({}),
+}));
+jest.mock('~/server/services/Tools/search', () => ({
+ createOnSearchResults: jest.fn(),
+}));
+jest.mock('~/server/services/Tools/mcp', () => ({
+ reinitMCPServer: jest.fn(),
+}));
+jest.mock('~/server/services/Files/process', () => ({
+ processFileURL: jest.fn(),
+ uploadImageBuffer: jest.fn(),
+}));
+jest.mock('~/app/clients/tools/util/fileSearch', () => ({
+ primeFiles: jest.fn().mockResolvedValue({}),
+}));
+jest.mock('~/server/services/Files/Code/process', () => ({
+ primeFiles: jest.fn().mockResolvedValue({}),
+}));
+jest.mock('../ActionService', () => ({
+ loadActionSets: (...args) => mockLoadActionSets(...args),
+ decryptMetadata: jest.fn(),
+ createActionTool: jest.fn(),
+ domainParser: jest.fn(),
+}));
+jest.mock('~/server/services/Threads', () => ({
+ recordUsage: jest.fn(),
+}));
+jest.mock('~/models', () => ({
+ findPluginAuthsByKeys: jest.fn(),
+}));
+jest.mock('~/config', () => ({
+ getFlowStateManager: jest.fn(() => ({})),
+}));
+jest.mock('~/cache', () => ({
+ getLogStores: jest.fn(() => ({})),
+}));
+
+const {
+ loadAgentTools,
+ loadToolsForExecution,
+ resolveAgentCapabilities,
+} = require('../ToolService');
+
+function createMockReq(capabilities) {
+ return {
+ user: { id: 'user_123' },
+ config: {
+ endpoints: {
+ [EModelEndpoint.agents]: {
+ capabilities,
+ },
+ },
+ },
+ };
+}
+
+function createEndpointsConfig(capabilities) {
+ return {
+ [EModelEndpoint.agents]: { capabilities },
+ };
+}
+
+describe('ToolService - Action Capability Gating', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ mockLoadToolDefinitions.mockResolvedValue({
+ toolDefinitions: [],
+ toolRegistry: new Map(),
+ hasDeferredTools: false,
+ });
+ mockLoadToolsUtil.mockResolvedValue({ loadedTools: [], toolContextMap: {} });
+ mockLoadActionSets.mockResolvedValue([]);
+ });
+
+ describe('resolveAgentCapabilities', () => {
+ it('should return capabilities from endpoints config', async () => {
+ const capabilities = [AgentCapabilities.tools, AgentCapabilities.actions];
+ const req = createMockReq(capabilities);
+ mockGetEndpointsConfig.mockResolvedValue(createEndpointsConfig(capabilities));
+
+ const result = await resolveAgentCapabilities(req, req.config, 'agent_123');
+
+ expect(result).toBeInstanceOf(Set);
+ expect(result.has(AgentCapabilities.tools)).toBe(true);
+ expect(result.has(AgentCapabilities.actions)).toBe(true);
+ expect(result.has(AgentCapabilities.web_search)).toBe(false);
+ });
+
+ it('should fall back to default capabilities for ephemeral agents with empty config', async () => {
+ const req = createMockReq(defaultAgentCapabilities);
+ mockGetEndpointsConfig.mockResolvedValue({});
+
+ const result = await resolveAgentCapabilities(req, req.config, Constants.EPHEMERAL_AGENT_ID);
+
+ for (const cap of defaultAgentCapabilities) {
+ expect(result.has(cap)).toBe(true);
+ }
+ });
+
+ it('should return empty set when no capabilities and not ephemeral', async () => {
+ const req = createMockReq([]);
+ mockGetEndpointsConfig.mockResolvedValue({});
+
+ const result = await resolveAgentCapabilities(req, req.config, 'agent_123');
+
+ expect(result.size).toBe(0);
+ });
+ });
+
+ describe('loadAgentTools (definitionsOnly=true) — action tool filtering', () => {
+ const actionToolName = `get_weather${actionDelimiter}api_example_com`;
+ const regularTool = 'calculator';
+
+ it('should exclude action tools from definitions when actions capability is disabled', async () => {
+ const capabilities = [AgentCapabilities.tools, AgentCapabilities.web_search];
+ const req = createMockReq(capabilities);
+ mockGetEndpointsConfig.mockResolvedValue(createEndpointsConfig(capabilities));
+
+ await loadAgentTools({
+ req,
+ res: {},
+ agent: { id: 'agent_123', tools: [regularTool, actionToolName] },
+ definitionsOnly: true,
+ });
+
+ expect(mockLoadToolDefinitions).toHaveBeenCalledTimes(1);
+ const [callArgs] = mockLoadToolDefinitions.mock.calls[0];
+ expect(callArgs.tools).toContain(regularTool);
+ expect(callArgs.tools).not.toContain(actionToolName);
+ });
+
+ it('should include action tools in definitions when actions capability is enabled', async () => {
+ const capabilities = [AgentCapabilities.tools, AgentCapabilities.actions];
+ const req = createMockReq(capabilities);
+ mockGetEndpointsConfig.mockResolvedValue(createEndpointsConfig(capabilities));
+
+ await loadAgentTools({
+ req,
+ res: {},
+ agent: { id: 'agent_123', tools: [regularTool, actionToolName] },
+ definitionsOnly: true,
+ });
+
+ expect(mockLoadToolDefinitions).toHaveBeenCalledTimes(1);
+ const [callArgs] = mockLoadToolDefinitions.mock.calls[0];
+ expect(callArgs.tools).toContain(regularTool);
+ expect(callArgs.tools).toContain(actionToolName);
+ });
+
+ it('should return actionsEnabled in the result', async () => {
+ const capabilities = [AgentCapabilities.tools];
+ const req = createMockReq(capabilities);
+ mockGetEndpointsConfig.mockResolvedValue(createEndpointsConfig(capabilities));
+
+ const result = await loadAgentTools({
+ req,
+ res: {},
+ agent: { id: 'agent_123', tools: [regularTool] },
+ definitionsOnly: true,
+ });
+
+ expect(result.actionsEnabled).toBe(false);
+ });
+ });
+
+ describe('loadAgentTools (definitionsOnly=false) — action tool filtering', () => {
+ const actionToolName = `get_weather${actionDelimiter}api_example_com`;
+ const regularTool = 'calculator';
+
+ it('should not load action sets when actions capability is disabled', async () => {
+ const capabilities = [AgentCapabilities.tools, AgentCapabilities.web_search];
+ const req = createMockReq(capabilities);
+ mockGetEndpointsConfig.mockResolvedValue(createEndpointsConfig(capabilities));
+
+ await loadAgentTools({
+ req,
+ res: {},
+ agent: { id: 'agent_123', tools: [regularTool, actionToolName] },
+ definitionsOnly: false,
+ });
+
+ expect(mockLoadActionSets).not.toHaveBeenCalled();
+ });
+
+ it('should load action sets when actions capability is enabled and action tools present', async () => {
+ const capabilities = [AgentCapabilities.tools, AgentCapabilities.actions];
+ const req = createMockReq(capabilities);
+ mockGetEndpointsConfig.mockResolvedValue(createEndpointsConfig(capabilities));
+
+ await loadAgentTools({
+ req,
+ res: {},
+ agent: { id: 'agent_123', tools: [regularTool, actionToolName] },
+ definitionsOnly: false,
+ });
+
+ expect(mockLoadActionSets).toHaveBeenCalledWith({ agent_id: 'agent_123' });
+ });
+ });
+
+ describe('loadToolsForExecution — action tool gating', () => {
+ const actionToolName = `get_weather${actionDelimiter}api_example_com`;
+ const regularTool = Tools.web_search;
+
+ it('should skip action tool loading when actionsEnabled=false', async () => {
+ const req = createMockReq([]);
+ req.config = {};
+
+ const result = await loadToolsForExecution({
+ req,
+ res: {},
+ agent: { id: 'agent_123' },
+ toolNames: [regularTool, actionToolName],
+ actionsEnabled: false,
+ });
+
+ expect(mockLoadActionSets).not.toHaveBeenCalled();
+ expect(result.loadedTools).toBeDefined();
+ });
+
+ it('should load action tools when actionsEnabled=true', async () => {
+ const req = createMockReq([AgentCapabilities.actions]);
+ req.config = {};
+
+ await loadToolsForExecution({
+ req,
+ res: {},
+ agent: { id: 'agent_123' },
+ toolNames: [actionToolName],
+ actionsEnabled: true,
+ });
+
+ expect(mockLoadActionSets).toHaveBeenCalledWith({ agent_id: 'agent_123' });
+ });
+
+ it('should resolve actionsEnabled from capabilities when not explicitly provided', async () => {
+ const capabilities = [AgentCapabilities.tools];
+ const req = createMockReq(capabilities);
+ mockGetEndpointsConfig.mockResolvedValue(createEndpointsConfig(capabilities));
+
+ await loadToolsForExecution({
+ req,
+ res: {},
+ agent: { id: 'agent_123' },
+ toolNames: [actionToolName],
+ });
+
+ expect(mockGetEndpointsConfig).toHaveBeenCalled();
+ expect(mockLoadActionSets).not.toHaveBeenCalled();
+ });
+
+ it('should not call loadActionSets when there are no action tools', async () => {
+ const req = createMockReq([AgentCapabilities.actions]);
+ req.config = {};
+
+ await loadToolsForExecution({
+ req,
+ res: {},
+ agent: { id: 'agent_123' },
+ toolNames: [regularTool],
+ actionsEnabled: true,
+ });
+
+ expect(mockLoadActionSets).not.toHaveBeenCalled();
+ });
+ });
-/**
- * Tests for ToolService capability checking logic.
- * The actual loadAgentTools function has many dependencies, so we test
- * the capability checking logic in isolation.
- */
-describe('ToolService - Capability Checking', () => {
describe('checkCapability logic', () => {
- /**
- * Simulates the checkCapability function from loadAgentTools
- */
const createCheckCapability = (enabledCapabilities, logger = { warn: jest.fn() }) => {
return (capability) => {
const enabled = enabledCapabilities.has(capability);
@@ -119,26 +408,68 @@ describe('ToolService - Capability Checking', () => {
});
});
+ describe('userMCPAuthMap gating', () => {
+ const shouldFetchMCPAuth = (tools) =>
+ tools?.some((t) => t.includes(Constants.mcp_delimiter)) ?? false;
+
+ it('should return true when agent has MCP tools', () => {
+ const tools = ['web_search', `search${Constants.mcp_delimiter}my-mcp-server`, 'calculator'];
+ expect(shouldFetchMCPAuth(tools)).toBe(true);
+ });
+
+ it('should return false when agent has no MCP tools', () => {
+ const tools = ['web_search', 'calculator', 'code_interpreter'];
+ expect(shouldFetchMCPAuth(tools)).toBe(false);
+ });
+
+ it('should return false when tools is empty', () => {
+ expect(shouldFetchMCPAuth([])).toBe(false);
+ });
+
+ it('should return false when tools is undefined', () => {
+ expect(shouldFetchMCPAuth(undefined)).toBe(false);
+ });
+
+ it('should return false when tools is null', () => {
+ expect(shouldFetchMCPAuth(null)).toBe(false);
+ });
+
+ it('should detect MCP tools with different server names', () => {
+ const tools = [
+ `listFiles${Constants.mcp_delimiter}file-server`,
+ `query${Constants.mcp_delimiter}db-server`,
+ ];
+ expect(shouldFetchMCPAuth(tools)).toBe(true);
+ });
+
+ it('should return true even when only one tool is MCP', () => {
+ const tools = [
+ 'web_search',
+ 'calculator',
+ 'code_interpreter',
+ `echo${Constants.mcp_delimiter}test-server`,
+ ];
+ expect(shouldFetchMCPAuth(tools)).toBe(true);
+ });
+ });
+
describe('deferredToolsEnabled integration', () => {
it('should correctly determine deferredToolsEnabled from capabilities set', () => {
const createCheckCapability = (enabledCapabilities) => {
return (capability) => enabledCapabilities.has(capability);
};
- // When deferred_tools is in capabilities
const withDeferred = new Set([AgentCapabilities.deferred_tools, AgentCapabilities.tools]);
const checkWithDeferred = createCheckCapability(withDeferred);
expect(checkWithDeferred(AgentCapabilities.deferred_tools)).toBe(true);
- // When deferred_tools is NOT in capabilities
const withoutDeferred = new Set([AgentCapabilities.tools, AgentCapabilities.actions]);
const checkWithoutDeferred = createCheckCapability(withoutDeferred);
expect(checkWithoutDeferred(AgentCapabilities.deferred_tools)).toBe(false);
});
it('should use defaultAgentCapabilities when no capabilities configured', () => {
- // Simulates the fallback behavior in loadAgentTools
- const endpointsConfig = {}; // No capabilities configured
+ const endpointsConfig = {};
const enabledCapabilities = new Set(
endpointsConfig?.capabilities ?? defaultAgentCapabilities,
);
diff --git a/api/server/services/cleanup.js b/api/server/services/cleanup.js
index 7d3dfdec12..dc4f62c2ac 100644
--- a/api/server/services/cleanup.js
+++ b/api/server/services/cleanup.js
@@ -1,5 +1,5 @@
const { logger } = require('@librechat/data-schemas');
-const { deleteNullOrEmptyConversations } = require('~/models/Conversation');
+const { deleteNullOrEmptyConversations } = require('~/models');
const cleanup = async () => {
try {
diff --git a/api/server/services/initializeMCPs.spec.js b/api/server/services/initializeMCPs.spec.js
index e37e12c356..d72fda0e00 100644
--- a/api/server/services/initializeMCPs.spec.js
+++ b/api/server/services/initializeMCPs.spec.js
@@ -3,8 +3,8 @@
*
* These tests verify that MCPServersRegistry and MCPManager are ALWAYS initialized,
* even when no explicitly configured MCP servers exist. This is critical for the
- * "Dynamic MCP Server Management" feature (v0.8.2-rc1) which allows users to
- * add MCP servers via the UI without requiring explicit configuration.
+ * "Dynamic MCP Server Management" feature (introduced in `0.8.2-rc1` release) which
+ * allows users to add MCP servers via the UI without requiring explicit configuration.
*
* Bug fixed: Previously, MCPManager was only initialized when mcpServers existed
* in librechat.yaml, causing "MCPManager has not been initialized" errors when
diff --git a/api/server/services/start/migration.js b/api/server/services/start/migration.js
index 83b9c83e39..70f8300e08 100644
--- a/api/server/services/start/migration.js
+++ b/api/server/services/start/migration.js
@@ -6,8 +6,6 @@ const {
checkAgentPermissionsMigration,
checkPromptPermissionsMigration,
} = require('@librechat/api');
-const { getProjectByName } = require('~/models/Project');
-const { Agent, PromptGroup } = require('~/db/models');
const { findRoleByIdentifier } = require('~/models');
/**
@@ -20,9 +18,8 @@ async function checkMigrations() {
mongoose,
methods: {
findRoleByIdentifier,
- getProjectByName,
},
- AgentModel: Agent,
+ AgentModel: mongoose.models.Agent,
});
logAgentMigrationWarning(agentMigrationResult);
} catch (error) {
@@ -33,9 +30,8 @@ async function checkMigrations() {
mongoose,
methods: {
findRoleByIdentifier,
- getProjectByName,
},
- PromptGroupModel: PromptGroup,
+ PromptGroupModel: mongoose.models.PromptGroup,
});
logPromptMigrationWarning(promptMigrationResult);
} catch (error) {
diff --git a/api/server/services/systemGrant.spec.js b/api/server/services/systemGrant.spec.js
new file mode 100644
index 0000000000..4e10ee5641
--- /dev/null
+++ b/api/server/services/systemGrant.spec.js
@@ -0,0 +1,407 @@
+const mongoose = require('mongoose');
+const { createModels, createMethods } = require('@librechat/data-schemas');
+const { MongoMemoryServer } = require('mongodb-memory-server');
+const { SystemRoles, PrincipalType } = require('librechat-data-provider');
+const { SystemCapabilities } = require('@librechat/data-schemas');
+
+jest.mock('@librechat/data-schemas', () => ({
+ ...jest.requireActual('@librechat/data-schemas'),
+ getTransactionSupport: jest.fn().mockResolvedValue(false),
+ createModels: jest.requireActual('@librechat/data-schemas').createModels,
+ createMethods: jest.requireActual('@librechat/data-schemas').createMethods,
+}));
+
+jest.mock('~/server/services/GraphApiService', () => ({
+ entraIdPrincipalFeatureEnabled: jest.fn().mockReturnValue(false),
+ getUserOwnedEntraGroups: jest.fn().mockResolvedValue([]),
+ getUserEntraGroups: jest.fn().mockResolvedValue([]),
+ getGroupMembers: jest.fn().mockResolvedValue([]),
+ getGroupOwners: jest.fn().mockResolvedValue([]),
+}));
+
+jest.mock('~/config', () => ({
+ logger: { error: jest.fn() },
+}));
+
+let mongoServer;
+let methods;
+let SystemGrant;
+
+beforeAll(async () => {
+ mongoServer = await MongoMemoryServer.create();
+ await mongoose.connect(mongoServer.getUri());
+
+ createModels(mongoose);
+ const dbModels = require('~/db/models');
+ Object.assign(mongoose.models, dbModels);
+ SystemGrant = dbModels.SystemGrant;
+
+ methods = createMethods(mongoose, {
+ matchModelName: () => null,
+ findMatchingPattern: () => null,
+ getCache: () => ({
+ get: async () => null,
+ set: async () => {},
+ }),
+ });
+});
+
+afterAll(async () => {
+ await mongoose.disconnect();
+ await mongoServer.stop();
+});
+
+beforeEach(async () => {
+ await SystemGrant.deleteMany({});
+});
+
+describe('SystemGrant methods', () => {
+ describe('seedSystemGrants', () => {
+ it('seeds all capabilities for the ADMIN role', async () => {
+ await methods.seedSystemGrants();
+
+ const grants = await SystemGrant.find({
+ principalType: PrincipalType.ROLE,
+ principalId: SystemRoles.ADMIN,
+ }).lean();
+
+ const expectedCount = Object.values(SystemCapabilities).length;
+ expect(grants).toHaveLength(expectedCount);
+
+ const capabilities = grants.map((g) => g.capability).sort();
+ const expected = Object.values(SystemCapabilities).sort();
+ expect(capabilities).toEqual(expected);
+ });
+
+ it('is idempotent — calling twice does not duplicate grants', async () => {
+ await methods.seedSystemGrants();
+ await methods.seedSystemGrants();
+
+ const count = await SystemGrant.countDocuments({
+ principalType: PrincipalType.ROLE,
+ principalId: SystemRoles.ADMIN,
+ });
+
+ expect(count).toBe(Object.values(SystemCapabilities).length);
+ });
+
+ it('seeds grants with no tenantId', async () => {
+ await methods.seedSystemGrants();
+
+ const withTenant = await SystemGrant.countDocuments({
+ principalType: PrincipalType.ROLE,
+ principalId: SystemRoles.ADMIN,
+ tenantId: { $exists: true },
+ });
+
+ expect(withTenant).toBe(0);
+ });
+ });
+
+ describe('grantCapability / revokeCapability', () => {
+ it('grants a capability to a user', async () => {
+ const userId = new mongoose.Types.ObjectId();
+
+ await methods.grantCapability({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ capability: SystemCapabilities.READ_USERS,
+ });
+
+ const grant = await SystemGrant.findOne({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ capability: SystemCapabilities.READ_USERS,
+ }).lean();
+
+ expect(grant).toBeTruthy();
+ expect(grant.grantedAt).toBeInstanceOf(Date);
+ });
+
+ it('upsert does not create duplicates', async () => {
+ const userId = new mongoose.Types.ObjectId();
+
+ await methods.grantCapability({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ capability: SystemCapabilities.READ_USERS,
+ });
+
+ await methods.grantCapability({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ capability: SystemCapabilities.READ_USERS,
+ });
+
+ const count = await SystemGrant.countDocuments({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ capability: SystemCapabilities.READ_USERS,
+ });
+
+ expect(count).toBe(1);
+ });
+
+ it('revokes a capability', async () => {
+ const userId = new mongoose.Types.ObjectId();
+
+ await methods.grantCapability({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ capability: SystemCapabilities.READ_USERS,
+ });
+
+ await methods.revokeCapability({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ capability: SystemCapabilities.READ_USERS,
+ });
+
+ const grant = await SystemGrant.findOne({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ capability: SystemCapabilities.READ_USERS,
+ }).lean();
+
+ expect(grant).toBeNull();
+ });
+ });
+
+ describe('hasCapabilityForPrincipals', () => {
+ it('returns true when role principal has the capability', async () => {
+ await methods.seedSystemGrants();
+
+ const principals = [
+ { principalType: PrincipalType.USER, principalId: new mongoose.Types.ObjectId() },
+ { principalType: PrincipalType.ROLE, principalId: SystemRoles.ADMIN },
+ { principalType: PrincipalType.PUBLIC },
+ ];
+
+ const result = await methods.hasCapabilityForPrincipals({
+ principals,
+ capability: SystemCapabilities.ACCESS_ADMIN,
+ });
+
+ expect(result).toBe(true);
+ });
+
+ it('returns false when no principal has the capability', async () => {
+ const principals = [
+ { principalType: PrincipalType.USER, principalId: new mongoose.Types.ObjectId() },
+ { principalType: PrincipalType.ROLE, principalId: SystemRoles.USER },
+ { principalType: PrincipalType.PUBLIC },
+ ];
+
+ const result = await methods.hasCapabilityForPrincipals({
+ principals,
+ capability: SystemCapabilities.ACCESS_ADMIN,
+ });
+
+ expect(result).toBe(false);
+ });
+
+ it('returns false for an empty principals list', async () => {
+ const result = await methods.hasCapabilityForPrincipals({
+ principals: [],
+ capability: SystemCapabilities.ACCESS_ADMIN,
+ });
+
+ expect(result).toBe(false);
+ });
+
+ it('ignores PUBLIC principals', async () => {
+ const result = await methods.hasCapabilityForPrincipals({
+ principals: [{ principalType: PrincipalType.PUBLIC }],
+ capability: SystemCapabilities.ACCESS_ADMIN,
+ });
+
+ expect(result).toBe(false);
+ });
+
+ it('matches user-level grants', async () => {
+ const userId = new mongoose.Types.ObjectId();
+
+ await methods.grantCapability({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ capability: SystemCapabilities.READ_CONFIGS,
+ });
+
+ const principals = [
+ { principalType: PrincipalType.USER, principalId: userId },
+ { principalType: PrincipalType.ROLE, principalId: SystemRoles.USER },
+ { principalType: PrincipalType.PUBLIC },
+ ];
+
+ const result = await methods.hasCapabilityForPrincipals({
+ principals,
+ capability: SystemCapabilities.READ_CONFIGS,
+ });
+
+ expect(result).toBe(true);
+ });
+
+ it('matches group-level grants', async () => {
+ const groupId = new mongoose.Types.ObjectId();
+
+ await methods.grantCapability({
+ principalType: PrincipalType.GROUP,
+ principalId: groupId,
+ capability: SystemCapabilities.READ_USAGE,
+ });
+
+ const principals = [
+ { principalType: PrincipalType.USER, principalId: new mongoose.Types.ObjectId() },
+ { principalType: PrincipalType.GROUP, principalId: groupId },
+ { principalType: PrincipalType.PUBLIC },
+ ];
+
+ const result = await methods.hasCapabilityForPrincipals({
+ principals,
+ capability: SystemCapabilities.READ_USAGE,
+ });
+
+ expect(result).toBe(true);
+ });
+ });
+
+ describe('getCapabilitiesForPrincipal', () => {
+ it('lists all capabilities for a principal', async () => {
+ await methods.seedSystemGrants();
+
+ const grants = await methods.getCapabilitiesForPrincipal({
+ principalType: PrincipalType.ROLE,
+ principalId: SystemRoles.ADMIN,
+ });
+
+ expect(grants).toHaveLength(Object.values(SystemCapabilities).length);
+ });
+
+ it('returns empty array for a principal with no grants', async () => {
+ const grants = await methods.getCapabilitiesForPrincipal({
+ principalType: PrincipalType.ROLE,
+ principalId: SystemRoles.USER,
+ });
+
+ expect(grants).toHaveLength(0);
+ });
+ });
+
+ describe('principalId normalization', () => {
+ it('grant with string userId is found by hasCapabilityForPrincipals with ObjectId', async () => {
+ const userId = new mongoose.Types.ObjectId();
+
+ await methods.grantCapability({
+ principalType: PrincipalType.USER,
+ principalId: userId.toString(), // string input
+ capability: SystemCapabilities.READ_USAGE,
+ });
+
+ const result = await methods.hasCapabilityForPrincipals({
+ principals: [{ principalType: PrincipalType.USER, principalId: userId }], // ObjectId input
+ capability: SystemCapabilities.READ_USAGE,
+ });
+
+ expect(result).toBe(true);
+ });
+
+ it('revoke with string userId removes the grant stored as ObjectId', async () => {
+ const userId = new mongoose.Types.ObjectId();
+
+ await methods.grantCapability({
+ principalType: PrincipalType.USER,
+ principalId: userId.toString(),
+ capability: SystemCapabilities.READ_USAGE,
+ });
+
+ await methods.revokeCapability({
+ principalType: PrincipalType.USER,
+ principalId: userId.toString(), // string revoke
+ capability: SystemCapabilities.READ_USAGE,
+ });
+
+ const result = await methods.hasCapabilityForPrincipals({
+ principals: [{ principalType: PrincipalType.USER, principalId: userId }],
+ capability: SystemCapabilities.READ_USAGE,
+ });
+
+ expect(result).toBe(false);
+ });
+
+ it('getCapabilitiesForPrincipal with string userId returns grants stored as ObjectId', async () => {
+ const userId = new mongoose.Types.ObjectId();
+
+ await methods.grantCapability({
+ principalType: PrincipalType.USER,
+ principalId: userId.toString(),
+ capability: SystemCapabilities.READ_USAGE,
+ });
+
+ const grants = await methods.getCapabilitiesForPrincipal({
+ principalType: PrincipalType.USER,
+ principalId: userId.toString(), // string lookup
+ });
+
+ expect(grants).toHaveLength(1);
+ expect(grants[0].capability).toBe(SystemCapabilities.READ_USAGE);
+ });
+ });
+
+ describe('tenant scoping', () => {
+ it('tenant-scoped grant does not match platform-level query', async () => {
+ const userId = new mongoose.Types.ObjectId();
+
+ await methods.grantCapability({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ capability: SystemCapabilities.READ_CONFIGS,
+ tenantId: 'tenant-1',
+ });
+
+ const result = await methods.hasCapabilityForPrincipals({
+ principals: [{ principalType: PrincipalType.USER, principalId: userId }],
+ capability: SystemCapabilities.READ_CONFIGS,
+ });
+
+ expect(result).toBe(false);
+ });
+
+ it('tenant-scoped grant matches same-tenant query', async () => {
+ const userId = new mongoose.Types.ObjectId();
+
+ await methods.grantCapability({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ capability: SystemCapabilities.READ_CONFIGS,
+ tenantId: 'tenant-1',
+ });
+
+ const result = await methods.hasCapabilityForPrincipals({
+ principals: [{ principalType: PrincipalType.USER, principalId: userId }],
+ capability: SystemCapabilities.READ_CONFIGS,
+ tenantId: 'tenant-1',
+ });
+
+ expect(result).toBe(true);
+ });
+
+ it('tenant-scoped grant does not match different tenant', async () => {
+ const userId = new mongoose.Types.ObjectId();
+
+ await methods.grantCapability({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ capability: SystemCapabilities.READ_CONFIGS,
+ tenantId: 'tenant-1',
+ });
+
+ const result = await methods.hasCapabilityForPrincipals({
+ principals: [{ principalType: PrincipalType.USER, principalId: userId }],
+ capability: SystemCapabilities.READ_CONFIGS,
+ tenantId: 'tenant-2',
+ });
+
+ expect(result).toBe(false);
+ });
+ });
+});
diff --git a/api/server/services/twoFactorService.js b/api/server/services/twoFactorService.js
index cce24e2322..313c557133 100644
--- a/api/server/services/twoFactorService.js
+++ b/api/server/services/twoFactorService.js
@@ -153,9 +153,11 @@ const generateBackupCodes = async (count = 10) => {
* @param {Object} params
* @param {Object} params.user
* @param {string} params.backupCode
+ * @param {boolean} [params.persist=true] - Whether to persist the used-mark to the database.
+ * Pass `false` when the caller will immediately overwrite `backupCodes` (e.g. re-enrollment).
* @returns {Promise}
*/
-const verifyBackupCode = async ({ user, backupCode }) => {
+const verifyBackupCode = async ({ user, backupCode, persist = true }) => {
if (!backupCode || !user || !Array.isArray(user.backupCodes)) {
return false;
}
@@ -165,17 +167,50 @@ const verifyBackupCode = async ({ user, backupCode }) => {
(codeObj) => codeObj.codeHash === hashedInput && !codeObj.used,
);
- if (matchingCode) {
+ if (!matchingCode) {
+ return false;
+ }
+
+ if (persist) {
const updatedBackupCodes = user.backupCodes.map((codeObj) =>
codeObj.codeHash === hashedInput && !codeObj.used
? { ...codeObj, used: true, usedAt: new Date() }
: codeObj,
);
- // Update the user record with the marked backup code.
await updateUser(user._id, { backupCodes: updatedBackupCodes });
- return true;
}
- return false;
+ return true;
+};
+
+/**
+ * Verifies a user's identity via TOTP token or backup code.
+ * @param {Object} params
+ * @param {Object} params.user - The user document (must include totpSecret and backupCodes).
+ * @param {string} [params.token] - A 6-digit TOTP token.
+ * @param {string} [params.backupCode] - An 8-character backup code.
+ * @param {boolean} [params.persistBackupUse=true] - Whether to mark the backup code as used in the DB.
+ * @returns {Promise<{ verified: boolean, status?: number, message?: string }>}
+ */
+const verifyOTPOrBackupCode = async ({ user, token, backupCode, persistBackupUse = true }) => {
+ if (!token && !backupCode) {
+ return { verified: false, status: 400 };
+ }
+
+ if (token) {
+ const secret = await getTOTPSecret(user.totpSecret);
+ if (!secret) {
+ return { verified: false, status: 400, message: '2FA secret is missing or corrupted' };
+ }
+ const ok = await verifyTOTP(secret, token);
+ return ok
+ ? { verified: true }
+ : { verified: false, status: 401, message: 'Invalid token or backup code' };
+ }
+
+ const ok = await verifyBackupCode({ user, backupCode, persist: persistBackupUse });
+ return ok
+ ? { verified: true }
+ : { verified: false, status: 401, message: 'Invalid token or backup code' };
};
/**
@@ -213,11 +248,12 @@ const generate2FATempToken = (userId) => {
};
module.exports = {
- generateTOTPSecret,
- generateTOTP,
- verifyTOTP,
+ verifyOTPOrBackupCode,
+ generate2FATempToken,
generateBackupCodes,
+ generateTOTPSecret,
verifyBackupCode,
getTOTPSecret,
- generate2FATempToken,
+ generateTOTP,
+ verifyTOTP,
};
diff --git a/api/server/utils/import/fork.js b/api/server/utils/import/fork.js
index c4ce8cb5d4..5df4d27af2 100644
--- a/api/server/utils/import/fork.js
+++ b/api/server/utils/import/fork.js
@@ -3,8 +3,7 @@ const { logger } = require('@librechat/data-schemas');
const { EModelEndpoint, Constants, ForkOptions } = require('librechat-data-provider');
const { createImportBatchBuilder } = require('./importBatchBuilder');
const BaseClient = require('~/app/clients/BaseClient');
-const { getConvo } = require('~/models/Conversation');
-const { getMessages } = require('~/models/Message');
+const { getConvo, getMessages } = require('~/models');
/**
* Helper function to clone messages with proper parent-child relationships and timestamps
@@ -358,16 +357,15 @@ function splitAtTargetLevel(messages, targetMessageId) {
* @param {object} params - The parameters for duplicating the conversation.
* @param {string} params.userId - The ID of the user duplicating the conversation.
* @param {string} params.conversationId - The ID of the conversation to duplicate.
+ * @param {string} [params.title] - Optional title override for the duplicate.
* @returns {Promise<{ conversation: TConversation, messages: TMessage[] }>} The duplicated conversation and messages.
*/
-async function duplicateConversation({ userId, conversationId }) {
- // Get original conversation
+async function duplicateConversation({ userId, conversationId, title }) {
const originalConvo = await getConvo(userId, conversationId);
if (!originalConvo) {
throw new Error('Conversation not found');
}
- // Get original messages
const originalMessages = await getMessages({
user: userId,
conversationId,
@@ -383,14 +381,11 @@ async function duplicateConversation({ userId, conversationId }) {
cloneMessagesWithTimestamps(messagesToClone, importBatchBuilder);
- const result = importBatchBuilder.finishConversation(
- originalConvo.title,
- new Date(),
- originalConvo,
- );
+ const duplicateTitle = title || originalConvo.title;
+ const result = importBatchBuilder.finishConversation(duplicateTitle, new Date(), originalConvo);
await importBatchBuilder.saveBatch();
logger.debug(
- `user: ${userId} | New conversation "${originalConvo.title}" duplicated from conversation ID ${conversationId}`,
+ `user: ${userId} | New conversation "${duplicateTitle}" duplicated from conversation ID ${conversationId}`,
);
const conversation = await getConvo(userId, result.conversation.conversationId);
diff --git a/api/server/utils/import/fork.spec.js b/api/server/utils/import/fork.spec.js
index 552620dc89..6fd108674a 100644
--- a/api/server/utils/import/fork.spec.js
+++ b/api/server/utils/import/fork.spec.js
@@ -1,16 +1,10 @@
const { Constants, ForkOptions } = require('librechat-data-provider');
-jest.mock('~/models/Conversation', () => ({
+jest.mock('~/models', () => ({
getConvo: jest.fn(),
bulkSaveConvos: jest.fn(),
-}));
-
-jest.mock('~/models/Message', () => ({
getMessages: jest.fn(),
bulkSaveMessages: jest.fn(),
-}));
-
-jest.mock('~/models/ConversationTag', () => ({
bulkIncrementTagCounts: jest.fn(),
}));
@@ -32,9 +26,13 @@ const {
getMessagesUpToTargetLevel,
cloneMessagesWithTimestamps,
} = require('./fork');
-const { bulkIncrementTagCounts } = require('~/models/ConversationTag');
-const { getConvo, bulkSaveConvos } = require('~/models/Conversation');
-const { getMessages, bulkSaveMessages } = require('~/models/Message');
+const {
+ bulkIncrementTagCounts,
+ getConvo,
+ bulkSaveConvos,
+ getMessages,
+ bulkSaveMessages,
+} = require('~/models');
const { createImportBatchBuilder } = require('./importBatchBuilder');
const BaseClient = require('~/app/clients/BaseClient');
diff --git a/api/server/utils/import/importBatchBuilder.js b/api/server/utils/import/importBatchBuilder.js
index 5e499043d2..29fbfa85a2 100644
--- a/api/server/utils/import/importBatchBuilder.js
+++ b/api/server/utils/import/importBatchBuilder.js
@@ -1,9 +1,7 @@
const { v4: uuidv4 } = require('uuid');
const { logger } = require('@librechat/data-schemas');
const { EModelEndpoint, Constants, openAISettings } = require('librechat-data-provider');
-const { bulkIncrementTagCounts } = require('~/models/ConversationTag');
-const { bulkSaveConvos } = require('~/models/Conversation');
-const { bulkSaveMessages } = require('~/models/Message');
+const { bulkIncrementTagCounts, bulkSaveConvos, bulkSaveMessages } = require('~/models');
/**
* Factory function for creating an instance of ImportBatchBuilder.
diff --git a/api/server/utils/import/importConversations.js b/api/server/utils/import/importConversations.js
index d9e4d4332d..e56176c609 100644
--- a/api/server/utils/import/importConversations.js
+++ b/api/server/utils/import/importConversations.js
@@ -1,7 +1,10 @@
const fs = require('fs').promises;
+const { resolveImportMaxFileSize } = require('@librechat/api');
const { logger } = require('@librechat/data-schemas');
const { getImporter } = require('./importers');
+const maxFileSize = resolveImportMaxFileSize();
+
/**
* Job definition for importing a conversation.
* @param {{ filepath, requestUserId }} job - The job object.
@@ -11,11 +14,10 @@ const importConversations = async (job) => {
try {
logger.debug(`user: ${requestUserId} | Importing conversation(s) from file...`);
- /* error if file is too large */
const fileInfo = await fs.stat(filepath);
- if (fileInfo.size > process.env.CONVERSATION_IMPORT_MAX_FILE_SIZE_BYTES) {
+ if (fileInfo.size > maxFileSize) {
throw new Error(
- `File size is ${fileInfo.size} bytes. It exceeds the maximum limit of ${process.env.CONVERSATION_IMPORT_MAX_FILE_SIZE_BYTES} bytes.`,
+ `File size is ${fileInfo.size} bytes. It exceeds the maximum limit of ${maxFileSize} bytes.`,
);
}
diff --git a/api/server/utils/import/importers-timestamp.spec.js b/api/server/utils/import/importers-timestamp.spec.js
index c7665dfe25..3fbf5bf404 100644
--- a/api/server/utils/import/importers-timestamp.spec.js
+++ b/api/server/utils/import/importers-timestamp.spec.js
@@ -3,10 +3,8 @@ const { ImportBatchBuilder } = require('./importBatchBuilder');
const { getImporter } = require('./importers');
// Mock the database methods
-jest.mock('~/models/Conversation', () => ({
+jest.mock('~/models', () => ({
bulkSaveConvos: jest.fn(),
-}));
-jest.mock('~/models/Message', () => ({
bulkSaveMessages: jest.fn(),
}));
jest.mock('~/cache/getLogStores');
diff --git a/api/server/utils/import/importers.spec.js b/api/server/utils/import/importers.spec.js
index a695a31555..7984144cbc 100644
--- a/api/server/utils/import/importers.spec.js
+++ b/api/server/utils/import/importers.spec.js
@@ -1,10 +1,9 @@
const fs = require('fs');
const path = require('path');
const { EModelEndpoint, Constants, openAISettings } = require('librechat-data-provider');
-const { bulkSaveConvos: _bulkSaveConvos } = require('~/models/Conversation');
const { getImporter, processAssistantMessage } = require('./importers');
const { ImportBatchBuilder } = require('./importBatchBuilder');
-const { bulkSaveMessages } = require('~/models/Message');
+const { bulkSaveMessages, bulkSaveConvos: _bulkSaveConvos } = require('~/models');
const getLogStores = require('~/cache/getLogStores');
jest.mock('~/cache/getLogStores');
@@ -14,10 +13,8 @@ getLogStores.mockImplementation(() => ({
}));
// Mock the database methods
-jest.mock('~/models/Conversation', () => ({
+jest.mock('~/models', () => ({
bulkSaveConvos: jest.fn(),
-}));
-jest.mock('~/models/Message', () => ({
bulkSaveMessages: jest.fn(),
}));
@@ -1277,12 +1274,9 @@ describe('processAssistantMessage', () => {
results.push(duration);
});
- // Check if processing time increases exponentially
- // In a ReDoS vulnerability, time would roughly double with each size increase
- for (let i = 1; i < results.length; i++) {
- const ratio = results[i] / results[i - 1];
- expect(ratio).toBeLessThan(3); // Allow for CI environment variability while still catching ReDoS
- console.log(`Size ${sizes[i]} processing time ratio: ${ratio}`);
+ // Each size should complete well under 100ms; a ReDoS would cause exponential blowup
+ for (let i = 0; i < results.length; i++) {
+ expect(results[i]).toBeLessThan(100);
}
// Also test with the exact payload from the security report
diff --git a/api/strategies/index.js b/api/strategies/index.js
index b4f7bd3cac..9a1c58ad38 100644
--- a/api/strategies/index.js
+++ b/api/strategies/index.js
@@ -1,4 +1,4 @@
-const { setupOpenId, getOpenIdConfig } = require('./openidStrategy');
+const { setupOpenId, getOpenIdConfig, getOpenIdEmail } = require('./openidStrategy');
const openIdJwtLogin = require('./openIdJwtStrategy');
const facebookLogin = require('./facebookStrategy');
const discordLogin = require('./discordStrategy');
@@ -20,6 +20,7 @@ module.exports = {
facebookLogin,
setupOpenId,
getOpenIdConfig,
+ getOpenIdEmail,
ldapLogin,
setupSaml,
openIdJwtLogin,
diff --git a/api/strategies/localStrategy.js b/api/strategies/localStrategy.js
index 0d220ead25..5d725c0907 100644
--- a/api/strategies/localStrategy.js
+++ b/api/strategies/localStrategy.js
@@ -1,8 +1,9 @@
+const bcrypt = require('bcryptjs');
const { logger } = require('@librechat/data-schemas');
const { errorsToString } = require('librechat-data-provider');
-const { isEnabled, checkEmailConfig } = require('@librechat/api');
const { Strategy: PassportLocalStrategy } = require('passport-local');
-const { findUser, comparePassword, updateUser } = require('~/models');
+const { isEnabled, checkEmailConfig, comparePassword } = require('@librechat/api');
+const { findUser, updateUser } = require('~/models');
const { loginSchema } = require('./validators');
// Unix timestamp for 2024-06-07 15:20:18 Eastern Time
@@ -35,7 +36,7 @@ async function passportLogin(req, email, password, done) {
return done(null, false, { message: 'Email does not exist.' });
}
- const isMatch = await comparePassword(user, password);
+ const isMatch = await comparePassword(user, password, { compare: bcrypt.compare });
if (!isMatch) {
logError('Passport Local Strategy - Password does not match', { isMatch });
logger.error(`[Login] [Login failed] [Username: ${email}] [Request-IP: ${req.ip}]`);
diff --git a/api/strategies/openIdJwtStrategy.js b/api/strategies/openIdJwtStrategy.js
index 997dcec397..83a40bf948 100644
--- a/api/strategies/openIdJwtStrategy.js
+++ b/api/strategies/openIdJwtStrategy.js
@@ -5,6 +5,7 @@ const { HttpsProxyAgent } = require('https-proxy-agent');
const { SystemRoles } = require('librechat-data-provider');
const { isEnabled, findOpenIDUser, math } = require('@librechat/api');
const { Strategy: JwtStrategy, ExtractJwt } = require('passport-jwt');
+const { getOpenIdEmail } = require('./openidStrategy');
const { updateUser, findUser } = require('~/models');
/**
@@ -53,7 +54,7 @@ const openIdJwtLogin = (openIdConfig) => {
const { user, error, migration } = await findOpenIDUser({
findUser,
- email: payload?.email,
+ email: payload ? getOpenIdEmail(payload) : undefined,
openidId: payload?.sub,
idOnTheSource: payload?.oid,
strategyName: 'openIdJwtLogin',
diff --git a/api/strategies/openIdJwtStrategy.spec.js b/api/strategies/openIdJwtStrategy.spec.js
index 566afe5a90..79af848046 100644
--- a/api/strategies/openIdJwtStrategy.spec.js
+++ b/api/strategies/openIdJwtStrategy.spec.js
@@ -29,10 +29,21 @@ jest.mock('~/models', () => ({
findUser: jest.fn(),
updateUser: jest.fn(),
}));
+jest.mock('~/server/services/Files/strategies', () => ({
+ getStrategyFunctions: jest.fn(() => ({
+ saveBuffer: jest.fn().mockResolvedValue('/fake/path/to/avatar.png'),
+ })),
+}));
+jest.mock('~/server/services/Config', () => ({
+ getAppConfig: jest.fn().mockResolvedValue({}),
+}));
+jest.mock('~/cache/getLogStores', () =>
+ jest.fn().mockReturnValue({ get: jest.fn(), set: jest.fn() }),
+);
const { findOpenIDUser } = require('@librechat/api');
-const { updateUser } = require('~/models');
const openIdJwtLogin = require('./openIdJwtStrategy');
+const { findUser, updateUser } = require('~/models');
// Helper: build a mock openIdConfig
const mockOpenIdConfig = {
@@ -181,3 +192,156 @@ describe('openIdJwtStrategy – token source handling', () => {
expect(user.federatedTokens.access_token).not.toBe(user.federatedTokens.id_token);
});
});
+
+describe('openIdJwtStrategy – OPENID_EMAIL_CLAIM', () => {
+ const payload = {
+ sub: 'oidc-123',
+ email: 'test@example.com',
+ preferred_username: 'testuser',
+ upn: 'test@corp.example.com',
+ exp: 9999999999,
+ };
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ delete process.env.OPENID_EMAIL_CLAIM;
+
+ // Use real findOpenIDUser so it delegates to the findUser mock
+ const realFindOpenIDUser = jest.requireActual('@librechat/api').findOpenIDUser;
+ findOpenIDUser.mockImplementation(realFindOpenIDUser);
+
+ findUser.mockResolvedValue(null);
+ updateUser.mockResolvedValue({});
+
+ openIdJwtLogin(mockOpenIdConfig);
+ });
+
+ afterEach(() => {
+ delete process.env.OPENID_EMAIL_CLAIM;
+ });
+
+ it('should use the default email when OPENID_EMAIL_CLAIM is not set', async () => {
+ const existingUser = {
+ _id: 'user-id-1',
+ provider: 'openid',
+ openidId: payload.sub,
+ email: payload.email,
+ role: SystemRoles.USER,
+ };
+ findUser.mockImplementation(async (query) => {
+ if (query.$or && query.$or.some((c) => c.openidId === payload.sub)) {
+ return existingUser;
+ }
+ return null;
+ });
+
+ const req = { headers: { authorization: 'Bearer tok' }, session: {} };
+ await invokeVerify(req, payload);
+
+ expect(findUser).toHaveBeenCalledWith(
+ expect.objectContaining({
+ $or: expect.arrayContaining([{ openidId: payload.sub }]),
+ }),
+ );
+ });
+
+ it('should use OPENID_EMAIL_CLAIM when set for email lookup', async () => {
+ process.env.OPENID_EMAIL_CLAIM = 'upn';
+ findUser.mockResolvedValue(null);
+
+ const req = { headers: { authorization: 'Bearer tok' }, session: {} };
+ const { user } = await invokeVerify(req, payload);
+
+ expect(findUser).toHaveBeenCalledTimes(2);
+ expect(findUser.mock.calls[0][0]).toMatchObject({
+ $or: expect.arrayContaining([{ openidId: payload.sub }]),
+ });
+ expect(findUser.mock.calls[1][0]).toEqual({ email: 'test@corp.example.com' });
+ expect(user).toBe(false);
+ });
+
+ it('should fall back to default chain when OPENID_EMAIL_CLAIM points to missing claim', async () => {
+ process.env.OPENID_EMAIL_CLAIM = 'nonexistent_claim';
+ findUser.mockResolvedValue(null);
+
+ const req = { headers: { authorization: 'Bearer tok' }, session: {} };
+ const { user } = await invokeVerify(req, payload);
+
+ expect(findUser).toHaveBeenCalledWith({ email: payload.email });
+ expect(user).toBe(false);
+ });
+
+ it('should trim whitespace from OPENID_EMAIL_CLAIM', async () => {
+ process.env.OPENID_EMAIL_CLAIM = ' upn ';
+ findUser.mockResolvedValue(null);
+
+ const req = { headers: { authorization: 'Bearer tok' }, session: {} };
+ await invokeVerify(req, payload);
+
+ expect(findUser).toHaveBeenCalledWith({ email: 'test@corp.example.com' });
+ });
+
+ it('should ignore empty string OPENID_EMAIL_CLAIM and use default fallback', async () => {
+ process.env.OPENID_EMAIL_CLAIM = '';
+ findUser.mockResolvedValue(null);
+
+ const req = { headers: { authorization: 'Bearer tok' }, session: {} };
+ await invokeVerify(req, payload);
+
+ expect(findUser).toHaveBeenCalledWith({ email: payload.email });
+ });
+
+ it('should ignore whitespace-only OPENID_EMAIL_CLAIM and use default fallback', async () => {
+ process.env.OPENID_EMAIL_CLAIM = ' ';
+ findUser.mockResolvedValue(null);
+
+ const req = { headers: { authorization: 'Bearer tok' }, session: {} };
+ await invokeVerify(req, payload);
+
+ expect(findUser).toHaveBeenCalledWith({ email: payload.email });
+ });
+
+ it('should resolve undefined email when payload is null', async () => {
+ const req = { headers: { authorization: 'Bearer tok' }, session: {} };
+ const { user } = await invokeVerify(req, null);
+
+ expect(user).toBe(false);
+ });
+
+ it('should attempt email lookup via preferred_username fallback when email claim is absent', async () => {
+ const payloadNoEmail = {
+ sub: 'oidc-new-sub',
+ preferred_username: 'legacy@corp.com',
+ upn: 'legacy@corp.com',
+ exp: 9999999999,
+ };
+
+ const legacyUser = {
+ _id: 'legacy-db-id',
+ email: 'legacy@corp.com',
+ openidId: null,
+ role: SystemRoles.USER,
+ };
+
+ findUser.mockImplementation(async (query) => {
+ if (query.$or) {
+ return null;
+ }
+ if (query.email === 'legacy@corp.com') {
+ return legacyUser;
+ }
+ return null;
+ });
+
+ const req = { headers: { authorization: 'Bearer tok' }, session: {} };
+ const { user } = await invokeVerify(req, payloadNoEmail);
+
+ expect(findUser).toHaveBeenCalledTimes(2);
+ expect(findUser.mock.calls[1][0]).toEqual({ email: 'legacy@corp.com' });
+ expect(user).toBeTruthy();
+ expect(updateUser).toHaveBeenCalledWith(
+ 'legacy-db-id',
+ expect.objectContaining({ provider: 'openid', openidId: payloadNoEmail.sub }),
+ );
+ });
+});
diff --git a/api/strategies/openidStrategy.js b/api/strategies/openidStrategy.js
index 198c8735ae..7c43358297 100644
--- a/api/strategies/openidStrategy.js
+++ b/api/strategies/openidStrategy.js
@@ -267,6 +267,34 @@ function getFullName(userinfo) {
return userinfo.username || userinfo.email;
}
+/**
+ * Resolves the user identifier from OpenID claims.
+ * Configurable via OPENID_EMAIL_CLAIM; defaults to: email -> preferred_username -> upn.
+ *
+ * @param {Object} userinfo - The user information object from OpenID Connect
+ * @returns {string|undefined} The resolved identifier string
+ */
+function getOpenIdEmail(userinfo) {
+ const claimKey = process.env.OPENID_EMAIL_CLAIM?.trim();
+ if (claimKey) {
+ const value = userinfo[claimKey];
+ if (typeof value === 'string' && value) {
+ return value;
+ }
+ if (value !== undefined && value !== null) {
+ logger.warn(
+ `[openidStrategy] OPENID_EMAIL_CLAIM="${claimKey}" resolved to a non-string value (type: ${typeof value}). Falling back to: email -> preferred_username -> upn.`,
+ );
+ } else {
+ logger.warn(
+ `[openidStrategy] OPENID_EMAIL_CLAIM="${claimKey}" not present in userinfo. Falling back to: email -> preferred_username -> upn.`,
+ );
+ }
+ }
+ const fallback = userinfo.email || userinfo.preferred_username || userinfo.upn;
+ return typeof fallback === 'string' ? fallback : undefined;
+}
+
/**
* Converts an input into a string suitable for a username.
* If the input is a string, it will be returned as is.
@@ -287,24 +315,85 @@ function convertToUsername(input, defaultValue = '') {
return defaultValue;
}
+/**
+ * Exchange the access token for a Graph-scoped token using the On-Behalf-Of (OBO) flow.
+ *
+ * The original access token has the app's own audience (api://), which Microsoft Graph
+ * rejects. This exchange produces a token with audience https://graph.microsoft.com and the
+ * minimum delegated scope (User.Read) required by /me/getMemberObjects.
+ *
+ * Uses a dedicated cache key (`${sub}:overage`) to avoid collisions with other OBO exchanges
+ * in the codebase (userinfo, Graph principal search).
+ *
+ * @param {string} accessToken - The original access token from the OpenID tokenset
+ * @param {string} sub - The subject identifier for cache keying
+ * @returns {Promise} A Graph-scoped access token
+ * @see https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-on-behalf-of-flow
+ */
+async function exchangeTokenForOverage(accessToken, sub) {
+ if (!openidConfig) {
+ throw new Error('[openidStrategy] OpenID config not initialized; cannot exchange OBO token');
+ }
+
+ const tokensCache = getLogStores(CacheKeys.OPENID_EXCHANGED_TOKENS);
+ const cacheKey = `${sub}:overage`;
+
+ const cached = await tokensCache.get(cacheKey);
+ if (cached?.access_token) {
+ logger.debug('[openidStrategy] Using cached Graph token for overage resolution');
+ return cached.access_token;
+ }
+
+ const grantResponse = await client.genericGrantRequest(
+ openidConfig,
+ 'urn:ietf:params:oauth:grant-type:jwt-bearer',
+ {
+ scope: 'https://graph.microsoft.com/User.Read',
+ assertion: accessToken,
+ requested_token_use: 'on_behalf_of',
+ },
+ );
+
+ if (!grantResponse.access_token) {
+ throw new Error(
+ '[openidStrategy] OBO exchange succeeded but returned no access_token; cannot call Graph API',
+ );
+ }
+
+ const ttlMs =
+ Number.isFinite(grantResponse.expires_in) && grantResponse.expires_in > 0
+ ? grantResponse.expires_in * 1000
+ : 3600 * 1000;
+
+ await tokensCache.set(cacheKey, { access_token: grantResponse.access_token }, ttlMs);
+
+ return grantResponse.access_token;
+}
+
/**
* Resolve Azure AD groups when group overage is in effect (groups moved to _claim_names/_claim_sources).
*
* NOTE: Microsoft recommends treating _claim_names/_claim_sources as a signal only and using Microsoft Graph
* to resolve group membership instead of calling the endpoint in _claim_sources directly.
*
- * @param {string} accessToken - Access token with Microsoft Graph permissions
+ * Before calling Graph, the access token is exchanged via the OBO flow to obtain a token with the
+ * correct audience (https://graph.microsoft.com) and User.Read scope.
+ *
+ * @param {string} accessToken - Access token from the OpenID tokenset (app audience)
+ * @param {string} sub - The subject identifier of the user (for OBO exchange and cache keying)
* @returns {Promise} Resolved group IDs or null on failure
* @see https://learn.microsoft.com/en-us/entra/identity-platform/access-token-claims-reference#groups-overage-claim
* @see https://learn.microsoft.com/en-us/graph/api/directoryobject-getmemberobjects
*/
-async function resolveGroupsFromOverage(accessToken) {
+async function resolveGroupsFromOverage(accessToken, sub) {
try {
if (!accessToken) {
logger.error('[openidStrategy] Access token missing; cannot resolve group overage');
return null;
}
+ const graphToken = await exchangeTokenForOverage(accessToken, sub);
+
// Use /me/getMemberObjects so least-privileged delegated permission User.Read is sufficient
// when resolving the signed-in user's group membership.
const url = 'https://graph.microsoft.com/v1.0/me/getMemberObjects';
@@ -316,7 +405,7 @@ async function resolveGroupsFromOverage(accessToken) {
const fetchOptions = {
method: 'POST',
headers: {
- Authorization: `Bearer ${accessToken}`,
+ Authorization: `Bearer ${graphToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ securityEnabledOnly: false }),
@@ -336,6 +425,7 @@ async function resolveGroupsFromOverage(accessToken) {
}
const data = await response.json();
+
const values = Array.isArray(data?.value) ? data.value : null;
if (!values) {
logger.error(
@@ -379,11 +469,10 @@ async function processOpenIDAuth(tokenset, existingUsersOnly = false) {
}
const appConfig = await getAppConfig();
- /** Azure AD sometimes doesn't return email, use preferred_username as fallback */
- const email = userinfo.email || userinfo.preferred_username || userinfo.upn;
+ const email = getOpenIdEmail(userinfo);
if (!isEmailDomainAllowed(email, appConfig?.registration?.allowedDomains)) {
logger.error(
- `[OpenID Strategy] Authentication blocked - email domain not allowed [Email: ${userinfo.email}]`,
+ `[OpenID Strategy] Authentication blocked - email domain not allowed [Identifier: ${email}]`,
);
throw new Error('Email domain not allowed');
}
@@ -405,6 +494,8 @@ async function processOpenIDAuth(tokenset, existingUsersOnly = false) {
const fullName = getFullName(userinfo);
const requiredRole = process.env.OPENID_REQUIRED_ROLE;
+ let resolvedOverageGroups = null;
+
if (requiredRole) {
const requiredRoles = requiredRole
.split(',')
@@ -424,19 +515,21 @@ async function processOpenIDAuth(tokenset, existingUsersOnly = false) {
// Handle Azure AD group overage for ID token groups: when hasgroups or _claim_* indicate overage,
// resolve groups via Microsoft Graph instead of relying on token group values.
+ const hasOverage =
+ decodedToken?.hasgroups ||
+ (decodedToken?._claim_names?.groups &&
+ decodedToken?._claim_sources?.[decodedToken._claim_names.groups]);
+
if (
- !Array.isArray(roles) &&
- typeof roles !== 'string' &&
requiredRoleTokenKind === 'id' &&
requiredRoleParameterPath === 'groups' &&
decodedToken &&
- (decodedToken.hasgroups ||
- (decodedToken._claim_names?.groups &&
- decodedToken._claim_sources?.[decodedToken._claim_names.groups]))
+ hasOverage
) {
- const overageGroups = await resolveGroupsFromOverage(tokenset.access_token);
+ const overageGroups = await resolveGroupsFromOverage(tokenset.access_token, claims.sub);
if (overageGroups) {
roles = overageGroups;
+ resolvedOverageGroups = overageGroups;
}
}
@@ -451,7 +544,7 @@ async function processOpenIDAuth(tokenset, existingUsersOnly = false) {
throw new Error(`You must have ${rolesList} role to log in.`);
}
- const roleValues = Array.isArray(roles) ? roles : [roles];
+ const roleValues = Array.isArray(roles) ? roles : roles.split(/[\s,]+/).filter(Boolean);
if (!requiredRoles.some((role) => roleValues.includes(role))) {
const rolesList =
@@ -523,14 +616,33 @@ async function processOpenIDAuth(tokenset, existingUsersOnly = false) {
throw new Error('Invalid admin role token kind');
}
- const adminRoles = get(adminRoleObject, adminRoleParameterPath);
+ let adminRoles = get(adminRoleObject, adminRoleParameterPath);
- if (
- adminRoles &&
- (adminRoles === true ||
- adminRoles === adminRole ||
- (Array.isArray(adminRoles) && adminRoles.includes(adminRole)))
- ) {
+ // Handle Azure AD group overage for admin role when using ID token groups
+ if (adminRoleTokenKind === 'id' && adminRoleParameterPath === 'groups' && adminRoleObject) {
+ const hasAdminOverage =
+ adminRoleObject.hasgroups ||
+ (adminRoleObject._claim_names?.groups &&
+ adminRoleObject._claim_sources?.[adminRoleObject._claim_names.groups]);
+
+ if (hasAdminOverage) {
+ const overageGroups =
+ resolvedOverageGroups ||
+ (await resolveGroupsFromOverage(tokenset.access_token, claims.sub));
+ if (overageGroups) {
+ adminRoles = overageGroups;
+ }
+ }
+ }
+
+ let adminRoleValues = [];
+ if (Array.isArray(adminRoles)) {
+ adminRoleValues = adminRoles;
+ } else if (typeof adminRoles === 'string') {
+ adminRoleValues = adminRoles.split(/[\s,]+/).filter(Boolean);
+ }
+
+ if (adminRoles && (adminRoles === true || adminRoleValues.includes(adminRole))) {
user.role = SystemRoles.ADMIN;
logger.info(`[openidStrategy] User ${username} is an admin based on role: ${adminRole}`);
} else if (user.role === SystemRoles.ADMIN) {
@@ -727,4 +839,5 @@ function getOpenIdConfig() {
module.exports = {
setupOpenId,
getOpenIdConfig,
+ getOpenIdEmail,
};
diff --git a/api/strategies/openidStrategy.spec.js b/api/strategies/openidStrategy.spec.js
index b1dc54d77b..16fa548a59 100644
--- a/api/strategies/openidStrategy.spec.js
+++ b/api/strategies/openidStrategy.spec.js
@@ -1,6 +1,6 @@
+const undici = require('undici');
const fetch = require('node-fetch');
const jwtDecode = require('jsonwebtoken/decode');
-const undici = require('undici');
const { ErrorTypes } = require('librechat-data-provider');
const { findUser, createUser, updateUser } = require('~/models');
const { setupOpenId } = require('./openidStrategy');
@@ -64,6 +64,10 @@ jest.mock('openid-client', () => {
// Only return additional properties, but don't override any claims
return Promise.resolve({});
}),
+ genericGrantRequest: jest.fn().mockResolvedValue({
+ access_token: 'exchanged_graph_token',
+ expires_in: 3600,
+ }),
customFetch: Symbol('customFetch'),
};
});
@@ -152,6 +156,7 @@ describe('setupOpenId', () => {
process.env.OPENID_ADMIN_ROLE_TOKEN_KIND = 'id';
delete process.env.OPENID_USERNAME_CLAIM;
delete process.env.OPENID_NAME_CLAIM;
+ delete process.env.OPENID_EMAIL_CLAIM;
delete process.env.PROXY;
delete process.env.OPENID_USE_PKCE;
@@ -384,6 +389,62 @@ describe('setupOpenId', () => {
expect(details.message).toBe('You must have "read" role to log in.');
});
+ it('should allow login when roles claim is a space-separated string containing the required role', async () => {
+ // Arrange – IdP returns roles as a space-delimited string
+ jwtDecode.mockReturnValue({
+ roles: 'role1 role2 requiredRole',
+ });
+
+ // Act
+ const { user } = await validate(tokenset);
+
+ // Assert – login succeeds when required role is present after splitting
+ expect(user).toBeTruthy();
+ expect(createUser).toHaveBeenCalled();
+ });
+
+ it('should allow login when roles claim is a comma-separated string containing the required role', async () => {
+ // Arrange – IdP returns roles as a comma-delimited string
+ jwtDecode.mockReturnValue({
+ roles: 'role1,role2,requiredRole',
+ });
+
+ // Act
+ const { user } = await validate(tokenset);
+
+ // Assert – login succeeds when required role is present after splitting
+ expect(user).toBeTruthy();
+ expect(createUser).toHaveBeenCalled();
+ });
+
+ it('should allow login when roles claim is a mixed comma-and-space-separated string containing the required role', async () => {
+ // Arrange – IdP returns roles with comma-and-space delimiters
+ jwtDecode.mockReturnValue({
+ roles: 'role1, role2, requiredRole',
+ });
+
+ // Act
+ const { user } = await validate(tokenset);
+
+ // Assert – login succeeds when required role is present after splitting
+ expect(user).toBeTruthy();
+ expect(createUser).toHaveBeenCalled();
+ });
+
+ it('should reject login when roles claim is a space-separated string that does not contain the required role', async () => {
+ // Arrange – IdP returns a delimited string but required role is absent
+ jwtDecode.mockReturnValue({
+ roles: 'role1 role2 otherRole',
+ });
+
+ // Act
+ const { user, details } = await validate(tokenset);
+
+ // Assert – login is rejected with the correct error message
+ expect(user).toBe(false);
+ expect(details.message).toBe('You must have "requiredRole" role to log in.');
+ });
+
it('should allow login when single required role is present (backward compatibility)', async () => {
// Arrange – ensure single role configuration (as set in beforeEach)
// OPENID_REQUIRED_ROLE = 'requiredRole'
@@ -673,7 +734,7 @@ describe('setupOpenId', () => {
expect.objectContaining({
method: 'POST',
headers: expect.objectContaining({
- Authorization: `Bearer ${tokenset.access_token}`,
+ Authorization: 'Bearer exchanged_graph_token',
}),
}),
);
@@ -688,6 +749,313 @@ describe('setupOpenId', () => {
);
});
+ describe('OBO token exchange for overage', () => {
+ it('exchanges access token via OBO before calling Graph API', async () => {
+ const openidClient = require('openid-client');
+ process.env.OPENID_REQUIRED_ROLE = 'group-required';
+ process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND = 'id';
+
+ jwtDecode.mockReturnValue({ hasgroups: true });
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ undici.fetch.mockResolvedValue({
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ json: async () => ({ value: ['group-required'] }),
+ });
+
+ await validate(tokenset);
+
+ expect(openidClient.genericGrantRequest).toHaveBeenCalledWith(
+ expect.anything(),
+ 'urn:ietf:params:oauth:grant-type:jwt-bearer',
+ expect.objectContaining({
+ scope: 'https://graph.microsoft.com/User.Read',
+ assertion: tokenset.access_token,
+ requested_token_use: 'on_behalf_of',
+ }),
+ );
+
+ expect(undici.fetch).toHaveBeenCalledWith(
+ 'https://graph.microsoft.com/v1.0/me/getMemberObjects',
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ Authorization: 'Bearer exchanged_graph_token',
+ }),
+ }),
+ );
+ });
+
+ it('caches the exchanged token and reuses it on subsequent calls', async () => {
+ const openidClient = require('openid-client');
+ const getLogStores = require('~/cache/getLogStores');
+ const mockSet = jest.fn();
+ const mockGet = jest
+ .fn()
+ .mockResolvedValueOnce(undefined)
+ .mockResolvedValueOnce({ access_token: 'exchanged_graph_token' });
+ getLogStores.mockReturnValue({ get: mockGet, set: mockSet });
+
+ process.env.OPENID_REQUIRED_ROLE = 'group-required';
+ process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND = 'id';
+
+ jwtDecode.mockReturnValue({ hasgroups: true });
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ undici.fetch.mockResolvedValue({
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ json: async () => ({ value: ['group-required'] }),
+ });
+
+ // First call: cache miss → OBO exchange → cache set
+ await validate(tokenset);
+ expect(mockSet).toHaveBeenCalledWith(
+ '1234:overage',
+ { access_token: 'exchanged_graph_token' },
+ 3600000,
+ );
+ expect(openidClient.genericGrantRequest).toHaveBeenCalledTimes(1);
+
+ // Second call: cache hit → no new OBO exchange
+ openidClient.genericGrantRequest.mockClear();
+ await validate(tokenset);
+ expect(openidClient.genericGrantRequest).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('admin role group overage', () => {
+ it('resolves admin groups via Graph when overage is detected for admin role', async () => {
+ process.env.OPENID_REQUIRED_ROLE = 'group-required';
+ process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND = 'id';
+ process.env.OPENID_ADMIN_ROLE = 'admin-group-id';
+ process.env.OPENID_ADMIN_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_ADMIN_ROLE_TOKEN_KIND = 'id';
+
+ jwtDecode.mockReturnValue({ hasgroups: true });
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ undici.fetch.mockResolvedValue({
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ json: async () => ({ value: ['group-required', 'admin-group-id'] }),
+ });
+
+ const { user } = await validate(tokenset);
+
+ expect(user.role).toBe('ADMIN');
+ });
+
+ it('does not grant admin when overage groups do not contain admin role', async () => {
+ process.env.OPENID_REQUIRED_ROLE = 'group-required';
+ process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND = 'id';
+ process.env.OPENID_ADMIN_ROLE = 'admin-group-id';
+ process.env.OPENID_ADMIN_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_ADMIN_ROLE_TOKEN_KIND = 'id';
+
+ jwtDecode.mockReturnValue({ hasgroups: true });
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ undici.fetch.mockResolvedValue({
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ json: async () => ({ value: ['group-required', 'other-group'] }),
+ });
+
+ const { user } = await validate(tokenset);
+
+ expect(user).toBeTruthy();
+ expect(user.role).toBeUndefined();
+ });
+
+ it('reuses already-resolved overage groups for admin role check (no duplicate Graph call)', async () => {
+ process.env.OPENID_REQUIRED_ROLE = 'group-required';
+ process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND = 'id';
+ process.env.OPENID_ADMIN_ROLE = 'admin-group-id';
+ process.env.OPENID_ADMIN_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_ADMIN_ROLE_TOKEN_KIND = 'id';
+
+ jwtDecode.mockReturnValue({ hasgroups: true });
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ undici.fetch.mockResolvedValue({
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ json: async () => ({ value: ['group-required', 'admin-group-id'] }),
+ });
+
+ await validate(tokenset);
+
+ // Graph API should be called only once (for required role), admin role reuses the result
+ expect(undici.fetch).toHaveBeenCalledTimes(1);
+ });
+
+ it('demotes existing admin when overage groups no longer contain admin role', async () => {
+ process.env.OPENID_REQUIRED_ROLE = 'group-required';
+ process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND = 'id';
+ process.env.OPENID_ADMIN_ROLE = 'admin-group-id';
+ process.env.OPENID_ADMIN_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_ADMIN_ROLE_TOKEN_KIND = 'id';
+
+ const existingAdminUser = {
+ _id: 'existingAdminId',
+ provider: 'openid',
+ email: tokenset.claims().email,
+ openidId: tokenset.claims().sub,
+ username: 'adminuser',
+ name: 'Admin User',
+ role: 'ADMIN',
+ };
+
+ findUser.mockImplementation(async (query) => {
+ if (query.openidId === tokenset.claims().sub || query.email === tokenset.claims().email) {
+ return existingAdminUser;
+ }
+ return null;
+ });
+
+ jwtDecode.mockReturnValue({ hasgroups: true });
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ undici.fetch.mockResolvedValue({
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ json: async () => ({ value: ['group-required'] }),
+ });
+
+ const { user } = await validate(tokenset);
+
+ expect(user.role).toBe('USER');
+ });
+
+ it('does not attempt overage for admin role when token kind is not id', async () => {
+ process.env.OPENID_REQUIRED_ROLE = 'requiredRole';
+ process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH = 'roles';
+ process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND = 'id';
+ process.env.OPENID_ADMIN_ROLE = 'admin';
+ process.env.OPENID_ADMIN_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_ADMIN_ROLE_TOKEN_KIND = 'access';
+
+ jwtDecode.mockReturnValue({
+ roles: ['requiredRole'],
+ hasgroups: true,
+ });
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ const { user } = await validate(tokenset);
+
+ // No Graph call since admin uses access token (not id)
+ expect(undici.fetch).not.toHaveBeenCalled();
+ expect(user.role).toBeUndefined();
+ });
+
+ it('resolves admin via Graph independently when OPENID_REQUIRED_ROLE is not configured', async () => {
+ delete process.env.OPENID_REQUIRED_ROLE;
+ process.env.OPENID_ADMIN_ROLE = 'admin-group-id';
+ process.env.OPENID_ADMIN_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_ADMIN_ROLE_TOKEN_KIND = 'id';
+
+ jwtDecode.mockReturnValue({ hasgroups: true });
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ undici.fetch.mockResolvedValue({
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ json: async () => ({ value: ['admin-group-id'] }),
+ });
+
+ const { user } = await validate(tokenset);
+ expect(user.role).toBe('ADMIN');
+ expect(undici.fetch).toHaveBeenCalledTimes(1);
+ });
+
+ it('denies admin when OPENID_REQUIRED_ROLE is absent and Graph does not contain admin group', async () => {
+ delete process.env.OPENID_REQUIRED_ROLE;
+ process.env.OPENID_ADMIN_ROLE = 'admin-group-id';
+ process.env.OPENID_ADMIN_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_ADMIN_ROLE_TOKEN_KIND = 'id';
+
+ jwtDecode.mockReturnValue({ hasgroups: true });
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ undici.fetch.mockResolvedValue({
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ json: async () => ({ value: ['other-group'] }),
+ });
+
+ const { user } = await validate(tokenset);
+ expect(user).toBeTruthy();
+ expect(user.role).toBeUndefined();
+ });
+
+ it('denies login and logs error when OBO exchange throws', async () => {
+ const openidClient = require('openid-client');
+ process.env.OPENID_REQUIRED_ROLE = 'group-required';
+ process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND = 'id';
+
+ jwtDecode.mockReturnValue({ hasgroups: true });
+ openidClient.genericGrantRequest.mockRejectedValueOnce(new Error('OBO exchange rejected'));
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ const { user, details } = await validate(tokenset);
+ expect(user).toBe(false);
+ expect(details.message).toBe('You must have "group-required" role to log in.');
+ expect(undici.fetch).not.toHaveBeenCalled();
+ });
+
+ it('denies login when OBO exchange returns no access_token', async () => {
+ const openidClient = require('openid-client');
+ process.env.OPENID_REQUIRED_ROLE = 'group-required';
+ process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND = 'id';
+
+ jwtDecode.mockReturnValue({ hasgroups: true });
+ openidClient.genericGrantRequest.mockResolvedValueOnce({ expires_in: 3600 });
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ const { user, details } = await validate(tokenset);
+ expect(user).toBe(false);
+ expect(details.message).toBe('You must have "group-required" role to log in.');
+ expect(undici.fetch).not.toHaveBeenCalled();
+ });
+ });
+
it('should attempt to download and save the avatar if picture is provided', async () => {
// Act
const { user } = await validate(tokenset);
@@ -1182,6 +1550,46 @@ describe('setupOpenId', () => {
expect(user.role).toBeUndefined();
});
+ it('should grant admin when admin role claim is a space-separated string containing the admin role', async () => {
+ // Arrange – IdP returns admin roles as a space-delimited string
+ process.env.OPENID_ADMIN_ROLE = 'site-admin';
+ process.env.OPENID_ADMIN_ROLE_PARAMETER_PATH = 'app_roles';
+
+ jwtDecode.mockReturnValue({
+ roles: ['requiredRole'],
+ app_roles: 'user site-admin moderator',
+ });
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ // Act
+ const { user } = await validate(tokenset);
+
+ // Assert – admin role is granted after splitting the delimited string
+ expect(user.role).toBe('ADMIN');
+ });
+
+ it('should not grant admin when admin role claim is a space-separated string that does not contain the admin role', async () => {
+ // Arrange – delimited string present but admin role is absent
+ process.env.OPENID_ADMIN_ROLE = 'site-admin';
+ process.env.OPENID_ADMIN_ROLE_PARAMETER_PATH = 'app_roles';
+
+ jwtDecode.mockReturnValue({
+ roles: ['requiredRole'],
+ app_roles: 'user moderator',
+ });
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ // Act
+ const { user } = await validate(tokenset);
+
+ // Assert – admin role is not granted
+ expect(user.role).toBeUndefined();
+ });
+
it('should handle nested path with special characters in keys', async () => {
process.env.OPENID_REQUIRED_ROLE = 'app-user';
process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH = 'resource_access.my-app-123.roles';
@@ -1306,4 +1714,82 @@ describe('setupOpenId', () => {
expect(user).toBe(false);
});
});
+
+ describe('OPENID_EMAIL_CLAIM', () => {
+ it('should use the default email when OPENID_EMAIL_CLAIM is not set', async () => {
+ const { user } = await validate(tokenset);
+ expect(user.email).toBe('test@example.com');
+ });
+
+ it('should use the configured claim when OPENID_EMAIL_CLAIM is set', async () => {
+ process.env.OPENID_EMAIL_CLAIM = 'upn';
+ const userinfo = { ...tokenset.claims(), upn: 'user@corp.example.com' };
+
+ const { user } = await validate({ ...tokenset, claims: () => userinfo });
+
+ expect(user.email).toBe('user@corp.example.com');
+ expect(createUser).toHaveBeenCalledWith(
+ expect.objectContaining({ email: 'user@corp.example.com' }),
+ expect.anything(),
+ true,
+ true,
+ );
+ });
+
+ it('should fall back to preferred_username when email is missing and OPENID_EMAIL_CLAIM is not set', async () => {
+ const userinfo = { ...tokenset.claims() };
+ delete userinfo.email;
+
+ const { user } = await validate({ ...tokenset, claims: () => userinfo });
+
+ expect(user.email).toBe('testusername');
+ });
+
+ it('should fall back to upn when email and preferred_username are missing and OPENID_EMAIL_CLAIM is not set', async () => {
+ const userinfo = { ...tokenset.claims(), upn: 'user@corp.example.com' };
+ delete userinfo.email;
+ delete userinfo.preferred_username;
+
+ const { user } = await validate({ ...tokenset, claims: () => userinfo });
+
+ expect(user.email).toBe('user@corp.example.com');
+ });
+
+ it('should ignore empty string OPENID_EMAIL_CLAIM and use default fallback', async () => {
+ process.env.OPENID_EMAIL_CLAIM = '';
+
+ const { user } = await validate(tokenset);
+
+ expect(user.email).toBe('test@example.com');
+ });
+
+ it('should trim whitespace from OPENID_EMAIL_CLAIM and resolve correctly', async () => {
+ process.env.OPENID_EMAIL_CLAIM = ' upn ';
+ const userinfo = { ...tokenset.claims(), upn: 'user@corp.example.com' };
+
+ const { user } = await validate({ ...tokenset, claims: () => userinfo });
+
+ expect(user.email).toBe('user@corp.example.com');
+ });
+
+ it('should ignore whitespace-only OPENID_EMAIL_CLAIM and use default fallback', async () => {
+ process.env.OPENID_EMAIL_CLAIM = ' ';
+
+ const { user } = await validate(tokenset);
+
+ expect(user.email).toBe('test@example.com');
+ });
+
+ it('should fall back to default chain with warning when configured claim is missing from userinfo', async () => {
+ const { logger } = require('@librechat/data-schemas');
+ process.env.OPENID_EMAIL_CLAIM = 'nonexistent_claim';
+
+ const { user } = await validate(tokenset);
+
+ expect(user.email).toBe('test@example.com');
+ expect(logger.warn).toHaveBeenCalledWith(
+ expect.stringContaining('OPENID_EMAIL_CLAIM="nonexistent_claim" not present in userinfo'),
+ );
+ });
+ });
});
diff --git a/api/strategies/samlStrategy.spec.js b/api/strategies/samlStrategy.spec.js
index 06c969ce46..1d16719b87 100644
--- a/api/strategies/samlStrategy.spec.js
+++ b/api/strategies/samlStrategy.spec.js
@@ -1,5 +1,4 @@
// --- Mocks ---
-jest.mock('tiktoken');
jest.mock('fs');
jest.mock('path');
jest.mock('node-fetch');
diff --git a/api/test/server/services/Files/S3/crud.test.js b/api/test/server/services/Files/S3/crud.test.js
deleted file mode 100644
index d847a82cf0..0000000000
--- a/api/test/server/services/Files/S3/crud.test.js
+++ /dev/null
@@ -1,72 +0,0 @@
-const { getS3URL } = require('../../../../../server/services/Files/S3/crud');
-
-// Mock AWS SDK
-jest.mock('@aws-sdk/client-s3', () => ({
- S3Client: jest.fn(() => ({
- send: jest.fn(),
- })),
- GetObjectCommand: jest.fn(),
-}));
-
-jest.mock('@aws-sdk/s3-request-presigner', () => ({
- getSignedUrl: jest.fn(),
-}));
-
-jest.mock('../../../../../config', () => ({
- logger: {
- error: jest.fn(),
- },
-}));
-
-const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');
-const { GetObjectCommand } = require('@aws-sdk/client-s3');
-
-describe('S3 crud.js - test only new parameter changes', () => {
- beforeEach(() => {
- jest.clearAllMocks();
- process.env.AWS_BUCKET_NAME = 'test-bucket';
- });
-
- // Test only the new customFilename parameter
- it('should include customFilename in response headers when provided', async () => {
- getSignedUrl.mockResolvedValue('https://test-presigned-url.com');
-
- await getS3URL({
- userId: 'user123',
- fileName: 'test.pdf',
- customFilename: 'cleaned_filename.pdf',
- });
-
- // Verify the new ResponseContentDisposition parameter is added to GetObjectCommand
- const commandArgs = GetObjectCommand.mock.calls[0][0];
- expect(commandArgs.ResponseContentDisposition).toBe(
- 'attachment; filename="cleaned_filename.pdf"',
- );
- });
-
- // Test only the new contentType parameter
- it('should include contentType in response headers when provided', async () => {
- getSignedUrl.mockResolvedValue('https://test-presigned-url.com');
-
- await getS3URL({
- userId: 'user123',
- fileName: 'test.pdf',
- contentType: 'application/pdf',
- });
-
- // Verify the new ResponseContentType parameter is added to GetObjectCommand
- const commandArgs = GetObjectCommand.mock.calls[0][0];
- expect(commandArgs.ResponseContentType).toBe('application/pdf');
- });
-
- it('should work without new parameters (backward compatibility)', async () => {
- getSignedUrl.mockResolvedValue('https://test-presigned-url.com');
-
- const result = await getS3URL({
- userId: 'user123',
- fileName: 'test.pdf',
- });
-
- expect(result).toBe('https://test-presigned-url.com');
- });
-});
diff --git a/api/test/services/Files/processFileCitations.test.js b/api/test/services/Files/processFileCitations.test.js
index e9fe850ebd..8dd588afe9 100644
--- a/api/test/services/Files/processFileCitations.test.js
+++ b/api/test/services/Files/processFileCitations.test.js
@@ -7,12 +7,7 @@ const {
// Mock dependencies
jest.mock('~/models', () => ({
- Files: {
- find: jest.fn().mockResolvedValue([]),
- },
-}));
-
-jest.mock('~/models/Role', () => ({
+ getFiles: jest.fn().mockResolvedValue([]),
getRoleByName: jest.fn(),
}));
@@ -179,7 +174,7 @@ describe('processFileCitations', () => {
});
describe('enhanceSourcesWithMetadata', () => {
- const { Files } = require('~/models');
+ const { getFiles } = require('~/models');
const mockCustomConfig = {
fileStrategy: 'local',
};
@@ -204,7 +199,7 @@ describe('processFileCitations', () => {
},
];
- Files.find.mockResolvedValue([
+ getFiles.mockResolvedValue([
{
file_id: 'file_123',
filename: 'example_from_db.pdf',
@@ -219,7 +214,7 @@ describe('processFileCitations', () => {
const result = await enhanceSourcesWithMetadata(sources, mockCustomConfig);
- expect(Files.find).toHaveBeenCalledWith({ file_id: { $in: ['file_123', 'file_456'] } });
+ expect(getFiles).toHaveBeenCalledWith({ file_id: { $in: ['file_123', 'file_456'] } });
expect(result).toHaveLength(2);
expect(result[0]).toEqual({
@@ -258,7 +253,7 @@ describe('processFileCitations', () => {
},
];
- Files.find.mockResolvedValue([
+ getFiles.mockResolvedValue([
{
file_id: 'file_123',
filename: 'example_from_db.pdf',
@@ -292,7 +287,7 @@ describe('processFileCitations', () => {
},
];
- Files.find.mockResolvedValue([]);
+ getFiles.mockResolvedValue([]);
const result = await enhanceSourcesWithMetadata(sources, mockCustomConfig);
@@ -317,7 +312,7 @@ describe('processFileCitations', () => {
},
];
- Files.find.mockRejectedValue(new Error('Database error'));
+ getFiles.mockRejectedValue(new Error('Database error'));
const result = await enhanceSourcesWithMetadata(sources, mockCustomConfig);
@@ -339,14 +334,14 @@ describe('processFileCitations', () => {
{ fileId: 'file_456', fileName: 'doc2.pdf', relevance: 0.7, type: 'file' },
];
- Files.find.mockResolvedValue([
+ getFiles.mockResolvedValue([
{ file_id: 'file_123', filename: 'document1.pdf', source: 's3' },
{ file_id: 'file_456', filename: 'document2.pdf', source: 'local' },
]);
await enhanceSourcesWithMetadata(sources, mockCustomConfig);
- expect(Files.find).toHaveBeenCalledWith({ file_id: { $in: ['file_123', 'file_456'] } });
+ expect(getFiles).toHaveBeenCalledWith({ file_id: { $in: ['file_123', 'file_456'] } });
});
});
});
diff --git a/api/utils/tokens.spec.js b/api/utils/tokens.spec.js
index b3ab87cd07..53ae43fb66 100644
--- a/api/utils/tokens.spec.js
+++ b/api/utils/tokens.spec.js
@@ -1,13 +1,13 @@
/** Note: No hard-coded values should be used in this file. */
+const { EModelEndpoint } = require('librechat-data-provider');
const {
- EModelEndpoint,
maxTokensMap,
matchModelName,
getModelMaxTokens,
maxOutputTokensMap,
findMatchingPattern,
-} = require('librechat-data-provider');
-const { processModelData } = require('@librechat/api');
+ processModelData,
+} = require('@librechat/api');
describe('getModelMaxTokens', () => {
test('should return correct tokens for exact match', () => {
@@ -200,6 +200,39 @@ describe('getModelMaxTokens', () => {
);
});
+ test('should return correct tokens for gpt-5.3 matches', () => {
+ expect(getModelMaxTokens('gpt-5.3')).toBe(maxTokensMap[EModelEndpoint.openAI]['gpt-5.3']);
+ expect(getModelMaxTokens('gpt-5.3-codex')).toBe(maxTokensMap[EModelEndpoint.openAI]['gpt-5.3']);
+ expect(getModelMaxTokens('openai/gpt-5.3')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['gpt-5.3'],
+ );
+ expect(getModelMaxTokens('gpt-5.3-2025-03-01')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['gpt-5.3'],
+ );
+ expect(getModelMaxTokens('gpt-5.3-preview')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['gpt-5.3'],
+ );
+ });
+
+ test('should return correct tokens for gpt-5.4 matches', () => {
+ expect(getModelMaxTokens('gpt-5.4')).toBe(maxTokensMap[EModelEndpoint.openAI]['gpt-5.4']);
+ expect(getModelMaxTokens('gpt-5.4-thinking')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['gpt-5.4'],
+ );
+ expect(getModelMaxTokens('openai/gpt-5.4')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['gpt-5.4'],
+ );
+ });
+
+ test('should return correct tokens for gpt-5.4-pro matches', () => {
+ expect(getModelMaxTokens('gpt-5.4-pro')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['gpt-5.4-pro'],
+ );
+ expect(getModelMaxTokens('openai/gpt-5.4-pro')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['gpt-5.4-pro'],
+ );
+ });
+
test('should return correct tokens for Anthropic models', () => {
const models = [
'claude-2.1',
@@ -237,16 +270,6 @@ describe('getModelMaxTokens', () => {
});
});
- // Tests for Google models
- test('should return correct tokens for exact match - Google models', () => {
- expect(getModelMaxTokens('text-bison-32k', EModelEndpoint.google)).toBe(
- maxTokensMap[EModelEndpoint.google]['text-bison-32k'],
- );
- expect(getModelMaxTokens('codechat-bison-32k', EModelEndpoint.google)).toBe(
- maxTokensMap[EModelEndpoint.google]['codechat-bison-32k'],
- );
- });
-
test('should return undefined for no match - Google models', () => {
expect(getModelMaxTokens('unknown-google-model', EModelEndpoint.google)).toBeUndefined();
});
@@ -279,6 +302,12 @@ describe('getModelMaxTokens', () => {
expect(getModelMaxTokens('gemini-3', EModelEndpoint.google)).toBe(
maxTokensMap[EModelEndpoint.google]['gemini-3'],
);
+ expect(getModelMaxTokens('gemini-3.1-pro-preview', EModelEndpoint.google)).toBe(
+ maxTokensMap[EModelEndpoint.google]['gemini-3.1'],
+ );
+ expect(getModelMaxTokens('gemini-3.1-pro-preview-customtools', EModelEndpoint.google)).toBe(
+ maxTokensMap[EModelEndpoint.google]['gemini-3.1'],
+ );
expect(getModelMaxTokens('gemini-2.5-pro', EModelEndpoint.google)).toBe(
maxTokensMap[EModelEndpoint.google]['gemini-2.5-pro'],
);
@@ -297,12 +326,6 @@ describe('getModelMaxTokens', () => {
expect(getModelMaxTokens('gemini-pro', EModelEndpoint.google)).toBe(
maxTokensMap[EModelEndpoint.google]['gemini'],
);
- expect(getModelMaxTokens('code-', EModelEndpoint.google)).toBe(
- maxTokensMap[EModelEndpoint.google]['code-'],
- );
- expect(getModelMaxTokens('chat-', EModelEndpoint.google)).toBe(
- maxTokensMap[EModelEndpoint.google]['chat-'],
- );
});
test('should return correct tokens for partial match - Cohere models', () => {
@@ -485,8 +508,20 @@ describe('getModelMaxTokens', () => {
});
test('should return correct max output tokens for GPT-5 models', () => {
- const { getModelMaxOutputTokens } = require('librechat-data-provider');
- ['gpt-5', 'gpt-5-mini', 'gpt-5-nano', 'gpt-5-pro'].forEach((model) => {
+ const { getModelMaxOutputTokens } = require('@librechat/api');
+ const gpt5Models = [
+ 'gpt-5',
+ 'gpt-5.1',
+ 'gpt-5.2',
+ 'gpt-5.3',
+ 'gpt-5.4',
+ 'gpt-5.4-pro',
+ 'gpt-5-mini',
+ 'gpt-5-nano',
+ 'gpt-5-pro',
+ 'gpt-5.2-pro',
+ ];
+ for (const model of gpt5Models) {
expect(getModelMaxOutputTokens(model)).toBe(maxOutputTokensMap[EModelEndpoint.openAI][model]);
expect(getModelMaxOutputTokens(model, EModelEndpoint.openAI)).toBe(
maxOutputTokensMap[EModelEndpoint.openAI][model],
@@ -494,7 +529,7 @@ describe('getModelMaxTokens', () => {
expect(getModelMaxOutputTokens(model, EModelEndpoint.azureOpenAI)).toBe(
maxOutputTokensMap[EModelEndpoint.azureOpenAI][model],
);
- });
+ }
});
test('should return correct max output tokens for GPT-OSS models', () => {
@@ -511,6 +546,184 @@ describe('getModelMaxTokens', () => {
});
});
+describe('findMatchingPattern - longest match wins', () => {
+ test('should prefer longer matching key over shorter cross-provider pattern', () => {
+ const result = findMatchingPattern(
+ 'gpt-5.2-chat-2025-12-11',
+ maxTokensMap[EModelEndpoint.openAI],
+ );
+ expect(result).toBe('gpt-5.2');
+ });
+
+ test('should match gpt-5.2 tokens for date-suffixed chat variant', () => {
+ expect(getModelMaxTokens('gpt-5.2-chat-2025-12-11')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['gpt-5.2'],
+ );
+ });
+
+ test('should match gpt-5.2-pro over shorter patterns', () => {
+ expect(getModelMaxTokens('gpt-5.2-pro-chat-2025-12-11')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['gpt-5.2-pro'],
+ );
+ });
+
+ test('should match gpt-5-mini over gpt-5 for mini variants', () => {
+ expect(getModelMaxTokens('gpt-5-mini-chat-2025-01-01')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['gpt-5-mini'],
+ );
+ });
+
+ test('should prefer gpt-4-1106 over gpt-4 for versioned model names', () => {
+ const result = findMatchingPattern('gpt-4-1106-preview', maxTokensMap[EModelEndpoint.openAI]);
+ expect(result).toBe('gpt-4-1106');
+ });
+
+ test('should prefer gpt-4-32k-0613 over gpt-4-32k for exact versioned names', () => {
+ const result = findMatchingPattern('gpt-4-32k-0613', maxTokensMap[EModelEndpoint.openAI]);
+ expect(result).toBe('gpt-4-32k-0613');
+ });
+
+ test('should prefer claude-3-5-sonnet over claude-3', () => {
+ const result = findMatchingPattern(
+ 'claude-3-5-sonnet-20241022',
+ maxTokensMap[EModelEndpoint.anthropic],
+ );
+ expect(result).toBe('claude-3-5-sonnet');
+ });
+
+ test('should prefer gemini-2.0-flash-lite over gemini-2.0-flash', () => {
+ const result = findMatchingPattern(
+ 'gemini-2.0-flash-lite-preview',
+ maxTokensMap[EModelEndpoint.google],
+ );
+ expect(result).toBe('gemini-2.0-flash-lite');
+ });
+});
+
+describe('findMatchingPattern - bestLength selection', () => {
+ test('should return the longest matching key when multiple keys match', () => {
+ const tokensMap = { short: 100, 'short-med': 200, 'short-med-long': 300 };
+ expect(findMatchingPattern('short-med-long-extra', tokensMap)).toBe('short-med-long');
+ });
+
+ test('should return the longest match regardless of key insertion order', () => {
+ const tokensMap = { 'a-b-c': 300, a: 100, 'a-b': 200 };
+ expect(findMatchingPattern('a-b-c-d', tokensMap)).toBe('a-b-c');
+ });
+
+ test('should return null when no key matches', () => {
+ const tokensMap = { alpha: 100, beta: 200 };
+ expect(findMatchingPattern('gamma-delta', tokensMap)).toBeNull();
+ });
+
+ test('should return the single matching key when only one matches', () => {
+ const tokensMap = { alpha: 100, beta: 200, gamma: 300 };
+ expect(findMatchingPattern('beta-extended', tokensMap)).toBe('beta');
+ });
+
+ test('should match case-insensitively against model name', () => {
+ const tokensMap = { 'gpt-5': 400000 };
+ expect(findMatchingPattern('GPT-5-turbo', tokensMap)).toBe('gpt-5');
+ });
+
+ test('should select the longest key among overlapping substring matches', () => {
+ const tokensMap = { 'gpt-': 100, 'gpt-5': 200, 'gpt-5.2': 300, 'gpt-5.2-pro': 400 };
+ expect(findMatchingPattern('gpt-5.2-pro-2025-01-01', tokensMap)).toBe('gpt-5.2-pro');
+ expect(findMatchingPattern('gpt-5.2-chat-2025-01-01', tokensMap)).toBe('gpt-5.2');
+ expect(findMatchingPattern('gpt-5.1-preview', tokensMap)).toBe('gpt-5');
+ expect(findMatchingPattern('gpt-unknown', tokensMap)).toBe('gpt-');
+ });
+
+ test('should not be confused by a short key that appears later in the model name', () => {
+ const tokensMap = { 'model-v2': 200, v2: 100 };
+ expect(findMatchingPattern('model-v2-extended', tokensMap)).toBe('model-v2');
+ });
+
+ test('should handle exact-length match as the best match', () => {
+ const tokensMap = { 'exact-model': 500, exact: 100 };
+ expect(findMatchingPattern('exact-model', tokensMap)).toBe('exact-model');
+ });
+
+ test('should return null for empty model name', () => {
+ expect(findMatchingPattern('', { 'gpt-5': 400000 })).toBeNull();
+ });
+
+ test('should prefer last-defined key on same-length ties', () => {
+ const tokensMap = { 'aa-bb': 100, 'cc-dd': 200 };
+ // model name contains both 5-char keys; last-defined wins in reverse iteration
+ expect(findMatchingPattern('aa-bb-cc-dd', tokensMap)).toBe('cc-dd');
+ });
+
+ test('longest match beats short cross-provider pattern even when both present', () => {
+ const tokensMap = { 'gpt-5.2': 400000, 'chat-': 8187 };
+ expect(findMatchingPattern('gpt-5.2-chat-2025-12-11', tokensMap)).toBe('gpt-5.2');
+ });
+
+ test('should match case-insensitively against keys', () => {
+ const tokensMap = { 'GPT-5': 400000 };
+ expect(findMatchingPattern('gpt-5-turbo', tokensMap)).toBe('GPT-5');
+ });
+});
+
+describe('findMatchingPattern - iteration performance', () => {
+ let includesSpy;
+
+ beforeEach(() => {
+ includesSpy = jest.spyOn(String.prototype, 'includes');
+ });
+
+ afterEach(() => {
+ includesSpy.mockRestore();
+ });
+
+ test('exact match early-exits with minimal includes() checks', () => {
+ const openAIMap = maxTokensMap[EModelEndpoint.openAI];
+ const keys = Object.keys(openAIMap);
+ const lastKey = keys[keys.length - 1];
+ includesSpy.mockClear();
+ const result = findMatchingPattern(lastKey, openAIMap);
+ const exactCalls = includesSpy.mock.calls.length;
+
+ expect(result).toBe(lastKey);
+ expect(exactCalls).toBe(1);
+ });
+
+ test('bestLength check skips includes() for shorter keys after a long match', () => {
+ const openAIMap = maxTokensMap[EModelEndpoint.openAI];
+ includesSpy.mockClear();
+ findMatchingPattern('gpt-3.5-turbo-0301-test', openAIMap);
+ const longKeyCalls = includesSpy.mock.calls.length;
+
+ includesSpy.mockClear();
+ findMatchingPattern('gpt-5.3-chat-latest', openAIMap);
+ const shortKeyCalls = includesSpy.mock.calls.length;
+
+ // gpt-3.5-turbo-0301 (20 chars) matches early, then bestLength prunes most keys
+ // gpt-5.3 (7 chars) is short, so fewer keys are pruned by the length check
+ expect(longKeyCalls).toBeLessThan(shortKeyCalls);
+ });
+
+ test('last-defined keys are checked first in reverse iteration', () => {
+ const tokensMap = { first: 100, second: 200, third: 300 };
+ includesSpy.mockClear();
+ const result = findMatchingPattern('third', tokensMap);
+ const calls = includesSpy.mock.calls.length;
+
+ // 'third' is last key, found on first reverse check, exact match exits immediately
+ expect(result).toBe('third');
+ expect(calls).toBe(1);
+ });
+});
+
+describe('deprecated PaLM2/Codey model removal', () => {
+ test('deprecated PaLM2/Codey models no longer have token entries', () => {
+ expect(getModelMaxTokens('text-bison-32k', EModelEndpoint.google)).toBeUndefined();
+ expect(getModelMaxTokens('codechat-bison-32k', EModelEndpoint.google)).toBeUndefined();
+ expect(getModelMaxTokens('code-bison', EModelEndpoint.google)).toBeUndefined();
+ expect(getModelMaxTokens('chat-bison', EModelEndpoint.google)).toBeUndefined();
+ });
+});
+
describe('matchModelName', () => {
it('should return the exact model name if it exists in maxTokensMap', () => {
expect(matchModelName('gpt-4-32k-0613')).toBe('gpt-4-32k-0613');
@@ -606,10 +819,16 @@ describe('matchModelName', () => {
expect(matchModelName('gpt-5-pro-2025-01-30-0130')).toBe('gpt-5-pro');
});
- // Tests for Google models
- it('should return the exact model name if it exists in maxTokensMap - Google models', () => {
- expect(matchModelName('text-bison-32k', EModelEndpoint.google)).toBe('text-bison-32k');
- expect(matchModelName('codechat-bison-32k', EModelEndpoint.google)).toBe('codechat-bison-32k');
+ it('should return the closest matching key for gpt-5.3 matches', () => {
+ expect(matchModelName('openai/gpt-5.3')).toBe('gpt-5.3');
+ expect(matchModelName('gpt-5.3-codex')).toBe('gpt-5.3');
+ expect(matchModelName('gpt-5.3-2025-03-01')).toBe('gpt-5.3');
+ });
+
+ it('should return the closest matching key for gpt-5.4 matches', () => {
+ expect(matchModelName('openai/gpt-5.4')).toBe('gpt-5.4');
+ expect(matchModelName('gpt-5.4-thinking')).toBe('gpt-5.4');
+ expect(matchModelName('gpt-5.4-pro')).toBe('gpt-5.4-pro');
});
it('should return the input model name if no match is found - Google models', () => {
@@ -617,11 +836,6 @@ describe('matchModelName', () => {
'unknown-google-model',
);
});
-
- it('should return the closest matching key for partial matches - Google models', () => {
- expect(matchModelName('code-', EModelEndpoint.google)).toBe('code-');
- expect(matchModelName('chat-', EModelEndpoint.google)).toBe('chat-');
- });
});
describe('Meta Models Tests', () => {
@@ -1162,6 +1376,56 @@ describe('Claude Model Tests', () => {
expect(matchModelName(model, EModelEndpoint.anthropic)).toBe('claude-opus-4-6');
});
});
+
+ it('should return correct context length for Claude Sonnet 4.6 (1M)', () => {
+ expect(getModelMaxTokens('claude-sonnet-4-6', EModelEndpoint.anthropic)).toBe(
+ maxTokensMap[EModelEndpoint.anthropic]['claude-sonnet-4-6'],
+ );
+ expect(getModelMaxTokens('claude-sonnet-4-6')).toBe(
+ maxTokensMap[EModelEndpoint.anthropic]['claude-sonnet-4-6'],
+ );
+ });
+
+ it('should return correct max output tokens for Claude Sonnet 4.6 (64K)', () => {
+ const { getModelMaxOutputTokens } = require('@librechat/api');
+ expect(getModelMaxOutputTokens('claude-sonnet-4-6', EModelEndpoint.anthropic)).toBe(
+ maxOutputTokensMap[EModelEndpoint.anthropic]['claude-sonnet-4-6'],
+ );
+ });
+
+ it('should handle Claude Sonnet 4.6 model name variations', () => {
+ const modelVariations = [
+ 'claude-sonnet-4-6',
+ 'claude-sonnet-4-6-20260101',
+ 'claude-sonnet-4-6-latest',
+ 'anthropic/claude-sonnet-4-6',
+ 'claude-sonnet-4-6/anthropic',
+ 'claude-sonnet-4-6-preview',
+ ];
+
+ modelVariations.forEach((model) => {
+ const modelKey = findMatchingPattern(model, maxTokensMap[EModelEndpoint.anthropic]);
+ expect(modelKey).toBe('claude-sonnet-4-6');
+ expect(getModelMaxTokens(model, EModelEndpoint.anthropic)).toBe(
+ maxTokensMap[EModelEndpoint.anthropic]['claude-sonnet-4-6'],
+ );
+ });
+ });
+
+ it('should match model names correctly for Claude Sonnet 4.6', () => {
+ const modelVariations = [
+ 'claude-sonnet-4-6',
+ 'claude-sonnet-4-6-20260101',
+ 'claude-sonnet-4-6-latest',
+ 'anthropic/claude-sonnet-4-6',
+ 'claude-sonnet-4-6/anthropic',
+ 'claude-sonnet-4-6-preview',
+ ];
+
+ modelVariations.forEach((model) => {
+ expect(matchModelName(model, EModelEndpoint.anthropic)).toBe('claude-sonnet-4-6');
+ });
+ });
});
describe('Moonshot/Kimi Model Tests', () => {
diff --git a/bun.lock b/bun.lock
index 600a640c87..f6e3228519 100644
--- a/bun.lock
+++ b/bun.lock
@@ -7,7 +7,7 @@
"devDependencies": {
"@axe-core/playwright": "^4.10.1",
"@eslint/compat": "^1.2.6",
- "@eslint/eslintrc": "^3.3.1",
+ "@eslint/eslintrc": "^3.3.4",
"@eslint/js": "^9.20.0",
"@playwright/test": "^1.56.1",
"@types/react-virtualized": "^9.22.0",
@@ -31,30 +31,33 @@
"lint-staged": "^15.4.3",
"prettier": "^3.5.0",
"prettier-plugin-tailwindcss": "^0.6.11",
+ "turbo": "^2.8.12",
"typescript-eslint": "^8.24.0",
},
},
"api": {
"name": "@librechat/backend",
- "version": "0.8.2-rc2",
+ "version": "0.8.4-rc1",
"dependencies": {
- "@aws-sdk/client-bedrock-runtime": "^3.941.0",
- "@aws-sdk/client-s3": "^3.758.0",
+ "@anthropic-ai/vertex-sdk": "^0.14.3",
+ "@aws-sdk/client-bedrock-runtime": "^3.980.0",
+ "@aws-sdk/client-s3": "^3.980.0",
"@aws-sdk/s3-request-presigner": "^3.758.0",
"@azure/identity": "^4.7.0",
"@azure/search-documents": "^12.0.0",
- "@azure/storage-blob": "^12.27.0",
- "@googleapis/youtube": "^20.0.0",
+ "@azure/storage-blob": "^12.30.0",
+ "@google/genai": "^1.19.0",
"@keyv/redis": "^4.3.3",
- "@langchain/core": "^0.3.79",
- "@librechat/agents": "^3.0.50",
+ "@langchain/core": "^0.3.80",
+ "@librechat/agents": "^3.1.56",
"@librechat/api": "*",
"@librechat/data-schemas": "*",
"@microsoft/microsoft-graph-client": "^3.0.7",
- "@modelcontextprotocol/sdk": "^1.24.3",
+ "@modelcontextprotocol/sdk": "^1.27.1",
"@node-saml/passport-saml": "^5.1.0",
"@smithy/node-http-handler": "^4.4.5",
- "axios": "^1.12.1",
+ "ai-tokenizer": "^1.0.6",
+ "axios": "^1.13.5",
"bcryptjs": "^2.4.3",
"compression": "^1.8.1",
"connect-redis": "^8.1.0",
@@ -64,12 +67,12 @@
"dedent": "^1.5.3",
"dotenv": "^16.0.3",
"eventsource": "^3.0.2",
- "express": "^5.1.0",
+ "express": "^5.2.1",
"express-mongo-sanitize": "^2.2.0",
- "express-rate-limit": "^8.2.1",
+ "express-rate-limit": "^8.3.0",
"express-session": "^1.18.2",
"express-static-gzip": "^2.2.0",
- "file-type": "^18.7.0",
+ "file-type": "^21.3.2",
"firebase": "^11.0.2",
"form-data": "^4.0.4",
"handlebars": "^4.7.7",
@@ -82,13 +85,15 @@
"keyv-file": "^5.1.2",
"klona": "^2.0.6",
"librechat-data-provider": "*",
- "lodash": "^4.17.21",
+ "lodash": "^4.17.23",
+ "mammoth": "^1.11.0",
+ "mathjs": "^15.1.0",
"meilisearch": "^0.38.0",
"memorystore": "^1.6.7",
"mime": "^3.0.0",
"module-alias": "^2.2.3",
"mongoose": "^8.12.1",
- "multer": "^2.0.2",
+ "multer": "^2.1.1",
"nanoid": "^3.3.7",
"node-fetch": "^2.7.0",
"nodemailer": "^7.0.11",
@@ -104,15 +109,15 @@
"passport-jwt": "^4.0.1",
"passport-ldapauth": "^3.0.1",
"passport-local": "^1.0.0",
+ "pdfjs-dist": "^5.4.624",
"rate-limit-redis": "^4.2.0",
"sharp": "^0.33.5",
- "tiktoken": "^1.0.15",
"traverse": "^0.6.7",
"ua-parser-js": "^1.0.36",
- "undici": "^7.10.0",
+ "undici": "^7.24.1",
"winston": "^3.11.0",
"winston-daily-rotate-file": "^5.0.0",
- "youtube-transcript": "^1.2.1",
+ "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
"zod": "^3.22.4",
},
"devDependencies": {
@@ -124,7 +129,7 @@
},
"client": {
"name": "@librechat/frontend",
- "version": "0.8.2-rc2",
+ "version": "0.8.4-rc1",
"dependencies": {
"@ariakit/react": "^0.4.15",
"@ariakit/react-core": "^0.4.17",
@@ -135,11 +140,12 @@
"@librechat/client": "*",
"@marsidev/react-turnstile": "^1.1.0",
"@mcp-ui/client": "^5.7.0",
+ "@monaco-editor/react": "^4.7.0",
"@radix-ui/react-accordion": "^1.1.2",
- "@radix-ui/react-alert-dialog": "^1.1.15",
+ "@radix-ui/react-alert-dialog": "1.0.2",
"@radix-ui/react-checkbox": "^1.0.3",
"@radix-ui/react-collapsible": "^1.0.3",
- "@radix-ui/react-dialog": "^1.1.15",
+ "@radix-ui/react-dialog": "1.0.2",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-hover-card": "^1.0.5",
"@radix-ui/react-icons": "^1.3.0",
@@ -174,9 +180,10 @@
"jotai": "^2.12.5",
"js-cookie": "^3.0.5",
"librechat-data-provider": "*",
- "lodash": "^4.17.21",
+ "lodash": "^4.17.23",
"lucide-react": "^0.394.0",
"match-sorter": "^8.1.0",
+ "mermaid": "^11.13.0",
"micromark-extension-llm-math": "^3.1.0",
"qrcode.react": "^4.2.0",
"rc-input-number": "^7.4.2",
@@ -189,10 +196,9 @@
"react-gtm-module": "^2.0.11",
"react-hook-form": "^7.43.9",
"react-i18next": "^15.4.0",
- "react-lazy-load-image-component": "^1.6.0",
"react-markdown": "^9.0.1",
"react-resizable-panels": "^3.0.6",
- "react-router-dom": "^6.11.2",
+ "react-router-dom": "^6.30.3",
"react-speech-recognition": "^3.10.0",
"react-textarea-autosize": "^8.4.0",
"react-transition-group": "^4.4.5",
@@ -206,9 +212,11 @@
"remark-math": "^6.0.0",
"remark-supersub": "^1.0.0",
"sse.js": "^2.5.0",
+ "swr": "^2.3.8",
"tailwind-merge": "^1.9.1",
"tailwindcss-animate": "^1.0.5",
"tailwindcss-radix": "^2.8.0",
+ "ts-md5": "^1.3.1",
"zod": "^3.22.4",
},
"devDependencies": {
@@ -216,6 +224,7 @@
"@babel/preset-env": "^7.22.15",
"@babel/preset-react": "^7.22.15",
"@babel/preset-typescript": "^7.22.15",
+ "@happy-dom/jest-environment": "^20.8.3",
"@tanstack/react-query-devtools": "^4.29.0",
"@testing-library/dom": "^9.3.0",
"@testing-library/jest-dom": "^5.16.5",
@@ -224,10 +233,10 @@
"@types/jest": "^29.5.14",
"@types/js-cookie": "^3.0.6",
"@types/lodash": "^4.17.15",
- "@types/node": "^20.3.0",
+ "@types/node": "^20.19.35",
"@types/react": "^18.2.11",
"@types/react-dom": "^18.2.4",
- "@vitejs/plugin-react": "^4.3.4",
+ "@vitejs/plugin-react": "^5.1.4",
"autoprefixer": "^10.4.20",
"babel-plugin-replace-ts-export-assignment": "^0.0.2",
"babel-plugin-root-import": "^6.6.0",
@@ -238,23 +247,23 @@
"identity-obj-proxy": "^3.0.0",
"jest": "^30.2.0",
"jest-canvas-mock": "^2.5.2",
- "jest-environment-jsdom": "^29.7.0",
+ "jest-environment-jsdom": "^30.2.0",
"jest-file-loader": "^1.0.3",
"jest-junit": "^16.0.0",
+ "monaco-editor": "^0.55.1",
"postcss": "^8.4.31",
- "postcss-loader": "^7.1.0",
- "postcss-preset-env": "^8.2.0",
+ "postcss-preset-env": "^11.2.0",
"tailwindcss": "^3.4.1",
"typescript": "^5.3.3",
- "vite": "^6.4.1",
+ "vite": "^7.3.1",
"vite-plugin-compression2": "^2.2.1",
- "vite-plugin-node-polyfills": "^0.23.0",
- "vite-plugin-pwa": "^0.21.2",
+ "vite-plugin-node-polyfills": "^0.25.0",
+ "vite-plugin-pwa": "^1.2.0",
},
},
"packages/api": {
"name": "@librechat/api",
- "version": "1.7.22",
+ "version": "1.7.26",
"devDependencies": {
"@babel/preset-env": "^7.21.5",
"@babel/preset-react": "^7.18.6",
@@ -266,7 +275,6 @@
"@rollup/plugin-replace": "^5.0.5",
"@rollup/plugin-typescript": "^12.1.2",
"@types/bun": "^1.2.15",
- "@types/diff": "^6.0.0",
"@types/express": "^5.0.0",
"@types/express-session": "^1.18.2",
"@types/jest": "^29.5.2",
@@ -279,49 +287,60 @@
"jest": "^30.2.0",
"jest-junit": "^16.0.0",
"librechat-data-provider": "*",
+ "mammoth": "^1.11.0",
"mongodb": "^6.14.2",
- "rimraf": "^6.1.2",
- "rollup": "^4.22.4",
+ "pdfjs-dist": "^5.4.624",
+ "rimraf": "^6.1.3",
+ "rollup": "^4.34.9",
"rollup-plugin-peer-deps-external": "^2.2.4",
"ts-node": "^10.9.2",
"typescript": "^5.0.4",
+ "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
},
"peerDependencies": {
- "@aws-sdk/client-s3": "^3.758.0",
+ "@anthropic-ai/vertex-sdk": "^0.14.3",
+ "@aws-sdk/client-bedrock-runtime": "^3.970.0",
+ "@aws-sdk/client-s3": "^3.980.0",
"@azure/identity": "^4.7.0",
"@azure/search-documents": "^12.0.0",
- "@azure/storage-blob": "^12.27.0",
+ "@azure/storage-blob": "^12.30.0",
+ "@google/genai": "^1.19.0",
"@keyv/redis": "^4.3.3",
- "@langchain/core": "^0.3.79",
- "@librechat/agents": "^3.0.50",
+ "@langchain/core": "^0.3.80",
+ "@librechat/agents": "^3.1.56",
"@librechat/data-schemas": "*",
- "@modelcontextprotocol/sdk": "^1.24.3",
- "axios": "^1.12.1",
+ "@modelcontextprotocol/sdk": "^1.27.1",
+ "@smithy/node-http-handler": "^4.4.5",
+ "ai-tokenizer": "^1.0.6",
+ "axios": "^1.13.5",
"connect-redis": "^8.1.0",
- "diff": "^7.0.0",
"eventsource": "^3.0.2",
"express": "^5.1.0",
"express-session": "^1.18.2",
"firebase": "^11.0.2",
"form-data": "^4.0.4",
+ "google-auth-library": "^9.15.1",
+ "https-proxy-agent": "^7.0.6",
"ioredis": "^5.3.2",
"js-yaml": "^4.1.1",
"jsonwebtoken": "^9.0.0",
"keyv": "^5.3.2",
"keyv-file": "^5.1.2",
"librechat-data-provider": "*",
+ "mammoth": "^1.11.0",
+ "mathjs": "^15.1.0",
"memorystore": "^1.6.7",
"mongoose": "^8.12.1",
"node-fetch": "2.7.0",
+ "pdfjs-dist": "^5.4.624",
"rate-limit-redis": "^4.2.0",
- "tiktoken": "^1.0.15",
- "undici": "^7.10.0",
+ "undici": "^7.24.1",
"zod": "^3.22.4",
},
},
"packages/client": {
"name": "@librechat/client",
- "version": "0.4.51",
+ "version": "0.4.55",
"devDependencies": {
"@babel/core": "^7.28.5",
"@babel/preset-env": "^7.28.5",
@@ -351,8 +370,8 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^15.4.0",
- "rimraf": "^6.1.2",
- "rollup": "^4.0.0",
+ "rimraf": "^6.1.3",
+ "rollup": "^4.34.9",
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-typescript2": "^0.35.0",
@@ -366,10 +385,10 @@
"@dicebear/core": "^9.2.2",
"@headlessui/react": "^2.1.2",
"@radix-ui/react-accordion": "^1.2.11",
- "@radix-ui/react-alert-dialog": "^1.1.15",
+ "@radix-ui/react-alert-dialog": "1.0.2",
"@radix-ui/react-checkbox": "^1.0.3",
"@radix-ui/react-collapsible": "^1.1.11",
- "@radix-ui/react-dialog": "^1.1.15",
+ "@radix-ui/react-dialog": "1.0.2",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-hover-card": "^1.0.5",
"@radix-ui/react-icons": "^1.3.0",
@@ -409,9 +428,9 @@
},
"packages/data-provider": {
"name": "librechat-data-provider",
- "version": "0.8.231",
+ "version": "0.8.400",
"dependencies": {
- "axios": "^1.12.1",
+ "axios": "^1.13.5",
"dayjs": "^1.11.13",
"js-yaml": "^4.1.1",
"zod": "^3.22.4",
@@ -420,7 +439,6 @@
"@babel/preset-env": "^7.21.5",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.21.0",
- "@langchain/core": "^0.3.62",
"@rollup/plugin-alias": "^5.1.0",
"@rollup/plugin-commonjs": "^29.0.0",
"@rollup/plugin-json": "^6.1.0",
@@ -435,8 +453,8 @@
"jest": "^30.2.0",
"jest-junit": "^16.0.0",
"openapi-types": "^12.1.3",
- "rimraf": "^6.1.2",
- "rollup": "^4.22.4",
+ "rimraf": "^6.1.3",
+ "rollup": "^4.34.9",
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-typescript2": "^0.35.0",
"typescript": "^5.0.4",
@@ -447,7 +465,7 @@
},
"packages/data-schemas": {
"name": "@librechat/data-schemas",
- "version": "0.0.35",
+ "version": "0.0.39",
"devDependencies": {
"@rollup/plugin-alias": "^5.1.0",
"@rollup/plugin-commonjs": "^29.0.0",
@@ -456,15 +474,14 @@
"@rollup/plugin-replace": "^5.0.5",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.2",
- "@types/diff": "^6.0.0",
"@types/express": "^5.0.0",
"@types/jest": "^29.5.2",
"@types/node": "^20.3.0",
"jest": "^30.2.0",
"jest-junit": "^16.0.0",
"mongodb-memory-server": "^10.1.4",
- "rimraf": "^6.1.2",
- "rollup": "^4.22.4",
+ "rimraf": "^6.1.3",
+ "rollup": "^4.34.9",
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-typescript2": "^0.35.0",
"ts-node": "^10.9.2",
@@ -474,7 +491,7 @@
"jsonwebtoken": "^9.0.2",
"klona": "^2.0.6",
"librechat-data-provider": "*",
- "lodash": "^4.17.21",
+ "lodash": "^4.17.23",
"meilisearch": "^0.38.0",
"mongoose": "^8.12.1",
"nanoid": "^3.3.7",
@@ -484,11 +501,20 @@
},
},
"overrides": {
+ "@anthropic-ai/sdk": "0.73.0",
+ "@hono/node-server": "^1.19.10",
"axios": "1.12.1",
"elliptic": "^6.6.1",
+ "fast-xml-parser": "5.3.8",
"form-data": "^4.0.4",
+ "hono": "^4.12.4",
"katex": "^0.16.21",
+ "langsmith": "0.4.12",
"mdast-util-gfm-autolink-literal": "2.0.0",
+ "serialize-javascript": "^7.0.3",
+ "svgo": "^2.8.2",
+ "tslib": "^2.8.1",
+ "underscore": "1.13.8",
},
"packages": {
"@aashutoshrathi/word-wrap": ["@aashutoshrathi/word-wrap@1.2.6", "", {}, "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA=="],
@@ -497,7 +523,11 @@
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
- "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.65.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-zIdPOcrCVEI8t3Di40nH4z9EoeyGZfXbYSvWdDLsB/KkaSYMnEgC7gmcgWu83g2NTn1ZTpbMvpdttWDGGIk6zw=="],
+ "@antfu/install-pkg": ["@antfu/install-pkg@1.1.0", "", { "dependencies": { "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" } }, "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ=="],
+
+ "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.73.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-URURVzhxXGJDGUGFunIOtBlSl7KWvZiAAKY/ttTkZAkXT9bTPqdk2eK0b8qqSxXpikh3QKPnPYpiyX98zf5ebw=="],
+
+ "@anthropic-ai/vertex-sdk": ["@anthropic-ai/vertex-sdk@0.14.4", "", { "dependencies": { "@anthropic-ai/sdk": ">=0.50.3 <1", "google-auth-library": "^9.4.2" } }, "sha512-BZUPRWghZxfSFtAxU563wH+jfWBPoedAwsVxG35FhmNsjeV8tyfN+lFriWhCpcZApxA4NdT6Soov+PzfnxxD5g=="],
"@apideck/better-ajv-errors": ["@apideck/better-ajv-errors@0.3.6", "", { "dependencies": { "json-schema": "^0.4.0", "jsonpointer": "^5.0.0", "leven": "^3.1.0" }, "peerDependencies": { "ajv": ">=8" } }, "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA=="],
@@ -525,19 +555,21 @@
"@aws-sdk/client-bedrock-agent-runtime": ["@aws-sdk/client-bedrock-agent-runtime@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/credential-provider-node": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/eventstream-serde-browser": "^4.2.4", "@smithy/eventstream-serde-config-resolver": "^4.3.4", "@smithy/eventstream-serde-node": "^4.2.4", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-k2UeG/+Ka74jztHDzYNrpNLDSsMCst+ph3+e7uAX5Jmo40tVKa+sVu4DkV3BIXuktc6jqM1ewtfPNug79kN6JQ=="],
- "@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.952.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/credential-provider-node": "3.952.0", "@aws-sdk/eventstream-handler-node": "3.936.0", "@aws-sdk/middleware-eventstream": "3.936.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/middleware-websocket": "3.936.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/token-providers": "3.952.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/eventstream-serde-browser": "^4.2.5", "@smithy/eventstream-serde-config-resolver": "^4.3.5", "@smithy/eventstream-serde-node": "^4.2.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Xc1xqIz/OdFd23UQ6cvROD+3tfvDpp5dabMqUYXFiKlk5psMNM9xhzLwWK7DE1tr1ra/dui77w8JOiLA1dC7AA=="],
+ "@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.1004.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.18", "@aws-sdk/credential-provider-node": "^3.972.18", "@aws-sdk/eventstream-handler-node": "^3.972.10", "@aws-sdk/middleware-eventstream": "^3.972.7", "@aws-sdk/middleware-host-header": "^3.972.7", "@aws-sdk/middleware-logger": "^3.972.7", "@aws-sdk/middleware-recursion-detection": "^3.972.7", "@aws-sdk/middleware-user-agent": "^3.972.19", "@aws-sdk/middleware-websocket": "^3.972.12", "@aws-sdk/region-config-resolver": "^3.972.7", "@aws-sdk/token-providers": "3.1004.0", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@aws-sdk/util-user-agent-browser": "^3.972.7", "@aws-sdk/util-user-agent-node": "^3.973.4", "@smithy/config-resolver": "^4.4.10", "@smithy/core": "^3.23.8", "@smithy/eventstream-serde-browser": "^4.2.11", "@smithy/eventstream-serde-config-resolver": "^4.3.11", "@smithy/eventstream-serde-node": "^4.2.11", "@smithy/fetch-http-handler": "^5.3.13", "@smithy/hash-node": "^4.2.11", "@smithy/invalid-dependency": "^4.2.11", "@smithy/middleware-content-length": "^4.2.11", "@smithy/middleware-endpoint": "^4.4.22", "@smithy/middleware-retry": "^4.4.39", "@smithy/middleware-serde": "^4.2.12", "@smithy/middleware-stack": "^4.2.11", "@smithy/node-config-provider": "^4.3.11", "@smithy/node-http-handler": "^4.4.14", "@smithy/protocol-http": "^5.3.11", "@smithy/smithy-client": "^4.12.2", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.38", "@smithy/util-defaults-mode-node": "^4.2.41", "@smithy/util-endpoints": "^3.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-retry": "^4.2.11", "@smithy/util-stream": "^4.5.17", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-t8cl+bPLlHZQD2Sw1a4hSLUybqJZU71+m8znkyeU8CHntFqEp2mMbuLKdHKaAYQ1fAApXMsvzenCAkDzNeeJlw=="],
"@aws-sdk/client-cognito-identity": ["@aws-sdk/client-cognito-identity@3.623.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/client-sso-oidc": "3.623.0", "@aws-sdk/core": "3.623.0", "@aws-sdk/credential-provider-node": "3.623.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", "@aws-sdk/middleware-user-agent": "3.620.0", "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@aws-sdk/util-endpoints": "3.614.0", "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", "@smithy/core": "^2.3.2", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-retry": "^3.0.14", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/smithy-client": "^3.1.12", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", "@smithy/util-defaults-mode-browser": "^3.0.14", "@smithy/util-defaults-mode-node": "^3.0.14", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-kGYnTzXTMGdjko5+GZ1PvWvfXA7quiOp5iMo5gbh5b55pzIdc918MHN0pvaqplVGWYlaFJF4YzxUT5Nbxd7Xeg=="],
"@aws-sdk/client-kendra": ["@aws-sdk/client-kendra@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/credential-provider-node": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-DWyNlC6BFhzoDkyKZ3xv0BC/xcXF3Tpq6j6Z42DXO9KEUjiGmC3se9l/GFEVtRLh/DR4p7cTJsxzA2QNuthRNg=="],
- "@aws-sdk/client-s3": ["@aws-sdk/client-s3@3.758.0", "", { "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.758.0", "@aws-sdk/credential-provider-node": "3.758.0", "@aws-sdk/middleware-bucket-endpoint": "3.734.0", "@aws-sdk/middleware-expect-continue": "3.734.0", "@aws-sdk/middleware-flexible-checksums": "3.758.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-location-constraint": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", "@aws-sdk/middleware-recursion-detection": "3.734.0", "@aws-sdk/middleware-sdk-s3": "3.758.0", "@aws-sdk/middleware-ssec": "3.734.0", "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/signature-v4-multi-region": "3.758.0", "@aws-sdk/types": "3.734.0", "@aws-sdk/util-endpoints": "3.743.0", "@aws-sdk/util-user-agent-browser": "3.734.0", "@aws-sdk/util-user-agent-node": "3.758.0", "@aws-sdk/xml-builder": "3.734.0", "@smithy/config-resolver": "^4.0.1", "@smithy/core": "^3.1.5", "@smithy/eventstream-serde-browser": "^4.0.1", "@smithy/eventstream-serde-config-resolver": "^4.0.1", "@smithy/eventstream-serde-node": "^4.0.1", "@smithy/fetch-http-handler": "^5.0.1", "@smithy/hash-blob-browser": "^4.0.1", "@smithy/hash-node": "^4.0.1", "@smithy/hash-stream-node": "^4.0.1", "@smithy/invalid-dependency": "^4.0.1", "@smithy/md5-js": "^4.0.1", "@smithy/middleware-content-length": "^4.0.1", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/middleware-retry": "^4.0.7", "@smithy/middleware-serde": "^4.0.2", "@smithy/middleware-stack": "^4.0.1", "@smithy/node-config-provider": "^4.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/protocol-http": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.7", "@smithy/util-defaults-mode-node": "^4.0.7", "@smithy/util-endpoints": "^3.0.1", "@smithy/util-middleware": "^4.0.1", "@smithy/util-retry": "^4.0.1", "@smithy/util-stream": "^4.1.2", "@smithy/util-utf8": "^4.0.0", "@smithy/util-waiter": "^4.0.2", "tslib": "^2.6.2" } }, "sha512-f8SlhU9/93OC/WEI6xVJf/x/GoQFj9a/xXK6QCtr5fvCjfSLgMVFmKTiIl/tgtDRzxUDc8YS6EGtbHjJ3Y/atg=="],
+ "@aws-sdk/client-s3": ["@aws-sdk/client-s3@3.1004.0", "", { "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.18", "@aws-sdk/credential-provider-node": "^3.972.18", "@aws-sdk/middleware-bucket-endpoint": "^3.972.7", "@aws-sdk/middleware-expect-continue": "^3.972.7", "@aws-sdk/middleware-flexible-checksums": "^3.973.4", "@aws-sdk/middleware-host-header": "^3.972.7", "@aws-sdk/middleware-location-constraint": "^3.972.7", "@aws-sdk/middleware-logger": "^3.972.7", "@aws-sdk/middleware-recursion-detection": "^3.972.7", "@aws-sdk/middleware-sdk-s3": "^3.972.18", "@aws-sdk/middleware-ssec": "^3.972.7", "@aws-sdk/middleware-user-agent": "^3.972.19", "@aws-sdk/region-config-resolver": "^3.972.7", "@aws-sdk/signature-v4-multi-region": "^3.996.6", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@aws-sdk/util-user-agent-browser": "^3.972.7", "@aws-sdk/util-user-agent-node": "^3.973.4", "@smithy/config-resolver": "^4.4.10", "@smithy/core": "^3.23.8", "@smithy/eventstream-serde-browser": "^4.2.11", "@smithy/eventstream-serde-config-resolver": "^4.3.11", "@smithy/eventstream-serde-node": "^4.2.11", "@smithy/fetch-http-handler": "^5.3.13", "@smithy/hash-blob-browser": "^4.2.12", "@smithy/hash-node": "^4.2.11", "@smithy/hash-stream-node": "^4.2.11", "@smithy/invalid-dependency": "^4.2.11", "@smithy/md5-js": "^4.2.11", "@smithy/middleware-content-length": "^4.2.11", "@smithy/middleware-endpoint": "^4.4.22", "@smithy/middleware-retry": "^4.4.39", "@smithy/middleware-serde": "^4.2.12", "@smithy/middleware-stack": "^4.2.11", "@smithy/node-config-provider": "^4.3.11", "@smithy/node-http-handler": "^4.4.14", "@smithy/protocol-http": "^5.3.11", "@smithy/smithy-client": "^4.12.2", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.38", "@smithy/util-defaults-mode-node": "^4.2.41", "@smithy/util-endpoints": "^3.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-retry": "^4.2.11", "@smithy/util-stream": "^4.5.17", "@smithy/util-utf8": "^4.2.2", "@smithy/util-waiter": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-m0zNfpsona9jQdX1cHtHArOiuvSGZPsgp/KRZS2YjJhKah96G2UN3UNGZQ6aVjXIQjCY6UanCJo0uW9Xf2U41w=="],
"@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.623.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.623.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", "@aws-sdk/middleware-user-agent": "3.620.0", "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@aws-sdk/util-endpoints": "3.614.0", "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", "@smithy/core": "^2.3.2", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-retry": "^3.0.14", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/smithy-client": "^3.1.12", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", "@smithy/util-defaults-mode-browser": "^3.0.14", "@smithy/util-defaults-mode-node": "^3.0.14", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-oEACriysQMnHIVcNp7TD6D1nzgiHfYK0tmMBMbUxgoFuCBkW9g9QYvspHN+S9KgoePfMEXHuPUe9mtG9AH9XeA=="],
"@aws-sdk/client-sso-oidc": ["@aws-sdk/client-sso-oidc@3.623.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.623.0", "@aws-sdk/credential-provider-node": "3.623.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", "@aws-sdk/middleware-user-agent": "3.620.0", "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@aws-sdk/util-endpoints": "3.614.0", "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", "@smithy/core": "^2.3.2", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-retry": "^3.0.14", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/smithy-client": "^3.1.12", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", "@smithy/util-defaults-mode-browser": "^3.0.14", "@smithy/util-defaults-mode-node": "^3.0.14", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-lMFEXCa6ES/FGV7hpyrppT1PiAkqQb51AbG0zVU3TIgI2IO4XX02uzMUXImRSRqRpGymRCbJCaCs9LtKvS/37Q=="],
- "@aws-sdk/core": ["@aws-sdk/core@3.758.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/core": "^3.1.5", "@smithy/node-config-provider": "^4.0.1", "@smithy/property-provider": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/signature-v4": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/util-middleware": "^4.0.1", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" } }, "sha512-0RswbdR9jt/XKemaLNuxi2gGr4xGlHyGxkTdhSQzCyUe9A9OPCoLl3rIESRguQEech+oJnbHk/wuiwHqTuP9sg=="],
+ "@aws-sdk/core": ["@aws-sdk/core@3.973.18", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws-sdk/xml-builder": "^3.972.10", "@smithy/core": "^3.23.8", "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/smithy-client": "^4.12.2", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-GUIlegfcK2LO1J2Y98sCJy63rQSiLiDOgVw7HiHPRqfI2vb3XozTVqemwO0VSGXp54ngCnAQz0Lf0YPCBINNxA=="],
+
+ "@aws-sdk/crc64-nvme": ["@aws-sdk/crc64-nvme@3.972.4", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-HKZIZLbRyvzo/bXZU7Zmk6XqU+1C9DjI56xd02vwuDIxedxBEqP17t9ExhbP9QFeNq/a3l9GOcyirFXxmbDhmw=="],
"@aws-sdk/credential-provider-cognito-identity": ["@aws-sdk/credential-provider-cognito-identity@3.623.0", "", { "dependencies": { "@aws-sdk/client-cognito-identity": "3.623.0", "@aws-sdk/types": "3.609.0", "@smithy/property-provider": "^3.1.3", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-sXU2KtWpFzIzE4iffSIUbl4mgbeN1Rta6BnuKtS3rrVrryku9akAxY//pulbsIsYfXRzOwZzULsa+cxQN00lrw=="],
@@ -547,9 +579,9 @@
"@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.623.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.620.1", "@aws-sdk/credential-provider-http": "3.622.0", "@aws-sdk/credential-provider-process": "3.620.1", "@aws-sdk/credential-provider-sso": "3.623.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", "@smithy/property-provider": "^3.1.3", "@smithy/shared-ini-file-loader": "^3.1.4", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-kvXA1SwGneqGzFwRZNpESitnmaENHGFFuuTvgGwtMe7mzXWuA/LkXdbiHmdyAzOo0iByKTCD8uetuwh3CXy4Pw=="],
- "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.952.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.952.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-jL9zc+e+7sZeJrHzYKK9GOjl1Ktinh0ORU3cM2uRBi7fuH/0zV9pdMN8PQnGXz0i4tJaKcZ1lrE4V0V6LB9NQg=="],
+ "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.17", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/nested-clients": "^3.996.7", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-gf2E5b7LpKb+JX2oQsRIDxdRZjBFZt2olCGlWCdb3vBERbXIPgm2t1R5mEnwd4j0UEO/Tbg5zN2KJbHXttJqwA=="],
- "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.758.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.758.0", "@aws-sdk/credential-provider-http": "3.758.0", "@aws-sdk/credential-provider-ini": "3.758.0", "@aws-sdk/credential-provider-process": "3.758.0", "@aws-sdk/credential-provider-sso": "3.758.0", "@aws-sdk/credential-provider-web-identity": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/credential-provider-imds": "^4.0.1", "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-+DaMv63wiq7pJrhIQzZYMn4hSarKiizDoJRvyR7WGhnn0oQ/getX9Z0VNCV3i7lIFoLNTb7WMmQ9k7+z/uD5EQ=="],
+ "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.18", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.16", "@aws-sdk/credential-provider-http": "^3.972.18", "@aws-sdk/credential-provider-ini": "^3.972.17", "@aws-sdk/credential-provider-process": "^3.972.16", "@aws-sdk/credential-provider-sso": "^3.972.17", "@aws-sdk/credential-provider-web-identity": "^3.972.17", "@aws-sdk/types": "^3.973.5", "@smithy/credential-provider-imds": "^4.2.11", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-ZDJa2gd1xiPg/nBDGhUlat02O8obaDEnICBAVS8qieZ0+nDfaB0Z3ec6gjZj27OqFTjnB/Q5a0GwQwb7rMVViw=="],
"@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.620.1", "", { "dependencies": { "@aws-sdk/types": "3.609.0", "@smithy/property-provider": "^3.1.3", "@smithy/shared-ini-file-loader": "^3.1.4", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg=="],
@@ -559,57 +591,57 @@
"@aws-sdk/credential-providers": ["@aws-sdk/credential-providers@3.623.0", "", { "dependencies": { "@aws-sdk/client-cognito-identity": "3.623.0", "@aws-sdk/client-sso": "3.623.0", "@aws-sdk/credential-provider-cognito-identity": "3.623.0", "@aws-sdk/credential-provider-env": "3.620.1", "@aws-sdk/credential-provider-http": "3.622.0", "@aws-sdk/credential-provider-ini": "3.623.0", "@aws-sdk/credential-provider-node": "3.623.0", "@aws-sdk/credential-provider-process": "3.620.1", "@aws-sdk/credential-provider-sso": "3.623.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", "@smithy/property-provider": "^3.1.3", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-abtlH1hkVWAkzuOX79Q47l0ztWOV2Q7l7J4JwQgzEQm7+zCk5iUAiwqKyDzr+ByCyo4I3IWFjy+e1gBdL7rXQQ=="],
- "@aws-sdk/eventstream-handler-node": ["@aws-sdk/eventstream-handler-node@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/eventstream-codec": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-4zIbhdRmol2KosIHmU31ATvNP0tkJhDlRj9GuawVJoEnMvJA1pd2U3SRdiOImJU3j8pT46VeS4YMmYxfjGHByg=="],
+ "@aws-sdk/eventstream-handler-node": ["@aws-sdk/eventstream-handler-node@3.972.10", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/eventstream-codec": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-g2Z9s6Y4iNh0wICaEqutgYgt/Pmhv5Ev9G3eKGFe2w9VuZDhc76vYdop6I5OocmpHV79d4TuLG+JWg5rQIVDVA=="],
- "@aws-sdk/middleware-bucket-endpoint": ["@aws-sdk/middleware-bucket-endpoint@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@aws-sdk/util-arn-parser": "3.723.0", "@smithy/node-config-provider": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-config-provider": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-etC7G18aF7KdZguW27GE/wpbrNmYLVT755EsFc8kXpZj8D6AFKxc7OuveinJmiy0bYXAMspJUWsF6CrGpOw6CQ=="],
+ "@aws-sdk/middleware-bucket-endpoint": ["@aws-sdk/middleware-bucket-endpoint@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-arn-parser": "^3.972.3", "@smithy/node-config-provider": "^4.3.11", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-goX+axlJ6PQlRnzE2bQisZ8wVrlm6dXJfBzMJhd8LhAIBan/w1Kl73fJnalM/S+18VnpzIHumyV6DtgmvqG5IA=="],
- "@aws-sdk/middleware-eventstream": ["@aws-sdk/middleware-eventstream@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-XQSH8gzLkk8CDUDxyt4Rdm9owTpRIPdtg2yw9Y2Wl5iSI55YQSiC3x8nM3c4Y4WqReJprunFPK225ZUDoYCfZA=="],
+ "@aws-sdk/middleware-eventstream": ["@aws-sdk/middleware-eventstream@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-VWndapHYCfwLgPpCb/xwlMKG4imhFzKJzZcKOEioGn7OHY+6gdr0K7oqy1HZgbLa3ACznZ9fku+DzmAi8fUC0g=="],
- "@aws-sdk/middleware-expect-continue": ["@aws-sdk/middleware-expect-continue@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-P38/v1l6HjuB2aFUewt7ueAW5IvKkFcv5dalPtbMGRhLeyivBOHwbCyuRKgVs7z7ClTpu9EaViEGki2jEQqEsQ=="],
+ "@aws-sdk/middleware-expect-continue": ["@aws-sdk/middleware-expect-continue@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-mvWqvm61bmZUKmmrtl2uWbokqpenY3Mc3Jf4nXB/Hse6gWxLPaCQThmhPBDzsPSV8/Odn8V6ovWt3pZ7vy4BFQ=="],
- "@aws-sdk/middleware-flexible-checksums": ["@aws-sdk/middleware-flexible-checksums@3.758.0", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", "@aws-sdk/core": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/is-array-buffer": "^4.0.0", "@smithy/node-config-provider": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-middleware": "^4.0.1", "@smithy/util-stream": "^4.1.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-o8Rk71S08YTKLoSobucjnbj97OCGaXgpEDNKXpXaavUM5xLNoHCLSUPRCiEN86Ivqxg1n17Y2nSRhfbsveOXXA=="],
+ "@aws-sdk/middleware-flexible-checksums": ["@aws-sdk/middleware-flexible-checksums@3.973.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", "@aws-sdk/core": "^3.973.18", "@aws-sdk/crc64-nvme": "^3.972.4", "@aws-sdk/types": "^3.973.5", "@smithy/is-array-buffer": "^4.2.2", "@smithy/node-config-provider": "^4.3.11", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-middleware": "^4.2.11", "@smithy/util-stream": "^4.5.17", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-7CH2jcGmkvkHc5Buz9IGbdjq1729AAlgYJiAvGq7qhCHqYleCsriWdSnmsqWTwdAfXHMT+pkxX3w6v5tJNcSug=="],
- "@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-LW7RRgSOHHBzWZnigNsDIzu3AiwtjeI2X66v+Wn1P1u+eXssy1+up4ZY/h+t2sU4LU36UvEf+jrZti9c6vRnFw=="],
+ "@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-aHQZgztBFEpDU1BB00VWCIIm85JjGjQW1OG9+98BdmaOpguJvzmXBGbnAiYcciCd+IS4e9BEq664lhzGnWJHgQ=="],
- "@aws-sdk/middleware-location-constraint": ["@aws-sdk/middleware-location-constraint@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-EJEIXwCQhto/cBfHdm3ZOeLxd2NlJD+X2F+ZTOxzokuhBtY0IONfC/91hOo5tWQweerojwshSMHRCKzRv1tlwg=="],
+ "@aws-sdk/middleware-location-constraint": ["@aws-sdk/middleware-location-constraint@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-vdK1LJfffBp87Lj0Bw3WdK1rJk9OLDYdQpqoKgmpIZPe+4+HawZ6THTbvjhJt4C4MNnRrHTKHQjkwBiIpDBoig=="],
- "@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-mUMFITpJUW3LcKvFok176eI5zXAUomVtahb9IQBwLzkqFYOrMJvWAvoV4yuxrJ8TlQBG8gyEnkb9SnhZvjg67w=="],
+ "@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-LXhiWlWb26txCU1vcI9PneESSeRp/RYY/McuM4SpdrimQR5NgwaPb4VJCadVeuGWgh6QmqZ6rAKSoL1ob16W6w=="],
- "@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-CUat2d9ITsFc2XsmeiRQO96iWpxSKYFjxvj27Hc7vo87YUHRnfMfnc8jw1EpxEwMcvBD7LsRa6vDNky6AjcrFA=="],
+ "@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-l2VQdcBcYLzIzykCHtXlbpiVCZ94/xniLIkAj0jpnpjY4xlgZx7f56Ypn+uV1y3gG0tNVytJqo3K9bfMFee7SQ=="],
- "@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.758.0", "", { "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/types": "3.734.0", "@aws-sdk/util-arn-parser": "3.723.0", "@smithy/core": "^3.1.5", "@smithy/node-config-provider": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/signature-v4": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/util-config-provider": "^4.0.0", "@smithy/util-middleware": "^4.0.1", "@smithy/util-stream": "^4.1.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-6mJ2zyyHPYSV6bAcaFpsdoXZJeQlR1QgBnZZ6juY/+dcYiuyWCdyLUbGzSZSE7GTfx6i+9+QWFeoIMlWKgU63A=="],
+ "@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.972.18", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-arn-parser": "^3.972.3", "@smithy/core": "^3.23.8", "@smithy/node-config-provider": "^4.3.11", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/smithy-client": "^4.12.2", "@smithy/types": "^4.13.0", "@smithy/util-config-provider": "^4.2.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-stream": "^4.5.17", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-5E3XxaElrdyk6ZJ0TjH7Qm6ios4b/qQCiLr6oQ8NK7e4Kn6JBTJCaYioQCQ65BpZ1+l1mK5wTAac2+pEz0Smpw=="],
- "@aws-sdk/middleware-ssec": ["@aws-sdk/middleware-ssec@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-d4yd1RrPW/sspEXizq2NSOUivnheac6LPeLSLnaeTbBG9g1KqIqvCzP1TfXEqv2CrWfHEsWtJpX7oyjySSPvDQ=="],
+ "@aws-sdk/middleware-ssec": ["@aws-sdk/middleware-ssec@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-G9clGVuAml7d8DYzY6DnRi7TIIDRvZ3YpqJPz/8wnWS5fYx/FNWNmkO6iJVlVkQg9BfeMzd+bVPtPJOvC4B+nQ=="],
- "@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.758.0", "", { "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/types": "3.734.0", "@aws-sdk/util-endpoints": "3.743.0", "@smithy/core": "^3.1.5", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-iNyehQXtQlj69JCgfaOssgZD4HeYGOwxcaKeG6F+40cwBjTAi0+Ph1yfDwqk2qiBPIRWJ/9l2LodZbxiBqgrwg=="],
+ "@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.19", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@smithy/core": "^3.23.8", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-retry": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-Km90fcXt3W/iqujHzuM6IaDkYCj73gsYufcuWXApWdzoTy6KGk8fnchAjePMARU0xegIR3K4N3yIo1vy7OVe8A=="],
- "@aws-sdk/middleware-websocket": ["@aws-sdk/middleware-websocket@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/util-format-url": "3.936.0", "@smithy/eventstream-codec": "^4.2.5", "@smithy/eventstream-serde-browser": "^4.2.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-bPe3rqeugyj/MmjP0yBSZox2v1Wa8Dv39KN+RxVbQroLO8VUitBo6xyZ0oZebhZ5sASwSg58aDcMlX0uFLQnTA=="],
+ "@aws-sdk/middleware-websocket": ["@aws-sdk/middleware-websocket@3.972.12", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-format-url": "^3.972.7", "@smithy/eventstream-codec": "^4.2.11", "@smithy/eventstream-serde-browser": "^4.2.11", "@smithy/fetch-http-handler": "^5.3.13", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-iyPP6FVDKe/5wy5ojC0akpDFG1vX3FeCUU47JuwN8xfvT66xlEI8qUJZPtN55TJVFzzWZJpWL78eqUE31md08Q=="],
- "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.952.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-OtuirjxuOqZyDcI0q4WtoyWfkq3nSnbH41JwJQsXJefduWcww1FQe5TL1JfYCU7seUxHzK8rg2nFxUBuqUlZtg=="],
+ "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.7", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.18", "@aws-sdk/middleware-host-header": "^3.972.7", "@aws-sdk/middleware-logger": "^3.972.7", "@aws-sdk/middleware-recursion-detection": "^3.972.7", "@aws-sdk/middleware-user-agent": "^3.972.19", "@aws-sdk/region-config-resolver": "^3.972.7", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@aws-sdk/util-user-agent-browser": "^3.972.7", "@aws-sdk/util-user-agent-node": "^3.973.4", "@smithy/config-resolver": "^4.4.10", "@smithy/core": "^3.23.8", "@smithy/fetch-http-handler": "^5.3.13", "@smithy/hash-node": "^4.2.11", "@smithy/invalid-dependency": "^4.2.11", "@smithy/middleware-content-length": "^4.2.11", "@smithy/middleware-endpoint": "^4.4.22", "@smithy/middleware-retry": "^4.4.39", "@smithy/middleware-serde": "^4.2.12", "@smithy/middleware-stack": "^4.2.11", "@smithy/node-config-provider": "^4.3.11", "@smithy/node-http-handler": "^4.4.14", "@smithy/protocol-http": "^5.3.11", "@smithy/smithy-client": "^4.12.2", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.38", "@smithy/util-defaults-mode-node": "^4.2.41", "@smithy/util-endpoints": "^3.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-retry": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-MlGWA8uPaOs5AiTZ5JLM4uuWDm9EEAnm9cqwvqQIc6kEgel/8s1BaOWm9QgUcfc9K8qd7KkC3n43yDbeXOA2tg=="],
- "@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/node-config-provider": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/util-config-provider": "^4.0.0", "@smithy/util-middleware": "^4.0.1", "tslib": "^2.6.2" } }, "sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ=="],
+ "@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/config-resolver": "^4.4.10", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-/Ev/6AI8bvt4HAAptzSjThGUMjcWaX3GX8oERkB0F0F9x2dLSBdgFDiyrRz3i0u0ZFZFQ1b28is4QhyqXTUsVA=="],
"@aws-sdk/s3-request-presigner": ["@aws-sdk/s3-request-presigner@3.758.0", "", { "dependencies": { "@aws-sdk/signature-v4-multi-region": "3.758.0", "@aws-sdk/types": "3.734.0", "@aws-sdk/util-format-url": "3.734.0", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/protocol-http": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dVyItwu/J1InfJBbCPpHRV9jrsBfI7L0RlDGyS3x/xqBwnm5qpvgNZQasQiyqIl+WJB4f5rZRZHgHuwftqINbA=="],
- "@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.758.0", "", { "dependencies": { "@aws-sdk/middleware-sdk-s3": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/protocol-http": "^5.0.1", "@smithy/signature-v4": "^5.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-0RPCo8fYJcrenJ6bRtiUbFOSgQ1CX/GpvwtLU2Fam1tS9h2klKK8d74caeV6A1mIUvBU7bhyQ0wMGlwMtn3EYw=="],
+ "@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.6", "", { "dependencies": { "@aws-sdk/middleware-sdk-s3": "^3.972.18", "@aws-sdk/types": "^3.973.5", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-NnsOQsVmJXy4+IdPFUjRCWPn9qNH1TzS/f7MiWgXeoHs903tJpAWQWQtoFvLccyPoBgomKP9L89RRr2YsT/L0g=="],
- "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.952.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.952.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-IpQVC9WOeXQlCEcFVNXWDIKy92CH1Az37u9K0H3DF/HT56AjhyDVKQQfHUy00nt7bHFe3u0K5+zlwErBeKy5ZA=="],
+ "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1004.0", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/nested-clients": "^3.996.7", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-j9BwZZId9sFp+4GPhf6KrwO8Tben2sXibZA8D1vv2I1zBdvkUHcBA2g4pkqIpTRalMTLC0NPkBPX0gERxfy/iA=="],
- "@aws-sdk/types": ["@aws-sdk/types@3.734.0", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg=="],
+ "@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="],
- "@aws-sdk/util-arn-parser": ["@aws-sdk/util-arn-parser@3.723.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-ZhEfvUwNliOQROcAk34WJWVYTlTa4694kSVhDSjW6lE1bMataPnIN8A0ycukEzBXmd8ZSoBcQLn6lKGl7XIJ5w=="],
+ "@aws-sdk/util-arn-parser": ["@aws-sdk/util-arn-parser@3.972.3", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-HzSD8PMFrvgi2Kserxuff5VitNq2sgf3w9qxmskKDiDTThWfVteJxuCS9JXiPIPtmCrp+7N9asfIaVhBFORllA=="],
- "@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.743.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/types": "^4.1.0", "@smithy/util-endpoints": "^3.0.1", "tslib": "^2.6.2" } }, "sha512-sN1l559zrixeh5x+pttrnd0A3+r34r0tmPkJ/eaaMaAzXqsmKU/xYre9K3FNnsSS1J1k4PEfk/nHDTVUgFYjnw=="],
+ "@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.4", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-endpoints": "^3.3.2", "tslib": "^2.6.2" } }, "sha512-Hek90FBmd4joCFj+Vc98KLJh73Zqj3s2W56gjAcTkrNLMDI5nIFkG9YpfcJiVI1YlE2Ne1uOQNe+IgQ/Vz2XRA=="],
"@aws-sdk/util-format-url": ["@aws-sdk/util-format-url@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-TxZMVm8V4aR/QkW9/NhujvYpPZjUYqzLwSge5imKZbWFR806NP7RMwc5ilVuHF/bMOln/cVHkl42kATElWBvNw=="],
"@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.568.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-3nh4TINkXYr+H41QaPelCceEB2FXP3fxp93YZXB/kqJvX0U9j0N0Uk45gvsjmEPzG8XxkPEeLIfT2I1M7A6Lig=="],
- "@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/types": "^4.1.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-xQTCus6Q9LwUuALW+S76OL0jcWtMOVu14q+GoLnWPUM7QeUw963oQcLhF7oq0CtaLLKyl4GOUfcwc773Zmwwng=="],
+ "@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-7SJVuvhKhMF/BkNS1n0QAJYgvEwYbK2QLKBrzDiwQGiTRU6Yf1f3nehTzm/l21xdAOtWSfp2uWSddPnP2ZtsVw=="],
- "@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.758.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/node-config-provider": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-A5EZw85V6WhoKMV2hbuFRvb9NPlxEErb4HPO6/SPXYY4QrjprIzScHxikqcWv1w4J3apB1wto9LPU3IMsYtfrw=="],
+ "@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.4", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.19", "@aws-sdk/types": "^3.973.5", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-uqKeLqZ9D3nQjH7HGIERNXK9qnSpUK08l4MlJ5/NZqSSdeJsVANYp437EM9sEzwU28c2xfj2V6qlkqzsgtKs6Q=="],
- "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.734.0", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Zrjxi5qwGEcUsJ0ru7fRtW74WcTS0rbLcehoFB+rN1GRi2hbLcFaYs4PwVA5diLeAJH0gszv3x4Hr/S87MfbKQ=="],
+ "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.10", "", { "dependencies": { "@smithy/types": "^4.13.0", "fast-xml-parser": "5.4.1", "tslib": "^2.6.2" } }, "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA=="],
"@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.2", "", {}, "sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg=="],
@@ -647,7 +679,9 @@
"@azure/search-documents": ["@azure/search-documents@12.0.0", "", { "dependencies": { "@azure/core-auth": "^1.3.0", "@azure/core-client": "^1.3.0", "@azure/core-http-compat": "^2.0.1", "@azure/core-paging": "^1.1.1", "@azure/core-rest-pipeline": "^1.3.0", "@azure/core-tracing": "^1.0.0", "@azure/logger": "^1.0.0", "events": "^3.0.0", "tslib": "^2.2.0" } }, "sha512-d9d53f2WWBpLHifk+LVn+AG52zuXvjgxJAdaH6kuT2qwrO1natcigtTgBM8qrI3iDYaDXsQhJSIMEgg9WKSoWA=="],
- "@azure/storage-blob": ["@azure/storage-blob@12.27.0", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.4.0", "@azure/core-client": "^1.6.2", "@azure/core-http-compat": "^2.0.0", "@azure/core-lro": "^2.2.0", "@azure/core-paging": "^1.1.1", "@azure/core-rest-pipeline": "^1.10.1", "@azure/core-tracing": "^1.1.2", "@azure/core-util": "^1.6.1", "@azure/core-xml": "^1.4.3", "@azure/logger": "^1.0.0", "events": "^3.0.0", "tslib": "^2.2.0" } }, "sha512-IQjj9RIzAKatmNca3D6bT0qJ+Pkox1WZGOg2esJF2YLHb45pQKOwGPIAV+w3rfgkj7zV3RMxpn/c6iftzSOZJQ=="],
+ "@azure/storage-blob": ["@azure/storage-blob@12.31.0", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.9.0", "@azure/core-client": "^1.9.3", "@azure/core-http-compat": "^2.2.0", "@azure/core-lro": "^2.2.0", "@azure/core-paging": "^1.6.2", "@azure/core-rest-pipeline": "^1.19.1", "@azure/core-tracing": "^1.2.0", "@azure/core-util": "^1.11.0", "@azure/core-xml": "^1.4.5", "@azure/logger": "^1.1.4", "@azure/storage-common": "^12.3.0", "events": "^3.0.0", "tslib": "^2.8.1" } }, "sha512-DBgNv10aCSxopt92DkTDD0o9xScXeBqPKGmR50FPZQaEcH4JLQ+GEOGEDv19V5BMkB7kxr+m4h6il/cCDPvmHg=="],
+
+ "@azure/storage-common": ["@azure/storage-common@12.3.0", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.9.0", "@azure/core-http-compat": "^2.2.0", "@azure/core-rest-pipeline": "^1.19.1", "@azure/core-tracing": "^1.2.0", "@azure/core-util": "^1.11.0", "@azure/logger": "^1.1.4", "events": "^3.3.0", "tslib": "^2.8.1" } }, "sha512-/OFHhy86aG5Pe8dP5tsp+BuJ25JOAl9yaMU3WZbkeoiFMHFtJ7tu5ili7qEdBXNW9G5lDB19trwyI6V49F/8iQ=="],
"@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
@@ -657,45 +691,33 @@
"@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="],
- "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.25.9", "", { "dependencies": { "@babel/types": "^7.25.9" } }, "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g=="],
-
- "@babel/helper-builder-binary-assignment-operator-visitor": ["@babel/helper-builder-binary-assignment-operator-visitor@7.22.15", "", { "dependencies": { "@babel/types": "^7.22.15" } }, "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw=="],
+ "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="],
- "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.26.9", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-member-expression-to-functions": "^7.25.9", "@babel/helper-optimise-call-expression": "^7.25.9", "@babel/helper-replace-supers": "^7.26.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", "@babel/traverse": "^7.26.9", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg=="],
+ "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
"@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.26.3", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "regexpu-core": "^6.2.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong=="],
- "@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.3", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg=="],
-
- "@babel/helper-environment-visitor": ["@babel/helper-environment-visitor@7.22.20", "", {}, "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA=="],
-
- "@babel/helper-function-name": ["@babel/helper-function-name@7.23.0", "", { "dependencies": { "@babel/template": "^7.22.15", "@babel/types": "^7.23.0" } }, "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw=="],
+ "@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
"@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="],
- "@babel/helper-hoist-variables": ["@babel/helper-hoist-variables@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw=="],
-
- "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.25.9", "", { "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" } }, "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ=="],
+ "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="],
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="],
- "@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.25.9", "", { "dependencies": { "@babel/types": "^7.25.9" } }, "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ=="],
+ "@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
"@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="],
- "@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.25.9", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-wrap-function": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw=="],
+ "@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="],
- "@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.26.5", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.25.9", "@babel/helper-optimise-call-expression": "^7.25.9", "@babel/traverse": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg=="],
+ "@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
- "@babel/helper-simple-access": ["@babel/helper-simple-access@7.24.7", "", { "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" } }, "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg=="],
-
- "@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.25.9", "", { "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" } }, "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA=="],
-
- "@babel/helper-split-export-declaration": ["@babel/helper-split-export-declaration@7.22.6", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g=="],
+ "@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
@@ -703,21 +725,21 @@
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
- "@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.25.9", "", { "dependencies": { "@babel/template": "^7.25.9", "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" } }, "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g=="],
+ "@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2" } }, "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g=="],
"@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="],
"@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": { "parser": "bin/babel-parser.js" } }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="],
- "@babel/plugin-bugfix-firefox-class-in-computed-class-key": ["@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g=="],
+ "@babel/plugin-bugfix-firefox-class-in-computed-class-key": ["@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q=="],
- "@babel/plugin-bugfix-safari-class-field-initializer-scope": ["@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw=="],
+ "@babel/plugin-bugfix-safari-class-field-initializer-scope": ["@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA=="],
- "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ["@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug=="],
+ "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ["@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA=="],
- "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ["@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", "@babel/plugin-transform-optional-chaining": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.13.0" } }, "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g=="],
+ "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ["@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.13.0" } }, "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw=="],
- "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ["@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg=="],
+ "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ["@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw=="],
"@babel/plugin-proposal-private-property-in-object": ["@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2", "", { "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w=="],
@@ -729,11 +751,7 @@
"@babel/plugin-syntax-class-static-block": ["@babel/plugin-syntax-class-static-block@7.14.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw=="],
- "@babel/plugin-syntax-dynamic-import": ["@babel/plugin-syntax-dynamic-import@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ=="],
-
- "@babel/plugin-syntax-export-namespace-from": ["@babel/plugin-syntax-export-namespace-from@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q=="],
-
- "@babel/plugin-syntax-import-assertions": ["@babel/plugin-syntax-import-assertions@7.26.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg=="],
+ "@babel/plugin-syntax-import-assertions": ["@babel/plugin-syntax-import-assertions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg=="],
"@babel/plugin-syntax-import-attributes": ["@babel/plugin-syntax-import-attributes@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww=="],
@@ -763,131 +781,131 @@
"@babel/plugin-syntax-unicode-sets-regex": ["@babel/plugin-syntax-unicode-sets-regex@7.18.6", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg=="],
- "@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg=="],
+ "@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA=="],
- "@babel/plugin-transform-async-generator-functions": ["@babel/plugin-transform-async-generator-functions@7.26.8", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-remap-async-to-generator": "^7.25.9", "@babel/traverse": "^7.26.8" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg=="],
+ "@babel/plugin-transform-async-generator-functions": ["@babel/plugin-transform-async-generator-functions@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1", "@babel/traverse": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q=="],
- "@babel/plugin-transform-async-to-generator": ["@babel/plugin-transform-async-to-generator@7.25.9", "", { "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-remap-async-to-generator": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ=="],
+ "@babel/plugin-transform-async-to-generator": ["@babel/plugin-transform-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA=="],
- "@babel/plugin-transform-block-scoped-functions": ["@babel/plugin-transform-block-scoped-functions@7.26.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ=="],
+ "@babel/plugin-transform-block-scoped-functions": ["@babel/plugin-transform-block-scoped-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg=="],
- "@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg=="],
+ "@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g=="],
- "@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.25.9", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q=="],
+ "@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA=="],
- "@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.26.0", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ=="],
+ "@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.28.3", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg=="],
- "@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.25.9", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-compilation-targets": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-replace-supers": "^7.25.9", "@babel/traverse": "^7.25.9", "globals": "^11.1.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg=="],
+ "@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.4", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA=="],
- "@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/template": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA=="],
+ "@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/template": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw=="],
- "@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ=="],
+ "@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw=="],
- "@babel/plugin-transform-dotall-regex": ["@babel/plugin-transform-dotall-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA=="],
+ "@babel/plugin-transform-dotall-regex": ["@babel/plugin-transform-dotall-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw=="],
- "@babel/plugin-transform-duplicate-keys": ["@babel/plugin-transform-duplicate-keys@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw=="],
+ "@babel/plugin-transform-duplicate-keys": ["@babel/plugin-transform-duplicate-keys@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q=="],
- "@babel/plugin-transform-duplicate-named-capturing-groups-regex": ["@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog=="],
+ "@babel/plugin-transform-duplicate-named-capturing-groups-regex": ["@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ=="],
- "@babel/plugin-transform-dynamic-import": ["@babel/plugin-transform-dynamic-import@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg=="],
+ "@babel/plugin-transform-dynamic-import": ["@babel/plugin-transform-dynamic-import@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A=="],
"@babel/plugin-transform-explicit-resource-management": ["@babel/plugin-transform-explicit-resource-management@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ=="],
- "@babel/plugin-transform-exponentiation-operator": ["@babel/plugin-transform-exponentiation-operator@7.26.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ=="],
+ "@babel/plugin-transform-exponentiation-operator": ["@babel/plugin-transform-exponentiation-operator@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw=="],
- "@babel/plugin-transform-export-namespace-from": ["@babel/plugin-transform-export-namespace-from@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww=="],
+ "@babel/plugin-transform-export-namespace-from": ["@babel/plugin-transform-export-namespace-from@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ=="],
- "@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.26.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg=="],
+ "@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw=="],
- "@babel/plugin-transform-function-name": ["@babel/plugin-transform-function-name@7.25.9", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA=="],
+ "@babel/plugin-transform-function-name": ["@babel/plugin-transform-function-name@7.27.1", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ=="],
- "@babel/plugin-transform-json-strings": ["@babel/plugin-transform-json-strings@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw=="],
+ "@babel/plugin-transform-json-strings": ["@babel/plugin-transform-json-strings@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q=="],
- "@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ=="],
+ "@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA=="],
- "@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q=="],
+ "@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA=="],
- "@babel/plugin-transform-member-expression-literals": ["@babel/plugin-transform-member-expression-literals@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA=="],
+ "@babel/plugin-transform-member-expression-literals": ["@babel/plugin-transform-member-expression-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ=="],
- "@babel/plugin-transform-modules-amd": ["@babel/plugin-transform-modules-amd@7.25.9", "", { "dependencies": { "@babel/helper-module-transforms": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw=="],
+ "@babel/plugin-transform-modules-amd": ["@babel/plugin-transform-modules-amd@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA=="],
- "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.26.3", "", { "dependencies": { "@babel/helper-module-transforms": "^7.26.0", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ=="],
+ "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="],
- "@babel/plugin-transform-modules-systemjs": ["@babel/plugin-transform-modules-systemjs@7.25.9", "", { "dependencies": { "@babel/helper-module-transforms": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA=="],
+ "@babel/plugin-transform-modules-systemjs": ["@babel/plugin-transform-modules-systemjs@7.28.5", "", { "dependencies": { "@babel/helper-module-transforms": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew=="],
- "@babel/plugin-transform-modules-umd": ["@babel/plugin-transform-modules-umd@7.25.9", "", { "dependencies": { "@babel/helper-module-transforms": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw=="],
+ "@babel/plugin-transform-modules-umd": ["@babel/plugin-transform-modules-umd@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w=="],
- "@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA=="],
+ "@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng=="],
- "@babel/plugin-transform-new-target": ["@babel/plugin-transform-new-target@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ=="],
+ "@babel/plugin-transform-new-target": ["@babel/plugin-transform-new-target@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ=="],
- "@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.26.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw=="],
+ "@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA=="],
- "@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q=="],
+ "@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw=="],
- "@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.25.9", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/plugin-transform-parameters": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg=="],
+ "@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.28.4", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew=="],
- "@babel/plugin-transform-object-super": ["@babel/plugin-transform-object-super@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-replace-supers": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A=="],
+ "@babel/plugin-transform-object-super": ["@babel/plugin-transform-object-super@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng=="],
- "@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g=="],
+ "@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q=="],
- "@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A=="],
+ "@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ=="],
- "@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g=="],
+ "@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.27.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg=="],
- "@babel/plugin-transform-private-methods": ["@babel/plugin-transform-private-methods@7.25.9", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw=="],
+ "@babel/plugin-transform-private-methods": ["@babel/plugin-transform-private-methods@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA=="],
- "@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.25.9", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw=="],
+ "@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ=="],
- "@babel/plugin-transform-property-literals": ["@babel/plugin-transform-property-literals@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA=="],
+ "@babel/plugin-transform-property-literals": ["@babel/plugin-transform-property-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ=="],
- "@babel/plugin-transform-react-display-name": ["@babel/plugin-transform-react-display-name@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-GnvhtVfA2OAtzdX58FJxU19rhoGeQzyVndw3GgtdECQvQFXPEZIOVULHVZGAYmOgmqjXpVpfocAbSjh99V/Fqw=="],
+ "@babel/plugin-transform-react-display-name": ["@babel/plugin-transform-react-display-name@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA=="],
- "@babel/plugin-transform-react-jsx": ["@babel/plugin-transform-react-jsx@7.23.4", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-module-imports": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-jsx": "^7.23.3", "@babel/types": "^7.23.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA=="],
+ "@babel/plugin-transform-react-jsx": ["@babel/plugin-transform-react-jsx@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/types": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw=="],
- "@babel/plugin-transform-react-jsx-development": ["@babel/plugin-transform-react-jsx-development@7.22.5", "", { "dependencies": { "@babel/plugin-transform-react-jsx": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A=="],
+ "@babel/plugin-transform-react-jsx-development": ["@babel/plugin-transform-react-jsx-development@7.27.1", "", { "dependencies": { "@babel/plugin-transform-react-jsx": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q=="],
- "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg=="],
+ "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="],
- "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg=="],
+ "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="],
- "@babel/plugin-transform-react-pure-annotations": ["@babel/plugin-transform-react-pure-annotations@7.23.3", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qMFdSS+TUhB7Q/3HVPnEdYJDQIk57jkntAwSuz9xfSE4n+3I+vHYCli3HoHawN1Z3RfCz/y1zXA/JXjG6cVImQ=="],
+ "@babel/plugin-transform-react-pure-annotations": ["@babel/plugin-transform-react-pure-annotations@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA=="],
- "@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "regenerator-transform": "^0.15.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg=="],
+ "@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.28.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA=="],
- "@babel/plugin-transform-regexp-modifiers": ["@babel/plugin-transform-regexp-modifiers@7.26.0", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw=="],
+ "@babel/plugin-transform-regexp-modifiers": ["@babel/plugin-transform-regexp-modifiers@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA=="],
- "@babel/plugin-transform-reserved-words": ["@babel/plugin-transform-reserved-words@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg=="],
+ "@babel/plugin-transform-reserved-words": ["@babel/plugin-transform-reserved-words@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw=="],
"@babel/plugin-transform-runtime": ["@babel/plugin-transform-runtime@7.23.9", "", { "dependencies": { "@babel/helper-module-imports": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", "babel-plugin-polyfill-corejs2": "^0.4.8", "babel-plugin-polyfill-corejs3": "^0.9.0", "babel-plugin-polyfill-regenerator": "^0.5.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-A7clW3a0aSjm3ONU9o2HAILSegJCYlEZmOhmBRReVtIpY/Z/p7yIZ+wR41Z+UipwdGuqwtID/V/dOdZXjwi9gQ=="],
- "@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng=="],
+ "@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ=="],
- "@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A=="],
+ "@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q=="],
- "@babel/plugin-transform-sticky-regex": ["@babel/plugin-transform-sticky-regex@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA=="],
+ "@babel/plugin-transform-sticky-regex": ["@babel/plugin-transform-sticky-regex@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g=="],
- "@babel/plugin-transform-template-literals": ["@babel/plugin-transform-template-literals@7.26.8", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q=="],
+ "@babel/plugin-transform-template-literals": ["@babel/plugin-transform-template-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg=="],
- "@babel/plugin-transform-typeof-symbol": ["@babel/plugin-transform-typeof-symbol@7.26.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jfoTXXZTgGg36BmhqT3cAYK5qkmqvJpvNrPhaK/52Vgjhw4Rq29s9UqpWWV0D6yuRmgiFH/BUVlkl96zJWqnaw=="],
+ "@babel/plugin-transform-typeof-symbol": ["@babel/plugin-transform-typeof-symbol@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw=="],
- "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.23.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-create-class-features-plugin": "^7.23.6", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-typescript": "^7.23.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA=="],
+ "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA=="],
- "@babel/plugin-transform-unicode-escapes": ["@babel/plugin-transform-unicode-escapes@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q=="],
+ "@babel/plugin-transform-unicode-escapes": ["@babel/plugin-transform-unicode-escapes@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg=="],
- "@babel/plugin-transform-unicode-property-regex": ["@babel/plugin-transform-unicode-property-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg=="],
+ "@babel/plugin-transform-unicode-property-regex": ["@babel/plugin-transform-unicode-property-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q=="],
- "@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA=="],
+ "@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw=="],
- "@babel/plugin-transform-unicode-sets-regex": ["@babel/plugin-transform-unicode-sets-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ=="],
+ "@babel/plugin-transform-unicode-sets-regex": ["@babel/plugin-transform-unicode-sets-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw=="],
- "@babel/preset-env": ["@babel/preset-env@7.26.9", "", { "dependencies": { "@babel/compat-data": "^7.26.8", "@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-validator-option": "^7.25.9", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.26.0", "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.25.9", "@babel/plugin-transform-async-generator-functions": "^7.26.8", "@babel/plugin-transform-async-to-generator": "^7.25.9", "@babel/plugin-transform-block-scoped-functions": "^7.26.5", "@babel/plugin-transform-block-scoping": "^7.25.9", "@babel/plugin-transform-class-properties": "^7.25.9", "@babel/plugin-transform-class-static-block": "^7.26.0", "@babel/plugin-transform-classes": "^7.25.9", "@babel/plugin-transform-computed-properties": "^7.25.9", "@babel/plugin-transform-destructuring": "^7.25.9", "@babel/plugin-transform-dotall-regex": "^7.25.9", "@babel/plugin-transform-duplicate-keys": "^7.25.9", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", "@babel/plugin-transform-dynamic-import": "^7.25.9", "@babel/plugin-transform-exponentiation-operator": "^7.26.3", "@babel/plugin-transform-export-namespace-from": "^7.25.9", "@babel/plugin-transform-for-of": "^7.26.9", "@babel/plugin-transform-function-name": "^7.25.9", "@babel/plugin-transform-json-strings": "^7.25.9", "@babel/plugin-transform-literals": "^7.25.9", "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", "@babel/plugin-transform-member-expression-literals": "^7.25.9", "@babel/plugin-transform-modules-amd": "^7.25.9", "@babel/plugin-transform-modules-commonjs": "^7.26.3", "@babel/plugin-transform-modules-systemjs": "^7.25.9", "@babel/plugin-transform-modules-umd": "^7.25.9", "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", "@babel/plugin-transform-new-target": "^7.25.9", "@babel/plugin-transform-nullish-coalescing-operator": "^7.26.6", "@babel/plugin-transform-numeric-separator": "^7.25.9", "@babel/plugin-transform-object-rest-spread": "^7.25.9", "@babel/plugin-transform-object-super": "^7.25.9", "@babel/plugin-transform-optional-catch-binding": "^7.25.9", "@babel/plugin-transform-optional-chaining": "^7.25.9", "@babel/plugin-transform-parameters": "^7.25.9", "@babel/plugin-transform-private-methods": "^7.25.9", "@babel/plugin-transform-private-property-in-object": "^7.25.9", "@babel/plugin-transform-property-literals": "^7.25.9", "@babel/plugin-transform-regenerator": "^7.25.9", "@babel/plugin-transform-regexp-modifiers": "^7.26.0", "@babel/plugin-transform-reserved-words": "^7.25.9", "@babel/plugin-transform-shorthand-properties": "^7.25.9", "@babel/plugin-transform-spread": "^7.25.9", "@babel/plugin-transform-sticky-regex": "^7.25.9", "@babel/plugin-transform-template-literals": "^7.26.8", "@babel/plugin-transform-typeof-symbol": "^7.26.7", "@babel/plugin-transform-unicode-escapes": "^7.25.9", "@babel/plugin-transform-unicode-property-regex": "^7.25.9", "@babel/plugin-transform-unicode-regex": "^7.25.9", "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", "babel-plugin-polyfill-corejs3": "^0.11.0", "babel-plugin-polyfill-regenerator": "^0.6.1", "core-js-compat": "^3.40.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ=="],
+ "@babel/preset-env": ["@babel/preset-env@7.28.5", "", { "dependencies": { "@babel/compat-data": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.27.1", "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", "@babel/plugin-transform-async-generator-functions": "^7.28.0", "@babel/plugin-transform-async-to-generator": "^7.27.1", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", "@babel/plugin-transform-block-scoping": "^7.28.5", "@babel/plugin-transform-class-properties": "^7.27.1", "@babel/plugin-transform-class-static-block": "^7.28.3", "@babel/plugin-transform-classes": "^7.28.4", "@babel/plugin-transform-computed-properties": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-dotall-regex": "^7.27.1", "@babel/plugin-transform-duplicate-keys": "^7.27.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.0", "@babel/plugin-transform-exponentiation-operator": "^7.28.5", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", "@babel/plugin-transform-json-strings": "^7.27.1", "@babel/plugin-transform-literals": "^7.27.1", "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-modules-systemjs": "^7.28.5", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", "@babel/plugin-transform-numeric-separator": "^7.27.1", "@babel/plugin-transform-object-rest-spread": "^7.28.4", "@babel/plugin-transform-object-super": "^7.27.1", "@babel/plugin-transform-optional-catch-binding": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-private-methods": "^7.27.1", "@babel/plugin-transform-private-property-in-object": "^7.27.1", "@babel/plugin-transform-property-literals": "^7.27.1", "@babel/plugin-transform-regenerator": "^7.28.4", "@babel/plugin-transform-regexp-modifiers": "^7.27.1", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", "@babel/plugin-transform-spread": "^7.27.1", "@babel/plugin-transform-sticky-regex": "^7.27.1", "@babel/plugin-transform-template-literals": "^7.27.1", "@babel/plugin-transform-typeof-symbol": "^7.27.1", "@babel/plugin-transform-unicode-escapes": "^7.27.1", "@babel/plugin-transform-unicode-property-regex": "^7.27.1", "@babel/plugin-transform-unicode-regex": "^7.27.1", "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", "babel-plugin-polyfill-regenerator": "^0.6.5", "core-js-compat": "^3.43.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg=="],
"@babel/preset-modules": ["@babel/preset-modules@0.1.6-no-external-plugins", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", "esutils": "^2.0.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA=="],
- "@babel/preset-react": ["@babel/preset-react@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-validator-option": "^7.22.15", "@babel/plugin-transform-react-display-name": "^7.23.3", "@babel/plugin-transform-react-jsx": "^7.22.15", "@babel/plugin-transform-react-jsx-development": "^7.22.5", "@babel/plugin-transform-react-pure-annotations": "^7.23.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tbkHOS9axH6Ysf2OUEqoSZ6T3Fa2SrNH6WTWSPBboxKzdxNc9qOICeLXkNG0ZEwbQ1HY8liwOce4aN/Ceyuq6w=="],
+ "@babel/preset-react": ["@babel/preset-react@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-transform-react-display-name": "^7.28.0", "@babel/plugin-transform-react-jsx": "^7.27.1", "@babel/plugin-transform-react-jsx-development": "^7.27.1", "@babel/plugin-transform-react-pure-annotations": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ=="],
- "@babel/preset-typescript": ["@babel/preset-typescript@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-validator-option": "^7.22.15", "@babel/plugin-syntax-jsx": "^7.23.3", "@babel/plugin-transform-modules-commonjs": "^7.23.3", "@babel/plugin-transform-typescript": "^7.23.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ=="],
+ "@babel/preset-typescript": ["@babel/preset-typescript@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g=="],
"@babel/runtime": ["@babel/runtime@7.26.10", "", { "dependencies": { "regenerator-runtime": "^0.14.0" } }, "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw=="],
@@ -899,8 +917,22 @@
"@bcoe/v8-coverage": ["@bcoe/v8-coverage@0.2.3", "", {}, "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw=="],
+ "@borewit/text-codec": ["@borewit/text-codec@0.2.2", "", {}, "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ=="],
+
+ "@braintree/sanitize-url": ["@braintree/sanitize-url@7.1.2", "", {}, "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA=="],
+
"@cfworker/json-schema": ["@cfworker/json-schema@4.1.1", "", {}, "sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og=="],
+ "@chevrotain/cst-dts-gen": ["@chevrotain/cst-dts-gen@11.1.2", "", { "dependencies": { "@chevrotain/gast": "11.1.2", "@chevrotain/types": "11.1.2", "lodash-es": "4.17.23" } }, "sha512-XTsjvDVB5nDZBQB8o0o/0ozNelQtn2KrUVteIHSlPd2VAV2utEb6JzyCJaJ8tGxACR4RiBNWy5uYUHX2eji88Q=="],
+
+ "@chevrotain/gast": ["@chevrotain/gast@11.1.2", "", { "dependencies": { "@chevrotain/types": "11.1.2", "lodash-es": "4.17.23" } }, "sha512-Z9zfXR5jNZb1Hlsd/p+4XWeUFugrHirq36bKzPWDSIacV+GPSVXdk+ahVWZTwjhNwofAWg/sZg58fyucKSQx5g=="],
+
+ "@chevrotain/regexp-to-ast": ["@chevrotain/regexp-to-ast@11.1.2", "", {}, "sha512-nMU3Uj8naWer7xpZTYJdxbAs6RIv/dxYzkYU8GSwgUtcAAlzjcPfX1w+RKRcYG8POlzMeayOQ/znfwxEGo5ulw=="],
+
+ "@chevrotain/types": ["@chevrotain/types@11.1.2", "", {}, "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw=="],
+
+ "@chevrotain/utils": ["@chevrotain/utils@11.1.2", "", {}, "sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA=="],
+
"@codemirror/autocomplete": ["@codemirror/autocomplete@6.18.0", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0" }, "peerDependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "@lezer/common": "^1.0.0" } }, "sha512-5DbOvBbY4qW5l57cjDsmmpDh3/TeK1vXfTHa+BUMrRzdWdcxKZ4U4V7vQaTtOpApNU4kLS4FQ6cINtLg245LXA=="],
"@codemirror/commands": ["@codemirror/commands@6.6.0", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.4.0", "@codemirror/view": "^6.27.0", "@lezer/common": "^1.1.0" } }, "sha512-qnY+b7j1UNcTS31Eenuc/5YJB6gQOzkUoNmJQc0rznwqSRpeaWWpjkWy2C/MPTcePpsKJEM26hXrOXl1+nceXg=="],
@@ -929,67 +961,109 @@
"@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="],
- "@csstools/cascade-layer-name-parser": ["@csstools/cascade-layer-name-parser@1.0.7", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^2.5.0", "@csstools/css-tokenizer": "^2.2.3" } }, "sha512-9J4aMRJ7A2WRjaRLvsMeWrL69FmEuijtiW1XlK/sG+V0UJiHVYUyvj9mY4WAXfU/hGIiGOgL8e0jJcRyaZTjDQ=="],
+ "@csstools/cascade-layer-name-parser": ["@csstools/cascade-layer-name-parser@3.0.0", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" } }, "sha512-/3iksyevwRfSJx5yH0RkcrcYXwuhMQx3Juqf40t97PeEy2/Mz2TItZ/z/216qpe4GgOyFBP8MKIwVvytzHmfIQ=="],
- "@csstools/color-helpers": ["@csstools/color-helpers@2.1.0", "", {}, "sha512-OWkqBa7PDzZuJ3Ha7T5bxdSVfSCfTq6K1mbAhbO1MD+GSULGjrp45i5RudyJOedstSarN/3mdwu9upJE7gDXfw=="],
+ "@csstools/color-helpers": ["@csstools/color-helpers@6.0.2", "", {}, "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q=="],
- "@csstools/css-calc": ["@csstools/css-calc@1.1.6", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^2.5.0", "@csstools/css-tokenizer": "^2.2.3" } }, "sha512-YHPAuFg5iA4qZGzMzvrQwzkvJpesXXyIUyaONflQrjtHB+BcFFbgltJkIkb31dMGO4SE9iZFA4HYpdk7+hnYew=="],
+ "@csstools/css-calc": ["@csstools/css-calc@3.1.1", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" } }, "sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ=="],
- "@csstools/css-color-parser": ["@csstools/css-color-parser@1.5.1", "", { "dependencies": { "@csstools/color-helpers": "^4.0.0", "@csstools/css-calc": "^1.1.6" }, "peerDependencies": { "@csstools/css-parser-algorithms": "^2.5.0", "@csstools/css-tokenizer": "^2.2.3" } }, "sha512-x+SajGB2paGrTjPOUorGi8iCztF008YMKXTn+XzGVDBEIVJ/W1121pPerpneJYGOe1m6zWLPLnzOPaznmQxKFw=="],
+ "@csstools/css-color-parser": ["@csstools/css-color-parser@4.0.2", "", { "dependencies": { "@csstools/color-helpers": "^6.0.2", "@csstools/css-calc": "^3.1.1" }, "peerDependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" } }, "sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw=="],
- "@csstools/css-parser-algorithms": ["@csstools/css-parser-algorithms@2.5.0", "", { "peerDependencies": { "@csstools/css-tokenizer": "^2.2.3" } }, "sha512-abypo6m9re3clXA00eu5syw+oaPHbJTPapu9C4pzNsJ4hdZDzushT50Zhu+iIYXgEe1CxnRMn7ngsbV+MLrlpQ=="],
+ "@csstools/css-parser-algorithms": ["@csstools/css-parser-algorithms@4.0.0", "", { "peerDependencies": { "@csstools/css-tokenizer": "^4.0.0" } }, "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w=="],
- "@csstools/css-tokenizer": ["@csstools/css-tokenizer@2.2.3", "", {}, "sha512-pp//EvZ9dUmGuGtG1p+n17gTHEOqu9jO+FiCUjNN3BDmyhdA2Jq9QsVeR7K8/2QCK17HSsioPlTW9ZkzoWb3Lg=="],
+ "@csstools/css-tokenizer": ["@csstools/css-tokenizer@4.0.0", "", {}, "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA=="],
- "@csstools/media-query-list-parser": ["@csstools/media-query-list-parser@2.1.7", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^2.5.0", "@csstools/css-tokenizer": "^2.2.3" } }, "sha512-lHPKJDkPUECsyAvD60joYfDmp8UERYxHGkFfyLJFTVK/ERJe0sVlIFLXU5XFxdjNDTerp5L4KeaKG+Z5S94qxQ=="],
+ "@csstools/media-query-list-parser": ["@csstools/media-query-list-parser@5.0.0", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" } }, "sha512-T9lXmZOfnam3eMERPsszjY5NK0jX8RmThmmm99FZ8b7z8yMaFZWKwLWGZuTwdO3ddRY5fy13GmmEYZXB4I98Eg=="],
- "@csstools/postcss-cascade-layers": ["@csstools/postcss-cascade-layers@3.0.1", "", { "dependencies": { "@csstools/selector-specificity": "^2.0.2", "postcss-selector-parser": "^6.0.10" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-dD8W98dOYNOH/yX4V4HXOhfCOnvVAg8TtsL+qCGNoKXuq5z2C/d026wGWgySgC8cajXXo/wNezS31Glj5GcqrA=="],
+ "@csstools/postcss-alpha-function": ["@csstools/postcss-alpha-function@2.0.3", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.2", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-8GqzD3JnfpKJSVxPIC0KadyAfB5VRzPZdv7XQ4zvK1q0ku+uHVUAS2N/IDavQkW40gkuUci64O0ea6QB/zgCSw=="],
- "@csstools/postcss-color-function": ["@csstools/postcss-color-function@2.2.3", "", { "dependencies": { "@csstools/css-color-parser": "^1.2.0", "@csstools/css-parser-algorithms": "^2.1.1", "@csstools/css-tokenizer": "^2.1.1", "@csstools/postcss-progressive-custom-properties": "^2.3.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-b1ptNkr1UWP96EEHqKBWWaV5m/0hgYGctgA/RVZhONeP1L3T/8hwoqDm9bB23yVCfOgE9U93KI9j06+pEkJTvw=="],
+ "@csstools/postcss-cascade-layers": ["@csstools/postcss-cascade-layers@6.0.0", "", { "dependencies": { "@csstools/selector-specificity": "^6.0.0", "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-WhsECqmrEZQGqaPlBA7JkmF/CJ2/+wetL4fkL9sOPccKd32PQ1qToFM6gqSI5rkpmYqubvbxjEJhyMTHYK0vZQ=="],
- "@csstools/postcss-color-mix-function": ["@csstools/postcss-color-mix-function@1.0.3", "", { "dependencies": { "@csstools/css-color-parser": "^1.2.0", "@csstools/css-parser-algorithms": "^2.1.1", "@csstools/css-tokenizer": "^2.1.1", "@csstools/postcss-progressive-custom-properties": "^2.3.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-QGXjGugTluqFZWzVf+S3wCiRiI0ukXlYqCi7OnpDotP/zaVTyl/aqZujLFzTOXy24BoWnu89frGMc79ohY5eog=="],
+ "@csstools/postcss-color-function": ["@csstools/postcss-color-function@5.0.2", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.2", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-CjBdFemUFcAh3087MEJhZcO+QT1b8S75agysa1rU9TEC1YecznzwV+jpMxUc0JRBEV4ET2PjLssqmndR9IygeA=="],
- "@csstools/postcss-font-format-keywords": ["@csstools/postcss-font-format-keywords@2.0.2", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-iKYZlIs6JsNT7NKyRjyIyezTCHLh4L4BBB3F5Nx7Dc4Z/QmBgX+YJFuUSar8IM6KclGiAUFGomXFdYxAwJydlA=="],
+ "@csstools/postcss-color-function-display-p3-linear": ["@csstools/postcss-color-function-display-p3-linear@2.0.2", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.2", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-TWUwSe1+2KdYGGWTx5LR4JQN07vKHAeSho+bGYRgow+9cs3dqgOqS1f/a1odiX30ESmZvwIudJ86wzeiDR6UGg=="],
- "@csstools/postcss-gradients-interpolation-method": ["@csstools/postcss-gradients-interpolation-method@3.0.6", "", { "dependencies": { "@csstools/css-color-parser": "^1.2.0", "@csstools/css-parser-algorithms": "^2.1.1", "@csstools/css-tokenizer": "^2.1.1", "@csstools/postcss-progressive-custom-properties": "^2.3.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-rBOBTat/YMmB0G8VHwKqDEx+RZ4KCU9j42K8LwS0IpZnyThalZZF7BCSsZ6TFlZhcRZKlZy3LLFI2pLqjNVGGA=="],
+ "@csstools/postcss-color-mix-function": ["@csstools/postcss-color-mix-function@4.0.2", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.2", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-PFKQKswFqZrYKpajZsP4lhqjU/6+J5PTOWq1rKiFnniKsf4LgpGXrgHS/C6nn5Rc51LX0n4dWOWqY5ZN2i5IjA=="],
- "@csstools/postcss-hwb-function": ["@csstools/postcss-hwb-function@2.2.2", "", { "dependencies": { "@csstools/css-color-parser": "^1.2.0", "@csstools/css-parser-algorithms": "^2.1.1", "@csstools/css-tokenizer": "^2.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-W5Y5oaJ382HSlbdGfPf60d7dAK6Hqf10+Be1yZbd/TNNrQ/3dDdV1c07YwOXPQ3PZ6dvFMhxbIbn8EC3ki3nEg=="],
+ "@csstools/postcss-color-mix-variadic-function-arguments": ["@csstools/postcss-color-mix-variadic-function-arguments@2.0.2", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.2", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-zEchsghpDH/6SytyjKu9TIPm4hiiWcur102cENl54cyIwTZsa+2MBJl/vtyALZ+uQ17h27L4waD+0Ow96sgZow=="],
- "@csstools/postcss-ic-unit": ["@csstools/postcss-ic-unit@2.0.4", "", { "dependencies": { "@csstools/postcss-progressive-custom-properties": "^2.3.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-9W2ZbV7whWnr1Gt4qYgxMWzbevZMOvclUczT5vk4yR6vS53W/njiiUhtm/jh/BKYwQ1W3PECZjgAd2dH4ebJig=="],
+ "@csstools/postcss-content-alt-text": ["@csstools/postcss-content-alt-text@3.0.0", "", { "dependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-OHa+4aCcrJtHpPWB3zptScHwpS1TUbeLR4uO0ntIz0Su/zw9SoWkVu+tDMSySSAsNtNSI3kut4fTliFwIsrHxA=="],
- "@csstools/postcss-is-pseudo-class": ["@csstools/postcss-is-pseudo-class@3.2.1", "", { "dependencies": { "@csstools/selector-specificity": "^2.0.0", "postcss-selector-parser": "^6.0.10" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-AtANdV34kJl04Al62is3eQRk/BfOfyAvEmRJvbt+nx5REqImLC+2XhuE6skgkcPli1l8ONS67wS+l1sBzySc3Q=="],
+ "@csstools/postcss-contrast-color-function": ["@csstools/postcss-contrast-color-function@3.0.2", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.2", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-fwOz/m+ytFPz4aIph2foQS9nEDOdOjYcN5bgwbGR2jGUV8mYaeD/EaTVMHTRb/zqB65y2qNwmcFcE6VQty69Pw=="],
- "@csstools/postcss-logical-float-and-clear": ["@csstools/postcss-logical-float-and-clear@1.0.1", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-eO9z2sMLddvlfFEW5Fxbjyd03zaO7cJafDurK4rCqyRt9P7aaWwha0LcSzoROlcZrw1NBV2JAp2vMKfPMQO1xw=="],
+ "@csstools/postcss-exponential-functions": ["@csstools/postcss-exponential-functions@3.0.1", "", { "dependencies": { "@csstools/css-calc": "^3.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-WHJ52Uk0AVUIICEYRY9xFHJZAuq0ZVg0f8xzqUN2zRFrZvGgRPpFwxK7h9FWvqKIOueOwN6hnJD23A8FwsUiVw=="],
- "@csstools/postcss-logical-resize": ["@csstools/postcss-logical-resize@1.0.1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-x1ge74eCSvpBkDDWppl+7FuD2dL68WP+wwP2qvdUcKY17vJksz+XoE1ZRV38uJgS6FNUwC0AxrPW5gy3MxsDHQ=="],
+ "@csstools/postcss-font-format-keywords": ["@csstools/postcss-font-format-keywords@5.0.0", "", { "dependencies": { "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-M1EjCe/J3u8fFhOZgRci74cQhJ7R0UFBX6T+WqoEvjrr8hVfMiV+HTYrzxLY5OW8YllvXYr5Q5t5OvJbsUSeDg=="],
- "@csstools/postcss-logical-viewport-units": ["@csstools/postcss-logical-viewport-units@1.0.3", "", { "dependencies": { "@csstools/css-tokenizer": "^2.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-6zqcyRg9HSqIHIPMYdt6THWhRmE5/tyHKJQLysn2TeDf/ftq7Em9qwMTx98t2C/7UxIsYS8lOiHHxAVjWn2WUg=="],
+ "@csstools/postcss-font-width-property": ["@csstools/postcss-font-width-property@1.0.0", "", { "dependencies": { "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-AvmySApdijbjYQuXXh95tb7iVnqZBbJrv3oajO927ksE/mDmJBiszm+psW8orL2lRGR8j6ZU5Uv9/ou2Z5KRKA=="],
- "@csstools/postcss-media-minmax": ["@csstools/postcss-media-minmax@1.1.2", "", { "dependencies": { "@csstools/css-calc": "^1.1.6", "@csstools/css-parser-algorithms": "^2.5.0", "@csstools/css-tokenizer": "^2.2.3", "@csstools/media-query-list-parser": "^2.1.7" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-7qTRTJxW96u2yiEaTep1+8nto1O/rEDacewKqH+Riq5E6EsHTOmGHxkB4Se5Ic5xgDC4I05lLZxzzxnlnSypxA=="],
+ "@csstools/postcss-gamut-mapping": ["@csstools/postcss-gamut-mapping@3.0.2", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.2", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-IrXAW3KQ3Sxm29C3/4mYQ/iA0Q5OH9YFOPQ2w24iIlXpD06A9MHvmQapP2vAGtQI3tlp2Xw5LIdm9F8khARfOA=="],
- "@csstools/postcss-media-queries-aspect-ratio-number-values": ["@csstools/postcss-media-queries-aspect-ratio-number-values@1.0.4", "", { "dependencies": { "@csstools/css-parser-algorithms": "^2.2.0", "@csstools/css-tokenizer": "^2.1.1", "@csstools/media-query-list-parser": "^2.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-IwyTbyR8E2y3kh6Fhrs251KjKBJeUPV5GlnUKnpU70PRFEN2DolWbf2V4+o/B9+Oj77P/DullLTulWEQ8uFtAA=="],
+ "@csstools/postcss-gradients-interpolation-method": ["@csstools/postcss-gradients-interpolation-method@6.0.2", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.2", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-saQHvD1PD/zCdn+kxCWCcQOdXZBljr8L6BKlCLs0w8GXYfo3SHdWL1HZQ+I1hVCPlU+MJPJJbZJjG/jHRJSlAw=="],
- "@csstools/postcss-nested-calc": ["@csstools/postcss-nested-calc@2.0.2", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-jbwrP8rN4e7LNaRcpx3xpMUjhtt34I9OV+zgbcsYAAk6k1+3kODXJBf95/JMYWhu9g1oif7r06QVUgfWsKxCFw=="],
+ "@csstools/postcss-hwb-function": ["@csstools/postcss-hwb-function@5.0.2", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.2", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-ChR0+pKc/2cs900jakiv8dLrb69aez5P3T+g+wfJx1j6mreAe8orKTiMrVBk+DZvCRqpdOA2m8VoFms64A3Dew=="],
- "@csstools/postcss-normalize-display-values": ["@csstools/postcss-normalize-display-values@2.0.1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-TQT5g3JQ5gPXC239YuRK8jFceXF9d25ZvBkyjzBGGoW5st5sPXFVQS8OjYb9IJ/K3CdfK4528y483cgS2DJR/w=="],
+ "@csstools/postcss-ic-unit": ["@csstools/postcss-ic-unit@5.0.0", "", { "dependencies": { "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-/ws5d6c4uKqfM9zIL3ugcGI+3fvZEOOkJHNzAyTAGJIdZ+aSL9BVPNlHGV4QzmL0vqBSCOdU3+rhcMEj3+KzYw=="],
- "@csstools/postcss-oklab-function": ["@csstools/postcss-oklab-function@2.2.3", "", { "dependencies": { "@csstools/css-color-parser": "^1.2.0", "@csstools/css-parser-algorithms": "^2.1.1", "@csstools/css-tokenizer": "^2.1.1", "@csstools/postcss-progressive-custom-properties": "^2.3.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-AgJ2rWMnLCDcbSMTHSqBYn66DNLBym6JpBpCaqmwZ9huGdljjDRuH3DzOYzkgQ7Pm2K92IYIq54IvFHloUOdvA=="],
+ "@csstools/postcss-initial": ["@csstools/postcss-initial@3.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-UVUrFmrTQyLomVepnjWlbBg7GoscLmXLwYFyjbcEnmpeGW7wde6lNpx5eM3eVwZI2M+7hCE3ykYnAsEPLcLa+Q=="],
- "@csstools/postcss-progressive-custom-properties": ["@csstools/postcss-progressive-custom-properties@2.3.0", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-Zd8ojyMlsL919TBExQ1I0CTpBDdyCpH/yOdqatZpuC3sd22K4SwC7+Yez3Q/vmXMWSAl+shjNeFZ7JMyxMjK+Q=="],
+ "@csstools/postcss-is-pseudo-class": ["@csstools/postcss-is-pseudo-class@6.0.0", "", { "dependencies": { "@csstools/selector-specificity": "^6.0.0", "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-1Hdy/ykg9RDo8vU8RiM2o+RaXO39WpFPaIkHxlAEJFofle/lc33tdQMKhBk3jR/Fe+uZNLOs3HlowFafyFptVw=="],
- "@csstools/postcss-relative-color-syntax": ["@csstools/postcss-relative-color-syntax@1.0.2", "", { "dependencies": { "@csstools/css-color-parser": "^1.2.0", "@csstools/css-parser-algorithms": "^2.1.1", "@csstools/css-tokenizer": "^2.1.1", "@csstools/postcss-progressive-custom-properties": "^2.3.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-juCoVInkgH2TZPfOhyx6tIal7jW37L/0Tt+Vcl1LoxqQA9sxcg3JWYZ98pl1BonDnki6s/M7nXzFQHWsWMeHgw=="],
+ "@csstools/postcss-light-dark-function": ["@csstools/postcss-light-dark-function@3.0.0", "", { "dependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-s++V5/hYazeRUCYIn2lsBVzUsxdeC46gtwpgW6lu5U/GlPOS5UTDT14kkEyPgXmFbCvaWLREqV7YTMJq1K3G6w=="],
- "@csstools/postcss-scope-pseudo-class": ["@csstools/postcss-scope-pseudo-class@2.0.2", "", { "dependencies": { "postcss-selector-parser": "^6.0.10" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-6Pvo4uexUCXt+Hz5iUtemQAcIuCYnL+ePs1khFR6/xPgC92aQLJ0zGHonWoewiBE+I++4gXK3pr+R1rlOFHe5w=="],
+ "@csstools/postcss-logical-float-and-clear": ["@csstools/postcss-logical-float-and-clear@4.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-NGzdIRVj/VxOa/TjVdkHeyiJoDihONV0+uB0csUdgWbFFr8xndtfqK8iIGP9IKJzco+w0hvBF2SSk2sDSTAnOQ=="],
- "@csstools/postcss-stepped-value-functions": ["@csstools/postcss-stepped-value-functions@2.1.1", "", { "dependencies": { "@csstools/css-calc": "^1.1.1", "@csstools/css-parser-algorithms": "^2.1.1", "@csstools/css-tokenizer": "^2.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-YCvdF0GCZK35nhLgs7ippcxDlRVe5QsSht3+EghqTjnYnyl3BbWIN6fYQ1dKWYTJ+7Bgi41TgqQFfJDcp9Xy/w=="],
+ "@csstools/postcss-logical-overflow": ["@csstools/postcss-logical-overflow@3.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-5cRg93QXVskM0MNepHpPcL0WLSf5Hncky0DrFDQY/4ozbH5lH7SX5ejayVpNTGSX7IpOvu7ykQDLOdMMGYzwpA=="],
- "@csstools/postcss-text-decoration-shorthand": ["@csstools/postcss-text-decoration-shorthand@2.2.4", "", { "dependencies": { "@csstools/color-helpers": "^2.1.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-zPN56sQkS/7YTCVZhOBVCWf7AiNge8fXDl7JVaHLz2RyT4pnyK2gFjckWRLpO0A2xkm1lCgZ0bepYZTwAVd/5A=="],
+ "@csstools/postcss-logical-overscroll-behavior": ["@csstools/postcss-logical-overscroll-behavior@3.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-82Jnl/5Wi5jb19nQE1XlBHrZcNL3PzOgcj268cDkfwf+xi10HBqufGo1Unwf5n8bbbEFhEKgyQW+vFsc9iY1jw=="],
- "@csstools/postcss-trigonometric-functions": ["@csstools/postcss-trigonometric-functions@2.1.1", "", { "dependencies": { "@csstools/css-calc": "^1.1.1", "@csstools/css-parser-algorithms": "^2.1.1", "@csstools/css-tokenizer": "^2.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-XcXmHEFfHXhvYz40FtDlA4Fp4NQln2bWTsCwthd2c+MCnYArUYU3YaMqzR5CrKP3pMoGYTBnp5fMqf1HxItNyw=="],
+ "@csstools/postcss-logical-resize": ["@csstools/postcss-logical-resize@4.0.0", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-L0T3q0gei/tGetCGZU0c7VN77VTivRpz1YZRNxjXYmW+85PKeI6U9YnSvDqLU2vBT2uN4kLEzfgZ0ThIZpN18A=="],
- "@csstools/postcss-unset-value": ["@csstools/postcss-unset-value@2.0.1", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-oJ9Xl29/yU8U7/pnMJRqAZd4YXNCfGEdcP4ywREuqm/xMqcgDNDppYRoCGDt40aaZQIEKBS79LytUDN/DHf0Ew=="],
+ "@csstools/postcss-logical-viewport-units": ["@csstools/postcss-logical-viewport-units@4.0.0", "", { "dependencies": { "@csstools/css-tokenizer": "^4.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-TA3AqVN/1IH3dKRC2UUWvprvwyOs2IeD7FDZk5Hz20w4q33yIuSg0i0gjyTUkcn90g8A4n7QpyZ2AgBrnYPnnA=="],
- "@csstools/selector-specificity": ["@csstools/selector-specificity@2.2.0", "", { "peerDependencies": { "postcss-selector-parser": "^6.0.10" } }, "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw=="],
+ "@csstools/postcss-media-minmax": ["@csstools/postcss-media-minmax@3.0.1", "", { "dependencies": { "@csstools/css-calc": "^3.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/media-query-list-parser": "^5.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-I+CrmZt23fyejMItpLQFOg9gPXkDBBDjTqRT0UxCTZlYZfGrzZn4z+2kbXLRwDfR59OK8zaf26M4kwYwG0e1MA=="],
+
+ "@csstools/postcss-media-queries-aspect-ratio-number-values": ["@csstools/postcss-media-queries-aspect-ratio-number-values@4.0.0", "", { "dependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/media-query-list-parser": "^5.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-FDdC3lbrj8Vr0SkGIcSLTcRB7ApG6nlJFxOxkEF2C5hIZC1jtgjISFSGn/WjFdVkn8Dqe+Vx9QXI3axS2w1XHw=="],
+
+ "@csstools/postcss-mixins": ["@csstools/postcss-mixins@1.0.0", "", { "dependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-rz6qjT2w9L3k65jGc2dX+3oGiSrYQ70EZPDrINSmSVoVys7lLBFH0tvEa8DW2sr9cbRVD/W+1sy8+7bfu0JUfg=="],
+
+ "@csstools/postcss-nested-calc": ["@csstools/postcss-nested-calc@5.0.0", "", { "dependencies": { "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-aPSw8P60e/i9BEfugauhikBqgjiwXcw3I9o4vXs+hktl4NSTgZRI0QHimxk9mst8N01A2TKDBxOln3mssRxiHQ=="],
+
+ "@csstools/postcss-normalize-display-values": ["@csstools/postcss-normalize-display-values@5.0.1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-FcbEmoxDEGYvm2W3rQzVzcuo66+dDJjzzVDs+QwRmZLHYofGmMGwIKPqzF86/YW+euMDa7sh1xjWDvz/fzByZQ=="],
+
+ "@csstools/postcss-oklab-function": ["@csstools/postcss-oklab-function@5.0.2", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.2", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-3d/Wcnp2uW6Io0Tajl0croeUo46gwOVQI9N32PjA/HVQo6z1iL7yp19Gp+6e5E5CDKGpW7U822MsDVo2XK1z0Q=="],
+
+ "@csstools/postcss-position-area-property": ["@csstools/postcss-position-area-property@2.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-TeEfzsJGB23Syv7yCm8AHCD2XTFujdjr9YYu9ebH64vnfCEvY4BG319jXAYSlNlf3Yc9PNJ6WnkDkUF5XVgSKQ=="],
+
+ "@csstools/postcss-progressive-custom-properties": ["@csstools/postcss-progressive-custom-properties@5.0.0", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-NsJoZ89rxmDrUsITf8QIk5w+lQZQ8Xw5K6cLFG+cfiffsLYHb3zcbOOrHLetGl1WIhjWWQ4Cr8MMrg46Q+oACg=="],
+
+ "@csstools/postcss-property-rule-prelude-list": ["@csstools/postcss-property-rule-prelude-list@2.0.0", "", { "dependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-qcMAkc9AhpzHgmQCD8hoJgGYifcOAxd1exXjjxilMM6euwRE619xDa4UsKBCv/v4g+sS63sd6c29LPM8s2ylSQ=="],
+
+ "@csstools/postcss-random-function": ["@csstools/postcss-random-function@3.0.1", "", { "dependencies": { "@csstools/css-calc": "^3.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-SvKGfmj+WHfn4bWHaBYlkXDyU3SlA3fL8aaYZ8Op6M8tunNf3iV9uZyZZGWMCbDw0sGeoTmYZW9nmKN8Qi/ctg=="],
+
+ "@csstools/postcss-relative-color-syntax": ["@csstools/postcss-relative-color-syntax@4.0.2", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.2", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-HaMN+qMURinllszbps2AhXKaLeibg/2VW6FriYDrqE58ji82+z2S3/eLloywVOY8BQCJ9lZMdy6TcRQNbn9u3w=="],
+
+ "@csstools/postcss-scope-pseudo-class": ["@csstools/postcss-scope-pseudo-class@5.0.0", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-kBrBFJcAji3MSHS4qQIihPvJfJC5xCabXLbejqDMiQi+86HD4eMBiTayAo46Urg7tlEmZZQFymFiJt+GH6nvXw=="],
+
+ "@csstools/postcss-sign-functions": ["@csstools/postcss-sign-functions@2.0.1", "", { "dependencies": { "@csstools/css-calc": "^3.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-C3br0qcHJkQ0qSGUBnDJHXQdO8XObnCpGwai5m1L2tv2nCjt0vRHG6A9aVCQHvh08OqHNM2ty1dYDNNXV99YAQ=="],
+
+ "@csstools/postcss-stepped-value-functions": ["@csstools/postcss-stepped-value-functions@5.0.1", "", { "dependencies": { "@csstools/css-calc": "^3.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-vZf7zPzRb7xIi2o5Z9q6wyeEAjoRCg74O2QvYxmQgxYO5V5cdBv4phgJDyOAOP3JHy4abQlm2YaEUS3gtGQo0g=="],
+
+ "@csstools/postcss-syntax-descriptor-syntax-production": ["@csstools/postcss-syntax-descriptor-syntax-production@2.0.0", "", { "dependencies": { "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-elYcbdiBXAkPqvojB9kIBRuHY6htUhjSITtFQ+XiXnt6SvZCbNGxQmaaw6uZ7SPHu/+i/XVjzIt09/1k3SIerQ=="],
+
+ "@csstools/postcss-system-ui-font-family": ["@csstools/postcss-system-ui-font-family@2.0.0", "", { "dependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-FyGZCgchFImFyiHS2x3rD5trAqatf/x23veBLTIgbaqyFfna6RNBD+Qf8HRSjt6HGMXOLhAjxJ3OoZg0bbn7Qw=="],
+
+ "@csstools/postcss-text-decoration-shorthand": ["@csstools/postcss-text-decoration-shorthand@5.0.3", "", { "dependencies": { "@csstools/color-helpers": "^6.0.2", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-62fjggvIM1YYfDJPcErMUDkEZB6CByG8neTJqexnZe1hRBgCjD4dnXDLoCSSurjs1LzjBq6irFDpDaOvDZfrlw=="],
+
+ "@csstools/postcss-trigonometric-functions": ["@csstools/postcss-trigonometric-functions@5.0.1", "", { "dependencies": { "@csstools/css-calc": "^3.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-e8me32Mhl8JeBnxVJgsQUYpV4Md4KiyvpILpQlaY/eK1Gwdb04kasiTTswPQ5q7Z8+FppJZ2Z4d8HRfn6rjD3w=="],
+
+ "@csstools/postcss-unset-value": ["@csstools/postcss-unset-value@5.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-EoO54sS2KCIfesvHyFYAW99RtzwHdgaJzhl7cqKZSaMYKZv3fXSOehDjAQx8WZBKn1JrMd7xJJI1T1BxPF7/jA=="],
+
+ "@csstools/selector-resolve-nested": ["@csstools/selector-resolve-nested@4.0.0", "", { "peerDependencies": { "postcss-selector-parser": "^7.1.1" } }, "sha512-9vAPxmp+Dx3wQBIUwc1v7Mdisw1kbbaGqXUM8QLTgWg7SoPGYtXBsMXvsFs/0Bn5yoFhcktzxNZGNaUt0VjgjA=="],
+
+ "@csstools/selector-specificity": ["@csstools/selector-specificity@6.0.0", "", { "peerDependencies": { "postcss-selector-parser": "^7.1.1" } }, "sha512-4sSgl78OtOXEX/2d++8A83zHNTgwCJMaR24FvsYL7Uf/VS8HZk9PTwR51elTbGqMuwH3szLvvOXEaVnqn0Z3zA=="],
+
+ "@csstools/utilities": ["@csstools/utilities@3.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-etDqA/4jYvOGBM6yfKCOsEXfH96BKztZdgGmGqKi2xHnDe0ILIBraRspwgYatJH9JsCZ5HCGoCst8w18EKOAdg=="],
"@dabh/diagnostics": ["@dabh/diagnostics@2.0.3", "", { "dependencies": { "colorspace": "1.1.x", "enabled": "2.0.x", "kuler": "^2.0.0" } }, "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA=="],
@@ -1063,55 +1137,57 @@
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
- "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ=="],
+ "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="],
- "@esbuild/android-arm": ["@esbuild/android-arm@0.25.1", "", { "os": "android", "cpu": "arm" }, "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q=="],
+ "@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="],
- "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.1", "", { "os": "android", "cpu": "arm64" }, "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA=="],
+ "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="],
- "@esbuild/android-x64": ["@esbuild/android-x64@0.25.1", "", { "os": "android", "cpu": "x64" }, "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw=="],
+ "@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="],
- "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ=="],
+ "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="],
- "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA=="],
+ "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="],
- "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A=="],
+ "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="],
- "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww=="],
+ "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="],
- "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.1", "", { "os": "linux", "cpu": "arm" }, "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ=="],
+ "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="],
- "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ=="],
+ "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="],
- "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.1", "", { "os": "linux", "cpu": "ia32" }, "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ=="],
+ "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="],
- "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.1", "", { "os": "linux", "cpu": "none" }, "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg=="],
+ "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="],
- "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.1", "", { "os": "linux", "cpu": "none" }, "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg=="],
+ "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="],
- "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg=="],
+ "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="],
- "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.1", "", { "os": "linux", "cpu": "none" }, "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ=="],
+ "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="],
- "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ=="],
+ "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="],
- "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA=="],
+ "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="],
- "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.1", "", { "os": "none", "cpu": "arm64" }, "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g=="],
+ "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="],
- "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.1", "", { "os": "none", "cpu": "x64" }, "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA=="],
+ "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="],
- "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.1", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg=="],
+ "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="],
- "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw=="],
+ "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="],
- "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.1", "", { "os": "sunos", "cpu": "x64" }, "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg=="],
+ "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="],
- "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ=="],
+ "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="],
- "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A=="],
+ "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="],
- "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.1", "", { "os": "win32", "cpu": "x64" }, "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg=="],
+ "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="],
+
+ "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="],
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="],
@@ -1125,7 +1201,7 @@
"@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="],
- "@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="],
+ "@eslint/eslintrc": ["@eslint/eslintrc@3.3.5", "", { "dependencies": { "ajv": "^6.14.0", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" } }, "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg=="],
"@eslint/js": ["@eslint/js@9.39.1", "", {}, "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw=="],
@@ -1231,17 +1307,19 @@
"@floating-ui/utils": ["@floating-ui/utils@0.2.8", "", {}, "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig=="],
- "@google/generative-ai": ["@google/generative-ai@0.24.0", "", {}, "sha512-fnEITCGEB7NdX0BhoYZ/cq/7WPZ1QS5IzJJfC3Tg/OwkvBetMiVJciyaan297OvE4B9Jg1xvo0zIazX/9sGu1Q=="],
+ "@google/genai": ["@google/genai@1.44.0", "", { "dependencies": { "google-auth-library": "^10.3.0", "p-retry": "^4.6.2", "protobufjs": "^7.5.4", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.2" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-kRt9ZtuXmz+tLlcNntN/VV4LRdpl6ZOu5B1KbfNgfR65db15O6sUQcwnwLka8sT/V6qysD93fWrgJHF2L7dA9A=="],
- "@googleapis/youtube": ["@googleapis/youtube@20.0.0", "", { "dependencies": { "googleapis-common": "^7.0.0" } }, "sha512-wdt1J0JoKYhvpoS2XIRHX0g/9ul/B0fQeeJAhuuBIdYINuuLt6/oZYZZCBmkuhtkA3IllXgqgAXOjLtLRAnR2g=="],
+ "@google/generative-ai": ["@google/generative-ai@0.24.0", "", {}, "sha512-fnEITCGEB7NdX0BhoYZ/cq/7WPZ1QS5IzJJfC3Tg/OwkvBetMiVJciyaan297OvE4B9Jg1xvo0zIazX/9sGu1Q=="],
"@grpc/grpc-js": ["@grpc/grpc-js@1.9.15", "", { "dependencies": { "@grpc/proto-loader": "^0.7.8", "@types/node": ">=12.12.47" } }, "sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ=="],
"@grpc/proto-loader": ["@grpc/proto-loader@0.7.13", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.2.5", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw=="],
+ "@happy-dom/jest-environment": ["@happy-dom/jest-environment@20.8.3", "", { "dependencies": { "happy-dom": "^20.8.3" }, "peerDependencies": { "@jest/environment": ">=25.0.0", "@jest/fake-timers": ">=25.0.0", "@jest/types": ">=25.0.0", "jest-mock": ">=25.0.0", "jest-util": ">=25.0.0" } }, "sha512-VMOfNvF7UPPHIc7SUrFqGXqJrkONYX6Vd0ZXblmjgb1JA2RFnrc1KiVodzG0c7IT5Q0jfA0CQjvlqWjQ/BYtkQ=="],
+
"@headlessui/react": ["@headlessui/react@2.2.4", "", { "dependencies": { "@floating-ui/react": "^0.26.16", "@react-aria/focus": "^3.20.2", "@react-aria/interactions": "^3.25.0", "@tanstack/react-virtual": "^3.13.9", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "sha512-lz+OGcAH1dK93rgSMzXmm1qKOJkBUqZf1L4M8TWLNplftQD3IkoEDdUFNfAn4ylsN6WOTVtWaLmvmaHOUk1dTA=="],
- "@hono/node-server": ["@hono/node-server@1.19.7", "", { "peerDependencies": { "hono": "^4" } }, "sha512-vUcD0uauS7EU2caukW8z5lJKtoGMokxNbJtBiwHgpqxEXokaHCBkQUmCHhjFB1VUTWdqj25QoMkMKzgjq+uhrw=="],
+ "@hono/node-server": ["@hono/node-server@1.19.11", "", { "peerDependencies": { "hono": "^4" } }, "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g=="],
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
@@ -1251,6 +1329,10 @@
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
+ "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="],
+
+ "@iconify/utils": ["@iconify/utils@3.1.0", "", { "dependencies": { "@antfu/install-pkg": "^1.1.0", "@iconify/types": "^2.0.0", "mlly": "^1.8.0" } }, "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw=="],
+
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="],
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.0.4" }, "os": "darwin", "cpu": "x64" }, "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q=="],
@@ -1315,7 +1397,7 @@
"@jest/expect-utils": ["@jest/expect-utils@29.7.0", "", { "dependencies": { "jest-get-type": "^29.6.3" } }, "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA=="],
- "@jest/fake-timers": ["@jest/fake-timers@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", "jest-message-util": "^29.7.0", "jest-mock": "^29.7.0", "jest-util": "^29.7.0" } }, "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ=="],
+ "@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="],
"@jest/get-type": ["@jest/get-type@30.1.0", "", {}, "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA=="],
@@ -1359,7 +1441,7 @@
"@langchain/aws": ["@langchain/aws@0.1.15", "", { "dependencies": { "@aws-sdk/client-bedrock-agent-runtime": "^3.755.0", "@aws-sdk/client-bedrock-runtime": "^3.840.0", "@aws-sdk/client-kendra": "^3.750.0", "@aws-sdk/credential-provider-node": "^3.750.0" }, "peerDependencies": { "@langchain/core": ">=0.3.58 <0.4.0" } }, "sha512-oyOMhTHP0rxdSCVI/g5KXYCOs9Kq/FpXMZbOk1JSIUoaIzUg4p6d98lsHu7erW//8NSaT+SX09QRbVDAgt7pNA=="],
- "@langchain/core": ["@langchain/core@0.3.79", "", { "dependencies": { "@cfworker/json-schema": "^4.0.2", "ansi-styles": "^5.0.0", "camelcase": "6", "decamelize": "1.2.0", "js-tiktoken": "^1.0.12", "langsmith": "^0.3.67", "mustache": "^4.2.0", "p-queue": "^6.6.2", "p-retry": "4", "uuid": "^10.0.0", "zod": "^3.25.32", "zod-to-json-schema": "^3.22.3" } }, "sha512-ZLAs5YMM5N2UXN3kExMglltJrKKoW7hs3KMZFlXUnD7a5DFKBYxPFMeXA4rT+uvTxuJRZPCYX0JKI5BhyAWx4A=="],
+ "@langchain/core": ["@langchain/core@0.3.80", "", { "dependencies": { "@cfworker/json-schema": "^4.0.2", "ansi-styles": "^5.0.0", "camelcase": "6", "decamelize": "1.2.0", "js-tiktoken": "^1.0.12", "langsmith": "^0.3.67", "mustache": "^4.2.0", "p-queue": "^6.6.2", "p-retry": "4", "uuid": "^10.0.0", "zod": "^3.25.32", "zod-to-json-schema": "^3.22.3" } }, "sha512-vcJDV2vk1AlCwSh3aBm/urQ1ZrlXFFBocv11bz/NBUfLWD5/UDNMzwPdaAd2dKvNmTWa9FM2lirLU3+JCf4cRA=="],
"@langchain/deepseek": ["@langchain/deepseek@0.0.2", "", { "dependencies": { "@langchain/openai": "^0.5.5" }, "peerDependencies": { "@langchain/core": ">=0.3.58 <0.4.0" } }, "sha512-u13KbPUXW7uhcybbRzYdRroBgqVUSgG0SJM15c7Etld2yjRQC2c4O/ga9eQZdLh/kaDlQfH/ZITFdjHe77RnGw=="],
@@ -1405,7 +1487,7 @@
"@lezer/lr": ["@lezer/lr@1.4.2", "", { "dependencies": { "@lezer/common": "^1.0.0" } }, "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA=="],
- "@librechat/agents": ["@librechat/agents@3.0.50", "", { "dependencies": { "@langchain/anthropic": "^0.3.26", "@langchain/aws": "^0.1.15", "@langchain/core": "^0.3.79", "@langchain/deepseek": "^0.0.2", "@langchain/google-genai": "^0.2.18", "@langchain/google-vertexai": "^0.2.18", "@langchain/langgraph": "^0.4.9", "@langchain/mistralai": "^0.2.1", "@langchain/openai": "0.5.18", "@langchain/textsplitters": "^0.1.0", "@langchain/xai": "^0.0.3", "@langfuse/langchain": "^4.3.0", "@langfuse/otel": "^4.3.0", "@langfuse/tracing": "^4.3.0", "@opentelemetry/sdk-node": "^0.207.0", "axios": "^1.12.1", "cheerio": "^1.0.0", "dotenv": "^16.4.7", "https-proxy-agent": "^7.0.6", "mathjs": "^15.1.0", "nanoid": "^3.3.7", "openai": "5.8.2" } }, "sha512-oovj3BsP/QoxPbWFAc71Ddplwd9BT8ucfYs+n+kiR37aCWtvxdvL9/XldRYfnaq9boNE324njQJyqc8v8AAPFQ=="],
+ "@librechat/agents": ["@librechat/agents@3.1.56", "", { "dependencies": { "@anthropic-ai/sdk": "^0.73.0", "@aws-sdk/client-bedrock-runtime": "^3.980.0", "@langchain/anthropic": "^0.3.26", "@langchain/aws": "^0.1.15", "@langchain/core": "^0.3.80", "@langchain/deepseek": "^0.0.2", "@langchain/google-genai": "^0.2.18", "@langchain/google-vertexai": "^0.2.18", "@langchain/langgraph": "^0.4.9", "@langchain/mistralai": "^0.2.1", "@langchain/openai": "0.5.18", "@langchain/textsplitters": "^0.1.0", "@langchain/xai": "^0.0.3", "@langfuse/langchain": "^4.3.0", "@langfuse/otel": "^4.3.0", "@langfuse/tracing": "^4.3.0", "@opentelemetry/sdk-node": "^0.207.0", "@scarf/scarf": "^1.4.0", "ai-tokenizer": "^1.0.6", "axios": "^1.13.5", "cheerio": "^1.0.0", "dotenv": "^16.4.7", "https-proxy-agent": "^7.0.6", "mathjs": "^15.1.0", "nanoid": "^3.3.7", "okapibm25": "^1.4.1", "openai": "5.8.2" } }, "sha512-HJJwRnLM4XKpTWB4/wPDJR+iegyKBVUwqj7A8QHqzEcHzjKJDTr3wBPxZVH1tagGr6/mbbnErOJ14cH1OSNmpA=="],
"@librechat/api": ["@librechat/api@workspace:packages/api"],
@@ -1421,14 +1503,44 @@
"@mcp-ui/client": ["@mcp-ui/client@5.7.0", "", { "dependencies": { "@modelcontextprotocol/sdk": "*", "@quilted/threads": "^3.1.3", "@r2wc/react-to-web-component": "^2.0.4", "@remote-dom/core": "^1.8.0", "@remote-dom/react": "^1.2.2", "react": "^18.3.1", "react-dom": "^18.3.1" } }, "sha512-+HbPw3VS46WUSWmyJ34ZVnygb81QByA3luR6y0JDbyDZxjYtHw1FcIN7v9WbbE8PrfI0WcuWCSiNOO6sOGbwpQ=="],
+ "@mermaid-js/parser": ["@mermaid-js/parser@1.0.1", "", { "dependencies": { "langium": "^4.0.0" } }, "sha512-opmV19kN1JsK0T6HhhokHpcVkqKpF+x2pPDKKM2ThHtZAB5F4PROopk0amuVYK5qMrIA4erzpNm8gmPNJgMDxQ=="],
+
"@microsoft/microsoft-graph-client": ["@microsoft/microsoft-graph-client@3.0.7", "", { "dependencies": { "@babel/runtime": "^7.12.5", "tslib": "^2.2.0" } }, "sha512-/AazAV/F+HK4LIywF9C+NYHcJo038zEnWkteilcxC1FM/uK/4NVGDKGrxx7nNq1ybspAroRKT4I1FHfxQzxkUw=="],
"@mistralai/mistralai": ["@mistralai/mistralai@1.10.0", "", { "dependencies": { "zod": "^3.20.0", "zod-to-json-schema": "^3.24.1" } }, "sha512-tdIgWs4Le8vpvPiUEWne6tK0qbVc+jMenujnvTqOjogrJUsCSQhus0tHTU1avDDh5//Rq2dFgP9mWRAdIEoBqg=="],
- "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.25.0", "", { "dependencies": { "@hono/node-server": "^1.19.7", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "jose": "^6.1.1", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.0" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-z0Zhn/LmQ3yz91dEfd5QgS7DpSjA4pk+3z2++zKgn5L6iDFM9QapsVoAQSbKLvlrFsZk9+ru6yHHWNq2lCYJKQ=="],
+ "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.27.1", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA=="],
+
+ "@monaco-editor/loader": ["@monaco-editor/loader@1.7.0", "", { "dependencies": { "state-local": "^1.0.6" } }, "sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA=="],
+
+ "@monaco-editor/react": ["@monaco-editor/react@4.7.0", "", { "dependencies": { "@monaco-editor/loader": "^1.5.0" }, "peerDependencies": { "monaco-editor": ">= 0.25.0 < 1", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA=="],
"@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.3.1", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-6nZrq5kfAz0POWyhljnbWQQJQ5uT8oE2ddX303q1uY0tWsivWKgBDXBBvuFPwOqRRalXJuVO9EjOdVtuhLX0zg=="],
+ "@napi-rs/canvas": ["@napi-rs/canvas@0.1.96", "", { "optionalDependencies": { "@napi-rs/canvas-android-arm64": "0.1.96", "@napi-rs/canvas-darwin-arm64": "0.1.96", "@napi-rs/canvas-darwin-x64": "0.1.96", "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.96", "@napi-rs/canvas-linux-arm64-gnu": "0.1.96", "@napi-rs/canvas-linux-arm64-musl": "0.1.96", "@napi-rs/canvas-linux-riscv64-gnu": "0.1.96", "@napi-rs/canvas-linux-x64-gnu": "0.1.96", "@napi-rs/canvas-linux-x64-musl": "0.1.96", "@napi-rs/canvas-win32-arm64-msvc": "0.1.96", "@napi-rs/canvas-win32-x64-msvc": "0.1.96" } }, "sha512-6NNmNxvoJKeucVjxaaRUt3La2i5jShgiAbaY3G/72s1Vp3U06XPrAIxkAjBxpDcamEn/t+WJ4OOlGmvILo4/Ew=="],
+
+ "@napi-rs/canvas-android-arm64": ["@napi-rs/canvas-android-arm64@0.1.96", "", { "os": "android", "cpu": "arm64" }, "sha512-ew1sPrN3dGdZ3L4FoohPfnjq0f9/Jk7o+wP7HkQZokcXgIUD6FIyICEWGhMYzv53j63wUcPvZeAwgewX58/egg=="],
+
+ "@napi-rs/canvas-darwin-arm64": ["@napi-rs/canvas-darwin-arm64@0.1.96", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Q/wOXZ5PzTqpdmA5eUOcegCf4Go/zz3aZ5DlzSeDpOjFmfwMKh8EzLAoweQ+mJVagcHQyzoJhaTEnrO68TNyNg=="],
+
+ "@napi-rs/canvas-darwin-x64": ["@napi-rs/canvas-darwin-x64@0.1.96", "", { "os": "darwin", "cpu": "x64" }, "sha512-UrXiQz28tQEvGM1qvyptewOAfmUrrd5+wvi6Rzjj2VprZI8iZ2KIvBD2lTTG1bVF95AbeDeG7PJA0D9sLKaOFA=="],
+
+ "@napi-rs/canvas-linux-arm-gnueabihf": ["@napi-rs/canvas-linux-arm-gnueabihf@0.1.96", "", { "os": "linux", "cpu": "arm" }, "sha512-I90ODxweD8aEP6XKU/NU+biso95MwCtQ2F46dUvhec1HesFi0tq/tAJkYic/1aBSiO/1kGKmSeD1B0duOHhEHQ=="],
+
+ "@napi-rs/canvas-linux-arm64-gnu": ["@napi-rs/canvas-linux-arm64-gnu@0.1.96", "", { "os": "linux", "cpu": "arm64" }, "sha512-Dx/0+RFV++w3PcRy+4xNXkghhXjA5d0Mw1bs95emn5Llinp1vihMaA6WJt3oYv2LAHc36+gnrhIBsPhUyI2SGw=="],
+
+ "@napi-rs/canvas-linux-arm64-musl": ["@napi-rs/canvas-linux-arm64-musl@0.1.96", "", { "os": "linux", "cpu": "arm64" }, "sha512-UvOi7fii3IE2KDfEfhh8m+LpzSRvhGK7o1eho99M2M0HTik11k3GX+2qgVx9EtujN3/bhFFS1kSO3+vPMaJ0Mg=="],
+
+ "@napi-rs/canvas-linux-riscv64-gnu": ["@napi-rs/canvas-linux-riscv64-gnu@0.1.96", "", { "os": "linux", "cpu": "none" }, "sha512-MBSukhGCQ5nRtf9NbFYWOU080yqkZU1PbuH4o1ROvB4CbPl12fchDR35tU83Wz8gWIM9JTn99lBn9DenPIv7Ig=="],
+
+ "@napi-rs/canvas-linux-x64-gnu": ["@napi-rs/canvas-linux-x64-gnu@0.1.96", "", { "os": "linux", "cpu": "x64" }, "sha512-I/ccu2SstyKiV3HIeVzyBIWfrJo8cN7+MSQZPnabewWV6hfJ2nY7Df2WqOHmobBRUw84uGR6zfQHsUEio/m5Vg=="],
+
+ "@napi-rs/canvas-linux-x64-musl": ["@napi-rs/canvas-linux-x64-musl@0.1.96", "", { "os": "linux", "cpu": "x64" }, "sha512-H3uov7qnTl73GDT4h52lAqpJPsl1tIUyNPWJyhQ6gHakohNqqRq3uf80+NEpzcytKGEOENP1wX3yGwZxhjiWEQ=="],
+
+ "@napi-rs/canvas-win32-arm64-msvc": ["@napi-rs/canvas-win32-arm64-msvc@0.1.96", "", { "os": "win32", "cpu": "arm64" }, "sha512-ATp6Y+djOjYtkfV/VRH7CZ8I1MEtkUQBmKUbuWw5zWEHHqfL0cEcInE4Cxgx7zkNAhEdBbnH8HMVrqNp+/gwxA=="],
+
+ "@napi-rs/canvas-win32-x64-msvc": ["@napi-rs/canvas-win32-x64-msvc@0.1.96", "", { "os": "win32", "cpu": "x64" }, "sha512-UYGdTltVd+Z8mcIuoqGmAXXUvwH5CLf2M6mIB5B0/JmX5J041jETjqtSYl7gN+aj3k1by/SG6sS0hAwCqyK7zw=="],
+
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="],
"@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
@@ -1547,7 +1659,7 @@
"@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collapsible": "1.1.11", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-l3W5D54emV2ues7jjeG1xcyN7S3jnK3zE2zHqgn0CmMsy9lNJwmgcrmaxS+7ipw15FAivzKNzH3d5EcGoFKw0A=="],
- "@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw=="],
+ "@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.0", "@radix-ui/react-compose-refs": "1.0.0", "@radix-ui/react-context": "1.0.0", "@radix-ui/react-dialog": "1.0.2", "@radix-ui/react-primitive": "1.0.1", "@radix-ui/react-slot": "1.0.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-0MtxV53FaEEBOKRgyLnEqHZKKDS5BldQ9oUBsKVXWI5FHbl2jp35qs+0aJET+K5hJDsc40kQUzP7g+wC7tqrqA=="],
"@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-primitive": "1.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA=="],
@@ -1561,17 +1673,17 @@
"@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="],
- "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="],
+ "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.0", "@radix-ui/react-compose-refs": "1.0.0", "@radix-ui/react-context": "1.0.0", "@radix-ui/react-dismissable-layer": "1.0.2", "@radix-ui/react-focus-guards": "1.0.0", "@radix-ui/react-focus-scope": "1.0.1", "@radix-ui/react-id": "1.0.0", "@radix-ui/react-portal": "1.0.1", "@radix-ui/react-presence": "1.0.0", "@radix-ui/react-primitive": "1.0.1", "@radix-ui/react-slot": "1.0.1", "@radix-ui/react-use-controllable-state": "1.0.0", "aria-hidden": "^1.1.1", "react-remove-scroll": "2.5.5" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-EKxxp2WNSmUPkx4trtWNmZ4/vAYEg7JkAfa1HKBUnaubw9eHzf1Orr9B472lJYaYz327RHDrd4R95fsw7VR8DA=="],
"@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="],
- "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
+ "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.0", "@radix-ui/react-compose-refs": "1.0.0", "@radix-ui/react-primitive": "1.0.1", "@radix-ui/react-use-callback-ref": "1.0.0", "@radix-ui/react-use-escape-keydown": "1.0.2" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-WjJzMrTWROozDqLB0uRWYvj4UuXsM/2L19EmQ3Au+IJWqwvwq9Bwd+P8ivo0Deg9JDPArR1I6MbWNi1CmXsskg=="],
"@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.1", "", { "dependencies": { "@radix-ui/primitive": "1.1.0", "@radix-ui/react-compose-refs": "1.1.0", "@radix-ui/react-context": "1.1.0", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-menu": "2.1.1", "@radix-ui/react-primitive": "2.0.0", "@radix-ui/react-use-controllable-state": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-y8E+x9fBq9qvteD2Zwa4397pUVhYsh9iq44b5RD5qu1GMJWBCBuVg1hMyItbc6+zH00TxGRqd9Iot4wzf3OoBQ=="],
- "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="],
+ "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-UagjDk4ijOAnGu4WMUPj9ahi7/zJJqNZ9ZAiGPp7waUWJO0O1aWXi/udPphI0IUjvrhBsZJGSN66dR2dsueLWQ=="],
- "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="],
+ "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.0", "@radix-ui/react-primitive": "1.0.1", "@radix-ui/react-use-callback-ref": "1.0.0" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-Ej2MQTit8IWJiS2uuujGUmxXjF/y5xZptIIQnyd2JHLwtV0R2j9NRVoRj/1j/gJ7e3REdaBw4Hjf4a1ImhkZcQ=="],
"@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.0.7", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.1", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-context": "1.0.1", "@radix-ui/react-dismissable-layer": "1.0.5", "@radix-ui/react-popper": "1.1.3", "@radix-ui/react-portal": "1.0.4", "@radix-ui/react-presence": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-controllable-state": "1.0.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-OcUN2FU0YpmajD/qkph3XzMcK/NmSk9hGWnjV68p6QiZMgILugusgQwnLSDs3oFSJYGKf3Y49zgFedhGh04k9A=="],
@@ -1587,7 +1699,7 @@
"@radix-ui/react-popper": ["@radix-ui/react-popper@1.1.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.0.3", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-context": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-callback-ref": "1.0.1", "@radix-ui/react-use-layout-effect": "1.0.1", "@radix-ui/react-use-rect": "1.0.1", "@radix-ui/react-use-size": "1.0.1", "@radix-ui/rect": "1.0.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w=="],
- "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="],
+ "@radix-ui/react-portal": ["@radix-ui/react-portal@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-primitive": "1.0.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-NY2vUWI5WENgAT1nfC6JS7RU5xRYBfjZVLq0HmgEN1Ezy3rk/UruMV4+Rd0F40PEaFC5SrLS1ixYvcYIQrb4Ig=="],
"@radix-ui/react-presence": ["@radix-ui/react-presence@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-use-layout-effect": "1.0.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg=="],
@@ -1619,7 +1731,7 @@
"@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="],
- "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="],
+ "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-callback-ref": "1.0.0" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-DXGim3x74WgUv+iMNCF+cAo8xUHHeqvjx8zs7trKf+FkQKPQXLk2sX7Gx1ysH7Q76xCpZuxIJE7HLPxRE+Q+GA=="],
"@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
@@ -1673,7 +1785,7 @@
"@redis/client": ["@redis/client@1.6.0", "", { "dependencies": { "cluster-key-slot": "1.1.2", "generic-pool": "3.9.0", "yallist": "4.0.0" } }, "sha512-aR0uffYI700OEEH4gYnitAnv3vzVGXCFvYfdpu/CJKvk4pHfLPEy/JSZyrpQ+15WhXe1yJRXLtfQ84s4mEXnPg=="],
- "@remix-run/router": ["@remix-run/router@1.15.0", "", {}, "sha512-HOil5aFtme37dVQTB6M34G95kPM3MMuqSmIRVCC52eKV+Y/tGSqw9P3rWhlAx6A+mz+MoX+XxsGsNJbaI5qCgQ=="],
+ "@remix-run/router": ["@remix-run/router@1.23.2", "", {}, "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w=="],
"@remote-dom/core": ["@remote-dom/core@1.9.0", "", { "dependencies": { "@remote-dom/polyfill": "^1.4.4", "htm": "^3.1.1" }, "peerDependencies": { "@preact/signals-core": "^1.3.0" } }, "sha512-h8OO2NRns2paXO/q5hkfXrwlZKq7oKj9XedGosi7J8OP3+aW7N2Gv4MBBVVQGCfOiZPkOj5m3sQH7FdyUWl7PQ=="],
@@ -1681,6 +1793,8 @@
"@remote-dom/react": ["@remote-dom/react@1.2.2", "", { "dependencies": { "@remote-dom/core": "^1.7.0", "@types/react": "^18.0.0", "htm": "^3.1.1" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0" } }, "sha512-PkvioODONTr1M0StGDYsR4Ssf5M0Rd4+IlWVvVoK3Zrw8nr7+5mJkgNofaj/z7i8Aep78L28PCW8/WduUt4unA=="],
+ "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.3", "", {}, "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q=="],
+
"@rollup/plugin-alias": ["@rollup/plugin-alias@5.1.0", "", { "dependencies": { "slash": "^4.0.0" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" } }, "sha512-lpA3RZ9PdIG7qqhEfv79tBffNaoDuukFDrmhLqg9ifv99u/ehn+lOg30x2zmhf8AQqQUZaMk/B9fZraQ6/acDQ=="],
"@rollup/plugin-babel": ["@rollup/plugin-babel@5.3.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.10.4", "@rollup/pluginutils": "^3.1.0" }, "peerDependencies": { "@babel/core": "^7.0.0", "@types/babel__core": "^7.1.9", "rollup": "^1.20.0||^2.0.0" } }, "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q=="],
@@ -1701,155 +1815,171 @@
"@rollup/pluginutils": ["@rollup/pluginutils@5.1.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^2.3.1" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" } }, "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g=="],
- "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.37.0", "", { "os": "android", "cpu": "arm" }, "sha512-l7StVw6WAa8l3vA1ov80jyetOAEo1FtHvZDbzXDO/02Sq/QVvqlHkYoFwDJPIMj0GKiistsBudfx5tGFnwYWDQ=="],
+ "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.59.0", "", { "os": "android", "cpu": "arm" }, "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg=="],
- "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.37.0", "", { "os": "android", "cpu": "arm64" }, "sha512-6U3SlVyMxezt8Y+/iEBcbp945uZjJwjZimu76xoG7tO1av9VO691z8PkhzQ85ith2I8R2RddEPeSfcbyPfD4hA=="],
+ "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.59.0", "", { "os": "android", "cpu": "arm64" }, "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q=="],
- "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.37.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-+iTQ5YHuGmPt10NTzEyMPbayiNTcOZDWsbxZYR1ZnmLnZxG17ivrPSWFO9j6GalY0+gV3Jtwrrs12DBscxnlYA=="],
+ "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.59.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg=="],
- "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.37.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-m8W2UbxLDcmRKVjgl5J/k4B8d7qX2EcJve3Sut7YGrQoPtCIQGPH5AMzuFvYRWZi0FVS0zEY4c8uttPfX6bwYQ=="],
+ "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.59.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w=="],
- "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.37.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-FOMXGmH15OmtQWEt174v9P1JqqhlgYge/bUjIbiVD1nI1NeJ30HYT9SJlZMqdo1uQFyt9cz748F1BHghWaDnVA=="],
+ "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.59.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA=="],
- "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.37.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SZMxNttjPKvV14Hjck5t70xS3l63sbVwl98g3FlVVx2YIDmfUIy29jQrsw06ewEYQ8lQSuY9mpAPlmgRD2iSsA=="],
+ "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.59.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg=="],
- "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.37.0", "", { "os": "linux", "cpu": "arm" }, "sha512-hhAALKJPidCwZcj+g+iN+38SIOkhK2a9bqtJR+EtyxrKKSt1ynCBeqrQy31z0oWU6thRZzdx53hVgEbRkuI19w=="],
+ "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw=="],
- "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.37.0", "", { "os": "linux", "cpu": "arm" }, "sha512-jUb/kmn/Gd8epbHKEqkRAxq5c2EwRt0DqhSGWjPFxLeFvldFdHQs/n8lQ9x85oAeVb6bHcS8irhTJX2FCOd8Ag=="],
+ "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA=="],
- "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.37.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-oNrJxcQT9IcbcmKlkF+Yz2tmOxZgG9D9GRq+1OE6XCQwCVwxixYAa38Z8qqPzQvzt1FCfmrHX03E0pWoXm1DqA=="],
+ "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA=="],
- "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.37.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-pfxLBMls+28Ey2enpX3JvjEjaJMBX5XlPCZNGxj4kdJyHduPBXtxYeb8alo0a7bqOoWZW2uKynhHxF/MWoHaGQ=="],
+ "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA=="],
+
+ "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg=="],
+
+ "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q=="],
"@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.37.0", "", { "os": "linux", "cpu": "none" }, "sha512-yCE0NnutTC/7IGUq/PUHmoeZbIwq3KRh02e9SfFh7Vmc1Z7atuJRYWhRME5fKgT8aS20mwi1RyChA23qSyRGpA=="],
"@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.37.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NxcICptHk06E2Lh3a4Pu+2PEdZ6ahNHuK7o6Np9zcWkrBMuv21j10SQDJW3C9Yf/A/P7cutWoC/DptNLVsZ0VQ=="],
- "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.37.0", "", { "os": "linux", "cpu": "none" }, "sha512-PpWwHMPCVpFZLTfLq7EWJWvrmEuLdGn1GMYcm5MV7PaRgwCEYJAwiN94uBuZev0/J/hFIIJCsYw4nLmXA9J7Pw=="],
+ "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA=="],
- "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.37.0", "", { "os": "linux", "cpu": "none" }, "sha512-DTNwl6a3CfhGTAOYZ4KtYbdS8b+275LSLqJVJIrPa5/JuIufWWZ/QFvkxp52gpmguN95eujrM68ZG+zVxa8zHA=="],
+ "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA=="],
- "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.37.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-hZDDU5fgWvDdHFuExN1gBOhCuzo/8TMpidfOR+1cPZJflcEzXdCy1LjnklQdW8/Et9sryOPJAKAQRw8Jq7Tg+A=="],
+ "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg=="],
- "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.37.0", "", { "os": "linux", "cpu": "x64" }, "sha512-pKivGpgJM5g8dwj0ywBwe/HeVAUSuVVJhUTa/URXjxvoyTT/AxsLTAbkHkDHG7qQxLoW2s3apEIl26uUe08LVQ=="],
+ "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg=="],
- "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.37.0", "", { "os": "linux", "cpu": "x64" }, "sha512-E2lPrLKE8sQbY/2bEkVTGDEk4/49UYRVWgj90MY8yPjpnGBQ+Xi1Qnr7b7UIWw1NOggdFQFOLZ8+5CzCiz143w=="],
+ "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.59.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w=="],
- "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.37.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Jm7biMazjNzTU4PrQtr7VS8ibeys9Pn29/1bm4ph7CP2kf21950LgN+BaE2mJ1QujnvOc6p54eWWiVvn05SOBg=="],
+ "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg=="],
- "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.37.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-e3/1SFm1OjefWICB2Ucstg2dxYDkDTZGDYgwufcbsxTHyqQps1UQf33dFEChBNmeSsTOyrjw2JJq0zbG5GF6RA=="],
+ "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg=="],
- "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.37.0", "", { "os": "win32", "cpu": "x64" }, "sha512-LWbXUBwn/bcLx2sSsqy7pK5o+Nr+VCoRoAohfJ5C/aBio9nfJmGQqHAhU6pwxV/RmyTk5AqdySma7uwWGlmeuA=="],
+ "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.59.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ=="],
+
+ "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.59.0", "", { "os": "none", "cpu": "arm64" }, "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA=="],
+
+ "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.59.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A=="],
+
+ "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.59.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA=="],
+
+ "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA=="],
+
+ "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA=="],
"@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="],
+ "@scarf/scarf": ["@scarf/scarf@1.4.0", "", {}, "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ=="],
+
"@sinclair/typebox": ["@sinclair/typebox@0.34.41", "", {}, "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g=="],
"@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="],
- "@sinonjs/fake-timers": ["@sinonjs/fake-timers@10.3.0", "", { "dependencies": { "@sinonjs/commons": "^3.0.0" } }, "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA=="],
+ "@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="],
- "@smithy/abort-controller": ["@smithy/abort-controller@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-P7JD4J+wxHMpGxqIg6SHno2tPkZbBUBLbPpR5/T1DEUvw/mEaINBMaPFZNM7lA+ToSCZ36j6nMHa+5kej+fhGg=="],
+ "@smithy/abort-controller": ["@smithy/abort-controller@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-Hj4WoYWMJnSpM6/kchsm4bUNTL9XiSyhvoMb2KIq4VJzyDt7JpGHUZHkVNPZVC7YE1tf8tPeVauxpFBKGW4/KQ=="],
- "@smithy/chunked-blob-reader": ["@smithy/chunked-blob-reader@5.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw=="],
+ "@smithy/chunked-blob-reader": ["@smithy/chunked-blob-reader@5.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-St+kVicSyayWQca+I1rGitaOEH6uKgE8IUWoYnnEX26SWdWQcL6LvMSD19Lg+vYHKdT9B2Zuu7rd3i6Wnyb/iw=="],
- "@smithy/chunked-blob-reader-native": ["@smithy/chunked-blob-reader-native@4.0.0", "", { "dependencies": { "@smithy/util-base64": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-R9wM2yPmfEMsUmlMlIgSzOyICs0x9uu7UTHoccMyt7BWw8shcGM8HqB355+BZCPBcySvbTYMs62EgEQkNxz2ig=="],
+ "@smithy/chunked-blob-reader-native": ["@smithy/chunked-blob-reader-native@4.2.3", "", { "dependencies": { "@smithy/util-base64": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-jA5k5Udn7Y5717L86h4EIv06wIr3xn8GM1qHRi/Nf31annXcXHJjBKvgztnbn2TxH3xWrPBfgwHsOwZf0UmQWw=="],
- "@smithy/config-resolver": ["@smithy/config-resolver@4.0.1", "", { "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/util-config-provider": "^4.0.0", "@smithy/util-middleware": "^4.0.1", "tslib": "^2.6.2" } }, "sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ=="],
+ "@smithy/config-resolver": ["@smithy/config-resolver@4.4.10", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "@smithy/util-config-provider": "^4.2.2", "@smithy/util-endpoints": "^3.3.2", "@smithy/util-middleware": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-IRTkd6ps0ru+lTWnfnsbXzW80A8Od8p3pYiZnW98K2Hb20rqfsX7VTlfUwhrcOeSSy68Gn9WBofwPuw3e5CCsg=="],
- "@smithy/core": ["@smithy/core@3.1.5", "", { "dependencies": { "@smithy/middleware-serde": "^4.0.2", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-middleware": "^4.0.1", "@smithy/util-stream": "^4.1.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-HLclGWPkCsekQgsyzxLhCQLa8THWXtB5PxyYN+2O6nkyLt550KQKTlbV2D1/j5dNIQapAZM1+qFnpBFxZQkgCA=="],
+ "@smithy/core": ["@smithy/core@3.23.9", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.12", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-stream": "^4.5.17", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-1Vcut4LEL9HZsdpI0vFiRYIsaoPwZLjAxnVQDUMQK8beMS+EYPLDQCXtbzfxmM5GzSgjfe2Q9M7WaXwIMQllyQ=="],
"@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@3.2.0", "", { "dependencies": { "@smithy/node-config-provider": "^3.1.4", "@smithy/property-provider": "^3.1.3", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "tslib": "^2.6.2" } }, "sha512-0SCIzgd8LYZ9EJxUjLXBmEKSZR/P/w6l7Rz/pab9culE/RWuqelAKGJvn5qUOl8BgX8Yj5HWM50A5hiB/RzsgA=="],
- "@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.6", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.10.0", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-OZfsI+YRG26XZik/jKMMg37acnBSbUiK/8nETW3uM3mLj+0tMmFXdHQw1e5WEd/IHN8BGOh3te91SNDe2o4RHg=="],
+ "@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.11", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.13.0", "@smithy/util-hex-encoding": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-Sf39Ml0iVX+ba/bgMPxaXWAAFmHqYLTmbjAPfLPLY8CrYkRDEqZdUsKC1OwVMCdJXfAt0v4j49GIJ8DoSYAe6w=="],
- "@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.4", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-d5T7ZS3J/r8P/PDjgmCcutmNxnSRvPH1U6iHeXjzI50sMr78GLmFcrczLw33Ap92oEKqa4CLrkAPeSSOqvGdUA=="],
+ "@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.11", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-3rEpo3G6f/nRS7fQDsZmxw/ius6rnlIpz4UX6FlALEzz8JoSxFmdBt0SZnthis+km7sQo6q5/3e+UJcuQivoXA=="],
- "@smithy/eventstream-serde-config-resolver": ["@smithy/eventstream-serde-config-resolver@4.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-lxfDT0UuSc1HqltOGsTEAlZ6H29gpfDSdEPTapD5G63RbnYToZ+ezjzdonCCH90j5tRRCw3aLXVbiZaBW3VRVg=="],
+ "@smithy/eventstream-serde-config-resolver": ["@smithy/eventstream-serde-config-resolver@4.3.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-XeNIA8tcP/GDWnnKkO7qEm/bg0B/bP9lvIXZBXcGZwZ+VYM8h8k9wuDvUODtdQ2Wcp2RcBkPTCSMmaniVHrMlA=="],
- "@smithy/eventstream-serde-node": ["@smithy/eventstream-serde-node@4.2.4", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-TPhiGByWnYyzcpU/K3pO5V7QgtXYpE0NaJPEZBCa1Y5jlw5SjqzMSbFiLb+ZkJhqoQc0ImGyVINqnq1ze0ZRcQ=="],
+ "@smithy/eventstream-serde-node": ["@smithy/eventstream-serde-node@4.2.11", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-fzbCh18rscBDTQSCrsp1fGcclLNF//nJyhjldsEl/5wCYmgpHblv5JSppQAyQI24lClsFT0wV06N1Porn0IsEw=="],
- "@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.4", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GNI/IXaY/XBB1SkGBFmbW033uWA0tj085eCxYih0eccUe/PFR7+UBQv9HNDk2fD9TJu7UVsCWsH99TkpEPSOzQ=="],
+ "@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.11", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-MJ7HcI+jEkqoWT5vp+uoVaAjBrmxBtKhZTeynDRG/seEjJfqyg3SiqMMqyPnAMzmIfLaeJ/uiuSDP/l9AnMy/Q=="],
- "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.0.1", "", { "dependencies": { "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA=="],
+ "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.13", "", { "dependencies": { "@smithy/protocol-http": "^5.3.11", "@smithy/querystring-builder": "^4.2.11", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-U2Hcfl2s3XaYjikN9cT4mPu8ybDbImV3baXR0PkVlC0TTx808bRP3FaPGAzPtB8OByI+JqJ1kyS+7GEgae7+qQ=="],
- "@smithy/hash-blob-browser": ["@smithy/hash-blob-browser@4.0.1", "", { "dependencies": { "@smithy/chunked-blob-reader": "^5.0.0", "@smithy/chunked-blob-reader-native": "^4.0.0", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-rkFIrQOKZGS6i1D3gKJ8skJ0RlXqDvb1IyAphksaFOMzkn3v3I1eJ8m7OkLj0jf1McP63rcCEoLlkAn/HjcTRw=="],
+ "@smithy/hash-blob-browser": ["@smithy/hash-blob-browser@4.2.12", "", { "dependencies": { "@smithy/chunked-blob-reader": "^5.2.2", "@smithy/chunked-blob-reader-native": "^4.2.3", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-1wQE33DsxkM/waftAhCH9VtJbUGyt1PJ9YRDpOu+q9FUi73LLFUZ2fD8A61g2mT1UY9k7b99+V1xZ41Rz4SHRQ=="],
- "@smithy/hash-node": ["@smithy/hash-node@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-TJ6oZS+3r2Xu4emVse1YPB3Dq3d8RkZDKcPr71Nj/lJsdAP1c7oFzYqEn1IBc915TsgLl2xIJNuxCz+gLbLE0w=="],
+ "@smithy/hash-node": ["@smithy/hash-node@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-T+p1pNynRkydpdL015ruIoyPSRw9e/SQOWmSAMmmprfswMrd5Ow5igOWNVlvyVFZlxXqGmyH3NQwfwy8r5Jx0A=="],
- "@smithy/hash-stream-node": ["@smithy/hash-stream-node@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-U1rAE1fxmReCIr6D2o/4ROqAQX+GffZpyMt3d7njtGDr2pUNmAKRWa49gsNVhCh2vVAuf3wXzWwNr2YN8PAXIw=="],
+ "@smithy/hash-stream-node": ["@smithy/hash-stream-node@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-hQsTjwPCRY8w9GK07w1RqJi3e+myh0UaOWBBhZ1UMSDgofH/Q1fEYzU1teaX6HkpX/eWDdm7tAGR0jBPlz9QEQ=="],
- "@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-gdudFPf4QRQ5pzj7HEnu6FhKRi61BfH/Gk5Yf6O0KiSbr1LlVhgjThcvjdu658VE6Nve8vaIWB8/fodmS1rBPQ=="],
+ "@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-cGNMrgykRmddrNhYy1yBdrp5GwIgEkniS7k9O1VLB38yxQtlvrxpZtUVvo6T4cKpeZsriukBuuxfJcdZQc/f/g=="],
- "@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
+ "@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow=="],
- "@smithy/md5-js": ["@smithy/md5-js@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-HLZ647L27APi6zXkZlzSFZIjpo8po45YiyjMGJZM3gyDY8n7dPGdmxIIljLm4gPt/7rRvutLTTkYJpZVfG5r+A=="],
+ "@smithy/md5-js": ["@smithy/md5-js@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-350X4kGIrty0Snx2OWv7rPM6p6vM7RzryvFs6B/56Cux3w3sChOb3bymo5oidXJlPcP9fIRxGUCk7GqpiSOtng=="],
- "@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.0.1", "", { "dependencies": { "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ=="],
+ "@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.11", "", { "dependencies": { "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-UvIfKYAKhCzr4p6jFevPlKhQwyQwlJ6IeKLDhmV1PlYfcW3RL4ROjNEDtSik4NYMi9kDkH7eSwyTP3vNJ/u/Dw=="],
- "@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.0.6", "", { "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-serde": "^4.0.2", "@smithy/node-config-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-middleware": "^4.0.1", "tslib": "^2.6.2" } }, "sha512-ftpmkTHIFqgaFugcjzLZv3kzPEFsBFSnq1JsIkr2mwFzCraZVhQk2gqN51OOeRxqhbPTkRFj39Qd2V91E/mQxg=="],
+ "@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.23", "", { "dependencies": { "@smithy/core": "^3.23.9", "@smithy/middleware-serde": "^4.2.12", "@smithy/node-config-provider": "^4.3.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-middleware": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-UEFIejZy54T1EJn2aWJ45voB7RP2T+IRzUqocIdM6GFFa5ClZncakYJfcYnoXt3UsQrZZ9ZRauGm77l9UCbBLw=="],
- "@smithy/middleware-retry": ["@smithy/middleware-retry@4.0.7", "", { "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/service-error-classification": "^4.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/util-middleware": "^4.0.1", "@smithy/util-retry": "^4.0.1", "tslib": "^2.6.2", "uuid": "^9.0.1" } }, "sha512-58j9XbUPLkqAcV1kHzVX/kAR16GT+j7DUZJqwzsxh1jtz7G82caZiGyyFgUvogVfNTg3TeAOIJepGc8TXF4AVQ=="],
+ "@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.40", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.11", "@smithy/protocol-http": "^5.3.11", "@smithy/service-error-classification": "^4.2.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/util-middleware": "^4.2.11", "@smithy/util-retry": "^4.2.11", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-YhEMakG1Ae57FajERdHNZ4ShOPIY7DsgV+ZoAxo/5BT0KIe+f6DDU2rtIymNNFIj22NJfeeI6LWIifrwM0f+rA=="],
- "@smithy/middleware-serde": ["@smithy/middleware-serde@4.0.2", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ=="],
+ "@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-W9g1bOLui7Xn5FABRVS0o3rXL0gfN37d/8I/W7i0N7oxjx9QecUmXEMSUMADTODwdtka9cN43t5BI2CodLJpng=="],
- "@smithy/middleware-stack": ["@smithy/middleware-stack@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA=="],
+ "@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-s+eenEPW6RgliDk2IhjD2hWOxIx1NKrOHxEwNUaUXxYBxIyCcDfNULZ2Mu15E3kwcJWBedTET/kEASPV1A1Akg=="],
- "@smithy/node-config-provider": ["@smithy/node-config-provider@4.0.1", "", { "dependencies": { "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ=="],
+ "@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.11", "", { "dependencies": { "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-xD17eE7kaLgBBGf5CZQ58hh2YmwK1Z0O8YhffwB/De2jsL0U3JklmhVYJ9Uf37OtUDLF2gsW40Xwwag9U869Gg=="],
- "@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.6", "", { "dependencies": { "@smithy/abort-controller": "^4.2.6", "@smithy/protocol-http": "^5.3.6", "@smithy/querystring-builder": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-Gsb9jf4ido5BhPfani4ggyrKDd3ZK+vTFWmUaZeFg5G3E5nhFmqiTzAIbHqmPs1sARuJawDiGMGR/nY+Gw6+aQ=="],
+ "@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.14", "", { "dependencies": { "@smithy/abort-controller": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/querystring-builder": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-DamSqaU8nuk0xTJDrYnRzZndHwwRnyj/n/+RqGGCcBKB4qrQem0mSDiWdupaNWdwxzyMU91qxDmHOCazfhtO3A=="],
"@smithy/property-provider": ["@smithy/property-provider@3.1.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g=="],
- "@smithy/protocol-http": ["@smithy/protocol-http@5.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw=="],
+ "@smithy/protocol-http": ["@smithy/protocol-http@5.3.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hI+barOVDJBkNt4y0L2mu3Ugc0w7+BpJ2CZuLwXtSltGAAwCb3IvnalGlbDV/UCS6a9ZuT3+exd1WxNdLb5IlQ=="],
- "@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-MeM9fTAiD3HvoInK/aA8mgJaKQDvm8N0dKy6EiFaCfgpovQr4CaOkJC28XqlSRABM+sHdSQXbC8NZ0DShBMHqg=="],
+ "@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "@smithy/util-uri-escape": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-7spdikrYiljpket6u0up2Ck2mxhy7dZ0+TDd+S53Dg2DHd6wg+YNJrTCHiLdgZmEXZKI7LJZcwL3721ZRDFiqA=="],
- "@smithy/querystring-parser": ["@smithy/querystring-parser@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw=="],
+ "@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-nE3IRNjDltvGcoThD2abTozI1dkSy8aX+a2N1Rs55en5UsdyyIXgGEmevUL3okZFoJC77JgRGe99xYohhsjivQ=="],
- "@smithy/service-error-classification": ["@smithy/service-error-classification@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0" } }, "sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA=="],
+ "@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0" } }, "sha512-HkMFJZJUhzU3HvND1+Yw/kYWXp4RPDLBWLcK1n+Vqw8xn4y2YiBhdww8IxhkQjP/QlZun5bwm3vcHc8AqIU3zw=="],
- "@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw=="],
+ "@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.6", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-IB/M5I8G0EeXZTHsAxpx51tMQ5R719F3aq+fjEB6VtNcCHDc0ajFDIGDZw+FW9GxtEkgTduiPpjveJdA/CX7sw=="],
- "@smithy/signature-v4": ["@smithy/signature-v4@5.3.4", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ScDCpasxH7w1HXHYbtk3jcivjvdA1VICyAdgvVqKhKKwxi+MTwZEqFw0minE+oZ7F07oF25xh4FGJxgqgShz0A=="],
+ "@smithy/signature-v4": ["@smithy/signature-v4@5.3.11", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.2", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-uri-escape": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-V1L6N9aKOBAN4wEHLyqjLBnAz13mtILU0SeDrjOaIZEeN6IFa6DxwRt1NNpOdmSpQUfkBj0qeD3m6P77uzMhgQ=="],
- "@smithy/smithy-client": ["@smithy/smithy-client@4.1.6", "", { "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/middleware-stack": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-stream": "^4.1.2", "tslib": "^2.6.2" } }, "sha512-UYDolNg6h2O0L+cJjtgSyKKvEKCOa/8FHYJnBobyeoeWDmNpXjwOAtw16ezyeu1ETuuLEOZbrynK0ZY1Lx9Jbw=="],
+ "@smithy/smithy-client": ["@smithy/smithy-client@4.12.3", "", { "dependencies": { "@smithy/core": "^3.23.9", "@smithy/middleware-endpoint": "^4.4.23", "@smithy/middleware-stack": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-stream": "^4.5.17", "tslib": "^2.6.2" } }, "sha512-7k4UxjSpHmPN2AxVhvIazRSzFQjWnud3sOsXcFStzagww17j1cFQYqTSiQ8xuYK3vKLR1Ni8FzuT3VlKr3xCNw=="],
- "@smithy/types": ["@smithy/types@4.8.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-N0Zn0OT1zc+NA+UVfkYqQzviRh5ucWwO7mBV3TmHHprMnfcJNfhlPicDkBHi0ewbh+y3evR6cNAW0Raxvb01NA=="],
+ "@smithy/types": ["@smithy/types@4.13.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw=="],
- "@smithy/url-parser": ["@smithy/url-parser@4.0.1", "", { "dependencies": { "@smithy/querystring-parser": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g=="],
+ "@smithy/url-parser": ["@smithy/url-parser@4.2.11", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-oTAGGHo8ZYc5VZsBREzuf5lf2pAurJQsccMusVZ85wDkX66ojEc/XauiGjzCj50A61ObFTPe6d7Pyt6UBYaing=="],
- "@smithy/util-base64": ["@smithy/util-base64@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg=="],
+ "@smithy/util-base64": ["@smithy/util-base64@4.3.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-XRH6b0H/5A3SgblmMa5ErXQ2XKhfbQB+Fm/oyLZ2O2kCUrwgg55bU0RekmzAhuwOjA9qdN5VU2BprOvGGUkOOQ=="],
- "@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA=="],
+ "@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-JKCrLNOup3OOgmzeaKQwi4ZCTWlYR5H4Gm1r2uTMVBXoemo1UEghk5vtMi1xSu2ymgKVGW631e2fp9/R610ZjQ=="],
- "@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg=="],
+ "@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.3", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-ZkJGvqBzMHVHE7r/hcuCxlTY8pQr1kMtdsVPs7ex4mMU+EAbcXppfo5NmyxMYi2XU49eqaz56j2gsk4dHHPG/g=="],
- "@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
+ "@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.2", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-FDXD7cvUoFWwN6vtQfEta540Y/YBe5JneK3SoZg9bThSoOAC/eGeYEua6RkBgKjGa/sz6Y+DuBZj3+YEY21y4Q=="],
- "@smithy/util-config-provider": ["@smithy/util-config-provider@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w=="],
+ "@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ=="],
- "@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.0.7", "", { "dependencies": { "@smithy/property-provider": "^4.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-CZgDDrYHLv0RUElOsmZtAnp1pIjwDVCSuZWOPhIOBvG36RDfX1Q9+6lS61xBf+qqvHoqRjHxgINeQz47cYFC2Q=="],
+ "@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.39", "", { "dependencies": { "@smithy/property-provider": "^4.2.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-ui7/Ho/+VHqS7Km2wBw4/Ab4RktoiSshgcgpJzC4keFPs6tLJS4IQwbeahxQS3E/w98uq6E1mirCH/id9xIXeQ=="],
- "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.0.7", "", { "dependencies": { "@smithy/config-resolver": "^4.0.1", "@smithy/credential-provider-imds": "^4.0.1", "@smithy/node-config-provider": "^4.0.1", "@smithy/property-provider": "^4.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-79fQW3hnfCdrfIi1soPbK3zmooRFnLpSx3Vxi6nUlqaaQeC5dm8plt4OTNDNqEEEDkvKghZSaoti684dQFVrGQ=="],
+ "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.42", "", { "dependencies": { "@smithy/config-resolver": "^4.4.10", "@smithy/credential-provider-imds": "^4.2.11", "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-QDA84CWNe8Akpj15ofLO+1N3Rfg8qa2K5uX0y6HnOp4AnRYRgWrKx/xzbYNbVF9ZsyJUYOfcoaN3y93wA/QJ2A=="],
- "@smithy/util-endpoints": ["@smithy/util-endpoints@3.0.1", "", { "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-zVdUENQpdtn9jbpD9SCFK4+aSiavRb9BxEtw9ZGUR1TYo6bBHbIoi7VkrFQ0/RwZlzx0wRBaRmPclj8iAoJCLA=="],
+ "@smithy/util-endpoints": ["@smithy/util-endpoints@3.3.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-+4HFLpE5u29AbFlTdlKIT7jfOzZ8PDYZKTb3e+AgLz986OYwqTourQ5H+jg79/66DB69Un1+qKecLnkZdAsYcA=="],
- "@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+ "@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Qcz3W5vuHK4sLQdyT93k/rfrUwdJ8/HZ+nMUOyGdpeGA1Wxt65zYwi3oEl9kOM+RswvYq90fzkNDahPS8K0OIg=="],
- "@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
+ "@smithy/util-middleware": ["@smithy/util-middleware@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-r3dtF9F+TpSZUxpOVVtPfk09Rlo4lT6ORBqEvX3IBT6SkQAdDSVKR5GcfmZbtl7WKhKnmb3wbDTQ6ibR2XHClw=="],
- "@smithy/util-retry": ["@smithy/util-retry@4.0.1", "", { "dependencies": { "@smithy/service-error-classification": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw=="],
+ "@smithy/util-retry": ["@smithy/util-retry@4.2.11", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-XSZULmL5x6aCTTii59wJqKsY1l3eMIAomRAccW7Tzh9r8s7T/7rdo03oektuH5jeYRlJMPcNP92EuRDvk9aXbw=="],
- "@smithy/util-stream": ["@smithy/util-stream@4.1.2", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-hex-encoding": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw=="],
+ "@smithy/util-stream": ["@smithy/util-stream@4.5.17", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.13", "@smithy/node-http-handler": "^4.4.14", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-793BYZ4h2JAQkNHcEnyFxDTcZbm9bVybD0UV/LEWmZ5bkTms7JqjfrLMi2Qy0E5WFcCzLwCAPgcvcvxoeALbAQ=="],
- "@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+ "@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-2kAStBlvq+lTXHyAZYfJRb/DfS3rsinLiwb+69SstC9Vb0s9vNWkRwpnj918Pfi85mzi42sOqdV72OLxWAISnw=="],
- "@smithy/util-utf8": ["@smithy/util-utf8@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow=="],
+ "@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
- "@smithy/util-waiter": ["@smithy/util-waiter@4.0.6", "", { "dependencies": { "@smithy/abort-controller": "^4.0.4", "@smithy/types": "^4.3.1", "tslib": "^2.6.2" } }, "sha512-slcr1wdRbX7NFphXZOxtxRNA7hXAAtJAXJDE/wdoMAos27SIquVCKiSqfB6/28YzQ8FCsB5NKkhdM5gMADbqxg=="],
+ "@smithy/util-waiter": ["@smithy/util-waiter@4.2.11", "", { "dependencies": { "@smithy/abort-controller": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-x7Rh2azQPs3XxbvCzcttRErKKvLnbZfqRf/gOjw2pb+ZscX88e5UkRPCB67bVnsFHxayvMvmePfKTqsRb+is1A=="],
- "@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+ "@smithy/uuid": ["@smithy/uuid@1.1.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g=="],
"@stitches/core": ["@stitches/core@1.2.8", "", {}, "sha512-Gfkvwk9o9kE9r9XNBmJRfV8zONvXThnm1tcuojL04Uy5uRyqg93DC83lDebl0rocZCfKSjUv+fWYtMQmEDJldg=="],
@@ -1881,12 +2011,10 @@
"@testing-library/user-event": ["@testing-library/user-event@14.5.2", "", { "peerDependencies": { "@testing-library/dom": ">=7.21.4" } }, "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ=="],
+ "@tokenizer/inflate": ["@tokenizer/inflate@0.4.1", "", { "dependencies": { "debug": "^4.4.3", "token-types": "^6.1.1" } }, "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA=="],
+
"@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
- "@tootallnate/once": ["@tootallnate/once@2.0.0", "", {}, "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A=="],
-
- "@trysound/sax": ["@trysound/sax@0.2.0", "", {}, "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA=="],
-
"@tsconfig/node10": ["@tsconfig/node10@1.0.11", "", {}, "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw=="],
"@tsconfig/node12": ["@tsconfig/node12@1.0.11", "", {}, "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag=="],
@@ -1913,9 +2041,69 @@
"@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="],
- "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
+ "@types/d3": ["@types/d3@7.4.3", "", { "dependencies": { "@types/d3-array": "*", "@types/d3-axis": "*", "@types/d3-brush": "*", "@types/d3-chord": "*", "@types/d3-color": "*", "@types/d3-contour": "*", "@types/d3-delaunay": "*", "@types/d3-dispatch": "*", "@types/d3-drag": "*", "@types/d3-dsv": "*", "@types/d3-ease": "*", "@types/d3-fetch": "*", "@types/d3-force": "*", "@types/d3-format": "*", "@types/d3-geo": "*", "@types/d3-hierarchy": "*", "@types/d3-interpolate": "*", "@types/d3-path": "*", "@types/d3-polygon": "*", "@types/d3-quadtree": "*", "@types/d3-random": "*", "@types/d3-scale": "*", "@types/d3-scale-chromatic": "*", "@types/d3-selection": "*", "@types/d3-shape": "*", "@types/d3-time": "*", "@types/d3-time-format": "*", "@types/d3-timer": "*", "@types/d3-transition": "*", "@types/d3-zoom": "*" } }, "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww=="],
- "@types/diff": ["@types/diff@6.0.0", "", {}, "sha512-dhVCYGv3ZSbzmQaBSagrv1WJ6rXCdkyTcDyoNu1MD8JohI7pR7k8wdZEm+mvdxRKXyHVwckFzWU1vJc+Z29MlA=="],
+ "@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="],
+
+ "@types/d3-axis": ["@types/d3-axis@3.0.6", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw=="],
+
+ "@types/d3-brush": ["@types/d3-brush@3.0.6", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A=="],
+
+ "@types/d3-chord": ["@types/d3-chord@3.0.6", "", {}, "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg=="],
+
+ "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="],
+
+ "@types/d3-contour": ["@types/d3-contour@3.0.6", "", { "dependencies": { "@types/d3-array": "*", "@types/geojson": "*" } }, "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg=="],
+
+ "@types/d3-delaunay": ["@types/d3-delaunay@6.0.4", "", {}, "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw=="],
+
+ "@types/d3-dispatch": ["@types/d3-dispatch@3.0.7", "", {}, "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA=="],
+
+ "@types/d3-drag": ["@types/d3-drag@3.0.7", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ=="],
+
+ "@types/d3-dsv": ["@types/d3-dsv@3.0.7", "", {}, "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g=="],
+
+ "@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="],
+
+ "@types/d3-fetch": ["@types/d3-fetch@3.0.7", "", { "dependencies": { "@types/d3-dsv": "*" } }, "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA=="],
+
+ "@types/d3-force": ["@types/d3-force@3.0.10", "", {}, "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw=="],
+
+ "@types/d3-format": ["@types/d3-format@3.0.4", "", {}, "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g=="],
+
+ "@types/d3-geo": ["@types/d3-geo@3.1.0", "", { "dependencies": { "@types/geojson": "*" } }, "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ=="],
+
+ "@types/d3-hierarchy": ["@types/d3-hierarchy@3.1.7", "", {}, "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg=="],
+
+ "@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "*" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="],
+
+ "@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="],
+
+ "@types/d3-polygon": ["@types/d3-polygon@3.0.2", "", {}, "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA=="],
+
+ "@types/d3-quadtree": ["@types/d3-quadtree@3.0.6", "", {}, "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg=="],
+
+ "@types/d3-random": ["@types/d3-random@3.0.3", "", {}, "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ=="],
+
+ "@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "*" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="],
+
+ "@types/d3-scale-chromatic": ["@types/d3-scale-chromatic@3.1.0", "", {}, "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ=="],
+
+ "@types/d3-selection": ["@types/d3-selection@3.0.11", "", {}, "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w=="],
+
+ "@types/d3-shape": ["@types/d3-shape@3.1.8", "", { "dependencies": { "@types/d3-path": "*" } }, "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w=="],
+
+ "@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="],
+
+ "@types/d3-time-format": ["@types/d3-time-format@4.0.3", "", {}, "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg=="],
+
+ "@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="],
+
+ "@types/d3-transition": ["@types/d3-transition@3.0.9", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg=="],
+
+ "@types/d3-zoom": ["@types/d3-zoom@3.0.8", "", { "dependencies": { "@types/d3-interpolate": "*", "@types/d3-selection": "*" } }, "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw=="],
+
+ "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
"@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="],
@@ -1927,6 +2115,8 @@
"@types/express-session": ["@types/express-session@1.18.2", "", { "dependencies": { "@types/express": "*" } }, "sha512-k+I0BxwVXsnEU2hV77cCobC08kIsn4y44C3gC0b46uxZVMaXA04lSPgRLR/bSL2w0t0ShJiG8o4jPzRG/nscFg=="],
+ "@types/geojson": ["@types/geojson@7946.0.16", "", {}, "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg=="],
+
"@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
"@types/http-errors": ["@types/http-errors@2.0.4", "", {}, "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA=="],
@@ -1965,7 +2155,7 @@
"@types/multer": ["@types/multer@1.4.13", "", { "dependencies": { "@types/express": "*" } }, "sha512-bhhdtPw7JqCiEfC9Jimx5LqX9BDIPJEh2q/fQ4bqbBPtyEZYr3cvF22NwG0DmPZNYA0CAf2CnqDB4KIGGpJcaw=="],
- "@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+ "@types/node": ["@types/node@20.19.37", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw=="],
"@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="],
@@ -2011,10 +2201,14 @@
"@types/webidl-conversions": ["@types/webidl-conversions@7.0.3", "", {}, "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA=="],
+ "@types/whatwg-mimetype": ["@types/whatwg-mimetype@3.0.2", "", {}, "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA=="],
+
"@types/whatwg-url": ["@types/whatwg-url@11.0.5", "", { "dependencies": { "@types/webidl-conversions": "*" } }, "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ=="],
"@types/winston": ["@types/winston@2.4.4", "", { "dependencies": { "winston": "*" } }, "sha512-BVGCztsypW8EYwJ+Hq+QNYiT/MUyCif0ouBH+flrY66O5W+KIXAMML6E/0fJpm7VjIzgangahl5S03bJJQGrZw=="],
+ "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
+
"@types/xml-encryption": ["@types/xml-encryption@1.2.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-I69K/WW1Dv7j6O3jh13z0X8sLWJRXbu5xnHDl9yHzUNDUBtUoBY058eb5s+x/WG6yZC1h8aKdI2EoyEPjyEh+Q=="],
"@types/xml2js": ["@types/xml2js@0.4.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ=="],
@@ -2039,6 +2233,8 @@
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.24.0", "", { "dependencies": { "@typescript-eslint/types": "8.24.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-kArLq83QxGLbuHrTMoOEWO+l2MwsNS2TGISEdx8xgqpkbytB07XmlQyQdNDrCc1ecSqx0cnmhGvpX+VBwqqSkg=="],
+ "@typespec/ts-http-runtime": ["@typespec/ts-http-runtime@0.3.4", "", { "dependencies": { "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "tslib": "^2.6.2" } }, "sha512-CI0NhTrz4EBaa0U+HaaUZrJhPoso8sG7ZFya8uQoBA57fjzrjRSv87ekCjLZOFExN+gXE/z0xuN2QfH4H2HrLQ=="],
+
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
"@unrs/resolver-binding-android-arm-eabi": ["@unrs/resolver-binding-android-arm-eabi@1.11.1", "", { "os": "android", "cpu": "arm" }, "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw=="],
@@ -2079,48 +2275,14 @@
"@unrs/resolver-binding-win32-x64-msvc": ["@unrs/resolver-binding-win32-x64-msvc@1.11.1", "", { "os": "win32", "cpu": "x64" }, "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g=="],
- "@vitejs/plugin-react": ["@vitejs/plugin-react@4.3.4", "", { "dependencies": { "@babel/core": "^7.26.0", "@babel/plugin-transform-react-jsx-self": "^7.25.9", "@babel/plugin-transform-react-jsx-source": "^7.25.9", "@types/babel__core": "^7.20.5", "react-refresh": "^0.14.2" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug=="],
+ "@upsetjs/venn.js": ["@upsetjs/venn.js@2.0.0", "", { "optionalDependencies": { "d3-selection": "^3.0.0", "d3-transition": "^3.0.1" } }, "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw=="],
- "@webassemblyjs/ast": ["@webassemblyjs/ast@1.12.1", "", { "dependencies": { "@webassemblyjs/helper-numbers": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg=="],
-
- "@webassemblyjs/floating-point-hex-parser": ["@webassemblyjs/floating-point-hex-parser@1.11.6", "", {}, "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw=="],
-
- "@webassemblyjs/helper-api-error": ["@webassemblyjs/helper-api-error@1.11.6", "", {}, "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q=="],
-
- "@webassemblyjs/helper-buffer": ["@webassemblyjs/helper-buffer@1.12.1", "", {}, "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw=="],
-
- "@webassemblyjs/helper-numbers": ["@webassemblyjs/helper-numbers@1.11.6", "", { "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.11.6", "@webassemblyjs/helper-api-error": "1.11.6", "@xtuc/long": "4.2.2" } }, "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g=="],
-
- "@webassemblyjs/helper-wasm-bytecode": ["@webassemblyjs/helper-wasm-bytecode@1.11.6", "", {}, "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA=="],
-
- "@webassemblyjs/helper-wasm-section": ["@webassemblyjs/helper-wasm-section@1.12.1", "", { "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", "@webassemblyjs/wasm-gen": "1.12.1" } }, "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g=="],
-
- "@webassemblyjs/ieee754": ["@webassemblyjs/ieee754@1.11.6", "", { "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg=="],
-
- "@webassemblyjs/leb128": ["@webassemblyjs/leb128@1.11.6", "", { "dependencies": { "@xtuc/long": "4.2.2" } }, "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ=="],
-
- "@webassemblyjs/utf8": ["@webassemblyjs/utf8@1.11.6", "", {}, "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA=="],
-
- "@webassemblyjs/wasm-edit": ["@webassemblyjs/wasm-edit@1.12.1", "", { "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", "@webassemblyjs/helper-wasm-section": "1.12.1", "@webassemblyjs/wasm-gen": "1.12.1", "@webassemblyjs/wasm-opt": "1.12.1", "@webassemblyjs/wasm-parser": "1.12.1", "@webassemblyjs/wast-printer": "1.12.1" } }, "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g=="],
-
- "@webassemblyjs/wasm-gen": ["@webassemblyjs/wasm-gen@1.12.1", "", { "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", "@webassemblyjs/ieee754": "1.11.6", "@webassemblyjs/leb128": "1.11.6", "@webassemblyjs/utf8": "1.11.6" } }, "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w=="],
-
- "@webassemblyjs/wasm-opt": ["@webassemblyjs/wasm-opt@1.12.1", "", { "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", "@webassemblyjs/wasm-gen": "1.12.1", "@webassemblyjs/wasm-parser": "1.12.1" } }, "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg=="],
-
- "@webassemblyjs/wasm-parser": ["@webassemblyjs/wasm-parser@1.12.1", "", { "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-api-error": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", "@webassemblyjs/ieee754": "1.11.6", "@webassemblyjs/leb128": "1.11.6", "@webassemblyjs/utf8": "1.11.6" } }, "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ=="],
-
- "@webassemblyjs/wast-printer": ["@webassemblyjs/wast-printer@1.12.1", "", { "dependencies": { "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" } }, "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA=="],
+ "@vitejs/plugin-react": ["@vitejs/plugin-react@5.1.4", "", { "dependencies": { "@babel/core": "^7.29.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-rc.3", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA=="],
"@xmldom/is-dom-node": ["@xmldom/is-dom-node@1.0.1", "", {}, "sha512-CJDxIgE5I0FH+ttq/Fxy6nRpxP70+e2O048EPe85J2use3XKdatVM7dDVvFNjQudd9B49NPoZ+8PG49zj4Er8Q=="],
"@xmldom/xmldom": ["@xmldom/xmldom@0.8.10", "", {}, "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw=="],
- "@xtuc/ieee754": ["@xtuc/ieee754@1.2.0", "", {}, "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA=="],
-
- "@xtuc/long": ["@xtuc/long@4.2.2", "", {}, "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="],
-
- "abab": ["abab@2.0.6", "", {}, "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA=="],
-
"abbrev": ["abbrev@1.1.1", "", {}, "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="],
"abstract-logging": ["abstract-logging@2.0.1", "", {}, "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA=="],
@@ -2129,8 +2291,6 @@
"acorn": ["acorn@8.15.0", "", { "bin": "bin/acorn" }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
- "acorn-globals": ["acorn-globals@7.0.1", "", { "dependencies": { "acorn": "^8.1.0", "acorn-walk": "^8.0.2" } }, "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q=="],
-
"acorn-import-attributes": ["acorn-import-attributes@1.9.5", "", { "peerDependencies": { "acorn": "^8" } }, "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ=="],
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
@@ -2139,12 +2299,12 @@
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
- "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
+ "ai-tokenizer": ["ai-tokenizer@1.0.6", "", { "peerDependencies": { "ai": "^5.0.0" }, "optionalPeers": ["ai"] }, "sha512-GaakQFxen0pRH/HIA4v68ZM40llCH27HUYUSBLK+gVuZ57e53pYJe1xFvSTj4sJJjbWU92m1X6NjPWyeWkFDow=="],
+
+ "ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="],
"ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" }, "peerDependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="],
- "ajv-keywords": ["ajv-keywords@3.5.2", "", { "peerDependencies": { "ajv": "^6.9.1" } }, "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="],
-
"anser": ["anser@2.1.1", "", {}, "sha512-nqLm4HxOTpeLOxcmB3QWmV5TcDFhW9y/fyQ+hivtDFcK4OQ+pQ5fzPnXHM1Mfcm0VkLtvVi1TCPr++Qy0Q/3EQ=="],
"ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="],
@@ -2161,7 +2321,7 @@
"arg": ["arg@4.1.3", "", {}, "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="],
- "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
+ "argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
"aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="],
@@ -2223,11 +2383,11 @@
"babel-plugin-jest-hoist": ["babel-plugin-jest-hoist@30.2.0", "", { "dependencies": { "@types/babel__core": "^7.20.5" } }, "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA=="],
- "babel-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.12", "", { "dependencies": { "@babel/compat-data": "^7.22.6", "@babel/helper-define-polyfill-provider": "^0.6.3", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og=="],
+ "babel-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.14", "", { "dependencies": { "@babel/compat-data": "^7.27.7", "@babel/helper-define-polyfill-provider": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg=="],
- "babel-plugin-polyfill-corejs3": ["babel-plugin-polyfill-corejs3@0.11.1", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.3", "core-js-compat": "^3.40.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ=="],
+ "babel-plugin-polyfill-corejs3": ["babel-plugin-polyfill-corejs3@0.13.0", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5", "core-js-compat": "^3.43.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A=="],
- "babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.6.3", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.3" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q=="],
+ "babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.6.5", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg=="],
"babel-plugin-replace-ts-export-assignment": ["babel-plugin-replace-ts-export-assignment@0.0.2", "", {}, "sha512-BiTEG2Ro+O1spuheL5nB289y37FFmz0ISE6GjpNCG2JuA/WNcuEHSYw01+vN8quGf208sID3FnZFDwVyqX18YQ=="],
@@ -2253,7 +2413,7 @@
"base64url": ["base64url@3.0.1", "", {}, "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A=="],
- "baseline-browser-mapping": ["baseline-browser-mapping@2.8.28", "", { "bin": "dist/cli.js" }, "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ=="],
+ "baseline-browser-mapping": ["baseline-browser-mapping@2.10.0", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA=="],
"bcryptjs": ["bcryptjs@2.4.3", "", {}, "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ=="],
@@ -2261,9 +2421,11 @@
"binary-extensions": ["binary-extensions@2.2.0", "", {}, "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="],
+ "bluebird": ["bluebird@3.4.7", "", {}, "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA=="],
+
"bn.js": ["bn.js@4.12.1", "", {}, "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg=="],
- "body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="],
+ "body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="],
"boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="],
@@ -2351,9 +2513,11 @@
"cheerio-select": ["cheerio-select@2.1.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-select": "^5.1.0", "css-what": "^6.1.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1" } }, "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g=="],
- "chokidar": ["chokidar@3.5.3", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw=="],
+ "chevrotain": ["chevrotain@11.1.2", "", { "dependencies": { "@chevrotain/cst-dts-gen": "11.1.2", "@chevrotain/gast": "11.1.2", "@chevrotain/regexp-to-ast": "11.1.2", "@chevrotain/types": "11.1.2", "@chevrotain/utils": "11.1.2", "lodash-es": "4.17.23" } }, "sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg=="],
- "chrome-trace-event": ["chrome-trace-event@1.0.3", "", {}, "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg=="],
+ "chevrotain-allstar": ["chevrotain-allstar@0.3.1", "", { "dependencies": { "lodash-es": "^4.17.21" }, "peerDependencies": { "chevrotain": "^11.0.0" } }, "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw=="],
+
+ "chokidar": ["chokidar@3.5.3", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw=="],
"ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="],
@@ -2419,6 +2583,8 @@
"concat-with-sourcemaps": ["concat-with-sourcemaps@1.1.0", "", { "dependencies": { "source-map": "^0.6.1" } }, "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg=="],
+ "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
+
"connect-redis": ["connect-redis@8.1.0", "", { "peerDependencies": { "express-session": ">=1" } }, "sha512-Km0EYLDlmExF52UCss5gLGTtrukGC57G6WCC2aqEMft5Vr4xNWuM4tL+T97kWrw+vp40SXFteb6Xk/7MxgpwdA=="],
"console-browserify": ["console-browserify@1.2.0", "", {}, "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA=="],
@@ -2445,13 +2611,13 @@
"copy-to-clipboard": ["copy-to-clipboard@3.3.3", "", { "dependencies": { "toggle-selection": "^1.0.6" } }, "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA=="],
- "core-js-compat": ["core-js-compat@3.40.0", "", { "dependencies": { "browserslist": "^4.24.3" } }, "sha512-0XEDpr5y5mijvw8Lbc6E5AkjrHfp7eEoPlu36SWeAbcL8fn1G1ANe8DBlo2XoNN89oVpxWwOjYIPVzR4ZvsKCQ=="],
+ "core-js-compat": ["core-js-compat@3.47.0", "", { "dependencies": { "browserslist": "^4.28.0" } }, "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ=="],
- "core-util-is": ["core-util-is@1.0.2", "", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="],
+ "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="],
"cors": ["cors@2.8.5", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="],
- "cosmiconfig": ["cosmiconfig@8.3.6", "", { "dependencies": { "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", "parse-json": "^5.2.0", "path-type": "^4.0.0" }, "peerDependencies": { "typescript": ">=4.9.5" } }, "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA=="],
+ "cose-base": ["cose-base@1.0.3", "", { "dependencies": { "layout-base": "^1.0.0" } }, "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg=="],
"create-ecdh": ["create-ecdh@4.0.4", "", { "dependencies": { "bn.js": "^4.1.0", "elliptic": "^6.5.3" } }, "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A=="],
@@ -2473,13 +2639,13 @@
"crypto-random-string": ["crypto-random-string@2.0.0", "", {}, "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA=="],
- "css-blank-pseudo": ["css-blank-pseudo@5.0.2", "", { "dependencies": { "postcss-selector-parser": "^6.0.10" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-aCU4AZ7uEcVSUzagTlA9pHciz7aWPKA/YzrEkpdSopJ2pvhIxiQ5sYeMz1/KByxlIo4XBdvMNJAVKMg/GRnhfw=="],
+ "css-blank-pseudo": ["css-blank-pseudo@8.0.1", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-C5B2e5hCM4llrQkUms+KnWEMVW8K1n2XvX9G7ppfMZJQ7KAS/4rNnkP1Cs+HhWriOz1mWWTMFD4j1J7s31Dgug=="],
"css-declaration-sorter": ["css-declaration-sorter@6.4.1", "", { "peerDependencies": { "postcss": "^8.0.9" } }, "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g=="],
- "css-has-pseudo": ["css-has-pseudo@5.0.2", "", { "dependencies": { "@csstools/selector-specificity": "^2.0.1", "postcss-selector-parser": "^6.0.10", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-q+U+4QdwwB7T9VEW/LyO6CFrLAeLqOykC5mDqJXc7aKZAhDbq7BvGT13VGJe+IwBfdN2o3Xdw2kJ5IxwV1Sc9Q=="],
+ "css-has-pseudo": ["css-has-pseudo@8.0.0", "", { "dependencies": { "@csstools/selector-specificity": "^6.0.0", "postcss-selector-parser": "^7.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-Uz/bsHRbOeir/5Oeuz85tq/yLJLxX+3dpoRdjNTshs6jjqwUg8XaEZGDd0ci3fw7l53Srw0EkJ8mYan0eW5uGQ=="],
- "css-prefers-color-scheme": ["css-prefers-color-scheme@8.0.2", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-OvFghizHJ45x7nsJJUSYLyQNTzsCU8yWjxAc/nhPQg1pbs18LMoET8N3kOweFDPy0JV0OSXN2iqRFhPBHYOeMA=="],
+ "css-prefers-color-scheme": ["css-prefers-color-scheme@11.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-fv0mgtwUhh2m9iio3Kxc2CkrogjIaRdMFaaqyzSFdii17JF4cfPyMNX72B15ZW2Nrr/NZUpxI4dec1VMHYJvdw=="],
"css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="],
@@ -2489,7 +2655,7 @@
"css.escape": ["css.escape@1.5.1", "", {}, "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg=="],
- "cssdb": ["cssdb@7.10.0", "", {}, "sha512-yGZ5tmA57gWh/uvdQBHs45wwFY0IBh3ypABk5sEubPBPSzXzkNgsWReqx7gdx6uhC+QoFBe+V8JwBB9/hQ6cIA=="],
+ "cssdb": ["cssdb@8.8.0", "", {}, "sha512-QbLeyz2Bgso1iRlh7IpWk6OKa3lLNGXsujVjDMPl9rOZpxKeiG69icLpbLCFxeURwmcdIfZqQyhlooKJYM4f8Q=="],
"cssesc": ["cssesc@3.0.0", "", { "bin": "bin/cssesc" }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="],
@@ -2503,14 +2669,84 @@
"csso": ["csso@4.2.0", "", { "dependencies": { "css-tree": "^1.1.2" } }, "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA=="],
- "cssom": ["cssom@0.5.0", "", {}, "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw=="],
-
"cssstyle": ["cssstyle@4.6.0", "", { "dependencies": { "@asamuzakjp/css-color": "^3.2.0", "rrweb-cssom": "^0.8.0" } }, "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg=="],
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
+ "cytoscape": ["cytoscape@3.33.1", "", {}, "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ=="],
+
+ "cytoscape-cose-bilkent": ["cytoscape-cose-bilkent@4.1.0", "", { "dependencies": { "cose-base": "^1.0.0" }, "peerDependencies": { "cytoscape": "^3.2.0" } }, "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ=="],
+
+ "cytoscape-fcose": ["cytoscape-fcose@2.2.0", "", { "dependencies": { "cose-base": "^2.2.0" }, "peerDependencies": { "cytoscape": "^3.2.0" } }, "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ=="],
+
"d": ["d@1.0.2", "", { "dependencies": { "es5-ext": "^0.10.64", "type": "^2.7.2" } }, "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw=="],
+ "d3": ["d3@7.9.0", "", { "dependencies": { "d3-array": "3", "d3-axis": "3", "d3-brush": "3", "d3-chord": "3", "d3-color": "3", "d3-contour": "4", "d3-delaunay": "6", "d3-dispatch": "3", "d3-drag": "3", "d3-dsv": "3", "d3-ease": "3", "d3-fetch": "3", "d3-force": "3", "d3-format": "3", "d3-geo": "3", "d3-hierarchy": "3", "d3-interpolate": "3", "d3-path": "3", "d3-polygon": "3", "d3-quadtree": "3", "d3-random": "3", "d3-scale": "4", "d3-scale-chromatic": "3", "d3-selection": "3", "d3-shape": "3", "d3-time": "3", "d3-time-format": "4", "d3-timer": "3", "d3-transition": "3", "d3-zoom": "3" } }, "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA=="],
+
+ "d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="],
+
+ "d3-axis": ["d3-axis@3.0.0", "", {}, "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw=="],
+
+ "d3-brush": ["d3-brush@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", "d3-interpolate": "1 - 3", "d3-selection": "3", "d3-transition": "3" } }, "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ=="],
+
+ "d3-chord": ["d3-chord@3.0.1", "", { "dependencies": { "d3-path": "1 - 3" } }, "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g=="],
+
+ "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="],
+
+ "d3-contour": ["d3-contour@4.0.2", "", { "dependencies": { "d3-array": "^3.2.0" } }, "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA=="],
+
+ "d3-delaunay": ["d3-delaunay@6.0.4", "", { "dependencies": { "delaunator": "5" } }, "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A=="],
+
+ "d3-dispatch": ["d3-dispatch@3.0.1", "", {}, "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg=="],
+
+ "d3-drag": ["d3-drag@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-selection": "3" } }, "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg=="],
+
+ "d3-dsv": ["d3-dsv@3.0.1", "", { "dependencies": { "commander": "7", "iconv-lite": "0.6", "rw": "1" }, "bin": { "csv2json": "bin/dsv2json.js", "csv2tsv": "bin/dsv2dsv.js", "dsv2dsv": "bin/dsv2dsv.js", "dsv2json": "bin/dsv2json.js", "json2csv": "bin/json2dsv.js", "json2dsv": "bin/json2dsv.js", "json2tsv": "bin/json2dsv.js", "tsv2csv": "bin/dsv2dsv.js", "tsv2json": "bin/dsv2json.js" } }, "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q=="],
+
+ "d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="],
+
+ "d3-fetch": ["d3-fetch@3.0.1", "", { "dependencies": { "d3-dsv": "1 - 3" } }, "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw=="],
+
+ "d3-force": ["d3-force@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-quadtree": "1 - 3", "d3-timer": "1 - 3" } }, "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg=="],
+
+ "d3-format": ["d3-format@3.1.2", "", {}, "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg=="],
+
+ "d3-geo": ["d3-geo@3.1.1", "", { "dependencies": { "d3-array": "2.5.0 - 3" } }, "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q=="],
+
+ "d3-hierarchy": ["d3-hierarchy@3.1.2", "", {}, "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA=="],
+
+ "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="],
+
+ "d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="],
+
+ "d3-polygon": ["d3-polygon@3.0.1", "", {}, "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg=="],
+
+ "d3-quadtree": ["d3-quadtree@3.0.1", "", {}, "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw=="],
+
+ "d3-random": ["d3-random@3.0.1", "", {}, "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ=="],
+
+ "d3-sankey": ["d3-sankey@0.12.3", "", { "dependencies": { "d3-array": "1 - 2", "d3-shape": "^1.2.0" } }, "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ=="],
+
+ "d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", "d3-interpolate": "1.2.0 - 3", "d3-time": "2.1.1 - 3", "d3-time-format": "2 - 4" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="],
+
+ "d3-scale-chromatic": ["d3-scale-chromatic@3.1.0", "", { "dependencies": { "d3-color": "1 - 3", "d3-interpolate": "1 - 3" } }, "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ=="],
+
+ "d3-selection": ["d3-selection@3.0.0", "", {}, "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="],
+
+ "d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "^3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="],
+
+ "d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "2 - 3" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="],
+
+ "d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "1 - 3" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="],
+
+ "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="],
+
+ "d3-transition": ["d3-transition@3.0.1", "", { "dependencies": { "d3-color": "1 - 3", "d3-dispatch": "1 - 3", "d3-ease": "1 - 3", "d3-interpolate": "1 - 3", "d3-timer": "1 - 3" }, "peerDependencies": { "d3-selection": "2 - 3" } }, "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w=="],
+
+ "d3-zoom": ["d3-zoom@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", "d3-interpolate": "1 - 3", "d3-selection": "2 - 3", "d3-transition": "2 - 3" } }, "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw=="],
+
+ "dagre-d3-es": ["dagre-d3-es@7.0.14", "", { "dependencies": { "d3": "^7.9.0", "lodash-es": "^4.17.21" } }, "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg=="],
+
"damerau-levenshtein": ["damerau-levenshtein@1.0.8", "", {}, "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="],
"data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="],
@@ -2525,9 +2761,9 @@
"date-fns": ["date-fns@3.3.1", "", {}, "sha512-y8e109LYGgoQDveiEBD3DYXKba1jWf5BA8YU1FL5Tvm0BTdEfy54WLCwnuYWZNnzzvALy/QQ4Hov+Q9RVRv+Zw=="],
- "dayjs": ["dayjs@1.11.13", "", {}, "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="],
+ "dayjs": ["dayjs@1.11.19", "", {}, "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="],
- "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+ "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
"decamelize": ["decamelize@1.2.0", "", {}, "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="],
@@ -2553,6 +2789,8 @@
"define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="],
+ "delaunator": ["delaunator@5.0.1", "", { "dependencies": { "robust-predicates": "^3.0.2" } }, "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw=="],
+
"delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="],
"denque": ["denque@2.1.0", "", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="],
@@ -2577,12 +2815,14 @@
"didyoumean": ["didyoumean@1.2.2", "", {}, "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="],
- "diff": ["diff@7.0.0", "", {}, "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw=="],
+ "diff": ["diff@4.0.2", "", {}, "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="],
"diff-sequences": ["diff-sequences@29.6.3", "", {}, "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q=="],
"diffie-hellman": ["diffie-hellman@5.0.3", "", { "dependencies": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", "randombytes": "^2.0.0" } }, "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg=="],
+ "dingbat-to-unicode": ["dingbat-to-unicode@1.0.1", "", {}, "sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w=="],
+
"dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="],
"dnd-core": ["dnd-core@16.0.1", "", { "dependencies": { "@react-dnd/asap": "^5.0.1", "@react-dnd/invariant": "^4.0.1", "redux": "^4.2.0" } }, "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng=="],
@@ -2599,11 +2839,9 @@
"domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="],
- "domexception": ["domexception@4.0.0", "", { "dependencies": { "webidl-conversions": "^7.0.0" } }, "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw=="],
-
"domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="],
- "dompurify": ["dompurify@3.3.0", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ=="],
+ "dompurify": ["dompurify@3.3.2", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ=="],
"domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="],
@@ -2611,6 +2849,8 @@
"downloadjs": ["downloadjs@1.4.7", "", {}, "sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q=="],
+ "duck": ["duck@0.1.12", "", { "dependencies": { "underscore": "^1.13.1" } }, "sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg=="],
+
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
@@ -2639,7 +2879,7 @@
"enhanced-resolve": ["enhanced-resolve@5.17.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg=="],
- "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
+ "entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="],
"environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="],
@@ -2655,8 +2895,6 @@
"es-iterator-helpers": ["es-iterator-helpers@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.6", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.4", "safe-array-concat": "^1.1.3" } }, "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w=="],
- "es-module-lexer": ["es-module-lexer@1.6.0", "", {}, "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ=="],
-
"es-object-atoms": ["es-object-atoms@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw=="],
"es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
@@ -2671,7 +2909,7 @@
"es6-symbol": ["es6-symbol@3.1.4", "", { "dependencies": { "d": "^1.0.2", "ext": "^1.7.0" } }, "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg=="],
- "esbuild": ["esbuild@0.25.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.1", "@esbuild/android-arm": "0.25.1", "@esbuild/android-arm64": "0.25.1", "@esbuild/android-x64": "0.25.1", "@esbuild/darwin-arm64": "0.25.1", "@esbuild/darwin-x64": "0.25.1", "@esbuild/freebsd-arm64": "0.25.1", "@esbuild/freebsd-x64": "0.25.1", "@esbuild/linux-arm": "0.25.1", "@esbuild/linux-arm64": "0.25.1", "@esbuild/linux-ia32": "0.25.1", "@esbuild/linux-loong64": "0.25.1", "@esbuild/linux-mips64el": "0.25.1", "@esbuild/linux-ppc64": "0.25.1", "@esbuild/linux-riscv64": "0.25.1", "@esbuild/linux-s390x": "0.25.1", "@esbuild/linux-x64": "0.25.1", "@esbuild/netbsd-arm64": "0.25.1", "@esbuild/netbsd-x64": "0.25.1", "@esbuild/openbsd-arm64": "0.25.1", "@esbuild/openbsd-x64": "0.25.1", "@esbuild/sunos-x64": "0.25.1", "@esbuild/win32-arm64": "0.25.1", "@esbuild/win32-ia32": "0.25.1", "@esbuild/win32-x64": "0.25.1" }, "bin": "bin/esbuild" }, "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ=="],
+ "esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="],
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
@@ -2683,8 +2921,6 @@
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
- "escodegen": ["escodegen@2.1.0", "", { "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", "esutils": "^2.0.2" }, "optionalDependencies": { "source-map": "~0.6.1" }, "bin": { "escodegen": "bin/escodegen.js", "esgenerate": "bin/esgenerate.js" } }, "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w=="],
-
"eslint": ["eslint@9.39.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.1", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "bin": "bin/eslint.js" }, "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g=="],
"eslint-config-prettier": ["eslint-config-prettier@10.0.1", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": "build/bin/cli.js" }, "sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw=="],
@@ -2755,11 +2991,11 @@
"export-from-json": ["export-from-json@1.7.4", "", {}, "sha512-FjmpluvZS2PTYyhkoMfQoyEJMfe2bfAyNpa5Apa6C9n7SWUWyJkG/VFnzERuj3q9Jjo3iwBjwVsDQ7Z7sczthA=="],
- "express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="],
+ "express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="],
"express-mongo-sanitize": ["express-mongo-sanitize@2.2.0", "", {}, "sha512-PZBs5nwhD6ek9ZuP+W2xmpvcrHwXZxD5GdieX2dsjPbAbH4azOkrHbycBud2QRU+YQF1CT+pki/lZGedHgo/dQ=="],
- "express-rate-limit": ["express-rate-limit@8.2.1", "", { "dependencies": { "ip-address": "10.0.1" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g=="],
+ "express-rate-limit": ["express-rate-limit@8.3.1", "", { "dependencies": { "ip-address": "10.1.0" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-D1dKN+cmyPWuvB+G2SREQDzPY1agpBIcTa9sJxOPMCNeH3gwzhqJRDWCXW3gg0y//+LQ/8j52JbMROWyrKdMdw=="],
"express-session": ["express-session@1.18.2", "", { "dependencies": { "cookie": "0.7.2", "cookie-signature": "1.0.7", "debug": "2.6.9", "depd": "~2.0.0", "on-headers": "~1.1.0", "parseurl": "~1.3.3", "safe-buffer": "5.2.1", "uid-safe": "~2.1.5" } }, "sha512-SZjssGQC7TzTs9rpPDuUrR23GNZ9+2+IkA/+IJWmvQilTr5OSliEHGF+D9scbIpdC6yGtTI0/VhaHoVes2AN/A=="],
@@ -2787,7 +3023,7 @@
"fast-uri": ["fast-uri@3.0.6", "", {}, "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw=="],
- "fast-xml-parser": ["fast-xml-parser@4.4.1", "", { "dependencies": { "strnum": "^1.0.5" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw=="],
+ "fast-xml-parser": ["fast-xml-parser@5.3.8", "", { "dependencies": { "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-53jIF4N6u/pxvaL1eb/hEZts/cFLWZ92eCfLrNyCI0k38lettCG/Bs40W9pPwoPXyHQlKu2OUbQtiEIZK/J6Vw=="],
"fastq": ["fastq@1.17.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w=="],
@@ -2807,7 +3043,7 @@
"file-stream-rotator": ["file-stream-rotator@0.6.1", "", { "dependencies": { "moment": "^2.29.1" } }, "sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ=="],
- "file-type": ["file-type@18.7.0", "", { "dependencies": { "readable-web-to-node-stream": "^3.0.2", "strtok3": "^7.0.0", "token-types": "^5.0.1" } }, "sha512-ihHtXRzXEziMrQ56VSgU7wkxh55iNchFkosu7Y9/S+tXHdKyrGjVK0ujbqNnsxzea+78MaLhN6PGmfYSAv1ACw=="],
+ "file-type": ["file-type@21.3.3", "", { "dependencies": { "@tokenizer/inflate": "^0.4.1", "strtok3": "^10.3.4", "token-types": "^6.1.1", "uint8array-extras": "^1.4.0" } }, "sha512-pNwbwz8c3aZ+GvbJnIsCnDjKvgCZLHxkFWLEFxU3RMa+Ey++ZSEfisvsWQMcdys6PpxQjWUOIDi1fifXsW3YRg=="],
"filelist": ["filelist@1.0.4", "", { "dependencies": { "minimatch": "^5.0.1" } }, "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q=="],
@@ -2849,7 +3085,7 @@
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
- "fraction.js": ["fraction.js@4.3.7", "", {}, "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew=="],
+ "fraction.js": ["fraction.js@5.3.4", "", {}, "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ=="],
"framer-motion": ["framer-motion@12.23.9", "", { "dependencies": { "motion-dom": "^12.23.9", "motion-utils": "^12.23.6", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid"] }, "sha512-TqEHXj8LWfQSKqfdr5Y4mYltYLw96deu6/K9kGDd+ysqRJPNwF9nb5mZcrLmybHbU7gcJ+HQar41U3UTGanbbQ=="],
@@ -2867,7 +3103,7 @@
"functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="],
- "gaxios": ["gaxios@5.1.3", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^5.0.0", "is-stream": "^2.0.0", "node-fetch": "^2.6.9" } }, "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA=="],
+ "gaxios": ["gaxios@6.2.0", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", "node-fetch": "^2.6.9" } }, "sha512-H6+bHeoEAU5D6XNc6mPKeN5dLZqEDs9Gpk6I+SZBEzK5So58JVrHPmevNi35fRl1J9Y5TaeLW0kYx3pCJ1U2mQ=="],
"gcp-metadata": ["gcp-metadata@5.3.0", "", { "dependencies": { "gaxios": "^5.0.0", "json-bigint": "^1.0.0" } }, "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w=="],
@@ -2897,12 +3133,10 @@
"get-tsconfig": ["get-tsconfig@4.10.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A=="],
- "glob": ["glob@13.0.0", "", { "dependencies": { "minimatch": "^10.1.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA=="],
+ "glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="],
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
- "glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="],
-
"globals": ["globals@15.14.0", "", {}, "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig=="],
"globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="],
@@ -2911,8 +3145,6 @@
"google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="],
- "googleapis-common": ["googleapis-common@7.0.1", "", { "dependencies": { "extend": "^3.0.2", "gaxios": "^6.0.3", "google-auth-library": "^9.0.0", "qs": "^6.7.0", "url-template": "^2.0.8", "uuid": "^9.0.0" } }, "sha512-mgt5zsd7zj5t5QXvDanjWguMdHAcJmmDrF9RkInCecNsyV7S7YtGqm5v2IWONNID88osb7zmx5FtrAP12JfD0w=="],
-
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
@@ -2921,10 +3153,14 @@
"gtoken": ["gtoken@7.1.0", "", { "dependencies": { "gaxios": "^6.0.0", "jws": "^4.0.0" } }, "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw=="],
+ "hachure-fill": ["hachure-fill@0.5.2", "", {}, "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg=="],
+
"hamt_plus": ["hamt_plus@1.0.2", "", {}, "sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA=="],
"handlebars": ["handlebars@4.7.8", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": "bin/handlebars" }, "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ=="],
+ "happy-dom": ["happy-dom@20.8.3", "", { "dependencies": { "@types/node": ">=20.0.0", "@types/whatwg-mimetype": "^3.0.2", "@types/ws": "^8.18.1", "entities": "^7.0.1", "whatwg-mimetype": "^3.0.0", "ws": "^8.18.3" } }, "sha512-lMHQRRwIPyJ70HV0kkFT7jH/gXzSI7yDkQFe07E2flwmNDFoWUTRMKpW2sglsnpeA7b6S2TJPp98EbQxai8eaQ=="],
+
"harmony-reflect": ["harmony-reflect@1.6.2", "", {}, "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g=="],
"has-bigints": ["has-bigints@1.0.2", "", {}, "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ=="],
@@ -2973,7 +3209,7 @@
"hoist-non-react-statics": ["hoist-non-react-statics@3.3.2", "", { "dependencies": { "react-is": "^16.7.0" } }, "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw=="],
- "hono": ["hono@4.11.1", "", {}, "sha512-KsFcH0xxHes0J4zaQgWbYwmz3UPOOskdqZmItstUG93+Wk1ePBLkLGwbP9zlmh1BFUiL8Qp+Xfu9P7feJWpGNg=="],
+ "hono": ["hono@4.12.5", "", {}, "sha512-3qq+FUBtlTHhtYxbxheZgY8NIFnkkC/MR8u5TTsr7YZ3wixryQ3cCwn3iZbg8p8B88iDBBAYSfZDS75t8MN7Vg=="],
"hookified": ["hookified@1.12.1", "", {}, "sha512-xnKGl+iMIlhrZmGHB729MqlmPoWBznctSQTYCpFKqNsCgimJQmithcW0xSQMMFzYnV2iKUh25alswn6epgxS0Q=="],
@@ -3025,6 +3261,8 @@
"ignore-by-default": ["ignore-by-default@1.0.1", "", {}, "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA=="],
+ "immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="],
+
"import-cwd": ["import-cwd@3.0.0", "", { "dependencies": { "import-from": "^3.0.0" } }, "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg=="],
"import-fresh": ["import-fresh@3.3.0", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw=="],
@@ -3049,11 +3287,13 @@
"internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="],
+ "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="],
+
"intersection-observer": ["intersection-observer@0.10.0", "", {}, "sha512-fn4bQ0Xq8FTej09YC/jqKZwtijpvARlRp6wxL5WTA6yPe2YWSJ5RJh7Nm79rK2qB0wr6iDQzH60XGq5V/7u8YQ=="],
"ioredis": ["ioredis@5.3.2", "", { "dependencies": { "@ioredis/commands": "^1.1.1", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", "lodash.defaults": "^4.2.0", "lodash.isarguments": "^3.1.0", "redis-errors": "^1.2.0", "redis-parser": "^3.0.0", "standard-as-callback": "^2.1.0" } }, "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA=="],
- "ip-address": ["ip-address@10.0.1", "", {}, "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA=="],
+ "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="],
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
@@ -3215,7 +3455,7 @@
"jest-message-util": ["jest-message-util@30.2.0", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" } }, "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw=="],
- "jest-mock": ["jest-mock@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", "jest-util": "^29.7.0" } }, "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw=="],
+ "jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="],
"jest-pnp-resolver": ["jest-pnp-resolver@1.2.3", "", { "peerDependencies": { "jest-resolve": "*" } }, "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w=="],
@@ -3231,7 +3471,7 @@
"jest-snapshot": ["jest-snapshot@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@babel/generator": "^7.27.5", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/types": "^7.27.3", "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "@jest/snapshot-utils": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "babel-preset-current-node-syntax": "^1.2.0", "chalk": "^4.1.2", "expect": "30.2.0", "graceful-fs": "^4.2.11", "jest-diff": "30.2.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-util": "30.2.0", "pretty-format": "30.2.0", "semver": "^7.7.2", "synckit": "^0.11.8" } }, "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA=="],
- "jest-util": ["jest-util@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", "picomatch": "^2.2.3" } }, "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA=="],
+ "jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
"jest-validate": ["jest-validate@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", "camelcase": "^6.3.0", "chalk": "^4.1.2", "leven": "^3.1.0", "pretty-format": "30.2.0" } }, "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw=="],
@@ -3283,6 +3523,8 @@
"jsx-ast-utils": ["jsx-ast-utils@3.3.5", "", { "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", "object.assign": "^4.1.4", "object.values": "^1.1.6" } }, "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ=="],
+ "jszip": ["jszip@3.10.1", "", { "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", "setimmediate": "^1.0.5" } }, "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g=="],
+
"jwa": ["jwa@2.0.0", "", { "dependencies": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA=="],
"jwks-rsa": ["jwks-rsa@3.2.0", "", { "dependencies": { "@types/express": "^4.17.20", "@types/jsonwebtoken": "^9.0.4", "debug": "^4.3.4", "jose": "^4.15.4", "limiter": "^1.1.5", "lru-memoizer": "^2.2.0" } }, "sha512-PwchfHcQK/5PSydeKCs1ylNym0w/SSv8a62DgHJ//7x2ZclCoinlsjAfDxAAbpoTPybOum/Jgy+vkvMmKz89Ww=="],
@@ -3297,16 +3539,22 @@
"keyv-file": ["keyv-file@5.2.0", "", { "dependencies": { "@keyv/serialize": "^1.0.1", "tslib": "^1.14.1" } }, "sha512-5JEBqQiDzjGCQHtf7KLReJdHKchaJyUZW+9TvBu+4dc+uuTqUG9KcdA3ICMXlwky3qjKc0ecNCNefbgjyDtlAg=="],
+ "khroma": ["khroma@2.1.0", "", {}, "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw=="],
+
"klona": ["klona@2.0.6", "", {}, "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA=="],
"kuler": ["kuler@2.0.0", "", {}, "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="],
- "langsmith": ["langsmith@0.3.67", "", { "dependencies": { "@types/uuid": "^10.0.0", "chalk": "^4.1.2", "console-table-printer": "^2.12.1", "p-queue": "^6.6.2", "p-retry": "4", "semver": "^7.6.3", "uuid": "^10.0.0" }, "peerDependencies": { "@opentelemetry/api": "*", "@opentelemetry/exporter-trace-otlp-proto": "*", "@opentelemetry/sdk-trace-base": "*", "openai": "*" } }, "sha512-l4y3RmJ9yWF5a29fLg3eWZQxn6Q6dxTOgLGgQHzPGZHF3NUynn+A+airYIe/Yt4rwjGbuVrABAPsXBkVu/Hi7g=="],
+ "langium": ["langium@4.2.1", "", { "dependencies": { "chevrotain": "~11.1.1", "chevrotain-allstar": "~0.3.1", "vscode-languageserver": "~9.0.1", "vscode-languageserver-textdocument": "~1.0.11", "vscode-uri": "~3.1.0" } }, "sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ=="],
+
+ "langsmith": ["langsmith@0.4.12", "", { "dependencies": { "@types/uuid": "^10.0.0", "chalk": "^4.1.2", "console-table-printer": "^2.12.1", "p-queue": "^6.6.2", "semver": "^7.6.3", "uuid": "^10.0.0" }, "peerDependencies": { "@opentelemetry/api": "*", "@opentelemetry/exporter-trace-otlp-proto": "*", "@opentelemetry/sdk-trace-base": "*", "openai": "*" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/exporter-trace-otlp-proto", "@opentelemetry/sdk-trace-base", "openai"] }, "sha512-YWt0jcGvKqjUgIvd78rd4QcdMss0lUkeUaqp0UpVRq7H2yNDx8H5jOUO/laWUmaPtWGgcip0qturykXe1g9Gqw=="],
"language-subtag-registry": ["language-subtag-registry@0.3.23", "", {}, "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ=="],
"language-tags": ["language-tags@1.0.9", "", { "dependencies": { "language-subtag-registry": "^0.3.20" } }, "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA=="],
+ "layout-base": ["layout-base@1.0.2", "", {}, "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg=="],
+
"ldap-filter": ["ldap-filter@0.3.3", "", { "dependencies": { "assert-plus": "^1.0.0" } }, "sha512-/tFkx5WIn4HuO+6w9lsfxq4FN3O+fDZeO9Mek8dCD8rTUpqzRa766BOBO7BcGkn3X86m5+cBm1/2S/Shzz7gMg=="],
"ldapauth-fork": ["ldapauth-fork@5.0.5", "", { "dependencies": { "@types/ldapjs": "^2.2.2", "bcryptjs": "^2.4.0", "ldapjs": "^2.2.1", "lru-cache": "^7.10.1" } }, "sha512-LWUk76+V4AOZbny/3HIPQtGPWZyA3SW2tRhsWIBi9imP22WJktKLHV1ofd8Jo/wY7Ve6vAT7FCI5mEn3blZTjw=="],
@@ -3319,6 +3567,8 @@
"librechat-data-provider": ["librechat-data-provider@workspace:packages/data-provider"],
+ "lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="],
+
"lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="],
"limiter": ["limiter@1.1.5", "", {}, "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA=="],
@@ -3329,13 +3579,13 @@
"listr2": ["listr2@8.2.5", "", { "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" } }, "sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ=="],
- "loader-runner": ["loader-runner@4.3.0", "", {}, "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg=="],
-
"loader-utils": ["loader-utils@3.3.1", "", {}, "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg=="],
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
- "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
+ "lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="],
+
+ "lodash-es": ["lodash-es@4.17.23", "", {}, "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg=="],
"lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="],
@@ -3367,8 +3617,6 @@
"lodash.sortby": ["lodash.sortby@4.7.0", "", {}, "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA=="],
- "lodash.throttle": ["lodash.throttle@4.1.1", "", {}, "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="],
-
"lodash.uniq": ["lodash.uniq@4.5.0", "", {}, "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ=="],
"log-update": ["log-update@6.1.0", "", { "dependencies": { "ansi-escapes": "^7.0.0", "cli-cursor": "^5.0.0", "slice-ansi": "^7.1.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w=="],
@@ -3381,6 +3629,8 @@
"loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": "cli.js" }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
+ "lop": ["lop@0.4.2", "", { "dependencies": { "duck": "^0.1.12", "option": "~0.2.1", "underscore": "^1.13.1" } }, "sha512-RefILVDQ4DKoRZsJ4Pj22TxE3omDO47yFpkIBoDKzkqPRISs5U1cnAdg/5583YPkWPaLIYHOKRMQSvjFsO26cw=="],
+
"lowlight": ["lowlight@2.9.0", "", { "dependencies": { "@types/hast": "^2.0.0", "fault": "^2.0.0", "highlight.js": "~11.8.0" } }, "sha512-OpcaUTCLmHuVuBcyNckKfH5B0oA4JUavb/M/8n9iAvanJYNQkrVm4pvyX0SUaqkBG4dnWHKt7p50B3ngAG2Rfw=="],
"lru-cache": ["lru-cache@4.1.5", "", { "dependencies": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" } }, "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g=="],
@@ -3399,8 +3649,12 @@
"makeerror": ["makeerror@1.0.12", "", { "dependencies": { "tmpl": "1.0.5" } }, "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg=="],
+ "mammoth": ["mammoth@1.11.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.6", "argparse": "~1.0.3", "base64-js": "^1.5.1", "bluebird": "~3.4.0", "dingbat-to-unicode": "^1.0.1", "jszip": "^3.7.1", "lop": "^0.4.2", "path-is-absolute": "^1.0.0", "underscore": "^1.13.1", "xmlbuilder": "^10.0.0" }, "bin": { "mammoth": "bin/mammoth" } }, "sha512-BcEqqY/BOwIcI1iR5tqyVlqc3KIaMRa4egSoK83YAVrBf6+yqdAAbtUcFDCWX8Zef8/fgNZ6rl4VUv+vVX8ddQ=="],
+
"markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="],
+ "marked": ["marked@14.0.0", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ=="],
+
"match-sorter": ["match-sorter@8.1.0", "", { "dependencies": { "@babel/runtime": "^7.23.8", "remove-accents": "0.5.0" } }, "sha512-0HX3BHPixkbECX+Vt7nS1vJ6P2twPgGTU3PMXjWrl1eyVCL24tFHeyYN1FN5RKLzve0TyzNI9qntqQGbebnfPQ=="],
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
@@ -3459,6 +3713,8 @@
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
+ "mermaid": ["mermaid@11.13.0", "", { "dependencies": { "@braintree/sanitize-url": "^7.1.1", "@iconify/utils": "^3.0.2", "@mermaid-js/parser": "^1.0.1", "@types/d3": "^7.4.3", "@upsetjs/venn.js": "^2.0.0", "cytoscape": "^3.33.1", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", "d3": "^7.9.0", "d3-sankey": "^0.12.3", "dagre-d3-es": "7.0.14", "dayjs": "^1.11.19", "dompurify": "^3.3.1", "katex": "^0.16.25", "khroma": "^2.1.0", "lodash-es": "^4.17.23", "marked": "^16.3.0", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", "uuid": "^11.1.0" } }, "sha512-fEnci+Immw6lKMFI8sqzjlATTyjLkRa6axrEgLV2yHTfv8r+h1wjFbV6xeRtd4rUV1cS4EpR9rwp3Rci7TRWDw=="],
+
"methods": ["methods@1.1.2", "", {}, "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="],
"micromark": ["micromark@4.0.0", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ=="],
@@ -3543,20 +3799,24 @@
"minimalistic-crypto-utils": ["minimalistic-crypto-utils@1.0.1", "", {}, "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg=="],
- "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
+ "minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
- "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
+ "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="],
"mkdirp": ["mkdirp@1.0.4", "", { "bin": "bin/cmd.js" }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
+ "mlly": ["mlly@1.8.1", "", { "dependencies": { "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.3" } }, "sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ=="],
+
"module-alias": ["module-alias@2.2.3", "", {}, "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q=="],
"module-details-from-path": ["module-details-from-path@1.0.4", "", {}, "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w=="],
"moment": ["moment@2.30.1", "", {}, "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="],
+ "monaco-editor": ["monaco-editor@0.55.1", "", { "dependencies": { "dompurify": "3.2.7", "marked": "14.0.0" } }, "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A=="],
+
"mongodb": ["mongodb@6.14.2", "", { "dependencies": { "@mongodb-js/saslprep": "^1.1.9", "bson": "^6.10.3", "mongodb-connection-string-url": "^3.0.0" }, "peerDependencies": { "@aws-sdk/credential-providers": "^3.188.0", "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", "gcp-metadata": "^5.2.0", "kerberos": "^2.0.1", "mongodb-client-encryption": ">=6.0.0 <7", "snappy": "^7.2.2", "socks": "^2.7.1" }, "optionalPeers": ["@mongodb-js/zstd", "kerberos", "mongodb-client-encryption", "snappy", "socks"] }, "sha512-kMEHNo0F3P6QKDq17zcDuPeaywK/YaJVCEQRzPF3TOM/Bl9MFg64YE5Tu7ifj37qZJMhwU1tl2Ioivws5gRG5Q=="],
"mongodb-connection-string-url": ["mongodb-connection-string-url@3.0.2", "", { "dependencies": { "@types/whatwg-url": "^11.0.2", "whatwg-url": "^14.1.0 || ^13.0.0" } }, "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA=="],
@@ -3579,13 +3839,13 @@
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
- "multer": ["multer@2.0.2", "", { "dependencies": { "append-field": "^1.0.0", "busboy": "^1.6.0", "concat-stream": "^2.0.0", "mkdirp": "^0.5.6", "object-assign": "^4.1.1", "type-is": "^1.6.18", "xtend": "^4.0.2" } }, "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw=="],
+ "multer": ["multer@2.1.1", "", { "dependencies": { "append-field": "^1.0.0", "busboy": "^1.6.0", "concat-stream": "^2.0.0", "type-is": "^1.6.18" } }, "sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A=="],
"mustache": ["mustache@4.2.0", "", { "bin": "bin/mustache" }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="],
"mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
- "nanoid": ["nanoid@3.3.8", "", { "bin": "bin/nanoid.cjs" }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="],
+ "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"napi-postinstall": ["napi-postinstall@0.3.4", "", { "bin": "lib/cli.js" }, "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ=="],
@@ -3605,6 +3865,8 @@
"node-int64": ["node-int64@0.4.0", "", {}, "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="],
+ "node-readable-to-web-readable-stream": ["node-readable-to-web-readable-stream@0.4.2", "", {}, "sha512-/cMZNI34v//jUTrI+UIo4ieHAB5EZRY/+7OmXZgBxaWBMcW2tGdceIw06RFxWxrKZ5Jp3sI2i5TsRo+CBhtVLQ=="],
+
"node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="],
"node-stdlib-browser": ["node-stdlib-browser@1.3.1", "", { "dependencies": { "assert": "^2.0.0", "browser-resolve": "^2.0.0", "browserify-zlib": "^0.2.0", "buffer": "^5.7.1", "console-browserify": "^1.1.0", "constants-browserify": "^1.0.0", "create-require": "^1.1.1", "crypto-browserify": "^3.12.1", "domain-browser": "4.22.0", "events": "^3.0.0", "https-browserify": "^1.0.0", "isomorphic-timers-promises": "^1.0.1", "os-browserify": "^0.3.0", "path-browserify": "^1.0.1", "pkg-dir": "^5.0.0", "process": "^0.11.10", "punycode": "^1.4.1", "querystring-es3": "^0.2.1", "readable-stream": "^3.6.0", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "string_decoder": "^1.0.0", "timers-browserify": "^2.0.4", "tty-browserify": "0.0.1", "url": "^0.11.4", "util": "^0.12.4", "vm-browserify": "^1.0.1" } }, "sha512-X75ZN8DCLftGM5iKwoYLA3rjnrAEs97MkzvSd4q2746Tgpg8b8XWiBGiBG4ZpgcAqBgtgPHTiAc8ZMCvZuikDw=="],
@@ -3651,6 +3913,8 @@
"object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="],
+ "okapibm25": ["okapibm25@1.4.1", "", {}, "sha512-UHmeH4MAtZXGFVncwbY7pfFvDVNxpsyM3W66aGPU0SHj1+ld59ty+9lJ0ifcrcnPUl1XdYoDgb06ObyCnpTs3g=="],
+
"ollama": ["ollama@0.5.18", "", { "dependencies": { "whatwg-fetch": "^3.6.20" } }, "sha512-lTFqTf9bo7Cd3hpF6CviBe/DEhewjoZYd9N/uCe7O20qYTvGqrNOFOBDj3lbZgFWHUgDv5EeyusYxsZSLS8nvg=="],
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
@@ -3671,6 +3935,8 @@
"openid-client": ["openid-client@6.5.0", "", { "dependencies": { "jose": "^6.0.10", "oauth4webapi": "^3.5.1" } }, "sha512-fAfYaTnOYE2kQCqEJGX9KDObW2aw7IQy4jWpU/+3D3WoCFLbix5Hg6qIPQ6Js9r7f8jDUmsnnguRNCSw4wU/IQ=="],
+ "option": ["option@0.2.4", "", {}, "sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A=="],
+
"optionator": ["optionator@0.9.3", "", { "dependencies": { "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0" } }, "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg=="],
"os-browserify": ["os-browserify@0.3.0", "", {}, "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A=="],
@@ -3695,6 +3961,8 @@
"package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
+ "package-manager-detector": ["package-manager-detector@1.6.0", "", {}, "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA=="],
+
"pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="],
"parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
@@ -3737,6 +4005,8 @@
"path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="],
+ "path-data-parser": ["path-data-parser@0.1.0", "", {}, "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w=="],
+
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
"path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="],
@@ -3745,17 +4015,17 @@
"path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
- "path-scurry": ["path-scurry@2.0.1", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA=="],
+ "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="],
"path-to-regexp": ["path-to-regexp@8.2.0", "", {}, "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ=="],
- "path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="],
+ "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"pause": ["pause@0.0.1", "", {}, "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="],
"pbkdf2": ["pbkdf2@3.1.3", "", { "dependencies": { "create-hash": "~1.1.3", "create-hmac": "^1.1.7", "ripemd160": "=2.0.1", "safe-buffer": "^5.2.1", "sha.js": "^2.4.11", "to-buffer": "^1.2.0" } }, "sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA=="],
- "peek-readable": ["peek-readable@5.0.0", "", {}, "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A=="],
+ "pdfjs-dist": ["pdfjs-dist@5.5.207", "", { "optionalDependencies": { "@napi-rs/canvas": "^0.1.95", "node-readable-to-web-readable-stream": "^0.4.2" } }, "sha512-WMqqw06w1vUt9ZfT0gOFhMf3wHsWhaCrxGrckGs5Cci6ybDW87IvPaOd2pnBwT6BJuP/CzXDZxjFgmSULLdsdw=="],
"pend": ["pend@1.2.0", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="],
@@ -3773,37 +4043,43 @@
"pkg-dir": ["pkg-dir@4.2.0", "", { "dependencies": { "find-up": "^4.0.0" } }, "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ=="],
+ "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
+
"playwright": ["playwright@1.56.1", "", { "dependencies": { "playwright-core": "1.56.1" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": "cli.js" }, "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw=="],
"playwright-core": ["playwright-core@1.56.1", "", { "bin": "cli.js" }, "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ=="],
+ "points-on-curve": ["points-on-curve@0.2.0", "", {}, "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A=="],
+
+ "points-on-path": ["points-on-path@0.2.1", "", { "dependencies": { "path-data-parser": "0.1.0", "points-on-curve": "0.2.0" } }, "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g=="],
+
"possible-typed-array-names": ["possible-typed-array-names@1.0.0", "", {}, "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q=="],
"postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="],
- "postcss-attribute-case-insensitive": ["postcss-attribute-case-insensitive@6.0.2", "", { "dependencies": { "postcss-selector-parser": "^6.0.10" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-IRuCwwAAQbgaLhxQdQcIIK0dCVXg3XDUnzgKD8iwdiYdwU4rMWRWyl/W9/0nA4ihVpq5pyALiHB2veBJ0292pw=="],
+ "postcss-attribute-case-insensitive": ["postcss-attribute-case-insensitive@8.0.0", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-fovIPEV35c2JzVXdmP+sp2xirbBMt54J+upU8u6TSj410kUU5+axgEzvBBSAX8KCybze8CFCelzFAw/FfWg2TA=="],
"postcss-calc": ["postcss-calc@8.2.4", "", { "dependencies": { "postcss-selector-parser": "^6.0.9", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.2.2" } }, "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q=="],
"postcss-clamp": ["postcss-clamp@4.1.0", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.6" } }, "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow=="],
- "postcss-color-functional-notation": ["postcss-color-functional-notation@5.1.0", "", { "dependencies": { "@csstools/postcss-progressive-custom-properties": "^2.3.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-w2R4py6zrVE1U7FwNaAc76tNQlG9GLkrBbcFw+VhUjyDDiV28vfZG+l4LyPmpoQpeSJVtu8VgNjE8Jv5SpC7dQ=="],
+ "postcss-color-functional-notation": ["postcss-color-functional-notation@8.0.2", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.2", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-tbmkk6teYpJzFcGwPIhN1gkvxqGHvNx2PMb8Y3S5Ktyn7xOlvD98XzQ99MFY5mAyvXWclDG+BgoJKYJXFJOp5Q=="],
- "postcss-color-hex-alpha": ["postcss-color-hex-alpha@9.0.3", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-7sEHU4tAS6htlxun8AB9LDrCXoljxaC34tFVRlYKcvO+18r5fvGiXgv5bQzN40+4gXLCyWSMRK5FK31244WcCA=="],
+ "postcss-color-hex-alpha": ["postcss-color-hex-alpha@11.0.0", "", { "dependencies": { "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-NCGa6vjIyrjosz9GqRxVKbONBklz5TeipYqTJp3IqbnBWlBq5e5EMtG6MaX4vqk9LzocPfMQkuRK9tfk+OQuKg=="],
- "postcss-color-rebeccapurple": ["postcss-color-rebeccapurple@8.0.2", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-xWf/JmAxVoB5bltHpXk+uGRoGFwu4WDAR7210el+iyvTdqiKpDhtcT8N3edXMoVJY0WHFMrKMUieql/wRNiXkw=="],
+ "postcss-color-rebeccapurple": ["postcss-color-rebeccapurple@11.0.0", "", { "dependencies": { "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-g9561mx7cbdqx7XeO/L+lJzVlzu7bICyXr72efBVKZGxIhvBBJf9fGXn3Cb6U4Bwh3LbzQO2e9NWBLVYdX5Eag=="],
"postcss-colormin": ["postcss-colormin@5.3.1", "", { "dependencies": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", "colord": "^2.9.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ=="],
"postcss-convert-values": ["postcss-convert-values@5.1.3", "", { "dependencies": { "browserslist": "^4.21.4", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA=="],
- "postcss-custom-media": ["postcss-custom-media@9.1.5", "", { "dependencies": { "@csstools/cascade-layer-name-parser": "^1.0.2", "@csstools/css-parser-algorithms": "^2.2.0", "@csstools/css-tokenizer": "^2.1.1", "@csstools/media-query-list-parser": "^2.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-GStyWMz7Qbo/Gtw1xVspzVSX8eipgNg4lpsO3CAeY4/A1mzok+RV6MCv3fg62trWijh/lYEj6vps4o8JcBBpDA=="],
+ "postcss-custom-media": ["postcss-custom-media@12.0.1", "", { "dependencies": { "@csstools/cascade-layer-name-parser": "^3.0.0", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/media-query-list-parser": "^5.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-66syE14+VeqkUf0rRX0bvbTCbNRJF132jD+ceo8th1dap2YJEAqpdh5uG98CE3IbgHT7m9XM0GIlOazNWqQdeA=="],
- "postcss-custom-properties": ["postcss-custom-properties@13.3.4", "", { "dependencies": { "@csstools/cascade-layer-name-parser": "^1.0.7", "@csstools/css-parser-algorithms": "^2.5.0", "@csstools/css-tokenizer": "^2.2.3", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-9YN0gg9sG3OH+Z9xBrp2PWRb+O4msw+5Sbp3ZgqrblrwKspXVQe5zr5sVqi43gJGwW/Rv1A483PRQUzQOEewvA=="],
+ "postcss-custom-properties": ["postcss-custom-properties@15.0.1", "", { "dependencies": { "@csstools/cascade-layer-name-parser": "^3.0.0", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-cuyq8sd8dLY0GLbelz1KB8IMIoDECo6RVXMeHeXY2Uw3Q05k/d1GVITdaKLsheqrHbnxlwxzSRZQQ5u+rNtbMg=="],
- "postcss-custom-selectors": ["postcss-custom-selectors@7.1.6", "", { "dependencies": { "@csstools/cascade-layer-name-parser": "^1.0.5", "@csstools/css-parser-algorithms": "^2.3.2", "@csstools/css-tokenizer": "^2.2.1", "postcss-selector-parser": "^6.0.13" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-svsjWRaxqL3vAzv71dV0/65P24/FB8TbPX+lWyyf9SZ7aZm4S4NhCn7N3Bg+Z5sZunG3FS8xQ80LrCU9hb37cw=="],
+ "postcss-custom-selectors": ["postcss-custom-selectors@9.0.1", "", { "dependencies": { "@csstools/cascade-layer-name-parser": "^3.0.0", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-2XBELy4DmdVKimChfaZ2id9u9CSGYQhiJ53SvlfBvMTzLMW2VxuMb9rHsMSQw9kRq/zSbhT5x13EaK8JSmK8KQ=="],
- "postcss-dir-pseudo-class": ["postcss-dir-pseudo-class@7.0.2", "", { "dependencies": { "postcss-selector-parser": "^6.0.10" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-cMnslilYxBf9k3qejnovrUONZx1rXeUZJw06fgIUBzABJe3D2LiLL5WAER7Imt3nrkaIgG05XZBztueLEf5P8w=="],
+ "postcss-dir-pseudo-class": ["postcss-dir-pseudo-class@10.0.0", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-DmtIzULpyC8XaH4b5AaUgt4Jic4QmrECqidNCdR7u7naQFdnxX80YI06u238a+ZVRXwURDxVzy0s/UQnWmpVeg=="],
"postcss-discard-comments": ["postcss-discard-comments@5.1.2", "", { "peerDependencies": { "postcss": "^8.2.15" } }, "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ=="],
@@ -3813,31 +4089,27 @@
"postcss-discard-overridden": ["postcss-discard-overridden@5.1.0", "", { "peerDependencies": { "postcss": "^8.2.15" } }, "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw=="],
- "postcss-double-position-gradients": ["postcss-double-position-gradients@4.0.4", "", { "dependencies": { "@csstools/postcss-progressive-custom-properties": "^2.3.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-nUAbUXURemLXIrl4Xoia2tiu5z/n8sY+BVDZApoeT9BlpByyrp02P/lFCRrRvZ/zrGRE+MOGLhk8o7VcMCtPtQ=="],
+ "postcss-double-position-gradients": ["postcss-double-position-gradients@7.0.0", "", { "dependencies": { "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-Msr/dxj8Os7KLJE5Hdhvprwm3K5Zrh1KTY0eFN3ngPKNkej/Usy4BM9JQmqE6CLAkDpHoQVsi4snbL72CPt6qg=="],
- "postcss-focus-visible": ["postcss-focus-visible@8.0.2", "", { "dependencies": { "postcss-selector-parser": "^6.0.10" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-f/Vd+EC/GaKElknU59esVcRYr/Y3t1ZAQyL4u2xSOgkDy4bMCmG7VP5cGvj3+BTLNE9ETfEuz2nnt4qkZwTTeA=="],
+ "postcss-focus-visible": ["postcss-focus-visible@11.0.0", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-VG1a9kBKizUBWS66t5xyB4uLONBnvZLCmZXxT40FALu8EF0QgVZBYy5ApC0KhmpHsv+pvHMJHB3agKHwmocWjw=="],
- "postcss-focus-within": ["postcss-focus-within@7.0.2", "", { "dependencies": { "postcss-selector-parser": "^6.0.10" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-AHAJ89UQBcqBvFgQJE9XasGuwMNkKsGj4D/f9Uk60jFmEBHpAL14DrnSk3Rj+SwZTr/WUG+mh+Rvf8fid/346w=="],
+ "postcss-focus-within": ["postcss-focus-within@10.0.0", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-dvql0fzUTG+gcJYp+KTbag5vAjuo94LDYZHkqDV1rnf5gPGer1v/SrmIZBdvKU8moep3HbcbujqGjzSb3DL53Q=="],
"postcss-font-variant": ["postcss-font-variant@5.0.0", "", { "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA=="],
- "postcss-gap-properties": ["postcss-gap-properties@4.0.1", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-V5OuQGw4lBumPlwHWk/PRfMKjaq/LTGR4WDTemIMCaMevArVfCCA9wBJiL1VjDAd+rzuCIlkRoRvDsSiAaZ4Fg=="],
+ "postcss-gap-properties": ["postcss-gap-properties@7.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-PSDF2QoZMRUbsINvXObQgxx4HExRP85QTT8qS/YN9fBsCPWCqUuwqAD6E6PNp0BqL/jU1eyWUBORaOK/J/9LDA=="],
- "postcss-image-set-function": ["postcss-image-set-function@5.0.2", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-Sszjwo0ubETX0Fi5MvpYzsONwrsjeabjMoc5YqHvURFItXgIu3HdCjcVuVKGMPGzKRhgaknmdM5uVWInWPJmeg=="],
+ "postcss-image-set-function": ["postcss-image-set-function@8.0.0", "", { "dependencies": { "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-rEGNkOkNusf4+IuMmfEoIdLuVmvbExGbmG+MIsyV6jR5UaWSoyPcAYHV/PxzVDCmudyF+2Nh/o6Ub2saqUdnuA=="],
"postcss-import": ["postcss-import@15.1.0", "", { "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", "resolve": "^1.1.7" }, "peerDependencies": { "postcss": "^8.0.0" } }, "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew=="],
- "postcss-initial": ["postcss-initial@4.0.1", "", { "peerDependencies": { "postcss": "^8.0.0" } }, "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ=="],
-
"postcss-js": ["postcss-js@4.0.1", "", { "dependencies": { "camelcase-css": "^2.0.1" }, "peerDependencies": { "postcss": "^8.4.21" } }, "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw=="],
- "postcss-lab-function": ["postcss-lab-function@5.2.3", "", { "dependencies": { "@csstools/css-color-parser": "^1.2.0", "@csstools/css-parser-algorithms": "^2.1.1", "@csstools/css-tokenizer": "^2.1.1", "@csstools/postcss-progressive-custom-properties": "^2.3.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-fi32AYKzji5/rvgxo5zXHFvAYBw0u0OzELbeCNjEZVLUir18Oj+9RmNphtM8QdLUaUnrfx8zy8vVYLmFLkdmrQ=="],
+ "postcss-lab-function": ["postcss-lab-function@8.0.2", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.2", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-1ZIAh8ODhZdnAb09Aq2BTenePKS1G/kUR0FwvzkQDfFtSOV64Ycv27YvV11fDycEvhIcEmgYkLABXKRiWcXRuA=="],
"postcss-load-config": ["postcss-load-config@3.1.4", "", { "dependencies": { "lilconfig": "^2.0.5", "yaml": "^1.10.2" }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" } }, "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg=="],
- "postcss-loader": ["postcss-loader@7.3.4", "", { "dependencies": { "cosmiconfig": "^8.3.5", "jiti": "^1.20.0", "semver": "^7.5.4" }, "peerDependencies": { "postcss": "^7.0.0 || ^8.0.1", "webpack": "^5.0.0" } }, "sha512-iW5WTTBSC5BfsBJ9daFMPVrLT36MrNiC6fqOZTTaHjBNX6Pfd5p+hSBqe/fEeNd7pc13QiAyGt7VdGMw4eRC4A=="],
-
- "postcss-logical": ["postcss-logical@6.2.0", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-aqlfKGaY0nnbgI9jwUikp4gJKBqcH5noU/EdnIVceghaaDPYhZuyJVxlvWNy55tlTG5tunRKCTAX9yljLiFgmw=="],
+ "postcss-logical": ["postcss-logical@9.0.0", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-A4LNd9dk3q/juEUA9Gd8ALhBO3TeOeYurnyHLlf2aAToD94VHR8c5Uv7KNmf8YVRhTxvWsyug4c5fKtARzyIRQ=="],
"postcss-merge-longhand": ["postcss-merge-longhand@5.1.7", "", { "dependencies": { "postcss-value-parser": "^4.2.0", "stylehacks": "^5.1.1" }, "peerDependencies": { "postcss": "^8.2.15" } }, "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ=="],
@@ -3863,7 +4135,7 @@
"postcss-nested": ["postcss-nested@6.0.1", "", { "dependencies": { "postcss-selector-parser": "^6.0.11" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ=="],
- "postcss-nesting": ["postcss-nesting@11.3.0", "", { "dependencies": { "@csstools/selector-specificity": "^2.0.0", "postcss-selector-parser": "^6.0.10" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-JlS10AQm/RzyrUGgl5irVkAlZYTJ99mNueUl+Qab+TcHhVedLiylWVkKBhRale+rS9yWIJK48JVzQlq3LcSdeA=="],
+ "postcss-nesting": ["postcss-nesting@14.0.0", "", { "dependencies": { "@csstools/selector-resolve-nested": "^4.0.0", "@csstools/selector-specificity": "^6.0.0", "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-YGFOfVrjxYfeGTS5XctP1WCI5hu8Lr9SmntjfRC+iX5hCihEO+QZl9Ra+pkjqkgoVdDKvb2JccpElcowhZtzpw=="],
"postcss-normalize-charset": ["postcss-normalize-charset@5.1.0", "", { "peerDependencies": { "postcss": "^8.2.15" } }, "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg=="],
@@ -3883,19 +4155,19 @@
"postcss-normalize-whitespace": ["postcss-normalize-whitespace@5.1.1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA=="],
- "postcss-opacity-percentage": ["postcss-opacity-percentage@2.0.0", "", { "peerDependencies": { "postcss": "^8.2" } }, "sha512-lyDrCOtntq5Y1JZpBFzIWm2wG9kbEdujpNt4NLannF+J9c8CgFIzPa80YQfdza+Y+yFfzbYj/rfoOsYsooUWTQ=="],
+ "postcss-opacity-percentage": ["postcss-opacity-percentage@3.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ=="],
"postcss-ordered-values": ["postcss-ordered-values@5.1.3", "", { "dependencies": { "cssnano-utils": "^3.1.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ=="],
- "postcss-overflow-shorthand": ["postcss-overflow-shorthand@4.0.1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-HQZ0qi/9iSYHW4w3ogNqVNr2J49DHJAl7r8O2p0Meip38jsdnRPgiDW7r/LlLrrMBMe3KHkvNtAV2UmRVxzLIg=="],
+ "postcss-overflow-shorthand": ["postcss-overflow-shorthand@7.0.0", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-9SLpjoUdGRoRrzoOdX66HbUs0+uDwfIAiXsRa7piKGOqPd6F4ZlON9oaDSP5r1Qpgmzw5L9Ht0undIK6igJPMA=="],
"postcss-page-break": ["postcss-page-break@3.0.4", "", { "peerDependencies": { "postcss": "^8" } }, "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ=="],
- "postcss-place": ["postcss-place@8.0.1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-Ow2LedN8sL4pq8ubukO77phSVt4QyCm35ZGCYXKvRFayAwcpgB0sjNJglDoTuRdUL32q/ZC1VkPBo0AOEr4Uiw=="],
+ "postcss-place": ["postcss-place@11.0.0", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-fAifpyjQ+fuDRp2nmF95WbotqbpjdazebedahXdfBxy5sHembOLpBQ1cHveZD9ZmjK26tYM8tikeNaUlp/KfHA=="],
- "postcss-preset-env": ["postcss-preset-env@8.5.1", "", { "dependencies": { "@csstools/postcss-cascade-layers": "^3.0.1", "@csstools/postcss-color-function": "^2.2.3", "@csstools/postcss-color-mix-function": "^1.0.3", "@csstools/postcss-font-format-keywords": "^2.0.2", "@csstools/postcss-gradients-interpolation-method": "^3.0.6", "@csstools/postcss-hwb-function": "^2.2.2", "@csstools/postcss-ic-unit": "^2.0.4", "@csstools/postcss-is-pseudo-class": "^3.2.1", "@csstools/postcss-logical-float-and-clear": "^1.0.1", "@csstools/postcss-logical-resize": "^1.0.1", "@csstools/postcss-logical-viewport-units": "^1.0.3", "@csstools/postcss-media-minmax": "^1.0.4", "@csstools/postcss-media-queries-aspect-ratio-number-values": "^1.0.4", "@csstools/postcss-nested-calc": "^2.0.2", "@csstools/postcss-normalize-display-values": "^2.0.1", "@csstools/postcss-oklab-function": "^2.2.3", "@csstools/postcss-progressive-custom-properties": "^2.3.0", "@csstools/postcss-relative-color-syntax": "^1.0.2", "@csstools/postcss-scope-pseudo-class": "^2.0.2", "@csstools/postcss-stepped-value-functions": "^2.1.1", "@csstools/postcss-text-decoration-shorthand": "^2.2.4", "@csstools/postcss-trigonometric-functions": "^2.1.1", "@csstools/postcss-unset-value": "^2.0.1", "autoprefixer": "^10.4.14", "browserslist": "^4.21.9", "css-blank-pseudo": "^5.0.2", "css-has-pseudo": "^5.0.2", "css-prefers-color-scheme": "^8.0.2", "cssdb": "^7.6.0", "postcss-attribute-case-insensitive": "^6.0.2", "postcss-clamp": "^4.1.0", "postcss-color-functional-notation": "^5.1.0", "postcss-color-hex-alpha": "^9.0.2", "postcss-color-rebeccapurple": "^8.0.2", "postcss-custom-media": "^9.1.5", "postcss-custom-properties": "^13.2.0", "postcss-custom-selectors": "^7.1.3", "postcss-dir-pseudo-class": "^7.0.2", "postcss-double-position-gradients": "^4.0.4", "postcss-focus-visible": "^8.0.2", "postcss-focus-within": "^7.0.2", "postcss-font-variant": "^5.0.0", "postcss-gap-properties": "^4.0.1", "postcss-image-set-function": "^5.0.2", "postcss-initial": "^4.0.1", "postcss-lab-function": "^5.2.3", "postcss-logical": "^6.2.0", "postcss-nesting": "^11.3.0", "postcss-opacity-percentage": "^2.0.0", "postcss-overflow-shorthand": "^4.0.1", "postcss-page-break": "^3.0.4", "postcss-place": "^8.0.1", "postcss-pseudo-class-any-link": "^8.0.2", "postcss-replace-overflow-wrap": "^4.0.0", "postcss-selector-not": "^7.0.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-qhWnJJjP6ArLUINWJ38t6Aftxnv9NW6cXK0NuwcLCcRilbuw72dSFLkCVUJeCfHGgJiKzX+pnhkGiki0PEynWg=="],
+ "postcss-preset-env": ["postcss-preset-env@11.2.0", "", { "dependencies": { "@csstools/postcss-alpha-function": "^2.0.3", "@csstools/postcss-cascade-layers": "^6.0.0", "@csstools/postcss-color-function": "^5.0.2", "@csstools/postcss-color-function-display-p3-linear": "^2.0.2", "@csstools/postcss-color-mix-function": "^4.0.2", "@csstools/postcss-color-mix-variadic-function-arguments": "^2.0.2", "@csstools/postcss-content-alt-text": "^3.0.0", "@csstools/postcss-contrast-color-function": "^3.0.2", "@csstools/postcss-exponential-functions": "^3.0.1", "@csstools/postcss-font-format-keywords": "^5.0.0", "@csstools/postcss-font-width-property": "^1.0.0", "@csstools/postcss-gamut-mapping": "^3.0.2", "@csstools/postcss-gradients-interpolation-method": "^6.0.2", "@csstools/postcss-hwb-function": "^5.0.2", "@csstools/postcss-ic-unit": "^5.0.0", "@csstools/postcss-initial": "^3.0.0", "@csstools/postcss-is-pseudo-class": "^6.0.0", "@csstools/postcss-light-dark-function": "^3.0.0", "@csstools/postcss-logical-float-and-clear": "^4.0.0", "@csstools/postcss-logical-overflow": "^3.0.0", "@csstools/postcss-logical-overscroll-behavior": "^3.0.0", "@csstools/postcss-logical-resize": "^4.0.0", "@csstools/postcss-logical-viewport-units": "^4.0.0", "@csstools/postcss-media-minmax": "^3.0.1", "@csstools/postcss-media-queries-aspect-ratio-number-values": "^4.0.0", "@csstools/postcss-mixins": "^1.0.0", "@csstools/postcss-nested-calc": "^5.0.0", "@csstools/postcss-normalize-display-values": "^5.0.1", "@csstools/postcss-oklab-function": "^5.0.2", "@csstools/postcss-position-area-property": "^2.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/postcss-property-rule-prelude-list": "^2.0.0", "@csstools/postcss-random-function": "^3.0.1", "@csstools/postcss-relative-color-syntax": "^4.0.2", "@csstools/postcss-scope-pseudo-class": "^5.0.0", "@csstools/postcss-sign-functions": "^2.0.1", "@csstools/postcss-stepped-value-functions": "^5.0.1", "@csstools/postcss-syntax-descriptor-syntax-production": "^2.0.0", "@csstools/postcss-system-ui-font-family": "^2.0.0", "@csstools/postcss-text-decoration-shorthand": "^5.0.3", "@csstools/postcss-trigonometric-functions": "^5.0.1", "@csstools/postcss-unset-value": "^5.0.0", "autoprefixer": "^10.4.24", "browserslist": "^4.28.1", "css-blank-pseudo": "^8.0.1", "css-has-pseudo": "^8.0.0", "css-prefers-color-scheme": "^11.0.0", "cssdb": "^8.8.0", "postcss-attribute-case-insensitive": "^8.0.0", "postcss-clamp": "^4.1.0", "postcss-color-functional-notation": "^8.0.2", "postcss-color-hex-alpha": "^11.0.0", "postcss-color-rebeccapurple": "^11.0.0", "postcss-custom-media": "^12.0.1", "postcss-custom-properties": "^15.0.1", "postcss-custom-selectors": "^9.0.1", "postcss-dir-pseudo-class": "^10.0.0", "postcss-double-position-gradients": "^7.0.0", "postcss-focus-visible": "^11.0.0", "postcss-focus-within": "^10.0.0", "postcss-font-variant": "^5.0.0", "postcss-gap-properties": "^7.0.0", "postcss-image-set-function": "^8.0.0", "postcss-lab-function": "^8.0.2", "postcss-logical": "^9.0.0", "postcss-nesting": "^14.0.0", "postcss-opacity-percentage": "^3.0.0", "postcss-overflow-shorthand": "^7.0.0", "postcss-page-break": "^3.0.4", "postcss-place": "^11.0.0", "postcss-pseudo-class-any-link": "^11.0.0", "postcss-replace-overflow-wrap": "^4.0.0", "postcss-selector-not": "^9.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-eNYpuj68cjGjvZMoSAbHilaCt3yIyzBL1cVuSGJfvJewsaBW/U6dI2bqCJl3iuZsL+yvBobcy4zJFA/3I68IHQ=="],
- "postcss-pseudo-class-any-link": ["postcss-pseudo-class-any-link@8.0.2", "", { "dependencies": { "postcss-selector-parser": "^6.0.10" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-FYTIuRE07jZ2CW8POvctRgArQJ43yxhr5vLmImdKUvjFCkR09kh8pIdlCwdx/jbFm7MiW4QP58L4oOUv3grQYA=="],
+ "postcss-pseudo-class-any-link": ["postcss-pseudo-class-any-link@11.0.0", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-DNFZ4GMa3C3pU5dM+UCTG1CEeLtS1ZqV5DKSqCTJQMn1G5jnd/30fS8+A7H4o5bSD3MOcnx+VgI+xPE9Z5Wvig=="],
"postcss-reduce-initial": ["postcss-reduce-initial@5.1.2", "", { "dependencies": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg=="],
@@ -3903,7 +4175,7 @@
"postcss-replace-overflow-wrap": ["postcss-replace-overflow-wrap@4.0.0", "", { "peerDependencies": { "postcss": "^8.0.3" } }, "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw=="],
- "postcss-selector-not": ["postcss-selector-not@7.0.1", "", { "dependencies": { "postcss-selector-parser": "^6.0.10" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-1zT5C27b/zeJhchN7fP0kBr16Cc61mu7Si9uWWLoA3Px/D9tIJPKchJCkUH3tPO5D0pCFmGeApAv8XpXBQJ8SQ=="],
+ "postcss-selector-not": ["postcss-selector-not@9.0.0", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-xhAtTdHnVU2M/CrpYOPyRUvg3njhVlKmn2GNYXDaRJV9Ygx4d5OkSkc7NINzjUqnbDFtaKXlISOBeyMXU/zyFQ=="],
"postcss-selector-parser": ["postcss-selector-parser@6.0.15", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw=="],
@@ -3937,7 +4209,7 @@
"property-information": ["property-information@6.4.1", "", {}, "sha512-OHYtXfu5aI2sS2LWFSN5rgJjrQ4pCy8i1jubJLe2QvMF8JJ++HXTUIVWFLfXJoaOfvYYjk2SN8J2wFUWIGXT4w=="],
- "protobufjs": ["protobufjs@7.4.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw=="],
+ "protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg=="],
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
@@ -3945,8 +4217,6 @@
"pseudomap": ["pseudomap@1.0.2", "", {}, "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ=="],
- "psl": ["psl@1.9.0", "", {}, "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="],
-
"pstree.remy": ["pstree.remy@1.1.8", "", {}, "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w=="],
"public-encrypt": ["public-encrypt@4.0.3", "", { "dependencies": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", "create-hash": "^1.1.0", "parse-asn1": "^5.0.0", "randombytes": "^2.0.1", "safe-buffer": "^5.1.2" } }, "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q=="],
@@ -3961,8 +4231,6 @@
"querystring-es3": ["querystring-es3@0.2.1", "", {}, "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA=="],
- "querystringify": ["querystringify@2.2.0", "", {}, "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="],
-
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"random-bytes": ["random-bytes@1.0.0", "", {}, "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ=="],
@@ -4003,23 +4271,21 @@
"react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="],
- "react-lazy-load-image-component": ["react-lazy-load-image-component@1.6.0", "", { "dependencies": { "lodash.debounce": "^4.0.8", "lodash.throttle": "^4.1.1" }, "peerDependencies": { "react": "^15.x.x || ^16.x.x || ^17.x.x || ^18.x.x", "react-dom": "^15.x.x || ^16.x.x || ^17.x.x || ^18.x.x" } }, "sha512-8KFkDTgjh+0+PVbH+cx0AgxLGbdTsxWMnxXzU5HEUztqewk9ufQAu8cstjZhyvtMIPsdMcPZfA0WAa7HtjQbBQ=="],
-
"react-lifecycles-compat": ["react-lifecycles-compat@3.0.4", "", {}, "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="],
"react-markdown": ["react-markdown@9.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "devlop": "^1.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" }, "peerDependencies": { "@types/react": ">=18", "react": ">=18" } }, "sha512-186Gw/vF1uRkydbsOIkcGXw7aHq0sZOCRFFjGrr7b9+nVZg4UfA4enXCaxm4fUzecU38sWfrNDitGhshuU7rdg=="],
- "react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="],
+ "react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="],
- "react-remove-scroll": ["react-remove-scroll@2.7.1", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA=="],
+ "react-remove-scroll": ["react-remove-scroll@2.5.5", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.3", "react-style-singleton": "^2.2.1", "tslib": "^2.1.0", "use-callback-ref": "^1.3.0", "use-sidecar": "^1.1.2" }, "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw=="],
"react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="],
"react-resizable-panels": ["react-resizable-panels@3.0.6", "", { "peerDependencies": { "react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-b3qKHQ3MLqOgSS+FRYKapNkJZf5EQzuf6+RLiq1/IlTHw99YrZ2NJZLk4hQIzTnnIkRg2LUqyVinu6YWWpUYew=="],
- "react-router": ["react-router@6.22.0", "", { "dependencies": { "@remix-run/router": "1.15.0" }, "peerDependencies": { "react": ">=16.8" } }, "sha512-q2yemJeg6gw/YixRlRnVx6IRJWZD6fonnfZhN1JIOhV2iJCPeRNSH3V1ISwHf+JWcESzLC3BOLD1T07tmO5dmg=="],
+ "react-router": ["react-router@6.30.3", "", { "dependencies": { "@remix-run/router": "1.23.2" }, "peerDependencies": { "react": ">=16.8" } }, "sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw=="],
- "react-router-dom": ["react-router-dom@6.22.0", "", { "dependencies": { "@remix-run/router": "1.15.0", "react-router": "6.22.0" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-z2w+M4tH5wlcLmH3BMMOMdrtrJ9T3oJJNsAlBJbwk+8Syxd5WFJ7J5dxMEW0/GEXD1BBis4uXRrNIz3mORr0ag=="],
+ "react-router-dom": ["react-router-dom@6.30.3", "", { "dependencies": { "@remix-run/router": "1.23.2", "react-router": "6.30.3" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag=="],
"react-speech-recognition": ["react-speech-recognition@3.10.0", "", { "peerDependencies": { "react": ">=16.8.0" } }, "sha512-EVSr4Ik8l9urwdPiK2r0+ADrLyDDrjB0qBRdUWO+w2MfwEBrj6NuRmy1GD3x7BU/V6/hab0pl8Lupen0zwlJyw=="],
@@ -4035,8 +4301,6 @@
"readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
- "readable-web-to-node-stream": ["readable-web-to-node-stream@3.0.2", "", { "dependencies": { "readable-stream": "^3.6.0" } }, "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw=="],
-
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
"recoil": ["recoil@0.7.7", "", { "dependencies": { "hamt_plus": "1.0.2" }, "peerDependencies": { "react": ">=16.13.1" } }, "sha512-8Og5KPQW9LwC577Vc7Ug2P0vQshkv1y3zG3tSSkWMqkWSwHmE+by06L8JtnGocjW6gcCvfwB3YtrJG6/tWivNQ=="],
@@ -4057,8 +4321,6 @@
"regenerator-runtime": ["regenerator-runtime@0.14.1", "", {}, "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="],
- "regenerator-transform": ["regenerator-transform@0.15.2", "", { "dependencies": { "@babel/runtime": "^7.8.4" } }, "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg=="],
-
"regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", "get-proto": "^1.0.1", "gopd": "^1.2.0", "set-function-name": "^2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="],
"regexpu-core": ["regexpu-core@6.2.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.0", "regjsgen": "^0.8.0", "regjsparser": "^0.12.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" } }, "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA=="],
@@ -4097,8 +4359,6 @@
"requireindex": ["requireindex@1.1.0", "", {}, "sha512-LBnkqsDE7BZKvqylbmn7lTIVdpx4K/QCduRATpO5R+wtPmky/a8pN1bO2D6wXppn1497AJF9mNjqAXr6bdl9jg=="],
- "requires-port": ["requires-port@1.0.0", "", {}, "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="],
-
"resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="],
"resolve-cwd": ["resolve-cwd@3.0.0", "", { "dependencies": { "resolve-from": "^5.0.0" } }, "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg=="],
@@ -4115,11 +4375,13 @@
"rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="],
- "rimraf": ["rimraf@6.1.2", "", { "dependencies": { "glob": "^13.0.0", "package-json-from-dist": "^1.0.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-cFCkPslJv7BAXJsYlK1dZsbP8/ZNLkCAQ0bi1hf5EKX2QHegmDFEFA6QhuYJlk7UDdc+02JjO80YSOrWPpw06g=="],
+ "rimraf": ["rimraf@6.1.3", "", { "dependencies": { "glob": "^13.0.3", "package-json-from-dist": "^1.0.1" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA=="],
"ripemd160": ["ripemd160@2.0.2", "", { "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1" } }, "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA=="],
- "rollup": ["rollup@4.37.0", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.37.0", "@rollup/rollup-android-arm64": "4.37.0", "@rollup/rollup-darwin-arm64": "4.37.0", "@rollup/rollup-darwin-x64": "4.37.0", "@rollup/rollup-freebsd-arm64": "4.37.0", "@rollup/rollup-freebsd-x64": "4.37.0", "@rollup/rollup-linux-arm-gnueabihf": "4.37.0", "@rollup/rollup-linux-arm-musleabihf": "4.37.0", "@rollup/rollup-linux-arm64-gnu": "4.37.0", "@rollup/rollup-linux-arm64-musl": "4.37.0", "@rollup/rollup-linux-loongarch64-gnu": "4.37.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.37.0", "@rollup/rollup-linux-riscv64-gnu": "4.37.0", "@rollup/rollup-linux-riscv64-musl": "4.37.0", "@rollup/rollup-linux-s390x-gnu": "4.37.0", "@rollup/rollup-linux-x64-gnu": "4.37.0", "@rollup/rollup-linux-x64-musl": "4.37.0", "@rollup/rollup-win32-arm64-msvc": "4.37.0", "@rollup/rollup-win32-ia32-msvc": "4.37.0", "@rollup/rollup-win32-x64-msvc": "4.37.0", "fsevents": "~2.3.2" }, "bin": "dist/bin/rollup" }, "sha512-iAtQy/L4QFU+rTJ1YUjXqJOJzuwEghqWzCEYD2FEghT7Gsy1VdABntrO4CLopA5IkflTyqNiLNwPcOJ3S7UKLg=="],
+ "robust-predicates": ["robust-predicates@3.0.2", "", {}, "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg=="],
+
+ "rollup": ["rollup@4.59.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.59.0", "@rollup/rollup-android-arm64": "4.59.0", "@rollup/rollup-darwin-arm64": "4.59.0", "@rollup/rollup-darwin-x64": "4.59.0", "@rollup/rollup-freebsd-arm64": "4.59.0", "@rollup/rollup-freebsd-x64": "4.59.0", "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", "@rollup/rollup-linux-arm-musleabihf": "4.59.0", "@rollup/rollup-linux-arm64-gnu": "4.59.0", "@rollup/rollup-linux-arm64-musl": "4.59.0", "@rollup/rollup-linux-loong64-gnu": "4.59.0", "@rollup/rollup-linux-loong64-musl": "4.59.0", "@rollup/rollup-linux-ppc64-gnu": "4.59.0", "@rollup/rollup-linux-ppc64-musl": "4.59.0", "@rollup/rollup-linux-riscv64-gnu": "4.59.0", "@rollup/rollup-linux-riscv64-musl": "4.59.0", "@rollup/rollup-linux-s390x-gnu": "4.59.0", "@rollup/rollup-linux-x64-gnu": "4.59.0", "@rollup/rollup-linux-x64-musl": "4.59.0", "@rollup/rollup-openbsd-x64": "4.59.0", "@rollup/rollup-openharmony-arm64": "4.59.0", "@rollup/rollup-win32-arm64-msvc": "4.59.0", "@rollup/rollup-win32-ia32-msvc": "4.59.0", "@rollup/rollup-win32-x64-gnu": "4.59.0", "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg=="],
"rollup-plugin-peer-deps-external": ["rollup-plugin-peer-deps-external@2.2.4", "", { "peerDependencies": { "rollup": "*" } }, "sha512-AWdukIM1+k5JDdAqV/Cxd+nejvno2FVLVeZ74NKggm3Q5s9cbbcOgUPGdbxPi4BXu7xGaZ8HG12F+thImYu/0g=="],
@@ -4129,6 +4391,8 @@
"rollup-pluginutils": ["rollup-pluginutils@2.8.2", "", { "dependencies": { "estree-walker": "^0.6.1" } }, "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ=="],
+ "roughjs": ["roughjs@4.6.6", "", { "dependencies": { "hachure-fill": "^0.5.2", "path-data-parser": "^0.1.0", "points-on-curve": "^0.2.0", "points-on-path": "^0.2.1" } }, "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ=="],
+
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
"rrweb-cssom": ["rrweb-cssom@0.8.0", "", {}, "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw=="],
@@ -4137,6 +4401,8 @@
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
+ "rw": ["rw@1.3.3", "", {}, "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="],
+
"safe-array-concat": ["safe-array-concat@1.1.3", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "has-symbols": "^1.1.0", "isarray": "^2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="],
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
@@ -4157,15 +4423,13 @@
"scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
- "schema-utils": ["schema-utils@3.3.0", "", { "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", "ajv-keywords": "^3.5.2" } }, "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg=="],
-
"seedrandom": ["seedrandom@3.0.5", "", {}, "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg=="],
"semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="],
- "serialize-javascript": ["serialize-javascript@6.0.2", "", { "dependencies": { "randombytes": "^2.1.0" } }, "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g=="],
+ "serialize-javascript": ["serialize-javascript@7.0.4", "", {}, "sha512-DuGdB+Po43Q5Jxwpzt1lhyFSYKryqoNjQSA9M92tyw0lyHIOur+XCalOUe0KTJpyqzT8+fQ5A0Jf7vCx/NKmIg=="],
"serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="],
@@ -4237,6 +4501,8 @@
"standard-as-callback": ["standard-as-callback@2.1.0", "", {}, "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="],
+ "state-local": ["state-local@1.0.7", "", {}, "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w=="],
+
"static-browser-server": ["static-browser-server@1.0.3", "", { "dependencies": { "@open-draft/deferred-promise": "^2.1.0", "dotenv": "^16.0.3", "mime-db": "^1.52.0", "outvariant": "^1.3.0" } }, "sha512-ZUyfgGDdFRbZGGJQ1YhiM930Yczz5VlbJObrQLlk24+qNHVQx4OlLcYswEUo3bIyNAbQUIUR9Yr5/Hqjzqb4zA=="],
"statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
@@ -4297,9 +4563,9 @@
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
- "strnum": ["strnum@1.0.5", "", {}, "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA=="],
+ "strnum": ["strnum@2.2.0", "", {}, "sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg=="],
- "strtok3": ["strtok3@7.0.0", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^5.0.0" } }, "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ=="],
+ "strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="],
"style-inject": ["style-inject@0.3.0", "", {}, "sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw=="],
@@ -4309,6 +4575,8 @@
"stylehacks": ["stylehacks@5.1.1", "", { "dependencies": { "browserslist": "^4.21.4", "postcss-selector-parser": "^6.0.4" }, "peerDependencies": { "postcss": "^8.2.15" } }, "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw=="],
+ "stylis": ["stylis@4.3.6", "", {}, "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ=="],
+
"sucrase": ["sucrase@3.35.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA=="],
"superagent": ["superagent@9.0.2", "", { "dependencies": { "component-emitter": "^1.3.0", "cookiejar": "^2.1.4", "debug": "^4.3.4", "fast-safe-stringify": "^2.1.1", "form-data": "^4.0.0", "formidable": "^3.5.1", "methods": "^1.1.2", "mime": "2.6.0", "qs": "^6.11.0" } }, "sha512-xuW7dzkUpcJq7QnhOsnNUgtYp3xRwpt2F7abdRYIpCsAt0hhUqia0EdxyXZQQpNmGtsCzYHryaKSV3q3GJnq7w=="],
@@ -4321,7 +4589,9 @@
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
- "svgo": ["svgo@2.8.0", "", { "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", "css-select": "^4.1.3", "css-tree": "^1.1.3", "csso": "^4.2.0", "picocolors": "^1.0.0", "stable": "^0.1.8" }, "bin": "bin/svgo" }, "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg=="],
+ "svgo": ["svgo@2.8.2", "", { "dependencies": { "commander": "^7.2.0", "css-select": "^4.1.3", "css-tree": "^1.1.3", "csso": "^4.2.0", "picocolors": "^1.0.0", "sax": "^1.5.0", "stable": "^0.1.8" }, "bin": "./bin/svgo" }, "sha512-TyzE4NVGLUFy+H/Uy4N6c3G0HEeprsVfge6Lmq+0FdQQ/zqoVYB62IsBZORsiL+o96s6ff/V6/3UQo/C0cgCAA=="],
+
+ "swr": ["swr@2.4.1", "", { "dependencies": { "dequal": "^2.0.3", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-2CC6CiKQtEwaEeNiqWTAw9PGykW8SR5zZX8MZk6TeAvEAnVS7Visz8WzphqgtQ8v2xz/4Q5K+j+SeMaKXeeQIA=="],
"symbol-tree": ["symbol-tree@3.2.4", "", {}, "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="],
@@ -4349,8 +4619,6 @@
"terser": ["terser@5.27.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": "bin/terser" }, "sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A=="],
- "terser-webpack-plugin": ["terser-webpack-plugin@5.3.10", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.1", "terser": "^5.26.0" }, "peerDependencies": { "webpack": "^5.1.0" } }, "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w=="],
-
"test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="],
"text-decoder": ["text-decoder@1.2.3", "", { "dependencies": { "b4a": "^1.6.4" } }, "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA=="],
@@ -4361,13 +4629,13 @@
"thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="],
- "tiktoken": ["tiktoken@1.0.15", "", {}, "sha512-sCsrq/vMWUSEW29CJLNmPvWxlVp7yh2tlkAjpJltIKqp5CKf98ZNpdeHRmAlPVFlGEbswDc6SmI8vz64W/qErw=="],
-
"timers-browserify": ["timers-browserify@2.0.12", "", { "dependencies": { "setimmediate": "^1.0.4" } }, "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ=="],
"tiny-emitter": ["tiny-emitter@2.1.0", "", {}, "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="],
- "tinyglobby": ["tinyglobby@0.2.13", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw=="],
+ "tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="],
+
+ "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
"tldts": ["tldts@6.1.86", "", { "dependencies": { "tldts-core": "^6.1.86" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ=="],
@@ -4383,7 +4651,7 @@
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
- "token-types": ["token-types@5.0.1", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg=="],
+ "token-types": ["token-types@6.1.2", "", { "dependencies": { "@borewit/text-codec": "^0.2.1", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww=="],
"touch": ["touch@3.1.0", "", { "dependencies": { "nopt": "~1.0.10" }, "bin": { "nodetouch": "bin/nodetouch.js" } }, "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA=="],
@@ -4403,8 +4671,12 @@
"ts-api-utils": ["ts-api-utils@2.0.1", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w=="],
+ "ts-dedent": ["ts-dedent@2.2.0", "", {}, "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ=="],
+
"ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="],
+ "ts-md5": ["ts-md5@1.3.1", "", {}, "sha512-DiwiXfwvcTeZ5wCE0z+2A9EseZsztaiZtGrtSaY5JOD7ekPnR/GoIVD5gXZAlK9Na9Kvpo9Waz5rW64WKAWApg=="],
+
"ts-node": ["ts-node@10.9.2", "", { "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", "@tsconfig/node16": "^1.0.2", "acorn": "^8.4.1", "acorn-walk": "^8.1.1", "arg": "^4.1.0", "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" }, "peerDependencies": { "@swc/core": ">=1.2.50", "@swc/wasm": ">=1.2.50", "@types/node": "*", "typescript": ">=2.7" }, "optionalPeers": ["@swc/core", "@swc/wasm"], "bin": { "ts-node": "dist/bin.js", "ts-node-cwd": "dist/bin-cwd.js", "ts-node-esm": "dist/bin-esm.js", "ts-node-script": "dist/bin-script.js", "ts-node-transpile-only": "dist/bin-transpile.js", "ts-script": "dist/bin-script-deprecated.js" } }, "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ=="],
"tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="],
@@ -4413,6 +4685,20 @@
"tty-browserify": ["tty-browserify@0.0.1", "", {}, "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw=="],
+ "turbo": ["turbo@2.8.14", "", { "optionalDependencies": { "turbo-darwin-64": "2.8.14", "turbo-darwin-arm64": "2.8.14", "turbo-linux-64": "2.8.14", "turbo-linux-arm64": "2.8.14", "turbo-windows-64": "2.8.14", "turbo-windows-arm64": "2.8.14" }, "bin": { "turbo": "bin/turbo" } }, "sha512-UCTxeMNYT1cKaHiIFdLCQ7ulI+jw5i5uOnJOrRXsgUD7G3+OjlUjwVd7JfeVt2McWSVGjYA3EVW/v1FSsJ5DtA=="],
+
+ "turbo-darwin-64": ["turbo-darwin-64@2.8.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-9sFi7n2lLfEsGWi5OEoA/eTtQU2BPKtzSYKqufMtDeRmqMT9vKjbv9gJCRkllSVE9BOXA0qXC3diyX8V8rKIKw=="],
+
+ "turbo-darwin-arm64": ["turbo-darwin-arm64@2.8.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-aS4yJuy6A1PCLws+PJpZP0qCURG8Y5iVx13z/WAbKyeDTY6W6PiGgcEllSaeLGxyn++382ztN/EZH85n2zZ6VQ=="],
+
+ "turbo-linux-64": ["turbo-linux-64@2.8.14", "", { "os": "linux", "cpu": "x64" }, "sha512-XC6wPUDJkakjhNLaS0NrHDMiujRVjH+naEAwvKLArgqRaFkNxjmyNDRM4eu3soMMFmjym6NTxYaF74rvET+Orw=="],
+
+ "turbo-linux-arm64": ["turbo-linux-arm64@2.8.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-ChfE7isyVNjZrVSPDwcfqcHLG/FuIBbOFxnt1FM8vSuBGzHAs8AlTdwFNIxlEMJfZ8Ad9mdMxdmsCUPIWiQ6cg=="],
+
+ "turbo-windows-64": ["turbo-windows-64@2.8.14", "", { "os": "win32", "cpu": "x64" }, "sha512-FTbIeQL1ycLFW2t9uQNMy+bRSzi3Xhwun/e7ZhFBdM+U0VZxxrtfYEBM9CHOejlfqomk6Jh7aRz0sJoqYn39Hg=="],
+
+ "turbo-windows-arm64": ["turbo-windows-arm64@2.8.14", "", { "os": "win32", "cpu": "arm64" }, "sha512-KgZX12cTyhY030qS7ieT8zRkhZZE2VWJasDFVUSVVn17nR7IShpv68/7j5UqJNeRLIGF1XPK0phsP5V5yw3how=="],
+
"type": ["type@2.7.3", "", {}, "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ=="],
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
@@ -4441,19 +4727,25 @@
"ua-parser-js": ["ua-parser-js@1.0.37", "", {}, "sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ=="],
+ "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="],
+
"uglify-js": ["uglify-js@3.17.4", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g=="],
"uid-safe": ["uid-safe@2.1.5", "", { "dependencies": { "random-bytes": "~1.0.0" } }, "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA=="],
"uid2": ["uid2@0.0.4", "", {}, "sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA=="],
+ "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="],
+
"unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="],
"undefsafe": ["undefsafe@2.0.5", "", {}, "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA=="],
- "undici": ["undici@7.16.0", "", {}, "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g=="],
+ "underscore": ["underscore@1.13.8", "", {}, "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ=="],
- "undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+ "undici": ["undici@7.24.4", "", {}, "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w=="],
+
+ "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
"unicode-canonical-property-names-ecmascript": ["unicode-canonical-property-names-ecmascript@2.0.1", "", {}, "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg=="],
@@ -4495,10 +4787,6 @@
"url": ["url@0.11.4", "", { "dependencies": { "punycode": "^1.4.1", "qs": "^6.12.3" } }, "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg=="],
- "url-parse": ["url-parse@1.5.10", "", { "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" } }, "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ=="],
-
- "url-template": ["url-template@2.0.8", "", {}, "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw=="],
-
"use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="],
"use-composed-ref": ["use-composed-ref@1.3.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ=="],
@@ -4535,36 +4823,42 @@
"vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="],
- "vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "tsx"], "bin": "bin/vite.js" }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="],
+ "vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="],
"vite-plugin-compression2": ["vite-plugin-compression2@2.2.1", "", { "dependencies": { "@rollup/pluginutils": "^5.1.0", "tar-mini": "^0.2.0" } }, "sha512-LMDkgheJaFBmb8cB8ymgUpXHXnd3m4kmjEInvp59fOZMSaT/9oDUtqpO0ihr4ExGsnWfYcRe13/TNN3BEk2t/g=="],
- "vite-plugin-node-polyfills": ["vite-plugin-node-polyfills@0.23.0", "", { "dependencies": { "@rollup/plugin-inject": "^5.0.5", "node-stdlib-browser": "^1.2.0" }, "peerDependencies": { "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" } }, "sha512-4n+Ys+2bKHQohPBKigFlndwWQ5fFKwaGY6muNDMTb0fSQLyBzS+jjUNRZG9sKF0S/Go4ApG6LFnUGopjkILg3w=="],
+ "vite-plugin-node-polyfills": ["vite-plugin-node-polyfills@0.25.0", "", { "dependencies": { "@rollup/plugin-inject": "^5.0.5", "node-stdlib-browser": "^1.3.1" }, "peerDependencies": { "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-rHZ324W3LhfGPxWwQb2N048TThB6nVvnipsqBUJEzh3R9xeK9KI3si+GMQxCuAcpPJBVf0LpDtJ+beYzB3/chg=="],
- "vite-plugin-pwa": ["vite-plugin-pwa@0.21.2", "", { "dependencies": { "debug": "^4.3.6", "pretty-bytes": "^6.1.1", "tinyglobby": "^0.2.10", "workbox-build": "^7.3.0", "workbox-window": "^7.3.0" }, "peerDependencies": { "@vite-pwa/assets-generator": "^0.2.6", "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", "workbox-build": "^7.3.0", "workbox-window": "^7.3.0" }, "optionalPeers": ["@vite-pwa/assets-generator"] }, "sha512-vFhH6Waw8itNu37hWUJxL50q+CBbNcMVzsKaYHQVrfxTt3ihk3PeLO22SbiP1UNWzcEPaTQv+YVxe4G0KOjAkg=="],
+ "vite-plugin-pwa": ["vite-plugin-pwa@1.2.0", "", { "dependencies": { "debug": "^4.3.6", "pretty-bytes": "^6.1.1", "tinyglobby": "^0.2.10", "workbox-build": "^7.4.0", "workbox-window": "^7.4.0" }, "peerDependencies": { "@vite-pwa/assets-generator": "^1.0.0", "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" }, "optionalPeers": ["@vite-pwa/assets-generator"] }, "sha512-a2xld+SJshT9Lgcv8Ji4+srFJL4k/1bVbd1x06JIkvecpQkwkvCncD1+gSzcdm3s+owWLpMJerG3aN5jupJEVw=="],
"vm-browserify": ["vm-browserify@1.1.2", "", {}, "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ=="],
"void-elements": ["void-elements@3.1.0", "", {}, "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="],
+ "vscode-jsonrpc": ["vscode-jsonrpc@8.2.0", "", {}, "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="],
+
+ "vscode-languageserver": ["vscode-languageserver@9.0.1", "", { "dependencies": { "vscode-languageserver-protocol": "3.17.5" }, "bin": { "installServerIntoExtension": "bin/installServerIntoExtension" } }, "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g=="],
+
+ "vscode-languageserver-protocol": ["vscode-languageserver-protocol@3.17.5", "", { "dependencies": { "vscode-jsonrpc": "8.2.0", "vscode-languageserver-types": "3.17.5" } }, "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg=="],
+
+ "vscode-languageserver-textdocument": ["vscode-languageserver-textdocument@1.0.12", "", {}, "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA=="],
+
+ "vscode-languageserver-types": ["vscode-languageserver-types@3.17.5", "", {}, "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="],
+
+ "vscode-uri": ["vscode-uri@3.1.0", "", {}, "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ=="],
+
"w3c-keyname": ["w3c-keyname@2.2.8", "", {}, "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="],
"w3c-xmlserializer": ["w3c-xmlserializer@5.0.0", "", { "dependencies": { "xml-name-validator": "^5.0.0" } }, "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA=="],
"walker": ["walker@1.0.8", "", { "dependencies": { "makeerror": "1.0.12" } }, "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ=="],
- "watchpack": ["watchpack@2.4.2", "", { "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" } }, "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw=="],
-
"web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="],
"web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
"webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
- "webpack": ["webpack@5.94.0", "", { "dependencies": { "@types/estree": "^1.0.5", "@webassemblyjs/ast": "^1.12.1", "@webassemblyjs/wasm-edit": "^1.12.1", "@webassemblyjs/wasm-parser": "^1.12.1", "acorn": "^8.7.1", "acorn-import-attributes": "^1.9.5", "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^3.2.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.10", "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "bin": "bin/webpack.js" }, "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg=="],
-
- "webpack-sources": ["webpack-sources@3.2.3", "", {}, "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w=="],
-
"websocket-driver": ["websocket-driver@0.7.4", "", { "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", "websocket-extensions": ">=0.1.1" } }, "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg=="],
"websocket-extensions": ["websocket-extensions@0.1.4", "", {}, "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg=="],
@@ -4595,37 +4889,37 @@
"wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="],
- "workbox-background-sync": ["workbox-background-sync@7.3.0", "", { "dependencies": { "idb": "^7.0.1", "workbox-core": "7.3.0" } }, "sha512-PCSk3eK7Mxeuyatb22pcSx9dlgWNv3+M8PqPaYDokks8Y5/FX4soaOqj3yhAZr5k6Q5JWTOMYgaJBpbw11G9Eg=="],
+ "workbox-background-sync": ["workbox-background-sync@7.4.0", "", { "dependencies": { "idb": "^7.0.1", "workbox-core": "7.4.0" } }, "sha512-8CB9OxKAgKZKyNMwfGZ1XESx89GryWTfI+V5yEj8sHjFH8MFelUwYXEyldEK6M6oKMmn807GoJFUEA1sC4XS9w=="],
- "workbox-broadcast-update": ["workbox-broadcast-update@7.3.0", "", { "dependencies": { "workbox-core": "7.3.0" } }, "sha512-T9/F5VEdJVhwmrIAE+E/kq5at2OY6+OXXgOWQevnubal6sO92Gjo24v6dCVwQiclAF5NS3hlmsifRrpQzZCdUA=="],
+ "workbox-broadcast-update": ["workbox-broadcast-update@7.4.0", "", { "dependencies": { "workbox-core": "7.4.0" } }, "sha512-+eZQwoktlvo62cI0b+QBr40v5XjighxPq3Fzo9AWMiAosmpG5gxRHgTbGGhaJv/q/MFVxwFNGh/UwHZ/8K88lA=="],
- "workbox-build": ["workbox-build@7.3.0", "", { "dependencies": { "@apideck/better-ajv-errors": "^0.3.1", "@babel/core": "^7.24.4", "@babel/preset-env": "^7.11.0", "@babel/runtime": "^7.11.2", "@rollup/plugin-babel": "^5.2.0", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-replace": "^2.4.1", "@rollup/plugin-terser": "^0.4.3", "@surma/rollup-plugin-off-main-thread": "^2.2.3", "ajv": "^8.6.0", "common-tags": "^1.8.0", "fast-json-stable-stringify": "^2.1.0", "fs-extra": "^9.0.1", "glob": "^7.1.6", "lodash": "^4.17.20", "pretty-bytes": "^5.3.0", "rollup": "^2.43.1", "source-map": "^0.8.0-beta.0", "stringify-object": "^3.3.0", "strip-comments": "^2.0.1", "tempy": "^0.6.0", "upath": "^1.2.0", "workbox-background-sync": "7.3.0", "workbox-broadcast-update": "7.3.0", "workbox-cacheable-response": "7.3.0", "workbox-core": "7.3.0", "workbox-expiration": "7.3.0", "workbox-google-analytics": "7.3.0", "workbox-navigation-preload": "7.3.0", "workbox-precaching": "7.3.0", "workbox-range-requests": "7.3.0", "workbox-recipes": "7.3.0", "workbox-routing": "7.3.0", "workbox-strategies": "7.3.0", "workbox-streams": "7.3.0", "workbox-sw": "7.3.0", "workbox-window": "7.3.0" } }, "sha512-JGL6vZTPlxnlqZRhR/K/msqg3wKP+m0wfEUVosK7gsYzSgeIxvZLi1ViJJzVL7CEeI8r7rGFV973RiEqkP3lWQ=="],
+ "workbox-build": ["workbox-build@7.4.0", "", { "dependencies": { "@apideck/better-ajv-errors": "^0.3.1", "@babel/core": "^7.24.4", "@babel/preset-env": "^7.11.0", "@babel/runtime": "^7.11.2", "@rollup/plugin-babel": "^5.2.0", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-replace": "^2.4.1", "@rollup/plugin-terser": "^0.4.3", "@surma/rollup-plugin-off-main-thread": "^2.2.3", "ajv": "^8.6.0", "common-tags": "^1.8.0", "fast-json-stable-stringify": "^2.1.0", "fs-extra": "^9.0.1", "glob": "^11.0.1", "lodash": "^4.17.20", "pretty-bytes": "^5.3.0", "rollup": "^2.79.2", "source-map": "^0.8.0-beta.0", "stringify-object": "^3.3.0", "strip-comments": "^2.0.1", "tempy": "^0.6.0", "upath": "^1.2.0", "workbox-background-sync": "7.4.0", "workbox-broadcast-update": "7.4.0", "workbox-cacheable-response": "7.4.0", "workbox-core": "7.4.0", "workbox-expiration": "7.4.0", "workbox-google-analytics": "7.4.0", "workbox-navigation-preload": "7.4.0", "workbox-precaching": "7.4.0", "workbox-range-requests": "7.4.0", "workbox-recipes": "7.4.0", "workbox-routing": "7.4.0", "workbox-strategies": "7.4.0", "workbox-streams": "7.4.0", "workbox-sw": "7.4.0", "workbox-window": "7.4.0" } }, "sha512-Ntk1pWb0caOFIvwz/hfgrov/OJ45wPEhI5PbTywQcYjyZiVhT3UrwwUPl6TRYbTm4moaFYithYnl1lvZ8UjxcA=="],
- "workbox-cacheable-response": ["workbox-cacheable-response@7.3.0", "", { "dependencies": { "workbox-core": "7.3.0" } }, "sha512-eAFERIg6J2LuyELhLlmeRcJFa5e16Mj8kL2yCDbhWE+HUun9skRQrGIFVUagqWj4DMaaPSMWfAolM7XZZxNmxA=="],
+ "workbox-cacheable-response": ["workbox-cacheable-response@7.4.0", "", { "dependencies": { "workbox-core": "7.4.0" } }, "sha512-0Fb8795zg/x23ISFkAc7lbWes6vbw34DGFIMw31cwuHPgDEC/5EYm6m/ZkylLX0EnEbbOyOCLjKgFS/Z5g0HeQ=="],
- "workbox-core": ["workbox-core@7.3.0", "", {}, "sha512-Z+mYrErfh4t3zi7NVTvOuACB0A/jA3bgxUN3PwtAVHvfEsZxV9Iju580VEETug3zYJRc0Dmii/aixI/Uxj8fmw=="],
+ "workbox-core": ["workbox-core@7.4.0", "", {}, "sha512-6BMfd8tYEnN4baG4emG9U0hdXM4gGuDU3ectXuVHnj71vwxTFI7WOpQJC4siTOlVtGqCUtj0ZQNsrvi6kZZTAQ=="],
- "workbox-expiration": ["workbox-expiration@7.3.0", "", { "dependencies": { "idb": "^7.0.1", "workbox-core": "7.3.0" } }, "sha512-lpnSSLp2BM+K6bgFCWc5bS1LR5pAwDWbcKt1iL87/eTSJRdLdAwGQznZE+1czLgn/X05YChsrEegTNxjM067vQ=="],
+ "workbox-expiration": ["workbox-expiration@7.4.0", "", { "dependencies": { "idb": "^7.0.1", "workbox-core": "7.4.0" } }, "sha512-V50p4BxYhtA80eOvulu8xVfPBgZbkxJ1Jr8UUn0rvqjGhLDqKNtfrDfjJKnLz2U8fO2xGQJTx/SKXNTzHOjnHw=="],
- "workbox-google-analytics": ["workbox-google-analytics@7.3.0", "", { "dependencies": { "workbox-background-sync": "7.3.0", "workbox-core": "7.3.0", "workbox-routing": "7.3.0", "workbox-strategies": "7.3.0" } }, "sha512-ii/tSfFdhjLHZ2BrYgFNTrb/yk04pw2hasgbM70jpZfLk0vdJAXgaiMAWsoE+wfJDNWoZmBYY0hMVI0v5wWDbg=="],
+ "workbox-google-analytics": ["workbox-google-analytics@7.4.0", "", { "dependencies": { "workbox-background-sync": "7.4.0", "workbox-core": "7.4.0", "workbox-routing": "7.4.0", "workbox-strategies": "7.4.0" } }, "sha512-MVPXQslRF6YHkzGoFw1A4GIB8GrKym/A5+jYDUSL+AeJw4ytQGrozYdiZqUW1TPQHW8isBCBtyFJergUXyNoWQ=="],
- "workbox-navigation-preload": ["workbox-navigation-preload@7.3.0", "", { "dependencies": { "workbox-core": "7.3.0" } }, "sha512-fTJzogmFaTv4bShZ6aA7Bfj4Cewaq5rp30qcxl2iYM45YD79rKIhvzNHiFj1P+u5ZZldroqhASXwwoyusnr2cg=="],
+ "workbox-navigation-preload": ["workbox-navigation-preload@7.4.0", "", { "dependencies": { "workbox-core": "7.4.0" } }, "sha512-etzftSgdQfjMcfPgbfaZCfM2QuR1P+4o8uCA2s4rf3chtKTq/Om7g/qvEOcZkG6v7JZOSOxVYQiOu6PbAZgU6w=="],
- "workbox-precaching": ["workbox-precaching@7.3.0", "", { "dependencies": { "workbox-core": "7.3.0", "workbox-routing": "7.3.0", "workbox-strategies": "7.3.0" } }, "sha512-ckp/3t0msgXclVAYaNndAGeAoWQUv7Rwc4fdhWL69CCAb2UHo3Cef0KIUctqfQj1p8h6aGyz3w8Cy3Ihq9OmIw=="],
+ "workbox-precaching": ["workbox-precaching@7.4.0", "", { "dependencies": { "workbox-core": "7.4.0", "workbox-routing": "7.4.0", "workbox-strategies": "7.4.0" } }, "sha512-VQs37T6jDqf1rTxUJZXRl3yjZMf5JX/vDPhmx2CPgDDKXATzEoqyRqhYnRoxl6Kr0rqaQlp32i9rtG5zTzIlNg=="],
- "workbox-range-requests": ["workbox-range-requests@7.3.0", "", { "dependencies": { "workbox-core": "7.3.0" } }, "sha512-EyFmM1KpDzzAouNF3+EWa15yDEenwxoeXu9bgxOEYnFfCxns7eAxA9WSSaVd8kujFFt3eIbShNqa4hLQNFvmVQ=="],
+ "workbox-range-requests": ["workbox-range-requests@7.4.0", "", { "dependencies": { "workbox-core": "7.4.0" } }, "sha512-3Vq854ZNuP6Y0KZOQWLaLC9FfM7ZaE+iuQl4VhADXybwzr4z/sMmnLgTeUZLq5PaDlcJBxYXQ3U91V7dwAIfvw=="],
- "workbox-recipes": ["workbox-recipes@7.3.0", "", { "dependencies": { "workbox-cacheable-response": "7.3.0", "workbox-core": "7.3.0", "workbox-expiration": "7.3.0", "workbox-precaching": "7.3.0", "workbox-routing": "7.3.0", "workbox-strategies": "7.3.0" } }, "sha512-BJro/MpuW35I/zjZQBcoxsctgeB+kyb2JAP5EB3EYzePg8wDGoQuUdyYQS+CheTb+GhqJeWmVs3QxLI8EBP1sg=="],
+ "workbox-recipes": ["workbox-recipes@7.4.0", "", { "dependencies": { "workbox-cacheable-response": "7.4.0", "workbox-core": "7.4.0", "workbox-expiration": "7.4.0", "workbox-precaching": "7.4.0", "workbox-routing": "7.4.0", "workbox-strategies": "7.4.0" } }, "sha512-kOkWvsAn4H8GvAkwfJTbwINdv4voFoiE9hbezgB1sb/0NLyTG4rE7l6LvS8lLk5QIRIto+DjXLuAuG3Vmt3cxQ=="],
- "workbox-routing": ["workbox-routing@7.3.0", "", { "dependencies": { "workbox-core": "7.3.0" } }, "sha512-ZUlysUVn5ZUzMOmQN3bqu+gK98vNfgX/gSTZ127izJg/pMMy4LryAthnYtjuqcjkN4HEAx1mdgxNiKJMZQM76A=="],
+ "workbox-routing": ["workbox-routing@7.4.0", "", { "dependencies": { "workbox-core": "7.4.0" } }, "sha512-C/ooj5uBWYAhAqwmU8HYQJdOjjDKBp9MzTQ+otpMmd+q0eF59K+NuXUek34wbL0RFrIXe/KKT+tUWcZcBqxbHQ=="],
- "workbox-strategies": ["workbox-strategies@7.3.0", "", { "dependencies": { "workbox-core": "7.3.0" } }, "sha512-tmZydug+qzDFATwX7QiEL5Hdf7FrkhjaF9db1CbB39sDmEZJg3l9ayDvPxy8Y18C3Y66Nrr9kkN1f/RlkDgllg=="],
+ "workbox-strategies": ["workbox-strategies@7.4.0", "", { "dependencies": { "workbox-core": "7.4.0" } }, "sha512-T4hVqIi5A4mHi92+5EppMX3cLaVywDp8nsyUgJhOZxcfSV/eQofcOA6/EMo5rnTNmNTpw0rUgjAI6LaVullPpg=="],
- "workbox-streams": ["workbox-streams@7.3.0", "", { "dependencies": { "workbox-core": "7.3.0", "workbox-routing": "7.3.0" } }, "sha512-SZnXucyg8x2Y61VGtDjKPO5EgPUG5NDn/v86WYHX+9ZqvAsGOytP0Jxp1bl663YUuMoXSAtsGLL+byHzEuMRpw=="],
+ "workbox-streams": ["workbox-streams@7.4.0", "", { "dependencies": { "workbox-core": "7.4.0", "workbox-routing": "7.4.0" } }, "sha512-QHPBQrey7hQbnTs5GrEVoWz7RhHJXnPT+12qqWM378orDMo5VMJLCkCM1cnCk+8Eq92lccx/VgRZ7WAzZWbSLg=="],
- "workbox-sw": ["workbox-sw@7.3.0", "", {}, "sha512-aCUyoAZU9IZtH05mn0ACUpyHzPs0lMeJimAYkQkBsOWiqaJLgusfDCR+yllkPkFRxWpZKF8vSvgHYeG7LwhlmA=="],
+ "workbox-sw": ["workbox-sw@7.4.0", "", {}, "sha512-ltU+Kr3qWR6BtbdlMnCjobZKzeV1hN+S6UvDywBrwM19TTyqA03X66dzw1tEIdJvQ4lYKkBFox6IAEhoSEZ8Xw=="],
- "workbox-window": ["workbox-window@7.3.0", "", { "dependencies": { "@types/trusted-types": "^2.0.2", "workbox-core": "7.3.0" } }, "sha512-qW8PDy16OV1UBaUNGlTVcepzrlzyzNW/ZJvFQQs2j2TzGsg6IKjcpZC1RSquqQnTOafl5pCj5bGfAHlCjOOjdA=="],
+ "workbox-window": ["workbox-window@7.4.0", "", { "dependencies": { "@types/trusted-types": "^2.0.2", "workbox-core": "7.4.0" } }, "sha512-/bIYdBLAVsNR3v7gYGaV4pQW3M3kEPx5E8vDxGvxo6khTrGtSSCS7QiFKv9ogzBgZiy0OXLP9zO28U/1nF1mfw=="],
"wrap-ansi": ["wrap-ansi@9.0.0", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q=="],
@@ -4637,6 +4931,8 @@
"ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="],
+ "xlsx": ["xlsx@https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz", { "bin": { "xlsx": "./bin/xlsx.njs" } }],
+
"xml": ["xml@1.0.1", "", {}, "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw=="],
"xml-crypto": ["xml-crypto@6.1.2", "", { "dependencies": { "@xmldom/is-dom-node": "^1.0.1", "@xmldom/xmldom": "^0.8.10", "xpath": "^0.0.33" } }, "sha512-leBOVQdVi8FvPJrMYoum7Ici9qyxfE4kVi+AkpUoYCSXaQF4IlBm1cneTK9oAxR61LpYxTx7lNcsnBIeRpGW2w=="],
@@ -4647,7 +4943,7 @@
"xml2js": ["xml2js@0.6.2", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA=="],
- "xmlbuilder": ["xmlbuilder@15.1.1", "", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="],
+ "xmlbuilder": ["xmlbuilder@10.1.1", "", {}, "sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg=="],
"xmlchars": ["xmlchars@2.2.0", "", {}, "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="],
@@ -4671,11 +4967,9 @@
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
- "youtube-transcript": ["youtube-transcript@1.2.1", "", {}, "sha512-TvEGkBaajKw+B6y91ziLuBLsa5cawgowou+Bk0ciGpjELDfAzSzTGXaZmeSSkUeknCPpEr/WGApOHDwV7V+Y9Q=="],
-
"zod": ["zod@3.25.67", "", {}, "sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw=="],
- "zod-to-json-schema": ["zod-to-json-schema@3.24.3", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-HIAfWdYIt1sssHfYZFCXp4rU1w2r8hVVXYIlmoa0r0gABLs5di3RCqPU5DDROogVz1pAdYBaz7HK5n9pSUNs3A=="],
+ "zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="],
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
@@ -4735,6 +5029,12 @@
"@aws-sdk/client-bedrock-agent-runtime/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.4", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-d5T7ZS3J/r8P/PDjgmCcutmNxnSRvPH1U6iHeXjzI50sMr78GLmFcrczLw33Ap92oEKqa4CLrkAPeSSOqvGdUA=="],
+
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/eventstream-serde-config-resolver": ["@smithy/eventstream-serde-config-resolver@4.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-lxfDT0UuSc1HqltOGsTEAlZ6H29gpfDSdEPTapD5G63RbnYToZ+ezjzdonCCH90j5tRRCw3aLXVbiZaBW3VRVg=="],
+
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/eventstream-serde-node": ["@smithy/eventstream-serde-node@4.2.4", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-TPhiGByWnYyzcpU/K3pO5V7QgtXYpE0NaJPEZBCa1Y5jlw5SjqzMSbFiLb+ZkJhqoQc0ImGyVINqnq1ze0ZRcQ=="],
+
"@aws-sdk/client-bedrock-agent-runtime/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
"@aws-sdk/client-bedrock-agent-runtime/@smithy/hash-node": ["@smithy/hash-node@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw=="],
@@ -4755,8 +5055,12 @@
"@aws-sdk/client-bedrock-agent-runtime/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/protocol-http": ["@smithy/protocol-http@5.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw=="],
+
"@aws-sdk/client-bedrock-agent-runtime/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/types": ["@smithy/types@4.8.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-N0Zn0OT1zc+NA+UVfkYqQzviRh5ucWwO7mBV3TmHHprMnfcJNfhlPicDkBHi0ewbh+y3evR6cNAW0Raxvb01NA=="],
+
"@aws-sdk/client-bedrock-agent-runtime/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
"@aws-sdk/client-bedrock-agent-runtime/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
@@ -4771,88 +5075,12 @@
"@aws-sdk/client-bedrock-agent-runtime/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
+
"@aws-sdk/client-bedrock-agent-runtime/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
"@aws-sdk/client-bedrock-agent-runtime/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/core": ["@aws-sdk/core@3.947.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.952.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.947.0", "@aws-sdk/credential-provider-http": "3.947.0", "@aws-sdk/credential-provider-ini": "3.952.0", "@aws-sdk/credential-provider-process": "3.947.0", "@aws-sdk/credential-provider-sso": "3.952.0", "@aws-sdk/credential-provider-web-identity": "3.952.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-pj7nidLrb3Dz9llcUPh6N0Yv1dBYTS9xJqi8u0kI8D5sn72HJMB+fIOhcDQVXXAw/dpVolOAH9FOAbog5JDAMg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.948.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Qa8Zj+EAqA0VlAVvxpRnpBpIWJI9KUwaioY1vkeNVwXPlNaz9y9zCKVM9iU9OZ5HXpoUg6TnhATAHXHAE8+QsQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.7", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-7rpKV8YNgCP2R4F9RjWZFcD2R+SO/0R4VHIbY9iZJdH2MzzJ8ZG7h8dZ2m8QkQd1fjx4wrFJGGPJUTYXPV3baA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.947.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-+vhHoDrdbb+zerV4noQk1DHaUMNzWFWPpPYjVTwW2186k5BEJIecAMChYkghRrBVJ3KPWP1+JnZwOd72F3d4rQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/config-resolver": ["@smithy/config-resolver@4.4.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/types": "^4.10.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.6", "@smithy/util-middleware": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-s3U5ChS21DwU54kMmZ0UJumoS5cg0+rGVZvN6f5Lp6EbAVi0ZyP+qDSHdewfmXKUgNK1j3z45JyzulkDukrjAA=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/core": ["@smithy/core@3.19.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.7", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-stream": "^4.5.7", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-Y9oHXpBcXQgYHOcAEmxjkDilUbSTkgKjoHYed3WaYUH8jngq8lPWDBSpjHblJ9uOgBdy5mh3pzebrScDdYr29w=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.6", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-6OiaAaEbLB6dEkRbQyNzFSJv5HDvly3Mc6q/qcPd2uS/g3szR8wAIkh7UndAFKfMypNSTuZ6eCBmgCLR5LacTg=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-config-resolver": ["@smithy/eventstream-serde-config-resolver@4.3.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-xP5YXbOVRVN8A4pDnSUkEUsL9fYFU6VNhxo8tgr13YnMbf3Pn4xVr+hSyLVjS1Frfi1Uk03ET5Bwml4+0CeYEw=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-node": ["@smithy/eventstream-serde-node@4.2.6", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-jhH7nJuaOpnTFcuZpWK9dqb6Ge2yGi1okTo0W6wkJrfwAm2vwmO74tF1v07JmrSyHBcKLQATEexclJw9K1Vj7w=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/querystring-builder": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-fcVap4QwqmzQwQK9QU3keeEpCzTjnP9NJ171vI7GnD7nbkAIcP9biZhDUx88uRH9BabSsQDS0unUps88uZvFIQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/hash-node": ["@smithy/hash-node@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-k3Dy9VNR37wfMh2/1RHkFf/e0rMyN0pjY0FdyY6ItJRjENYyVPRMwad6ZR1S9HFm6tTuIOd9pqKBmtJ4VHxvxg=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-E4t/V/q2T46RY21fpfznd1iSLTvCXKNKo4zJ1QuEFN4SE9gKfu2vb6bgq35LpufkQ+SETWIC7ZAf2GGvTlBaMQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.6", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-0cjqjyfj+Gls30ntq45SsBtqF3dfJQCeqQPyGz58Pk8OgrAr5YiB7ZvDzjCA94p4r6DCI4qLm7FKobqBjf515w=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.0", "", { "dependencies": { "@smithy/core": "^3.19.0", "@smithy/middleware-serde": "^4.2.7", "@smithy/node-config-provider": "^4.3.6", "@smithy/shared-ini-file-loader": "^4.4.1", "@smithy/types": "^4.10.0", "@smithy/url-parser": "^4.2.6", "@smithy/util-middleware": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-M6qWfUNny6NFNy8amrCGIb9TfOMUkHVtg9bHtEFGRgfH7A7AtPpn/fcrToGPjVDK1ECuMVvqGQOXcZxmu9K+7A=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.16", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/protocol-http": "^5.3.6", "@smithy/service-error-classification": "^4.2.6", "@smithy/smithy-client": "^4.10.1", "@smithy/types": "^4.10.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-retry": "^4.2.6", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-XPpNhNRzm3vhYm7YCsyw3AtmWggJbg1wNGAoqb7NBYr5XA5isMRv14jgbYyUV6IvbTBFZQdf2QpeW43LrRdStQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-PFMVHVPgtFECeu4iZ+4SX6VOQT0+dIpm4jSPLLL6JLSkp9RohGqKBKD0cbiXdeIFS08Forp0UHI6kc0gIHenSA=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-JSbALU3G+JS4kyBZPqnJ3hxIYwOVRV7r9GNQMS6j5VsQDo5+Es5nddLfr9TQlxZLNHPvKSh+XSB0OuWGfSWFcA=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.6", "", { "dependencies": { "@smithy/property-provider": "^4.2.6", "@smithy/shared-ini-file-loader": "^4.4.1", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-fYEyL59Qe82Ha1p97YQTMEQPJYmBS+ux76foqluaTVWoG9Px5J53w6NvXZNE3wP7lIicLDF7Vj1Em18XTX7fsA=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/protocol-http": ["@smithy/protocol-http@5.3.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qLRZzP2+PqhE3OSwvY2jpBbP0WKTZ9opTsn+6IWYI0SKVpbG+imcfNxXPq9fj5XeaUTr7odpsNpK6dmoiM1gJQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/smithy-client": ["@smithy/smithy-client@4.10.1", "", { "dependencies": { "@smithy/core": "^3.19.0", "@smithy/middleware-endpoint": "^4.4.0", "@smithy/middleware-stack": "^4.2.6", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-stream": "^4.5.7", "tslib": "^2.6.2" } }, "sha512-1ovWdxzYprhq+mWqiGZlt3kF69LJthuQcfY9BIyHx9MywTFKzFapluku1QXoaBB43GCsLDxNqS+1v30ure69AA=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/url-parser": ["@smithy/url-parser@4.2.6", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tVoyzJ2vXp4R3/aeV4EQjBDmCuWxRa8eo3KybL7Xv4wEM16nObYh7H1sNfcuLWHAAAzb0RVyxUz1S3sGj4X+Tg=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.15", "", { "dependencies": { "@smithy/property-provider": "^4.2.6", "@smithy/smithy-client": "^4.10.1", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-LiZQVAg/oO8kueX4c+oMls5njaD2cRLXRfcjlTYjhIqmwHnCwkQO5B3dMQH0c5PACILxGAQf6Mxsq7CjlDc76A=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.18", "", { "dependencies": { "@smithy/config-resolver": "^4.4.4", "@smithy/credential-provider-imds": "^4.2.6", "@smithy/node-config-provider": "^4.3.6", "@smithy/property-provider": "^4.2.6", "@smithy/smithy-client": "^4.10.1", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-Kw2J+KzYm9C9Z9nY6+W0tEnoZOofstVCMTshli9jhQbQCy64rueGfKzPfuFBnVUqZD9JobxTh2DzHmPkp/Va/Q=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-v60VNM2+mPvgHCBXEfMCYrQ0RepP6u6xvbAkMenfe4Mi872CqNkJzgcnQL837e8NdeDxBgrWQRTluKq5Lqdhfg=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-middleware": ["@smithy/util-middleware@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qrvXUkxBSAFomM3/OEMuDVwjh4wtqK8D2uDZPShzIqOylPst6gor2Cdp6+XrH4dyksAWq/bE2aSDYBTTnj0Rxg=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-retry": ["@smithy/util-retry@4.2.6", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-x7CeDQLPQ9cb6xN7fRJEjlP9NyGW/YeXWc4j/RUhg4I+H60F0PEeRc2c/z3rm9zmsdiMFzpV/rT+4UHW6KM1SA=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-stream": ["@smithy/util-stream@4.5.7", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.7", "@smithy/node-http-handler": "^4.4.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Uuy4S5Aj4oF6k1z+i2OtIBJUns4mlg29Ph4S+CqjR+f4XXpSFVgTCYLzMszHJTicYDBxKFtwq2/QSEDSS5l02A=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
"@aws-sdk/client-cognito-identity/@aws-sdk/core": ["@aws-sdk/core@3.623.0", "", { "dependencies": { "@smithy/core": "^2.3.2", "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/signature-v4": "^4.1.0", "@smithy/smithy-client": "^3.1.12", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" } }, "sha512-8Toq3X6trX/67obSdh4K0MFQY4f132bEbr1i0YPDWk/O3KdBt12mLC/sW3aVRnlIs110XMuX9yrWWqJ8fDW10g=="],
"@aws-sdk/client-cognito-identity/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.623.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.620.1", "@aws-sdk/credential-provider-http": "3.622.0", "@aws-sdk/credential-provider-ini": "3.623.0", "@aws-sdk/credential-provider-process": "3.620.1", "@aws-sdk/credential-provider-sso": "3.623.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", "@smithy/property-provider": "^3.1.3", "@smithy/shared-ini-file-loader": "^3.1.4", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-qDwCOkhbu5PfaQHyuQ+h57HEx3+eFhKdtIw7aISziWkGdFrMe07yIBd7TJqGe4nxXnRF1pfkg05xeOlMId997g=="],
@@ -4971,8 +5199,12 @@
"@aws-sdk/client-kendra/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+ "@aws-sdk/client-kendra/@smithy/protocol-http": ["@smithy/protocol-http@5.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw=="],
+
"@aws-sdk/client-kendra/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
+ "@aws-sdk/client-kendra/@smithy/types": ["@smithy/types@4.8.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-N0Zn0OT1zc+NA+UVfkYqQzviRh5ucWwO7mBV3TmHHprMnfcJNfhlPicDkBHi0ewbh+y3evR6cNAW0Raxvb01NA=="],
+
"@aws-sdk/client-kendra/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
"@aws-sdk/client-kendra/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
@@ -4987,11 +5219,13 @@
"@aws-sdk/client-kendra/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
+ "@aws-sdk/client-kendra/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
+
"@aws-sdk/client-kendra/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
"@aws-sdk/client-kendra/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
- "@aws-sdk/client-s3/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
+ "@aws-sdk/client-kendra/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
"@aws-sdk/client-sso/@aws-sdk/core": ["@aws-sdk/core@3.623.0", "", { "dependencies": { "@smithy/core": "^2.3.2", "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/signature-v4": "^4.1.0", "@smithy/smithy-client": "^3.1.12", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" } }, "sha512-8Toq3X6trX/67obSdh4K0MFQY4f132bEbr1i0YPDWk/O3KdBt12mLC/sW3aVRnlIs110XMuX9yrWWqJ8fDW10g=="],
@@ -5135,7 +5369,7 @@
"@aws-sdk/client-sso-oidc/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
- "@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
+ "@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-14T1V64o6/ndyrnl1ze1ZhyLzIeYNN47oF/QU6P5m82AEtyOkMJTb0gO1dPubYjyyKuPD6OSVMPDKe+zioOnCg=="],
"@aws-sdk/credential-provider-cognito-identity/@aws-sdk/types": ["@aws-sdk/types@3.609.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q=="],
@@ -5165,33 +5399,23 @@
"@aws-sdk/credential-provider-ini/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core": ["@aws-sdk/core@3.947.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw=="],
+ "@aws-sdk/credential-provider-login/@smithy/property-provider": ["@smithy/property-provider@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-14T1V64o6/ndyrnl1ze1ZhyLzIeYNN47oF/QU6P5m82AEtyOkMJTb0gO1dPubYjyyKuPD6OSVMPDKe+zioOnCg=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="],
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.16", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-HrdtnadvTGAQUr18sPzGlE5El3ICphnH6SU7UQOMOWFgRKbTRNN8msTxM4emzguUso9CzaHU2xy5ctSrmK5YNA=="],
- "@aws-sdk/credential-provider-login/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.18", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/types": "^3.973.5", "@smithy/fetch-http-handler": "^5.3.13", "@smithy/node-http-handler": "^4.4.14", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/smithy-client": "^4.12.2", "@smithy/types": "^4.13.0", "@smithy/util-stream": "^4.5.17", "tslib": "^2.6.2" } }, "sha512-NyB6smuZAixND5jZumkpkunQ0voc4Mwgkd+SZ6cvAzIB7gK8HV8Zd4rS8Kn5MmoGgusyNfVGG+RLoYc4yFiw+A=="],
- "@aws-sdk/credential-provider-login/@smithy/protocol-http": ["@smithy/protocol-http@5.3.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qLRZzP2+PqhE3OSwvY2jpBbP0WKTZ9opTsn+6IWYI0SKVpbG+imcfNxXPq9fj5XeaUTr7odpsNpK6dmoiM1gJQ=="],
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.972.17", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/credential-provider-env": "^3.972.16", "@aws-sdk/credential-provider-http": "^3.972.18", "@aws-sdk/credential-provider-login": "^3.972.17", "@aws-sdk/credential-provider-process": "^3.972.16", "@aws-sdk/credential-provider-sso": "^3.972.17", "@aws-sdk/credential-provider-web-identity": "^3.972.17", "@aws-sdk/nested-clients": "^3.996.7", "@aws-sdk/types": "^3.973.5", "@smithy/credential-provider-imds": "^4.2.11", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-dFqh7nfX43B8dO1aPQHOcjC0SnCJ83H3F+1LoCh3X1P7E7N09I+0/taID0asU6GCddfDExqnEvQtDdkuMe5tKQ=="],
- "@aws-sdk/credential-provider-login/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.1", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tph+oQYPbpN6NamF030hx1gb5YN2Plog+GLaRHpoEDwp8+ZPG26rIJvStG9hkWzN2HBn3HcWg0sHeB0tmkYzqA=="],
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.16", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-n89ibATwnLEg0ZdZmUds5bq8AfBAdoYEDpqP3uzPLaRuGelsKlIvCYSNNvfgGLi8NaHPNNhs1HjJZYbqkW9b+g=="],
- "@aws-sdk/credential-provider-login/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.972.17", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/nested-clients": "^3.996.7", "@aws-sdk/token-providers": "3.1004.0", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-wGtte+48xnhnhHMl/MsxzacBPs5A+7JJedjiP452IkHY7vsbYKcvQBqFye8LwdTJVeHtBHv+JFeTscnwepoWGg=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.758.0", "", { "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/property-provider": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-N27eFoRrO6MeUNumtNHDW9WOiwfd59LPXPqDrIa3kWL/s+fOKFHb9xIcF++bAwtcZnAxKkgpDCUP+INNZskE+w=="],
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.17", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/nested-clients": "^3.996.7", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-8aiVJh6fTdl8gcyL+sVNcNwTtWpmoFa1Sh7xlj6Z7L/cZ/tYMEBHq44wTYG8Kt0z/PpGNopD89nbj3FHl9QmTA=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.758.0", "", { "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/fetch-http-handler": "^5.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/property-provider": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/util-stream": "^4.1.2", "tslib": "^2.6.2" } }, "sha512-Xt9/U8qUCiw1hihztWkNeIR+arg6P+yda10OuCHX6kFVx3auTlU7+hCqs3UxqniGU4dguHuftf3mRpi5/GJ33Q=="],
+ "@aws-sdk/credential-provider-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.11", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-lBXrS6ku0kTj3xLmsJW0WwqWbGQ6ueooYyp/1L9lkyT0M02C+DWwYwc5aTyXFbRaK38ojALxNixg+LxKSHZc0g=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.758.0", "", { "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/credential-provider-env": "3.758.0", "@aws-sdk/credential-provider-http": "3.758.0", "@aws-sdk/credential-provider-process": "3.758.0", "@aws-sdk/credential-provider-sso": "3.758.0", "@aws-sdk/credential-provider-web-identity": "3.758.0", "@aws-sdk/nested-clients": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/credential-provider-imds": "^4.0.1", "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-cymSKMcP5d+OsgetoIZ5QCe1wnp2Q/tq+uIxVdh9MbfdBBEnl9Ecq6dH6VlYS89sp4QKuxHxkWXVnbXU3Q19Aw=="],
-
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.758.0", "", { "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-AzcY74QTPqcbXWVgjpPZ3HOmxQZYPROIBz2YINF0OQk0MhezDWV/O7Xec+K1+MPGQO3qS6EDrUUlnPLjsqieHA=="],
-
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.758.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.758.0", "@aws-sdk/core": "3.758.0", "@aws-sdk/token-providers": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-x0FYJqcOLUCv8GLLFDYMXRAQKGjoM+L0BG4BiHYZRDf24yQWFCAZsCQAYKo6XZYh2qznbsW6f//qpyJ5b0QVKQ=="],
-
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.758.0", "", { "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/nested-clients": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/property-provider": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-XGguXhBqiCXMXRxcfCAVPlMbm3VyJTou79r/3mxWddHWF0XbhaQiBIbUz6vobVTD25YQRbWSmSch7VA8kI5Lrw=="],
-
- "@aws-sdk/credential-provider-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.0.1", "", { "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/property-provider": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "tslib": "^2.6.2" } }, "sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg=="],
-
- "@aws-sdk/credential-provider-node/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
+ "@aws-sdk/credential-provider-node/@smithy/property-provider": ["@smithy/property-provider@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-14T1V64o6/ndyrnl1ze1ZhyLzIeYNN47oF/QU6P5m82AEtyOkMJTb0gO1dPubYjyyKuPD6OSVMPDKe+zioOnCg=="],
"@aws-sdk/credential-provider-process/@aws-sdk/types": ["@aws-sdk/types@3.609.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q=="],
@@ -5217,113 +5441,41 @@
"@aws-sdk/credential-providers/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
- "@aws-sdk/eventstream-handler-node/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="],
+ "@aws-sdk/middleware-websocket/@aws-sdk/util-format-url": ["@aws-sdk/util-format-url@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/querystring-builder": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-V+PbnWfUl93GuFwsOHsAq7hY/fnm9kElRqR8IexIJr5Rvif9e614X5sGSyz3mVSf1YAZ+VTy63W1/pGdA55zyA=="],
- "@aws-sdk/eventstream-handler-node/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.758.0", "", { "dependencies": { "@aws-sdk/middleware-sdk-s3": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/protocol-http": "^5.0.1", "@smithy/signature-v4": "^5.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-0RPCo8fYJcrenJ6bRtiUbFOSgQ1CX/GpvwtLU2Fam1tS9h2klKK8d74caeV6A1mIUvBU7bhyQ0wMGlwMtn3EYw=="],
- "@aws-sdk/middleware-eventstream/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/types": ["@aws-sdk/types@3.734.0", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg=="],
- "@aws-sdk/middleware-eventstream/@smithy/protocol-http": ["@smithy/protocol-http@5.3.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qLRZzP2+PqhE3OSwvY2jpBbP0WKTZ9opTsn+6IWYI0SKVpbG+imcfNxXPq9fj5XeaUTr7odpsNpK6dmoiM1gJQ=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.0.6", "", { "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-serde": "^4.0.2", "@smithy/node-config-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-middleware": "^4.0.1", "tslib": "^2.6.2" } }, "sha512-ftpmkTHIFqgaFugcjzLZv3kzPEFsBFSnq1JsIkr2mwFzCraZVhQk2gqN51OOeRxqhbPTkRFj39Qd2V91E/mQxg=="],
- "@aws-sdk/middleware-eventstream/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
+ "@aws-sdk/s3-request-presigner/@smithy/protocol-http": ["@smithy/protocol-http@5.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw=="],
- "@aws-sdk/middleware-websocket/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client": ["@smithy/smithy-client@4.1.6", "", { "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/middleware-stack": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-stream": "^4.1.2", "tslib": "^2.6.2" } }, "sha512-UYDolNg6h2O0L+cJjtgSyKKvEKCOa/8FHYJnBobyeoeWDmNpXjwOAtw16ezyeu1ETuuLEOZbrynK0ZY1Lx9Jbw=="],
- "@aws-sdk/middleware-websocket/@aws-sdk/util-format-url": ["@aws-sdk/util-format-url@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/querystring-builder": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-MS5eSEtDUFIAMHrJaMERiHAvDPdfxc/T869ZjDNFAIiZhyc037REw0aoTNeimNXDNy2txRNZJaAUn/kE4RwN+g=="],
+ "@aws-sdk/s3-request-presigner/@smithy/types": ["@smithy/types@4.8.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-N0Zn0OT1zc+NA+UVfkYqQzviRh5ucWwO7mBV3TmHHprMnfcJNfhlPicDkBHi0ewbh+y3evR6cNAW0Raxvb01NA=="],
- "@aws-sdk/middleware-websocket/@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.6", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-6OiaAaEbLB6dEkRbQyNzFSJv5HDvly3Mc6q/qcPd2uS/g3szR8wAIkh7UndAFKfMypNSTuZ6eCBmgCLR5LacTg=="],
+ "@aws-sdk/token-providers/@smithy/property-provider": ["@smithy/property-provider@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-14T1V64o6/ndyrnl1ze1ZhyLzIeYNN47oF/QU6P5m82AEtyOkMJTb0gO1dPubYjyyKuPD6OSVMPDKe+zioOnCg=="],
- "@aws-sdk/middleware-websocket/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/querystring-builder": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-fcVap4QwqmzQwQK9QU3keeEpCzTjnP9NJ171vI7GnD7nbkAIcP9biZhDUx88uRH9BabSsQDS0unUps88uZvFIQ=="],
-
- "@aws-sdk/middleware-websocket/@smithy/protocol-http": ["@smithy/protocol-http@5.3.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qLRZzP2+PqhE3OSwvY2jpBbP0WKTZ9opTsn+6IWYI0SKVpbG+imcfNxXPq9fj5XeaUTr7odpsNpK6dmoiM1gJQ=="],
-
- "@aws-sdk/middleware-websocket/@smithy/signature-v4": ["@smithy/signature-v4@5.3.6", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-P1TXDHuQMadTMTOBv4oElZMURU4uyEhxhHfn+qOc2iofW9Rd4sZtBGx58Lzk112rIGVEYZT8eUMK4NftpewpRA=="],
-
- "@aws-sdk/middleware-websocket/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
-
- "@aws-sdk/nested-clients/@aws-sdk/core": ["@aws-sdk/core@3.947.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw=="],
-
- "@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="],
-
- "@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="],
-
- "@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.948.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Qa8Zj+EAqA0VlAVvxpRnpBpIWJI9KUwaioY1vkeNVwXPlNaz9y9zCKVM9iU9OZ5HXpoUg6TnhATAHXHAE8+QsQ=="],
-
- "@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.7", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-7rpKV8YNgCP2R4F9RjWZFcD2R+SO/0R4VHIbY9iZJdH2MzzJ8ZG7h8dZ2m8QkQd1fjx4wrFJGGPJUTYXPV3baA=="],
-
- "@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="],
-
- "@aws-sdk/nested-clients/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="],
-
- "@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="],
-
- "@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="],
-
- "@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.947.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-+vhHoDrdbb+zerV4noQk1DHaUMNzWFWPpPYjVTwW2186k5BEJIecAMChYkghRrBVJ3KPWP1+JnZwOd72F3d4rQ=="],
-
- "@aws-sdk/nested-clients/@smithy/config-resolver": ["@smithy/config-resolver@4.4.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/types": "^4.10.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.6", "@smithy/util-middleware": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-s3U5ChS21DwU54kMmZ0UJumoS5cg0+rGVZvN6f5Lp6EbAVi0ZyP+qDSHdewfmXKUgNK1j3z45JyzulkDukrjAA=="],
-
- "@aws-sdk/nested-clients/@smithy/core": ["@smithy/core@3.19.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.7", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-stream": "^4.5.7", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-Y9oHXpBcXQgYHOcAEmxjkDilUbSTkgKjoHYed3WaYUH8jngq8lPWDBSpjHblJ9uOgBdy5mh3pzebrScDdYr29w=="],
-
- "@aws-sdk/nested-clients/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/querystring-builder": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-fcVap4QwqmzQwQK9QU3keeEpCzTjnP9NJ171vI7GnD7nbkAIcP9biZhDUx88uRH9BabSsQDS0unUps88uZvFIQ=="],
-
- "@aws-sdk/nested-clients/@smithy/hash-node": ["@smithy/hash-node@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-k3Dy9VNR37wfMh2/1RHkFf/e0rMyN0pjY0FdyY6ItJRjENYyVPRMwad6ZR1S9HFm6tTuIOd9pqKBmtJ4VHxvxg=="],
-
- "@aws-sdk/nested-clients/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-E4t/V/q2T46RY21fpfznd1iSLTvCXKNKo4zJ1QuEFN4SE9gKfu2vb6bgq35LpufkQ+SETWIC7ZAf2GGvTlBaMQ=="],
-
- "@aws-sdk/nested-clients/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.6", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-0cjqjyfj+Gls30ntq45SsBtqF3dfJQCeqQPyGz58Pk8OgrAr5YiB7ZvDzjCA94p4r6DCI4qLm7FKobqBjf515w=="],
-
- "@aws-sdk/nested-clients/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.0", "", { "dependencies": { "@smithy/core": "^3.19.0", "@smithy/middleware-serde": "^4.2.7", "@smithy/node-config-provider": "^4.3.6", "@smithy/shared-ini-file-loader": "^4.4.1", "@smithy/types": "^4.10.0", "@smithy/url-parser": "^4.2.6", "@smithy/util-middleware": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-M6qWfUNny6NFNy8amrCGIb9TfOMUkHVtg9bHtEFGRgfH7A7AtPpn/fcrToGPjVDK1ECuMVvqGQOXcZxmu9K+7A=="],
-
- "@aws-sdk/nested-clients/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.16", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/protocol-http": "^5.3.6", "@smithy/service-error-classification": "^4.2.6", "@smithy/smithy-client": "^4.10.1", "@smithy/types": "^4.10.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-retry": "^4.2.6", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-XPpNhNRzm3vhYm7YCsyw3AtmWggJbg1wNGAoqb7NBYr5XA5isMRv14jgbYyUV6IvbTBFZQdf2QpeW43LrRdStQ=="],
-
- "@aws-sdk/nested-clients/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-PFMVHVPgtFECeu4iZ+4SX6VOQT0+dIpm4jSPLLL6JLSkp9RohGqKBKD0cbiXdeIFS08Forp0UHI6kc0gIHenSA=="],
-
- "@aws-sdk/nested-clients/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-JSbALU3G+JS4kyBZPqnJ3hxIYwOVRV7r9GNQMS6j5VsQDo5+Es5nddLfr9TQlxZLNHPvKSh+XSB0OuWGfSWFcA=="],
-
- "@aws-sdk/nested-clients/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.6", "", { "dependencies": { "@smithy/property-provider": "^4.2.6", "@smithy/shared-ini-file-loader": "^4.4.1", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-fYEyL59Qe82Ha1p97YQTMEQPJYmBS+ux76foqluaTVWoG9Px5J53w6NvXZNE3wP7lIicLDF7Vj1Em18XTX7fsA=="],
-
- "@aws-sdk/nested-clients/@smithy/protocol-http": ["@smithy/protocol-http@5.3.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qLRZzP2+PqhE3OSwvY2jpBbP0WKTZ9opTsn+6IWYI0SKVpbG+imcfNxXPq9fj5XeaUTr7odpsNpK6dmoiM1gJQ=="],
-
- "@aws-sdk/nested-clients/@smithy/smithy-client": ["@smithy/smithy-client@4.10.1", "", { "dependencies": { "@smithy/core": "^3.19.0", "@smithy/middleware-endpoint": "^4.4.0", "@smithy/middleware-stack": "^4.2.6", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-stream": "^4.5.7", "tslib": "^2.6.2" } }, "sha512-1ovWdxzYprhq+mWqiGZlt3kF69LJthuQcfY9BIyHx9MywTFKzFapluku1QXoaBB43GCsLDxNqS+1v30ure69AA=="],
-
- "@aws-sdk/nested-clients/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
-
- "@aws-sdk/nested-clients/@smithy/url-parser": ["@smithy/url-parser@4.2.6", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tVoyzJ2vXp4R3/aeV4EQjBDmCuWxRa8eo3KybL7Xv4wEM16nObYh7H1sNfcuLWHAAAzb0RVyxUz1S3sGj4X+Tg=="],
-
- "@aws-sdk/nested-clients/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/nested-clients/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/nested-clients/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
-
- "@aws-sdk/nested-clients/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.15", "", { "dependencies": { "@smithy/property-provider": "^4.2.6", "@smithy/smithy-client": "^4.10.1", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-LiZQVAg/oO8kueX4c+oMls5njaD2cRLXRfcjlTYjhIqmwHnCwkQO5B3dMQH0c5PACILxGAQf6Mxsq7CjlDc76A=="],
-
- "@aws-sdk/nested-clients/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.18", "", { "dependencies": { "@smithy/config-resolver": "^4.4.4", "@smithy/credential-provider-imds": "^4.2.6", "@smithy/node-config-provider": "^4.3.6", "@smithy/property-provider": "^4.2.6", "@smithy/smithy-client": "^4.10.1", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-Kw2J+KzYm9C9Z9nY6+W0tEnoZOofstVCMTshli9jhQbQCy64rueGfKzPfuFBnVUqZD9JobxTh2DzHmPkp/Va/Q=="],
-
- "@aws-sdk/nested-clients/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-v60VNM2+mPvgHCBXEfMCYrQ0RepP6u6xvbAkMenfe4Mi872CqNkJzgcnQL837e8NdeDxBgrWQRTluKq5Lqdhfg=="],
-
- "@aws-sdk/nested-clients/@smithy/util-middleware": ["@smithy/util-middleware@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qrvXUkxBSAFomM3/OEMuDVwjh4wtqK8D2uDZPShzIqOylPst6gor2Cdp6+XrH4dyksAWq/bE2aSDYBTTnj0Rxg=="],
-
- "@aws-sdk/nested-clients/@smithy/util-retry": ["@smithy/util-retry@4.2.6", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-x7CeDQLPQ9cb6xN7fRJEjlP9NyGW/YeXWc4j/RUhg4I+H60F0PEeRc2c/z3rm9zmsdiMFzpV/rT+4UHW6KM1SA=="],
-
- "@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/token-providers/@aws-sdk/core": ["@aws-sdk/core@3.947.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw=="],
-
- "@aws-sdk/token-providers/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="],
-
- "@aws-sdk/token-providers/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
-
- "@aws-sdk/token-providers/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.1", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tph+oQYPbpN6NamF030hx1gb5YN2Plog+GLaRHpoEDwp8+ZPG26rIJvStG9hkWzN2HBn3HcWg0sHeB0tmkYzqA=="],
-
- "@aws-sdk/token-providers/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
+ "@aws-sdk/util-format-url/@aws-sdk/types": ["@aws-sdk/types@3.734.0", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg=="],
"@aws-sdk/util-format-url/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+ "@aws-sdk/util-format-url/@smithy/types": ["@smithy/types@4.8.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-N0Zn0OT1zc+NA+UVfkYqQzviRh5ucWwO7mBV3TmHHprMnfcJNfhlPicDkBHi0ewbh+y3evR6cNAW0Raxvb01NA=="],
+
"@azure/core-http-compat/@azure/abort-controller": ["@azure/abort-controller@1.1.0", "", { "dependencies": { "tslib": "^2.2.0" } }, "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw=="],
- "@azure/core-xml/fast-xml-parser": ["fast-xml-parser@5.0.9", "", { "dependencies": { "strnum": "^2.0.5" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-2mBwCiuW3ycKQQ6SOesSB8WeF+fIGb6I/GG5vU5/XEptwFFhp9PE8b9O7fbs2dpq9fXn4ULR3UsfydNUCntf5A=="],
+ "@azure/storage-blob/@azure/core-http-compat": ["@azure/core-http-compat@2.3.2", "", { "dependencies": { "@azure/abort-controller": "^2.1.2" }, "peerDependencies": { "@azure/core-client": "^1.10.0", "@azure/core-rest-pipeline": "^1.22.0" } }, "sha512-Tf6ltdKzOJEgxZeWLCjMxrxbodB/ZeCbzzA1A2qHbhzAjzjHoBVSUeSl/baT/oHAxhc4qdqVaDKnc2+iE932gw=="],
+
+ "@azure/storage-blob/@azure/core-paging": ["@azure/core-paging@1.6.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA=="],
+
+ "@azure/storage-blob/@azure/logger": ["@azure/logger@1.3.0", "", { "dependencies": { "@typespec/ts-http-runtime": "^0.3.0", "tslib": "^2.6.2" } }, "sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA=="],
+
+ "@azure/storage-common/@azure/core-http-compat": ["@azure/core-http-compat@2.3.2", "", { "dependencies": { "@azure/abort-controller": "^2.1.2" }, "peerDependencies": { "@azure/core-client": "^1.10.0", "@azure/core-rest-pipeline": "^1.22.0" } }, "sha512-Tf6ltdKzOJEgxZeWLCjMxrxbodB/ZeCbzzA1A2qHbhzAjzjHoBVSUeSl/baT/oHAxhc4qdqVaDKnc2+iE932gw=="],
+
+ "@azure/storage-common/@azure/logger": ["@azure/logger@1.3.0", "", { "dependencies": { "@typespec/ts-http-runtime": "^0.3.0", "tslib": "^2.6.2" } }, "sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA=="],
+
+ "@babel/core/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
"@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
@@ -5331,11 +5483,17 @@
"@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
- "@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
+ "@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.25.9", "", { "dependencies": { "@babel/types": "^7.25.9" } }, "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g=="],
- "@babel/plugin-transform-classes/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="],
+ "@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
- "@babel/plugin-transform-explicit-resource-management/@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw=="],
+ "@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
"@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.8", "", { "dependencies": { "@babel/compat-data": "^7.22.6", "@babel/helper-define-polyfill-provider": "^0.5.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-OtIuQfafSzpo/LhnJaykc0R/MMnuLSSVjVYy9mHArIZ9qTCSZ6TpWCuEKZYVoN//t8HqBNScHrOtCrIK5IaGLg=="],
@@ -5343,18 +5501,40 @@
"@babel/plugin-transform-runtime/babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.5.5", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.5.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg=="],
- "@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.23.10", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-member-expression-to-functions": "^7.23.0", "@babel/helper-optimise-call-expression": "^7.22.5", "@babel/helper-replace-supers": "^7.22.20", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw=="],
+ "@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
- "@babel/preset-typescript/@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.23.3", "", { "dependencies": { "@babel/helper-module-transforms": "^7.23.3", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-simple-access": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA=="],
+ "@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@babel/traverse/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
"@codesandbox/sandpack-client/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
- "@csstools/css-color-parser/@csstools/color-helpers": ["@csstools/color-helpers@4.0.0", "", {}, "sha512-wjyXB22/h2OvxAr3jldPB7R7kjTUEzopvjitS8jWtyd8fN6xJ8vy1HnHu0ZNfEkqpBJgQ76Q+sBDshWcMvTa/w=="],
+ "@csstools/postcss-cascade-layers/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
+
+ "@csstools/postcss-is-pseudo-class/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
+
+ "@csstools/postcss-scope-pseudo-class/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
+
+ "@csstools/selector-resolve-nested/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
+
+ "@csstools/selector-specificity/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
+ "@eslint/config-array/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
+ "@eslint/config-array/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
+
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
+ "@google/genai/google-auth-library": ["google-auth-library@10.5.0", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.0.0", "gcp-metadata": "^8.0.0", "google-logging-utils": "^1.0.0", "gtoken": "^8.0.0", "jws": "^4.0.0" } }, "sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w=="],
+
+ "@grpc/grpc-js/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
+ "@grpc/proto-loader/protobufjs": ["protobufjs@7.4.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw=="],
+
"@headlessui/react/@tanstack/react-virtual": ["@tanstack/react-virtual@3.13.12", "", { "dependencies": { "@tanstack/virtual-core": "3.13.12" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Gd13QdxPSukP8ZrkbgS2RwoZseTTbQPLnQEn7HY/rqtM+8Zt95f7xKC7N0EsKs7aoz0WzZ+fditZux+F8EzYxA=="],
"@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="],
@@ -5373,39 +5553,31 @@
"@istanbuljs/load-nyc-config/resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
- "@jest/console/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
+ "@jest/console/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
"@jest/console/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
- "@jest/core/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
+ "@jest/core/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
"@jest/core/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="],
"@jest/core/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
- "@jest/environment/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="],
+ "@jest/environment/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
- "@jest/environment/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="],
-
- "@jest/environment-jsdom-abstract/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="],
-
- "@jest/environment-jsdom-abstract/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="],
-
- "@jest/environment-jsdom-abstract/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
+ "@jest/environment-jsdom-abstract/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
"@jest/expect/expect": ["expect@30.2.0", "", { "dependencies": { "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw=="],
- "@jest/fake-timers/@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="],
+ "@jest/fake-timers/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
- "@jest/fake-timers/jest-message-util": ["jest-message-util@29.7.0", "", { "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", "pretty-format": "^29.7.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" } }, "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w=="],
-
- "@jest/globals/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="],
+ "@jest/pattern/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
"@jest/reporters/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
- "@jest/reporters/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
+ "@jest/reporters/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
- "@jest/reporters/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
+ "@jest/reporters/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
"@jest/reporters/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
@@ -5415,10 +5587,10 @@
"@jest/transform/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
- "@jest/transform/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
-
"@jest/transform/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
+ "@jest/types/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
"@jridgewell/gen-mapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
"@jridgewell/remapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
@@ -5445,38 +5617,30 @@
"@langchain/mistralai/uuid": ["uuid@10.0.0", "", { "bin": "dist/bin/uuid" }, "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ=="],
- "@librechat/client/@babel/preset-env": ["@babel/preset-env@7.28.5", "", { "dependencies": { "@babel/compat-data": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.27.1", "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", "@babel/plugin-transform-async-generator-functions": "^7.28.0", "@babel/plugin-transform-async-to-generator": "^7.27.1", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", "@babel/plugin-transform-block-scoping": "^7.28.5", "@babel/plugin-transform-class-properties": "^7.27.1", "@babel/plugin-transform-class-static-block": "^7.28.3", "@babel/plugin-transform-classes": "^7.28.4", "@babel/plugin-transform-computed-properties": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-dotall-regex": "^7.27.1", "@babel/plugin-transform-duplicate-keys": "^7.27.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.0", "@babel/plugin-transform-exponentiation-operator": "^7.28.5", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", "@babel/plugin-transform-json-strings": "^7.27.1", "@babel/plugin-transform-literals": "^7.27.1", "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-modules-systemjs": "^7.28.5", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", "@babel/plugin-transform-numeric-separator": "^7.27.1", "@babel/plugin-transform-object-rest-spread": "^7.28.4", "@babel/plugin-transform-object-super": "^7.27.1", "@babel/plugin-transform-optional-catch-binding": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-private-methods": "^7.27.1", "@babel/plugin-transform-private-property-in-object": "^7.27.1", "@babel/plugin-transform-property-literals": "^7.27.1", "@babel/plugin-transform-regenerator": "^7.28.4", "@babel/plugin-transform-regexp-modifiers": "^7.27.1", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", "@babel/plugin-transform-spread": "^7.27.1", "@babel/plugin-transform-sticky-regex": "^7.27.1", "@babel/plugin-transform-template-literals": "^7.27.1", "@babel/plugin-transform-typeof-symbol": "^7.27.1", "@babel/plugin-transform-unicode-escapes": "^7.27.1", "@babel/plugin-transform-unicode-property-regex": "^7.27.1", "@babel/plugin-transform-unicode-regex": "^7.27.1", "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", "babel-plugin-polyfill-regenerator": "^0.6.5", "core-js-compat": "^3.43.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg=="],
-
- "@librechat/client/@babel/preset-react": ["@babel/preset-react@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-transform-react-display-name": "^7.28.0", "@babel/plugin-transform-react-jsx": "^7.27.1", "@babel/plugin-transform-react-jsx-development": "^7.27.1", "@babel/plugin-transform-react-pure-annotations": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ=="],
-
- "@librechat/client/@babel/preset-typescript": ["@babel/preset-typescript@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g=="],
-
- "@librechat/frontend/@babel/preset-env": ["@babel/preset-env@7.28.5", "", { "dependencies": { "@babel/compat-data": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.27.1", "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", "@babel/plugin-transform-async-generator-functions": "^7.28.0", "@babel/plugin-transform-async-to-generator": "^7.27.1", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", "@babel/plugin-transform-block-scoping": "^7.28.5", "@babel/plugin-transform-class-properties": "^7.27.1", "@babel/plugin-transform-class-static-block": "^7.28.3", "@babel/plugin-transform-classes": "^7.28.4", "@babel/plugin-transform-computed-properties": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-dotall-regex": "^7.27.1", "@babel/plugin-transform-duplicate-keys": "^7.27.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.0", "@babel/plugin-transform-exponentiation-operator": "^7.28.5", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", "@babel/plugin-transform-json-strings": "^7.27.1", "@babel/plugin-transform-literals": "^7.27.1", "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-modules-systemjs": "^7.28.5", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", "@babel/plugin-transform-numeric-separator": "^7.27.1", "@babel/plugin-transform-object-rest-spread": "^7.28.4", "@babel/plugin-transform-object-super": "^7.27.1", "@babel/plugin-transform-optional-catch-binding": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-private-methods": "^7.27.1", "@babel/plugin-transform-private-property-in-object": "^7.27.1", "@babel/plugin-transform-property-literals": "^7.27.1", "@babel/plugin-transform-regenerator": "^7.28.4", "@babel/plugin-transform-regexp-modifiers": "^7.27.1", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", "@babel/plugin-transform-spread": "^7.27.1", "@babel/plugin-transform-sticky-regex": "^7.27.1", "@babel/plugin-transform-template-literals": "^7.27.1", "@babel/plugin-transform-typeof-symbol": "^7.27.1", "@babel/plugin-transform-unicode-escapes": "^7.27.1", "@babel/plugin-transform-unicode-property-regex": "^7.27.1", "@babel/plugin-transform-unicode-regex": "^7.27.1", "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", "babel-plugin-polyfill-regenerator": "^0.6.5", "core-js-compat": "^3.43.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg=="],
-
- "@librechat/frontend/@babel/preset-react": ["@babel/preset-react@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-transform-react-display-name": "^7.28.0", "@babel/plugin-transform-react-jsx": "^7.27.1", "@babel/plugin-transform-react-jsx-development": "^7.27.1", "@babel/plugin-transform-react-pure-annotations": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ=="],
-
- "@librechat/frontend/@babel/preset-typescript": ["@babel/preset-typescript@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g=="],
+ "@librechat/client/rollup": ["rollup@4.37.0", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.37.0", "@rollup/rollup-android-arm64": "4.37.0", "@rollup/rollup-darwin-arm64": "4.37.0", "@rollup/rollup-darwin-x64": "4.37.0", "@rollup/rollup-freebsd-arm64": "4.37.0", "@rollup/rollup-freebsd-x64": "4.37.0", "@rollup/rollup-linux-arm-gnueabihf": "4.37.0", "@rollup/rollup-linux-arm-musleabihf": "4.37.0", "@rollup/rollup-linux-arm64-gnu": "4.37.0", "@rollup/rollup-linux-arm64-musl": "4.37.0", "@rollup/rollup-linux-loongarch64-gnu": "4.37.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.37.0", "@rollup/rollup-linux-riscv64-gnu": "4.37.0", "@rollup/rollup-linux-riscv64-musl": "4.37.0", "@rollup/rollup-linux-s390x-gnu": "4.37.0", "@rollup/rollup-linux-x64-gnu": "4.37.0", "@rollup/rollup-linux-x64-musl": "4.37.0", "@rollup/rollup-win32-arm64-msvc": "4.37.0", "@rollup/rollup-win32-ia32-msvc": "4.37.0", "@rollup/rollup-win32-x64-msvc": "4.37.0", "fsevents": "~2.3.2" }, "bin": "dist/bin/rollup" }, "sha512-iAtQy/L4QFU+rTJ1YUjXqJOJzuwEghqWzCEYD2FEghT7Gsy1VdABntrO4CLopA5IkflTyqNiLNwPcOJ3S7UKLg=="],
"@librechat/frontend/@react-spring/web": ["@react-spring/web@9.7.5", "", { "dependencies": { "@react-spring/animated": "~9.7.5", "@react-spring/core": "~9.7.5", "@react-spring/shared": "~9.7.5", "@react-spring/types": "~9.7.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-lmvqGwpe+CSttsWNZVr+Dg62adtKhauGwLyGE/RRyZ8AAMLgb9x3NDMA5RMElXo+IMyTkPp7nxTB8ZQlmhb6JQ=="],
"@librechat/frontend/@testing-library/jest-dom": ["@testing-library/jest-dom@5.17.0", "", { "dependencies": { "@adobe/css-tools": "^4.0.1", "@babel/runtime": "^7.9.2", "@types/testing-library__jest-dom": "^5.9.1", "aria-query": "^5.0.0", "chalk": "^3.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.5.6", "lodash": "^4.17.15", "redent": "^3.0.0" } }, "sha512-ynmNeT7asXyH3aSVv4vvX4Rb+0qjOhdNHnO/3vuZNqPmhDpV/+rCSGwQ7bLcmU2cJ4dvoheIO85LQj0IbJHEtg=="],
- "@librechat/frontend/framer-motion": ["framer-motion@11.18.2", "", { "dependencies": { "motion-dom": "^11.18.1", "motion-utils": "^11.18.1", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid"] }, "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w=="],
+ "@librechat/frontend/dompurify": ["dompurify@3.3.0", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ=="],
- "@librechat/frontend/jest-environment-jsdom": ["jest-environment-jsdom@29.7.0", "", { "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/jsdom": "^20.0.0", "@types/node": "*", "jest-mock": "^29.7.0", "jest-util": "^29.7.0", "jsdom": "^20.0.0" }, "peerDependencies": { "canvas": "^2.5.0" }, "optionalPeers": ["canvas"] }, "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA=="],
+ "@librechat/frontend/framer-motion": ["framer-motion@11.18.2", "", { "dependencies": { "motion-dom": "^11.18.1", "motion-utils": "^11.18.1", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid"] }, "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w=="],
"@librechat/frontend/lucide-react": ["lucide-react@0.394.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0" } }, "sha512-PzTbJ0bsyXRhH59k5qe7MpTd5MxlpYZUcM9kGSwvPGAfnn0J6FElDwu2EX6Vuh//F7y60rcVJiFQ7EK9DCMgfw=="],
"@mcp-ui/client/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.21.0", "", { "dependencies": { "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" } }, "sha512-YFBsXJMFCyI1zP98u7gezMFKX4lgu/XpoZJk7ufI6UlFKXLj2hAMUuRlQX/nrmIPOmhRrG6tw2OQ2ZA/ZlXYpQ=="],
+ "@mistralai/mistralai/zod-to-json-schema": ["zod-to-json-schema@3.24.3", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-HIAfWdYIt1sssHfYZFCXp4rU1w2r8hVVXYIlmoa0r0gABLs5di3RCqPU5DDROogVz1pAdYBaz7HK5n9pSUNs3A=="],
+
"@modelcontextprotocol/sdk/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
- "@modelcontextprotocol/sdk/express-rate-limit": ["express-rate-limit@7.5.0", "", { "peerDependencies": { "express": "^4.11 || 5 || ^5.0.0-beta.1" } }, "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg=="],
-
- "@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.25.0", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ=="],
-
"@node-saml/node-saml/@types/qs": ["@types/qs@6.14.0", "", {}, "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ=="],
+ "@node-saml/node-saml/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
+ "@node-saml/node-saml/xmlbuilder": ["xmlbuilder@15.1.1", "", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="],
+
"@node-saml/passport-saml/@types/express": ["@types/express@4.17.23", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ=="],
"@node-saml/passport-saml/passport": ["passport@0.7.0", "", { "dependencies": { "passport-strategy": "1.x.x", "pause": "0.0.1", "utils-merge": "^1.0.1" } }, "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ=="],
@@ -5485,9 +5649,19 @@
"@opentelemetry/exporter-trace-otlp-http/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.208.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.208.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/sdk-logs": "0.208.0", "@opentelemetry/sdk-metrics": "2.2.0", "@opentelemetry/sdk-trace-base": "2.2.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-DCFPY8C6lAQHUNkzcNT9R+qYExvsk6C5Bto2pbNxgicpcSWbe2WHShLxkOxIdNcBiYPdVHv/e7vH7K6TI+C+fQ=="],
+ "@opentelemetry/otlp-transformer/protobufjs": ["protobufjs@7.4.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw=="],
+
"@opentelemetry/sdk-node/@opentelemetry/exporter-trace-otlp-http": ["@opentelemetry/exporter-trace-otlp-http@0.207.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/otlp-exporter-base": "0.207.0", "@opentelemetry/otlp-transformer": "0.207.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/sdk-trace-base": "2.2.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-HSRBzXHIC7C8UfPQdu15zEEoBGv0yWkhEwxqgPCHVUKUQ9NLHVGXkVrf65Uaj7UwmAkC1gQfkuVYvLlD//AnUQ=="],
- "@radix-ui/react-alert-dialog/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
+ "@radix-ui/react-alert-dialog/@radix-ui/primitive": ["@radix-ui/primitive@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" } }, "sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA=="],
+
+ "@radix-ui/react-alert-dialog/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA=="],
+
+ "@radix-ui/react-alert-dialog/@radix-ui/react-context": ["@radix-ui/react-context@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg=="],
+
+ "@radix-ui/react-alert-dialog/@radix-ui/react-primitive": ["@radix-ui/react-primitive@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "1.0.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA=="],
+
+ "@radix-ui/react-alert-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.0" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw=="],
"@radix-ui/react-arrow/@radix-ui/react-primitive": ["@radix-ui/react-primitive@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "1.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g=="],
@@ -5503,11 +5677,29 @@
"@radix-ui/react-collapsible/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA=="],
- "@radix-ui/react-dialog/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
+ "@radix-ui/react-dialog/@radix-ui/primitive": ["@radix-ui/primitive@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" } }, "sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA=="],
- "@radix-ui/react-dialog/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
+ "@radix-ui/react-dialog/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA=="],
- "@radix-ui/react-dismissable-layer/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
+ "@radix-ui/react-dialog/@radix-ui/react-context": ["@radix-ui/react-context@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg=="],
+
+ "@radix-ui/react-dialog/@radix-ui/react-id": ["@radix-ui/react-id@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-layout-effect": "1.0.0" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw=="],
+
+ "@radix-ui/react-dialog/@radix-ui/react-presence": ["@radix-ui/react-presence@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.0", "@radix-ui/react-use-layout-effect": "1.0.0" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w=="],
+
+ "@radix-ui/react-dialog/@radix-ui/react-primitive": ["@radix-ui/react-primitive@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "1.0.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA=="],
+
+ "@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.0" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw=="],
+
+ "@radix-ui/react-dialog/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-callback-ref": "1.0.0" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg=="],
+
+ "@radix-ui/react-dismissable-layer/@radix-ui/primitive": ["@radix-ui/primitive@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" } }, "sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA=="],
+
+ "@radix-ui/react-dismissable-layer/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA=="],
+
+ "@radix-ui/react-dismissable-layer/@radix-ui/react-primitive": ["@radix-ui/react-primitive@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "1.0.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA=="],
+
+ "@radix-ui/react-dismissable-layer/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg=="],
"@radix-ui/react-dropdown-menu/@radix-ui/primitive": ["@radix-ui/primitive@1.1.0", "", {}, "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA=="],
@@ -5521,6 +5713,12 @@
"@radix-ui/react-dropdown-menu/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.1.0", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw=="],
+ "@radix-ui/react-focus-scope/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA=="],
+
+ "@radix-ui/react-focus-scope/@radix-ui/react-primitive": ["@radix-ui/react-primitive@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "1.0.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA=="],
+
+ "@radix-ui/react-focus-scope/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg=="],
+
"@radix-ui/react-hover-card/@radix-ui/primitive": ["@radix-ui/primitive@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" } }, "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw=="],
"@radix-ui/react-hover-card/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="],
@@ -5567,8 +5765,6 @@
"@radix-ui/react-menu/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
- "@radix-ui/react-menu/react-remove-scroll": ["react-remove-scroll@2.5.5", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.3", "react-style-singleton": "^2.2.1", "tslib": "^2.1.0", "use-callback-ref": "^1.3.0", "use-sidecar": "^1.1.2" }, "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw=="],
-
"@radix-ui/react-popover/@radix-ui/primitive": ["@radix-ui/primitive@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" } }, "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw=="],
"@radix-ui/react-popover/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="],
@@ -5591,8 +5787,6 @@
"@radix-ui/react-popover/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-callback-ref": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA=="],
- "@radix-ui/react-popover/react-remove-scroll": ["react-remove-scroll@2.5.5", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.3", "react-style-singleton": "^2.2.1", "tslib": "^2.1.0", "use-callback-ref": "^1.3.0", "use-sidecar": "^1.1.2" }, "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw=="],
-
"@radix-ui/react-popper/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="],
"@radix-ui/react-popper/@radix-ui/react-context": ["@radix-ui/react-context@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg=="],
@@ -5603,6 +5797,8 @@
"@radix-ui/react-popper/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ=="],
+ "@radix-ui/react-portal/@radix-ui/react-primitive": ["@radix-ui/react-primitive@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "1.0.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA=="],
+
"@radix-ui/react-presence/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="],
"@radix-ui/react-presence/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ=="],
@@ -5621,10 +5817,16 @@
"@radix-ui/react-select/@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA=="],
+ "@radix-ui/react-select/@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="],
+
"@radix-ui/react-select/@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.7", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ=="],
+ "@radix-ui/react-select/@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="],
+
"@radix-ui/react-select/@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="],
+ "@radix-ui/react-select/react-remove-scroll": ["react-remove-scroll@2.7.1", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA=="],
+
"@radix-ui/react-slider/@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="],
"@radix-ui/react-slider/@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="],
@@ -5669,6 +5871,8 @@
"@radix-ui/react-toast/@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-primitive": "1.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA=="],
+ "@radix-ui/react-use-escape-keydown/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg=="],
+
"@radix-ui/react-use-size/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ=="],
"@rollup/plugin-babel/@rollup/pluginutils": ["@rollup/pluginutils@3.1.0", "", { "dependencies": { "@types/estree": "0.0.39", "estree-walker": "^1.0.1", "picomatch": "^2.2.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0" } }, "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg=="],
@@ -5681,45 +5885,21 @@
"@rollup/pluginutils/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
- "@smithy/abort-controller/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
-
"@smithy/credential-provider-imds/@smithy/node-config-provider": ["@smithy/node-config-provider@3.1.4", "", { "dependencies": { "@smithy/property-provider": "^3.1.3", "@smithy/shared-ini-file-loader": "^3.1.4", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ=="],
"@smithy/credential-provider-imds/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
"@smithy/credential-provider-imds/@smithy/url-parser": ["@smithy/url-parser@3.0.3", "", { "dependencies": { "@smithy/querystring-parser": "^3.0.3", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A=="],
- "@smithy/eventstream-codec/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
-
- "@smithy/eventstream-serde-universal/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-aV8blR9RBDKrOlZVgjOdmOibTC2sBXNiT7WA558b4MPdsLTV6sbyc1WIE9QiIuYMJjYtnPLciefoqSW8Gi+MZQ=="],
-
- "@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
-
- "@smithy/middleware-retry/uuid": ["uuid@9.0.1", "", { "bin": "dist/bin/uuid" }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
-
- "@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
-
- "@smithy/node-http-handler/@smithy/protocol-http": ["@smithy/protocol-http@5.3.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qLRZzP2+PqhE3OSwvY2jpBbP0WKTZ9opTsn+6IWYI0SKVpbG+imcfNxXPq9fj5XeaUTr7odpsNpK6dmoiM1gJQ=="],
-
- "@smithy/node-http-handler/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
+ "@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-14T1V64o6/ndyrnl1ze1ZhyLzIeYNN47oF/QU6P5m82AEtyOkMJTb0gO1dPubYjyyKuPD6OSVMPDKe+zioOnCg=="],
"@smithy/property-provider/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
- "@smithy/querystring-builder/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
+ "@smithy/util-defaults-mode-browser/@smithy/property-provider": ["@smithy/property-provider@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-14T1V64o6/ndyrnl1ze1ZhyLzIeYNN47oF/QU6P5m82AEtyOkMJTb0gO1dPubYjyyKuPD6OSVMPDKe+zioOnCg=="],
- "@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@smithy/util-defaults-mode-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.11", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-lBXrS6ku0kTj3xLmsJW0WwqWbGQ6ueooYyp/1L9lkyT0M02C+DWwYwc5aTyXFbRaK38ojALxNixg+LxKSHZc0g=="],
- "@smithy/signature-v4/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@smithy/util-defaults-mode-browser/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
-
- "@smithy/util-defaults-mode-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.0.1", "", { "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/property-provider": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "tslib": "^2.6.2" } }, "sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg=="],
-
- "@smithy/util-defaults-mode-node/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
-
- "@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
-
- "@smithy/util-waiter/@smithy/abort-controller": ["@smithy/abort-controller@4.0.4", "", { "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" } }, "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA=="],
+ "@smithy/util-defaults-mode-node/@smithy/property-provider": ["@smithy/property-provider@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-14T1V64o6/ndyrnl1ze1ZhyLzIeYNN47oF/QU6P5m82AEtyOkMJTb0gO1dPubYjyyKuPD6OSVMPDKe+zioOnCg=="],
"@surma/rollup-plugin-off-main-thread/magic-string": ["magic-string@0.25.9", "", { "dependencies": { "sourcemap-codec": "^1.4.8" } }, "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ=="],
@@ -5731,18 +5911,48 @@
"@testing-library/dom/pretty-format": ["pretty-format@27.5.1", "", { "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" } }, "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ=="],
+ "@types/body-parser/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
+ "@types/connect/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
+ "@types/express-serve-static-core/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
+ "@types/jsdom/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
+ "@types/jsonwebtoken/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
+ "@types/ldapjs/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
"@types/mdast/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
+ "@types/node-fetch/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
+ "@types/send/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
+ "@types/serve-static/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
"@types/testing-library__jest-dom/@types/jest": ["@types/jest@29.5.12", "", { "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" } }, "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw=="],
"@types/winston/winston": ["winston@3.11.0", "", { "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", "logform": "^2.4.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", "winston-transport": "^4.5.0" } }, "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g=="],
+ "@types/xml-encryption/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
+ "@types/xml2js/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
+ "@typescript-eslint/parser/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
+ "@typescript-eslint/type-utils/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
+ "@typescript-eslint/typescript-estree/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@typescript-eslint/typescript-estree/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="],
+ "@vitejs/plugin-react/@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="],
+
"accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
"ajv-formats/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
@@ -5751,10 +5961,18 @@
"asn1.js/bn.js": ["bn.js@4.12.2", "", {}, "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw=="],
+ "autoprefixer/fraction.js": ["fraction.js@4.3.7", "", {}, "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew=="],
+
"babel-jest/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
"babel-plugin-root-import/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
+ "body-parser/iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="],
+
+ "body-parser/qs": ["qs@6.15.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ=="],
+
+ "body-parser/raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="],
+
"browser-resolve/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
"browserify-rsa/bn.js": ["bn.js@5.2.2", "", {}, "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw=="],
@@ -5763,12 +5981,16 @@
"browserify-sign/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
+ "bun-types/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
"caniuse-api/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
"chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
+ "cheerio/undici": ["undici@7.16.0", "", {}, "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g=="],
+
"chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"cli-truncate/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
@@ -5783,32 +6005,66 @@
"cookie-parser/cookie-signature": ["cookie-signature@1.0.6", "", {}, "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="],
+ "core-js-compat/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
+
"create-ecdh/bn.js": ["bn.js@4.12.2", "", {}, "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw=="],
+ "css-blank-pseudo/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
+
+ "css-has-pseudo/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
+
"cssnano/lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="],
"cssnano/yaml": ["yaml@1.10.2", "", {}, "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="],
+ "cytoscape-fcose/cose-base": ["cose-base@2.2.0", "", { "dependencies": { "layout-base": "^2.0.0" } }, "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g=="],
+
+ "d3-dsv/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="],
+
+ "d3-sankey/d3-array": ["d3-array@2.12.1", "", { "dependencies": { "internmap": "^1.0.0" } }, "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ=="],
+
+ "d3-sankey/d3-shape": ["d3-shape@1.3.7", "", { "dependencies": { "d3-path": "1" } }, "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw=="],
+
"data-urls/whatwg-url": ["whatwg-url@14.2.0", "", { "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" } }, "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw=="],
"diffie-hellman/bn.js": ["bn.js@4.12.2", "", {}, "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw=="],
- "domexception/webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="],
+ "dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
"error-ex/is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="],
+ "eslint/@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="],
+
+ "eslint/ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
+
+ "eslint/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
+ "eslint/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
+
"eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
"eslint-import-resolver-node/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
+ "eslint-import-resolver-typescript/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
"eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
+ "eslint-plugin-i18next/lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
+
"eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
+ "eslint-plugin-import/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
+
+ "eslint-plugin-jsx-a11y/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
+
+ "eslint-plugin-react/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
+
"execa/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="],
"expect/jest-message-util": ["jest-message-util@29.7.0", "", { "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", "pretty-format": "^29.7.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" } }, "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w=="],
+ "expect/jest-util": ["jest-util@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", "picomatch": "^2.2.3" } }, "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA=="],
+
"express-session/cookie-signature": ["cookie-signature@1.0.7", "", {}, "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA=="],
"express-session/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
@@ -5819,25 +6075,23 @@
"filelist/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
+ "finalhandler/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
"flat-cache/keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
"form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
- "gaxios/https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],
+ "gaxios/https-proxy-agent": ["https-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.0.2", "debug": "4" } }, "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA=="],
- "glob/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="],
+ "gcp-metadata/gaxios": ["gaxios@5.1.3", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^5.0.0", "is-stream": "^2.0.0", "node-fetch": "^2.6.9" } }, "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA=="],
- "google-auth-library/gaxios": ["gaxios@6.2.0", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", "node-fetch": "^2.6.9" } }, "sha512-H6+bHeoEAU5D6XNc6mPKeN5dLZqEDs9Gpk6I+SZBEzK5So58JVrHPmevNi35fRl1J9Y5TaeLW0kYx3pCJ1U2mQ=="],
+ "glob/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="],
"google-auth-library/gcp-metadata": ["gcp-metadata@6.1.1", "", { "dependencies": { "gaxios": "^6.1.1", "google-logging-utils": "^0.0.2", "json-bigint": "^1.0.0" } }, "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A=="],
- "googleapis-common/gaxios": ["gaxios@6.2.0", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", "node-fetch": "^2.6.9" } }, "sha512-H6+bHeoEAU5D6XNc6mPKeN5dLZqEDs9Gpk6I+SZBEzK5So58JVrHPmevNi35fRl1J9Y5TaeLW0kYx3pCJ1U2mQ=="],
+ "happy-dom/whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="],
- "googleapis-common/qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="],
-
- "googleapis-common/uuid": ["uuid@9.0.1", "", { "bin": "dist/bin/uuid" }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
-
- "gtoken/gaxios": ["gaxios@6.2.0", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", "node-fetch": "^2.6.9" } }, "sha512-H6+bHeoEAU5D6XNc6mPKeN5dLZqEDs9Gpk6I+SZBEzK5So58JVrHPmevNi35fRl1J9Y5TaeLW0kYx3pCJ1U2mQ=="],
+ "happy-dom/ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="],
"hast-util-from-html/@types/hast": ["@types/hast@2.3.10", "", { "dependencies": { "@types/unist": "^2" } }, "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw=="],
@@ -5871,10 +6125,16 @@
"http-proxy-agent/agent-base": ["agent-base@7.1.3", "", {}, "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw=="],
+ "http-proxy-agent/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
+ "https-proxy-agent/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
"import-from/resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
"import-in-the-middle/cjs-module-lexer": ["cjs-module-lexer@1.2.3", "", {}, "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ=="],
+ "ioredis/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
"is-bun-module/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"istanbul-lib-instrument/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
@@ -5885,43 +6145,37 @@
"istanbul-lib-source-maps/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
+ "istanbul-lib-source-maps/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
+ "jake/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
+
"jest-changed-files/execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="],
- "jest-changed-files/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
+ "jest-circus/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
"jest-circus/jest-matcher-utils": ["jest-matcher-utils@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "jest-diff": "30.2.0", "pretty-format": "30.2.0" } }, "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg=="],
- "jest-circus/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
-
"jest-circus/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="],
"jest-circus/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
- "jest-cli/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
-
"jest-config/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
- "jest-config/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
-
"jest-config/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="],
"jest-config/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
"jest-diff/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="],
- "jest-each/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
-
"jest-each/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="],
- "jest-environment-node/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="],
+ "jest-environment-jsdom/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
- "jest-environment-node/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="],
-
- "jest-environment-node/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
+ "jest-environment-node/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
"jest-file-loader/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
- "jest-haste-map/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
+ "jest-haste-map/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
"jest-leak-detector/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="],
@@ -5931,24 +6185,18 @@
"jest-message-util/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
- "jest-mock/@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="],
-
- "jest-resolve/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
+ "jest-mock/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
"jest-resolve/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
- "jest-runner/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
+ "jest-runner/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
"jest-runner/source-map-support": ["source-map-support@0.5.13", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w=="],
- "jest-runtime/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="],
+ "jest-runtime/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
"jest-runtime/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
- "jest-runtime/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="],
-
- "jest-runtime/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
-
"jest-runtime/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
"jest-runtime/strip-bom": ["strip-bom@4.0.0", "", {}, "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="],
@@ -5959,28 +6207,24 @@
"jest-snapshot/jest-matcher-utils": ["jest-matcher-utils@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "jest-diff": "30.2.0", "pretty-format": "30.2.0" } }, "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg=="],
- "jest-snapshot/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
-
"jest-snapshot/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="],
"jest-snapshot/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"jest-snapshot/synckit": ["synckit@0.11.11", "", { "dependencies": { "@pkgr/core": "^0.2.9" } }, "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw=="],
- "jest-util/@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="],
-
- "jest-util/ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="],
-
- "jest-util/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
+ "jest-util/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
"jest-validate/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="],
- "jest-watcher/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
+ "jest-watcher/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
- "jest-worker/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
+ "jest-worker/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
"jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
+ "js-yaml/argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
+
"jsdom/decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="],
"jsdom/webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="],
@@ -5991,30 +6235,28 @@
"jsonwebtoken/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
+ "jszip/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
+
"jwks-rsa/@types/express": ["@types/express@4.17.21", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ=="],
+ "jwks-rsa/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
"jwks-rsa/jose": ["jose@4.15.5", "", {}, "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg=="],
"katex/commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="],
"keyv-file/@keyv/serialize": ["@keyv/serialize@1.0.3", "", { "dependencies": { "buffer": "^6.0.3" } }, "sha512-qnEovoOp5Np2JDGonIDL6Ayihw0RhnRh6vxPuHo4RDn1UOzwEo4AeIfpL6UGIrsceWrCMiVPgwRjbHu4vYFc3g=="],
- "keyv-file/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="],
-
"langsmith/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"langsmith/uuid": ["uuid@10.0.0", "", { "bin": "dist/bin/uuid" }, "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ=="],
"ldapauth-fork/lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="],
- "librechat-data-provider/@babel/preset-env": ["@babel/preset-env@7.28.5", "", { "dependencies": { "@babel/compat-data": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.27.1", "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", "@babel/plugin-transform-async-generator-functions": "^7.28.0", "@babel/plugin-transform-async-to-generator": "^7.27.1", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", "@babel/plugin-transform-block-scoping": "^7.28.5", "@babel/plugin-transform-class-properties": "^7.27.1", "@babel/plugin-transform-class-static-block": "^7.28.3", "@babel/plugin-transform-classes": "^7.28.4", "@babel/plugin-transform-computed-properties": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-dotall-regex": "^7.27.1", "@babel/plugin-transform-duplicate-keys": "^7.27.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.0", "@babel/plugin-transform-exponentiation-operator": "^7.28.5", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", "@babel/plugin-transform-json-strings": "^7.27.1", "@babel/plugin-transform-literals": "^7.27.1", "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-modules-systemjs": "^7.28.5", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", "@babel/plugin-transform-numeric-separator": "^7.27.1", "@babel/plugin-transform-object-rest-spread": "^7.28.4", "@babel/plugin-transform-object-super": "^7.27.1", "@babel/plugin-transform-optional-catch-binding": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-private-methods": "^7.27.1", "@babel/plugin-transform-private-property-in-object": "^7.27.1", "@babel/plugin-transform-property-literals": "^7.27.1", "@babel/plugin-transform-regenerator": "^7.28.4", "@babel/plugin-transform-regexp-modifiers": "^7.27.1", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", "@babel/plugin-transform-spread": "^7.27.1", "@babel/plugin-transform-sticky-regex": "^7.27.1", "@babel/plugin-transform-template-literals": "^7.27.1", "@babel/plugin-transform-typeof-symbol": "^7.27.1", "@babel/plugin-transform-unicode-escapes": "^7.27.1", "@babel/plugin-transform-unicode-property-regex": "^7.27.1", "@babel/plugin-transform-unicode-regex": "^7.27.1", "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", "babel-plugin-polyfill-regenerator": "^0.6.5", "core-js-compat": "^3.43.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg=="],
-
- "librechat-data-provider/@babel/preset-react": ["@babel/preset-react@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-transform-react-display-name": "^7.28.0", "@babel/plugin-transform-react-jsx": "^7.27.1", "@babel/plugin-transform-react-jsx-development": "^7.27.1", "@babel/plugin-transform-react-pure-annotations": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ=="],
-
- "librechat-data-provider/@babel/preset-typescript": ["@babel/preset-typescript@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g=="],
-
"lint-staged/chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
+ "lint-staged/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
"log-update/ansi-escapes": ["ansi-escapes@7.0.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw=="],
"log-update/slice-ansi": ["slice-ansi@7.1.0", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg=="],
@@ -6027,30 +6269,48 @@
"lru-memoizer/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="],
- "mathjs/fraction.js": ["fraction.js@5.3.4", "", {}, "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ=="],
-
"mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
"mdast-util-math/unist-util-remove-position": ["unist-util-remove-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q=="],
"mdast-util-mdx-jsx/unist-util-remove-position": ["unist-util-remove-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q=="],
+ "memorystore/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
+ "mermaid/marked": ["marked@16.4.2", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA=="],
+
+ "mermaid/uuid": ["uuid@11.1.0", "", { "bin": "dist/esm/bin/uuid" }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="],
+
+ "micromark/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"miller-rabin/bn.js": ["bn.js@4.12.2", "", {}, "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw=="],
+ "mlly/acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
+
+ "monaco-editor/dompurify": ["dompurify@3.2.7", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw=="],
+
"mongodb-connection-string-url/whatwg-url": ["whatwg-url@14.2.0", "", { "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" } }, "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw=="],
+ "mongodb-memory-server-core/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
"mongodb-memory-server-core/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
- "multer/mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": "bin/cmd.js" }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="],
+ "mquery/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
"multer/type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="],
+ "new-find-package-json/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
"node-stdlib-browser/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="],
"node-stdlib-browser/pkg-dir": ["pkg-dir@5.0.0", "", { "dependencies": { "find-up": "^5.0.0" } }, "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA=="],
+ "nodemon/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
+ "nodemon/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
+
"nodemon/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
@@ -6073,18 +6333,28 @@
"playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
+ "postcss/nanoid": ["nanoid@3.3.8", "", { "bin": "bin/nanoid.cjs" }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="],
+
+ "postcss-attribute-case-insensitive/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
+
"postcss-colormin/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
"postcss-convert-values/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
+ "postcss-custom-selectors/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
+
+ "postcss-dir-pseudo-class/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
+
+ "postcss-focus-visible/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
+
+ "postcss-focus-within/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
+
"postcss-import/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
"postcss-load-config/lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="],
"postcss-load-config/yaml": ["yaml@1.10.2", "", {}, "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="],
- "postcss-loader/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
-
"postcss-merge-rules/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
"postcss-minify-params/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
@@ -6093,14 +6363,20 @@
"postcss-modules-scope/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
+ "postcss-nesting/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
+
"postcss-normalize-unicode/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
- "postcss-preset-env/autoprefixer": ["autoprefixer@10.4.17", "", { "dependencies": { "browserslist": "^4.22.2", "caniuse-lite": "^1.0.30001578", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": "bin/autoprefixer" }, "sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg=="],
+ "postcss-preset-env/autoprefixer": ["autoprefixer@10.4.27", "", { "dependencies": { "browserslist": "^4.28.1", "caniuse-lite": "^1.0.30001774", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA=="],
- "postcss-preset-env/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
+ "postcss-preset-env/browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="],
+
+ "postcss-pseudo-class-any-link/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
"postcss-reduce-initial/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
+ "postcss-selector-not/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
+
"pretty-format/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="],
"pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
@@ -6133,10 +6409,14 @@
"remark-supersub/unist-util-visit": ["unist-util-visit@4.1.2", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0", "unist-util-visit-parents": "^5.1.1" } }, "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg=="],
+ "require-in-the-middle/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
"resolve-cwd/resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
"restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
+ "rollup/@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
+
"rollup-plugin-postcss/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
"rollup-plugin-typescript2/@rollup/pluginutils": ["@rollup/pluginutils@4.2.1", "", { "dependencies": { "estree-walker": "^2.0.1", "picomatch": "^2.2.2" } }, "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ=="],
@@ -6147,7 +6427,9 @@
"rollup-pluginutils/estree-walker": ["estree-walker@0.6.1", "", {}, "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w=="],
- "schema-utils/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
+ "router/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
+ "send/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
"sharp/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
@@ -6173,6 +6455,8 @@
"sucrase/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
+ "superagent/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
"superagent/mime": ["mime@2.6.0", "", { "bin": "cli.js" }, "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="],
"superagent/qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="],
@@ -6181,6 +6465,10 @@
"svgo/css-select": ["css-select@4.3.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.0.1", "domhandler": "^4.3.1", "domutils": "^2.8.0", "nth-check": "^2.0.1" } }, "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ=="],
+ "svgo/sax": ["sax@1.5.0", "", {}, "sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA=="],
+
+ "swr/use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
+
"tailwindcss/arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="],
"tailwindcss/lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="],
@@ -6193,17 +6481,9 @@
"terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="],
- "terser-webpack-plugin/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
-
- "terser-webpack-plugin/jest-worker": ["jest-worker@27.5.1", "", { "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg=="],
-
"test-exclude/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
- "tinyglobby/fdir": ["fdir@6.4.4", "", { "peerDependencies": { "picomatch": "^3 || ^4" } }, "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg=="],
-
- "tinyglobby/picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="],
-
- "ts-node/diff": ["diff@4.0.2", "", {}, "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="],
+ "test-exclude/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": "lib/cli.js" }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="],
@@ -6225,19 +6505,17 @@
"vasync/verror": ["verror@1.10.0", "", { "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw=="],
+ "verror/core-util-is": ["core-util-is@1.0.2", "", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="],
+
"vfile-location/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
"vfile-location/vfile": ["vfile@5.3.7", "", { "dependencies": { "@types/unist": "^2.0.0", "is-buffer": "^2.0.0", "unist-util-stringify-position": "^3.0.0", "vfile-message": "^3.0.0" } }, "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g=="],
- "webpack/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
-
- "webpack/eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="],
-
- "webpack/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
+ "vite/postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="],
"winston-daily-rotate-file/winston-transport": ["winston-transport@4.7.0", "", { "dependencies": { "logform": "^2.3.2", "readable-stream": "^3.6.0", "triple-beam": "^1.3.0" } }, "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg=="],
- "workbox-build/@babel/preset-env": ["@babel/preset-env@7.23.9", "", { "dependencies": { "@babel/compat-data": "^7.23.5", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-validator-option": "^7.23.5", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", "@babel/plugin-syntax-import-assertions": "^7.23.3", "@babel/plugin-syntax-import-attributes": "^7.23.3", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.23.3", "@babel/plugin-transform-async-generator-functions": "^7.23.9", "@babel/plugin-transform-async-to-generator": "^7.23.3", "@babel/plugin-transform-block-scoped-functions": "^7.23.3", "@babel/plugin-transform-block-scoping": "^7.23.4", "@babel/plugin-transform-class-properties": "^7.23.3", "@babel/plugin-transform-class-static-block": "^7.23.4", "@babel/plugin-transform-classes": "^7.23.8", "@babel/plugin-transform-computed-properties": "^7.23.3", "@babel/plugin-transform-destructuring": "^7.23.3", "@babel/plugin-transform-dotall-regex": "^7.23.3", "@babel/plugin-transform-duplicate-keys": "^7.23.3", "@babel/plugin-transform-dynamic-import": "^7.23.4", "@babel/plugin-transform-exponentiation-operator": "^7.23.3", "@babel/plugin-transform-export-namespace-from": "^7.23.4", "@babel/plugin-transform-for-of": "^7.23.6", "@babel/plugin-transform-function-name": "^7.23.3", "@babel/plugin-transform-json-strings": "^7.23.4", "@babel/plugin-transform-literals": "^7.23.3", "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", "@babel/plugin-transform-member-expression-literals": "^7.23.3", "@babel/plugin-transform-modules-amd": "^7.23.3", "@babel/plugin-transform-modules-commonjs": "^7.23.3", "@babel/plugin-transform-modules-systemjs": "^7.23.9", "@babel/plugin-transform-modules-umd": "^7.23.3", "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", "@babel/plugin-transform-new-target": "^7.23.3", "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", "@babel/plugin-transform-numeric-separator": "^7.23.4", "@babel/plugin-transform-object-rest-spread": "^7.23.4", "@babel/plugin-transform-object-super": "^7.23.3", "@babel/plugin-transform-optional-catch-binding": "^7.23.4", "@babel/plugin-transform-optional-chaining": "^7.23.4", "@babel/plugin-transform-parameters": "^7.23.3", "@babel/plugin-transform-private-methods": "^7.23.3", "@babel/plugin-transform-private-property-in-object": "^7.23.4", "@babel/plugin-transform-property-literals": "^7.23.3", "@babel/plugin-transform-regenerator": "^7.23.3", "@babel/plugin-transform-reserved-words": "^7.23.3", "@babel/plugin-transform-shorthand-properties": "^7.23.3", "@babel/plugin-transform-spread": "^7.23.3", "@babel/plugin-transform-sticky-regex": "^7.23.3", "@babel/plugin-transform-template-literals": "^7.23.3", "@babel/plugin-transform-typeof-symbol": "^7.23.3", "@babel/plugin-transform-unicode-escapes": "^7.23.3", "@babel/plugin-transform-unicode-property-regex": "^7.23.3", "@babel/plugin-transform-unicode-regex": "^7.23.3", "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.8", "babel-plugin-polyfill-corejs3": "^0.9.0", "babel-plugin-polyfill-regenerator": "^0.5.5", "core-js-compat": "^3.31.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-3kBGTNBBk9DQiPoXYS0g0BYlwTQYUTifqgKTjxUwEUkduRT2QOa0FPGBJ+NROQhGyYO5BuTJwGvBnqKDykac6A=="],
+ "workbox-build/@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="],
"workbox-build/@rollup/plugin-replace": ["@rollup/plugin-replace@2.4.2", "", { "dependencies": { "@rollup/pluginutils": "^3.1.0", "magic-string": "^0.25.7" }, "peerDependencies": { "rollup": "^1.20.0 || ^2.0.0" } }, "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg=="],
@@ -6245,7 +6523,7 @@
"workbox-build/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="],
- "workbox-build/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
+ "workbox-build/glob": ["glob@11.1.0", "", { "dependencies": { "foreground-child": "^3.3.1", "jackspeak": "^4.1.1", "minimatch": "^10.1.1", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw=="],
"workbox-build/pretty-bytes": ["pretty-bytes@5.6.0", "", {}, "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg=="],
@@ -6293,6 +6571,8 @@
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
+ "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.4", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ScDCpasxH7w1HXHYbtk3jcivjvdA1VICyAdgvVqKhKKwxi+MTwZEqFw0minE+oZ7F07oF25xh4FGJxgqgShz0A=="],
+
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/property-provider": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-bAllBpmaWINpf0brXQWh/hjkBctapknZPYb3FJRlBHytEGHi7TpgqBXi8riT0tc6RVWChhnw58rQz22acOmBuw=="],
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-jEvb8C7tuRBFhe8vZY9vm9z6UQnbP85IMEt3Qiz0dxAd341Hgu0lOzMv5mSKQ5yBnTLq+t3FPKgD9tIiHLqxSQ=="],
@@ -6317,6 +6597,12 @@
"@aws-sdk/client-bedrock-agent-runtime/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/core/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/eventstream-serde-browser/@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.4", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GNI/IXaY/XBB1SkGBFmbW033uWA0tj085eCxYih0eccUe/PFR7+UBQv9HNDk2fD9TJu7UVsCWsH99TkpEPSOzQ=="],
+
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/eventstream-serde-node/@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.4", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GNI/IXaY/XBB1SkGBFmbW033uWA0tj085eCxYih0eccUe/PFR7+UBQv9HNDk2fD9TJu7UVsCWsH99TkpEPSOzQ=="],
+
"@aws-sdk/client-bedrock-agent-runtime/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
"@aws-sdk/client-bedrock-agent-runtime/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
@@ -6325,6 +6611,8 @@
"@aws-sdk/client-bedrock-agent-runtime/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/middleware-retry/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
"@aws-sdk/client-bedrock-agent-runtime/@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
"@aws-sdk/client-bedrock-agent-runtime/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-y5ozxeQ9omVjbnJo9dtTsdXj9BEvGx2X8xvRgKnV+/7wLBuYJQL6dOa/qMY6omyHi7yjt1OA97jZLoVRYi8lxA=="],
@@ -6349,62 +6637,6 @@
"@aws-sdk/client-bedrock-agent-runtime/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.6", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-P1TXDHuQMadTMTOBv4oElZMURU4uyEhxhHfn+qOc2iofW9Rd4sZtBGx58Lzk112rIGVEYZT8eUMK4NftpewpRA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-VR2V6dRELmzwAsCpK4GqxUi6UW5WNhAXS9F9AzWi5jvijwJo3nH92YNJUP4quMpgFZxJHEWyXLWgPjh9u0zYOA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-inF09lh9SlHj63Vmr5d+LmwPXZc2IbK8lAruhOr3KLsZAIHEgHgGPXWDC2ukTEMzg0pkexQ6FOhXXad6klK4RA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.952.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/credential-provider-env": "3.947.0", "@aws-sdk/credential-provider-http": "3.947.0", "@aws-sdk/credential-provider-login": "3.952.0", "@aws-sdk/credential-provider-process": "3.947.0", "@aws-sdk/credential-provider-sso": "3.952.0", "@aws-sdk/credential-provider-web-identity": "3.952.0", "@aws-sdk/nested-clients": "3.952.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-N5B15SwzMkZ8/LLopNksTlPEWWZn5tbafZAUfMY5Xde4rSHGWmv5H/ws2M3P8L0X77E2wKnOJsNmu+GsArBreQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-WpanFbHe08SP1hAJNeDdBDVz9SGgMu/gc0XJ9u3uNpW99nKZjDpvPRAdW7WLA4K6essMjxWkguIGNOpij6Do2Q=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.952.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.948.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/token-providers": "3.952.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-1CQdP5RzxeXuEfytbAD5TgreY1c9OacjtCdO8+n9m05tpzBABoNBof0hcjzw1dtrWFH7deyUgfwCl1TAN3yBWQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.952.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.952.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-5hJbfaZdHDAP8JlwplNbXJAat9Vv7L0AbTZzkbPIgjHhC3vrMf5r3a6I1HWFp5i5pXo7J45xyuf5uQGZJxJlCg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/property-provider": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/url-parser": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-xBmawExyTzOjbhzkZwg+vVm/khg28kG+rj2sbGlULjFd1jI70sv/cbpaR0Ev4Yfd6CpDUDRMe64cTqR//wAOyA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.1", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tph+oQYPbpN6NamF030hx1gb5YN2Plog+GLaRHpoEDwp8+ZPG26rIJvStG9hkWzN2HBn3HcWg0sHeB0tmkYzqA=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-browser/@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.6", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-olIfZ230B64TvPD6b0tPvrEp2eB0FkyL3KvDlqF4RVmIc/kn3orzXnV6DTQdOOW5UU+M5zKY3/BU47X420/oPw=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-node/@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.6", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-olIfZ230B64TvPD6b0tPvrEp2eB0FkyL3KvDlqF4RVmIc/kn3orzXnV6DTQdOOW5UU+M5zKY3/BU47X420/oPw=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.1", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tph+oQYPbpN6NamF030hx1gb5YN2Plog+GLaRHpoEDwp8+ZPG26rIJvStG9hkWzN2HBn3HcWg0sHeB0tmkYzqA=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0" } }, "sha512-Q73XBrzJlGTut2nf5RglSntHKgAG0+KiTJdO5QQblLfr4TdliGwIAha1iZIjwisc3rA5ulzqwwsYC6xrclxVQg=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.1", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tph+oQYPbpN6NamF030hx1gb5YN2Plog+GLaRHpoEDwp8+ZPG26rIJvStG9hkWzN2HBn3HcWg0sHeB0tmkYzqA=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-YmWxl32SQRw/kIRccSOxzS/Ib8/b5/f9ex0r5PR40jRJg8X1wgM3KrR2In+8zvOGVhRSXgvyQpw9yOSlmfmSnA=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-browser/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/property-provider": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/url-parser": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-xBmawExyTzOjbhzkZwg+vVm/khg28kG+rj2sbGlULjFd1jI70sv/cbpaR0Ev4Yfd6CpDUDRMe64cTqR//wAOyA=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-node/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0" } }, "sha512-Q73XBrzJlGTut2nf5RglSntHKgAG0+KiTJdO5QQblLfr4TdliGwIAha1iZIjwisc3rA5ulzqwwsYC6xrclxVQg=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
"@aws-sdk/client-cognito-identity/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@4.1.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "@smithy/protocol-http": "^4.1.0", "@smithy/types": "^3.3.0", "@smithy/util-hex-encoding": "^3.0.0", "@smithy/util-middleware": "^3.0.3", "@smithy/util-uri-escape": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aRryp2XNZeRcOtuJoxjydO6QTaVhxx/vjaR+gx7ZjaFgrgPRyZ3HCTbfwqYj6ZWEBHkCSUfcaymKPURaByukag=="],
"@aws-sdk/client-cognito-identity/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@3.1.4", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ=="],
@@ -6443,6 +6675,8 @@
"@aws-sdk/client-kendra/@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
+ "@aws-sdk/client-kendra/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.4", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ScDCpasxH7w1HXHYbtk3jcivjvdA1VICyAdgvVqKhKKwxi+MTwZEqFw0minE+oZ7F07oF25xh4FGJxgqgShz0A=="],
+
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/property-provider": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-bAllBpmaWINpf0brXQWh/hjkBctapknZPYb3FJRlBHytEGHi7TpgqBXi8riT0tc6RVWChhnw58rQz22acOmBuw=="],
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-jEvb8C7tuRBFhe8vZY9vm9z6UQnbP85IMEt3Qiz0dxAd341Hgu0lOzMv5mSKQ5yBnTLq+t3FPKgD9tIiHLqxSQ=="],
@@ -6499,10 +6733,6 @@
"@aws-sdk/client-kendra/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/client-s3/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
-
- "@aws-sdk/client-s3/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
-
"@aws-sdk/client-sso-oidc/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@4.1.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "@smithy/protocol-http": "^4.1.0", "@smithy/types": "^3.3.0", "@smithy/util-hex-encoding": "^3.0.0", "@smithy/util-middleware": "^3.0.3", "@smithy/util-uri-escape": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aRryp2XNZeRcOtuJoxjydO6QTaVhxx/vjaR+gx7ZjaFgrgPRyZ3HCTbfwqYj6ZWEBHkCSUfcaymKPURaByukag=="],
"@aws-sdk/client-sso-oidc/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@3.1.4", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ=="],
@@ -6589,104 +6819,46 @@
"@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="],
-
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core": ["@smithy/core@3.19.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.7", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-stream": "^4.5.7", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-Y9oHXpBcXQgYHOcAEmxjkDilUbSTkgKjoHYed3WaYUH8jngq8lPWDBSpjHblJ9uOgBdy5mh3pzebrScDdYr29w=="],
-
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.6", "", { "dependencies": { "@smithy/property-provider": "^4.2.6", "@smithy/shared-ini-file-loader": "^4.4.1", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-fYEyL59Qe82Ha1p97YQTMEQPJYmBS+ux76foqluaTVWoG9Px5J53w6NvXZNE3wP7lIicLDF7Vj1Em18XTX7fsA=="],
-
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.6", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-P1TXDHuQMadTMTOBv4oElZMURU4uyEhxhHfn+qOc2iofW9Rd4sZtBGx58Lzk112rIGVEYZT8eUMK4NftpewpRA=="],
-
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.10.1", "", { "dependencies": { "@smithy/core": "^3.19.0", "@smithy/middleware-endpoint": "^4.4.0", "@smithy/middleware-stack": "^4.2.6", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-stream": "^4.5.7", "tslib": "^2.6.2" } }, "sha512-1ovWdxzYprhq+mWqiGZlt3kF69LJthuQcfY9BIyHx9MywTFKzFapluku1QXoaBB43GCsLDxNqS+1v30ure69AA=="],
-
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qrvXUkxBSAFomM3/OEMuDVwjh4wtqK8D2uDZPShzIqOylPst6gor2Cdp6+XrH4dyksAWq/bE2aSDYBTTnj0Rxg=="],
-
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
-
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.758.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.758.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", "@aws-sdk/middleware-recursion-detection": "3.734.0", "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", "@aws-sdk/util-endpoints": "3.743.0", "@aws-sdk/util-user-agent-browser": "3.734.0", "@aws-sdk/util-user-agent-node": "3.758.0", "@smithy/config-resolver": "^4.0.1", "@smithy/core": "^3.1.5", "@smithy/fetch-http-handler": "^5.0.1", "@smithy/hash-node": "^4.0.1", "@smithy/invalid-dependency": "^4.0.1", "@smithy/middleware-content-length": "^4.0.1", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/middleware-retry": "^4.0.7", "@smithy/middleware-serde": "^4.0.2", "@smithy/middleware-stack": "^4.0.1", "@smithy/node-config-provider": "^4.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/protocol-http": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.7", "@smithy/util-defaults-mode-node": "^4.0.7", "@smithy/util-endpoints": "^3.0.1", "@smithy/util-middleware": "^4.0.1", "@smithy/util-retry": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-YZ5s7PSvyF3Mt2h1EQulCG93uybprNGbBkPmVuy/HMMfbFTt4iL3SbKjxqvOZelm86epFfj7pvK7FliI2WOEcg=="],
-
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.758.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.758.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", "@aws-sdk/middleware-recursion-detection": "3.734.0", "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", "@aws-sdk/util-endpoints": "3.743.0", "@aws-sdk/util-user-agent-browser": "3.734.0", "@aws-sdk/util-user-agent-node": "3.758.0", "@smithy/config-resolver": "^4.0.1", "@smithy/core": "^3.1.5", "@smithy/fetch-http-handler": "^5.0.1", "@smithy/hash-node": "^4.0.1", "@smithy/invalid-dependency": "^4.0.1", "@smithy/middleware-content-length": "^4.0.1", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/middleware-retry": "^4.0.7", "@smithy/middleware-serde": "^4.0.2", "@smithy/middleware-stack": "^4.0.1", "@smithy/node-config-provider": "^4.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/protocol-http": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.7", "@smithy/util-defaults-mode-node": "^4.0.7", "@smithy/util-endpoints": "^3.0.1", "@smithy/util-middleware": "^4.0.1", "@smithy/util-retry": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-BoGO6IIWrLyLxQG6txJw6RT2urmbtlwfggapNCrNPyYjlXpzTSJhBYjndg7TpDATFd0SXL0zm8y/tXsUXNkdYQ=="],
-
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.758.0", "", { "dependencies": { "@aws-sdk/nested-clients": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-ckptN1tNrIfQUaGWm/ayW1ddG+imbKN7HHhjFdS4VfItsP0QQOB0+Ov+tpgb4MoNR4JaUghMIVStjIeHN2ks1w=="],
-
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.758.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.758.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", "@aws-sdk/middleware-recursion-detection": "3.734.0", "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", "@aws-sdk/util-endpoints": "3.743.0", "@aws-sdk/util-user-agent-browser": "3.734.0", "@aws-sdk/util-user-agent-node": "3.758.0", "@smithy/config-resolver": "^4.0.1", "@smithy/core": "^3.1.5", "@smithy/fetch-http-handler": "^5.0.1", "@smithy/hash-node": "^4.0.1", "@smithy/invalid-dependency": "^4.0.1", "@smithy/middleware-content-length": "^4.0.1", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/middleware-retry": "^4.0.7", "@smithy/middleware-serde": "^4.0.2", "@smithy/middleware-stack": "^4.0.1", "@smithy/node-config-provider": "^4.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/protocol-http": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.7", "@smithy/util-defaults-mode-node": "^4.0.7", "@smithy/util-endpoints": "^3.0.1", "@smithy/util-middleware": "^4.0.1", "@smithy/util-retry": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-YZ5s7PSvyF3Mt2h1EQulCG93uybprNGbBkPmVuy/HMMfbFTt4iL3SbKjxqvOZelm86epFfj7pvK7FliI2WOEcg=="],
-
"@aws-sdk/credential-providers/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@3.1.4", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ=="],
- "@aws-sdk/middleware-websocket/@smithy/eventstream-serde-browser/@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.6", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-olIfZ230B64TvPD6b0tPvrEp2eB0FkyL3KvDlqF4RVmIc/kn3orzXnV6DTQdOOW5UU+M5zKY3/BU47X420/oPw=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.758.0", "", { "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/types": "3.734.0", "@aws-sdk/util-arn-parser": "3.723.0", "@smithy/core": "^3.1.5", "@smithy/node-config-provider": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/signature-v4": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/util-config-provider": "^4.0.0", "@smithy/util-middleware": "^4.0.1", "@smithy/util-stream": "^4.1.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-6mJ2zyyHPYSV6bAcaFpsdoXZJeQlR1QgBnZZ6juY/+dcYiuyWCdyLUbGzSZSE7GTfx6i+9+QWFeoIMlWKgU63A=="],
- "@aws-sdk/middleware-websocket/@smithy/fetch-http-handler/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4": ["@smithy/signature-v4@5.3.4", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ScDCpasxH7w1HXHYbtk3jcivjvdA1VICyAdgvVqKhKKwxi+MTwZEqFw0minE+oZ7F07oF25xh4FGJxgqgShz0A=="],
- "@aws-sdk/middleware-websocket/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core": ["@smithy/core@3.1.5", "", { "dependencies": { "@smithy/middleware-serde": "^4.0.2", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-middleware": "^4.0.1", "@smithy/util-stream": "^4.1.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-HLclGWPkCsekQgsyzxLhCQLa8THWXtB5PxyYN+2O6nkyLt550KQKTlbV2D1/j5dNIQapAZM1+qFnpBFxZQkgCA=="],
- "@aws-sdk/middleware-websocket/@smithy/signature-v4/@smithy/util-middleware": ["@smithy/util-middleware@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qrvXUkxBSAFomM3/OEMuDVwjh4wtqK8D2uDZPShzIqOylPst6gor2Cdp6+XrH4dyksAWq/bE2aSDYBTTnj0Rxg=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.0.2", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ=="],
- "@aws-sdk/middleware-websocket/@smithy/signature-v4/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/node-config-provider": ["@smithy/node-config-provider@4.0.1", "", { "dependencies": { "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ=="],
- "@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw=="],
- "@aws-sdk/nested-clients/@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.0.1", "", { "dependencies": { "@smithy/querystring-parser": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g=="],
- "@aws-sdk/nested-clients/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.6", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-P1TXDHuQMadTMTOBv4oElZMURU4uyEhxhHfn+qOc2iofW9Rd4sZtBGx58Lzk112rIGVEYZT8eUMK4NftpewpRA=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
- "@aws-sdk/nested-clients/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/core": ["@smithy/core@3.1.5", "", { "dependencies": { "@smithy/middleware-serde": "^4.0.2", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-middleware": "^4.0.1", "@smithy/util-stream": "^4.1.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-HLclGWPkCsekQgsyzxLhCQLa8THWXtB5PxyYN+2O6nkyLt550KQKTlbV2D1/j5dNIQapAZM1+qFnpBFxZQkgCA=="],
- "@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.7", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.7", "@smithy/node-http-handler": "^4.4.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Uuy4S5Aj4oF6k1z+i2OtIBJUns4mlg29Ph4S+CqjR+f4XXpSFVgTCYLzMszHJTicYDBxKFtwq2/QSEDSS5l02A=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA=="],
- "@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.1.2", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-hex-encoding": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw=="],
- "@aws-sdk/nested-clients/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.1", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tph+oQYPbpN6NamF030hx1gb5YN2Plog+GLaRHpoEDwp8+ZPG26rIJvStG9hkWzN2HBn3HcWg0sHeB0tmkYzqA=="],
+ "@aws-sdk/util-format-url/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
- "@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0" } }, "sha512-Q73XBrzJlGTut2nf5RglSntHKgAG0+KiTJdO5QQblLfr4TdliGwIAha1iZIjwisc3rA5ulzqwwsYC6xrclxVQg=="],
-
- "@aws-sdk/nested-clients/@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
-
- "@aws-sdk/nested-clients/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.1", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tph+oQYPbpN6NamF030hx1gb5YN2Plog+GLaRHpoEDwp8+ZPG26rIJvStG9hkWzN2HBn3HcWg0sHeB0tmkYzqA=="],
-
- "@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.7", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.7", "@smithy/node-http-handler": "^4.4.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Uuy4S5Aj4oF6k1z+i2OtIBJUns4mlg29Ph4S+CqjR+f4XXpSFVgTCYLzMszHJTicYDBxKFtwq2/QSEDSS5l02A=="],
-
- "@aws-sdk/nested-clients/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-YmWxl32SQRw/kIRccSOxzS/Ib8/b5/f9ex0r5PR40jRJg8X1wgM3KrR2In+8zvOGVhRSXgvyQpw9yOSlmfmSnA=="],
-
- "@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/nested-clients/@smithy/util-defaults-mode-browser/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
-
- "@aws-sdk/nested-clients/@smithy/util-defaults-mode-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/property-provider": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/url-parser": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-xBmawExyTzOjbhzkZwg+vVm/khg28kG+rj2sbGlULjFd1jI70sv/cbpaR0Ev4Yfd6CpDUDRMe64cTqR//wAOyA=="],
-
- "@aws-sdk/nested-clients/@smithy/util-defaults-mode-node/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
-
- "@aws-sdk/nested-clients/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0" } }, "sha512-Q73XBrzJlGTut2nf5RglSntHKgAG0+KiTJdO5QQblLfr4TdliGwIAha1iZIjwisc3rA5ulzqwwsYC6xrclxVQg=="],
-
- "@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/token-providers/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="],
-
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core": ["@smithy/core@3.19.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.7", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-stream": "^4.5.7", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-Y9oHXpBcXQgYHOcAEmxjkDilUbSTkgKjoHYed3WaYUH8jngq8lPWDBSpjHblJ9uOgBdy5mh3pzebrScDdYr29w=="],
-
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.6", "", { "dependencies": { "@smithy/property-provider": "^4.2.6", "@smithy/shared-ini-file-loader": "^4.4.1", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-fYEyL59Qe82Ha1p97YQTMEQPJYmBS+ux76foqluaTVWoG9Px5J53w6NvXZNE3wP7lIicLDF7Vj1Em18XTX7fsA=="],
-
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/protocol-http": ["@smithy/protocol-http@5.3.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qLRZzP2+PqhE3OSwvY2jpBbP0WKTZ9opTsn+6IWYI0SKVpbG+imcfNxXPq9fj5XeaUTr7odpsNpK6dmoiM1gJQ=="],
-
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.6", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-P1TXDHuQMadTMTOBv4oElZMURU4uyEhxhHfn+qOc2iofW9Rd4sZtBGx58Lzk112rIGVEYZT8eUMK4NftpewpRA=="],
-
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.10.1", "", { "dependencies": { "@smithy/core": "^3.19.0", "@smithy/middleware-endpoint": "^4.4.0", "@smithy/middleware-stack": "^4.2.6", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-stream": "^4.5.7", "tslib": "^2.6.2" } }, "sha512-1ovWdxzYprhq+mWqiGZlt3kF69LJthuQcfY9BIyHx9MywTFKzFapluku1QXoaBB43GCsLDxNqS+1v30ure69AA=="],
-
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qrvXUkxBSAFomM3/OEMuDVwjh4wtqK8D2uDZPShzIqOylPst6gor2Cdp6+XrH4dyksAWq/bE2aSDYBTTnj0Rxg=="],
-
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@azure/core-xml/fast-xml-parser/strnum": ["strnum@2.0.5", "", {}, "sha512-YAT3K/sgpCUxhxNMrrdhtod3jckkpYwH6JAuwmUdXZsmzH1wUyzTMrrK2wYCEEqlKwrWDd35NeuUkbBy/1iK+Q=="],
+ "@babel/helper-compilation-targets/browserslist/baseline-browser-mapping": ["baseline-browser-mapping@2.8.28", "", { "bin": "dist/cli.js" }, "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ=="],
"@babel/helper-compilation-targets/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
"@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
+ "@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
"@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.5.0", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q=="],
"@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.5.0", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q=="],
@@ -6695,13 +6867,21 @@
"@babel/plugin-transform-runtime/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.5.0", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q=="],
- "@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.23.0", "", { "dependencies": { "@babel/types": "^7.23.0" } }, "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA=="],
+ "@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
- "@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw=="],
+ "@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
- "@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.22.20", "", { "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-member-expression-to-functions": "^7.22.15", "@babel/helper-optimise-call-expression": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw=="],
+ "@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
- "@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q=="],
+ "@google/genai/google-auth-library/gaxios": ["gaxios@7.1.3", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2", "rimraf": "^5.0.1" } }, "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ=="],
+
+ "@google/genai/google-auth-library/gcp-metadata": ["gcp-metadata@8.1.2", "", { "dependencies": { "gaxios": "^7.0.0", "google-logging-utils": "^1.0.0", "json-bigint": "^1.0.0" } }, "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg=="],
+
+ "@google/genai/google-auth-library/gtoken": ["gtoken@8.0.0", "", { "dependencies": { "gaxios": "^7.0.0", "jws": "^4.0.0" } }, "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw=="],
+
+ "@grpc/grpc-js/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
+ "@grpc/proto-loader/protobufjs/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
"@headlessui/react/@tanstack/react-virtual/@tanstack/virtual-core": ["@tanstack/virtual-core@3.13.12", "", {}, "sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA=="],
@@ -6711,36 +6891,34 @@
"@istanbuljs/load-nyc-config/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="],
- "@istanbuljs/load-nyc-config/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
+ "@jest/console/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
+ "@jest/core/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
"@jest/core/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
- "@jest/environment-jsdom-abstract/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="],
+ "@jest/environment-jsdom-abstract/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
- "@jest/environment/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="],
-
- "@jest/environment/@jest/fake-timers/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
-
- "@jest/environment/jest-mock/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
+ "@jest/environment/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
"@jest/expect/expect/@jest/expect-utils": ["@jest/expect-utils@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0" } }, "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA=="],
"@jest/expect/expect/jest-matcher-utils": ["jest-matcher-utils@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "jest-diff": "30.2.0", "pretty-format": "30.2.0" } }, "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg=="],
- "@jest/expect/expect/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="],
+ "@jest/fake-timers/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
- "@jest/expect/expect/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
+ "@jest/pattern/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
- "@jest/fake-timers/@jest/types/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="],
-
- "@jest/fake-timers/jest-message-util/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
-
- "@jest/globals/jest-mock/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
+ "@jest/reporters/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
"@jest/reporters/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
+ "@jest/reporters/glob/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
+
"@jest/reporters/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
+ "@jest/types/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/eventstream-handler-node": ["@aws-sdk/eventstream-handler-node@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/eventstream-codec": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-DTKHeH1Bk17zSdoa5qXPGwCmZXuhQReqXOVW2/jIVX8NGVvnraH7WppGPlQxBjFtwSSwVTgzH2NVPgediQphNA=="],
@@ -6773,6 +6951,12 @@
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.4", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-d5T7ZS3J/r8P/PDjgmCcutmNxnSRvPH1U6iHeXjzI50sMr78GLmFcrczLw33Ap92oEKqa4CLrkAPeSSOqvGdUA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-config-resolver": ["@smithy/eventstream-serde-config-resolver@4.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-lxfDT0UuSc1HqltOGsTEAlZ6H29gpfDSdEPTapD5G63RbnYToZ+ezjzdonCCH90j5tRRCw3aLXVbiZaBW3VRVg=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-node": ["@smithy/eventstream-serde-node@4.2.4", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-TPhiGByWnYyzcpU/K3pO5V7QgtXYpE0NaJPEZBCa1Y5jlw5SjqzMSbFiLb+ZkJhqoQc0ImGyVINqnq1ze0ZRcQ=="],
+
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/hash-node": ["@smithy/hash-node@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw=="],
@@ -6793,8 +6977,12 @@
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/protocol-http": ["@smithy/protocol-http@5.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw=="],
+
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/types": ["@smithy/types@4.8.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-N0Zn0OT1zc+NA+UVfkYqQzviRh5ucWwO7mBV3TmHHprMnfcJNfhlPicDkBHi0ewbh+y3evR6cNAW0Raxvb01NA=="],
+
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
@@ -6809,12 +6997,16 @@
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
+
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/property-provider": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-bAllBpmaWINpf0brXQWh/hjkBctapknZPYb3FJRlBHytEGHi7TpgqBXi8riT0tc6RVWChhnw58rQz22acOmBuw=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-jEvb8C7tuRBFhe8vZY9vm9z6UQnbP85IMEt3Qiz0dxAd341Hgu0lOzMv5mSKQ5yBnTLq+t3FPKgD9tIiHLqxSQ=="],
@@ -6835,275 +7027,49 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-y5ozxeQ9omVjbnJo9dtTsdXj9BEvGx2X8xvRgKnV+/7wLBuYJQL6dOa/qMY6omyHi7yjt1OA97jZLoVRYi8lxA=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@smithy/types": ["@smithy/types@4.8.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-N0Zn0OT1zc+NA+UVfkYqQzviRh5ucWwO7mBV3TmHHprMnfcJNfhlPicDkBHi0ewbh+y3evR6cNAW0Raxvb01NA=="],
+
"@langchain/google-gauth/google-auth-library/gaxios": ["gaxios@7.1.3", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2", "rimraf": "^5.0.1" } }, "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ=="],
"@langchain/google-gauth/google-auth-library/gcp-metadata": ["gcp-metadata@8.1.2", "", { "dependencies": { "gaxios": "^7.0.0", "google-logging-utils": "^1.0.0", "json-bigint": "^1.0.0" } }, "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg=="],
"@langchain/google-gauth/google-auth-library/gtoken": ["gtoken@8.0.0", "", { "dependencies": { "gaxios": "^7.0.0", "jws": "^4.0.0" } }, "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-bugfix-firefox-class-in-computed-class-key": ["@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q=="],
+ "@librechat/client/rollup/@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.37.0", "", { "os": "android", "cpu": "arm" }, "sha512-l7StVw6WAa8l3vA1ov80jyetOAEo1FtHvZDbzXDO/02Sq/QVvqlHkYoFwDJPIMj0GKiistsBudfx5tGFnwYWDQ=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-bugfix-safari-class-field-initializer-scope": ["@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA=="],
+ "@librechat/client/rollup/@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.37.0", "", { "os": "android", "cpu": "arm64" }, "sha512-6U3SlVyMxezt8Y+/iEBcbp945uZjJwjZimu76xoG7tO1av9VO691z8PkhzQ85ith2I8R2RddEPeSfcbyPfD4hA=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ["@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA=="],
+ "@librechat/client/rollup/@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.37.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-+iTQ5YHuGmPt10NTzEyMPbayiNTcOZDWsbxZYR1ZnmLnZxG17ivrPSWFO9j6GalY0+gV3Jtwrrs12DBscxnlYA=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ["@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.13.0" } }, "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw=="],
+ "@librechat/client/rollup/@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.37.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-m8W2UbxLDcmRKVjgl5J/k4B8d7qX2EcJve3Sut7YGrQoPtCIQGPH5AMzuFvYRWZi0FVS0zEY4c8uttPfX6bwYQ=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ["@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw=="],
+ "@librechat/client/rollup/@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.37.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-FOMXGmH15OmtQWEt174v9P1JqqhlgYge/bUjIbiVD1nI1NeJ30HYT9SJlZMqdo1uQFyt9cz748F1BHghWaDnVA=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-syntax-import-assertions": ["@babel/plugin-syntax-import-assertions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg=="],
+ "@librechat/client/rollup/@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.37.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SZMxNttjPKvV14Hjck5t70xS3l63sbVwl98g3FlVVx2YIDmfUIy29jQrsw06ewEYQ8lQSuY9mpAPlmgRD2iSsA=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA=="],
+ "@librechat/client/rollup/@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.37.0", "", { "os": "linux", "cpu": "arm" }, "sha512-hhAALKJPidCwZcj+g+iN+38SIOkhK2a9bqtJR+EtyxrKKSt1ynCBeqrQy31z0oWU6thRZzdx53hVgEbRkuI19w=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-async-generator-functions": ["@babel/plugin-transform-async-generator-functions@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1", "@babel/traverse": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q=="],
+ "@librechat/client/rollup/@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.37.0", "", { "os": "linux", "cpu": "arm" }, "sha512-jUb/kmn/Gd8epbHKEqkRAxq5c2EwRt0DqhSGWjPFxLeFvldFdHQs/n8lQ9x85oAeVb6bHcS8irhTJX2FCOd8Ag=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-async-to-generator": ["@babel/plugin-transform-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA=="],
+ "@librechat/client/rollup/@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.37.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-oNrJxcQT9IcbcmKlkF+Yz2tmOxZgG9D9GRq+1OE6XCQwCVwxixYAa38Z8qqPzQvzt1FCfmrHX03E0pWoXm1DqA=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-block-scoped-functions": ["@babel/plugin-transform-block-scoped-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg=="],
+ "@librechat/client/rollup/@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.37.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-pfxLBMls+28Ey2enpX3JvjEjaJMBX5XlPCZNGxj4kdJyHduPBXtxYeb8alo0a7bqOoWZW2uKynhHxF/MWoHaGQ=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g=="],
+ "@librechat/client/rollup/@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.37.0", "", { "os": "linux", "cpu": "none" }, "sha512-PpWwHMPCVpFZLTfLq7EWJWvrmEuLdGn1GMYcm5MV7PaRgwCEYJAwiN94uBuZev0/J/hFIIJCsYw4nLmXA9J7Pw=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA=="],
+ "@librechat/client/rollup/@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.37.0", "", { "os": "linux", "cpu": "none" }, "sha512-DTNwl6a3CfhGTAOYZ4KtYbdS8b+275LSLqJVJIrPa5/JuIufWWZ/QFvkxp52gpmguN95eujrM68ZG+zVxa8zHA=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.28.3", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg=="],
+ "@librechat/client/rollup/@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.37.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-hZDDU5fgWvDdHFuExN1gBOhCuzo/8TMpidfOR+1cPZJflcEzXdCy1LjnklQdW8/Et9sryOPJAKAQRw8Jq7Tg+A=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.4", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA=="],
+ "@librechat/client/rollup/@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.37.0", "", { "os": "linux", "cpu": "x64" }, "sha512-pKivGpgJM5g8dwj0ywBwe/HeVAUSuVVJhUTa/URXjxvoyTT/AxsLTAbkHkDHG7qQxLoW2s3apEIl26uUe08LVQ=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/template": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw=="],
+ "@librechat/client/rollup/@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.37.0", "", { "os": "linux", "cpu": "x64" }, "sha512-E2lPrLKE8sQbY/2bEkVTGDEk4/49UYRVWgj90MY8yPjpnGBQ+Xi1Qnr7b7UIWw1NOggdFQFOLZ8+5CzCiz143w=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw=="],
+ "@librechat/client/rollup/@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.37.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Jm7biMazjNzTU4PrQtr7VS8ibeys9Pn29/1bm4ph7CP2kf21950LgN+BaE2mJ1QujnvOc6p54eWWiVvn05SOBg=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-dotall-regex": ["@babel/plugin-transform-dotall-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw=="],
+ "@librechat/client/rollup/@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.37.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-e3/1SFm1OjefWICB2Ucstg2dxYDkDTZGDYgwufcbsxTHyqQps1UQf33dFEChBNmeSsTOyrjw2JJq0zbG5GF6RA=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-duplicate-keys": ["@babel/plugin-transform-duplicate-keys@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex": ["@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-dynamic-import": ["@babel/plugin-transform-dynamic-import@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-exponentiation-operator": ["@babel/plugin-transform-exponentiation-operator@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-export-namespace-from": ["@babel/plugin-transform-export-namespace-from@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-function-name": ["@babel/plugin-transform-function-name@7.27.1", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-json-strings": ["@babel/plugin-transform-json-strings@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-member-expression-literals": ["@babel/plugin-transform-member-expression-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-modules-amd": ["@babel/plugin-transform-modules-amd@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-modules-systemjs": ["@babel/plugin-transform-modules-systemjs@7.28.5", "", { "dependencies": { "@babel/helper-module-transforms": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-modules-umd": ["@babel/plugin-transform-modules-umd@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-new-target": ["@babel/plugin-transform-new-target@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.28.4", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-object-super": ["@babel/plugin-transform-object-super@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.27.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-methods": ["@babel/plugin-transform-private-methods@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-property-literals": ["@babel/plugin-transform-property-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.28.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-regexp-modifiers": ["@babel/plugin-transform-regexp-modifiers@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-reserved-words": ["@babel/plugin-transform-reserved-words@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-sticky-regex": ["@babel/plugin-transform-sticky-regex@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-template-literals": ["@babel/plugin-transform-template-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-typeof-symbol": ["@babel/plugin-transform-typeof-symbol@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-escapes": ["@babel/plugin-transform-unicode-escapes@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-property-regex": ["@babel/plugin-transform-unicode-property-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex": ["@babel/plugin-transform-unicode-sets-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw=="],
-
- "@librechat/client/@babel/preset-env/babel-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.14", "", { "dependencies": { "@babel/compat-data": "^7.27.7", "@babel/helper-define-polyfill-provider": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg=="],
-
- "@librechat/client/@babel/preset-env/babel-plugin-polyfill-corejs3": ["babel-plugin-polyfill-corejs3@0.13.0", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5", "core-js-compat": "^3.43.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A=="],
-
- "@librechat/client/@babel/preset-env/babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.6.5", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg=="],
-
- "@librechat/client/@babel/preset-env/core-js-compat": ["core-js-compat@3.47.0", "", { "dependencies": { "browserslist": "^4.28.0" } }, "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ=="],
-
- "@librechat/client/@babel/preset-react/@babel/plugin-transform-react-display-name": ["@babel/plugin-transform-react-display-name@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA=="],
-
- "@librechat/client/@babel/preset-react/@babel/plugin-transform-react-jsx": ["@babel/plugin-transform-react-jsx@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/types": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw=="],
-
- "@librechat/client/@babel/preset-react/@babel/plugin-transform-react-jsx-development": ["@babel/plugin-transform-react-jsx-development@7.27.1", "", { "dependencies": { "@babel/plugin-transform-react-jsx": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q=="],
-
- "@librechat/client/@babel/preset-react/@babel/plugin-transform-react-pure-annotations": ["@babel/plugin-transform-react-pure-annotations@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA=="],
-
- "@librechat/client/@babel/preset-typescript/@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="],
-
- "@librechat/client/@babel/preset-typescript/@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-bugfix-firefox-class-in-computed-class-key": ["@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-bugfix-safari-class-field-initializer-scope": ["@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ["@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ["@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.13.0" } }, "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ["@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-syntax-import-assertions": ["@babel/plugin-syntax-import-assertions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-async-generator-functions": ["@babel/plugin-transform-async-generator-functions@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1", "@babel/traverse": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-async-to-generator": ["@babel/plugin-transform-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-block-scoped-functions": ["@babel/plugin-transform-block-scoped-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.28.3", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.4", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/template": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-dotall-regex": ["@babel/plugin-transform-dotall-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-duplicate-keys": ["@babel/plugin-transform-duplicate-keys@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex": ["@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-dynamic-import": ["@babel/plugin-transform-dynamic-import@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-exponentiation-operator": ["@babel/plugin-transform-exponentiation-operator@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-export-namespace-from": ["@babel/plugin-transform-export-namespace-from@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-function-name": ["@babel/plugin-transform-function-name@7.27.1", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-json-strings": ["@babel/plugin-transform-json-strings@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-member-expression-literals": ["@babel/plugin-transform-member-expression-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-modules-amd": ["@babel/plugin-transform-modules-amd@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-modules-systemjs": ["@babel/plugin-transform-modules-systemjs@7.28.5", "", { "dependencies": { "@babel/helper-module-transforms": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-modules-umd": ["@babel/plugin-transform-modules-umd@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-new-target": ["@babel/plugin-transform-new-target@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.28.4", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-object-super": ["@babel/plugin-transform-object-super@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.27.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-methods": ["@babel/plugin-transform-private-methods@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-property-literals": ["@babel/plugin-transform-property-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.28.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-regexp-modifiers": ["@babel/plugin-transform-regexp-modifiers@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-reserved-words": ["@babel/plugin-transform-reserved-words@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-sticky-regex": ["@babel/plugin-transform-sticky-regex@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-template-literals": ["@babel/plugin-transform-template-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-typeof-symbol": ["@babel/plugin-transform-typeof-symbol@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-escapes": ["@babel/plugin-transform-unicode-escapes@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-property-regex": ["@babel/plugin-transform-unicode-property-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex": ["@babel/plugin-transform-unicode-sets-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw=="],
-
- "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.14", "", { "dependencies": { "@babel/compat-data": "^7.27.7", "@babel/helper-define-polyfill-provider": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg=="],
-
- "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-corejs3": ["babel-plugin-polyfill-corejs3@0.13.0", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5", "core-js-compat": "^3.43.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A=="],
-
- "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.6.5", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg=="],
-
- "@librechat/frontend/@babel/preset-env/core-js-compat": ["core-js-compat@3.47.0", "", { "dependencies": { "browserslist": "^4.28.0" } }, "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ=="],
-
- "@librechat/frontend/@babel/preset-react/@babel/plugin-transform-react-display-name": ["@babel/plugin-transform-react-display-name@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA=="],
-
- "@librechat/frontend/@babel/preset-react/@babel/plugin-transform-react-jsx": ["@babel/plugin-transform-react-jsx@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/types": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw=="],
-
- "@librechat/frontend/@babel/preset-react/@babel/plugin-transform-react-jsx-development": ["@babel/plugin-transform-react-jsx-development@7.27.1", "", { "dependencies": { "@babel/plugin-transform-react-jsx": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q=="],
-
- "@librechat/frontend/@babel/preset-react/@babel/plugin-transform-react-pure-annotations": ["@babel/plugin-transform-react-pure-annotations@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA=="],
-
- "@librechat/frontend/@babel/preset-typescript/@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="],
-
- "@librechat/frontend/@babel/preset-typescript/@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA=="],
+ "@librechat/client/rollup/@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.37.0", "", { "os": "win32", "cpu": "x64" }, "sha512-LWbXUBwn/bcLx2sSsqy7pK5o+Nr+VCoRoAohfJ5C/aBio9nfJmGQqHAhU6pwxV/RmyTk5AqdySma7uwWGlmeuA=="],
"@librechat/frontend/@react-spring/web/@react-spring/animated": ["@react-spring/animated@9.7.5", "", { "dependencies": { "@react-spring/shared": "~9.7.5", "@react-spring/types": "~9.7.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg=="],
@@ -7121,22 +7087,20 @@
"@librechat/frontend/@testing-library/jest-dom/dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="],
+ "@librechat/frontend/@testing-library/jest-dom/lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
+
"@librechat/frontend/framer-motion/motion-dom": ["motion-dom@11.18.1", "", { "dependencies": { "motion-utils": "^11.18.1" } }, "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw=="],
"@librechat/frontend/framer-motion/motion-utils": ["motion-utils@11.18.1", "", {}, "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA=="],
- "@librechat/frontend/jest-environment-jsdom/@jest/environment": ["@jest/environment@29.7.0", "", { "dependencies": { "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "jest-mock": "^29.7.0" } }, "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw=="],
-
- "@librechat/frontend/jest-environment-jsdom/@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="],
-
- "@librechat/frontend/jest-environment-jsdom/@types/jsdom": ["@types/jsdom@20.0.1", "", { "dependencies": { "@types/node": "*", "@types/tough-cookie": "*", "parse5": "^7.0.0" } }, "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ=="],
-
- "@librechat/frontend/jest-environment-jsdom/jsdom": ["jsdom@20.0.3", "", { "dependencies": { "abab": "^2.0.6", "acorn": "^8.8.1", "acorn-globals": "^7.0.0", "cssom": "^0.5.0", "cssstyle": "^2.3.0", "data-urls": "^3.0.2", "decimal.js": "^10.4.2", "domexception": "^4.0.0", "escodegen": "^2.0.0", "form-data": "^4.0.0", "html-encoding-sniffer": "^3.0.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.1", "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.2", "parse5": "^7.1.1", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^4.1.2", "w3c-xmlserializer": "^4.0.0", "webidl-conversions": "^7.0.0", "whatwg-encoding": "^2.0.0", "whatwg-mimetype": "^3.0.0", "whatwg-url": "^11.0.0", "ws": "^8.11.0", "xml-name-validator": "^4.0.0" }, "peerDependencies": { "canvas": "^2.5.0" }, "optionalPeers": ["canvas"] }, "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ=="],
-
"@mcp-ui/client/@modelcontextprotocol/sdk/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
+ "@mcp-ui/client/@modelcontextprotocol/sdk/express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="],
+
"@mcp-ui/client/@modelcontextprotocol/sdk/express-rate-limit": ["express-rate-limit@7.5.0", "", { "peerDependencies": { "express": "^4.11 || 5 || ^5.0.0-beta.1" } }, "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg=="],
+ "@mcp-ui/client/@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.24.3", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-HIAfWdYIt1sssHfYZFCXp4rU1w2r8hVVXYIlmoa0r0gABLs5di3RCqPU5DDROogVz1pAdYBaz7HK5n9pSUNs3A=="],
+
"@modelcontextprotocol/sdk/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
"@node-saml/passport-saml/@types/express/@types/express-serve-static-core": ["@types/express-serve-static-core@4.19.6", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A=="],
@@ -7147,18 +7111,32 @@
"@opentelemetry/exporter-trace-otlp-http/@opentelemetry/otlp-transformer/@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.208.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.208.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-QlAyL1jRpOeaqx7/leG1vJMp84g0xKP6gJmfELBpnI4O/9xPX+Hu5m1POk9Kl+veNkyth5t19hRlN6tNY1sjbA=="],
+ "@opentelemetry/exporter-trace-otlp-http/@opentelemetry/otlp-transformer/protobufjs": ["protobufjs@7.4.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw=="],
+
+ "@opentelemetry/otlp-transformer/protobufjs/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
"@radix-ui/react-arrow/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
"@radix-ui/react-checkbox/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
"@radix-ui/react-checkbox/@radix-ui/react-use-controllable-state/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ=="],
+ "@radix-ui/react-dialog/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ=="],
+
+ "@radix-ui/react-dialog/@radix-ui/react-presence/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ=="],
+
+ "@radix-ui/react-dialog/@radix-ui/react-use-controllable-state/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg=="],
+
+ "@radix-ui/react-dismissable-layer/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.0" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw=="],
+
"@radix-ui/react-dropdown-menu/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
"@radix-ui/react-dropdown-menu/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.1.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw=="],
"@radix-ui/react-dropdown-menu/@radix-ui/react-use-controllable-state/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
+ "@radix-ui/react-focus-scope/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.0" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw=="],
+
"@radix-ui/react-hover-card/@radix-ui/react-dismissable-layer/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ=="],
"@radix-ui/react-hover-card/@radix-ui/react-dismissable-layer/@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-callback-ref": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg=="],
@@ -7199,8 +7177,12 @@
"@radix-ui/react-popper/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
+ "@radix-ui/react-portal/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.0" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw=="],
+
"@radix-ui/react-progress/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ=="],
+ "@radix-ui/react-select/@radix-ui/react-dismissable-layer/@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="],
+
"@radix-ui/react-select/@radix-ui/react-popper/@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="],
"@radix-ui/react-select/@radix-ui/react-popper/@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.1", "", { "dependencies": { "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w=="],
@@ -7237,26 +7219,64 @@
"@smithy/credential-provider-imds/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ=="],
- "@smithy/signature-v4/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@types/body-parser/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
- "@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
+ "@types/connect/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
- "@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+ "@types/express-serve-static-core/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
+ "@types/jsdom/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
+ "@types/jsonwebtoken/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
+ "@types/ldapjs/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
+ "@types/node-fetch/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
+ "@types/send/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
+ "@types/serve-static/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
"@types/winston/winston/logform": ["logform@2.6.0", "", { "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" } }, "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ=="],
"@types/winston/winston/winston-transport": ["winston-transport@4.7.0", "", { "dependencies": { "logform": "^2.3.2", "readable-stream": "^3.6.0", "triple-beam": "^1.3.0" } }, "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg=="],
+ "@types/xml-encryption/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
+ "@types/xml2js/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
+ "@vitejs/plugin-react/@babel/core/@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="],
+
+ "@vitejs/plugin-react/@babel/core/@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="],
+
+ "@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="],
+
+ "@vitejs/plugin-react/@babel/core/@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="],
+
+ "@vitejs/plugin-react/@babel/core/@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="],
+
+ "@vitejs/plugin-react/@babel/core/@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="],
+
+ "@vitejs/plugin-react/@babel/core/@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="],
+
+ "@vitejs/plugin-react/@babel/core/@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="],
+
+ "@vitejs/plugin-react/@babel/core/@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="],
+
"ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
- "browserify-sign/readable-stream/core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="],
+ "body-parser/raw-body/http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="],
"browserify-sign/readable-stream/isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
"browserify-sign/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
+ "bun-types/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
+ "caniuse-api/browserslist/baseline-browser-mapping": ["baseline-browser-mapping@2.8.28", "", { "bin": "dist/cli.js" }, "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ=="],
+
"caniuse-api/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
"chalk/supports-color/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
@@ -7271,14 +7291,34 @@
"compression/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
+ "core-js-compat/browserslist/baseline-browser-mapping": ["baseline-browser-mapping@2.8.28", "", { "bin": "dist/cli.js" }, "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ=="],
+
+ "core-js-compat/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
+
+ "cytoscape-fcose/cose-base/layout-base": ["layout-base@2.0.1", "", {}, "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg=="],
+
+ "d3-sankey/d3-array/internmap": ["internmap@1.0.1", "", {}, "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="],
+
+ "d3-sankey/d3-shape/d3-path": ["d3-path@1.0.9", "", {}, "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="],
+
"data-urls/whatwg-url/tr46": ["tr46@5.1.1", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw=="],
"data-urls/whatwg-url/webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="],
+ "eslint/@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
+
"expect/jest-message-util/@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="],
"expect/jest-message-util/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
+ "expect/jest-util/@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="],
+
+ "expect/jest-util/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
+ "expect/jest-util/ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="],
+
+ "expect/jest-util/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
+
"express-session/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
"express-static-gzip/serve-static/send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="],
@@ -7287,16 +7327,16 @@
"form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
- "gaxios/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
+ "gaxios/https-proxy-agent/agent-base": ["agent-base@7.1.0", "", { "dependencies": { "debug": "^4.3.4" } }, "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg=="],
- "google-auth-library/gaxios/https-proxy-agent": ["https-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.0.2", "debug": "4" } }, "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA=="],
+ "gaxios/https-proxy-agent/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
+ "gcp-metadata/gaxios/https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],
+
+ "glob/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="],
"google-auth-library/gcp-metadata/google-logging-utils": ["google-logging-utils@0.0.2", "", {}, "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ=="],
- "googleapis-common/gaxios/https-proxy-agent": ["https-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.0.2", "debug": "4" } }, "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA=="],
-
- "gtoken/gaxios/https-proxy-agent": ["https-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.0.2", "debug": "4" } }, "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA=="],
-
"hast-util-from-html-isomorphic/@types/hast/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
"hast-util-from-html/@types/hast/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
@@ -7333,10 +7373,14 @@
"jest-changed-files/execa/strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
+ "jest-circus/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
"jest-circus/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
"jest-config/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
+ "jest-config/glob/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
+
"jest-config/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
"jest-config/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
@@ -7345,170 +7389,52 @@
"jest-each/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
- "jest-environment-node/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="],
+ "jest-environment-jsdom/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
+ "jest-environment-node/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
+ "jest-haste-map/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
"jest-leak-detector/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
"jest-message-util/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
- "jest-mock/@jest/types/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="],
+ "jest-mock/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
- "jest-runtime/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="],
+ "jest-runner/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
+ "jest-runtime/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
"jest-runtime/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
- "jest-runtime/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
+ "jest-runtime/glob/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
- "jest-snapshot/expect/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="],
+ "jest-runtime/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
"jest-snapshot/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
"jest-snapshot/synckit/@pkgr/core": ["@pkgr/core@0.2.9", "", {}, "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA=="],
- "jest-util/@jest/types/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="],
+ "jest-util/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
"jest-validate/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
+ "jest-watcher/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
+ "jest-worker/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
"jest-worker/supports-color/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
"jsdom/whatwg-url/tr46": ["tr46@5.1.1", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw=="],
"jsonwebtoken/jws/jwa": ["jwa@1.4.1", "", { "dependencies": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA=="],
+ "jszip/readable-stream/isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
+
+ "jszip/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
+
"jwks-rsa/@types/express/@types/express-serve-static-core": ["@types/express-serve-static-core@4.19.6", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A=="],
- "librechat-data-provider/@babel/preset-env/@babel/plugin-bugfix-firefox-class-in-computed-class-key": ["@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-bugfix-safari-class-field-initializer-scope": ["@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ["@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ["@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.13.0" } }, "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ["@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-syntax-import-assertions": ["@babel/plugin-syntax-import-assertions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-async-generator-functions": ["@babel/plugin-transform-async-generator-functions@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1", "@babel/traverse": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-async-to-generator": ["@babel/plugin-transform-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-block-scoped-functions": ["@babel/plugin-transform-block-scoped-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.28.3", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.4", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/template": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-dotall-regex": ["@babel/plugin-transform-dotall-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-duplicate-keys": ["@babel/plugin-transform-duplicate-keys@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex": ["@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-dynamic-import": ["@babel/plugin-transform-dynamic-import@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-exponentiation-operator": ["@babel/plugin-transform-exponentiation-operator@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-export-namespace-from": ["@babel/plugin-transform-export-namespace-from@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-function-name": ["@babel/plugin-transform-function-name@7.27.1", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-json-strings": ["@babel/plugin-transform-json-strings@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-member-expression-literals": ["@babel/plugin-transform-member-expression-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-modules-amd": ["@babel/plugin-transform-modules-amd@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-modules-systemjs": ["@babel/plugin-transform-modules-systemjs@7.28.5", "", { "dependencies": { "@babel/helper-module-transforms": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-modules-umd": ["@babel/plugin-transform-modules-umd@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-new-target": ["@babel/plugin-transform-new-target@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.28.4", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-object-super": ["@babel/plugin-transform-object-super@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.27.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-methods": ["@babel/plugin-transform-private-methods@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-property-literals": ["@babel/plugin-transform-property-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.28.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-regexp-modifiers": ["@babel/plugin-transform-regexp-modifiers@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-reserved-words": ["@babel/plugin-transform-reserved-words@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-sticky-regex": ["@babel/plugin-transform-sticky-regex@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-template-literals": ["@babel/plugin-transform-template-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-typeof-symbol": ["@babel/plugin-transform-typeof-symbol@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-escapes": ["@babel/plugin-transform-unicode-escapes@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-property-regex": ["@babel/plugin-transform-unicode-property-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex": ["@babel/plugin-transform-unicode-sets-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw=="],
-
- "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.14", "", { "dependencies": { "@babel/compat-data": "^7.27.7", "@babel/helper-define-polyfill-provider": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg=="],
-
- "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-corejs3": ["babel-plugin-polyfill-corejs3@0.13.0", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5", "core-js-compat": "^3.43.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A=="],
-
- "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.6.5", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg=="],
-
- "librechat-data-provider/@babel/preset-env/core-js-compat": ["core-js-compat@3.47.0", "", { "dependencies": { "browserslist": "^4.28.0" } }, "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ=="],
-
- "librechat-data-provider/@babel/preset-react/@babel/plugin-transform-react-display-name": ["@babel/plugin-transform-react-display-name@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA=="],
-
- "librechat-data-provider/@babel/preset-react/@babel/plugin-transform-react-jsx": ["@babel/plugin-transform-react-jsx@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/types": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw=="],
-
- "librechat-data-provider/@babel/preset-react/@babel/plugin-transform-react-jsx-development": ["@babel/plugin-transform-react-jsx-development@7.27.1", "", { "dependencies": { "@babel/plugin-transform-react-jsx": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q=="],
-
- "librechat-data-provider/@babel/preset-react/@babel/plugin-transform-react-pure-annotations": ["@babel/plugin-transform-react-pure-annotations@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA=="],
-
- "librechat-data-provider/@babel/preset-typescript/@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="],
-
- "librechat-data-provider/@babel/preset-typescript/@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA=="],
-
"log-update/slice-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
"log-update/slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@5.0.0", "", { "dependencies": { "get-east-asian-width": "^1.0.0" } }, "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA=="],
@@ -7529,17 +7455,35 @@
"pkg-dir/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="],
+ "postcss-colormin/browserslist/baseline-browser-mapping": ["baseline-browser-mapping@2.8.28", "", { "bin": "dist/cli.js" }, "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ=="],
+
"postcss-colormin/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
+ "postcss-convert-values/browserslist/baseline-browser-mapping": ["baseline-browser-mapping@2.8.28", "", { "bin": "dist/cli.js" }, "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ=="],
+
"postcss-convert-values/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
+ "postcss-merge-rules/browserslist/baseline-browser-mapping": ["baseline-browser-mapping@2.8.28", "", { "bin": "dist/cli.js" }, "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ=="],
+
"postcss-merge-rules/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
+ "postcss-minify-params/browserslist/baseline-browser-mapping": ["baseline-browser-mapping@2.8.28", "", { "bin": "dist/cli.js" }, "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ=="],
+
"postcss-minify-params/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
+ "postcss-normalize-unicode/browserslist/baseline-browser-mapping": ["baseline-browser-mapping@2.8.28", "", { "bin": "dist/cli.js" }, "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ=="],
+
"postcss-normalize-unicode/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
- "postcss-preset-env/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
+ "postcss-preset-env/autoprefixer/caniuse-lite": ["caniuse-lite@1.0.30001777", "", {}, "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ=="],
+
+ "postcss-preset-env/browserslist/caniuse-lite": ["caniuse-lite@1.0.30001777", "", {}, "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ=="],
+
+ "postcss-preset-env/browserslist/electron-to-chromium": ["electron-to-chromium@1.5.307", "", {}, "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg=="],
+
+ "postcss-preset-env/browserslist/update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="],
+
+ "postcss-reduce-initial/browserslist/baseline-browser-mapping": ["baseline-browser-mapping@2.8.28", "", { "bin": "dist/cli.js" }, "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ=="],
"postcss-reduce-initial/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
@@ -7573,12 +7517,14 @@
"rollup-plugin-typescript2/@rollup/pluginutils/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
- "schema-utils/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
+ "stylehacks/browserslist/baseline-browser-mapping": ["baseline-browser-mapping@2.8.28", "", { "bin": "dist/cli.js" }, "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ=="],
"stylehacks/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
"sucrase/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
+ "sucrase/glob/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
+
"sucrase/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
"svgo/css-select/domhandler": ["domhandler@4.3.1", "", { "dependencies": { "domelementtype": "^2.2.0" } }, "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ=="],
@@ -7587,135 +7533,35 @@
"tailwindcss/postcss-load-config/lilconfig": ["lilconfig@3.0.0", "", {}, "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g=="],
- "terser-webpack-plugin/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
-
"unist-util-remove-position/unist-util-visit/unist-util-is": ["unist-util-is@5.2.1", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw=="],
"unist-util-remove-position/unist-util-visit/unist-util-visit-parents": ["unist-util-visit-parents@5.1.3", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0" } }, "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg=="],
+ "vasync/verror/core-util-is": ["core-util-is@1.0.2", "", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="],
+
"vfile-location/vfile/unist-util-stringify-position": ["unist-util-stringify-position@3.0.3", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg=="],
"vfile-location/vfile/vfile-message": ["vfile-message@3.1.4", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-stringify-position": "^3.0.0" } }, "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw=="],
- "webpack/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
-
- "webpack/eslint-scope/estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="],
-
- "webpack/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
-
"winston-daily-rotate-file/winston-transport/logform": ["logform@2.6.0", "", { "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" } }, "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ=="],
- "workbox-build/@babel/preset-env/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ["@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ=="],
+ "workbox-build/@babel/core/@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="],
- "workbox-build/@babel/preset-env/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ["@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", "@babel/plugin-transform-optional-chaining": "^7.23.3" }, "peerDependencies": { "@babel/core": "^7.13.0" } }, "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ=="],
+ "workbox-build/@babel/core/@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="],
- "workbox-build/@babel/preset-env/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ["@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7", "", { "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw=="],
+ "workbox-build/@babel/core/@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="],
- "workbox-build/@babel/preset-env/@babel/plugin-syntax-import-assertions": ["@babel/plugin-syntax-import-assertions@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw=="],
+ "workbox-build/@babel/core/@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="],
- "workbox-build/@babel/preset-env/@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ=="],
+ "workbox-build/@babel/core/@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="],
- "workbox-build/@babel/preset-env/@babel/plugin-transform-async-generator-functions": ["@babel/plugin-transform-async-generator-functions@7.23.9", "", { "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-remap-async-to-generator": "^7.22.20", "@babel/plugin-syntax-async-generators": "^7.8.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ=="],
+ "workbox-build/@babel/core/@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="],
- "workbox-build/@babel/preset-env/@babel/plugin-transform-async-to-generator": ["@babel/plugin-transform-async-to-generator@7.23.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-remap-async-to-generator": "^7.22.20" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw=="],
+ "workbox-build/@babel/core/@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="],
- "workbox-build/@babel/preset-env/@babel/plugin-transform-block-scoped-functions": ["@babel/plugin-transform-block-scoped-functions@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A=="],
+ "workbox-build/@babel/core/@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="],
- "workbox-build/@babel/preset-env/@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.23.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.23.3", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.23.4", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.23.8", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-replace-supers": "^7.22.20", "@babel/helper-split-export-declaration": "^7.22.6", "globals": "^11.1.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/template": "^7.22.15" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-dotall-regex": ["@babel/plugin-transform-dotall-regex@7.23.3", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-duplicate-keys": ["@babel/plugin-transform-duplicate-keys@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-dynamic-import": ["@babel/plugin-transform-dynamic-import@7.23.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-exponentiation-operator": ["@babel/plugin-transform-exponentiation-operator@7.23.3", "", { "dependencies": { "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-export-namespace-from": ["@babel/plugin-transform-export-namespace-from@7.23.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.23.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-function-name": ["@babel/plugin-transform-function-name@7.23.3", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.22.15", "@babel/helper-function-name": "^7.23.0", "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-json-strings": ["@babel/plugin-transform-json-strings@7.23.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-json-strings": "^7.8.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.23.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-member-expression-literals": ["@babel/plugin-transform-member-expression-literals@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-modules-amd": ["@babel/plugin-transform-modules-amd@7.23.3", "", { "dependencies": { "@babel/helper-module-transforms": "^7.23.3", "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.23.3", "", { "dependencies": { "@babel/helper-module-transforms": "^7.23.3", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-simple-access": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-modules-systemjs": ["@babel/plugin-transform-modules-systemjs@7.23.9", "", { "dependencies": { "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-module-transforms": "^7.23.3", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-validator-identifier": "^7.22.20" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-KDlPRM6sLo4o1FkiSlXoAa8edLXFsKKIda779fbLrvmeuc3itnjCtaO6RrtoaANsIJANj+Vk1zqbZIMhkCAHVw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-modules-umd": ["@babel/plugin-transform-modules-umd@7.23.3", "", { "dependencies": { "@babel/helper-module-transforms": "^7.23.3", "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.22.5", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-new-target": ["@babel/plugin-transform-new-target@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.23.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.23.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.23.4", "", { "dependencies": { "@babel/compat-data": "^7.23.3", "@babel/helper-compilation-targets": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-transform-parameters": "^7.23.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-object-super": ["@babel/plugin-transform-object-super@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-replace-supers": "^7.22.20" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.23.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.23.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-private-methods": ["@babel/plugin-transform-private-methods@7.23.3", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.23.4", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-create-class-features-plugin": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-property-literals": ["@babel/plugin-transform-property-literals@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "regenerator-transform": "^0.15.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-reserved-words": ["@babel/plugin-transform-reserved-words@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-sticky-regex": ["@babel/plugin-transform-sticky-regex@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-template-literals": ["@babel/plugin-transform-template-literals@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-typeof-symbol": ["@babel/plugin-transform-typeof-symbol@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-unicode-escapes": ["@babel/plugin-transform-unicode-escapes@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-unicode-property-regex": ["@babel/plugin-transform-unicode-property-regex@7.23.3", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.23.3", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex": ["@babel/plugin-transform-unicode-sets-regex@7.23.3", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw=="],
-
- "workbox-build/@babel/preset-env/babel-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.8", "", { "dependencies": { "@babel/compat-data": "^7.22.6", "@babel/helper-define-polyfill-provider": "^0.5.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-OtIuQfafSzpo/LhnJaykc0R/MMnuLSSVjVYy9mHArIZ9qTCSZ6TpWCuEKZYVoN//t8HqBNScHrOtCrIK5IaGLg=="],
-
- "workbox-build/@babel/preset-env/babel-plugin-polyfill-corejs3": ["babel-plugin-polyfill-corejs3@0.9.0", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.5.0", "core-js-compat": "^3.34.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg=="],
-
- "workbox-build/@babel/preset-env/babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.5.5", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.5.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg=="],
-
- "workbox-build/@babel/preset-env/core-js-compat": ["core-js-compat@3.35.1", "", { "dependencies": { "browserslist": "^4.22.2" } }, "sha512-sftHa5qUJY3rs9Zht1WEnmkvXputCyDBczPnr7QDgL8n3qrF3CMXY4VPSYtOLLiOUJcah2WNXREd48iOl6mQIw=="],
+ "workbox-build/@babel/core/@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="],
"workbox-build/@rollup/plugin-replace/@rollup/pluginutils": ["@rollup/pluginutils@3.1.0", "", { "dependencies": { "@types/estree": "0.0.39", "estree-walker": "^1.0.1", "picomatch": "^2.2.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0" } }, "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg=="],
@@ -7723,6 +7569,16 @@
"workbox-build/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
+ "workbox-build/glob/foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
+
+ "workbox-build/glob/jackspeak": ["jackspeak@4.2.3", "", { "dependencies": { "@isaacs/cliui": "^9.0.0" } }, "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg=="],
+
+ "workbox-build/glob/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="],
+
+ "workbox-build/glob/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
+
+ "workbox-build/glob/path-scurry": ["path-scurry@2.0.1", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA=="],
+
"workbox-build/source-map/whatwg-url": ["whatwg-url@7.1.0", "", { "dependencies": { "lodash.sortby": "^4.7.0", "tr46": "^1.0.1", "webidl-conversions": "^4.0.2" } }, "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg=="],
"wrap-ansi/string-width/emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="],
@@ -7735,7 +7591,11 @@
"@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
+ "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+
+ "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/core/@smithy/signature-v4/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
+ "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/core/@smithy/signature-v4/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
@@ -7749,28 +7609,26 @@
"@aws-sdk/client-bedrock-agent-runtime/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/core/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/eventstream-serde-browser/@smithy/eventstream-serde-universal/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-aV8blR9RBDKrOlZVgjOdmOibTC2sBXNiT7WA558b4MPdsLTV6sbyc1WIE9QiIuYMJjYtnPLciefoqSW8Gi+MZQ=="],
+
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/eventstream-serde-node/@smithy/eventstream-serde-universal/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-aV8blR9RBDKrOlZVgjOdmOibTC2sBXNiT7WA558b4MPdsLTV6sbyc1WIE9QiIuYMJjYtnPLciefoqSW8Gi+MZQ=="],
+
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@aws-sdk/client-bedrock-agent-runtime/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@aws-sdk/client-bedrock-agent-runtime/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/smithy-client/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@aws-sdk/client-bedrock-agent-runtime/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@aws-sdk/client-bedrock-agent-runtime/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.948.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-iWjchXy8bIAVBUsKnbfKYXRwhLgRg3EqCQ5FTr3JbR+QR75rZm4ZOYXlvHGztVTmtAZ+PQVA1Y4zO7v7N87C0A=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
"@aws-sdk/client-cognito-identity/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
"@aws-sdk/client-cognito-identity/@aws-sdk/core/@smithy/signature-v4/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ=="],
@@ -7791,7 +7649,11 @@
"@aws-sdk/client-cognito-identity/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
- "@aws-sdk/client-kendra/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
+ "@aws-sdk/client-kendra/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+
+ "@aws-sdk/client-kendra/@aws-sdk/core/@smithy/signature-v4/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
+ "@aws-sdk/client-kendra/@aws-sdk/core/@smithy/signature-v4/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
@@ -7805,10 +7667,18 @@
"@aws-sdk/client-kendra/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@aws-sdk/client-kendra/@smithy/core/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
+ "@aws-sdk/client-kendra/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@aws-sdk/client-kendra/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/client-kendra/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@aws-sdk/client-kendra/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@aws-sdk/client-kendra/@smithy/smithy-client/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@aws-sdk/client-kendra/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@aws-sdk/client-kendra/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
@@ -7873,92 +7743,128 @@
"@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@aws-sdk/core": ["@aws-sdk/core@3.758.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/core": "^3.1.5", "@smithy/node-config-provider": "^4.0.1", "@smithy/property-provider": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/signature-v4": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/util-middleware": "^4.0.1", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" } }, "sha512-0RswbdR9jt/XKemaLNuxi2gGr4xGlHyGxkTdhSQzCyUe9A9OPCoLl3rIESRguQEech+oJnbHk/wuiwHqTuP9sg=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-PFMVHVPgtFECeu4iZ+4SX6VOQT0+dIpm4jSPLLL6JLSkp9RohGqKBKD0cbiXdeIFS08Forp0UHI6kc0gIHenSA=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@aws-sdk/util-arn-parser": ["@aws-sdk/util-arn-parser@3.723.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-ZhEfvUwNliOQROcAk34WJWVYTlTa4694kSVhDSjW6lE1bMataPnIN8A0ycukEzBXmd8ZSoBcQLn6lKGl7XIJ5w=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/core": ["@smithy/core@3.1.5", "", { "dependencies": { "@smithy/middleware-serde": "^4.0.2", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-middleware": "^4.0.1", "@smithy/util-stream": "^4.1.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-HLclGWPkCsekQgsyzxLhCQLa8THWXtB5PxyYN+2O6nkyLt550KQKTlbV2D1/j5dNIQapAZM1+qFnpBFxZQkgCA=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.7", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.7", "@smithy/node-http-handler": "^4.4.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Uuy4S5Aj4oF6k1z+i2OtIBJUns4mlg29Ph4S+CqjR+f4XXpSFVgTCYLzMszHJTicYDBxKFtwq2/QSEDSS5l02A=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/node-config-provider": ["@smithy/node-config-provider@4.0.1", "", { "dependencies": { "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/util-config-provider": ["@smithy/util-config-provider@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.0", "", { "dependencies": { "@smithy/core": "^3.19.0", "@smithy/middleware-serde": "^4.2.7", "@smithy/node-config-provider": "^4.3.6", "@smithy/shared-ini-file-loader": "^4.4.1", "@smithy/types": "^4.10.0", "@smithy/url-parser": "^4.2.6", "@smithy/util-middleware": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-M6qWfUNny6NFNy8amrCGIb9TfOMUkHVtg9bHtEFGRgfH7A7AtPpn/fcrToGPjVDK1ECuMVvqGQOXcZxmu9K+7A=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-JSbALU3G+JS4kyBZPqnJ3hxIYwOVRV7r9GNQMS6j5VsQDo5+Es5nddLfr9TQlxZLNHPvKSh+XSB0OuWGfSWFcA=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/util-stream": ["@smithy/util-stream@4.1.2", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-hex-encoding": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.7", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.7", "@smithy/node-http-handler": "^4.4.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Uuy4S5Aj4oF6k1z+i2OtIBJUns4mlg29Ph4S+CqjR+f4XXpSFVgTCYLzMszHJTicYDBxKFtwq2/QSEDSS5l02A=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/util-utf8": ["@smithy/util-utf8@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.758.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.758.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", "@aws-sdk/middleware-recursion-detection": "3.734.0", "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", "@aws-sdk/util-endpoints": "3.743.0", "@aws-sdk/util-user-agent-browser": "3.734.0", "@aws-sdk/util-user-agent-node": "3.758.0", "@smithy/config-resolver": "^4.0.1", "@smithy/core": "^3.1.5", "@smithy/fetch-http-handler": "^5.0.1", "@smithy/hash-node": "^4.0.1", "@smithy/invalid-dependency": "^4.0.1", "@smithy/middleware-content-length": "^4.0.1", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/middleware-retry": "^4.0.7", "@smithy/middleware-serde": "^4.0.2", "@smithy/middleware-stack": "^4.0.1", "@smithy/node-config-provider": "^4.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/protocol-http": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.7", "@smithy/util-defaults-mode-node": "^4.0.7", "@smithy/util-endpoints": "^3.0.1", "@smithy/util-middleware": "^4.0.1", "@smithy/util-retry": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-YZ5s7PSvyF3Mt2h1EQulCG93uybprNGbBkPmVuy/HMMfbFTt4iL3SbKjxqvOZelm86epFfj7pvK7FliI2WOEcg=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.1.2", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-hex-encoding": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-utf8": ["@smithy/util-utf8@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow=="],
- "@aws-sdk/middleware-websocket/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
- "@aws-sdk/middleware-websocket/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw=="],
- "@aws-sdk/middleware-websocket/@smithy/signature-v4/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.0.2", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ=="],
- "@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA=="],
- "@aws-sdk/nested-clients/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
- "@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/core/@smithy/util-utf8": ["@smithy/util-utf8@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow=="],
- "@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.0.1", "", { "dependencies": { "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA=="],
- "@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
- "@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/util-base64": ["@smithy/util-base64@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg=="],
- "@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
- "@aws-sdk/token-providers/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-PFMVHVPgtFECeu4iZ+4SX6VOQT0+dIpm4jSPLLL6JLSkp9RohGqKBKD0cbiXdeIFS08Forp0UHI6kc0gIHenSA=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/util-utf8": ["@smithy/util-utf8@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow=="],
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
+ "@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.7", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.7", "@smithy/node-http-handler": "^4.4.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Uuy4S5Aj4oF6k1z+i2OtIBJUns4mlg29Ph4S+CqjR+f4XXpSFVgTCYLzMszHJTicYDBxKFtwq2/QSEDSS5l02A=="],
+ "@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.0", "", { "dependencies": { "@smithy/core": "^3.19.0", "@smithy/middleware-serde": "^4.2.7", "@smithy/node-config-provider": "^4.3.6", "@smithy/shared-ini-file-loader": "^4.4.1", "@smithy/types": "^4.10.0", "@smithy/url-parser": "^4.2.6", "@smithy/util-middleware": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-M6qWfUNny6NFNy8amrCGIb9TfOMUkHVtg9bHtEFGRgfH7A7AtPpn/fcrToGPjVDK1ECuMVvqGQOXcZxmu9K+7A=="],
+ "@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-JSbALU3G+JS4kyBZPqnJ3hxIYwOVRV7r9GNQMS6j5VsQDo5+Es5nddLfr9TQlxZLNHPvKSh+XSB0OuWGfSWFcA=="],
+ "@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.7", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.7", "@smithy/node-http-handler": "^4.4.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Uuy4S5Aj4oF6k1z+i2OtIBJUns4mlg29Ph4S+CqjR+f4XXpSFVgTCYLzMszHJTicYDBxKFtwq2/QSEDSS5l02A=="],
+ "@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
+
+ "@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
+
+ "@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
+
+ "@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
+
+ "@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
+
+ "@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
"@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
+ "@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
"@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
"@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs3/core-js-compat/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
+ "@babel/plugin-transform-runtime/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
"@babel/plugin-transform-runtime/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
+ "@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
+
+ "@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
+
+ "@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
+
+ "@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
+
+ "@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
+
+ "@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
+
+ "@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
+
+ "@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
+
+ "@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
+
+ "@google/genai/google-auth-library/gaxios/node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="],
+
+ "@google/genai/google-auth-library/gaxios/rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": "dist/esm/bin.mjs" }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="],
+
+ "@grpc/proto-loader/protobufjs/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
"@istanbuljs/load-nyc-config/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],
"@jest/expect/expect/jest-matcher-utils/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="],
- "@jest/fake-timers/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="],
-
"@jest/reporters/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"@jest/reporters/glob/path-scurry/lru-cache": ["lru-cache@10.2.0", "", {}, "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q=="],
@@ -7967,6 +7873,8 @@
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.4", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ScDCpasxH7w1HXHYbtk3jcivjvdA1VICyAdgvVqKhKKwxi+MTwZEqFw0minE+oZ7F07oF25xh4FGJxgqgShz0A=="],
+
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/eventstream-handler-node/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-aV8blR9RBDKrOlZVgjOdmOibTC2sBXNiT7WA558b4MPdsLTV6sbyc1WIE9QiIuYMJjYtnPLciefoqSW8Gi+MZQ=="],
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-recursion-detection/@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.1.1", "", {}, "sha512-RcLam17LdlbSOSp9VxmUu1eI6Mwxp+OwhD2QhiSNmNCzoDb0EeUXTD2n/WbcnrAYMGlmf05th6QYq23VqvJqpA=="],
@@ -7975,6 +7883,10 @@
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-websocket/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-aV8blR9RBDKrOlZVgjOdmOibTC2sBXNiT7WA558b4MPdsLTV6sbyc1WIE9QiIuYMJjYtnPLciefoqSW8Gi+MZQ=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-websocket/@smithy/signature-v4": ["@smithy/signature-v4@5.3.4", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ScDCpasxH7w1HXHYbtk3jcivjvdA1VICyAdgvVqKhKKwxi+MTwZEqFw0minE+oZ7F07oF25xh4FGJxgqgShz0A=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-websocket/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Oy6w7+fzIdr10DhF/HpfVLy6raZFTdiE7pxS1rvpuj2JgxzW2y6urm2sYf3eLOpMiHyuG4xUBwFiJpU9CCEvJA=="],
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
@@ -7983,6 +7895,10 @@
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-browser/@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.4", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GNI/IXaY/XBB1SkGBFmbW033uWA0tj085eCxYih0eccUe/PFR7+UBQv9HNDk2fD9TJu7UVsCWsH99TkpEPSOzQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-node/@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.4", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GNI/IXaY/XBB1SkGBFmbW033uWA0tj085eCxYih0eccUe/PFR7+UBQv9HNDk2fD9TJu7UVsCWsH99TkpEPSOzQ=="],
+
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
@@ -8013,6 +7929,8 @@
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
@@ -8023,6 +7941,8 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/protocol-http": ["@smithy/protocol-http@5.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
@@ -8051,172 +7971,48 @@
"@langchain/google-gauth/google-auth-library/gaxios/rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": "dist/esm/bin.mjs" }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-for-of/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-optional-chaining/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-spread/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "@librechat/client/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
-
- "@librechat/client/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
-
- "@librechat/client/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
-
- "@librechat/client/@babel/preset-env/core-js-compat/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
-
- "@librechat/client/@babel/preset-react/@babel/plugin-transform-react-jsx/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/client/@babel/preset-react/@babel/plugin-transform-react-pure-annotations/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/client/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/client/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
-
- "@librechat/client/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-for-of/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-optional-chaining/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-spread/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
-
- "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
-
- "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
-
- "@librechat/frontend/@babel/preset-env/core-js-compat/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
-
- "@librechat/frontend/@babel/preset-react/@babel/plugin-transform-react-jsx/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/frontend/@babel/preset-react/@babel/plugin-transform-react-pure-annotations/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/frontend/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/frontend/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
-
- "@librechat/frontend/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
"@librechat/frontend/@react-spring/web/@react-spring/shared/@react-spring/rafz": ["@react-spring/rafz@9.7.5", "", {}, "sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw=="],
"@librechat/frontend/@testing-library/jest-dom/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"@librechat/frontend/@testing-library/jest-dom/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
- "@librechat/frontend/jest-environment-jsdom/@jest/types/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="],
-
- "@librechat/frontend/jest-environment-jsdom/jsdom/cssstyle": ["cssstyle@2.3.0", "", { "dependencies": { "cssom": "~0.3.6" } }, "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A=="],
-
- "@librechat/frontend/jest-environment-jsdom/jsdom/data-urls": ["data-urls@3.0.2", "", { "dependencies": { "abab": "^2.0.6", "whatwg-mimetype": "^3.0.0", "whatwg-url": "^11.0.0" } }, "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ=="],
-
- "@librechat/frontend/jest-environment-jsdom/jsdom/html-encoding-sniffer": ["html-encoding-sniffer@3.0.0", "", { "dependencies": { "whatwg-encoding": "^2.0.0" } }, "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA=="],
-
- "@librechat/frontend/jest-environment-jsdom/jsdom/http-proxy-agent": ["http-proxy-agent@5.0.0", "", { "dependencies": { "@tootallnate/once": "2", "agent-base": "6", "debug": "4" } }, "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w=="],
-
- "@librechat/frontend/jest-environment-jsdom/jsdom/https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],
-
- "@librechat/frontend/jest-environment-jsdom/jsdom/nwsapi": ["nwsapi@2.2.7", "", {}, "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ=="],
-
- "@librechat/frontend/jest-environment-jsdom/jsdom/tough-cookie": ["tough-cookie@4.1.3", "", { "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", "universalify": "^0.2.0", "url-parse": "^1.5.3" } }, "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw=="],
-
- "@librechat/frontend/jest-environment-jsdom/jsdom/w3c-xmlserializer": ["w3c-xmlserializer@4.0.0", "", { "dependencies": { "xml-name-validator": "^4.0.0" } }, "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw=="],
-
- "@librechat/frontend/jest-environment-jsdom/jsdom/webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="],
-
- "@librechat/frontend/jest-environment-jsdom/jsdom/whatwg-encoding": ["whatwg-encoding@2.0.0", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg=="],
-
- "@librechat/frontend/jest-environment-jsdom/jsdom/whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="],
-
- "@librechat/frontend/jest-environment-jsdom/jsdom/whatwg-url": ["whatwg-url@11.0.0", "", { "dependencies": { "tr46": "^3.0.0", "webidl-conversions": "^7.0.0" } }, "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ=="],
-
- "@librechat/frontend/jest-environment-jsdom/jsdom/xml-name-validator": ["xml-name-validator@4.0.0", "", {}, "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw=="],
-
"@mcp-ui/client/@modelcontextprotocol/sdk/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
+ "@mcp-ui/client/@modelcontextprotocol/sdk/express/body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="],
+
+ "@mcp-ui/client/@modelcontextprotocol/sdk/express/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
+ "@node-saml/passport-saml/@types/express/@types/express-serve-static-core/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
"@node-saml/passport-saml/@types/express/@types/express-serve-static-core/@types/qs": ["@types/qs@6.9.17", "", {}, "sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ=="],
+ "@opentelemetry/exporter-trace-otlp-http/@opentelemetry/otlp-transformer/protobufjs/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
+ "@opentelemetry/otlp-transformer/protobufjs/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
"@radix-ui/react-arrow/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="],
+ "@radix-ui/react-portal/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA=="],
+
"@radix-ui/react-progress/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
"@radix-ui/react-tabs/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="],
"@radix-ui/react-tabs/@radix-ui/react-roving-focus/@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
+ "@vitejs/plugin-react/@babel/core/@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
+
+ "@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="],
+
+ "@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="],
+
+ "@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
+
+ "@vitejs/plugin-react/@babel/core/@babel/helper-module-transforms/@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="],
+
+ "body-parser/raw-body/http-errors/statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
+
"cli-truncate/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
"colorspace/color/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
@@ -8225,6 +8021,12 @@
"expect/jest-message-util/@jest/types/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="],
+ "expect/jest-message-util/@jest/types/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
+
+ "expect/jest-util/@jest/types/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="],
+
+ "expect/jest-util/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
"express-static-gzip/serve-static/send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
"express-static-gzip/serve-static/send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="],
@@ -8233,11 +8035,11 @@
"express-static-gzip/serve-static/send/mime": ["mime@1.6.0", "", { "bin": "cli.js" }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="],
- "google-auth-library/gaxios/https-proxy-agent/agent-base": ["agent-base@7.1.0", "", { "dependencies": { "debug": "^4.3.4" } }, "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg=="],
+ "gcp-metadata/gaxios/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
- "googleapis-common/gaxios/https-proxy-agent/agent-base": ["agent-base@7.1.0", "", { "dependencies": { "debug": "^4.3.4" } }, "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg=="],
+ "gcp-metadata/gaxios/https-proxy-agent/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
- "gtoken/gaxios/https-proxy-agent/agent-base": ["agent-base@7.1.0", "", { "dependencies": { "debug": "^4.3.4" } }, "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg=="],
+ "glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
"jest-changed-files/execa/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
@@ -8245,75 +8047,13 @@
"jest-config/glob/path-scurry/lru-cache": ["lru-cache@10.2.0", "", {}, "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q=="],
- "jest-mock/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="],
-
"jest-runtime/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"jest-runtime/glob/path-scurry/lru-cache": ["lru-cache@10.2.0", "", {}, "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q=="],
- "jest-util/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="],
-
"jsdom/whatwg-url/tr46/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
- "librechat-data-provider/@babel/preset-env/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-for-of/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-optional-chaining/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-spread/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
-
- "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
-
- "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
-
- "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
-
- "librechat-data-provider/@babel/preset-env/core-js-compat/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
-
- "librechat-data-provider/@babel/preset-react/@babel/plugin-transform-react-jsx/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "librechat-data-provider/@babel/preset-react/@babel/plugin-transform-react-pure-annotations/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "librechat-data-provider/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "librechat-data-provider/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
-
- "librechat-data-provider/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+ "jwks-rsa/@types/express/@types/express-serve-static-core/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
"mongodb-connection-string-url/whatwg-url/tr46/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
@@ -8331,41 +8071,15 @@
"svgo/css-select/domutils/dom-serializer": ["dom-serializer@1.4.1", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" } }, "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag=="],
- "terser-webpack-plugin/jest-worker/supports-color/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
+ "workbox-build/@babel/core/@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
- "workbox-build/@babel/preset-env/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q=="],
+ "workbox-build/@babel/core/@babel/helper-compilation-targets/@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="],
- "workbox-build/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.22.20", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-wrap-function": "^7.22.20" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw=="],
+ "workbox-build/@babel/core/@babel/helper-compilation-targets/browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="],
- "workbox-build/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.22.20", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-wrap-function": "^7.22.20" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw=="],
+ "workbox-build/@babel/core/@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
- "workbox-build/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.23.10", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-member-expression-to-functions": "^7.23.0", "@babel/helper-optimise-call-expression": "^7.22.5", "@babel/helper-replace-supers": "^7.22.20", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.23.10", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-member-expression-to-functions": "^7.23.0", "@babel/helper-optimise-call-expression": "^7.22.5", "@babel/helper-replace-supers": "^7.22.20", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.22.20", "", { "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-member-expression-to-functions": "^7.22.15", "@babel/helper-optimise-call-expression": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-classes/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-for-of/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.22.20", "", { "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-member-expression-to-functions": "^7.22.15", "@babel/helper-optimise-call-expression": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-optional-chaining/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.23.10", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-member-expression-to-functions": "^7.23.0", "@babel/helper-optimise-call-expression": "^7.22.5", "@babel/helper-replace-supers": "^7.22.20", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.23.10", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-member-expression-to-functions": "^7.23.0", "@babel/helper-optimise-call-expression": "^7.22.5", "@babel/helper-replace-supers": "^7.22.20", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-spread/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q=="],
-
- "workbox-build/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.5.0", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q=="],
-
- "workbox-build/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.5.0", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q=="],
-
- "workbox-build/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.5.0", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q=="],
-
- "workbox-build/@babel/preset-env/core-js-compat/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
+ "workbox-build/@babel/core/@babel/helper-module-transforms/@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="],
"workbox-build/@rollup/plugin-replace/@rollup/pluginutils/@types/estree": ["@types/estree@0.0.39", "", {}, "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw=="],
@@ -8373,28 +8087,34 @@
"workbox-build/@rollup/plugin-replace/@rollup/pluginutils/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
+ "workbox-build/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@9.0.0", "", {}, "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg=="],
+
+ "workbox-build/glob/path-scurry/lru-cache": ["lru-cache@11.2.2", "", {}, "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg=="],
+
"workbox-build/source-map/whatwg-url/tr46": ["tr46@1.0.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA=="],
"workbox-build/source-map/whatwg-url/webidl-conversions": ["webidl-conversions@4.0.2", "", {}, "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Oy6w7+fzIdr10DhF/HpfVLy6raZFTdiE7pxS1rvpuj2JgxzW2y6urm2sYf3eLOpMiHyuG4xUBwFiJpU9CCEvJA=="],
"@aws-sdk/client-bedrock-agent-runtime/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/client-bedrock-agent-runtime/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/eventstream-serde-browser/@smithy/eventstream-serde-universal/@smithy/eventstream-codec/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/eventstream-serde-node/@smithy/eventstream-serde-universal/@smithy/eventstream-codec/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
+ "@aws-sdk/client-bedrock-agent-runtime/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@aws-sdk/client-cognito-identity/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
- "@aws-sdk/client-kendra/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Oy6w7+fzIdr10DhF/HpfVLy6raZFTdiE7pxS1rvpuj2JgxzW2y6urm2sYf3eLOpMiHyuG4xUBwFiJpU9CCEvJA=="],
"@aws-sdk/client-kendra/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
@@ -8409,76 +8129,86 @@
"@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/querystring-builder": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-fcVap4QwqmzQwQK9QU3keeEpCzTjnP9NJ171vI7GnD7nbkAIcP9biZhDUx88uRH9BabSsQDS0unUps88uZvFIQ=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.0.2", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-PFMVHVPgtFECeu4iZ+4SX6VOQT0+dIpm4jSPLLL6JLSkp9RohGqKBKD0cbiXdeIFS08Forp0UHI6kc0gIHenSA=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.6", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tVoyzJ2vXp4R3/aeV4EQjBDmCuWxRa8eo3KybL7Xv4wEM16nObYh7H1sNfcuLWHAAAzb0RVyxUz1S3sGj4X+Tg=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/querystring-builder": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-fcVap4QwqmzQwQK9QU3keeEpCzTjnP9NJ171vI7GnD7nbkAIcP9biZhDUx88uRH9BabSsQDS0unUps88uZvFIQ=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.0.1", "", { "dependencies": { "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/util-base64": ["@smithy/util-base64@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.0.1", "", { "dependencies": { "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/util-base64": ["@smithy/util-base64@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
- "@aws-sdk/middleware-websocket/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
- "@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
- "@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
- "@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
- "@aws-sdk/token-providers/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/querystring-builder": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-fcVap4QwqmzQwQK9QU3keeEpCzTjnP9NJ171vI7GnD7nbkAIcP9biZhDUx88uRH9BabSsQDS0unUps88uZvFIQ=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-PFMVHVPgtFECeu4iZ+4SX6VOQT0+dIpm4jSPLLL6JLSkp9RohGqKBKD0cbiXdeIFS08Forp0UHI6kc0gIHenSA=="],
-
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.6", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tVoyzJ2vXp4R3/aeV4EQjBDmCuWxRa8eo3KybL7Xv4wEM16nObYh7H1sNfcuLWHAAAzb0RVyxUz1S3sGj4X+Tg=="],
-
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/querystring-builder": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-fcVap4QwqmzQwQK9QU3keeEpCzTjnP9NJ171vI7GnD7nbkAIcP9biZhDUx88uRH9BabSsQDS0unUps88uZvFIQ=="],
-
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs3/core-js-compat/browserslist/baseline-browser-mapping": ["baseline-browser-mapping@2.8.28", "", { "bin": "dist/cli.js" }, "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ=="],
"@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs3/core-js-compat/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
+ "@google/genai/google-auth-library/gaxios/rimraf/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
+
"@istanbuljs/load-nyc-config/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
"@jest/expect/expect/jest-matcher-utils/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
- "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@smithy/signature-v4/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@smithy/signature-v4/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/eventstream-handler-node/@smithy/eventstream-codec/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-websocket/@aws-sdk/util-format-url/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-websocket/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-websocket/@smithy/signature-v4/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-browser/@smithy/eventstream-serde-universal/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-aV8blR9RBDKrOlZVgjOdmOibTC2sBXNiT7WA558b4MPdsLTV6sbyc1WIE9QiIuYMJjYtnPLciefoqSW8Gi+MZQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-node/@smithy/eventstream-serde-universal/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-aV8blR9RBDKrOlZVgjOdmOibTC2sBXNiT7WA558b4MPdsLTV6sbyc1WIE9QiIuYMJjYtnPLciefoqSW8Gi+MZQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
@@ -8491,10 +8221,16 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/protocol-http": ["@smithy/protocol-http@5.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.4", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ScDCpasxH7w1HXHYbtk3jcivjvdA1VICyAdgvVqKhKKwxi+MTwZEqFw0minE+oZ7F07oF25xh4FGJxgqgShz0A=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
@@ -8503,8 +8239,12 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.4", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ScDCpasxH7w1HXHYbtk3jcivjvdA1VICyAdgvVqKhKKwxi+MTwZEqFw0minE+oZ7F07oF25xh4FGJxgqgShz0A=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
@@ -8525,6 +8265,8 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
@@ -8533,10 +8275,16 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/protocol-http": ["@smithy/protocol-http@5.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.4", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ScDCpasxH7w1HXHYbtk3jcivjvdA1VICyAdgvVqKhKKwxi+MTwZEqFw0minE+oZ7F07oF25xh4FGJxgqgShz0A=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA=="],
@@ -8579,6 +8327,8 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/protocol-http": ["@smithy/protocol-http@5.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
@@ -8595,6 +8345,8 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
@@ -8605,10 +8357,16 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/protocol-http": ["@smithy/protocol-http@5.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.4", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ScDCpasxH7w1HXHYbtk3jcivjvdA1VICyAdgvVqKhKKwxi+MTwZEqFw0minE+oZ7F07oF25xh4FGJxgqgShz0A=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA=="],
@@ -8651,6 +8409,8 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/protocol-http": ["@smithy/protocol-http@5.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
@@ -8667,6 +8427,8 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
@@ -8677,10 +8439,16 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/protocol-http": ["@smithy/protocol-http@5.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.4", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ScDCpasxH7w1HXHYbtk3jcivjvdA1VICyAdgvVqKhKKwxi+MTwZEqFw0minE+oZ7F07oF25xh4FGJxgqgShz0A=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Oy6w7+fzIdr10DhF/HpfVLy6raZFTdiE7pxS1rvpuj2JgxzW2y6urm2sYf3eLOpMiHyuG4xUBwFiJpU9CCEvJA=="],
@@ -8691,10 +8459,16 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/protocol-http": ["@smithy/protocol-http@5.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.4", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ScDCpasxH7w1HXHYbtk3jcivjvdA1VICyAdgvVqKhKKwxi+MTwZEqFw0minE+oZ7F07oF25xh4FGJxgqgShz0A=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA=="],
@@ -8737,6 +8511,8 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/protocol-http": ["@smithy/protocol-http@5.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
@@ -8753,6 +8529,8 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
@@ -8761,387 +8539,41 @@
"@langchain/google-gauth/google-auth-library/gaxios/rimraf/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator/@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2" } }, "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator/@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2" } }, "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "@librechat/client/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
-
- "@librechat/client/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
-
- "@librechat/client/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
-
- "@librechat/client/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
-
- "@librechat/client/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
-
- "@librechat/client/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
-
- "@librechat/client/@babel/preset-env/core-js-compat/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
-
- "@librechat/client/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "@librechat/client/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "@librechat/client/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator/@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2" } }, "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator/@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2" } }, "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
-
- "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
-
- "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
-
- "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
-
- "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
-
- "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
-
- "@librechat/frontend/@babel/preset-env/core-js-compat/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
-
- "@librechat/frontend/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "@librechat/frontend/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "@librechat/frontend/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
"@librechat/frontend/@testing-library/jest-dom/chalk/supports-color/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
- "@librechat/frontend/jest-environment-jsdom/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="],
+ "@node-saml/passport-saml/@types/express/@types/express-serve-static-core/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
- "@librechat/frontend/jest-environment-jsdom/jsdom/cssstyle/cssom": ["cssom@0.3.8", "", {}, "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="],
+ "@opentelemetry/exporter-trace-otlp-http/@opentelemetry/otlp-transformer/protobufjs/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
- "@librechat/frontend/jest-environment-jsdom/jsdom/http-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
+ "@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/browserslist/caniuse-lite": ["caniuse-lite@1.0.30001777", "", {}, "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ=="],
- "@librechat/frontend/jest-environment-jsdom/jsdom/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
+ "@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/browserslist/electron-to-chromium": ["electron-to-chromium@1.5.307", "", {}, "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg=="],
- "@librechat/frontend/jest-environment-jsdom/jsdom/tough-cookie/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
+ "@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/browserslist/update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="],
- "@librechat/frontend/jest-environment-jsdom/jsdom/tough-cookie/universalify": ["universalify@0.2.0", "", {}, "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg=="],
-
- "@librechat/frontend/jest-environment-jsdom/jsdom/whatwg-url/tr46": ["tr46@3.0.0", "", { "dependencies": { "punycode": "^2.1.1" } }, "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA=="],
+ "@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
"expect/jest-message-util/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="],
+ "expect/jest-message-util/@jest/types/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
+ "expect/jest-util/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="],
+
"express-static-gzip/serve-static/send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator/@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2" } }, "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator/@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2" } }, "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
-
- "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
-
- "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
-
- "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
-
- "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
-
- "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
-
- "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
-
- "librechat-data-provider/@babel/preset-env/core-js-compat/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
-
- "librechat-data-provider/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
-
- "librechat-data-provider/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
-
- "librechat-data-provider/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+ "jwks-rsa/@types/express/@types/express-serve-static-core/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
"pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
"svgo/css-select/domutils/dom-serializer/entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="],
- "workbox-build/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator/@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.22.20", "", { "dependencies": { "@babel/helper-function-name": "^7.22.5", "@babel/template": "^7.22.15", "@babel/types": "^7.22.19" } }, "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw=="],
+ "workbox-build/@babel/core/@babel/helper-compilation-targets/browserslist/caniuse-lite": ["caniuse-lite@1.0.30001777", "", {}, "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ=="],
- "workbox-build/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator/@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.22.20", "", { "dependencies": { "@babel/helper-function-name": "^7.22.5", "@babel/template": "^7.22.15", "@babel/types": "^7.22.19" } }, "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw=="],
+ "workbox-build/@babel/core/@babel/helper-compilation-targets/browserslist/electron-to-chromium": ["electron-to-chromium@1.5.307", "", {}, "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg=="],
- "workbox-build/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.23.0", "", { "dependencies": { "@babel/types": "^7.23.0" } }, "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA=="],
+ "workbox-build/@babel/core/@babel/helper-compilation-targets/browserslist/update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="],
- "workbox-build/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.22.20", "", { "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-member-expression-to-functions": "^7.22.15", "@babel/helper-optimise-call-expression": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.23.0", "", { "dependencies": { "@babel/types": "^7.23.0" } }, "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.22.20", "", { "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-member-expression-to-functions": "^7.22.15", "@babel/helper-optimise-call-expression": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.23.0", "", { "dependencies": { "@babel/types": "^7.23.0" } }, "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.23.0", "", { "dependencies": { "@babel/types": "^7.23.0" } }, "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.23.0", "", { "dependencies": { "@babel/types": "^7.23.0" } }, "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.22.20", "", { "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-member-expression-to-functions": "^7.22.15", "@babel/helper-optimise-call-expression": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.23.0", "", { "dependencies": { "@babel/types": "^7.23.0" } }, "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.22.20", "", { "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-member-expression-to-functions": "^7.22.15", "@babel/helper-optimise-call-expression": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw=="],
-
- "workbox-build/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q=="],
-
- "workbox-build/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
-
- "workbox-build/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
-
- "workbox-build/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
-
- "workbox-build/@babel/preset-env/core-js-compat/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
+ "workbox-build/@babel/core/@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
"workbox-build/source-map/whatwg-url/tr46/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
@@ -9149,25 +8581,43 @@
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-YmWxl32SQRw/kIRccSOxzS/Ib8/b5/f9ex0r5PR40jRJg8X1wgM3KrR2In+8zvOGVhRSXgvyQpw9yOSlmfmSnA=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
- "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
- "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-YmWxl32SQRw/kIRccSOxzS/Ib8/b5/f9ex0r5PR40jRJg8X1wgM3KrR2In+8zvOGVhRSXgvyQpw9yOSlmfmSnA=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
- "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
- "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
- "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
+
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
+
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@google/genai/google-auth-library/gaxios/rimraf/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
+
+ "@google/genai/google-auth-library/gaxios/rimraf/glob/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
+
+ "@google/genai/google-auth-library/gaxios/rimraf/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-websocket/@aws-sdk/util-format-url/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-browser/@smithy/eventstream-serde-universal/@smithy/eventstream-codec/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-node/@smithy/eventstream-serde-universal/@smithy/eventstream-codec/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
@@ -9175,6 +8625,14 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/signature-v4/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/signature-v4/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
@@ -9185,37 +8643,51 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/core/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/signature-v4/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/signature-v4/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
- "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
- "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
@@ -9223,6 +8695,14 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/signature-v4/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/signature-v4/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
@@ -9239,12 +8719,16 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/core/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
@@ -9259,14 +8743,20 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/signature-v4/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/signature-v4/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
@@ -9283,12 +8773,16 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/core/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-retry/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
@@ -9303,14 +8797,20 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/signature-v4/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/signature-v4/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
@@ -9361,6 +8861,8 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/protocol-http": ["@smithy/protocol-http@5.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
@@ -9377,18 +8879,26 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
- "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/signature-v4/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/signature-v4/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
@@ -9405,12 +8915,16 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/core/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
@@ -9427,137 +8941,21 @@
"@langchain/google-gauth/google-auth-library/gaxios/rimraf/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
+ "@langchain/google-gauth/google-auth-library/gaxios/rimraf/glob/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
+
"@langchain/google-gauth/google-auth-library/gaxios/rimraf/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
+ "@aws-sdk/s3-request-presigner/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
+ "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
+ "@google/genai/google-auth-library/gaxios/rimraf/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "@librechat/frontend/jest-environment-jsdom/jsdom/whatwg-url/tr46/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
-
- "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
-
- "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
+ "@google/genai/google-auth-library/gaxios/rimraf/glob/path-scurry/lru-cache": ["lru-cache@10.2.0", "", {}, "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
@@ -9565,6 +8963,8 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
@@ -9575,12 +8975,12 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
@@ -9593,14 +8993,14 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
- "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
@@ -9611,28 +9011,38 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
@@ -9643,28 +9053,38 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/core/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
@@ -9675,6 +9095,8 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
@@ -9685,12 +9107,16 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
@@ -9705,14 +9131,14 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
@@ -9723,16 +9149,26 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
@@ -9827,10 +9263,18 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
@@ -9857,8 +9301,48 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
+
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
}
}
diff --git a/client/jest.config.cjs b/client/jest.config.cjs
index 53d4063a0a..f97adb39ce 100644
--- a/client/jest.config.cjs
+++ b/client/jest.config.cjs
@@ -1,4 +1,4 @@
-/** v0.8.2 */
+/** v0.8.4-rc1 */
module.exports = {
roots: ['/src'],
testEnvironment: 'jsdom',
@@ -32,6 +32,7 @@ module.exports = {
'^librechat-data-provider/react-query$':
'/../node_modules/librechat-data-provider/src/react-query',
},
+ maxWorkers: '50%',
restoreMocks: true,
testResultsProcessor: 'jest-junit',
coverageReporters: ['text', 'cobertura', 'lcov'],
diff --git a/client/package.json b/client/package.json
index cd40c7c7c6..a3ff5529e5 100644
--- a/client/package.json
+++ b/client/package.json
@@ -1,6 +1,6 @@
{
"name": "@librechat/frontend",
- "version": "v0.8.2",
+ "version": "v0.8.4-rc1",
"description": "",
"type": "module",
"scripts": {
@@ -38,6 +38,7 @@
"@librechat/client": "*",
"@marsidev/react-turnstile": "^1.1.0",
"@mcp-ui/client": "^5.7.0",
+ "@monaco-editor/react": "^4.7.0",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-alert-dialog": "1.0.2",
"@radix-ui/react-checkbox": "^1.0.3",
@@ -80,7 +81,7 @@
"lodash": "^4.17.23",
"lucide-react": "^0.394.0",
"match-sorter": "^8.1.0",
- "mermaid": "^11.12.2",
+ "mermaid": "^11.13.0",
"micromark-extension-llm-math": "^3.1.0",
"qrcode.react": "^4.2.0",
"rc-input-number": "^7.4.2",
@@ -93,7 +94,6 @@
"react-gtm-module": "^2.0.11",
"react-hook-form": "^7.43.9",
"react-i18next": "^15.4.0",
- "react-lazy-load-image-component": "^1.6.0",
"react-markdown": "^9.0.1",
"react-resizable-panels": "^3.0.6",
"react-router-dom": "^6.30.3",
@@ -122,6 +122,7 @@
"@babel/preset-env": "^7.22.15",
"@babel/preset-react": "^7.22.15",
"@babel/preset-typescript": "^7.22.15",
+ "@happy-dom/jest-environment": "^20.8.3",
"@tanstack/react-query-devtools": "^4.29.0",
"@testing-library/dom": "^9.3.0",
"@testing-library/jest-dom": "^5.16.5",
@@ -130,10 +131,10 @@
"@types/jest": "^29.5.14",
"@types/js-cookie": "^3.0.6",
"@types/lodash": "^4.17.15",
- "@types/node": "^20.3.0",
+ "@types/node": "^20.19.35",
"@types/react": "^18.2.11",
"@types/react-dom": "^18.2.4",
- "@vitejs/plugin-react": "^4.3.4",
+ "@vitejs/plugin-react": "^5.1.4",
"autoprefixer": "^10.4.20",
"babel-plugin-replace-ts-export-assignment": "^0.0.2",
"babel-plugin-root-import": "^6.6.0",
@@ -144,16 +145,17 @@
"identity-obj-proxy": "^3.0.0",
"jest": "^30.2.0",
"jest-canvas-mock": "^2.5.2",
- "jest-environment-jsdom": "^29.7.0",
+ "jest-environment-jsdom": "^30.2.0",
"jest-file-loader": "^1.0.3",
"jest-junit": "^16.0.0",
+ "monaco-editor": "^0.55.1",
"postcss": "^8.4.31",
- "postcss-preset-env": "^8.2.0",
+ "postcss-preset-env": "^11.2.0",
"tailwindcss": "^3.4.1",
"typescript": "^5.3.3",
- "vite": "^6.4.1",
+ "vite": "^7.3.1",
"vite-plugin-compression2": "^2.2.1",
- "vite-plugin-node-polyfills": "^0.23.0",
- "vite-plugin-pwa": "^0.21.2"
+ "vite-plugin-node-polyfills": "^0.25.0",
+ "vite-plugin-pwa": "^1.2.0"
}
}
diff --git a/client/public/assets/azure-ai-search.svg b/client/public/assets/azure-ai-search.svg
new file mode 100644
index 0000000000..5db3422b9b
--- /dev/null
+++ b/client/public/assets/azure-ai-search.svg
@@ -0,0 +1 @@
+
diff --git a/client/public/assets/bfl-ai.svg b/client/public/assets/bfl-ai.svg
new file mode 100644
index 0000000000..c8556b8557
--- /dev/null
+++ b/client/public/assets/bfl-ai.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/client/public/assets/calculator.svg b/client/public/assets/calculator.svg
new file mode 100644
index 0000000000..440367fe9e
--- /dev/null
+++ b/client/public/assets/calculator.svg
@@ -0,0 +1 @@
+
diff --git a/client/public/assets/google-search.svg b/client/public/assets/google-search.svg
new file mode 100644
index 0000000000..be3c8db3d5
--- /dev/null
+++ b/client/public/assets/google-search.svg
@@ -0,0 +1 @@
+
diff --git a/client/public/assets/stability-ai.svg b/client/public/assets/stability-ai.svg
new file mode 100644
index 0000000000..bdc74a14d6
--- /dev/null
+++ b/client/public/assets/stability-ai.svg
@@ -0,0 +1 @@
+
diff --git a/client/public/assets/tavily.svg b/client/public/assets/tavily.svg
new file mode 100644
index 0000000000..544d55319b
--- /dev/null
+++ b/client/public/assets/tavily.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/client/src/Providers/ArtifactsContext.tsx b/client/src/Providers/ArtifactsContext.tsx
index 139f679003..fd67d5af94 100644
--- a/client/src/Providers/ArtifactsContext.tsx
+++ b/client/src/Providers/ArtifactsContext.tsx
@@ -1,7 +1,8 @@
import React, { createContext, useContext, useMemo } from 'react';
+import { useRecoilValue } from 'recoil';
import type { TMessage } from 'librechat-data-provider';
-import { useChatContext } from './ChatContext';
import { getLatestText } from '~/utils';
+import store from '~/store';
export interface ArtifactsContextValue {
isSubmitting: boolean;
@@ -18,27 +19,28 @@ interface ArtifactsProviderProps {
}
export function ArtifactsProvider({ children, value }: ArtifactsProviderProps) {
- const { isSubmitting, latestMessage, conversation } = useChatContext();
+ const isSubmitting = useRecoilValue(store.isSubmittingFamily(0));
+ const latestMessage = useRecoilValue(store.latestMessageFamily(0));
+ const conversationId = useRecoilValue(store.conversationIdByIndex(0));
const chatLatestMessageText = useMemo(() => {
return getLatestText({
- messageId: latestMessage?.messageId ?? null,
text: latestMessage?.text ?? null,
content: latestMessage?.content ?? null,
+ messageId: latestMessage?.messageId ?? null,
} as TMessage);
}, [latestMessage?.messageId, latestMessage?.text, latestMessage?.content]);
const defaultContextValue = useMemo(
() => ({
isSubmitting,
+ conversationId: conversationId ?? null,
latestMessageText: chatLatestMessageText,
latestMessageId: latestMessage?.messageId ?? null,
- conversationId: conversation?.conversationId ?? null,
}),
- [isSubmitting, chatLatestMessageText, latestMessage?.messageId, conversation?.conversationId],
+ [isSubmitting, chatLatestMessageText, latestMessage?.messageId, conversationId],
);
- /** Context value only created when relevant values change */
const contextValue = useMemo(
() => (value ? { ...defaultContextValue, ...value } : defaultContextValue),
[defaultContextValue, value],
diff --git a/client/src/Providers/BadgeRowContext.tsx b/client/src/Providers/BadgeRowContext.tsx
index 40df795aba..dce1c38a78 100644
--- a/client/src/Providers/BadgeRowContext.tsx
+++ b/client/src/Providers/BadgeRowContext.tsx
@@ -1,4 +1,4 @@
-import React, { createContext, useContext, useEffect, useRef } from 'react';
+import React, { createContext, useContext, useEffect, useMemo, useRef } from 'react';
import { useSetRecoilState } from 'recoil';
import { Tools, Constants, LocalStorageKeys, AgentCapabilities } from 'librechat-data-provider';
import type { TAgentsEndpoint } from 'librechat-data-provider';
@@ -9,11 +9,13 @@ import {
useCodeApiKeyForm,
useToolToggle,
} from '~/hooks';
-import { getTimestampedValue, setTimestamp } from '~/utils/timestamps';
+import { getTimestampedValue } from '~/utils/timestamps';
+import { useGetStartupConfig } from '~/data-provider';
import { ephemeralAgentByConvoId } from '~/store';
interface BadgeRowContextType {
conversationId?: string | null;
+ storageContextKey?: string;
agentsConfig?: TAgentsEndpoint | null;
webSearch: ReturnType;
artifacts: ReturnType;
@@ -38,34 +40,70 @@ interface BadgeRowProviderProps {
children: React.ReactNode;
isSubmitting?: boolean;
conversationId?: string | null;
+ specName?: string | null;
}
export default function BadgeRowProvider({
children,
isSubmitting,
conversationId,
+ specName,
}: BadgeRowProviderProps) {
- const lastKeyRef = useRef('');
+ const lastContextKeyRef = useRef('');
const hasInitializedRef = useRef(false);
const { agentsConfig } = useGetAgentsConfig();
+ const { data: startupConfig } = useGetStartupConfig();
const key = conversationId ?? Constants.NEW_CONVO;
+ const hasModelSpecs = (startupConfig?.modelSpecs?.list?.length ?? 0) > 0;
+
+ /**
+ * Compute the storage context key for non-spec persistence:
+ * - `__defaults__`: specs configured but none active → shared defaults key
+ * - undefined: spec active (no persistence) or no specs configured (original behavior)
+ *
+ * When a spec is active, tool/MCP state is NOT persisted — the admin's spec
+ * configuration is always applied fresh. Only non-spec user preferences persist.
+ */
+ const storageContextKey = useMemo(() => {
+ if (!specName && hasModelSpecs) {
+ return Constants.spec_defaults_key as string;
+ }
+ return undefined;
+ }, [specName, hasModelSpecs]);
+
+ /**
+ * Compute the storage suffix for reading localStorage defaults:
+ * - New conversations read from environment key (spec or non-spec defaults)
+ * - Existing conversations read from conversation key (per-conversation state)
+ */
+ const isNewConvo = key === Constants.NEW_CONVO;
+ const storageSuffix = isNewConvo && storageContextKey ? storageContextKey : key;
const setEphemeralAgent = useSetRecoilState(ephemeralAgentByConvoId(key));
- /** Initialize ephemeralAgent from localStorage on mount and when conversation changes */
+ /** Initialize ephemeralAgent from localStorage on mount and when conversation/spec changes.
+ * Skipped when a spec is active — applyModelSpecEphemeralAgent handles both new conversations
+ * (pure spec values) and existing conversations (spec values + localStorage overrides). */
useEffect(() => {
if (isSubmitting) {
return;
}
- // Check if this is a new conversation or the first load
- if (!hasInitializedRef.current || lastKeyRef.current !== key) {
+ if (specName) {
+ // Spec active: applyModelSpecEphemeralAgent handles all state (spec base + localStorage
+ // overrides for existing conversations). Reset init flag so switching back to non-spec
+ // triggers a fresh re-init.
+ hasInitializedRef.current = false;
+ return;
+ }
+ // Check if this is a new conversation/spec or the first load
+ if (!hasInitializedRef.current || lastContextKeyRef.current !== storageSuffix) {
hasInitializedRef.current = true;
- lastKeyRef.current = key;
+ lastContextKeyRef.current = storageSuffix;
- const codeToggleKey = `${LocalStorageKeys.LAST_CODE_TOGGLE_}${key}`;
- const webSearchToggleKey = `${LocalStorageKeys.LAST_WEB_SEARCH_TOGGLE_}${key}`;
- const fileSearchToggleKey = `${LocalStorageKeys.LAST_FILE_SEARCH_TOGGLE_}${key}`;
- const artifactsToggleKey = `${LocalStorageKeys.LAST_ARTIFACTS_TOGGLE_}${key}`;
+ const codeToggleKey = `${LocalStorageKeys.LAST_CODE_TOGGLE_}${storageSuffix}`;
+ const webSearchToggleKey = `${LocalStorageKeys.LAST_WEB_SEARCH_TOGGLE_}${storageSuffix}`;
+ const fileSearchToggleKey = `${LocalStorageKeys.LAST_FILE_SEARCH_TOGGLE_}${storageSuffix}`;
+ const artifactsToggleKey = `${LocalStorageKeys.LAST_ARTIFACTS_TOGGLE_}${storageSuffix}`;
const codeToggleValue = getTimestampedValue(codeToggleKey);
const webSearchToggleValue = getTimestampedValue(webSearchToggleKey);
@@ -106,39 +144,53 @@ export default function BadgeRowProvider({
}
}
- /**
- * Always set values for all tools (use defaults if not in `localStorage`)
- * If `ephemeralAgent` is `null`, create a new object with just our tool values
- */
- const finalValues = {
- [Tools.execute_code]: initialValues[Tools.execute_code] ?? false,
- [Tools.web_search]: initialValues[Tools.web_search] ?? false,
- [Tools.file_search]: initialValues[Tools.file_search] ?? false,
- [AgentCapabilities.artifacts]: initialValues[AgentCapabilities.artifacts] ?? false,
- };
+ const hasOverrides = Object.keys(initialValues).length > 0;
- setEphemeralAgent((prev) => ({
- ...(prev || {}),
- ...finalValues,
- }));
-
- Object.entries(finalValues).forEach(([toolKey, value]) => {
- if (value !== false) {
- let storageKey = artifactsToggleKey;
- if (toolKey === Tools.execute_code) {
- storageKey = codeToggleKey;
- } else if (toolKey === Tools.web_search) {
- storageKey = webSearchToggleKey;
- } else if (toolKey === Tools.file_search) {
- storageKey = fileSearchToggleKey;
+ /** Read persisted MCP values from localStorage */
+ let mcpOverrides: string[] | null = null;
+ const mcpStorageKey = `${LocalStorageKeys.LAST_MCP_}${storageSuffix}`;
+ const mcpRaw = localStorage.getItem(mcpStorageKey);
+ if (mcpRaw !== null) {
+ try {
+ const parsed = JSON.parse(mcpRaw);
+ if (Array.isArray(parsed) && parsed.length > 0) {
+ mcpOverrides = parsed;
}
- // Store the value and set timestamp for existing values
- localStorage.setItem(storageKey, JSON.stringify(value));
- setTimestamp(storageKey);
+ } catch (e) {
+ console.error('Failed to parse MCP values:', e);
}
+ }
+
+ setEphemeralAgent((prev) => {
+ if (prev == null) {
+ /** ephemeralAgent is null — use localStorage defaults */
+ if (hasOverrides || mcpOverrides) {
+ const result = { ...initialValues };
+ if (mcpOverrides) {
+ result.mcp = mcpOverrides;
+ }
+ return result;
+ }
+ return prev;
+ }
+ /** ephemeralAgent already has values (from prior state).
+ * Only fill in undefined keys from localStorage. */
+ let changed = false;
+ const result = { ...prev };
+ for (const [toolKey, value] of Object.entries(initialValues)) {
+ if (result[toolKey] === undefined) {
+ result[toolKey] = value;
+ changed = true;
+ }
+ }
+ if (mcpOverrides && result.mcp === undefined) {
+ result.mcp = mcpOverrides;
+ changed = true;
+ }
+ return changed ? result : prev;
});
}
- }, [key, isSubmitting, setEphemeralAgent]);
+ }, [storageSuffix, specName, isSubmitting, setEphemeralAgent]);
/** CodeInterpreter hooks */
const codeApiKeyForm = useCodeApiKeyForm({});
@@ -146,6 +198,7 @@ export default function BadgeRowProvider({
const codeInterpreter = useToolToggle({
conversationId,
+ storageContextKey,
setIsDialogOpen: setCodeDialogOpen,
toolKey: Tools.execute_code,
localStorageKey: LocalStorageKeys.LAST_CODE_TOGGLE_,
@@ -161,6 +214,7 @@ export default function BadgeRowProvider({
const webSearch = useToolToggle({
conversationId,
+ storageContextKey,
toolKey: Tools.web_search,
localStorageKey: LocalStorageKeys.LAST_WEB_SEARCH_TOGGLE_,
setIsDialogOpen: setWebSearchDialogOpen,
@@ -173,6 +227,7 @@ export default function BadgeRowProvider({
/** FileSearch hook */
const fileSearch = useToolToggle({
conversationId,
+ storageContextKey,
toolKey: Tools.file_search,
localStorageKey: LocalStorageKeys.LAST_FILE_SEARCH_TOGGLE_,
isAuthenticated: true,
@@ -181,12 +236,13 @@ export default function BadgeRowProvider({
/** Artifacts hook - using a custom key since it's not a Tool but a capability */
const artifacts = useToolToggle({
conversationId,
+ storageContextKey,
toolKey: AgentCapabilities.artifacts,
localStorageKey: LocalStorageKeys.LAST_ARTIFACTS_TOGGLE_,
isAuthenticated: true,
});
- const mcpServerManager = useMCPServerManager({ conversationId });
+ const mcpServerManager = useMCPServerManager({ conversationId, storageContextKey });
const value: BadgeRowContextType = {
webSearch,
@@ -194,6 +250,7 @@ export default function BadgeRowProvider({
fileSearch,
agentsConfig,
conversationId,
+ storageContextKey,
codeApiKeyForm,
codeInterpreter,
searchApiKeyForm,
diff --git a/client/src/Providers/DragDropContext.tsx b/client/src/Providers/DragDropContext.tsx
index e5a2177f2d..b519c0171f 100644
--- a/client/src/Providers/DragDropContext.tsx
+++ b/client/src/Providers/DragDropContext.tsx
@@ -1,5 +1,5 @@
import React, { createContext, useContext, useMemo } from 'react';
-import { getEndpointField, isAgentsEndpoint } from 'librechat-data-provider';
+import { isAgentsEndpoint, resolveEndpointType } from 'librechat-data-provider';
import type { EModelEndpoint } from 'librechat-data-provider';
import { useGetEndpointsQuery, useGetAgentByIdQuery } from '~/data-provider';
import { useAgentsMapContext } from './AgentsMapContext';
@@ -9,7 +9,7 @@ interface DragDropContextValue {
conversationId: string | null | undefined;
agentId: string | null | undefined;
endpoint: string | null | undefined;
- endpointType?: EModelEndpoint | undefined;
+ endpointType?: EModelEndpoint | string | undefined;
useResponsesApi?: boolean;
}
@@ -20,13 +20,6 @@ export function DragDropProvider({ children }: { children: React.ReactNode }) {
const { data: endpointsConfig } = useGetEndpointsQuery();
const agentsMap = useAgentsMapContext();
- const endpointType = useMemo(() => {
- return (
- getEndpointField(endpointsConfig, conversation?.endpoint, 'type') ||
- (conversation?.endpoint as EModelEndpoint | undefined)
- );
- }, [conversation?.endpoint, endpointsConfig]);
-
const needsAgentFetch = useMemo(() => {
const isAgents = isAgentsEndpoint(conversation?.endpoint);
if (!isAgents || !conversation?.agent_id) {
@@ -40,6 +33,20 @@ export function DragDropProvider({ children }: { children: React.ReactNode }) {
enabled: needsAgentFetch,
});
+ const agentProvider = useMemo(() => {
+ const isAgents = isAgentsEndpoint(conversation?.endpoint);
+ if (!isAgents || !conversation?.agent_id) {
+ return undefined;
+ }
+ const agent = agentData || agentsMap?.[conversation.agent_id];
+ return agent?.provider;
+ }, [conversation?.endpoint, conversation?.agent_id, agentData, agentsMap]);
+
+ const endpointType = useMemo(
+ () => resolveEndpointType(endpointsConfig, conversation?.endpoint, agentProvider),
+ [endpointsConfig, conversation?.endpoint, agentProvider],
+ );
+
const useResponsesApi = useMemo(() => {
const isAgents = isAgentsEndpoint(conversation?.endpoint);
if (!isAgents || !conversation?.agent_id || conversation?.useResponsesApi) {
diff --git a/client/src/Providers/MessagesViewContext.tsx b/client/src/Providers/MessagesViewContext.tsx
index f8f5eef12a..f1cae204a4 100644
--- a/client/src/Providers/MessagesViewContext.tsx
+++ b/client/src/Providers/MessagesViewContext.tsx
@@ -18,7 +18,8 @@ interface MessagesViewContextValue {
/** Message state management */
index: ReturnType['index'];
- latestMessage: ReturnType['latestMessage'];
+ latestMessageId: ReturnType['latestMessageId'];
+ latestMessageDepth: ReturnType['latestMessageDepth'];
setLatestMessage: ReturnType['setLatestMessage'];
getMessages: ReturnType['getMessages'];
setMessages: ReturnType['setMessages'];
@@ -39,7 +40,8 @@ export function MessagesViewProvider({ children }: { children: React.ReactNode }
regenerate,
isSubmitting,
conversation,
- latestMessage,
+ latestMessageId,
+ latestMessageDepth,
setAbortScroll,
handleContinue,
setLatestMessage,
@@ -83,10 +85,11 @@ export function MessagesViewProvider({ children }: { children: React.ReactNode }
const messageState = useMemo(
() => ({
index,
- latestMessage,
+ latestMessageId,
+ latestMessageDepth,
setLatestMessage,
}),
- [index, latestMessage, setLatestMessage],
+ [index, latestMessageId, latestMessageDepth, setLatestMessage],
);
/** Combine all values into final context value */
@@ -139,9 +142,9 @@ export function useMessagesOperations() {
/** Hook for components that only need message state */
export function useMessagesState() {
- const { index, latestMessage, setLatestMessage } = useMessagesViewContext();
+ const { index, latestMessageId, latestMessageDepth, setLatestMessage } = useMessagesViewContext();
return useMemo(
- () => ({ index, latestMessage, setLatestMessage }),
- [index, latestMessage, setLatestMessage],
+ () => ({ index, latestMessageId, latestMessageDepth, setLatestMessage }),
+ [index, latestMessageId, latestMessageDepth, setLatestMessage],
);
}
diff --git a/client/src/Providers/__tests__/DragDropContext.spec.tsx b/client/src/Providers/__tests__/DragDropContext.spec.tsx
new file mode 100644
index 0000000000..3c5e0f0796
--- /dev/null
+++ b/client/src/Providers/__tests__/DragDropContext.spec.tsx
@@ -0,0 +1,134 @@
+import React from 'react';
+import { renderHook } from '@testing-library/react';
+import { EModelEndpoint } from 'librechat-data-provider';
+import type { TEndpointsConfig, Agent } from 'librechat-data-provider';
+import { DragDropProvider, useDragDropContext } from '../DragDropContext';
+
+const mockEndpointsConfig: TEndpointsConfig = {
+ [EModelEndpoint.openAI]: { userProvide: false, order: 0 },
+ [EModelEndpoint.agents]: { userProvide: false, order: 1 },
+ [EModelEndpoint.anthropic]: { userProvide: false, order: 6 },
+ Moonshot: { type: EModelEndpoint.custom, userProvide: false, order: 9999 },
+ 'Some Endpoint': { type: EModelEndpoint.custom, userProvide: false, order: 9999 },
+};
+
+let mockConversation: Record | null = null;
+let mockAgentsMap: Record> = {};
+let mockAgentQueryData: Partial | undefined;
+
+jest.mock('~/data-provider', () => ({
+ useGetEndpointsQuery: () => ({ data: mockEndpointsConfig }),
+ useGetAgentByIdQuery: () => ({ data: mockAgentQueryData }),
+}));
+
+jest.mock('../AgentsMapContext', () => ({
+ useAgentsMapContext: () => mockAgentsMap,
+}));
+
+jest.mock('../ChatContext', () => ({
+ useChatContext: () => ({ conversation: mockConversation }),
+}));
+
+function wrapper({ children }: { children: React.ReactNode }) {
+ return {children} ;
+}
+
+describe('DragDropContext endpointType resolution', () => {
+ beforeEach(() => {
+ mockConversation = null;
+ mockAgentsMap = {};
+ mockAgentQueryData = undefined;
+ });
+
+ describe('non-agents endpoints', () => {
+ it('resolves custom endpoint type for a custom endpoint', () => {
+ mockConversation = { endpoint: 'Moonshot' };
+ const { result } = renderHook(() => useDragDropContext(), { wrapper });
+ expect(result.current.endpointType).toBe(EModelEndpoint.custom);
+ });
+
+ it('resolves endpoint name for a standard endpoint', () => {
+ mockConversation = { endpoint: EModelEndpoint.openAI };
+ const { result } = renderHook(() => useDragDropContext(), { wrapper });
+ expect(result.current.endpointType).toBe(EModelEndpoint.openAI);
+ });
+ });
+
+ describe('agents endpoint with provider from agentsMap', () => {
+ it('resolves to custom for agent with Moonshot provider', () => {
+ mockConversation = { endpoint: EModelEndpoint.agents, agent_id: 'agent-1' };
+ mockAgentsMap = {
+ 'agent-1': { provider: 'Moonshot', model_parameters: {} } as Partial,
+ };
+ const { result } = renderHook(() => useDragDropContext(), { wrapper });
+ expect(result.current.endpointType).toBe(EModelEndpoint.custom);
+ });
+
+ it('resolves to custom for agent with custom provider with spaces', () => {
+ mockConversation = { endpoint: EModelEndpoint.agents, agent_id: 'agent-1' };
+ mockAgentsMap = {
+ 'agent-1': { provider: 'Some Endpoint', model_parameters: {} } as Partial,
+ };
+ const { result } = renderHook(() => useDragDropContext(), { wrapper });
+ expect(result.current.endpointType).toBe(EModelEndpoint.custom);
+ });
+
+ it('resolves to openAI for agent with openAI provider', () => {
+ mockConversation = { endpoint: EModelEndpoint.agents, agent_id: 'agent-1' };
+ mockAgentsMap = {
+ 'agent-1': { provider: EModelEndpoint.openAI, model_parameters: {} } as Partial,
+ };
+ const { result } = renderHook(() => useDragDropContext(), { wrapper });
+ expect(result.current.endpointType).toBe(EModelEndpoint.openAI);
+ });
+
+ it('resolves to anthropic for agent with anthropic provider', () => {
+ mockConversation = { endpoint: EModelEndpoint.agents, agent_id: 'agent-1' };
+ mockAgentsMap = {
+ 'agent-1': { provider: EModelEndpoint.anthropic, model_parameters: {} } as Partial,
+ };
+ const { result } = renderHook(() => useDragDropContext(), { wrapper });
+ expect(result.current.endpointType).toBe(EModelEndpoint.anthropic);
+ });
+ });
+
+ describe('agents endpoint with provider from agentData query', () => {
+ it('uses agentData when agent is not in agentsMap', () => {
+ mockConversation = { endpoint: EModelEndpoint.agents, agent_id: 'agent-2' };
+ mockAgentsMap = {};
+ mockAgentQueryData = { provider: 'Moonshot' } as Partial;
+ const { result } = renderHook(() => useDragDropContext(), { wrapper });
+ expect(result.current.endpointType).toBe(EModelEndpoint.custom);
+ });
+ });
+
+ describe('agents endpoint without provider', () => {
+ it('falls back to agents when no agent_id', () => {
+ mockConversation = { endpoint: EModelEndpoint.agents };
+ const { result } = renderHook(() => useDragDropContext(), { wrapper });
+ expect(result.current.endpointType).toBe(EModelEndpoint.agents);
+ });
+
+ it('falls back to agents when agent has no provider', () => {
+ mockConversation = { endpoint: EModelEndpoint.agents, agent_id: 'agent-1' };
+ mockAgentsMap = { 'agent-1': { model_parameters: {} } as Partial };
+ const { result } = renderHook(() => useDragDropContext(), { wrapper });
+ expect(result.current.endpointType).toBe(EModelEndpoint.agents);
+ });
+ });
+
+ describe('consistency: same endpoint type whether used directly or through agents', () => {
+ it('Moonshot resolves to the same type as direct endpoint and as agent provider', () => {
+ mockConversation = { endpoint: 'Moonshot' };
+ const { result: directResult } = renderHook(() => useDragDropContext(), { wrapper });
+
+ mockConversation = { endpoint: EModelEndpoint.agents, agent_id: 'agent-1' };
+ mockAgentsMap = {
+ 'agent-1': { provider: 'Moonshot', model_parameters: {} } as Partial,
+ };
+ const { result: agentResult } = renderHook(() => useDragDropContext(), { wrapper });
+
+ expect(directResult.current.endpointType).toBe(agentResult.current.endpointType);
+ });
+ });
+});
diff --git a/client/src/a11y/LiveAnnouncer.tsx b/client/src/a11y/LiveAnnouncer.tsx
index 9a02711556..0eac8089bc 100644
--- a/client/src/a11y/LiveAnnouncer.tsx
+++ b/client/src/a11y/LiveAnnouncer.tsx
@@ -56,10 +56,13 @@ const LiveAnnouncer: React.FC = ({ children }) => {
const announceAssertive = announcePolite;
- const contextValue = {
- announcePolite,
- announceAssertive,
- };
+ const contextValue = useMemo(
+ () => ({
+ announcePolite,
+ announceAssertive,
+ }),
+ [announcePolite, announceAssertive],
+ );
useEffect(() => {
return () => {
diff --git a/client/src/components/Agents/tests/VirtualScrollingPerformance.test.tsx b/client/src/components/Agents/tests/VirtualScrollingPerformance.test.tsx
index 1e1b7d1e4b..293bd8878e 100644
--- a/client/src/components/Agents/tests/VirtualScrollingPerformance.test.tsx
+++ b/client/src/components/Agents/tests/VirtualScrollingPerformance.test.tsx
@@ -179,9 +179,7 @@ describe('Virtual Scrolling Performance', () => {
};
it('efficiently handles 1000 agents without rendering all DOM nodes', () => {
- const startTime = performance.now();
renderComponent(1000);
- const endTime = performance.now();
const virtualList = screen.getByTestId('virtual-list');
expect(virtualList).toBeInTheDocument();
@@ -191,19 +189,10 @@ describe('Virtual Scrolling Performance', () => {
const renderedCards = screen.getAllByTestId(/agent-card-/);
expect(renderedCards.length).toBeLessThan(50); // Much less than 1000
expect(renderedCards.length).toBeGreaterThan(0);
-
- // Performance check: rendering should be fast
- const renderTime = endTime - startTime;
- expect(renderTime).toBeLessThan(740);
-
- console.log(`Rendered 1000 agents in ${renderTime.toFixed(2)}ms`);
- console.log(`Only ${renderedCards.length} DOM nodes created for 1000 agents`);
});
it('efficiently handles 5000 agents (stress test)', () => {
- const startTime = performance.now();
renderComponent(5000);
- const endTime = performance.now();
const virtualList = screen.getByTestId('virtual-list');
expect(virtualList).toBeInTheDocument();
@@ -213,13 +202,6 @@ describe('Virtual Scrolling Performance', () => {
const renderedCards = screen.getAllByTestId(/agent-card-/);
expect(renderedCards.length).toBeLessThan(50);
expect(renderedCards.length).toBeGreaterThan(0);
-
- // Performance should still be reasonable
- const renderTime = endTime - startTime;
- expect(renderTime).toBeLessThan(200); // Should render in less than 200ms
-
- console.log(`Rendered 5000 agents in ${renderTime.toFixed(2)}ms`);
- console.log(`Only ${renderedCards.length} DOM nodes created for 5000 agents`);
});
it('calculates correct number of virtual rows for different screen sizes', () => {
diff --git a/client/src/components/Artifacts/ArtifactCodeEditor.tsx b/client/src/components/Artifacts/ArtifactCodeEditor.tsx
index 4ab2b182b8..d03397821d 100644
--- a/client/src/components/Artifacts/ArtifactCodeEditor.tsx
+++ b/client/src/components/Artifacts/ArtifactCodeEditor.tsx
@@ -1,206 +1,326 @@
-import React, { useMemo, useState, useEffect, useRef, memo } from 'react';
+import React, { useMemo, useState, useEffect, useRef, useCallback } from 'react';
import debounce from 'lodash/debounce';
-import { KeyBinding } from '@codemirror/view';
-import { autocompletion, completionKeymap } from '@codemirror/autocomplete';
-import {
- useSandpack,
- SandpackCodeEditor,
- SandpackProvider as StyledProvider,
-} from '@codesandbox/sandpack-react';
-import type { SandpackProviderProps } from '@codesandbox/sandpack-react/unstyled';
-import type { SandpackBundlerFile } from '@codesandbox/sandpack-client';
-import type { CodeEditorRef } from '@codesandbox/sandpack-react';
-import type { ArtifactFiles, Artifact } from '~/common';
-import { useEditArtifact, useGetStartupConfig } from '~/data-provider';
+import MonacoEditor from '@monaco-editor/react';
+import type { Monaco } from '@monaco-editor/react';
+import type { editor } from 'monaco-editor';
+import type { Artifact } from '~/common';
import { useMutationState, useCodeState } from '~/Providers/EditorContext';
import { useArtifactsContext } from '~/Providers';
-import { sharedFiles, sharedOptions } from '~/utils/artifacts';
+import { useEditArtifact } from '~/data-provider';
-const CodeEditor = memo(
- ({
- fileKey,
- readOnly,
- artifact,
- editorRef,
- }: {
- fileKey: string;
- readOnly?: boolean;
- artifact: Artifact;
- editorRef: React.MutableRefObject;
- }) => {
- const { sandpack } = useSandpack();
- const [currentUpdate, setCurrentUpdate] = useState(null);
- const { isMutating, setIsMutating } = useMutationState();
- const { setCurrentCode } = useCodeState();
- const editArtifact = useEditArtifact({
- onMutate: (vars) => {
- setIsMutating(true);
- setCurrentUpdate(vars.updated);
- },
- onSuccess: () => {
- setIsMutating(false);
- setCurrentUpdate(null);
- },
- onError: () => {
- setIsMutating(false);
- },
- });
+const LANG_MAP: Record = {
+ javascript: 'javascript',
+ typescript: 'typescript',
+ python: 'python',
+ css: 'css',
+ json: 'json',
+ markdown: 'markdown',
+ html: 'html',
+ xml: 'xml',
+ sql: 'sql',
+ yaml: 'yaml',
+ shell: 'shell',
+ bash: 'shell',
+ tsx: 'typescript',
+ jsx: 'javascript',
+ c: 'c',
+ cpp: 'cpp',
+ java: 'java',
+ go: 'go',
+ rust: 'rust',
+ kotlin: 'kotlin',
+ swift: 'swift',
+ php: 'php',
+ ruby: 'ruby',
+ r: 'r',
+ lua: 'lua',
+ scala: 'scala',
+ perl: 'perl',
+};
- /**
- * Create stable debounced mutation that doesn't depend on changing callbacks
- * Use refs to always access the latest values without recreating the debounce
- */
- const artifactRef = useRef(artifact);
- const isMutatingRef = useRef(isMutating);
- const currentUpdateRef = useRef(currentUpdate);
- const editArtifactRef = useRef(editArtifact);
- const setCurrentCodeRef = useRef(setCurrentCode);
+const TYPE_MAP: Record = {
+ 'text/html': 'html',
+ 'application/vnd.code-html': 'html',
+ 'application/vnd.react': 'typescript',
+ 'application/vnd.ant.react': 'typescript',
+ 'text/markdown': 'markdown',
+ 'text/md': 'markdown',
+ 'text/plain': 'plaintext',
+ 'application/vnd.mermaid': 'markdown',
+};
- useEffect(() => {
- artifactRef.current = artifact;
- }, [artifact]);
+function getMonacoLanguage(type?: string, language?: string): string {
+ if (language && LANG_MAP[language]) {
+ return LANG_MAP[language];
+ }
+ return TYPE_MAP[type ?? ''] ?? 'plaintext';
+}
- useEffect(() => {
- isMutatingRef.current = isMutating;
- }, [isMutating]);
-
- useEffect(() => {
- currentUpdateRef.current = currentUpdate;
- }, [currentUpdate]);
-
- useEffect(() => {
- editArtifactRef.current = editArtifact;
- }, [editArtifact]);
-
- useEffect(() => {
- setCurrentCodeRef.current = setCurrentCode;
- }, [setCurrentCode]);
-
- /**
- * Create debounced mutation once - never recreate it
- * All values are accessed via refs so they're always current
- */
- const debouncedMutation = useMemo(
- () =>
- debounce((code: string) => {
- if (readOnly) {
- return;
- }
- if (isMutatingRef.current) {
- return;
- }
- if (artifactRef.current.index == null) {
- return;
- }
-
- const artifact = artifactRef.current;
- const artifactIndex = artifact.index;
- const isNotOriginal =
- code && artifact.content != null && code.trim() !== artifact.content.trim();
- const isNotRepeated =
- currentUpdateRef.current == null
- ? true
- : code != null && code.trim() !== currentUpdateRef.current.trim();
-
- if (artifact.content && isNotOriginal && isNotRepeated && artifactIndex != null) {
- setCurrentCodeRef.current(code);
- editArtifactRef.current.mutate({
- index: artifactIndex,
- messageId: artifact.messageId ?? '',
- original: artifact.content,
- updated: code,
- });
- }
- }, 500),
- [readOnly],
- );
-
- /**
- * Listen to Sandpack file changes and trigger debounced mutation
- */
- useEffect(() => {
- const currentCode = (sandpack.files['/' + fileKey] as SandpackBundlerFile | undefined)?.code;
- if (currentCode) {
- debouncedMutation(currentCode);
- }
- }, [sandpack.files, fileKey, debouncedMutation]);
-
- /**
- * Cleanup: cancel pending mutations when component unmounts or artifact changes
- */
- useEffect(() => {
- return () => {
- debouncedMutation.cancel();
- };
- }, [artifact.id, debouncedMutation]);
-
- return (
- (completionKeymap)}
- className="hljs language-javascript bg-black"
- />
- );
- },
-);
-
-export const ArtifactCodeEditor = function ({
- files,
- fileKey,
- template,
+export const ArtifactCodeEditor = function ArtifactCodeEditor({
artifact,
- editorRef,
- sharedProps,
+ monacoRef,
readOnly: externalReadOnly,
}: {
- fileKey: string;
artifact: Artifact;
- files: ArtifactFiles;
- template: SandpackProviderProps['template'];
- sharedProps: Partial;
- editorRef: React.MutableRefObject;
+ monacoRef: React.MutableRefObject;
readOnly?: boolean;
}) {
- const { data: config } = useGetStartupConfig();
const { isSubmitting } = useArtifactsContext();
- const options: typeof sharedOptions = useMemo(() => {
- if (!config) {
- return sharedOptions;
- }
- return {
- ...sharedOptions,
- activeFile: '/' + fileKey,
- bundlerURL: template === 'static' ? config.staticBundlerURL : config.bundlerURL,
- };
- }, [config, template, fileKey]);
- const initialReadOnly = (externalReadOnly ?? false) || (isSubmitting ?? false);
- const [readOnly, setReadOnly] = useState(initialReadOnly);
- useEffect(() => {
- setReadOnly((externalReadOnly ?? false) || (isSubmitting ?? false));
- }, [isSubmitting, externalReadOnly]);
+ const readOnly = (externalReadOnly ?? false) || isSubmitting;
+ const { setCurrentCode } = useCodeState();
+ const [currentUpdate, setCurrentUpdate] = useState(null);
+ const { isMutating, setIsMutating } = useMutationState();
+ const editArtifact = useEditArtifact({
+ onMutate: (vars) => {
+ setIsMutating(true);
+ setCurrentUpdate(vars.updated);
+ },
+ onSuccess: () => {
+ setIsMutating(false);
+ setCurrentUpdate(null);
+ },
+ onError: () => {
+ setIsMutating(false);
+ },
+ });
- if (Object.keys(files).length === 0) {
+ const artifactRef = useRef(artifact);
+ const isMutatingRef = useRef(isMutating);
+ const currentUpdateRef = useRef(currentUpdate);
+ const editArtifactRef = useRef(editArtifact);
+ const setCurrentCodeRef = useRef(setCurrentCode);
+ const prevContentRef = useRef(artifact.content ?? '');
+ const prevArtifactId = useRef(artifact.id);
+ const prevReadOnly = useRef(readOnly);
+
+ artifactRef.current = artifact;
+ isMutatingRef.current = isMutating;
+ currentUpdateRef.current = currentUpdate;
+ editArtifactRef.current = editArtifact;
+ setCurrentCodeRef.current = setCurrentCode;
+
+ const debouncedMutation = useMemo(
+ () =>
+ debounce((code: string) => {
+ if (readOnly || isMutatingRef.current || artifactRef.current.index == null) {
+ return;
+ }
+ const art = artifactRef.current;
+ const isNotOriginal = art.content != null && code.trim() !== art.content.trim();
+ const isNotRepeated =
+ currentUpdateRef.current == null ? true : code.trim() !== currentUpdateRef.current.trim();
+
+ if (art.content != null && isNotOriginal && isNotRepeated && art.index != null) {
+ setCurrentCodeRef.current(code);
+ editArtifactRef.current.mutate({
+ index: art.index,
+ messageId: art.messageId ?? '',
+ original: art.content,
+ updated: code,
+ });
+ }
+ }, 500),
+ [readOnly],
+ );
+
+ useEffect(() => {
+ return () => debouncedMutation.cancel();
+ }, [artifact.id, debouncedMutation]);
+
+ /**
+ * Streaming: use model.applyEdits() to append new content.
+ * Unlike setValue/pushEditOperations, applyEdits preserves existing
+ * tokens so syntax highlighting doesn't flash during updates.
+ */
+ useEffect(() => {
+ const ed = monacoRef.current;
+ if (!ed || !readOnly) {
+ return;
+ }
+ const newContent = artifact.content ?? '';
+ const prev = prevContentRef.current;
+
+ if (newContent === prev) {
+ return;
+ }
+
+ const model = ed.getModel();
+ if (!model) {
+ return;
+ }
+
+ if (newContent.startsWith(prev) && prev.length > 0) {
+ const appended = newContent.slice(prev.length);
+ const endPos = model.getPositionAt(model.getValueLength());
+ model.applyEdits([
+ {
+ range: {
+ startLineNumber: endPos.lineNumber,
+ startColumn: endPos.column,
+ endLineNumber: endPos.lineNumber,
+ endColumn: endPos.column,
+ },
+ text: appended,
+ },
+ ]);
+ } else {
+ model.setValue(newContent);
+ }
+
+ prevContentRef.current = newContent;
+ ed.revealLine(model.getLineCount());
+ }, [artifact.content, readOnly, monacoRef]);
+
+ useEffect(() => {
+ if (artifact.id === prevArtifactId.current) {
+ return;
+ }
+ prevArtifactId.current = artifact.id;
+ prevContentRef.current = artifact.content ?? '';
+ const ed = monacoRef.current;
+ if (ed && artifact.content != null) {
+ ed.getModel()?.setValue(artifact.content);
+ }
+ }, [artifact.id, artifact.content, monacoRef]);
+
+ useEffect(() => {
+ if (prevReadOnly.current && !readOnly && artifact.content != null) {
+ const ed = monacoRef.current;
+ if (ed) {
+ ed.getModel()?.setValue(artifact.content);
+ prevContentRef.current = artifact.content;
+ }
+ }
+ prevReadOnly.current = readOnly;
+ }, [readOnly, artifact.content, monacoRef]);
+
+ const handleChange = useCallback(
+ (value: string | undefined) => {
+ if (value === undefined || readOnly) {
+ return;
+ }
+ prevContentRef.current = value;
+ setCurrentCode(value);
+ if (value.length > 0) {
+ debouncedMutation(value);
+ }
+ },
+ [readOnly, debouncedMutation, setCurrentCode],
+ );
+
+ /**
+ * Disable all validation — this is an artifact viewer/editor, not an IDE.
+ * Note: these are global Monaco settings that affect all editor instances on the page.
+ * The `as unknown` cast is required because monaco-editor v0.55 types `.languages.typescript`
+ * as `{ deprecated: true }` while the runtime API is fully functional.
+ */
+ const handleBeforeMount = useCallback((monaco: Monaco) => {
+ const { typescriptDefaults, javascriptDefaults, JsxEmit } = monaco.languages
+ .typescript as unknown as {
+ typescriptDefaults: {
+ setDiagnosticsOptions: (o: {
+ noSemanticValidation: boolean;
+ noSyntaxValidation: boolean;
+ }) => void;
+ setCompilerOptions: (o: {
+ allowNonTsExtensions: boolean;
+ allowJs: boolean;
+ jsx: number;
+ }) => void;
+ };
+ javascriptDefaults: {
+ setDiagnosticsOptions: (o: {
+ noSemanticValidation: boolean;
+ noSyntaxValidation: boolean;
+ }) => void;
+ setCompilerOptions: (o: {
+ allowNonTsExtensions: boolean;
+ allowJs: boolean;
+ jsx: number;
+ }) => void;
+ };
+ JsxEmit: { React: number };
+ };
+ const diagnosticsOff = { noSemanticValidation: true, noSyntaxValidation: true };
+ const compilerBase = { allowNonTsExtensions: true, allowJs: true, jsx: JsxEmit.React };
+ typescriptDefaults.setDiagnosticsOptions(diagnosticsOff);
+ javascriptDefaults.setDiagnosticsOptions(diagnosticsOff);
+ typescriptDefaults.setCompilerOptions(compilerBase);
+ javascriptDefaults.setCompilerOptions(compilerBase);
+ }, []);
+
+ const handleMount = useCallback(
+ (ed: editor.IStandaloneCodeEditor) => {
+ monacoRef.current = ed;
+ prevContentRef.current = ed.getModel()?.getValue() ?? artifact.content ?? '';
+ if (readOnly) {
+ const model = ed.getModel();
+ if (model) {
+ ed.revealLine(model.getLineCount());
+ }
+ }
+ },
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ [monacoRef],
+ );
+
+ const language = getMonacoLanguage(artifact.type, artifact.language);
+
+ const editorOptions = useMemo(
+ () => ({
+ readOnly,
+ minimap: { enabled: false },
+ lineNumbers: 'on',
+ scrollBeyondLastLine: false,
+ fontSize: 13,
+ tabSize: 2,
+ wordWrap: 'on',
+ automaticLayout: true,
+ padding: { top: 8 },
+ renderLineHighlight: readOnly ? 'none' : 'line',
+ cursorStyle: readOnly ? 'underline-thin' : 'line',
+ scrollbar: {
+ vertical: 'visible',
+ horizontal: 'auto',
+ verticalScrollbarSize: 8,
+ horizontalScrollbarSize: 8,
+ useShadows: false,
+ alwaysConsumeMouseWheel: false,
+ },
+ overviewRulerLanes: 0,
+ hideCursorInOverviewRuler: true,
+ overviewRulerBorder: false,
+ folding: false,
+ glyphMargin: false,
+ colorDecorators: !readOnly,
+ occurrencesHighlight: readOnly ? 'off' : 'singleFile',
+ selectionHighlight: !readOnly,
+ renderValidationDecorations: readOnly ? 'off' : 'editable',
+ quickSuggestions: !readOnly,
+ suggestOnTriggerCharacters: !readOnly,
+ parameterHints: { enabled: !readOnly },
+ hover: { enabled: !readOnly },
+ matchBrackets: readOnly ? 'never' : 'always',
+ }),
+ [readOnly],
+ );
+
+ if (!artifact.content) {
return null;
}
return (
-
-
-
+
+
+
);
};
diff --git a/client/src/components/Artifacts/ArtifactTabs.tsx b/client/src/components/Artifacts/ArtifactTabs.tsx
index 8e2a92eb9c..32332215f0 100644
--- a/client/src/components/Artifacts/ArtifactTabs.tsx
+++ b/client/src/components/Artifacts/ArtifactTabs.tsx
@@ -1,30 +1,26 @@
import { useRef, useEffect } from 'react';
import * as Tabs from '@radix-ui/react-tabs';
import type { SandpackPreviewRef } from '@codesandbox/sandpack-react/unstyled';
-import type { CodeEditorRef } from '@codesandbox/sandpack-react';
+import type { editor } from 'monaco-editor';
import type { Artifact } from '~/common';
import { useCodeState } from '~/Providers/EditorContext';
-import { useArtifactsContext } from '~/Providers';
import useArtifactProps from '~/hooks/Artifacts/useArtifactProps';
-import { useAutoScroll } from '~/hooks/Artifacts/useAutoScroll';
import { ArtifactCodeEditor } from './ArtifactCodeEditor';
import { useGetStartupConfig } from '~/data-provider';
import { ArtifactPreview } from './ArtifactPreview';
export default function ArtifactTabs({
artifact,
- editorRef,
previewRef,
isSharedConvo,
}: {
artifact: Artifact;
- editorRef: React.MutableRefObject;
previewRef: React.MutableRefObject;
isSharedConvo?: boolean;
}) {
- const { isSubmitting } = useArtifactsContext();
const { currentCode, setCurrentCode } = useCodeState();
const { data: startupConfig } = useGetStartupConfig();
+ const monacoRef = useRef(null);
const lastIdRef = useRef(null);
useEffect(() => {
@@ -34,33 +30,24 @@ export default function ArtifactTabs({
lastIdRef.current = artifact.id;
}, [setCurrentCode, artifact.id]);
- const content = artifact.content ?? '';
- const contentRef = useRef(null);
- useAutoScroll({ ref: contentRef, content, isSubmitting });
-
const { files, fileKey, template, sharedProps } = useArtifactProps({ artifact });
return (
-
+
-
+
();
const previewRef = useRef();
const [isVisible, setIsVisible] = useState(false);
const [isClosing, setIsClosing] = useState(false);
@@ -297,7 +296,6 @@ export default function Artifacts() {
}
previewRef={previewRef as React.MutableRefObject}
isSharedConvo={isSharedConvo}
/>
diff --git a/client/src/components/Artifacts/Code.tsx b/client/src/components/Artifacts/Code.tsx
index 6894ce775b..001b010908 100644
--- a/client/src/components/Artifacts/Code.tsx
+++ b/client/src/components/Artifacts/Code.tsx
@@ -1,11 +1,8 @@
-import React, { memo, useEffect, useRef, useState } from 'react';
+import React, { memo, useState } from 'react';
import copy from 'copy-to-clipboard';
-import rehypeKatex from 'rehype-katex';
-import ReactMarkdown from 'react-markdown';
import { Button } from '@librechat/client';
-import rehypeHighlight from 'rehype-highlight';
import { Copy, CircleCheckBig } from 'lucide-react';
-import { handleDoubleClick, langSubset } from '~/utils';
+import { handleDoubleClick } from '~/utils';
import { useLocalize } from '~/hooks';
type TCodeProps = {
@@ -29,74 +26,6 @@ export const code: React.ElementType = memo(({ inline, className, children }: TC
return {children};
});
-export const CodeMarkdown = memo(
- ({ content = '', isSubmitting }: { content: string; isSubmitting: boolean }) => {
- const scrollRef = useRef(null);
- const [userScrolled, setUserScrolled] = useState(false);
- const currentContent = content;
- const rehypePlugins = [
- [rehypeKatex],
- [
- rehypeHighlight,
- {
- detect: true,
- ignoreMissing: true,
- subset: langSubset,
- },
- ],
- ];
-
- useEffect(() => {
- const scrollContainer = scrollRef.current;
- if (!scrollContainer) {
- return;
- }
-
- const handleScroll = () => {
- const { scrollTop, scrollHeight, clientHeight } = scrollContainer;
- const isNearBottom = scrollHeight - scrollTop - clientHeight < 50;
-
- if (!isNearBottom) {
- setUserScrolled(true);
- } else {
- setUserScrolled(false);
- }
- };
-
- scrollContainer.addEventListener('scroll', handleScroll);
-
- return () => {
- scrollContainer.removeEventListener('scroll', handleScroll);
- };
- }, []);
-
- useEffect(() => {
- const scrollContainer = scrollRef.current;
- if (!scrollContainer || !isSubmitting || userScrolled) {
- return;
- }
-
- scrollContainer.scrollTop = scrollContainer.scrollHeight;
- }, [content, isSubmitting, userScrolled]);
-
- return (
-
-
- {currentContent}
-
-
- );
- },
-);
-
export const CopyCodeButton: React.FC<{ content: string }> = ({ content }) => {
const localize = useLocalize();
const [isCopied, setIsCopied] = useState(false);
diff --git a/client/src/components/Artifacts/Mermaid.tsx b/client/src/components/Artifacts/Mermaid.tsx
index f7291998a4..5eb55be3ae 100644
--- a/client/src/components/Artifacts/Mermaid.tsx
+++ b/client/src/components/Artifacts/Mermaid.tsx
@@ -1,153 +1,123 @@
-import React, { useEffect, useRef, useState } from 'react';
+import React, { useEffect, useRef, useState, useCallback } from 'react';
import mermaid from 'mermaid';
import { Button } from '@librechat/client';
-import { TransformWrapper, TransformComponent, ReactZoomPanPinchRef } from 'react-zoom-pan-pinch';
-import { ZoomIn, ZoomOut, RefreshCw } from 'lucide-react';
+import { ZoomIn, ZoomOut, RotateCcw } from 'lucide-react';
+import { TransformWrapper, TransformComponent } from 'react-zoom-pan-pinch';
+import type { ReactZoomPanPinchRef } from 'react-zoom-pan-pinch';
+import { artifactFlowchartConfig } from '~/utils/mermaid';
interface MermaidDiagramProps {
content: string;
+ isDarkMode?: boolean;
}
-/** Note: this is just for testing purposes, don't actually use this component */
-const MermaidDiagram: React.FC = ({ content }) => {
+const MermaidDiagram: React.FC = ({ content, isDarkMode = true }) => {
const mermaidRef = useRef(null);
const transformRef = useRef(null);
const [isRendered, setIsRendered] = useState(false);
+ const theme = isDarkMode ? 'dark' : 'neutral';
+ const bgColor = isDarkMode ? '#212121' : '#FFFFFF';
useEffect(() => {
mermaid.initialize({
startOnLoad: false,
- theme: 'base',
+ theme,
securityLevel: 'sandbox',
- themeVariables: {
- background: '#282C34',
- primaryColor: '#333842',
- secondaryColor: '#333842',
- tertiaryColor: '#333842',
- primaryTextColor: '#ABB2BF',
- secondaryTextColor: '#ABB2BF',
- lineColor: '#636D83',
- fontSize: '16px',
- nodeBorder: '#636D83',
- mainBkg: '#282C34',
- altBackground: '#282C34',
- textColor: '#ABB2BF',
- edgeLabelBackground: '#282C34',
- clusterBkg: '#282C34',
- clusterBorder: '#636D83',
- labelBoxBkgColor: '#333842',
- labelBoxBorderColor: '#636D83',
- labelTextColor: '#ABB2BF',
- },
- flowchart: {
- curve: 'basis',
- nodeSpacing: 50,
- rankSpacing: 50,
- diagramPadding: 8,
- htmlLabels: true,
- useMaxWidth: true,
- padding: 15,
- wrappingWidth: 200,
- },
+ flowchart: artifactFlowchartConfig,
});
const renderDiagram = async () => {
- if (mermaidRef.current) {
- try {
- const { svg } = await mermaid.render('mermaid-diagram', content);
- mermaidRef.current.innerHTML = svg;
+ if (!mermaidRef.current) {
+ return;
+ }
- const svgElement = mermaidRef.current.querySelector('svg');
- if (svgElement) {
- svgElement.style.width = '100%';
- svgElement.style.height = '100%';
+ try {
+ const { svg } = await mermaid.render('mermaid-diagram', content);
+ mermaidRef.current.innerHTML = svg;
- const pathElements = svgElement.querySelectorAll('path');
- pathElements.forEach((path) => {
- path.style.strokeWidth = '1.5px';
- });
-
- const rectElements = svgElement.querySelectorAll('rect');
- rectElements.forEach((rect) => {
- const parent = rect.parentElement;
- if (parent && parent.classList.contains('node')) {
- rect.style.stroke = '#636D83';
- rect.style.strokeWidth = '1px';
- } else {
- rect.style.stroke = 'none';
- }
- });
- }
- setIsRendered(true);
- } catch (error) {
- console.error('Mermaid rendering error:', error);
+ const svgElement = mermaidRef.current.querySelector('svg');
+ if (svgElement) {
+ svgElement.style.width = '100%';
+ svgElement.style.height = '100%';
+ }
+ setIsRendered(true);
+ } catch (error) {
+ console.error('Mermaid rendering error:', error);
+ if (mermaidRef.current) {
mermaidRef.current.innerHTML = 'Error rendering diagram';
}
}
};
renderDiagram();
- }, [content]);
+ }, [content, theme]);
- const centerAndFitDiagram = () => {
+ const centerAndFitDiagram = useCallback(() => {
if (transformRef.current && mermaidRef.current) {
const { centerView, zoomToElement } = transformRef.current;
zoomToElement(mermaidRef.current as HTMLElement);
centerView(1, 0);
}
- };
+ }, []);
useEffect(() => {
if (isRendered) {
centerAndFitDiagram();
}
- }, [isRendered]);
+ }, [isRendered, centerAndFitDiagram]);
- const handlePanning = () => {
- if (transformRef.current) {
- const { state, instance } = (transformRef.current as ReactZoomPanPinchRef | undefined) ?? {};
- if (!state || !instance) {
- return;
- }
- const { scale, positionX, positionY } = state;
- const { wrapperComponent, contentComponent } = instance;
-
- if (wrapperComponent && contentComponent) {
- const wrapperRect = wrapperComponent.getBoundingClientRect();
- const contentRect = contentComponent.getBoundingClientRect();
- const maxX = wrapperRect.width - contentRect.width * scale;
- const maxY = wrapperRect.height - contentRect.height * scale;
-
- let newX = positionX;
- let newY = positionY;
-
- if (newX > 0) {
- newX = 0;
- }
- if (newY > 0) {
- newY = 0;
- }
- if (newX < maxX) {
- newX = maxX;
- }
- if (newY < maxY) {
- newY = maxY;
- }
-
- if (newX !== positionX || newY !== positionY) {
- instance.setTransformState(scale, newX, newY);
- }
- }
+ const handlePanning = useCallback(() => {
+ if (!transformRef.current) {
+ return;
}
- };
+
+ const { state, instance } = transformRef.current;
+ if (!state || !instance) {
+ return;
+ }
+ const { scale, positionX, positionY } = state;
+ const { wrapperComponent, contentComponent } = instance;
+
+ if (!wrapperComponent || !contentComponent) {
+ return;
+ }
+
+ const wrapperRect = wrapperComponent.getBoundingClientRect();
+ const contentRect = contentComponent.getBoundingClientRect();
+ const maxX = wrapperRect.width - contentRect.width * scale;
+ const maxY = wrapperRect.height - contentRect.height * scale;
+
+ let newX = positionX;
+ let newY = positionY;
+
+ if (newX > 0) {
+ newX = 0;
+ }
+ if (newY > 0) {
+ newY = 0;
+ }
+ if (newX < maxX) {
+ newX = maxX;
+ }
+ if (newY < maxY) {
+ newY = maxY;
+ }
+
+ if (newX !== positionX || newY !== positionY) {
+ instance.setTransformState(scale, newX, newY);
+ }
+ }, []);
return (
-
+
= ({ content }) => {
-
+
>
diff --git a/client/src/components/Auth/Login.tsx b/client/src/components/Auth/Login.tsx
index 48a506879f..7c3adf51bd 100644
--- a/client/src/components/Auth/Login.tsx
+++ b/client/src/components/Auth/Login.tsx
@@ -1,15 +1,19 @@
import { useEffect, useState } from 'react';
import { ErrorTypes, registerPage } from 'librechat-data-provider';
import { OpenIDIcon, useToastContext } from '@librechat/client';
-import { useOutletContext, useSearchParams } from 'react-router-dom';
+import { useOutletContext, useSearchParams, useLocation } from 'react-router-dom';
import type { TLoginLayoutContext } from '~/common';
+import { getLoginError, persistRedirectToSession } from '~/utils';
import { ErrorMessage } from '~/components/Auth/ErrorMessage';
import SocialButton from '~/components/Auth/SocialButton';
import { useAuthContext } from '~/hooks/AuthContext';
-import { getLoginError } from '~/utils';
import { useLocalize } from '~/hooks';
import LoginForm from './LoginForm';
+interface LoginLocationState {
+ redirect_to?: string;
+}
+
function Login() {
const localize = useLocalize();
const { showToast } = useToastContext();
@@ -17,13 +21,22 @@ function Login() {
const { startupConfig } = useOutletContext
();
const [searchParams, setSearchParams] = useSearchParams();
- // Determine if auto-redirect should be disabled based on the URL parameter
+ const location = useLocation();
const disableAutoRedirect = searchParams.get('redirect') === 'false';
- // Persist the disable flag locally so that once detected, auto-redirect stays disabled.
const [isAutoRedirectDisabled, setIsAutoRedirectDisabled] = useState(disableAutoRedirect);
useEffect(() => {
+ const redirectTo = searchParams.get('redirect_to');
+ if (redirectTo) {
+ persistRedirectToSession(redirectTo);
+ } else {
+ const state = location.state as LoginLocationState | null;
+ if (state?.redirect_to) {
+ persistRedirectToSession(state.redirect_to);
+ }
+ }
+
const oauthError = searchParams?.get('error');
if (oauthError && oauthError === ErrorTypes.AUTH_FAILED) {
showToast({
@@ -34,9 +47,8 @@ function Login() {
newParams.delete('error');
setSearchParams(newParams, { replace: true });
}
- }, [searchParams, setSearchParams, showToast, localize]);
+ }, [searchParams, setSearchParams, showToast, localize, location.state]);
- // Once the disable flag is detected, update local state and remove the parameter from the URL.
useEffect(() => {
if (disableAutoRedirect) {
setIsAutoRedirectDisabled(true);
@@ -46,7 +58,6 @@ function Login() {
}
}, [disableAutoRedirect, searchParams, setSearchParams]);
- // Determine whether we should auto-redirect to OpenID.
const shouldAutoRedirect =
startupConfig?.openidLoginEnabled &&
startupConfig?.openidAutoRedirect &&
@@ -60,7 +71,6 @@ function Login() {
}
}, [shouldAutoRedirect, startupConfig]);
- // Render fallback UI if auto-redirect is active.
if (shouldAutoRedirect) {
return (
diff --git a/client/src/components/Chat/AddMultiConvo.tsx b/client/src/components/Chat/AddMultiConvo.tsx
index 7cabe0f336..48e9919092 100644
--- a/client/src/components/Chat/AddMultiConvo.tsx
+++ b/client/src/components/Chat/AddMultiConvo.tsx
@@ -1,17 +1,21 @@
+import { useCallback } from 'react';
+import { useSetRecoilState, useRecoilValue } from 'recoil';
import { PlusCircle } from 'lucide-react';
import { TooltipAnchor } from '@librechat/client';
import { isAssistantsEndpoint } from 'librechat-data-provider';
import type { TConversation } from 'librechat-data-provider';
-import { useChatContext, useAddedChatContext } from '~/Providers';
+import { useGetConversation, useLocalize } from '~/hooks';
import { mainTextareaId } from '~/common';
-import { useLocalize } from '~/hooks';
+import store from '~/store';
function AddMultiConvo() {
- const { conversation } = useChatContext();
- const { setConversation: setAddedConvo } = useAddedChatContext();
const localize = useLocalize();
+ const getConversation = useGetConversation(0);
+ const endpoint = useRecoilValue(store.conversationEndpointByIndex(0));
+ const setAddedConvo = useSetRecoilState(store.conversationByIndex(1));
- const clickHandler = () => {
+ const clickHandler = useCallback(() => {
+ const conversation = getConversation();
const { title: _t, ...convo } = conversation ?? ({} as TConversation);
setAddedConvo({
...convo,
@@ -22,13 +26,13 @@ function AddMultiConvo() {
if (textarea) {
textarea.focus();
}
- };
+ }, [getConversation, setAddedConvo]);
- if (!conversation) {
+ if (!endpoint) {
return null;
}
- if (isAssistantsEndpoint(conversation.endpoint)) {
+ if (isAssistantsEndpoint(endpoint)) {
return null;
}
diff --git a/client/src/components/Chat/Footer.tsx b/client/src/components/Chat/Footer.tsx
index 75dd853c4f..541647a8d0 100644
--- a/client/src/components/Chat/Footer.tsx
+++ b/client/src/components/Chat/Footer.tsx
@@ -1,11 +1,11 @@
-import React, { useEffect } from 'react';
-import ReactMarkdown from 'react-markdown';
+import React, { useEffect, memo } from 'react';
import TagManager from 'react-gtm-module';
+import ReactMarkdown from 'react-markdown';
import { Constants } from 'librechat-data-provider';
import { useGetStartupConfig } from '~/data-provider';
import { useLocalize } from '~/hooks';
-export default function Footer({ className }: { className?: string }) {
+function Footer({ className }: { className?: string }) {
const { data: config } = useGetStartupConfig();
const localize = useLocalize();
@@ -98,3 +98,8 @@ export default function Footer({ className }: { className?: string }) {
);
}
+
+const MemoizedFooter = memo(Footer);
+MemoizedFooter.displayName = 'Footer';
+
+export default MemoizedFooter;
diff --git a/client/src/components/Chat/Header.tsx b/client/src/components/Chat/Header.tsx
index 40e2c6b7ad..9e44e804c9 100644
--- a/client/src/components/Chat/Header.tsx
+++ b/client/src/components/Chat/Header.tsx
@@ -1,4 +1,4 @@
-import { useMemo } from 'react';
+import { memo, useMemo } from 'react';
import { useMediaQuery } from '@librechat/client';
import { useOutletContext } from 'react-router-dom';
import { AnimatePresence, motion } from 'framer-motion';
@@ -16,7 +16,7 @@ import { cn } from '~/utils';
const defaultInterface = getConfigDefaults().interface;
-export default function Header() {
+function Header() {
const { data: startupConfig } = useGetStartupConfig();
const { navVisible, setNavVisible } = useOutletContext();
@@ -35,6 +35,11 @@ export default function Header() {
permission: Permissions.USE,
});
+ const hasAccessToTemporaryChat = useHasAccess({
+ permissionType: PermissionTypes.TEMPORARY_CHAT,
+ permission: Permissions.USE,
+ });
+
const isSmallScreen = useMediaQuery('(max-width: 768px)');
return (
@@ -73,7 +78,7 @@ export default function Header() {
-
+ {hasAccessToTemporaryChat === true && }
>
)}
@@ -85,7 +90,7 @@ export default function Header() {
-
+ {hasAccessToTemporaryChat === true && }
)}
@@ -94,3 +99,8 @@ export default function Header() {
);
}
+
+const MemoizedHeader = memo(Header);
+MemoizedHeader.displayName = 'Header';
+
+export default MemoizedHeader;
diff --git a/client/src/components/Chat/Input/BadgeRow.tsx b/client/src/components/Chat/Input/BadgeRow.tsx
index 5036dcd5e4..6fea6b0d58 100644
--- a/client/src/components/Chat/Input/BadgeRow.tsx
+++ b/client/src/components/Chat/Input/BadgeRow.tsx
@@ -28,6 +28,7 @@ interface BadgeRowProps {
onChange: (badges: Pick[]) => void;
onToggle?: (badgeId: string, currentActive: boolean) => void;
conversationId?: string | null;
+ specName?: string | null;
isSubmitting?: boolean;
isInChat: boolean;
}
@@ -142,6 +143,7 @@ const dragReducer = (state: DragState, action: DragAction): DragState => {
function BadgeRow({
showEphemeralBadges,
conversationId,
+ specName,
isSubmitting,
onChange,
onToggle,
@@ -320,7 +322,11 @@ function BadgeRow({
}, [dragState.draggedBadge, handleMouseMove, handleMouseUp]);
return (
-
+
{showEphemeralBadges === true &&
}
{tempBadges.map((badge, index) => (
diff --git a/client/src/components/Chat/Input/ChatForm.tsx b/client/src/components/Chat/Input/ChatForm.tsx
index c1ea69ee67..8a0f3ec02c 100644
--- a/client/src/components/Chat/Input/ChatForm.tsx
+++ b/client/src/components/Chat/Input/ChatForm.tsx
@@ -197,7 +197,7 @@ const ChatForm = memo(({ index = 0 }: { index?: number }) => {
const baseClasses = useMemo(
() =>
cn(
- 'md:py-3.5 m-0 w-full resize-none py-[13px] placeholder-black/50 bg-transparent dark:placeholder-white/50 [&:has(textarea:focus)]:shadow-[0_2px_6px_rgba(0,0,0,.05)]',
+ 'md:py-3.5 m-0 w-full resize-none py-[13px] placeholder-black/60 bg-transparent dark:placeholder-white/60 [&:has(textarea:focus)]:shadow-[0_2px_6px_rgba(0,0,0,.05)]',
isCollapsed ? 'max-h-[52px]' : 'max-h-[45vh] md:max-h-[55vh]',
isMoreThanThreeRows ? 'pl-5' : 'px-5',
),
@@ -222,7 +222,6 @@ const ChatForm = memo(({ index = 0 }: { index?: number }) => {
{showPlusPopover && !isAssistantsEndpoint(endpoint) && (
{
)}
{showMentionPopover && (
{
}
isSubmitting={isSubmitting}
conversationId={conversationId}
+ specName={conversation?.spec}
onChange={setBadges}
isInChat={
Array.isArray(conversation?.messages) && conversation.messages.length >= 1
diff --git a/client/src/components/Chat/Input/Files/AttachFileChat.tsx b/client/src/components/Chat/Input/Files/AttachFileChat.tsx
index 37b3584d3e..2f954d01d5 100644
--- a/client/src/components/Chat/Input/Files/AttachFileChat.tsx
+++ b/client/src/components/Chat/Input/Files/AttachFileChat.tsx
@@ -2,10 +2,9 @@ import { memo, useMemo } from 'react';
import {
Constants,
supportsFiles,
- EModelEndpoint,
mergeFileConfig,
isAgentsEndpoint,
- getEndpointField,
+ resolveEndpointType,
isAssistantsEndpoint,
getEndpointFileConfig,
} from 'librechat-data-provider';
@@ -55,21 +54,31 @@ function AttachFileChat({
const { data: endpointsConfig } = useGetEndpointsQuery();
- const endpointType = useMemo(() => {
- return (
- getEndpointField(endpointsConfig, endpoint, 'type') ||
- (endpoint as EModelEndpoint | undefined)
- );
- }, [endpoint, endpointsConfig]);
+ const agentProvider = useMemo(() => {
+ if (!isAgents || !conversation?.agent_id) {
+ return undefined;
+ }
+ const agent = agentData || agentsMap?.[conversation.agent_id];
+ return agent?.provider;
+ }, [isAgents, conversation?.agent_id, agentData, agentsMap]);
+ const endpointType = useMemo(
+ () => resolveEndpointType(endpointsConfig, endpoint, agentProvider),
+ [endpointsConfig, endpoint, agentProvider],
+ );
+
+ const fileConfigEndpoint = useMemo(
+ () => (isAgents && agentProvider ? agentProvider : endpoint),
+ [isAgents, agentProvider, endpoint],
+ );
const endpointFileConfig = useMemo(
() =>
getEndpointFileConfig({
- endpoint,
fileConfig,
endpointType,
+ endpoint: fileConfigEndpoint,
}),
- [endpoint, fileConfig, endpointType],
+ [fileConfigEndpoint, fileConfig, endpointType],
);
const endpointSupportsFiles: boolean = useMemo(
() => supportsFiles[endpointType ?? endpoint ?? ''] ?? false,
@@ -82,7 +91,7 @@ function AttachFileChat({
if (isAssistants && endpointSupportsFiles && !isUploadDisabled) {
return ;
- } else if (isAgents || (endpointSupportsFiles && !isUploadDisabled)) {
+ } else if ((isAgents || endpointSupportsFiles) && !isUploadDisabled) {
return (
= 'image_document';
if (currentProvider === Providers.GOOGLE || currentProvider === Providers.OPENROUTER) {
fileType = 'image_document_video_audio';
+ } else if (
+ currentProvider === Providers.BEDROCK ||
+ endpointType === EModelEndpoint.bedrock
+ ) {
+ fileType = 'image_document_extended';
}
onAction(fileType);
},
diff --git a/client/src/components/Chat/Input/Files/DragDropModal.tsx b/client/src/components/Chat/Input/Files/DragDropModal.tsx
index a59a7e3e9d..cb5109c866 100644
--- a/client/src/components/Chat/Input/Files/DragDropModal.tsx
+++ b/client/src/components/Chat/Input/Files/DragDropModal.tsx
@@ -1,14 +1,6 @@
import React, { useMemo } from 'react';
import { useRecoilValue } from 'recoil';
import { OGDialog, OGDialogTemplate } from '@librechat/client';
-import {
- Providers,
- inferMimeType,
- EToolResources,
- EModelEndpoint,
- defaultAgentCapabilities,
- isDocumentSupportedProvider,
-} from 'librechat-data-provider';
import {
ImageUpIcon,
FileSearch,
@@ -16,6 +8,15 @@ import {
FileImageIcon,
TerminalSquareIcon,
} from 'lucide-react';
+import {
+ Providers,
+ inferMimeType,
+ EToolResources,
+ EModelEndpoint,
+ isBedrockDocumentType,
+ defaultAgentCapabilities,
+ isDocumentSupportedProvider,
+} from 'librechat-data-provider';
import {
useAgentToolPermissions,
useAgentCapabilities,
@@ -77,20 +78,26 @@ const DragDropModal = ({ onOptionSelect, setShowModal, files, isVisible }: DragD
) {
const supportsImageDocVideoAudio =
currentProvider === EModelEndpoint.google || currentProvider === Providers.OPENROUTER;
- const validFileTypes = supportsImageDocVideoAudio
- ? files.every((file) => {
- const type = getFileType(file);
- return (
- type?.startsWith('image/') ||
- type?.startsWith('video/') ||
- type?.startsWith('audio/') ||
- type === 'application/pdf'
- );
- })
- : files.every((file) => {
- const type = getFileType(file);
- return type?.startsWith('image/') || type === 'application/pdf';
- });
+ const isBedrock =
+ currentProvider === Providers.BEDROCK || endpointType === EModelEndpoint.bedrock;
+
+ const isValidProviderFile = (file: File): boolean => {
+ const type = getFileType(file);
+ if (supportsImageDocVideoAudio) {
+ return (
+ type?.startsWith('image/') ||
+ type?.startsWith('video/') ||
+ type?.startsWith('audio/') ||
+ type === 'application/pdf'
+ );
+ }
+ if (isBedrock) {
+ return type?.startsWith('image/') || isBedrockDocumentType(type);
+ }
+ return type?.startsWith('image/') || type === 'application/pdf';
+ };
+
+ const validFileTypes = files.every(isValidProviderFile);
_options.push({
label: localize('com_ui_upload_provider'),
diff --git a/client/src/components/Chat/Input/Files/DragDropOverlay.tsx b/client/src/components/Chat/Input/Files/DragDropOverlay.tsx
index f5f45e2b88..43700206c3 100644
--- a/client/src/components/Chat/Input/Files/DragDropOverlay.tsx
+++ b/client/src/components/Chat/Input/Files/DragDropOverlay.tsx
@@ -36,7 +36,7 @@ const DragDropOverlay = memo(({ isActive }: DragDropOverlayProps) => {
}}
>
{/** Content area with subtle background */}
-
+
| undefined;
abortUpload?: () => void;
setFiles: React.Dispatch>>;
- setFilesLoading: React.Dispatch>;
+ setFilesLoading?: React.Dispatch>;
fileFilter?: (file: ExtendedFile) => boolean;
assistant_id?: string;
agent_id?: string;
@@ -58,6 +58,7 @@ export default function FileRow({
const { deleteFile } = useFileDeletion({ mutateAsync, agent_id, assistant_id, tool_resource });
useEffect(() => {
+ if (!setFilesLoading) return;
if (files.length === 0) {
setFilesLoading(false);
return;
@@ -111,13 +112,15 @@ export default function FileRow({
)
.uniqueFiles.map((file: ExtendedFile, index: number) => {
const handleDelete = () => {
- showToast({
- message: localize('com_ui_deleting_file'),
- status: 'info',
- });
if (abortUpload && file.progress < 1) {
abortUpload();
}
+ if (file.progress >= 1) {
+ showToast({
+ message: localize('com_ui_deleting_file'),
+ status: 'info',
+ });
+ }
deleteFile({ file, setFiles });
};
const isImage = file.type?.startsWith('image') ?? false;
@@ -133,7 +136,7 @@ export default function FileRow({
>
{isImage ? (
> = {};
+let mockAgentQueryData: Partial | undefined;
+
+jest.mock('~/data-provider', () => ({
+ useGetEndpointsQuery: () => ({ data: mockEndpointsConfig }),
+ useGetFileConfig: ({ select }: { select?: (data: unknown) => unknown }) => ({
+ data: select != null ? select(mockFileConfig) : mockFileConfig,
+ }),
+ useGetAgentByIdQuery: () => ({ data: mockAgentQueryData }),
+}));
+
+jest.mock('~/Providers', () => ({
+ useAgentsMapContext: () => mockAgentsMap,
+}));
+
+/** Capture the props passed to AttachFileMenu */
+let mockAttachFileMenuProps: Record = {};
+jest.mock('../AttachFileMenu', () => {
+ return function MockAttachFileMenu(props: Record) {
+ mockAttachFileMenuProps = props;
+ return
;
+ };
+});
+
+jest.mock('../AttachFile', () => {
+ return function MockAttachFile() {
+ return
;
+ };
+});
+
+const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
+
+function renderComponent(conversation: Record | null, disableInputs = false) {
+ return render(
+
+
+
+
+ ,
+ );
+}
+
+describe('AttachFileChat', () => {
+ beforeEach(() => {
+ mockFileConfig = defaultFileConfig;
+ mockAgentsMap = {};
+ mockAgentQueryData = undefined;
+ mockAttachFileMenuProps = {};
+ });
+
+ describe('rendering decisions', () => {
+ it('renders AttachFileMenu for agents endpoint', () => {
+ renderComponent({ endpoint: EModelEndpoint.agents, agent_id: 'agent-1' });
+ expect(screen.getByTestId('attach-file-menu')).toBeInTheDocument();
+ });
+
+ it('renders AttachFileMenu for custom endpoint with file support', () => {
+ renderComponent({ endpoint: 'Moonshot' });
+ expect(screen.getByTestId('attach-file-menu')).toBeInTheDocument();
+ });
+
+ it('renders null for null conversation', () => {
+ const { container } = renderComponent(null);
+ expect(container.innerHTML).toBe('');
+ });
+ });
+
+ describe('endpointType resolution for agents', () => {
+ it('passes custom endpointType when agent provider is a custom endpoint', () => {
+ mockAgentsMap = {
+ 'agent-1': { provider: 'Moonshot', model_parameters: {} } as Partial,
+ };
+ renderComponent({ endpoint: EModelEndpoint.agents, agent_id: 'agent-1' });
+ expect(mockAttachFileMenuProps.endpointType).toBe(EModelEndpoint.custom);
+ });
+
+ it('passes openAI endpointType when agent provider is openAI', () => {
+ mockAgentsMap = {
+ 'agent-1': { provider: EModelEndpoint.openAI, model_parameters: {} } as Partial,
+ };
+ renderComponent({ endpoint: EModelEndpoint.agents, agent_id: 'agent-1' });
+ expect(mockAttachFileMenuProps.endpointType).toBe(EModelEndpoint.openAI);
+ });
+
+ it('passes agents endpointType when no agent provider', () => {
+ renderComponent({ endpoint: EModelEndpoint.agents, agent_id: 'agent-1' });
+ expect(mockAttachFileMenuProps.endpointType).toBe(EModelEndpoint.agents);
+ });
+
+ it('passes agents endpointType when no agent_id', () => {
+ renderComponent({ endpoint: EModelEndpoint.agents });
+ expect(mockAttachFileMenuProps.endpointType).toBe(EModelEndpoint.agents);
+ });
+
+ it('uses agentData query when agent not in agentsMap', () => {
+ mockAgentQueryData = { provider: 'Moonshot' } as Partial;
+ renderComponent({ endpoint: EModelEndpoint.agents, agent_id: 'agent-2' });
+ expect(mockAttachFileMenuProps.endpointType).toBe(EModelEndpoint.custom);
+ });
+ });
+
+ describe('endpointType resolution for non-agents', () => {
+ it('passes custom endpointType for a custom endpoint', () => {
+ renderComponent({ endpoint: 'Moonshot' });
+ expect(mockAttachFileMenuProps.endpointType).toBe(EModelEndpoint.custom);
+ });
+
+ it('passes openAI endpointType for openAI endpoint', () => {
+ renderComponent({ endpoint: EModelEndpoint.openAI });
+ expect(mockAttachFileMenuProps.endpointType).toBe(EModelEndpoint.openAI);
+ });
+ });
+
+ describe('consistency: same endpoint type for direct vs agent usage', () => {
+ it('resolves Moonshot the same way whether used directly or through an agent', () => {
+ renderComponent({ endpoint: 'Moonshot' });
+ const directType = mockAttachFileMenuProps.endpointType;
+
+ mockAgentsMap = {
+ 'agent-1': { provider: 'Moonshot', model_parameters: {} } as Partial,
+ };
+ renderComponent({ endpoint: EModelEndpoint.agents, agent_id: 'agent-1' });
+ const agentType = mockAttachFileMenuProps.endpointType;
+
+ expect(directType).toBe(agentType);
+ });
+ });
+
+ describe('upload disabled rendering', () => {
+ it('renders null for agents endpoint when fileConfig.agents.disabled is true', () => {
+ mockFileConfig = mergeFileConfig({
+ endpoints: {
+ [EModelEndpoint.agents]: { disabled: true },
+ },
+ });
+ const { container } = renderComponent({
+ endpoint: EModelEndpoint.agents,
+ agent_id: 'agent-1',
+ });
+ expect(container.innerHTML).toBe('');
+ });
+
+ it('renders null for agents endpoint when disableInputs is true', () => {
+ const { container } = renderComponent(
+ { endpoint: EModelEndpoint.agents, agent_id: 'agent-1' },
+ true,
+ );
+ expect(container.innerHTML).toBe('');
+ });
+
+ it('renders AttachFile for assistants endpoint when not disabled', () => {
+ renderComponent({ endpoint: EModelEndpoint.assistants });
+ expect(screen.getByTestId('attach-file')).toBeInTheDocument();
+ });
+
+ it('renders AttachFileMenu when provider-specific config overrides agents disabled', () => {
+ mockFileConfig = mergeFileConfig({
+ endpoints: {
+ Moonshot: { disabled: false, fileLimit: 5 },
+ [EModelEndpoint.agents]: { disabled: true },
+ },
+ });
+ mockAgentsMap = {
+ 'agent-1': { provider: 'Moonshot', model_parameters: {} } as Partial,
+ };
+ renderComponent({ endpoint: EModelEndpoint.agents, agent_id: 'agent-1' });
+ expect(screen.getByTestId('attach-file-menu')).toBeInTheDocument();
+ });
+
+ it('renders null for assistants endpoint when fileConfig.assistants.disabled is true', () => {
+ mockFileConfig = mergeFileConfig({
+ endpoints: {
+ [EModelEndpoint.assistants]: { disabled: true },
+ },
+ });
+ const { container } = renderComponent({
+ endpoint: EModelEndpoint.assistants,
+ });
+ expect(container.innerHTML).toBe('');
+ });
+ });
+
+ describe('endpointFileConfig resolution', () => {
+ it('passes Moonshot-specific file config for agent with Moonshot provider', () => {
+ mockAgentsMap = {
+ 'agent-1': { provider: 'Moonshot', model_parameters: {} } as Partial,
+ };
+ renderComponent({ endpoint: EModelEndpoint.agents, agent_id: 'agent-1' });
+ const config = mockAttachFileMenuProps.endpointFileConfig as { fileLimit?: number };
+ expect(config?.fileLimit).toBe(5);
+ });
+
+ it('passes agents file config when agent has no specific provider config', () => {
+ mockAgentsMap = {
+ 'agent-1': { provider: EModelEndpoint.openAI, model_parameters: {} } as Partial,
+ };
+ renderComponent({ endpoint: EModelEndpoint.agents, agent_id: 'agent-1' });
+ const config = mockAttachFileMenuProps.endpointFileConfig as { fileLimit?: number };
+ expect(config?.fileLimit).toBe(10);
+ });
+
+ it('passes agents file config when no agent provider', () => {
+ renderComponent({ endpoint: EModelEndpoint.agents });
+ const config = mockAttachFileMenuProps.endpointFileConfig as { fileLimit?: number };
+ expect(config?.fileLimit).toBe(20);
+ });
+ });
+});
diff --git a/client/src/components/Chat/Input/Files/__tests__/AttachFileMenu.spec.tsx b/client/src/components/Chat/Input/Files/__tests__/AttachFileMenu.spec.tsx
index d3f0fb65bc..cf08721207 100644
--- a/client/src/components/Chat/Input/Files/__tests__/AttachFileMenu.spec.tsx
+++ b/client/src/components/Chat/Input/Files/__tests__/AttachFileMenu.spec.tsx
@@ -1,12 +1,10 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
-import '@testing-library/jest-dom';
import { RecoilRoot } from 'recoil';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
-import { EModelEndpoint } from 'librechat-data-provider';
+import { EModelEndpoint, Providers } from 'librechat-data-provider';
import AttachFileMenu from '../AttachFileMenu';
-// Mock all the hooks
jest.mock('~/hooks', () => ({
useAgentToolPermissions: jest.fn(),
useAgentCapabilities: jest.fn(),
@@ -25,53 +23,45 @@ jest.mock('~/data-provider', () => ({
}));
jest.mock('~/components/SharePoint', () => ({
- SharePointPickerDialog: jest.fn(() => null),
+ SharePointPickerDialog: () => null,
}));
jest.mock('@librechat/client', () => {
- const React = jest.requireActual('react');
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
+ const R = require('react');
return {
- FileUpload: React.forwardRef(({ children, handleFileChange }: any, ref: any) => (
-
-
- {children}
-
- )),
- TooltipAnchor: ({ render }: any) => render,
- DropdownPopup: ({ trigger, items, isOpen, setIsOpen }: any) => {
- const handleTriggerClick = () => {
- if (setIsOpen) {
- setIsOpen(!isOpen);
- }
- };
-
- return (
-
-
{trigger}
- {isOpen && (
-
- {items.map((item: any, idx: number) => (
-
- {item.label}
-
- ))}
-
- )}
-
- );
- },
- AttachmentIcon: () => 📎 ,
- SharePointIcon: () => SP ,
+ FileUpload: (props) => R.createElement('div', { 'data-testid': 'file-upload' }, props.children),
+ TooltipAnchor: (props) => props.render,
+ DropdownPopup: (props) =>
+ R.createElement(
+ 'div',
+ null,
+ R.createElement('div', { onClick: () => props.setIsOpen(!props.isOpen) }, props.trigger),
+ props.isOpen &&
+ R.createElement(
+ 'div',
+ { 'data-testid': 'dropdown-menu' },
+ props.items.map((item, idx) =>
+ R.createElement(
+ 'button',
+ { key: idx, onClick: item.onClick, 'data-testid': `menu-item-${idx}` },
+ item.label,
+ ),
+ ),
+ ),
+ ),
+ AttachmentIcon: () => R.createElement('span', { 'data-testid': 'attachment-icon' }),
+ SharePointIcon: () => R.createElement('span', { 'data-testid': 'sharepoint-icon' }),
};
});
-jest.mock('@ariakit/react', () => ({
- MenuButton: ({ children, onClick, disabled, ...props }: any) => (
-
- {children}
-
- ),
-}));
+jest.mock('@ariakit/react', () => {
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
+ const R = require('react');
+ return {
+ MenuButton: (props) => R.createElement('button', props, props.children),
+ };
+});
const mockUseAgentToolPermissions = jest.requireMock('~/hooks').useAgentToolPermissions;
const mockUseAgentCapabilities = jest.requireMock('~/hooks').useAgentCapabilities;
@@ -83,558 +73,283 @@ const mockUseSharePointFileHandling = jest.requireMock(
).default;
const mockUseGetStartupConfig = jest.requireMock('~/data-provider').useGetStartupConfig;
-describe('AttachFileMenu', () => {
- const queryClient = new QueryClient({
- defaultOptions: {
- queries: { retry: false },
- },
- });
+const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
- const mockHandleFileChange = jest.fn();
-
- beforeEach(() => {
- jest.clearAllMocks();
-
- // Default mock implementations
- mockUseLocalize.mockReturnValue((key: string) => {
- const translations: Record = {
- com_ui_upload_provider: 'Upload to Provider',
- com_ui_upload_image_input: 'Upload Image',
- com_ui_upload_ocr_text: 'Upload OCR Text',
- com_ui_upload_file_search: 'Upload for File Search',
- com_ui_upload_code_files: 'Upload Code Files',
- com_sidepanel_attach_files: 'Attach Files',
- com_files_upload_sharepoint: 'Upload from SharePoint',
- };
- return translations[key] || key;
- });
-
- mockUseAgentCapabilities.mockReturnValue({
- contextEnabled: false,
- fileSearchEnabled: false,
- codeEnabled: false,
- });
-
- mockUseGetAgentsConfig.mockReturnValue({
- agentsConfig: {
- capabilities: {
- contextEnabled: false,
- fileSearchEnabled: false,
- codeEnabled: false,
- },
- },
- });
-
- mockUseFileHandling.mockReturnValue({
- handleFileChange: mockHandleFileChange,
- });
-
- mockUseSharePointFileHandling.mockReturnValue({
- handleSharePointFiles: jest.fn(),
- isProcessing: false,
- downloadProgress: 0,
- });
-
- mockUseGetStartupConfig.mockReturnValue({
- data: {
- sharePointFilePickerEnabled: false,
- },
- });
-
- mockUseAgentToolPermissions.mockReturnValue({
- fileSearchAllowedByAgent: false,
- codeAllowedByAgent: false,
- provider: undefined,
- });
- });
-
- const renderAttachFileMenu = (props: any = {}) => {
- return render(
-
-
-
-
- ,
- );
+function setupMocks(overrides: { provider?: string } = {}) {
+ const translations: Record = {
+ com_ui_upload_provider: 'Upload to Provider',
+ com_ui_upload_image_input: 'Upload Image',
+ com_ui_upload_ocr_text: 'Upload as Text',
+ com_ui_upload_file_search: 'Upload for File Search',
+ com_ui_upload_code_files: 'Upload Code Files',
+ com_sidepanel_attach_files: 'Attach Files',
+ com_files_upload_sharepoint: 'Upload from SharePoint',
};
-
- describe('Basic Rendering', () => {
- it('should render the attachment button', () => {
- renderAttachFileMenu();
- const button = screen.getByRole('button', { name: /attach file options/i });
- expect(button).toBeInTheDocument();
- });
-
- it('should be disabled when disabled prop is true', () => {
- renderAttachFileMenu({ disabled: true });
- const button = screen.getByRole('button', { name: /attach file options/i });
- expect(button).toBeDisabled();
- });
-
- it('should not be disabled when disabled prop is false', () => {
- renderAttachFileMenu({ disabled: false });
- const button = screen.getByRole('button', { name: /attach file options/i });
- expect(button).not.toBeDisabled();
- });
+ mockUseLocalize.mockReturnValue((key: string) => translations[key] || key);
+ mockUseAgentCapabilities.mockReturnValue({
+ contextEnabled: false,
+ fileSearchEnabled: false,
+ codeEnabled: false,
});
+ mockUseGetAgentsConfig.mockReturnValue({ agentsConfig: {} });
+ mockUseFileHandling.mockReturnValue({ handleFileChange: jest.fn() });
+ mockUseSharePointFileHandling.mockReturnValue({
+ handleSharePointFiles: jest.fn(),
+ isProcessing: false,
+ downloadProgress: 0,
+ });
+ mockUseGetStartupConfig.mockReturnValue({ data: { sharePointFilePickerEnabled: false } });
+ mockUseAgentToolPermissions.mockReturnValue({
+ fileSearchAllowedByAgent: false,
+ codeAllowedByAgent: false,
+ provider: overrides.provider ?? undefined,
+ });
+}
- describe('Provider Detection Fix - endpointType Priority', () => {
- it('should prioritize endpointType over currentProvider for LiteLLM gateway', () => {
- mockUseAgentToolPermissions.mockReturnValue({
- fileSearchAllowedByAgent: false,
- codeAllowedByAgent: false,
- provider: 'litellm', // Custom gateway name NOT in documentSupportedProviders
- });
+function renderMenu(props: Record = {}) {
+ return render(
+
+
+
+
+ ,
+ );
+}
- renderAttachFileMenu({
- endpoint: 'litellm',
- endpointType: EModelEndpoint.openAI, // Backend override IS in documentSupportedProviders
- });
+function openMenu() {
+ fireEvent.click(screen.getByRole('button', { name: /attach file options/i }));
+}
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
+describe('AttachFileMenu', () => {
+ beforeEach(jest.clearAllMocks);
- // With the fix, should show "Upload to Provider" because endpointType is checked first
+ describe('Upload to Provider vs Upload Image', () => {
+ it('shows "Upload to Provider" when endpointType is custom (resolved from agent provider)', () => {
+ setupMocks({ provider: 'Moonshot' });
+ renderMenu({ endpointType: EModelEndpoint.custom });
+ openMenu();
expect(screen.getByText('Upload to Provider')).toBeInTheDocument();
expect(screen.queryByText('Upload Image')).not.toBeInTheDocument();
});
- it('should show Upload to Provider for custom endpoints with OpenAI endpointType', () => {
- mockUseAgentToolPermissions.mockReturnValue({
- fileSearchAllowedByAgent: false,
- codeAllowedByAgent: false,
- provider: 'my-custom-gateway',
- });
-
- renderAttachFileMenu({
- endpoint: 'my-custom-gateway',
- endpointType: EModelEndpoint.openAI,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
-
+ it('shows "Upload to Provider" when endpointType is openAI', () => {
+ setupMocks({ provider: EModelEndpoint.openAI });
+ renderMenu({ endpointType: EModelEndpoint.openAI });
+ openMenu();
expect(screen.getByText('Upload to Provider')).toBeInTheDocument();
});
- it('should show Upload Image when neither endpointType nor provider support documents', () => {
- mockUseAgentToolPermissions.mockReturnValue({
- fileSearchAllowedByAgent: false,
- codeAllowedByAgent: false,
- provider: 'unsupported-provider',
- });
+ it('shows "Upload to Provider" when endpointType is anthropic', () => {
+ setupMocks({ provider: EModelEndpoint.anthropic });
+ renderMenu({ endpointType: EModelEndpoint.anthropic });
+ openMenu();
+ expect(screen.getByText('Upload to Provider')).toBeInTheDocument();
+ });
- renderAttachFileMenu({
- endpoint: 'unsupported-provider',
- endpointType: 'unsupported-endpoint' as any,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
+ it('shows "Upload to Provider" when endpointType is google', () => {
+ setupMocks({ provider: Providers.GOOGLE });
+ renderMenu({ endpointType: EModelEndpoint.google });
+ openMenu();
+ expect(screen.getByText('Upload to Provider')).toBeInTheDocument();
+ });
+ it('shows "Upload Image" when endpointType is agents (no provider resolution)', () => {
+ setupMocks();
+ renderMenu({ endpointType: EModelEndpoint.agents });
+ openMenu();
expect(screen.getByText('Upload Image')).toBeInTheDocument();
expect(screen.queryByText('Upload to Provider')).not.toBeInTheDocument();
});
- it('should fallback to currentProvider when endpointType is undefined', () => {
- mockUseAgentToolPermissions.mockReturnValue({
- fileSearchAllowedByAgent: false,
- codeAllowedByAgent: false,
- provider: EModelEndpoint.openAI,
- });
-
- renderAttachFileMenu({
- endpoint: EModelEndpoint.openAI,
- endpointType: undefined,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
+ it('shows "Upload Image" when neither endpointType nor provider supports documents', () => {
+ setupMocks({ provider: 'unknown-provider' });
+ renderMenu({ endpointType: 'unknown-type' });
+ openMenu();
+ expect(screen.getByText('Upload Image')).toBeInTheDocument();
+ });
+ it('shows "Upload to Provider" for azureOpenAI with useResponsesApi', () => {
+ setupMocks({ provider: EModelEndpoint.azureOpenAI });
+ renderMenu({ endpointType: EModelEndpoint.azureOpenAI, useResponsesApi: true });
+ openMenu();
expect(screen.getByText('Upload to Provider')).toBeInTheDocument();
});
- it('should fallback to currentProvider when endpointType is null', () => {
- mockUseAgentToolPermissions.mockReturnValue({
- fileSearchAllowedByAgent: false,
- codeAllowedByAgent: false,
- provider: EModelEndpoint.anthropic,
- });
-
- renderAttachFileMenu({
- endpoint: EModelEndpoint.anthropic,
- endpointType: null,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
-
- expect(screen.getByText('Upload to Provider')).toBeInTheDocument();
+ it('shows "Upload Image" for azureOpenAI without useResponsesApi', () => {
+ setupMocks({ provider: EModelEndpoint.azureOpenAI });
+ renderMenu({ endpointType: EModelEndpoint.azureOpenAI, useResponsesApi: false });
+ openMenu();
+ expect(screen.getByText('Upload Image')).toBeInTheDocument();
});
});
- describe('Supported Providers', () => {
- const supportedProviders = [
- { name: 'OpenAI', endpoint: EModelEndpoint.openAI },
- { name: 'Anthropic', endpoint: EModelEndpoint.anthropic },
- { name: 'Google', endpoint: EModelEndpoint.google },
- { name: 'Custom', endpoint: EModelEndpoint.custom },
- ];
-
- supportedProviders.forEach(({ name, endpoint }) => {
- it(`should show Upload to Provider for ${name}`, () => {
- mockUseAgentToolPermissions.mockReturnValue({
- fileSearchAllowedByAgent: false,
- codeAllowedByAgent: false,
- provider: endpoint,
- });
-
- renderAttachFileMenu({
- endpoint,
- endpointType: endpoint,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
-
- expect(screen.getByText('Upload to Provider')).toBeInTheDocument();
+ describe('agent provider resolution scenario', () => {
+ it('shows "Upload to Provider" when agents endpoint has custom endpointType from provider', () => {
+ setupMocks({ provider: 'Moonshot' });
+ renderMenu({
+ endpoint: EModelEndpoint.agents,
+ endpointType: EModelEndpoint.custom,
});
- });
-
- it('should show Upload to Provider for Azure OpenAI with useResponsesApi', () => {
- mockUseAgentToolPermissions.mockReturnValue({
- fileSearchAllowedByAgent: false,
- codeAllowedByAgent: false,
- provider: EModelEndpoint.azureOpenAI,
- });
-
- renderAttachFileMenu({
- endpoint: EModelEndpoint.azureOpenAI,
- endpointType: EModelEndpoint.azureOpenAI,
- useResponsesApi: true,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
-
+ openMenu();
expect(screen.getByText('Upload to Provider')).toBeInTheDocument();
});
- it('should NOT show Upload to Provider for Azure OpenAI without useResponsesApi', () => {
- mockUseAgentToolPermissions.mockReturnValue({
- fileSearchAllowedByAgent: false,
- codeAllowedByAgent: false,
- provider: EModelEndpoint.azureOpenAI,
+ it('shows "Upload Image" when agents endpoint has no resolved provider type', () => {
+ setupMocks();
+ renderMenu({
+ endpoint: EModelEndpoint.agents,
+ endpointType: EModelEndpoint.agents,
});
-
- renderAttachFileMenu({
- endpoint: EModelEndpoint.azureOpenAI,
- endpointType: EModelEndpoint.azureOpenAI,
- useResponsesApi: false,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
-
- expect(screen.queryByText('Upload to Provider')).not.toBeInTheDocument();
+ openMenu();
expect(screen.getByText('Upload Image')).toBeInTheDocument();
});
});
+ describe('Basic Rendering', () => {
+ it('renders the attachment button', () => {
+ setupMocks();
+ renderMenu();
+ expect(screen.getByRole('button', { name: /attach file options/i })).toBeInTheDocument();
+ });
+
+ it('is disabled when disabled prop is true', () => {
+ setupMocks();
+ renderMenu({ disabled: true });
+ expect(screen.getByRole('button', { name: /attach file options/i })).toBeDisabled();
+ });
+
+ it('is not disabled when disabled prop is false', () => {
+ setupMocks();
+ renderMenu({ disabled: false });
+ expect(screen.getByRole('button', { name: /attach file options/i })).not.toBeDisabled();
+ });
+ });
+
describe('Agent Capabilities', () => {
- it('should show OCR Text option when context is enabled', () => {
+ it('shows OCR Text option when context is enabled', () => {
+ setupMocks();
mockUseAgentCapabilities.mockReturnValue({
contextEnabled: true,
fileSearchEnabled: false,
codeEnabled: false,
});
-
- renderAttachFileMenu({
- endpointType: EModelEndpoint.openAI,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
-
- expect(screen.getByText('Upload OCR Text')).toBeInTheDocument();
+ renderMenu({ endpointType: EModelEndpoint.openAI });
+ openMenu();
+ expect(screen.getByText('Upload as Text')).toBeInTheDocument();
});
- it('should show File Search option when enabled and allowed by agent', () => {
+ it('shows File Search option when enabled and allowed by agent', () => {
+ setupMocks();
mockUseAgentCapabilities.mockReturnValue({
contextEnabled: false,
fileSearchEnabled: true,
codeEnabled: false,
});
-
mockUseAgentToolPermissions.mockReturnValue({
fileSearchAllowedByAgent: true,
codeAllowedByAgent: false,
provider: undefined,
});
-
- renderAttachFileMenu({
- endpointType: EModelEndpoint.openAI,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
-
+ renderMenu({ endpointType: EModelEndpoint.openAI });
+ openMenu();
expect(screen.getByText('Upload for File Search')).toBeInTheDocument();
});
- it('should NOT show File Search when enabled but not allowed by agent', () => {
+ it('does NOT show File Search when enabled but not allowed by agent', () => {
+ setupMocks();
mockUseAgentCapabilities.mockReturnValue({
contextEnabled: false,
fileSearchEnabled: true,
codeEnabled: false,
});
-
- mockUseAgentToolPermissions.mockReturnValue({
- fileSearchAllowedByAgent: false,
- codeAllowedByAgent: false,
- provider: undefined,
- });
-
- renderAttachFileMenu({
- endpointType: EModelEndpoint.openAI,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
-
+ renderMenu({ endpointType: EModelEndpoint.openAI });
+ openMenu();
expect(screen.queryByText('Upload for File Search')).not.toBeInTheDocument();
});
- it('should show Code Files option when enabled and allowed by agent', () => {
+ it('shows Code Files option when enabled and allowed by agent', () => {
+ setupMocks();
mockUseAgentCapabilities.mockReturnValue({
contextEnabled: false,
fileSearchEnabled: false,
codeEnabled: true,
});
-
mockUseAgentToolPermissions.mockReturnValue({
fileSearchAllowedByAgent: false,
codeAllowedByAgent: true,
provider: undefined,
});
-
- renderAttachFileMenu({
- endpointType: EModelEndpoint.openAI,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
-
+ renderMenu({ endpointType: EModelEndpoint.openAI });
+ openMenu();
expect(screen.getByText('Upload Code Files')).toBeInTheDocument();
});
- it('should show all options when all capabilities are enabled', () => {
+ it('shows all options when all capabilities are enabled', () => {
+ setupMocks();
mockUseAgentCapabilities.mockReturnValue({
contextEnabled: true,
fileSearchEnabled: true,
codeEnabled: true,
});
-
mockUseAgentToolPermissions.mockReturnValue({
fileSearchAllowedByAgent: true,
codeAllowedByAgent: true,
provider: undefined,
});
-
- renderAttachFileMenu({
- endpointType: EModelEndpoint.openAI,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
-
+ renderMenu({ endpointType: EModelEndpoint.openAI });
+ openMenu();
expect(screen.getByText('Upload to Provider')).toBeInTheDocument();
- expect(screen.getByText('Upload OCR Text')).toBeInTheDocument();
+ expect(screen.getByText('Upload as Text')).toBeInTheDocument();
expect(screen.getByText('Upload for File Search')).toBeInTheDocument();
expect(screen.getByText('Upload Code Files')).toBeInTheDocument();
});
});
describe('SharePoint Integration', () => {
- it('should show SharePoint option when enabled', () => {
+ it('shows SharePoint option when enabled', () => {
+ setupMocks();
mockUseGetStartupConfig.mockReturnValue({
- data: {
- sharePointFilePickerEnabled: true,
- },
+ data: { sharePointFilePickerEnabled: true },
});
-
- renderAttachFileMenu({
- endpointType: EModelEndpoint.openAI,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
-
+ renderMenu({ endpointType: EModelEndpoint.openAI });
+ openMenu();
expect(screen.getByText('Upload from SharePoint')).toBeInTheDocument();
});
- it('should NOT show SharePoint option when disabled', () => {
- mockUseGetStartupConfig.mockReturnValue({
- data: {
- sharePointFilePickerEnabled: false,
- },
- });
-
- renderAttachFileMenu({
- endpointType: EModelEndpoint.openAI,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
-
+ it('does NOT show SharePoint option when disabled', () => {
+ setupMocks();
+ renderMenu({ endpointType: EModelEndpoint.openAI });
+ openMenu();
expect(screen.queryByText('Upload from SharePoint')).not.toBeInTheDocument();
});
});
describe('Edge Cases', () => {
- it('should handle undefined endpoint and provider gracefully', () => {
- mockUseAgentToolPermissions.mockReturnValue({
- fileSearchAllowedByAgent: false,
- codeAllowedByAgent: false,
- provider: undefined,
- });
-
- renderAttachFileMenu({
- endpoint: undefined,
- endpointType: undefined,
- });
-
+ it('handles undefined endpoint and provider gracefully', () => {
+ setupMocks();
+ renderMenu({ endpoint: undefined, endpointType: undefined });
const button = screen.getByRole('button', { name: /attach file options/i });
expect(button).toBeInTheDocument();
fireEvent.click(button);
-
- // Should show Upload Image as fallback
expect(screen.getByText('Upload Image')).toBeInTheDocument();
});
- it('should handle null endpoint and provider gracefully', () => {
- mockUseAgentToolPermissions.mockReturnValue({
- fileSearchAllowedByAgent: false,
- codeAllowedByAgent: false,
- provider: null,
- });
-
- renderAttachFileMenu({
- endpoint: null,
- endpointType: null,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- expect(button).toBeInTheDocument();
+ it('handles null endpoint and provider gracefully', () => {
+ setupMocks();
+ renderMenu({ endpoint: null, endpointType: null });
+ expect(screen.getByRole('button', { name: /attach file options/i })).toBeInTheDocument();
});
- it('should handle missing agentId gracefully', () => {
- renderAttachFileMenu({
- agentId: undefined,
- endpointType: EModelEndpoint.openAI,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- expect(button).toBeInTheDocument();
+ it('handles missing agentId gracefully', () => {
+ setupMocks();
+ renderMenu({ agentId: undefined, endpointType: EModelEndpoint.openAI });
+ expect(screen.getByRole('button', { name: /attach file options/i })).toBeInTheDocument();
});
- it('should handle empty string agentId', () => {
- renderAttachFileMenu({
- agentId: '',
- endpointType: EModelEndpoint.openAI,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- expect(button).toBeInTheDocument();
- });
- });
-
- describe('Google Provider Special Case', () => {
- it('should use image_document_video_audio file type for Google provider', () => {
- mockUseAgentToolPermissions.mockReturnValue({
- fileSearchAllowedByAgent: false,
- codeAllowedByAgent: false,
- provider: EModelEndpoint.google,
- });
-
- renderAttachFileMenu({
- endpoint: EModelEndpoint.google,
- endpointType: EModelEndpoint.google,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
-
- const uploadProviderButton = screen.getByText('Upload to Provider');
- expect(uploadProviderButton).toBeInTheDocument();
-
- // Click the upload to provider option
- fireEvent.click(uploadProviderButton);
-
- // The file input should have been clicked (indirectly tested through the implementation)
- });
-
- it('should use image_document file type for non-Google providers', () => {
- mockUseAgentToolPermissions.mockReturnValue({
- fileSearchAllowedByAgent: false,
- codeAllowedByAgent: false,
- provider: EModelEndpoint.openAI,
- });
-
- renderAttachFileMenu({
- endpoint: EModelEndpoint.openAI,
- endpointType: EModelEndpoint.openAI,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
-
- const uploadProviderButton = screen.getByText('Upload to Provider');
- expect(uploadProviderButton).toBeInTheDocument();
- fireEvent.click(uploadProviderButton);
-
- // Implementation detail - image_document type is used
- });
- });
-
- describe('Regression Tests', () => {
- it('should not break the previous behavior for direct provider attachments', () => {
- // When using a direct supported provider (not through a gateway)
- mockUseAgentToolPermissions.mockReturnValue({
- fileSearchAllowedByAgent: false,
- codeAllowedByAgent: false,
- provider: EModelEndpoint.anthropic,
- });
-
- renderAttachFileMenu({
- endpoint: EModelEndpoint.anthropic,
- endpointType: EModelEndpoint.anthropic,
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
-
- expect(screen.getByText('Upload to Provider')).toBeInTheDocument();
- });
-
- it('should maintain correct priority when both are supported', () => {
- // Both endpointType and provider are supported, endpointType should be checked first
- mockUseAgentToolPermissions.mockReturnValue({
- fileSearchAllowedByAgent: false,
- codeAllowedByAgent: false,
- provider: EModelEndpoint.google,
- });
-
- renderAttachFileMenu({
- endpoint: EModelEndpoint.google,
- endpointType: EModelEndpoint.openAI, // Different but both supported
- });
-
- const button = screen.getByRole('button', { name: /attach file options/i });
- fireEvent.click(button);
-
- // Should still work because endpointType (openAI) is supported
- expect(screen.getByText('Upload to Provider')).toBeInTheDocument();
+ it('handles empty string agentId', () => {
+ setupMocks();
+ renderMenu({ agentId: '', endpointType: EModelEndpoint.openAI });
+ expect(screen.getByRole('button', { name: /attach file options/i })).toBeInTheDocument();
});
});
});
diff --git a/client/src/components/Chat/Input/Files/__tests__/FileRow.spec.tsx b/client/src/components/Chat/Input/Files/__tests__/FileRow.spec.tsx
index 90c1c3a7b5..ccfa19ffc8 100644
--- a/client/src/components/Chat/Input/Files/__tests__/FileRow.spec.tsx
+++ b/client/src/components/Chat/Input/Files/__tests__/FileRow.spec.tsx
@@ -21,6 +21,7 @@ jest.mock('~/utils', () => ({
logger: {
log: jest.fn(),
},
+ getCachedPreview: jest.fn(() => undefined),
}));
jest.mock('../Image', () => {
@@ -95,7 +96,7 @@ describe('FileRow', () => {
};
describe('Image URL Selection Logic', () => {
- it('should use filepath instead of preview when progress is 1 (upload complete)', () => {
+ it('should prefer cached preview over filepath when upload is complete', () => {
const file = createMockFile({
file_id: 'uploaded-file',
preview: 'blob:http://localhost:3080/temp-preview',
@@ -109,8 +110,7 @@ describe('FileRow', () => {
renderFileRow(filesMap);
const imageUrl = screen.getByTestId('image-url').textContent;
- expect(imageUrl).toBe('/images/user123/uploaded-file__image.png');
- expect(imageUrl).not.toContain('blob:');
+ expect(imageUrl).toBe('blob:http://localhost:3080/temp-preview');
});
it('should use preview when progress is less than 1 (uploading)', () => {
@@ -147,7 +147,7 @@ describe('FileRow', () => {
expect(imageUrl).toBe('/images/user123/file-without-preview__image.png');
});
- it('should use filepath when both preview and filepath exist and progress is exactly 1', () => {
+ it('should prefer preview over filepath when both exist and progress is 1', () => {
const file = createMockFile({
file_id: 'complete-file',
preview: 'blob:http://localhost:3080/old-blob',
@@ -161,7 +161,7 @@ describe('FileRow', () => {
renderFileRow(filesMap);
const imageUrl = screen.getByTestId('image-url').textContent;
- expect(imageUrl).toBe('/images/user123/complete-file__image.png');
+ expect(imageUrl).toBe('blob:http://localhost:3080/old-blob');
});
});
@@ -284,7 +284,7 @@ describe('FileRow', () => {
const urls = screen.getAllByTestId('image-url').map((el) => el.textContent);
expect(urls).toContain('blob:http://localhost:3080/preview-1');
- expect(urls).toContain('/images/user123/file-2__image.png');
+ expect(urls).toContain('blob:http://localhost:3080/preview-2');
});
it('should deduplicate files with the same file_id', () => {
@@ -321,10 +321,10 @@ describe('FileRow', () => {
});
});
- describe('Regression: Blob URL Bug Fix', () => {
- it('should NOT use revoked blob URL after upload completes', () => {
+ describe('Preview Cache Integration', () => {
+ it('should prefer preview blob URL over filepath for zero-flicker rendering', () => {
const file = createMockFile({
- file_id: 'regression-test',
+ file_id: 'cache-test',
preview: 'blob:http://localhost:3080/d25f730c-152d-41f7-8d79-c9fa448f606b',
filepath:
'/images/68c98b26901ebe2d87c193a2/c0fe1b93-ba3d-456c-80be-9a492bfd9ed0__image.png',
@@ -337,8 +337,24 @@ describe('FileRow', () => {
renderFileRow(filesMap);
const imageUrl = screen.getByTestId('image-url').textContent;
+ expect(imageUrl).toBe('blob:http://localhost:3080/d25f730c-152d-41f7-8d79-c9fa448f606b');
+ });
- expect(imageUrl).not.toContain('blob:');
+ it('should fall back to filepath when no preview exists', () => {
+ const file = createMockFile({
+ file_id: 'no-preview',
+ preview: undefined,
+ filepath:
+ '/images/68c98b26901ebe2d87c193a2/c0fe1b93-ba3d-456c-80be-9a492bfd9ed0__image.png',
+ progress: 1,
+ });
+
+ const filesMap = new Map();
+ filesMap.set(file.file_id, file);
+
+ renderFileRow(filesMap);
+
+ const imageUrl = screen.getByTestId('image-url').textContent;
expect(imageUrl).toBe(
'/images/68c98b26901ebe2d87c193a2/c0fe1b93-ba3d-456c-80be-9a492bfd9ed0__image.png',
);
diff --git a/client/src/components/Chat/Input/MCPSelect.tsx b/client/src/components/Chat/Input/MCPSelect.tsx
index 278e603db0..13a86c856a 100644
--- a/client/src/components/Chat/Input/MCPSelect.tsx
+++ b/client/src/components/Chat/Input/MCPSelect.tsx
@@ -1,4 +1,4 @@
-import React, { memo, useMemo, useCallback, useRef } from 'react';
+import React, { memo, useMemo } from 'react';
import * as Ariakit from '@ariakit/react';
import { ChevronDown } from 'lucide-react';
import { PermissionTypes, Permissions } from 'librechat-data-provider';
@@ -11,7 +11,7 @@ import { useHasAccess } from '~/hooks';
import { cn } from '~/utils';
function MCPSelectContent() {
- const { conversationId, mcpServerManager } = useBadgeRowContext();
+ const { conversationId, storageContextKey, mcpServerManager } = useBadgeRowContext();
const {
localize,
isPinned,
@@ -27,24 +27,9 @@ function MCPSelectContent() {
const menuStore = Ariakit.useMenuStore({ focusLoop: true });
const isOpen = menuStore.useState('open');
- const focusedElementRef = useRef(null);
const selectedCount = mcpValues?.length ?? 0;
- // Wrap toggleServerSelection to preserve focus after state update
- const handleToggle = useCallback(
- (serverName: string) => {
- // Save currently focused element
- focusedElementRef.current = document.activeElement as HTMLElement;
- toggleServerSelection(serverName);
- // Restore focus after React re-renders
- requestAnimationFrame(() => {
- focusedElementRef.current?.focus();
- });
- },
- [toggleServerSelection],
- );
-
const selectedServers = useMemo(() => {
if (!mcpValues || mcpValues.length === 0) {
return [];
@@ -103,6 +88,8 @@ function MCPSelectContent() {
))}
{configDialogProps && (
-
+
)}
>
);
diff --git a/client/src/components/Chat/Input/MCPSubMenu.tsx b/client/src/components/Chat/Input/MCPSubMenu.tsx
index ca547ca1f7..f8e617cba3 100644
--- a/client/src/components/Chat/Input/MCPSubMenu.tsx
+++ b/client/src/components/Chat/Input/MCPSubMenu.tsx
@@ -15,7 +15,7 @@ interface MCPSubMenuProps {
const MCPSubMenu = React.forwardRef
(
({ placeholder, ...props }, ref) => {
const localize = useLocalize();
- const { mcpServerManager } = useBadgeRowContext();
+ const { storageContextKey, mcpServerManager } = useBadgeRowContext();
const {
isPinned,
mcpValues,
@@ -35,7 +35,6 @@ const MCPSubMenu = React.forwardRef(
placement: 'right',
});
- // Don't render if no MCP servers are configured
if (!selectableServers || selectableServers.length === 0) {
return null;
}
@@ -106,7 +105,9 @@ const MCPSubMenu = React.forwardRef(
- {configDialogProps && }
+ {configDialogProps && (
+
+ )}
);
},
diff --git a/client/src/components/Chat/Input/Mention.tsx b/client/src/components/Chat/Input/Mention.tsx
index 9e56068def..34bddba519 100644
--- a/client/src/components/Chat/Input/Mention.tsx
+++ b/client/src/components/Chat/Input/Mention.tsx
@@ -2,11 +2,10 @@ import { useState, useRef, useEffect } from 'react';
import { useCombobox } from '@librechat/client';
import { AutoSizer, List } from 'react-virtualized';
import { EModelEndpoint } from 'librechat-data-provider';
-import type { TConversation } from 'librechat-data-provider';
import type { MentionOption, ConvoGenerator } from '~/common';
import type { SetterOrUpdater } from 'recoil';
+import { useGetConversation, useLocalize, TranslationKeys } from '~/hooks';
import useSelectMention from '~/hooks/Input/useSelectMention';
-import { useLocalize, TranslationKeys } from '~/hooks';
import { useAssistantsMapContext } from '~/Providers';
import useMentions from '~/hooks/Input/useMentions';
import { removeCharIfLast } from '~/utils';
@@ -15,7 +14,6 @@ import MentionItem from './MentionItem';
const ROW_HEIGHT = 44;
export default function Mention({
- conversation,
setShowMentionPopover,
newConversation,
textAreaRef,
@@ -23,7 +21,6 @@ export default function Mention({
placeholder = 'com_ui_mention',
includeAssistants = true,
}: {
- conversation: TConversation | null;
setShowMentionPopover: SetterOrUpdater
;
newConversation: ConvoGenerator;
textAreaRef: React.MutableRefObject;
@@ -32,6 +29,7 @@ export default function Mention({
includeAssistants?: boolean;
}) {
const localize = useLocalize();
+ const getConversation = useGetConversation(0);
const assistantsMap = useAssistantsMapContext();
const {
options,
@@ -45,9 +43,9 @@ export default function Mention({
const { onSelectMention } = useSelectMention({
presets,
modelSpecs,
- conversation,
assistantsMap,
endpointsConfig,
+ getConversation,
newConversation,
});
diff --git a/client/src/components/Chat/Input/SendButton.tsx b/client/src/components/Chat/Input/SendButton.tsx
index 14c21f0586..a07e574928 100644
--- a/client/src/components/Chat/Input/SendButton.tsx
+++ b/client/src/components/Chat/Input/SendButton.tsx
@@ -41,7 +41,8 @@ const SubmitButton = React.memo(
const SendButton = React.memo(
forwardRef((props: SendButtonProps, ref: React.ForwardedRef) => {
const data = useWatch({ control: props.control });
- return ;
+ const content = data?.text?.trim();
+ return ;
}),
);
diff --git a/client/src/components/Chat/Input/__tests__/MCPSelect.spec.tsx b/client/src/components/Chat/Input/__tests__/MCPSelect.spec.tsx
new file mode 100644
index 0000000000..7662ee5e6e
--- /dev/null
+++ b/client/src/components/Chat/Input/__tests__/MCPSelect.spec.tsx
@@ -0,0 +1,142 @@
+import React from 'react';
+import userEvent from '@testing-library/user-event';
+import { render, screen, within } from '@testing-library/react';
+import MCPSelect from '../MCPSelect';
+
+const mockToggleServerSelection = jest.fn();
+
+const defaultMcpServerManager = {
+ localize: (key: string) => key,
+ isPinned: true,
+ mcpValues: [] as string[],
+ placeholderText: 'MCP Servers',
+ selectableServers: [
+ { serverName: 'server-a', config: { title: 'Server A' } },
+ { serverName: 'server-b', config: { title: 'Server B' } },
+ ],
+ connectionStatus: {},
+ isInitializing: () => false,
+ getConfigDialogProps: () => null,
+ toggleServerSelection: mockToggleServerSelection,
+ getServerStatusIconProps: () => null,
+};
+
+let mockCanUseMcp = true;
+let mockMcpServerManager = { ...defaultMcpServerManager };
+
+jest.mock('~/Providers', () => ({
+ useBadgeRowContext: () => ({
+ conversationId: 'test-conv',
+ storageContextKey: undefined,
+ mcpServerManager: mockMcpServerManager,
+ }),
+}));
+
+jest.mock('~/hooks', () => ({
+ useLocalize: () => (key: string) => key,
+ useHasAccess: () => mockCanUseMcp,
+}));
+
+jest.mock('@librechat/client', () => {
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
+ const R = require('react');
+ return {
+ TooltipAnchor: ({
+ children,
+ render,
+ }: {
+ children: React.ReactNode;
+ render: React.ReactElement;
+ }) => R.cloneElement(render, {}, ...(Array.isArray(children) ? children : [children])),
+ MCPIcon: ({ className }: { className?: string }) => R.createElement('span', { className }),
+ Spinner: ({ className }: { className?: string }) => R.createElement('span', { className }),
+ };
+});
+
+jest.mock('~/components/MCP/MCPConfigDialog', () => ({
+ __esModule: true,
+ default: () => null,
+}));
+
+describe('MCPSelect', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ mockCanUseMcp = true;
+ mockMcpServerManager = { ...defaultMcpServerManager };
+ });
+
+ it('renders the menu button', () => {
+ render( );
+ expect(screen.getByRole('button', { name: /MCP Servers/i })).toBeInTheDocument();
+ });
+
+ it('opens menu on button click and shows server items', async () => {
+ const user = userEvent.setup();
+ render( );
+
+ await user.click(screen.getByRole('button', { name: /MCP Servers/i }));
+
+ const menu = screen.getByRole('menu', { name: /com_ui_mcp_servers/i });
+ expect(menu).toBeVisible();
+ expect(within(menu).getByRole('menuitemcheckbox', { name: /Server A/i })).toBeInTheDocument();
+ expect(within(menu).getByRole('menuitemcheckbox', { name: /Server B/i })).toBeInTheDocument();
+ });
+
+ it('closes menu on Escape', async () => {
+ const user = userEvent.setup();
+ render( );
+
+ await user.click(screen.getByRole('button', { name: /MCP Servers/i }));
+ expect(screen.getByRole('menu', { name: /com_ui_mcp_servers/i })).toBeVisible();
+
+ await user.keyboard('{Escape}');
+ expect(screen.getByRole('button', { name: /MCP Servers/i })).toHaveAttribute(
+ 'aria-expanded',
+ 'false',
+ );
+ });
+
+ it('keeps menu open after toggling a server item', async () => {
+ const user = userEvent.setup();
+ render( );
+
+ await user.click(screen.getByRole('button', { name: /MCP Servers/i }));
+ await user.click(screen.getByRole('menuitemcheckbox', { name: /Server A/i }));
+
+ expect(mockToggleServerSelection).toHaveBeenCalledWith('server-a');
+ expect(screen.getByRole('menu', { name: /com_ui_mcp_servers/i })).toBeVisible();
+ });
+
+ it('arrow-key navigation wraps from last item to first', async () => {
+ const user = userEvent.setup();
+ render( );
+
+ await user.click(screen.getByRole('button', { name: /MCP Servers/i }));
+ const items = screen.getAllByRole('menuitemcheckbox');
+ expect(items).toHaveLength(2);
+
+ await user.keyboard('{ArrowDown}');
+ await user.keyboard('{ArrowDown}');
+ await user.keyboard('{ArrowDown}');
+ expect(items[0]).toHaveFocus();
+ });
+
+ it('renders nothing when user lacks MCP access', () => {
+ mockCanUseMcp = false;
+ const { container } = render( );
+ expect(container.firstChild).toBeNull();
+ expect(screen.queryByRole('button')).not.toBeInTheDocument();
+ });
+
+ it('renders nothing when selectableServers is empty', () => {
+ mockMcpServerManager = { ...defaultMcpServerManager, selectableServers: [] };
+ const { container } = render( );
+ expect(container.firstChild).toBeNull();
+ });
+
+ it('renders nothing when not pinned and no servers selected', () => {
+ mockMcpServerManager = { ...defaultMcpServerManager, isPinned: false, mcpValues: [] };
+ const { container } = render( );
+ expect(container.firstChild).toBeNull();
+ });
+});
diff --git a/client/src/components/Chat/Input/__tests__/MCPSubMenu.spec.tsx b/client/src/components/Chat/Input/__tests__/MCPSubMenu.spec.tsx
new file mode 100644
index 0000000000..be8fb5d9c2
--- /dev/null
+++ b/client/src/components/Chat/Input/__tests__/MCPSubMenu.spec.tsx
@@ -0,0 +1,156 @@
+import React from 'react';
+import * as Ariakit from '@ariakit/react';
+import userEvent from '@testing-library/user-event';
+import { render, screen, within } from '@testing-library/react';
+import MCPSubMenu from '../MCPSubMenu';
+
+const mockToggleServerSelection = jest.fn();
+const mockSetIsPinned = jest.fn();
+
+const defaultMcpServerManager = {
+ isPinned: true,
+ mcpValues: [] as string[],
+ setIsPinned: mockSetIsPinned,
+ placeholderText: 'MCP Servers',
+ selectableServers: [
+ { serverName: 'server-a', config: { title: 'Server A' } },
+ { serverName: 'server-b', config: { title: 'Server B', description: 'Second server' } },
+ ],
+ connectionStatus: {},
+ isInitializing: () => false,
+ getConfigDialogProps: () => null,
+ toggleServerSelection: mockToggleServerSelection,
+ getServerStatusIconProps: () => null,
+};
+
+let mockMcpServerManager = { ...defaultMcpServerManager };
+
+jest.mock('~/Providers', () => ({
+ useBadgeRowContext: () => ({
+ storageContextKey: undefined,
+ mcpServerManager: mockMcpServerManager,
+ }),
+}));
+
+jest.mock('~/hooks', () => ({
+ useLocalize: () => (key: string) => key,
+ useHasAccess: () => true,
+}));
+
+jest.mock('@librechat/client', () => {
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
+ const R = require('react');
+ return {
+ MCPIcon: ({ className }: { className?: string }) => R.createElement('span', { className }),
+ PinIcon: ({ unpin }: { unpin?: boolean }) =>
+ R.createElement('span', { 'data-testid': unpin ? 'unpin-icon' : 'pin-icon' }),
+ Spinner: ({ className }: { className?: string }) => R.createElement('span', { className }),
+ };
+});
+
+jest.mock('~/components/MCP/MCPConfigDialog', () => ({
+ __esModule: true,
+ default: () => null,
+}));
+
+function ParentMenu({ children }: { children: React.ReactNode }) {
+ return (
+
+ {/* eslint-disable-next-line i18next/no-literal-string */}
+ Parent
+ {children}
+
+ );
+}
+
+function renderSubMenu(props: React.ComponentProps = {}) {
+ return render(
+
+
+ ,
+ );
+}
+
+describe('MCPSubMenu', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ mockMcpServerManager = { ...defaultMcpServerManager };
+ });
+
+ it('renders nothing when selectableServers is empty', () => {
+ mockMcpServerManager = { ...defaultMcpServerManager, selectableServers: [] };
+ renderSubMenu();
+ expect(screen.queryByText('MCP Servers')).not.toBeInTheDocument();
+ });
+
+ it('renders the submenu trigger with default placeholder', () => {
+ renderSubMenu();
+ expect(screen.getByText('MCP Servers')).toBeInTheDocument();
+ });
+
+ it('renders custom placeholder when provided', () => {
+ renderSubMenu({ placeholder: 'Custom Label' });
+ expect(screen.getByText('Custom Label')).toBeInTheDocument();
+ expect(screen.queryByText('MCP Servers')).not.toBeInTheDocument();
+ });
+
+ it('opens submenu and shows real server items', async () => {
+ const user = userEvent.setup();
+ renderSubMenu();
+
+ await user.click(screen.getByText('MCP Servers'));
+
+ const menu = screen.getByRole('menu', { name: /com_ui_mcp_servers/i });
+ expect(menu).toBeVisible();
+ expect(within(menu).getByRole('menuitemcheckbox', { name: /Server A/i })).toBeInTheDocument();
+ expect(within(menu).getByRole('menuitemcheckbox', { name: /Server B/i })).toBeInTheDocument();
+ });
+
+ it('keeps menu open after toggling a server item', async () => {
+ const user = userEvent.setup();
+ renderSubMenu();
+
+ await user.click(screen.getByText('MCP Servers'));
+ await user.click(screen.getByRole('menuitemcheckbox', { name: /Server A/i }));
+
+ expect(mockToggleServerSelection).toHaveBeenCalledWith('server-a');
+ expect(screen.getByRole('menu', { name: /com_ui_mcp_servers/i })).toBeVisible();
+ });
+
+ it('calls setIsPinned with toggled value when pin button is clicked', async () => {
+ const user = userEvent.setup();
+ mockMcpServerManager = { ...defaultMcpServerManager, isPinned: false };
+ renderSubMenu();
+
+ await user.click(screen.getByRole('button', { name: /com_ui_pin/i }));
+
+ expect(mockSetIsPinned).toHaveBeenCalledWith(true);
+ });
+
+ it('arrow-key navigation wraps from last item to first', async () => {
+ const user = userEvent.setup();
+ renderSubMenu();
+
+ await user.click(screen.getByText('MCP Servers'));
+ const items = screen.getAllByRole('menuitemcheckbox');
+ expect(items).toHaveLength(2);
+
+ await user.click(items[1]);
+ expect(items[1]).toHaveFocus();
+
+ await user.keyboard('{ArrowDown}');
+ expect(items[0]).toHaveFocus();
+ });
+
+ it('pin button shows unpin label when pinned', () => {
+ mockMcpServerManager = { ...defaultMcpServerManager, isPinned: true };
+ renderSubMenu();
+ expect(screen.getByRole('button', { name: /com_ui_unpin/i })).toBeInTheDocument();
+ });
+
+ it('pin button shows pin label when not pinned', () => {
+ mockMcpServerManager = { ...defaultMcpServerManager, isPinned: false };
+ renderSubMenu();
+ expect(screen.getByRole('button', { name: /com_ui_pin/i })).toBeInTheDocument();
+ });
+});
diff --git a/client/src/components/Chat/Menus/Endpoints/ModelSelectorChatContext.tsx b/client/src/components/Chat/Menus/Endpoints/ModelSelectorChatContext.tsx
index eac3bb200c..c6f2416d78 100644
--- a/client/src/components/Chat/Menus/Endpoints/ModelSelectorChatContext.tsx
+++ b/client/src/components/Chat/Menus/Endpoints/ModelSelectorChatContext.tsx
@@ -1,6 +1,9 @@
-import React, { createContext, useContext, useMemo } from 'react';
+import React, { createContext, useCallback, useContext, useMemo, useRef } from 'react';
+import { useRecoilValue } from 'recoil';
import type { EModelEndpoint, TConversation } from 'librechat-data-provider';
-import { useChatContext } from '~/Providers/ChatContext';
+import type { ConvoGenerator } from '~/common';
+import { useGetConversation, useNewConvo } from '~/hooks';
+import store from '~/store';
interface ModelSelectorChatContextValue {
endpoint?: EModelEndpoint | null;
@@ -8,8 +11,8 @@ interface ModelSelectorChatContextValue {
spec?: string | null;
agent_id?: string | null;
assistant_id?: string | null;
- conversation: TConversation | null;
- newConversation: ReturnType['newConversation'];
+ getConversation: () => TConversation | null;
+ newConversation: ConvoGenerator;
}
const ModelSelectorChatContext = createContext(
@@ -17,20 +20,34 @@ const ModelSelectorChatContext = createContext(
+ (params) => newConversationRef.current(params),
+ [],
+ );
/** Context value only created when relevant conversation properties change */
const contextValue = useMemo(
() => ({
- endpoint: conversation?.endpoint,
- model: conversation?.model,
- spec: conversation?.spec,
- agent_id: conversation?.agent_id,
- assistant_id: conversation?.assistant_id,
- conversation,
+ model,
+ spec,
+ agent_id,
+ endpoint,
+ assistant_id,
+ getConversation,
newConversation,
}),
- [conversation, newConversation],
+ [endpoint, model, spec, agent_id, assistant_id, getConversation, newConversation],
);
return (
diff --git a/client/src/components/Chat/Menus/Endpoints/ModelSelectorContext.tsx b/client/src/components/Chat/Menus/Endpoints/ModelSelectorContext.tsx
index dd08728560..5a51db6ce9 100644
--- a/client/src/components/Chat/Menus/Endpoints/ModelSelectorContext.tsx
+++ b/client/src/components/Chat/Menus/Endpoints/ModelSelectorContext.tsx
@@ -58,7 +58,7 @@ export function ModelSelectorProvider({ children, startupConfig }: ModelSelector
const agentsMap = useAgentsMapContext();
const assistantsMap = useAssistantsMapContext();
const { data: endpointsConfig } = useGetEndpointsQuery();
- const { endpoint, model, spec, agent_id, assistant_id, conversation, newConversation } =
+ const { endpoint, model, spec, agent_id, assistant_id, getConversation, newConversation } =
useModelSelectorChatContext();
const localize = useLocalize();
const { announcePolite } = useLiveAnnouncer();
@@ -114,7 +114,7 @@ export function ModelSelectorProvider({ children, startupConfig }: ModelSelector
const { onSelectEndpoint, onSelectSpec } = useSelectMention({
// presets,
modelSpecs,
- conversation,
+ getConversation,
assistantsMap,
endpointsConfig,
newConversation,
@@ -171,90 +171,115 @@ export function ModelSelectorProvider({ children, startupConfig }: ModelSelector
}, 200),
[],
);
- const setEndpointSearchValue = (endpoint: string, value: string) => {
+ const setEndpointSearchValue = useCallback((endpoint: string, value: string) => {
setEndpointSearchValues((prev) => ({
...prev,
[endpoint]: value,
}));
- };
+ }, []);
- const handleSelectSpec = (spec: t.TModelSpec) => {
- let model = spec.preset.model ?? null;
- onSelectSpec?.(spec);
- if (isAgentsEndpoint(spec.preset.endpoint)) {
- model = spec.preset.agent_id ?? '';
- } else if (isAssistantsEndpoint(spec.preset.endpoint)) {
- model = spec.preset.assistant_id ?? '';
- }
- setSelectedValues({
- endpoint: spec.preset.endpoint,
- model,
- modelSpec: spec.name,
- });
- };
+ const handleSelectSpec = useCallback(
+ (spec: t.TModelSpec) => {
+ let model = spec.preset.model ?? null;
+ onSelectSpec?.(spec);
+ if (isAgentsEndpoint(spec.preset.endpoint)) {
+ model = spec.preset.agent_id ?? '';
+ } else if (isAssistantsEndpoint(spec.preset.endpoint)) {
+ model = spec.preset.assistant_id ?? '';
+ }
+ setSelectedValues({
+ endpoint: spec.preset.endpoint,
+ model,
+ modelSpec: spec.name,
+ });
+ },
+ [onSelectSpec],
+ );
- const handleSelectEndpoint = (endpoint: Endpoint) => {
- if (!endpoint.hasModels) {
- if (endpoint.value) {
- onSelectEndpoint?.(endpoint.value);
+ const handleSelectEndpoint = useCallback(
+ (endpoint: Endpoint) => {
+ if (!endpoint.hasModels) {
+ if (endpoint.value) {
+ onSelectEndpoint?.(endpoint.value);
+ }
+ setSelectedValues({
+ endpoint: endpoint.value,
+ model: '',
+ modelSpec: '',
+ });
+ }
+ },
+ [onSelectEndpoint],
+ );
+
+ const handleSelectModel = useCallback(
+ (endpoint: Endpoint, model: string) => {
+ if (isAgentsEndpoint(endpoint.value)) {
+ onSelectEndpoint?.(endpoint.value, {
+ agent_id: model,
+ model: agentsMap?.[model]?.model ?? '',
+ });
+ } else if (isAssistantsEndpoint(endpoint.value)) {
+ onSelectEndpoint?.(endpoint.value, {
+ assistant_id: model,
+ model: assistantsMap?.[endpoint.value]?.[model]?.model ?? '',
+ });
+ } else if (endpoint.value) {
+ onSelectEndpoint?.(endpoint.value, { model });
}
setSelectedValues({
endpoint: endpoint.value,
- model: '',
+ model,
modelSpec: '',
});
- }
- };
- const handleSelectModel = (endpoint: Endpoint, model: string) => {
- if (isAgentsEndpoint(endpoint.value)) {
- onSelectEndpoint?.(endpoint.value, {
- agent_id: model,
- model: agentsMap?.[model]?.model ?? '',
- });
- } else if (isAssistantsEndpoint(endpoint.value)) {
- onSelectEndpoint?.(endpoint.value, {
- assistant_id: model,
- model: assistantsMap?.[endpoint.value]?.[model]?.model ?? '',
- });
- } else if (endpoint.value) {
- onSelectEndpoint?.(endpoint.value, { model });
- }
- setSelectedValues({
- endpoint: endpoint.value,
- model,
- modelSpec: '',
- });
+ const modelDisplayName = getModelDisplayName(endpoint, model);
+ const announcement = localize('com_ui_model_selected', { 0: modelDisplayName });
+ announcePolite({ message: announcement, isStatus: true });
+ },
+ [agentsMap, announcePolite, assistantsMap, getModelDisplayName, localize, onSelectEndpoint],
+ );
- const modelDisplayName = getModelDisplayName(endpoint, model);
- const announcement = localize('com_ui_model_selected', { 0: modelDisplayName });
- announcePolite({ message: announcement, isStatus: true });
- };
-
- const value = {
- // State
- searchValue,
- searchResults,
- selectedValues,
- endpointSearchValues,
- // LibreChat
- agentsMap,
- modelSpecs,
- assistantsMap,
- mappedEndpoints,
- endpointsConfig,
-
- // Functions
- handleSelectSpec,
- handleSelectModel,
- setSelectedValues,
- handleSelectEndpoint,
- setEndpointSearchValue,
- endpointRequiresUserKey,
- setSearchValue: setDebouncedSearchValue,
- // Dialog
- ...keyProps,
- };
+ const value = useMemo(
+ () => ({
+ searchValue,
+ searchResults,
+ selectedValues,
+ endpointSearchValues,
+ agentsMap,
+ modelSpecs,
+ assistantsMap,
+ mappedEndpoints,
+ endpointsConfig,
+ handleSelectSpec,
+ handleSelectModel,
+ setSelectedValues,
+ handleSelectEndpoint,
+ setEndpointSearchValue,
+ endpointRequiresUserKey,
+ setSearchValue: setDebouncedSearchValue,
+ ...keyProps,
+ }),
+ [
+ searchValue,
+ searchResults,
+ selectedValues,
+ endpointSearchValues,
+ agentsMap,
+ modelSpecs,
+ assistantsMap,
+ mappedEndpoints,
+ endpointsConfig,
+ handleSelectSpec,
+ handleSelectModel,
+ setSelectedValues,
+ handleSelectEndpoint,
+ setEndpointSearchValue,
+ endpointRequiresUserKey,
+ setDebouncedSearchValue,
+ keyProps,
+ ],
+ );
return {children} ;
}
diff --git a/client/src/components/Chat/Menus/Endpoints/components/EndpointItem.tsx b/client/src/components/Chat/Menus/Endpoints/components/EndpointItem.tsx
index 27c1236cb2..c8cef36010 100644
--- a/client/src/components/Chat/Menus/Endpoints/components/EndpointItem.tsx
+++ b/client/src/components/Chat/Menus/Endpoints/components/EndpointItem.tsx
@@ -80,12 +80,70 @@ const SettingsButton = ({
);
};
+/**
+ * Lazily-rendered content for an endpoint submenu. By extracting this into a
+ * separate component, the expensive model-list rendering (and per-item hooks
+ * such as MutationObservers in EndpointModelItem) only runs when the submenu
+ * is actually mounted — which Ariakit defers via `unmountOnHide`.
+ */
+function EndpointMenuContent({
+ endpoint,
+ endpointIndex,
+}: {
+ endpoint: Endpoint;
+ endpointIndex: number;
+}) {
+ const localize = useLocalize();
+ const { agentsMap, assistantsMap, modelSpecs, selectedValues, endpointSearchValues } =
+ useModelSelectorContext();
+ const { modelSpec: selectedSpec } = selectedValues;
+ const searchValue = endpointSearchValues[endpoint.value] || '';
+
+ const endpointSpecs = useMemo(() => {
+ if (!modelSpecs || !modelSpecs.length) {
+ return [];
+ }
+ return modelSpecs.filter((spec: TModelSpec) => spec.group === endpoint.value);
+ }, [modelSpecs, endpoint.value]);
+
+ if (isAssistantsEndpoint(endpoint.value) && endpoint.models === undefined) {
+ return (
+
+
+
+ );
+ }
+
+ const filteredModels = searchValue
+ ? filterModels(
+ endpoint,
+ (endpoint.models || []).map((model) => model.name),
+ searchValue,
+ agentsMap,
+ assistantsMap,
+ )
+ : null;
+
+ return (
+ <>
+ {endpointSpecs.map((spec: TModelSpec) => (
+
+ ))}
+ {filteredModels
+ ? renderEndpointModels(endpoint, endpoint.models || [], filteredModels, endpointIndex)
+ : endpoint.models &&
+ renderEndpointModels(endpoint, endpoint.models, undefined, endpointIndex)}
+ >
+ );
+}
+
export function EndpointItem({ endpoint, endpointIndex }: EndpointItemProps) {
const localize = useLocalize();
const {
- agentsMap,
- assistantsMap,
- modelSpecs,
selectedValues,
handleOpenKeyDialog,
handleSelectEndpoint,
@@ -93,19 +151,7 @@ export function EndpointItem({ endpoint, endpointIndex }: EndpointItemProps) {
setEndpointSearchValue,
endpointRequiresUserKey,
} = useModelSelectorContext();
- const {
- model: selectedModel,
- endpoint: selectedEndpoint,
- modelSpec: selectedSpec,
- } = selectedValues;
-
- // Filter modelSpecs for this endpoint (by group matching endpoint value)
- const endpointSpecs = useMemo(() => {
- if (!modelSpecs || !modelSpecs.length) {
- return [];
- }
- return modelSpecs.filter((spec: TModelSpec) => spec.group === endpoint.value);
- }, [modelSpecs, endpoint.value]);
+ const { endpoint: selectedEndpoint, modelSpec: selectedSpec } = selectedValues;
const searchValue = endpointSearchValues[endpoint.value] || '';
const isUserProvided = useMemo(
@@ -127,18 +173,9 @@ export function EndpointItem({ endpoint, endpointIndex }: EndpointItemProps) {
);
- const isEndpointSelected = selectedEndpoint === endpoint.value;
+ const isEndpointSelected = !selectedSpec && selectedEndpoint === endpoint.value;
if (endpoint.hasModels) {
- const filteredModels = searchValue
- ? filterModels(
- endpoint,
- (endpoint.models || []).map((model) => model.name),
- searchValue,
- agentsMap,
- assistantsMap,
- )
- : null;
const placeholder =
isAgentsEndpoint(endpoint.value) || isAssistantsEndpoint(endpoint.value)
? localize('com_endpoint_search_var', { 0: endpoint.label })
@@ -147,7 +184,6 @@ export function EndpointItem({ endpoint, endpointIndex }: EndpointItemProps) {
);
} else {
diff --git a/client/src/components/Chat/Menus/Endpoints/components/EndpointModelItem.tsx b/client/src/components/Chat/Menus/Endpoints/components/EndpointModelItem.tsx
index 752788d63a..7cec4744d5 100644
--- a/client/src/components/Chat/Menus/Endpoints/components/EndpointModelItem.tsx
+++ b/client/src/components/Chat/Menus/Endpoints/components/EndpointModelItem.tsx
@@ -11,12 +11,18 @@ import { cn } from '~/utils';
interface EndpointModelItemProps {
modelId: string | null;
endpoint: Endpoint;
- isSelected: boolean;
}
-export function EndpointModelItem({ modelId, endpoint, isSelected }: EndpointModelItemProps) {
+export function EndpointModelItem({ modelId, endpoint }: EndpointModelItemProps) {
const localize = useLocalize();
- const { handleSelectModel } = useModelSelectorContext();
+ const { handleSelectModel, selectedValues } = useModelSelectorContext();
+ const {
+ endpoint: selectedEndpoint,
+ model: selectedModel,
+ modelSpec: selectedSpec,
+ } = selectedValues;
+ const isSelected =
+ !selectedSpec && selectedEndpoint === endpoint.value && selectedModel === modelId;
const { isFavoriteModel, toggleFavoriteModel, isFavoriteAgent, toggleFavoriteAgent } =
useFavorites();
@@ -147,7 +153,6 @@ export function EndpointModelItem({ modelId, endpoint, isSelected }: EndpointMod
export function renderEndpointModels(
endpoint: Endpoint | null,
models: Array<{ name: string; isGlobal?: boolean }>,
- selectedModel: string | null,
filteredModels?: string[],
endpointIndex?: number,
) {
@@ -161,7 +166,6 @@ export function renderEndpointModels(
key={`${endpoint.value}${indexSuffix}-${modelId}-${modelIndex}`}
modelId={modelId}
endpoint={endpoint}
- isSelected={selectedModel === modelId}
/>
),
);
diff --git a/client/src/components/Chat/Menus/Endpoints/components/SearchResults.tsx b/client/src/components/Chat/Menus/Endpoints/components/SearchResults.tsx
index 34985639c5..26831a577e 100644
--- a/client/src/components/Chat/Menus/Endpoints/components/SearchResults.tsx
+++ b/client/src/components/Chat/Menus/Endpoints/components/SearchResults.tsx
@@ -160,7 +160,9 @@ export function SearchResults({ results, localize, searchValue }: SearchResultsP
}
const isModelSelected =
- selectedEndpoint === endpoint.value && selectedModel === modelId;
+ !selectedSpec &&
+ selectedEndpoint === endpoint.value &&
+ selectedModel === modelId;
return (
({
+ useModelSelectorContext: () => ({
+ handleSelectModel: mockHandleSelectModel,
+ selectedValues: mockSelectedValues,
+ }),
+}));
+
+jest.mock('~/components/Chat/Menus/Endpoints/CustomMenu', () => {
+ const React = jest.requireActual('react');
+ return {
+ CustomMenuItem: React.forwardRef(function MockMenuItem(
+ { children, ...rest }: { children?: React.ReactNode },
+ ref: React.Ref,
+ ) {
+ return React.createElement('div', { ref, role: 'menuitem', ...rest }, children);
+ }),
+ };
+});
+
+jest.mock('~/hooks', () => ({
+ useLocalize: () => (key: string) => key,
+ useFavorites: () => ({
+ isFavoriteModel: () => false,
+ toggleFavoriteModel: jest.fn(),
+ isFavoriteAgent: () => false,
+ toggleFavoriteAgent: jest.fn(),
+ }),
+}));
+
+const baseEndpoint: Endpoint = {
+ value: 'anthropic',
+ label: 'Anthropic',
+ hasModels: true,
+ models: [{ name: 'claude-opus-4-6' }],
+ icon: null,
+};
+
+describe('EndpointModelItem', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('renders checkmark when model and endpoint match with no active spec', () => {
+ mockSelectedValues = { endpoint: 'anthropic', model: 'claude-opus-4-6', modelSpec: '' };
+ render( );
+
+ const menuItem = screen.getByRole('menuitem');
+ expect(menuItem).toHaveAttribute('aria-selected', 'true');
+ });
+
+ it('does NOT render checkmark when a model spec is active even if endpoint and model match', () => {
+ mockSelectedValues = {
+ endpoint: 'anthropic',
+ model: 'claude-opus-4-6',
+ modelSpec: 'my-anthropic-spec',
+ };
+ render( );
+
+ const menuItem = screen.getByRole('menuitem');
+ expect(menuItem).not.toHaveAttribute('aria-selected');
+ });
+
+ it('does NOT render checkmark when model matches but endpoint differs', () => {
+ mockSelectedValues = { endpoint: 'openai', model: 'claude-opus-4-6', modelSpec: '' };
+ render( );
+
+ const menuItem = screen.getByRole('menuitem');
+ expect(menuItem).not.toHaveAttribute('aria-selected');
+ });
+
+ it('does NOT render checkmark when endpoint matches but model differs', () => {
+ mockSelectedValues = { endpoint: 'anthropic', model: 'claude-sonnet-4-5', modelSpec: '' };
+ render( );
+
+ const menuItem = screen.getByRole('menuitem');
+ expect(menuItem).not.toHaveAttribute('aria-selected');
+ });
+});
diff --git a/client/src/components/Chat/Menus/Endpoints/components/__tests__/SearchResults.test.tsx b/client/src/components/Chat/Menus/Endpoints/components/__tests__/SearchResults.test.tsx
new file mode 100644
index 0000000000..8ab9235f6f
--- /dev/null
+++ b/client/src/components/Chat/Menus/Endpoints/components/__tests__/SearchResults.test.tsx
@@ -0,0 +1,109 @@
+import { render, screen } from '@testing-library/react';
+import type { Endpoint, SelectedValues } from '~/common';
+import { SearchResults } from '../SearchResults';
+
+const mockHandleSelectSpec = jest.fn();
+const mockHandleSelectModel = jest.fn();
+const mockHandleSelectEndpoint = jest.fn();
+let mockSelectedValues: SelectedValues;
+
+jest.mock('~/components/Chat/Menus/Endpoints/ModelSelectorContext', () => ({
+ useModelSelectorContext: () => ({
+ selectedValues: mockSelectedValues,
+ handleSelectSpec: mockHandleSelectSpec,
+ handleSelectModel: mockHandleSelectModel,
+ handleSelectEndpoint: mockHandleSelectEndpoint,
+ endpointsConfig: {},
+ }),
+}));
+
+jest.mock('~/components/Chat/Menus/Endpoints/CustomMenu', () => {
+ const React = jest.requireActual('react');
+ return {
+ CustomMenuItem: React.forwardRef(function MockMenuItem(
+ { children, ...rest }: { children?: React.ReactNode },
+ ref: React.Ref,
+ ) {
+ return React.createElement('div', { ref, role: 'menuitem', ...rest }, children);
+ }),
+ };
+});
+
+jest.mock('../SpecIcon', () => {
+ const React = jest.requireActual('react');
+ return {
+ __esModule: true,
+ default: () => React.createElement('span', null, 'icon'),
+ };
+});
+
+const localize = (key: string) => key;
+
+const anthropicEndpoint: Endpoint = {
+ value: 'anthropic',
+ label: 'Anthropic',
+ hasModels: true,
+ models: [{ name: 'claude-opus-4-6' }, { name: 'claude-sonnet-4-5' }],
+ icon: null,
+};
+
+const noModelsEndpoint: Endpoint = {
+ value: 'custom',
+ label: 'Custom',
+ hasModels: false,
+ icon: null,
+};
+
+describe('SearchResults', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('marks model as selected when endpoint and model match with no active spec', () => {
+ mockSelectedValues = { endpoint: 'anthropic', model: 'claude-opus-4-6', modelSpec: '' };
+ render(
+ ,
+ );
+
+ const items = screen.getAllByRole('menuitem');
+ const selectedItem = items.find((el) => el.getAttribute('aria-selected') === 'true');
+ expect(selectedItem).toBeDefined();
+ expect(selectedItem).toHaveTextContent('claude-opus-4-6');
+ });
+
+ it('does not mark model as selected when a spec is active', () => {
+ mockSelectedValues = {
+ endpoint: 'anthropic',
+ model: 'claude-opus-4-6',
+ modelSpec: 'my-spec',
+ };
+ render(
+ ,
+ );
+
+ const items = screen.getAllByRole('menuitem');
+ for (const item of items) {
+ expect(item).not.toHaveAttribute('aria-selected');
+ }
+ });
+
+ it('does not mark endpoint as selected when a spec is active', () => {
+ mockSelectedValues = {
+ endpoint: 'custom',
+ model: '',
+ modelSpec: 'my-spec',
+ };
+ render( );
+
+ const item = screen.getByRole('menuitem');
+ expect(item).not.toHaveAttribute('aria-selected');
+ });
+
+ it('marks endpoint as selected when no spec is active and endpoint matches', () => {
+ mockSelectedValues = { endpoint: 'custom', model: '', modelSpec: '' };
+ render( );
+
+ const item = screen.getByRole('menuitem');
+ expect(item).toHaveAttribute('aria-selected', 'true');
+ });
+});
diff --git a/client/src/components/Chat/Menus/HeaderNewChat.tsx b/client/src/components/Chat/Menus/HeaderNewChat.tsx
index 764397eddb..a50d42af85 100644
--- a/client/src/components/Chat/Menus/HeaderNewChat.tsx
+++ b/client/src/components/Chat/Menus/HeaderNewChat.tsx
@@ -1,14 +1,16 @@
import { QueryKeys } from 'librechat-data-provider';
+import { useRecoilValue } from 'recoil';
import { useQueryClient } from '@tanstack/react-query';
import { TooltipAnchor, Button, NewChatIcon } from '@librechat/client';
-import { useChatContext } from '~/Providers';
+import { useNewConvo, useLocalize } from '~/hooks';
import { clearMessagesCache } from '~/utils';
-import { useLocalize } from '~/hooks';
+import store from '~/store';
export default function HeaderNewChat() {
const localize = useLocalize();
const queryClient = useQueryClient();
- const { conversation, newConversation } = useChatContext();
+ const { newConversation } = useNewConvo();
+ const conversation = useRecoilValue(store.conversationByIndex(0));
const clickHandler: React.MouseEventHandler = (e) => {
if (e.button === 0 && (e.ctrlKey || e.metaKey)) {
diff --git a/client/src/components/Chat/Menus/PresetsMenu.tsx b/client/src/components/Chat/Menus/PresetsMenu.tsx
index 48bd927845..a53447e014 100644
--- a/client/src/components/Chat/Menus/PresetsMenu.tsx
+++ b/client/src/components/Chat/Menus/PresetsMenu.tsx
@@ -1,4 +1,5 @@
import { useRef } from 'react';
+import { useRecoilValue } from 'recoil';
import { Trans } from 'react-i18next';
import { BookCopy } from 'lucide-react';
import { Content, Portal, Root, Trigger } from '@radix-ui/react-popover';
@@ -13,7 +14,7 @@ import {
import type { FC } from 'react';
import { EditPresetDialog, PresetItems } from './Presets';
import { useLocalize, usePresets } from '~/hooks';
-import { useChatContext } from '~/Providers';
+import store from '~/store';
const PresetsMenu: FC = () => {
const localize = useLocalize();
@@ -33,7 +34,7 @@ const PresetsMenu: FC = () => {
presetToDelete,
confirmDeletePreset,
} = usePresets();
- const { preset } = useChatContext();
+ const preset = useRecoilValue(store.presetByIndex(0));
const handleDeleteDialogChange = (open: boolean) => {
setShowDeleteDialog(open);
diff --git a/client/src/components/Chat/Messages/Content/ContentParts.tsx b/client/src/components/Chat/Messages/Content/ContentParts.tsx
index 42ce8b8f14..4b431d7a98 100644
--- a/client/src/components/Chat/Messages/Content/ContentParts.tsx
+++ b/client/src/components/Chat/Messages/Content/ContentParts.tsx
@@ -15,6 +15,61 @@ import Sources from '~/components/Web/Sources';
import Container from './Container';
import Part from './Part';
+type PartWithContextProps = {
+ part: TMessageContentParts;
+ idx: number;
+ isLastPart: boolean;
+ messageId: string;
+ conversationId?: string | null;
+ nextType?: string;
+ isSubmitting: boolean;
+ isLatestMessage?: boolean;
+ isCreatedByUser: boolean;
+ isLast: boolean;
+ partAttachments: TAttachment[] | undefined;
+};
+
+const PartWithContext = memo(function PartWithContext({
+ part,
+ idx,
+ isLastPart,
+ messageId,
+ conversationId,
+ nextType,
+ isSubmitting,
+ isLatestMessage,
+ isCreatedByUser,
+ isLast,
+ partAttachments,
+}: PartWithContextProps) {
+ const contextValue = useMemo(
+ () => ({
+ messageId,
+ isExpanded: true as const,
+ conversationId,
+ partIndex: idx,
+ nextType,
+ isSubmitting,
+ isLatestMessage,
+ }),
+ [messageId, conversationId, idx, nextType, isSubmitting, isLatestMessage],
+ );
+
+ return (
+
+
+
+ );
+});
+
type ContentPartsProps = {
content: Array | undefined;
messageId: string;
@@ -58,37 +113,24 @@ const ContentParts = memo(function ContentParts({
const attachmentMap = useMemo(() => mapAttachments(attachments ?? []), [attachments]);
const effectiveIsSubmitting = isLatestMessage ? isSubmitting : false;
- /**
- * Render a single content part with proper context.
- */
const renderPart = useCallback(
(part: TMessageContentParts, idx: number, isLastPart: boolean) => {
const toolCallId = (part?.[ContentTypes.TOOL_CALL] as Agents.ToolCall | undefined)?.id ?? '';
- const partAttachments = attachmentMap[toolCallId];
-
return (
-
-
-
+ idx={idx}
+ part={part}
+ isLast={isLast}
+ messageId={messageId}
+ isLastPart={isLastPart}
+ conversationId={conversationId}
+ isLatestMessage={isLatestMessage}
+ isCreatedByUser={isCreatedByUser}
+ nextType={content?.[idx + 1]?.type}
+ isSubmitting={effectiveIsSubmitting}
+ partAttachments={attachmentMap[toolCallId]}
+ />
);
},
[
diff --git a/client/src/components/Chat/Messages/Content/DialogImage.tsx b/client/src/components/Chat/Messages/Content/DialogImage.tsx
index cb496de646..b9cbe64555 100644
--- a/client/src/components/Chat/Messages/Content/DialogImage.tsx
+++ b/client/src/components/Chat/Messages/Content/DialogImage.tsx
@@ -4,6 +4,8 @@ import { Button, TooltipAnchor } from '@librechat/client';
import { X, ArrowDownToLine, PanelLeftOpen, PanelLeftClose, RotateCcw } from 'lucide-react';
import { useLocalize } from '~/hooks';
+const imageSizeCache = new Map();
+
const getQualityStyles = (quality: string): string => {
if (quality === 'high') {
return 'bg-green-100 text-green-800';
@@ -50,18 +52,26 @@ export default function DialogImage({
const closeButtonRef = useRef(null);
const getImageSize = useCallback(async (url: string) => {
+ const cached = imageSizeCache.get(url);
+ if (cached) {
+ return cached;
+ }
try {
const response = await fetch(url, { method: 'HEAD' });
const contentLength = response.headers.get('Content-Length');
if (contentLength) {
const bytes = parseInt(contentLength, 10);
- return formatFileSize(bytes);
+ const result = formatFileSize(bytes);
+ imageSizeCache.set(url, result);
+ return result;
}
const fullResponse = await fetch(url);
const blob = await fullResponse.blob();
- return formatFileSize(blob.size);
+ const result = formatFileSize(blob.size);
+ imageSizeCache.set(url, result);
+ return result;
} catch (error) {
console.error('Error getting image size:', error);
return null;
@@ -355,6 +365,7 @@ export default function DialogImage({
ref={imageRef}
src={src}
alt="Image"
+ decoding="async"
className="block max-h-[85vh] object-contain"
style={{
maxWidth: getImageMaxWidth(),
diff --git a/client/src/components/Chat/Messages/Content/Files.tsx b/client/src/components/Chat/Messages/Content/Files.tsx
index 8997d5e822..504e48e883 100644
--- a/client/src/components/Chat/Messages/Content/Files.tsx
+++ b/client/src/components/Chat/Messages/Content/Files.tsx
@@ -1,6 +1,7 @@
import { useMemo, memo } from 'react';
import type { TFile, TMessage } from 'librechat-data-provider';
import FileContainer from '~/components/Chat/Input/Files/FileContainer';
+import { getCachedPreview } from '~/utils';
import Image from './Image';
const Files = ({ message }: { message?: TMessage }) => {
@@ -17,21 +18,18 @@ const Files = ({ message }: { message?: TMessage }) => {
{otherFiles.length > 0 &&
otherFiles.map((file) => )}
{imageFiles.length > 0 &&
- imageFiles.map((file) => (
-
- ))}
+ imageFiles.map((file) => {
+ const cached = file.file_id ? getCachedPreview(file.file_id) : undefined;
+ return (
+
+ );
+ })}
>
);
};
diff --git a/client/src/components/Chat/Messages/Content/Image.tsx b/client/src/components/Chat/Messages/Content/Image.tsx
index cd72733298..7e3e12e65b 100644
--- a/client/src/components/Chat/Messages/Content/Image.tsx
+++ b/client/src/components/Chat/Messages/Content/Image.tsx
@@ -1,27 +1,39 @@
-import React, { useState, useRef, useMemo } from 'react';
+import React, { useState, useRef, useMemo, useEffect } from 'react';
import { Skeleton } from '@librechat/client';
-import { LazyLoadImage } from 'react-lazy-load-image-component';
import { apiBaseUrl } from 'librechat-data-provider';
-import { cn, scaleImage } from '~/utils';
import DialogImage from './DialogImage';
+import { cn } from '~/utils';
+
+/** Max display height for chat images (Tailwind JIT class) */
+export const IMAGE_MAX_H = 'max-h-[45vh]' as const;
+/** Matches the `max-w-lg` Tailwind class on the wrapper button (32rem = 512px at 16px base) */
+const IMAGE_MAX_W_PX = 512;
+
+/** Caches image dimensions by src so remounts can reserve space */
+const dimensionCache = new Map();
+/** Tracks URLs that have been fully painted — skip skeleton on remount */
+const paintedUrls = new Set();
+
+/** Test-only: resets module-level caches */
+export function _resetImageCaches(): void {
+ dimensionCache.clear();
+ paintedUrls.clear();
+}
+
+function computeHeightStyle(w: number, h: number): React.CSSProperties {
+ return { height: `min(45vh, ${(h / w) * 100}vw, ${(h / w) * IMAGE_MAX_W_PX}px)` };
+}
const Image = ({
imagePath,
altText,
- height,
- width,
- placeholderDimensions,
className,
args,
+ width,
+ height,
}: {
imagePath: string;
altText: string;
- height: number;
- width: number;
- placeholderDimensions?: {
- height?: string;
- width?: string;
- };
className?: string;
args?: {
prompt?: string;
@@ -30,19 +42,15 @@ const Image = ({
style?: string;
[key: string]: unknown;
};
+ width?: number;
+ height?: number;
}) => {
const [isOpen, setIsOpen] = useState(false);
- const [isLoaded, setIsLoaded] = useState(false);
- const containerRef = useRef(null);
const triggerRef = useRef(null);
- const handleImageLoad = () => setIsLoaded(true);
-
- // Fix image path to include base path for subdirectory deployments
const absoluteImageUrl = useMemo(() => {
if (!imagePath) return imagePath;
- // If it's already an absolute URL or doesn't start with /images/, return as is
if (
imagePath.startsWith('http') ||
imagePath.startsWith('data:') ||
@@ -51,21 +59,10 @@ const Image = ({
return imagePath;
}
- // Get the base URL and prepend it to the image path
const baseURL = apiBaseUrl();
return `${baseURL}${imagePath}`;
}, [imagePath]);
- const { width: scaledWidth, height: scaledHeight } = useMemo(
- () =>
- scaleImage({
- originalWidth: Number(placeholderDimensions?.width?.split('px')[0] ?? width),
- originalHeight: Number(placeholderDimensions?.height?.split('px')[0] ?? height),
- containerRef,
- }),
- [placeholderDimensions, height, width],
- );
-
const downloadImage = async () => {
try {
const response = await fetch(absoluteImageUrl);
@@ -95,8 +92,19 @@ const Image = ({
}
};
+ useEffect(() => {
+ if (width && height && absoluteImageUrl) {
+ dimensionCache.set(absoluteImageUrl, { width, height });
+ }
+ }, [absoluteImageUrl, width, height]);
+
+ const dims = width && height ? { width, height } : dimensionCache.get(absoluteImageUrl);
+ const hasDimensions = !!(dims?.width && dims?.height);
+ const heightStyle = hasDimensions ? computeHeightStyle(dims.width, dims.height) : undefined;
+ const showSkeleton = hasDimensions && !paintedUrls.has(absoluteImageUrl);
+
return (
-
+
setIsOpen(true)}
className={cn(
- 'relative mt-1 flex h-auto w-full max-w-lg cursor-pointer items-center justify-center overflow-hidden rounded-lg border border-border-light text-text-secondary-alt shadow-md transition-shadow',
+ 'relative mt-1 w-full max-w-lg cursor-pointer overflow-hidden rounded-lg border border-border-light text-text-secondary-alt shadow-md transition-shadow',
'focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-primary',
className,
)}
+ style={heightStyle}
>
- }
+
- }
+ onLoad={() => paintedUrls.add(absoluteImageUrl)}
+ className={cn(
+ 'relative block text-transparent',
+ hasDimensions
+ ? 'size-full object-contain'
+ : cn('h-auto w-auto max-w-full', IMAGE_MAX_H),
+ )}
/>
- {isLoaded && (
-
- )}
+
);
};
diff --git a/client/src/components/Chat/Messages/Content/Markdown.tsx b/client/src/components/Chat/Messages/Content/Markdown.tsx
index a763885d2f..1217869a2c 100644
--- a/client/src/components/Chat/Messages/Content/Markdown.tsx
+++ b/client/src/components/Chat/Messages/Content/Markdown.tsx
@@ -27,7 +27,7 @@ type TContentProps = {
isLatestMessage: boolean;
};
-const Markdown = memo(({ content = '', isLatestMessage }: TContentProps) => {
+const Markdown = memo(function Markdown({ content = '', isLatestMessage }: TContentProps) {
const LaTeXParsing = useRecoilValue
(store.LaTeXParsing);
const isInitializing = content === '';
@@ -106,5 +106,6 @@ const Markdown = memo(({ content = '', isLatestMessage }: TContentProps) => {
);
});
+Markdown.displayName = 'Markdown';
export default Markdown;
diff --git a/client/src/components/Chat/Messages/Content/MarkdownComponents.tsx b/client/src/components/Chat/Messages/Content/MarkdownComponents.tsx
index d647147151..1c5369955d 100644
--- a/client/src/components/Chat/Messages/Content/MarkdownComponents.tsx
+++ b/client/src/components/Chat/Messages/Content/MarkdownComponents.tsx
@@ -18,7 +18,10 @@ type TCodeProps = {
children: React.ReactNode;
};
-export const code: React.ElementType = memo(({ className, children }: TCodeProps) => {
+export const code: React.ElementType = memo(function MarkdownCode({
+ className,
+ children,
+}: TCodeProps) {
const canRunCode = useHasAccess({
permissionType: PermissionTypes.RUN_CODE,
permission: Permissions.USE,
@@ -62,8 +65,12 @@ export const code: React.ElementType = memo(({ className, children }: TCodeProps
);
}
});
+code.displayName = 'MarkdownCode';
-export const codeNoExecution: React.ElementType = memo(({ className, children }: TCodeProps) => {
+export const codeNoExecution: React.ElementType = memo(function MarkdownCodeNoExecution({
+ className,
+ children,
+}: TCodeProps) {
const match = /language-(\w+)/.exec(className ?? '');
const lang = match && match[1];
@@ -82,13 +89,14 @@ export const codeNoExecution: React.ElementType = memo(({ className, children }:
return ;
}
});
+codeNoExecution.displayName = 'MarkdownCodeNoExecution';
type TAnchorProps = {
href: string;
children: React.ReactNode;
};
-export const a: React.ElementType = memo(({ href, children }: TAnchorProps) => {
+export const a: React.ElementType = memo(function MarkdownAnchor({ href, children }: TAnchorProps) {
const user = useRecoilValue(store.user);
const { showToast } = useToastContext();
const localize = useLocalize();
@@ -163,14 +171,16 @@ export const a: React.ElementType = memo(({ href, children }: TAnchorProps) => {
);
});
+a.displayName = 'MarkdownAnchor';
type TParagraphProps = {
children: React.ReactNode;
};
-export const p: React.ElementType = memo(({ children }: TParagraphProps) => {
+export const p: React.ElementType = memo(function MarkdownParagraph({ children }: TParagraphProps) {
return {children}
;
});
+p.displayName = 'MarkdownParagraph';
type TImageProps = {
src?: string;
@@ -180,7 +190,13 @@ type TImageProps = {
style?: React.CSSProperties;
};
-export const img: React.ElementType = memo(({ src, alt, title, className, style }: TImageProps) => {
+export const img: React.ElementType = memo(function MarkdownImage({
+ src,
+ alt,
+ title,
+ className,
+ style,
+}: TImageProps) {
// Get the base URL from the API endpoints
const baseURL = apiBaseUrl();
@@ -199,3 +215,4 @@ export const img: React.ElementType = memo(({ src, alt, title, className, style
return ;
});
+img.displayName = 'MarkdownImage';
diff --git a/client/src/components/Chat/Messages/Content/MessageContent.tsx b/client/src/components/Chat/Messages/Content/MessageContent.tsx
index 7a823a07e9..0e2e7faa2c 100644
--- a/client/src/components/Chat/Messages/Content/MessageContent.tsx
+++ b/client/src/components/Chat/Messages/Content/MessageContent.tsx
@@ -185,4 +185,7 @@ const MessageContent = ({
);
};
-export default memo(MessageContent);
+const MemoizedMessageContent = memo(MessageContent);
+MemoizedMessageContent.displayName = 'MessageContent';
+
+export default MemoizedMessageContent;
diff --git a/client/src/components/Chat/Messages/Content/Part.tsx b/client/src/components/Chat/Messages/Content/Part.tsx
index 4a74e3606f..7bce7ac11d 100644
--- a/client/src/components/Chat/Messages/Content/Part.tsx
+++ b/client/src/components/Chat/Messages/Content/Part.tsx
@@ -11,6 +11,7 @@ import type { TMessageContentParts, TAttachment } from 'librechat-data-provider'
import { OpenAIImageGen, EmptyText, Reasoning, ExecuteCode, AgentUpdate, Text } from './Parts';
import { ErrorMessage } from './MessageContent';
import RetrievalCall from './RetrievalCall';
+import { getCachedPreview } from '~/utils';
import AgentHandoff from './AgentHandoff';
import CodeAnalyze from './CodeAnalyze';
import Container from './Container';
@@ -28,201 +29,213 @@ type PartProps = {
attachments?: TAttachment[];
};
-const Part = memo(
- ({ part, isSubmitting, attachments, isLast, showCursor, isCreatedByUser }: PartProps) => {
- if (!part) {
+const Part = memo(function Part({
+ part,
+ isSubmitting,
+ attachments,
+ isLast,
+ showCursor,
+ isCreatedByUser,
+}: PartProps) {
+ if (!part) {
+ return null;
+ }
+
+ if (part.type === ContentTypes.ERROR) {
+ return (
+
+ );
+ } else if (part.type === ContentTypes.AGENT_UPDATE) {
+ return (
+ <>
+
+ {isLast && showCursor && (
+
+
+
+ )}
+ >
+ );
+ } else if (part.type === ContentTypes.TEXT) {
+ const text = typeof part.text === 'string' ? part.text : part.text?.value;
+
+ if (typeof text !== 'string') {
+ return null;
+ }
+ if (part.tool_call_ids != null && !text) {
+ return null;
+ }
+ /** Handle whitespace-only text to avoid layout shift */
+ if (text.length > 0 && /^\s*$/.test(text)) {
+ /** Show placeholder for whitespace-only last part during streaming */
+ if (isLast && showCursor) {
+ return (
+
+
+
+ );
+ }
+ /** Skip rendering non-last whitespace-only parts to avoid empty Container */
+ if (!isLast) {
+ return null;
+ }
+ }
+ return (
+
+
+
+ );
+ } else if (part.type === ContentTypes.THINK) {
+ const reasoning = typeof part.think === 'string' ? part.think : part.think?.value;
+ if (typeof reasoning !== 'string') {
+ return null;
+ }
+ return ;
+ } else if (part.type === ContentTypes.TOOL_CALL) {
+ const toolCall = part[ContentTypes.TOOL_CALL];
+
+ if (!toolCall) {
return null;
}
- if (part.type === ContentTypes.ERROR) {
+ const isToolCall =
+ 'args' in toolCall && (!toolCall.type || toolCall.type === ToolCallTypes.TOOL_CALL);
+ if (
+ isToolCall &&
+ (toolCall.name === Tools.execute_code ||
+ toolCall.name === Constants.PROGRAMMATIC_TOOL_CALLING)
+ ) {
return (
-
);
- } else if (part.type === ContentTypes.AGENT_UPDATE) {
+ } else if (
+ isToolCall &&
+ (toolCall.name === 'image_gen_oai' ||
+ toolCall.name === 'image_edit_oai' ||
+ toolCall.name === 'gemini_image_gen')
+ ) {
return (
- <>
-
- {isLast && showCursor && (
+
+ );
+ } else if (isToolCall && toolCall.name === Tools.web_search) {
+ return (
+
+ );
+ } else if (isToolCall && toolCall.name?.startsWith(Constants.LC_TRANSFER_TO_)) {
+ return (
+
+ );
+ } else if (isToolCall) {
+ return (
+
+ );
+ } else if (toolCall.type === ToolCallTypes.CODE_INTERPRETER) {
+ const code_interpreter = toolCall[ToolCallTypes.CODE_INTERPRETER];
+ return (
+
+ );
+ } else if (
+ toolCall.type === ToolCallTypes.RETRIEVAL ||
+ toolCall.type === ToolCallTypes.FILE_SEARCH
+ ) {
+ return (
+
+ );
+ } else if (
+ toolCall.type === ToolCallTypes.FUNCTION &&
+ ToolCallTypes.FUNCTION in toolCall &&
+ imageGenTools.has(toolCall.function.name)
+ ) {
+ return (
+
+ );
+ } else if (toolCall.type === ToolCallTypes.FUNCTION && ToolCallTypes.FUNCTION in toolCall) {
+ if (isImageVisionTool(toolCall)) {
+ if (isSubmitting && showCursor) {
+ return (
-
+
- )}
- >
- );
- } else if (part.type === ContentTypes.TEXT) {
- const text = typeof part.text === 'string' ? part.text : part.text?.value;
-
- if (typeof text !== 'string') {
- return null;
- }
- if (part.tool_call_ids != null && !text) {
- return null;
- }
- /** Skip rendering if text is only whitespace to avoid empty Container */
- if (!isLast && text.length > 0 && /^\s*$/.test(text)) {
- return null;
- }
- return (
-
-
-
- );
- } else if (part.type === ContentTypes.THINK) {
- const reasoning = typeof part.think === 'string' ? part.think : part.think?.value;
- if (typeof reasoning !== 'string') {
- return null;
- }
- return ;
- } else if (part.type === ContentTypes.TOOL_CALL) {
- const toolCall = part[ContentTypes.TOOL_CALL];
-
- if (!toolCall) {
- return null;
- }
-
- const isToolCall =
- 'args' in toolCall && (!toolCall.type || toolCall.type === ToolCallTypes.TOOL_CALL);
- if (
- isToolCall &&
- (toolCall.name === Tools.execute_code ||
- toolCall.name === Constants.PROGRAMMATIC_TOOL_CALLING)
- ) {
- return (
-
- );
- } else if (
- isToolCall &&
- (toolCall.name === 'image_gen_oai' ||
- toolCall.name === 'image_edit_oai' ||
- toolCall.name === 'gemini_image_gen')
- ) {
- return (
-
- );
- } else if (isToolCall && toolCall.name === Tools.web_search) {
- return (
-
- );
- } else if (isToolCall && toolCall.name?.startsWith(Constants.LC_TRANSFER_TO_)) {
- return (
-
- );
- } else if (isToolCall) {
- return (
-
- );
- } else if (toolCall.type === ToolCallTypes.CODE_INTERPRETER) {
- const code_interpreter = toolCall[ToolCallTypes.CODE_INTERPRETER];
- return (
-
- );
- } else if (
- toolCall.type === ToolCallTypes.RETRIEVAL ||
- toolCall.type === ToolCallTypes.FILE_SEARCH
- ) {
- return (
-
- );
- } else if (
- toolCall.type === ToolCallTypes.FUNCTION &&
- ToolCallTypes.FUNCTION in toolCall &&
- imageGenTools.has(toolCall.function.name)
- ) {
- return (
-
- );
- } else if (toolCall.type === ToolCallTypes.FUNCTION && ToolCallTypes.FUNCTION in toolCall) {
- if (isImageVisionTool(toolCall)) {
- if (isSubmitting && showCursor) {
- return (
-
-
-
- );
- }
- return null;
+ );
}
-
- return (
-
- );
+ return null;
}
- } else if (part.type === ContentTypes.IMAGE_FILE) {
- const imageFile = part[ContentTypes.IMAGE_FILE];
- const height = imageFile.height ?? 1920;
- const width = imageFile.width ?? 1080;
+
return (
-
);
}
+ } else if (part.type === ContentTypes.IMAGE_FILE) {
+ const imageFile = part[ContentTypes.IMAGE_FILE];
+ const cached = imageFile.file_id ? getCachedPreview(imageFile.file_id) : undefined;
+ return (
+
+ );
+ }
- return null;
- },
-);
+ return null;
+});
+Part.displayName = 'Part';
export default Part;
diff --git a/client/src/components/Chat/Messages/Content/Parts/Attachment.tsx b/client/src/components/Chat/Messages/Content/Parts/Attachment.tsx
index b5d1e07cbf..31e30772dc 100644
--- a/client/src/components/Chat/Messages/Content/Parts/Attachment.tsx
+++ b/client/src/components/Chat/Messages/Content/Parts/Attachment.tsx
@@ -76,8 +76,8 @@ const ImageAttachment = memo(({ attachment }: { attachment: TAttachment }) => {
diff --git a/client/src/components/Chat/Messages/Content/Parts/EmptyText.tsx b/client/src/components/Chat/Messages/Content/Parts/EmptyText.tsx
index 1b514164df..409461a058 100644
--- a/client/src/components/Chat/Messages/Content/Parts/EmptyText.tsx
+++ b/client/src/components/Chat/Messages/Content/Parts/EmptyText.tsx
@@ -1,8 +1,9 @@
import { memo } from 'react';
+/** Streaming cursor placeholder — no bottom margin to match Container's structure and prevent CLS */
const EmptyTextPart = memo(() => {
return (
-
+
diff --git a/client/src/components/Chat/Messages/Content/Parts/LogContent.tsx b/client/src/components/Chat/Messages/Content/Parts/LogContent.tsx
index da2a8f175e..a675ff06d8 100644
--- a/client/src/components/Chat/Messages/Content/Parts/LogContent.tsx
+++ b/client/src/components/Chat/Messages/Content/Parts/LogContent.tsx
@@ -12,11 +12,7 @@ interface LogContentProps {
attachments?: TAttachment[];
}
-type ImageAttachment = TFile &
- TAttachmentMetadata & {
- height: number;
- width: number;
- };
+type ImageAttachment = TFile & TAttachmentMetadata;
const LogContent: React.FC = ({ output = '', renderImages, attachments }) => {
const localize = useLocalize();
@@ -35,12 +31,8 @@ const LogContent: React.FC = ({ output = '', renderImages, atta
const nonImageAtts: TAttachment[] = [];
attachments?.forEach((attachment) => {
- const { width, height, filepath = null } = attachment as TFile & TAttachmentMetadata;
- const isImage =
- imageExtRegex.test(attachment.filename ?? '') &&
- width != null &&
- height != null &&
- filepath != null;
+ const { filepath = null } = attachment as TFile & TAttachmentMetadata;
+ const isImage = imageExtRegex.test(attachment.filename ?? '') && filepath != null;
if (isImage) {
imageAtts.push(attachment as ImageAttachment);
} else {
@@ -100,18 +92,15 @@ const LogContent: React.FC = ({ output = '', renderImages, atta
))}
)}
- {imageAttachments?.map((attachment, index) => {
- const { width, height, filepath } = attachment;
- return (
-
- );
- })}
+ {imageAttachments?.map((attachment) => (
+
+ ))}
>
);
};
diff --git a/client/src/components/Chat/Messages/Content/Parts/OpenAIImageGen/OpenAIImageGen.tsx b/client/src/components/Chat/Messages/Content/Parts/OpenAIImageGen/OpenAIImageGen.tsx
index aa1b07827b..bdce6d3209 100644
--- a/client/src/components/Chat/Messages/Content/Parts/OpenAIImageGen/OpenAIImageGen.tsx
+++ b/client/src/components/Chat/Messages/Content/Parts/OpenAIImageGen/OpenAIImageGen.tsx
@@ -1,9 +1,12 @@
-import { useState, useEffect, useRef, useCallback } from 'react';
+import { useState, useEffect, useRef } from 'react';
import { PixelCard } from '@librechat/client';
import type { TAttachment, TFile, TAttachmentMetadata } from 'librechat-data-provider';
import Image from '~/components/Chat/Messages/Content/Image';
import ProgressText from './ProgressText';
-import { scaleImage } from '~/utils';
+import { cn } from '~/utils';
+
+const IMAGE_MAX_H = 'max-h-[45vh]' as const;
+const IMAGE_FULL_H = 'h-[45vh]' as const;
export default function OpenAIImageGen({
initialProgress = 0.1,
@@ -28,8 +31,6 @@ export default function OpenAIImageGen({
const cancelled = (!isSubmitting && initialProgress < 1) || error === true;
- let width: number | undefined;
- let height: number | undefined;
let quality: 'low' | 'medium' | 'high' = 'high';
// Parse args if it's a string
@@ -41,62 +42,21 @@ export default function OpenAIImageGen({
parsedArgs = {};
}
- try {
- const argsObj = parsedArgs;
-
- if (argsObj && typeof argsObj.size === 'string') {
- const [w, h] = argsObj.size.split('x').map((v: string) => parseInt(v, 10));
- if (!isNaN(w) && !isNaN(h)) {
- width = w;
- height = h;
- }
- } else if (argsObj && (typeof argsObj.size !== 'string' || !argsObj.size)) {
- width = undefined;
- height = undefined;
+ if (parsedArgs && typeof parsedArgs.quality === 'string') {
+ const q = parsedArgs.quality.toLowerCase();
+ if (q === 'low' || q === 'medium' || q === 'high') {
+ quality = q;
}
-
- if (argsObj && typeof argsObj.quality === 'string') {
- const q = argsObj.quality.toLowerCase();
- if (q === 'low' || q === 'medium' || q === 'high') {
- quality = q;
- }
- }
- } catch (e) {
- width = undefined;
- height = undefined;
}
- // Default to 1024x1024 if width and height are still undefined after parsing args and attachment metadata
const attachment = attachments?.[0];
const {
- width: imageWidth,
- height: imageHeight,
filepath = null,
filename = '',
+ width: imgWidth,
+ height: imgHeight,
} = (attachment as TFile & TAttachmentMetadata) || {};
- let origWidth = width ?? imageWidth;
- let origHeight = height ?? imageHeight;
-
- if (origWidth === undefined || origHeight === undefined) {
- origWidth = 1024;
- origHeight = 1024;
- }
-
- const [dimensions, setDimensions] = useState({ width: 'auto', height: 'auto' });
- const containerRef = useRef
(null);
-
- const updateDimensions = useCallback(() => {
- if (origWidth && origHeight && containerRef.current) {
- const scaled = scaleImage({
- originalWidth: origWidth,
- originalHeight: origHeight,
- containerRef,
- });
- setDimensions(scaled);
- }
- }, [origWidth, origHeight]);
-
useEffect(() => {
if (isSubmitting) {
setProgress(initialProgress);
@@ -156,45 +116,21 @@ export default function OpenAIImageGen({
}
}, [initialProgress, cancelled]);
- useEffect(() => {
- updateDimensions();
-
- const resizeObserver = new ResizeObserver(() => {
- updateDimensions();
- });
-
- if (containerRef.current) {
- resizeObserver.observe(containerRef.current);
- }
-
- return () => {
- resizeObserver.disconnect();
- };
- }, [updateDimensions]);
-
return (
<>
-
-
- {dimensions.width !== 'auto' && progress < 1 && (
-
- )}
+
diff --git a/client/src/components/Chat/Messages/Content/Parts/Reasoning.tsx b/client/src/components/Chat/Messages/Content/Parts/Reasoning.tsx
index 85d1b00b4b..44d646fcd8 100644
--- a/client/src/components/Chat/Messages/Content/Parts/Reasoning.tsx
+++ b/client/src/components/Chat/Messages/Content/Parts/Reasoning.tsx
@@ -1,4 +1,4 @@
-import { memo, useMemo, useState, useCallback, useRef } from 'react';
+import { memo, useMemo, useState, useCallback, useRef, useId } from 'react';
import { useAtom } from 'jotai';
import type { MouseEvent, FocusEvent } from 'react';
import { ContentTypes } from 'librechat-data-provider';
@@ -36,6 +36,7 @@ type ReasoningProps = {
* For legacy text-based messages, see Thinking.tsx component.
*/
const Reasoning = memo(({ reasoning, isLast }: ReasoningProps) => {
+ const contentId = useId();
const localize = useLocalize();
const [showThinking] = useAtom(showThinkingAtom);
const [isExpanded, setIsExpanded] = useState(showThinking);
@@ -104,9 +105,14 @@ const Reasoning = memo(({ reasoning, isLast }: ReasoningProps) => {
onClick={handleClick}
label={label}
content={reasoningText}
+ contentId={contentId}
/>
{
isExpanded={isExpanded}
onClick={handleClick}
content={reasoningText}
+ contentId={contentId}
/>
diff --git a/client/src/components/Chat/Messages/Content/Parts/Text.tsx b/client/src/components/Chat/Messages/Content/Parts/Text.tsx
index c926622c9d..aec8d949e0 100644
--- a/client/src/components/Chat/Messages/Content/Parts/Text.tsx
+++ b/client/src/components/Chat/Messages/Content/Parts/Text.tsx
@@ -17,7 +17,7 @@ type ContentType =
| ReactElement>
| ReactElement;
-const TextPart = memo(({ text, isCreatedByUser, showCursor }: TextPartProps) => {
+const TextPart = memo(function TextPart({ text, isCreatedByUser, showCursor }: TextPartProps) {
const { isSubmitting = false, isLatestMessage = false } = useMessageContext();
const enableUserMsgMarkdown = useRecoilValue(store.enableUserMsgMarkdown);
const showCursorState = useMemo(() => showCursor && isSubmitting, [showCursor, isSubmitting]);
@@ -46,5 +46,6 @@ const TextPart = memo(({ text, isCreatedByUser, showCursor }: TextPartProps) =>
);
});
+TextPart.displayName = 'TextPart';
export default TextPart;
diff --git a/client/src/components/Chat/Messages/Content/Parts/Thinking.tsx b/client/src/components/Chat/Messages/Content/Parts/Thinking.tsx
index 0c5992f4ab..7641738c15 100644
--- a/client/src/components/Chat/Messages/Content/Parts/Thinking.tsx
+++ b/client/src/components/Chat/Messages/Content/Parts/Thinking.tsx
@@ -1,4 +1,4 @@
-import { useState, useMemo, memo, useCallback, useRef, type MouseEvent } from 'react';
+import { useState, useMemo, memo, useCallback, useRef, useId, type MouseEvent } from 'react';
import { useAtomValue } from 'jotai';
import { Clipboard, CheckMark, TooltipAnchor } from '@librechat/client';
import { Lightbulb, ChevronDown, ChevronUp } from 'lucide-react';
@@ -35,12 +35,14 @@ export const ThinkingButton = memo(
onClick,
label,
content,
+ contentId,
showCopyButton = true,
}: {
isExpanded: boolean;
onClick: (e: MouseEvent
) => void;
label: string;
content?: string;
+ contentId: string;
showCopyButton?: boolean;
}) => {
const localize = useLocalize();
@@ -66,6 +68,7 @@ export const ThinkingButton = memo(
type="button"
onClick={onClick}
aria-expanded={isExpanded}
+ aria-controls={contentId}
className={cn(
'group/button flex flex-1 items-center justify-start rounded-lg leading-[18px]',
fontSize,
@@ -132,11 +135,13 @@ export const FloatingThinkingBar = memo(
isExpanded,
onClick,
content,
+ contentId,
}: {
isVisible: boolean;
isExpanded: boolean;
onClick: (e: MouseEvent) => void;
content?: string;
+ contentId: string;
}) => {
const localize = useLocalize();
const [isCopied, setIsCopied] = useState(false);
@@ -176,6 +181,8 @@ export const FloatingThinkingBar = memo(
tabIndex={isVisible ? 0 : -1}
onClick={onClick}
aria-label={collapseTooltip}
+ aria-expanded={isExpanded}
+ aria-controls={contentId}
className={cn(
'flex items-center justify-center rounded-lg bg-surface-secondary p-1.5 text-text-secondary-alt shadow-sm',
'hover:bg-surface-hover hover:text-text-primary',
@@ -240,6 +247,7 @@ const Thinking: React.ElementType = memo(({ children }: { children: React.ReactN
const [isExpanded, setIsExpanded] = useState(showThinking);
const [isBarVisible, setIsBarVisible] = useState(false);
const containerRef = useRef(null);
+ const contentId = useId();
const handleClick = useCallback((e: MouseEvent) => {
e.preventDefault();
@@ -295,9 +303,14 @@ const Thinking: React.ElementType = memo(({ children }: { children: React.ReactN
onClick={handleClick}
label={label}
content={textContent}
+ contentId={contentId}
/>
@@ -322,4 +336,4 @@ ThinkingContent.displayName = 'ThinkingContent';
FloatingThinkingBar.displayName = 'FloatingThinkingBar';
Thinking.displayName = 'Thinking';
-export default memo(Thinking);
+export default Thinking;
diff --git a/client/src/components/Chat/Messages/Content/__tests__/Image.test.tsx b/client/src/components/Chat/Messages/Content/__tests__/Image.test.tsx
new file mode 100644
index 0000000000..e7e0b99f1e
--- /dev/null
+++ b/client/src/components/Chat/Messages/Content/__tests__/Image.test.tsx
@@ -0,0 +1,179 @@
+import React from 'react';
+import { render, screen, fireEvent } from '@testing-library/react';
+import Image, { _resetImageCaches } from '../Image';
+
+jest.mock('~/utils', () => ({
+ cn: (...classes: (string | boolean | undefined | null)[]) =>
+ classes
+ .flat(Infinity)
+ .filter((c): c is string => typeof c === 'string' && c.length > 0)
+ .join(' '),
+}));
+
+jest.mock('librechat-data-provider', () => ({
+ apiBaseUrl: () => '',
+}));
+
+jest.mock('@librechat/client', () => ({
+ Skeleton: ({ className, ...props }: React.HTMLAttributes) => (
+
+ ),
+}));
+
+jest.mock('../DialogImage', () => ({
+ __esModule: true,
+ default: ({ isOpen, src }: { isOpen: boolean; src: string }) =>
+ isOpen ?
: null,
+}));
+
+describe('Image', () => {
+ const defaultProps = {
+ imagePath: '/images/test.png',
+ altText: 'Test image',
+ };
+
+ beforeEach(() => {
+ _resetImageCaches();
+ jest.clearAllMocks();
+ });
+
+ describe('rendering without dimensions', () => {
+ it('renders with max-h-[45vh] height constraint', () => {
+ render( );
+ const img = screen.getByRole('img');
+ expect(img.className).toContain('max-h-[45vh]');
+ });
+
+ it('renders with max-w-full to prevent landscape clipping', () => {
+ render( );
+ const img = screen.getByRole('img');
+ expect(img.className).toContain('max-w-full');
+ });
+
+ it('renders with w-auto and h-auto for natural aspect ratio', () => {
+ render( );
+ const img = screen.getByRole('img');
+ expect(img.className).toContain('w-auto');
+ expect(img.className).toContain('h-auto');
+ });
+
+ it('does not show skeleton without dimensions', () => {
+ render( );
+ expect(screen.queryByTestId('skeleton')).not.toBeInTheDocument();
+ });
+
+ it('does not apply heightStyle without dimensions', () => {
+ render( );
+ const button = screen.getByRole('button');
+ expect(button.style.height).toBeFalsy();
+ });
+ });
+
+ describe('rendering with dimensions', () => {
+ it('shows skeleton behind image', () => {
+ render( );
+ expect(screen.getByTestId('skeleton')).toBeInTheDocument();
+ });
+
+ it('applies computed heightStyle to button', () => {
+ render( );
+ const button = screen.getByRole('button');
+ expect(button.style.height).toBeTruthy();
+ expect(button.style.height).toContain('min(45vh');
+ });
+
+ it('uses size-full object-contain on image when dimensions provided', () => {
+ render( );
+ const img = screen.getByRole('img');
+ expect(img.className).toContain('size-full');
+ expect(img.className).toContain('object-contain');
+ });
+
+ it('skeleton is absolute inset-0', () => {
+ render( );
+ const skeleton = screen.getByTestId('skeleton');
+ expect(skeleton.className).toContain('absolute');
+ expect(skeleton.className).toContain('inset-0');
+ });
+
+ it('marks URL as painted on load and skips skeleton on rerender', () => {
+ const { rerender } = render( );
+ const img = screen.getByRole('img');
+
+ expect(screen.getByTestId('skeleton')).toBeInTheDocument();
+
+ fireEvent.load(img);
+
+ // Rerender same component — skeleton should not show (URL painted)
+ rerender( );
+ expect(screen.queryByTestId('skeleton')).not.toBeInTheDocument();
+ });
+ });
+
+ describe('common behavior', () => {
+ it('applies custom className to the button wrapper', () => {
+ render( );
+ const button = screen.getByRole('button');
+ expect(button.className).toContain('mb-4');
+ });
+
+ it('sets correct alt text', () => {
+ render( );
+ const img = screen.getByRole('img');
+ expect(img).toHaveAttribute('alt', 'Test image');
+ });
+
+ it('has correct accessibility attributes on button', () => {
+ render( );
+ const button = screen.getByRole('button');
+ expect(button).toHaveAttribute('aria-label', 'View Test image in dialog');
+ expect(button).toHaveAttribute('aria-haspopup', 'dialog');
+ });
+ });
+
+ describe('dialog interaction', () => {
+ it('opens dialog on button click', () => {
+ render( );
+ expect(screen.queryByTestId('dialog-image')).not.toBeInTheDocument();
+
+ const button = screen.getByRole('button');
+ fireEvent.click(button);
+
+ expect(screen.getByTestId('dialog-image')).toBeInTheDocument();
+ });
+
+ it('dialog is always mounted (not gated by load state)', () => {
+ render( );
+ // DialogImage mock returns null when isOpen=false, but the component is in the tree
+ // Clicking should immediately show it
+ fireEvent.click(screen.getByRole('button'));
+ expect(screen.getByTestId('dialog-image')).toBeInTheDocument();
+ });
+ });
+
+ describe('image URL resolution', () => {
+ it('passes /images/ paths through with base URL', () => {
+ render( );
+ const img = screen.getByRole('img');
+ expect(img).toHaveAttribute('src', '/images/test.png');
+ });
+
+ it('passes absolute http URLs through unchanged', () => {
+ render( );
+ const img = screen.getByRole('img');
+ expect(img).toHaveAttribute('src', 'https://example.com/photo.jpg');
+ });
+
+ it('passes data URIs through unchanged', () => {
+ render( );
+ const img = screen.getByRole('img');
+ expect(img).toHaveAttribute('src', 'data:image/png;base64,abc');
+ });
+
+ it('passes non-/images/ paths through unchanged', () => {
+ render( );
+ const img = screen.getByRole('img');
+ expect(img).toHaveAttribute('src', '/other/path.png');
+ });
+ });
+});
diff --git a/client/src/components/Chat/Messages/Content/__tests__/OpenAIImageGen.test.tsx b/client/src/components/Chat/Messages/Content/__tests__/OpenAIImageGen.test.tsx
new file mode 100644
index 0000000000..ef8ac2807a
--- /dev/null
+++ b/client/src/components/Chat/Messages/Content/__tests__/OpenAIImageGen.test.tsx
@@ -0,0 +1,182 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import OpenAIImageGen from '../Parts/OpenAIImageGen/OpenAIImageGen';
+
+jest.mock('~/utils', () => ({
+ cn: (...classes: (string | boolean | undefined | null)[]) =>
+ classes
+ .flat(Infinity)
+ .filter((c): c is string => typeof c === 'string' && c.length > 0)
+ .join(' '),
+}));
+
+jest.mock('~/hooks', () => ({
+ useLocalize: () => (key: string) => key,
+}));
+
+jest.mock('~/components/Chat/Messages/Content/Image', () => ({
+ __esModule: true,
+ default: ({
+ altText,
+ imagePath,
+ className,
+ }: {
+ altText: string;
+ imagePath: string;
+ className?: string;
+ }) => (
+
+ ),
+}));
+
+jest.mock('@librechat/client', () => ({
+ PixelCard: ({ progress }: { progress: number }) => (
+
+ ),
+}));
+
+jest.mock('../Parts/OpenAIImageGen/ProgressText', () => ({
+ __esModule: true,
+ default: ({ progress, error }: { progress: number; error: boolean }) => (
+
+ ),
+}));
+
+describe('OpenAIImageGen', () => {
+ const defaultProps = {
+ initialProgress: 0.1,
+ isSubmitting: true,
+ toolName: 'image_gen_oai',
+ args: '{"prompt":"a cat","quality":"high","size":"1024x1024"}',
+ output: null as string | null,
+ attachments: undefined,
+ };
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ jest.useFakeTimers();
+ });
+
+ afterEach(() => {
+ jest.useRealTimers();
+ });
+
+ describe('image preloading', () => {
+ it('keeps Image mounted during generation (progress < 1)', () => {
+ render( );
+ expect(screen.getByTestId('image-component')).toBeInTheDocument();
+ });
+
+ it('hides Image with invisible absolute while progress < 1', () => {
+ render( );
+ const image = screen.getByTestId('image-component');
+ expect(image.className).toContain('invisible');
+ expect(image.className).toContain('absolute');
+ });
+
+ it('shows Image without hiding classes when progress >= 1', () => {
+ render(
+ ,
+ );
+ const image = screen.getByTestId('image-component');
+ expect(image.className).not.toContain('invisible');
+ expect(image.className).not.toContain('absolute');
+ });
+ });
+
+ describe('PixelCard visibility', () => {
+ it('shows PixelCard when progress < 1', () => {
+ render( );
+ expect(screen.getByTestId('pixel-card')).toBeInTheDocument();
+ });
+
+ it('hides PixelCard when progress >= 1', () => {
+ render( );
+ expect(screen.queryByTestId('pixel-card')).not.toBeInTheDocument();
+ });
+ });
+
+ describe('layout classes', () => {
+ it('applies max-h-[45vh] to the outer container', () => {
+ const { container } = render( );
+ const outerDiv = container.querySelector('[class*="max-h-"]');
+ expect(outerDiv?.className).toContain('max-h-[45vh]');
+ });
+
+ it('applies h-[45vh] w-full to inner container during loading', () => {
+ const { container } = render( );
+ const innerDiv = container.querySelector('[class*="h-[45vh]"]');
+ expect(innerDiv).not.toBeNull();
+ expect(innerDiv?.className).toContain('w-full');
+ });
+
+ it('applies w-auto to inner container when complete', () => {
+ const { container } = render(
+ ,
+ );
+ const overflowDiv = container.querySelector('[class*="overflow-hidden"]');
+ expect(overflowDiv?.className).toContain('w-auto');
+ });
+ });
+
+ describe('args parsing', () => {
+ it('parses quality from args', () => {
+ render( );
+ expect(screen.getByTestId('progress-text')).toBeInTheDocument();
+ });
+
+ it('handles invalid JSON args gracefully', () => {
+ const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
+ render( );
+ expect(screen.getByTestId('image-component')).toBeInTheDocument();
+ consoleSpy.mockRestore();
+ });
+
+ it('handles object args', () => {
+ render(
+ ,
+ );
+ expect(screen.getByTestId('image-component')).toBeInTheDocument();
+ });
+ });
+
+ describe('cancellation', () => {
+ it('shows error state when output contains error', () => {
+ render(
+ ,
+ );
+ const progressText = screen.getByTestId('progress-text');
+ expect(progressText).toHaveAttribute('data-error', 'true');
+ });
+
+ it('shows cancelled state when not submitting and incomplete', () => {
+ render( );
+ const progressText = screen.getByTestId('progress-text');
+ expect(progressText).toHaveAttribute('data-error', 'true');
+ });
+ });
+});
diff --git a/client/src/components/Chat/Messages/HoverButtons.tsx b/client/src/components/Chat/Messages/HoverButtons.tsx
index 5d60223d08..180e8b599e 100644
--- a/client/src/components/Chat/Messages/HoverButtons.tsx
+++ b/client/src/components/Chat/Messages/HoverButtons.tsx
@@ -18,7 +18,7 @@ type THoverButtons = {
message: TMessage;
regenerate: () => void;
handleContinue: (e: React.MouseEvent) => void;
- latestMessage: TMessage | null;
+ latestMessageId?: string;
isLast: boolean;
index: number;
handleFeedback?: ({ feedback }: { feedback: TFeedback | undefined }) => void;
@@ -119,7 +119,7 @@ const HoverButtons = ({
message,
regenerate,
handleContinue,
- latestMessage,
+ latestMessageId,
isLast,
handleFeedback,
}: THoverButtons) => {
@@ -143,7 +143,7 @@ const HoverButtons = ({
searchResult: message.searchResult,
finish_reason: message.finish_reason,
isCreatedByUser: message.isCreatedByUser,
- latestMessageId: latestMessage?.messageId,
+ latestMessageId: latestMessageId,
});
const {
@@ -239,7 +239,7 @@ const HoverButtons = ({
messageId={message.messageId}
conversationId={conversation.conversationId}
forkingSupported={forkingSupported}
- latestMessageId={latestMessage?.messageId}
+ latestMessageId={latestMessageId}
isLast={isLast}
/>
diff --git a/client/src/components/Chat/Messages/Message.tsx b/client/src/components/Chat/Messages/Message.tsx
index 78e08e3631..f9db38fdab 100644
--- a/client/src/components/Chat/Messages/Message.tsx
+++ b/client/src/components/Chat/Messages/Message.tsx
@@ -4,25 +4,23 @@ import type { TMessageProps } from '~/common';
import MessageRender from './ui/MessageRender';
import MultiMessage from './MultiMessage';
-const MessageContainer = React.memo(
- ({
- handleScroll,
- children,
- }: {
- handleScroll: (event?: unknown) => void;
- children: React.ReactNode;
- }) => {
- return (
-
- {children}
-
- );
- },
-);
+const MessageContainer = React.memo(function MessageContainer({
+ handleScroll,
+ children,
+}: {
+ handleScroll: (event?: unknown) => void;
+ children: React.ReactNode;
+}) {
+ return (
+
+ {children}
+
+ );
+});
export default function Message(props: TMessageProps) {
const { conversation, handleScroll } = useMessageProcess({
diff --git a/client/src/components/Chat/Messages/MessageParts.tsx b/client/src/components/Chat/Messages/MessageParts.tsx
index 0005ee0499..7aa73a54e6 100644
--- a/client/src/components/Chat/Messages/MessageParts.tsx
+++ b/client/src/components/Chat/Messages/MessageParts.tsx
@@ -32,7 +32,7 @@ export default function Message(props: TMessageProps) {
handleScroll,
conversation,
isSubmitting,
- latestMessage,
+ latestMessageId,
handleContinue,
copyToClipboard,
regenerateMessage,
@@ -129,7 +129,7 @@ export default function Message(props: TMessageProps) {
)}
-
+
}
/>
{isLast && isSubmitting ? (
-
+
) : (
regenerateMessage()}
copyToClipboard={copyToClipboard}
handleContinue={handleContinue}
- latestMessage={latestMessage}
+ latestMessageId={latestMessageId}
isLast={isLast}
/>
diff --git a/client/src/components/Chat/Messages/ui/MessageRender.tsx b/client/src/components/Chat/Messages/ui/MessageRender.tsx
index 0d40b4a98f..e261a576bd 100644
--- a/client/src/components/Chat/Messages/ui/MessageRender.tsx
+++ b/client/src/components/Chat/Messages/ui/MessageRender.tsx
@@ -4,11 +4,11 @@ import { useRecoilValue } from 'recoil';
import { type TMessage } from 'librechat-data-provider';
import type { TMessageProps, TMessageIcon } from '~/common';
import MessageContent from '~/components/Chat/Messages/Content/MessageContent';
+import { useLocalize, useMessageActions, useContentMetadata } from '~/hooks';
import PlaceholderRow from '~/components/Chat/Messages/ui/PlaceholderRow';
import SiblingSwitch from '~/components/Chat/Messages/SiblingSwitch';
import HoverButtons from '~/components/Chat/Messages/HoverButtons';
import MessageIcon from '~/components/Chat/Messages/MessageIcon';
-import { useLocalize, useMessageActions, useContentMetadata } from '~/hooks';
import SubRow from '~/components/Chat/Messages/SubRow';
import { cn, getMessageAriaLabel } from '~/utils';
import { fontSizeAtom } from '~/store/fontSize';
@@ -23,180 +23,183 @@ type MessageRenderProps = {
'currentEditId' | 'setCurrentEditId' | 'siblingIdx' | 'setSiblingIdx' | 'siblingCount'
>;
-const MessageRender = memo(
- ({
+const MessageRender = memo(function MessageRender({
+ message: msg,
+ siblingIdx,
+ siblingCount,
+ setSiblingIdx,
+ currentEditId,
+ setCurrentEditId,
+ isSubmitting = false,
+}: MessageRenderProps) {
+ const localize = useLocalize();
+ const {
+ ask,
+ edit,
+ index,
+ agent,
+ assistant,
+ enterEdit,
+ conversation,
+ messageLabel,
+ handleFeedback,
+ handleContinue,
+ latestMessageId,
+ copyToClipboard,
+ regenerateMessage,
+ latestMessageDepth,
+ } = useMessageActions({
message: msg,
- siblingIdx,
- siblingCount,
- setSiblingIdx,
currentEditId,
setCurrentEditId,
- isSubmitting = false,
- }: MessageRenderProps) => {
- const localize = useLocalize();
- const {
- ask,
- edit,
- index,
- agent,
- assistant,
- enterEdit,
- conversation,
+ });
+ const fontSize = useAtomValue(fontSizeAtom);
+ const maximizeChatSpace = useRecoilValue(store.maximizeChatSpace);
+
+ const handleRegenerateMessage = useCallback(() => regenerateMessage(), [regenerateMessage]);
+ const hasNoChildren = !(msg?.children?.length ?? 0);
+ const isLast = useMemo(
+ () => hasNoChildren && (msg?.depth === latestMessageDepth || msg?.depth === -1),
+ [hasNoChildren, msg?.depth, latestMessageDepth],
+ );
+ const isLatestMessage = msg?.messageId === latestMessageId;
+ /** Only pass isSubmitting to the latest message to prevent unnecessary re-renders */
+ const effectiveIsSubmitting = isLatestMessage ? isSubmitting : false;
+
+ const iconData: TMessageIcon = useMemo(
+ () => ({
+ endpoint: msg?.endpoint ?? conversation?.endpoint,
+ model: msg?.model ?? conversation?.model,
+ iconURL: msg?.iconURL,
+ modelLabel: messageLabel,
+ isCreatedByUser: msg?.isCreatedByUser,
+ }),
+ [
messageLabel,
- latestMessage,
- handleFeedback,
- handleContinue,
- copyToClipboard,
- regenerateMessage,
- } = useMessageActions({
- message: msg,
- currentEditId,
- setCurrentEditId,
- });
- const fontSize = useAtomValue(fontSizeAtom);
- const maximizeChatSpace = useRecoilValue(store.maximizeChatSpace);
+ conversation?.endpoint,
+ conversation?.model,
+ msg?.model,
+ msg?.iconURL,
+ msg?.endpoint,
+ msg?.isCreatedByUser,
+ ],
+ );
- const handleRegenerateMessage = useCallback(() => regenerateMessage(), [regenerateMessage]);
- const hasNoChildren = !(msg?.children?.length ?? 0);
- const isLast = useMemo(
- () => hasNoChildren && (msg?.depth === latestMessage?.depth || msg?.depth === -1),
- [hasNoChildren, msg?.depth, latestMessage?.depth],
- );
- const isLatestMessage = msg?.messageId === latestMessage?.messageId;
- /** Only pass isSubmitting to the latest message to prevent unnecessary re-renders */
- const effectiveIsSubmitting = isLatestMessage ? isSubmitting : false;
+ const { hasParallelContent } = useContentMetadata(msg);
+ const messageId = msg?.messageId ?? '';
+ const messageContextValue = useMemo(
+ () => ({
+ messageId,
+ isLatestMessage,
+ isExpanded: false as const,
+ isSubmitting: effectiveIsSubmitting,
+ conversationId: conversation?.conversationId,
+ }),
+ [messageId, conversation?.conversationId, effectiveIsSubmitting, isLatestMessage],
+ );
- const iconData: TMessageIcon = useMemo(
- () => ({
- endpoint: msg?.endpoint ?? conversation?.endpoint,
- model: msg?.model ?? conversation?.model,
- iconURL: msg?.iconURL,
- modelLabel: messageLabel,
- isCreatedByUser: msg?.isCreatedByUser,
- }),
- [
- messageLabel,
- conversation?.endpoint,
- conversation?.model,
- msg?.model,
- msg?.iconURL,
- msg?.endpoint,
- msg?.isCreatedByUser,
- ],
- );
+ if (!msg) {
+ return null;
+ }
- const { hasParallelContent } = useContentMetadata(msg);
-
- if (!msg) {
- return null;
+ const getChatWidthClass = () => {
+ if (maximizeChatSpace) {
+ return 'w-full max-w-full md:px-5 lg:px-1 xl:px-5';
}
+ if (hasParallelContent) {
+ return 'md:max-w-[58rem] xl:max-w-[70rem]';
+ }
+ return 'md:max-w-[47rem] xl:max-w-[55rem]';
+ };
- const getChatWidthClass = () => {
- if (maximizeChatSpace) {
- return 'w-full max-w-full md:px-5 lg:px-1 xl:px-5';
- }
- if (hasParallelContent) {
- return 'md:max-w-[58rem] xl:max-w-[70rem]';
- }
- return 'md:max-w-[47rem] xl:max-w-[55rem]';
- };
+ const baseClasses = {
+ common: 'group mx-auto flex flex-1 gap-3 transition-all duration-300 transform-gpu ',
+ chat: getChatWidthClass(),
+ };
- const baseClasses = {
- common: 'group mx-auto flex flex-1 gap-3 transition-all duration-300 transform-gpu ',
- chat: getChatWidthClass(),
- };
+ const conditionalClasses = {
+ focus: 'focus:outline-none focus:ring-2 focus:ring-border-xheavy',
+ };
- const conditionalClasses = {
- focus: 'focus:outline-none focus:ring-2 focus:ring-border-xheavy',
- };
+ return (
+
+ {!hasParallelContent && (
+
+ )}
- return (
{!hasParallelContent && (
-
+
{messageLabel}
)}
-
- {!hasParallelContent && (
-
{messageLabel}
- )}
-
-
-
-
- ({}))}
- />
-
-
- {hasNoChildren && effectiveIsSubmitting ? (
-
- ) : (
-
-
-
-
- )}
+
+
+
+ ({}))}
+ />
+
+ {hasNoChildren && effectiveIsSubmitting ? (
+
+ ) : (
+
+
+
+
+ )}
- );
- },
-);
+
+ );
+});
+MessageRender.displayName = 'MessageRender';
export default MessageRender;
diff --git a/client/src/components/Chat/Messages/ui/PlaceholderRow.tsx b/client/src/components/Chat/Messages/ui/PlaceholderRow.tsx
index d67424a46f..e60dc28278 100644
--- a/client/src/components/Chat/Messages/ui/PlaceholderRow.tsx
+++ b/client/src/components/Chat/Messages/ui/PlaceholderRow.tsx
@@ -1,7 +1,9 @@
import { memo } from 'react';
-const PlaceholderRow = memo(() => {
- return
;
+/** Height matches the SubRow action buttons row (31px) — keep in sync with HoverButtons */
+const PlaceholderRow = memo(function PlaceholderRow() {
+ return
;
});
+PlaceholderRow.displayName = 'PlaceholderRow';
export default PlaceholderRow;
diff --git a/client/src/components/Chat/TemporaryChat.tsx b/client/src/components/Chat/TemporaryChat.tsx
index d09cc73289..a4d72d081e 100644
--- a/client/src/components/Chat/TemporaryChat.tsx
+++ b/client/src/components/Chat/TemporaryChat.tsx
@@ -1,8 +1,8 @@
import React from 'react';
+import { useRecoilValue } from 'recoil';
import { TooltipAnchor } from '@librechat/client';
import { MessageCircleDashed } from 'lucide-react';
import { useRecoilState, useRecoilCallback } from 'recoil';
-import { useChatContext } from '~/Providers';
import { useLocalize } from '~/hooks';
import { cn } from '~/utils';
import store from '~/store';
@@ -10,13 +10,8 @@ import store from '~/store';
export function TemporaryChat() {
const localize = useLocalize();
const [isTemporary, setIsTemporary] = useRecoilState(store.isTemporary);
- const { conversation, isSubmitting } = useChatContext();
-
- const temporaryBadge = {
- id: 'temporary',
- atom: store.isTemporary,
- isAvailable: true,
- };
+ const conversation = useRecoilValue(store.conversationByIndex(0));
+ const isSubmitting = useRecoilValue(store.isSubmittingFamily(0));
const handleBadgeToggle = useRecoilCallback(
() => () => {
diff --git a/client/src/components/Conversations/Conversations.tsx b/client/src/components/Conversations/Conversations.tsx
index fc66c0977a..c7eb4d53ef 100644
--- a/client/src/components/Conversations/Conversations.tsx
+++ b/client/src/components/Conversations/Conversations.tsx
@@ -384,6 +384,7 @@ const Conversations: FC
= ({
onRowsRendered={handleRowsRendered}
tabIndex={-1}
style={{ outline: 'none', scrollbarGutter: 'stable' }}
+ containerRole="rowgroup"
/>
)}
diff --git a/client/src/components/Endpoints/Icon.tsx b/client/src/components/Endpoints/Icon.tsx
index 3256145bfb..fae0f286d3 100644
--- a/client/src/components/Endpoints/Icon.tsx
+++ b/client/src/components/Endpoints/Icon.tsx
@@ -1,64 +1,102 @@
-import React, { memo, useState } from 'react';
+import React, { memo } from 'react';
import { UserIcon, useAvatar } from '@librechat/client';
-import type { TUser } from 'librechat-data-provider';
import type { IconProps } from '~/common';
import MessageEndpointIcon from './MessageEndpointIcon';
import { useAuthContext } from '~/hooks/AuthContext';
import { useLocalize } from '~/hooks';
import { cn } from '~/utils';
+type ResolvedAvatar = { type: 'image'; src: string } | { type: 'fallback' };
+
+/**
+ * Caches the resolved avatar decision per user ID.
+ * Invalidated when `user.avatar` changes (e.g., settings upload).
+ * Tracks failed image URLs so they fall back to SVG permanently for the session.
+ */
+const avatarCache = new Map<
+ string,
+ { avatar: string; avatarSrc: string; resolved: ResolvedAvatar }
+>();
+const failedUrls = new Set();
+
+function resolveAvatar(userId: string, userAvatar: string, avatarSrc: string): ResolvedAvatar {
+ if (!userId) {
+ const imgSrc = userAvatar || avatarSrc;
+ return imgSrc && !failedUrls.has(imgSrc)
+ ? { type: 'image', src: imgSrc }
+ : { type: 'fallback' };
+ }
+
+ const cached = avatarCache.get(userId);
+ if (cached && cached.avatar === userAvatar && cached.avatarSrc === avatarSrc) {
+ return cached.resolved;
+ }
+
+ const imgSrc = userAvatar || avatarSrc;
+ const resolved: ResolvedAvatar =
+ imgSrc && !failedUrls.has(imgSrc) ? { type: 'image', src: imgSrc } : { type: 'fallback' };
+
+ avatarCache.set(userId, { avatar: userAvatar, avatarSrc, resolved });
+ return resolved;
+}
+
+function markAvatarFailed(userId: string, src: string): ResolvedAvatar {
+ failedUrls.add(src);
+ const fallback: ResolvedAvatar = { type: 'fallback' };
+ const cached = avatarCache.get(userId);
+ if (cached) {
+ avatarCache.set(userId, { ...cached, resolved: fallback });
+ }
+ return fallback;
+}
+
type UserAvatarProps = {
size: number;
- user?: TUser;
+ avatar: string;
avatarSrc: string;
+ userId: string;
username: string;
className?: string;
};
-const UserAvatar = memo(({ size, user, avatarSrc, username, className }: UserAvatarProps) => {
- const [imageError, setImageError] = useState(false);
+const UserAvatar = memo(
+ ({ size, avatar, avatarSrc, userId, username, className }: UserAvatarProps) => {
+ const [resolved, setResolved] = React.useState(() => resolveAvatar(userId, avatar, avatarSrc));
- const handleImageError = () => {
- setImageError(true);
- };
+ React.useEffect(() => {
+ setResolved(resolveAvatar(userId, avatar, avatarSrc));
+ }, [userId, avatar, avatarSrc]);
- const renderDefaultAvatar = () => (
-
-
-
- );
-
- return (
-
- {(!(user?.avatar ?? '') && (!(user?.username ?? '') || user?.username.trim() === '')) ||
- imageError ? (
- renderDefaultAvatar()
- ) : (
-
- )}
-
- );
-});
+ return (
+
+ {resolved.type === 'image' ? (
+
setResolved(markAvatarFailed(userId, resolved.src))}
+ />
+ ) : (
+
+
+
+ )}
+
+ );
+ },
+);
UserAvatar.displayName = 'UserAvatar';
@@ -74,9 +112,10 @@ const Icon: React.FC = memo((props) => {
return (
);
diff --git a/client/src/components/MCP/MCPConfigDialog.tsx b/client/src/components/MCP/MCPConfigDialog.tsx
index a3727971e9..f1079c2799 100644
--- a/client/src/components/MCP/MCPConfigDialog.tsx
+++ b/client/src/components/MCP/MCPConfigDialog.tsx
@@ -24,6 +24,7 @@ interface MCPConfigDialogProps {
serverName: string;
serverStatus?: MCPServerStatus;
conversationId?: string | null;
+ storageContextKey?: string;
}
export default function MCPConfigDialog({
@@ -36,6 +37,7 @@ export default function MCPConfigDialog({
serverName,
serverStatus,
conversationId,
+ storageContextKey,
}: MCPConfigDialogProps) {
const localize = useLocalize();
@@ -167,6 +169,7 @@ export default function MCPConfigDialog({
0}
/>
diff --git a/client/src/components/MCP/MCPServerMenuItem.tsx b/client/src/components/MCP/MCPServerMenuItem.tsx
index 2291a5233e..7fcb773bb9 100644
--- a/client/src/components/MCP/MCPServerMenuItem.tsx
+++ b/client/src/components/MCP/MCPServerMenuItem.tsx
@@ -46,7 +46,6 @@ export default function MCPServerMenuItem({
name="mcp-servers"
value={server.serverName}
checked={isSelected}
- setValueOnChange={false}
onChange={() => onToggle(server.serverName)}
aria-label={accessibleLabel}
className={cn(
diff --git a/client/src/components/MCP/ServerInitializationSection.tsx b/client/src/components/MCP/ServerInitializationSection.tsx
index b5f71335d7..c080866b3d 100644
--- a/client/src/components/MCP/ServerInitializationSection.tsx
+++ b/client/src/components/MCP/ServerInitializationSection.tsx
@@ -9,12 +9,14 @@ interface ServerInitializationSectionProps {
requiresOAuth: boolean;
hasCustomUserVars?: boolean;
conversationId?: string | null;
+ storageContextKey?: string;
}
export default function ServerInitializationSection({
serverName,
requiresOAuth,
conversationId,
+ storageContextKey,
sidePanel = false,
hasCustomUserVars = false,
}: ServerInitializationSectionProps) {
@@ -28,7 +30,7 @@ export default function ServerInitializationSection({
initializeServer,
availableMCPServers,
revokeOAuthForServer,
- } = useMCPServerManager({ conversationId });
+ } = useMCPServerManager({ conversationId, storageContextKey });
const { connectionStatus } = useMCPConnectionStatus({
enabled: !!availableMCPServers && availableMCPServers.length > 0,
diff --git a/client/src/components/Messages/Content/CodeBlock.tsx b/client/src/components/Messages/Content/CodeBlock.tsx
index eae84e49a9..7407098c5e 100644
--- a/client/src/components/Messages/Content/CodeBlock.tsx
+++ b/client/src/components/Messages/Content/CodeBlock.tsx
@@ -23,125 +23,138 @@ interface FloatingCodeBarProps extends CodeBarProps {
isVisible: boolean;
}
-const CodeBar: React.FC = React.memo(
- ({ lang, error, codeRef, blockIndex, plugin = null, allowExecution = true }) => {
- const localize = useLocalize();
- const [isCopied, setIsCopied] = useState(false);
- return (
-
-
{lang}
- {plugin === true ? (
-
- ) : (
-
- {allowExecution === true && (
-
+const CodeBar: React.FC
= React.memo(function CodeBar({
+ lang,
+ error,
+ codeRef,
+ blockIndex,
+ plugin = null,
+ allowExecution = true,
+}) {
+ const localize = useLocalize();
+ const [isCopied, setIsCopied] = useState(false);
+ return (
+
+
{lang}
+ {plugin === true ? (
+
+ ) : (
+
+ {allowExecution === true && (
+
+ )}
+ {
- const codeString = codeRef.current?.textContent;
- if (codeString != null) {
- setIsCopied(true);
- copy(codeString.trim(), { format: 'text/plain' });
+ onClick={async () => {
+ const codeString = codeRef.current?.textContent;
+ if (codeString != null) {
+ setIsCopied(true);
+ copy(codeString.trim(), { format: 'text/plain' });
- setTimeout(() => {
- setIsCopied(false);
- }, 3000);
- }
- }}
- >
- {isCopied ? : }
- {error !== true && (
-
- {localize('com_ui_copy_code')}
-
- {isCopied ? localize('com_ui_copied') : localize('com_ui_copy_code')}
-
-
- )}
-
-
- )}
-
- );
- },
-);
-
-const FloatingCodeBar: React.FC = React.memo(
- ({ lang, error, codeRef, blockIndex, plugin = null, allowExecution = true, isVisible }) => {
- const localize = useLocalize();
- const [isCopied, setIsCopied] = useState(false);
- const copyButtonRef = useRef(null);
-
- const handleCopy = useCallback(() => {
- const codeString = codeRef.current?.textContent;
- if (codeString != null) {
- const wasFocused = document.activeElement === copyButtonRef.current;
- setIsCopied(true);
- copy(codeString.trim(), { format: 'text/plain' });
- if (wasFocused) {
- requestAnimationFrame(() => {
- copyButtonRef.current?.focus();
- });
- }
-
- setTimeout(() => {
- const focusedElement = document.activeElement as HTMLElement | null;
- setIsCopied(false);
- requestAnimationFrame(() => {
- focusedElement?.focus();
- });
- }, 3000);
- }
- }, [codeRef]);
-
- return (
-
- {plugin === true ? (
-
- ) : (
- <>
- {allowExecution === true && (
-
- )}
-
- {isCopied ? (
-
- ) : (
-
- )}
-
+ setTimeout(() => {
+ setIsCopied(false);
+ }, 3000);
}
- />
- >
- )}
-
- );
- },
-);
+ }}
+ >
+ {isCopied ? : }
+ {error !== true && (
+
+ {localize('com_ui_copy_code')}
+
+ {isCopied ? localize('com_ui_copied') : localize('com_ui_copy_code')}
+
+
+ )}
+
+
+ )}
+
+ );
+});
+CodeBar.displayName = 'CodeBar';
+
+const FloatingCodeBar: React.FC = React.memo(function FloatingCodeBar({
+ lang,
+ error,
+ codeRef,
+ blockIndex,
+ plugin = null,
+ allowExecution = true,
+ isVisible,
+}) {
+ const localize = useLocalize();
+ const [isCopied, setIsCopied] = useState(false);
+ const copyButtonRef = useRef(null);
+
+ const handleCopy = useCallback(() => {
+ const codeString = codeRef.current?.textContent;
+ if (codeString != null) {
+ const wasFocused = document.activeElement === copyButtonRef.current;
+ setIsCopied(true);
+ copy(codeString.trim(), { format: 'text/plain' });
+ if (wasFocused) {
+ requestAnimationFrame(() => {
+ copyButtonRef.current?.focus();
+ });
+ }
+
+ setTimeout(() => {
+ const focusedElement = document.activeElement as HTMLElement | null;
+ setIsCopied(false);
+ requestAnimationFrame(() => {
+ focusedElement?.focus();
+ });
+ }, 3000);
+ }
+ }, [codeRef]);
+
+ return (
+
+ {plugin === true ? (
+
+ ) : (
+ <>
+ {allowExecution === true && (
+
+ )}
+
+ {isCopied ? (
+
+ ) : (
+
+ )}
+
+ }
+ />
+ >
+ )}
+
+ );
+});
+FloatingCodeBar.displayName = 'FloatingCodeBar';
const CodeBlock: React.FC = ({
lang,
diff --git a/client/src/components/Messages/Content/Error.tsx b/client/src/components/Messages/Content/Error.tsx
index 469e29fe32..ff2f2d7e90 100644
--- a/client/src/components/Messages/Content/Error.tsx
+++ b/client/src/components/Messages/Content/Error.tsx
@@ -41,6 +41,7 @@ const errorMessages = {
[ErrorTypes.NO_USER_KEY]: 'com_error_no_user_key',
[ErrorTypes.INVALID_USER_KEY]: 'com_error_invalid_user_key',
[ErrorTypes.NO_BASE_URL]: 'com_error_no_base_url',
+ [ErrorTypes.INVALID_BASE_URL]: 'com_error_invalid_base_url',
[ErrorTypes.INVALID_ACTION]: `com_error_${ErrorTypes.INVALID_ACTION}`,
[ErrorTypes.INVALID_REQUEST]: `com_error_${ErrorTypes.INVALID_REQUEST}`,
[ErrorTypes.REFUSAL]: 'com_error_refusal',
diff --git a/client/src/components/Messages/Content/Mermaid.tsx b/client/src/components/Messages/Content/Mermaid.tsx
index 9d830b3fdc..03037f4427 100644
--- a/client/src/components/Messages/Content/Mermaid.tsx
+++ b/client/src/components/Messages/Content/Mermaid.tsx
@@ -12,6 +12,7 @@ import {
OGDialogContent,
} from '@librechat/client';
import { useLocalize, useDebouncedMermaid } from '~/hooks';
+import { fixSubgraphTitleContrast } from '~/utils/mermaid';
import MermaidHeader from './MermaidHeader';
import cn from '~/utils/cn';
@@ -181,6 +182,8 @@ const Mermaid: React.FC = memo(({ children, id, theme }) => {
svgElement.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
}
+ fixSubgraphTitleContrast(svgElement);
+
return {
processedSvg: new XMLSerializer().serializeToString(doc),
parsedDimensions: dimensions,
@@ -672,7 +675,7 @@ const Mermaid: React.FC = memo(({ children, id, theme }) => {
className={cn(
'relative overflow-hidden p-4 transition-colors duration-200',
'rounded-md',
- showControls ? 'bg-surface-primary-alt' : 'bg-transparent',
+ showControls ? 'bg-surface-primary-alt dark:bg-white/[0.03]' : 'bg-transparent',
isPanning ? 'cursor-grabbing' : 'cursor-grab',
)}
style={{ height: `${calculatedHeight}px` }}
@@ -811,7 +814,7 @@ const Mermaid: React.FC = memo(({ children, id, theme }) => {
className={cn(
'relative overflow-hidden p-4 transition-colors duration-200',
'rounded-md',
- showControls ? 'bg-surface-primary-alt' : 'bg-transparent',
+ showControls ? 'bg-surface-primary-alt dark:bg-white/[0.03]' : 'bg-transparent',
isPanning ? 'cursor-grabbing' : 'cursor-grab',
)}
style={{ height: `${calculatedHeight}px` }}
diff --git a/client/src/components/Messages/Content/MermaidHeader.tsx b/client/src/components/Messages/Content/MermaidHeader.tsx
index 03b49b6558..2d3a416a5a 100644
--- a/client/src/components/Messages/Content/MermaidHeader.tsx
+++ b/client/src/components/Messages/Content/MermaidHeader.tsx
@@ -1,7 +1,7 @@
import React, { memo, useState, useCallback, useRef } from 'react';
import copy from 'copy-to-clipboard';
import { Expand, ChevronUp, ChevronDown } from 'lucide-react';
-import { Button, Clipboard, CheckMark } from '@librechat/client';
+import { Clipboard, CheckMark, TooltipAnchor } from '@librechat/client';
import { useLocalize } from '~/hooks';
import cn from '~/utils/cn';
@@ -15,8 +15,8 @@ interface MermaidHeaderProps {
onToggleCode: () => void;
}
-const buttonClasses =
- 'h-auto gap-1 rounded-sm px-1 py-0 text-xs text-gray-200 hover:bg-gray-600 hover:text-white focus-visible:ring-white focus-visible:ring-offset-0';
+const iconBtnClass =
+ 'flex items-center justify-center rounded p-1.5 text-text-secondary hover:bg-surface-hover focus-visible:outline focus-visible:outline-white';
const MermaidHeader: React.FC = memo(
({
@@ -49,46 +49,58 @@ const MermaidHeader: React.FC = memo(
return (
-
{localize('com_ui_mermaid')}
-
- {showExpandButton && onExpand && (
-
+
+
+ }
+ />
+ )}
+
-
- {localize('com_ui_expand')}
-
- )}
-
- {showCode ? : }
- {showCode ? localize('com_ui_hide_code') : localize('com_ui_show_code')}
-
-
- {isCopied ? : }
- {localize('com_ui_copy_code')}
-
-
+ {showCode ?
:
}
+
+ }
+ />
+
+ {isCopied ? (
+
+ ) : (
+
+ )}
+
+ }
+ />
);
},
diff --git a/client/src/components/Messages/ContentRender.tsx b/client/src/components/Messages/ContentRender.tsx
index 5724ff77c2..4114baefe4 100644
--- a/client/src/components/Messages/ContentRender.tsx
+++ b/client/src/components/Messages/ContentRender.tsx
@@ -22,176 +22,175 @@ type ContentRenderProps = {
'currentEditId' | 'setCurrentEditId' | 'siblingIdx' | 'setSiblingIdx' | 'siblingCount'
>;
-const ContentRender = memo(
- ({
+const ContentRender = memo(function ContentRender({
+ message: msg,
+ siblingIdx,
+ siblingCount,
+ setSiblingIdx,
+ currentEditId,
+ setCurrentEditId,
+ isSubmitting = false,
+}: ContentRenderProps) {
+ const localize = useLocalize();
+ const { attachments, searchResults } = useAttachments({
+ messageId: msg?.messageId,
+ attachments: msg?.attachments,
+ });
+ const {
+ edit,
+ index,
+ agent,
+ assistant,
+ enterEdit,
+ conversation,
+ messageLabel,
+ handleContinue,
+ handleFeedback,
+ latestMessageId,
+ copyToClipboard,
+ regenerateMessage,
+ latestMessageDepth,
+ } = useMessageActions({
message: msg,
- siblingIdx,
- siblingCount,
- setSiblingIdx,
+ searchResults,
currentEditId,
setCurrentEditId,
- isSubmitting = false,
- }: ContentRenderProps) => {
- const localize = useLocalize();
- const { attachments, searchResults } = useAttachments({
- messageId: msg?.messageId,
- attachments: msg?.attachments,
- });
- const {
- edit,
- index,
- agent,
- assistant,
- enterEdit,
- conversation,
+ });
+ const fontSize = useAtomValue(fontSizeAtom);
+ const maximizeChatSpace = useRecoilValue(store.maximizeChatSpace);
+
+ const handleRegenerateMessage = useCallback(() => regenerateMessage(), [regenerateMessage]);
+ const isLast = useMemo(
+ () => !(msg?.children?.length ?? 0) && (msg?.depth === latestMessageDepth || msg?.depth === -1),
+ [msg?.children, msg?.depth, latestMessageDepth],
+ );
+ const hasNoChildren = !(msg?.children?.length ?? 0);
+ const isLatestMessage = msg?.messageId === latestMessageId;
+ /** Only pass isSubmitting to the latest message to prevent unnecessary re-renders */
+ const effectiveIsSubmitting = isLatestMessage ? isSubmitting : false;
+
+ const iconData: TMessageIcon = useMemo(
+ () => ({
+ endpoint: msg?.endpoint ?? conversation?.endpoint,
+ model: msg?.model ?? conversation?.model,
+ iconURL: msg?.iconURL,
+ modelLabel: messageLabel,
+ isCreatedByUser: msg?.isCreatedByUser,
+ }),
+ [
messageLabel,
- latestMessage,
- handleContinue,
- handleFeedback,
- copyToClipboard,
- regenerateMessage,
- } = useMessageActions({
- message: msg,
- searchResults,
- currentEditId,
- setCurrentEditId,
- });
- const fontSize = useAtomValue(fontSizeAtom);
- const maximizeChatSpace = useRecoilValue(store.maximizeChatSpace);
+ conversation?.endpoint,
+ conversation?.model,
+ msg?.model,
+ msg?.iconURL,
+ msg?.endpoint,
+ msg?.isCreatedByUser,
+ ],
+ );
- const handleRegenerateMessage = useCallback(() => regenerateMessage(), [regenerateMessage]);
- const isLast = useMemo(
- () =>
- !(msg?.children?.length ?? 0) && (msg?.depth === latestMessage?.depth || msg?.depth === -1),
- [msg?.children, msg?.depth, latestMessage?.depth],
- );
- const hasNoChildren = !(msg?.children?.length ?? 0);
- const isLatestMessage = msg?.messageId === latestMessage?.messageId;
- /** Only pass isSubmitting to the latest message to prevent unnecessary re-renders */
- const effectiveIsSubmitting = isLatestMessage ? isSubmitting : false;
+ const { hasParallelContent } = useContentMetadata(msg);
- const iconData: TMessageIcon = useMemo(
- () => ({
- endpoint: msg?.endpoint ?? conversation?.endpoint,
- model: msg?.model ?? conversation?.model,
- iconURL: msg?.iconURL,
- modelLabel: messageLabel,
- isCreatedByUser: msg?.isCreatedByUser,
- }),
- [
- messageLabel,
- conversation?.endpoint,
- conversation?.model,
- msg?.model,
- msg?.iconURL,
- msg?.endpoint,
- msg?.isCreatedByUser,
- ],
- );
+ if (!msg) {
+ return null;
+ }
- const { hasParallelContent } = useContentMetadata(msg);
-
- if (!msg) {
- return null;
+ const getChatWidthClass = () => {
+ if (maximizeChatSpace) {
+ return 'w-full max-w-full md:px-5 lg:px-1 xl:px-5';
}
+ if (hasParallelContent) {
+ return 'md:max-w-[58rem] xl:max-w-[70rem]';
+ }
+ return 'md:max-w-[47rem] xl:max-w-[55rem]';
+ };
- const getChatWidthClass = () => {
- if (maximizeChatSpace) {
- return 'w-full max-w-full md:px-5 lg:px-1 xl:px-5';
- }
- if (hasParallelContent) {
- return 'md:max-w-[58rem] xl:max-w-[70rem]';
- }
- return 'md:max-w-[47rem] xl:max-w-[55rem]';
- };
+ const baseClasses = {
+ common: 'group mx-auto flex flex-1 gap-3 transition-all duration-300 transform-gpu ',
+ chat: getChatWidthClass(),
+ };
- const baseClasses = {
- common: 'group mx-auto flex flex-1 gap-3 transition-all duration-300 transform-gpu ',
- chat: getChatWidthClass(),
- };
+ const conditionalClasses = {
+ focus: 'focus:outline-none focus:ring-2 focus:ring-border-xheavy',
+ };
- const conditionalClasses = {
- focus: 'focus:outline-none focus:ring-2 focus:ring-border-xheavy',
- };
+ return (
+
+ {!hasParallelContent && (
+
+ )}
- return (
{!hasParallelContent && (
-
+
{messageLabel}
)}
-
- {!hasParallelContent && (
-
{messageLabel}
- )}
-
-
-
- }
- />
-
- {hasNoChildren && effectiveIsSubmitting ? (
-
- ) : (
-
-
-
-
- )}
+
+
+ }
+ />
+ {hasNoChildren && effectiveIsSubmitting ? (
+
+ ) : (
+
+
+
+
+ )}
- );
- },
-);
+
+ );
+});
+ContentRender.displayName = 'ContentRender';
export default ContentRender;
diff --git a/client/src/components/Messages/MessageContent.tsx b/client/src/components/Messages/MessageContent.tsx
index 68fe2d8629..0e53b1c840 100644
--- a/client/src/components/Messages/MessageContent.tsx
+++ b/client/src/components/Messages/MessageContent.tsx
@@ -5,25 +5,23 @@ import type { TMessageProps } from '~/common';
import MultiMessage from '~/components/Chat/Messages/MultiMessage';
import ContentRender from './ContentRender';
-const MessageContainer = React.memo(
- ({
- handleScroll,
- children,
- }: {
- handleScroll: (event?: unknown) => void;
- children: React.ReactNode;
- }) => {
- return (
-
- {children}
-
- );
- },
-);
+const MessageContainer = React.memo(function MessageContainer({
+ handleScroll,
+ children,
+}: {
+ handleScroll: (event?: unknown) => void;
+ children: React.ReactNode;
+}) {
+ return (
+
+ {children}
+
+ );
+});
export default function MessageContent(props: TMessageProps) {
const { conversation, handleScroll, isSubmitting } = useMessageProcess({
diff --git a/client/src/components/Nav/AccountSettings.tsx b/client/src/components/Nav/AccountSettings.tsx
index e3f97160eb..cf80f89ca2 100644
--- a/client/src/components/Nav/AccountSettings.tsx
+++ b/client/src/components/Nav/AccountSettings.tsx
@@ -1,5 +1,5 @@
import { useState, memo, useRef } from 'react';
-import * as Select from '@ariakit/react/select';
+import * as Menu from '@ariakit/react/menu';
import { FileText, LogOut } from 'lucide-react';
import { LinkIcon, GearIcon, DropdownMenuSeparator, Avatar } from '@librechat/client';
import { MyFilesModal } from '~/components/Chat/Input/Files/MyFilesModal';
@@ -20,8 +20,8 @@ function AccountSettings() {
const accountSettingsButtonRef = useRef
(null);
return (
-
-
+
{user?.name ?? user?.username ?? localize('com_nav_user')}
-
-
+
>
)}
- setShowFiles(true)}
- className="select-item text-sm"
- >
+ setShowFiles(true)} className="select-item text-sm">
{localize('com_nav_my_files')}
-
+
{startupConfig?.helpAndFaqURL !== '/' && (
- window.open(startupConfig?.helpAndFaqURL, '_blank')}
className="select-item text-sm"
>
{localize('com_nav_help_faq')}
-
+
)}
- setShowSettings(true)}
- className="select-item text-sm"
- >
+ setShowSettings(true)} className="select-item text-sm">
{localize('com_nav_settings')}
-
+
- logout()}
- value="logout"
- className="select-item text-sm"
- >
+ logout()} className="select-item text-sm">
{localize('com_nav_log_out')}
-
-
+
+
{showFiles && (
)}
{showSettings &&
}
-
+
);
}
diff --git a/client/src/components/Nav/Favorites/FavoriteItem.tsx b/client/src/components/Nav/Favorites/FavoriteItem.tsx
index 173be27d00..248008869d 100644
--- a/client/src/components/Nav/Favorites/FavoriteItem.tsx
+++ b/client/src/components/Nav/Favorites/FavoriteItem.tsx
@@ -126,8 +126,8 @@ export default function FavoriteItem({
className={cn(
'absolute right-2 flex items-center',
isPopoverActive
- ? 'opacity-100'
- : 'opacity-0 group-focus-within:opacity-100 group-hover:opacity-100',
+ ? 'pointer-events-auto opacity-100'
+ : 'pointer-events-none opacity-0 group-focus-within:pointer-events-auto group-focus-within:opacity-100 group-hover:pointer-events-auto group-hover:opacity-100',
)}
onClick={(e) => e.stopPropagation()}
>
diff --git a/client/src/components/Nav/Favorites/FavoritesList.tsx b/client/src/components/Nav/Favorites/FavoritesList.tsx
index 86fe4a793f..82225733fd 100644
--- a/client/src/components/Nav/Favorites/FavoritesList.tsx
+++ b/client/src/components/Nav/Favorites/FavoritesList.tsx
@@ -1,15 +1,21 @@
import React, { useRef, useCallback, useMemo, useEffect } from 'react';
-import { useRecoilValue } from 'recoil';
import { LayoutGrid } from 'lucide-react';
import { useDrag, useDrop } from 'react-dnd';
import { Skeleton } from '@librechat/client';
import { useNavigate } from 'react-router-dom';
import { useQueries } from '@tanstack/react-query';
+import { useRecoilValue } from 'recoil';
import { QueryKeys, dataService } from 'librechat-data-provider';
import type t from 'librechat-data-provider';
-import { useFavorites, useLocalize, useShowMarketplace, useNewConvo } from '~/hooks';
-import { useAssistantsMapContext, useAgentsMapContext } from '~/Providers';
import type { AgentQueryResult } from '~/common';
+import {
+ useGetConversation,
+ useShowMarketplace,
+ useFavorites,
+ useLocalize,
+ useNewConvo,
+} from '~/hooks';
+import { useAssistantsMapContext, useAgentsMapContext } from '~/Providers';
import useSelectMention from '~/hooks/Input/useSelectMention';
import { useGetEndpointsQuery } from '~/data-provider';
import FavoriteItem from './FavoriteItem';
@@ -122,20 +128,20 @@ export default function FavoritesList({
const navigate = useNavigate();
const localize = useLocalize();
const search = useRecoilValue(store.search);
+ const getConversation = useGetConversation(0);
const { favorites, reorderFavorites, isLoading: isFavoritesLoading } = useFavorites();
const showAgentMarketplace = useShowMarketplace();
const { newConversation } = useNewConvo();
const assistantsMap = useAssistantsMapContext();
const agentsMap = useAgentsMapContext();
- const conversation = useRecoilValue(store.conversationByIndex(0));
const { data: endpointsConfig = {} as t.TEndpointsConfig } = useGetEndpointsQuery();
const { onSelectEndpoint } = useSelectMention({
modelSpecs: [],
- conversation,
assistantsMap,
endpointsConfig,
+ getConversation,
newConversation,
returnHandlers: true,
});
diff --git a/client/src/components/Nav/Favorites/tests/FavoritesList.spec.tsx b/client/src/components/Nav/Favorites/tests/FavoritesList.spec.tsx
index 8318b94698..ed71221de3 100644
--- a/client/src/components/Nav/Favorites/tests/FavoritesList.spec.tsx
+++ b/client/src/components/Nav/Favorites/tests/FavoritesList.spec.tsx
@@ -56,6 +56,7 @@ jest.mock('~/hooks', () => ({
useLocalize: () => (key: string) => key,
useShowMarketplace: () => false,
useNewConvo: () => ({ newConversation: jest.fn() }),
+ useGetConversation: () => () => null,
}));
jest.mock('~/Providers', () => ({
diff --git a/client/src/components/Nav/Nav.tsx b/client/src/components/Nav/Nav.tsx
index 74883b94f4..cdee938663 100644
--- a/client/src/components/Nav/Nav.tsx
+++ b/client/src/components/Nav/Nav.tsx
@@ -225,6 +225,7 @@ const Nav = memo(
aria-label={localize('com_ui_chat_history')}
className="flex h-full flex-col px-2 pb-3.5"
aria-hidden={!navVisible}
+ {...{ inert: !navVisible ? '' : undefined }}
>
= useCallback(
+ const clickHandler: React.MouseEventHandler = useCallback(
(e) => {
- if (e.button === 0 && (e.ctrlKey || e.metaKey)) {
- window.open('/c/new', '_blank');
+ // Let browser handle modified/non-left clicks (new tab, context menu, etc.)
+ if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
return;
}
+
+ e.preventDefault();
clearMessagesCache(queryClient, conversation?.conversationId);
queryClient.invalidateQueries([QueryKeys.messages]);
newConvo();
- navigate('/c/new', { state: { focusChat: true } });
if (isSmallScreen) {
toggleNav();
}
},
- [queryClient, conversation, newConvo, navigate, toggleNav, isSmallScreen],
+ [queryClient, conversation, newConvo, toggleNav, isSmallScreen],
);
return (
@@ -84,14 +84,16 @@ export default function NewChat({
description={localize('com_ui_new_chat')}
render={
-
+
+
+
}
/>
diff --git a/client/src/components/Nav/SettingsTabs/Account/BackupCodesItem.tsx b/client/src/components/Nav/SettingsTabs/Account/BackupCodesItem.tsx
index c89ce61fff..e66cb7b08a 100644
--- a/client/src/components/Nav/SettingsTabs/Account/BackupCodesItem.tsx
+++ b/client/src/components/Nav/SettingsTabs/Account/BackupCodesItem.tsx
@@ -1,12 +1,23 @@
import React, { useState } from 'react';
import { RefreshCcw } from 'lucide-react';
+import { useSetRecoilState } from 'recoil';
import { motion, AnimatePresence } from 'framer-motion';
-import { TBackupCode, TRegenerateBackupCodesResponse, type TUser } from 'librechat-data-provider';
+import { REGEXP_ONLY_DIGITS, REGEXP_ONLY_DIGITS_AND_CHARS } from 'input-otp';
+import type {
+ TRegenerateBackupCodesResponse,
+ TRegenerateBackupCodesRequest,
+ TBackupCode,
+ TUser,
+} from 'librechat-data-provider';
import {
- OGDialog,
+ InputOTPSeparator,
+ InputOTPGroup,
+ InputOTPSlot,
OGDialogContent,
OGDialogTitle,
OGDialogTrigger,
+ OGDialog,
+ InputOTP,
Button,
Label,
Spinner,
@@ -15,7 +26,6 @@ import {
} from '@librechat/client';
import { useRegenerateBackupCodesMutation } from '~/data-provider';
import { useAuthContext, useLocalize } from '~/hooks';
-import { useSetRecoilState } from 'recoil';
import store from '~/store';
const BackupCodesItem: React.FC = () => {
@@ -24,25 +34,30 @@ const BackupCodesItem: React.FC = () => {
const { showToast } = useToastContext();
const setUser = useSetRecoilState(store.user);
const [isDialogOpen, setDialogOpen] = useState(false);
+ const [otpToken, setOtpToken] = useState('');
+ const [useBackup, setUseBackup] = useState(false);
const { mutate: regenerateBackupCodes, isLoading } = useRegenerateBackupCodesMutation();
+ const needs2FA = !!user?.twoFactorEnabled;
+
const fetchBackupCodes = (auto: boolean = false) => {
- regenerateBackupCodes(undefined, {
+ let payload: TRegenerateBackupCodesRequest | undefined;
+ if (needs2FA && otpToken.trim()) {
+ payload = useBackup ? { backupCode: otpToken.trim() } : { token: otpToken.trim() };
+ }
+
+ regenerateBackupCodes(payload, {
onSuccess: (data: TRegenerateBackupCodesResponse) => {
- const newBackupCodes: TBackupCode[] = data.backupCodesHash.map((codeHash) => ({
- codeHash,
- used: false,
- usedAt: null,
- }));
+ const newBackupCodes: TBackupCode[] = data.backupCodesHash;
setUser((prev) => ({ ...prev, backupCodes: newBackupCodes }) as TUser);
+ setOtpToken('');
showToast({
message: localize('com_ui_backup_codes_regenerated'),
status: 'success',
});
- // Trigger file download only when user explicitly clicks the button.
if (!auto && newBackupCodes.length) {
const codesString = data.backupCodes.join('\n');
const blob = new Blob([codesString], { type: 'text/plain;charset=utf-8' });
@@ -66,6 +81,8 @@ const BackupCodesItem: React.FC = () => {
fetchBackupCodes(false);
};
+ const otpReady = !needs2FA || otpToken.length === (useBackup ? 8 : 6);
+
return (
@@ -161,10 +178,10 @@ const BackupCodesItem: React.FC = () => {
);
})}
-
+
@@ -183,7 +200,7 @@ const BackupCodesItem: React.FC = () => {
@@ -192,6 +209,59 @@ const BackupCodesItem: React.FC = () => {
)}
+ {needs2FA && (
+
+
+ {localize('com_ui_2fa_verification_required')}
+
+
+
+ {useBackup ? (
+
+