mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-10-22 01:53:33 +00:00
* feat: theme-adaptive SVG support for custom MCP and group icons Custom icons (MCP server iconPath, model spec groupIcon) were rendered as plain <img>, so monochrome SVGs kept fixed dark colors and were nearly invisible in dark theme. Introduce a shared CustomIcon component that detects monochrome SVG glyphs and tints them with currentColor so they follow the active theme, while multi-color SVG logos and raster images keep their original colors. The monochrome decision parses the SVG's color tokens; content is fetched once, cached, and any failure falls back to the original image. Monochrome SVGs render via CSS mask, never inlined, so no SVG markup reaches the DOM. Apply across all custom-icon surfaces: MCP settings cards, the chat MCP dropdown, stacked MCP icons, tool-call headers, and model group icons. Also support SVG in the MCP avatar uploader: add SVG to the accepted file types and sanitize uploaded SVGs with DOMPurify before storing them, and make the dialog preview theme-adaptive via the same component. Add unit tests for SVG detection, monochrome analysis, sanitization, and CustomIcon rendering. * fix: reset adaptive icon tint state when the source changes A reused CustomIcon instance kept the monochrome verdict from a previous source until its effect re-ran, so switching to a raster image or a new multi-color SVG could briefly render it as a currentColor silhouette. Key the resolved verdict to the current source and reset it synchronously during render (seeding from cache when available), so a stale verdict can never tint a different icon. Add hook tests covering the source change. * fix: do not tint custom SVGs that have an opaque background A grayscale SVG with an opaque full-canvas background (for example an exported logo with a white background rect and a black glyph) passed the monochrome check and was drawn through a CSS mask. Masks key off the alpha channel, so the opaque background filled the whole area with the tint color and the icon collapsed into a solid block. Detect a full-canvas opaque background rect and exclude such SVGs from tinting, rendering them with their own colors instead. Transparent single-color and multi-shade glyphs remain tintable. Add tests for the background cases. * fix: detect opaque SVG backgrounds without a viewBox Opaque background detection only read canvas dimensions from the viewBox, so an SVG that declares width and height on the root element but omits the viewBox slipped through and was tinted into a solid block. Fall back to the root svg width and height when no viewBox is present, and match attribute names exactly so stroke-width is not mistaken for the canvas width. Add tests for the no-viewBox cases. * fix: parse comma-separated SVG viewBox values The viewBox regex only accepted whitespace between values, so a valid viewBox like "0,0,24,24" failed to parse and an opaque background went undetected, tinting the icon into a solid block. Accept commas and whitespace as separators. Add a test for the comma-separated case. * refactor: detect SVG tintability with DOMParser instead of regexes The monochrome/tintable decision scraped SVG markup with regexes, which kept missing edge cases (opaque backgrounds, missing or comma-separated viewBox, stroke-width vs canvas width, embedded raster images). Parse the SVG once with DOMParser and inspect real elements and attributes: reject embedded <image>/<foreignObject> content, detect a full-canvas opaque background rect, read the canvas size from the viewBox or root width/height, and gather paint colors from attributes, inline styles, and <style> blocks. Unparseable input is treated as not tintable. Tests cover these cases. * fix: only tint single-tone grayscale SVGs A grayscale SVG can draw its background as a full-canvas path (not just a rect), e.g. a white background path plus a black glyph. The rect-only background check missed that, and the icon flattened to a solid currentColor block under the CSS mask. Tint only when the SVG resolves to a single grayscale tone. Any second tone (a background shape drawn as a path or rect, an accent, or a second shade) now preserves the icon's own colors, which covers full-canvas path backgrounds without per-shape geometry parsing. * fix: count default black fill when detecting tintable SVGs * fix: treat currentColor as a tone and stroked closed shapes as filled * fix: ignore non-rendering template paint and count filled open paths * fix: scan defs and symbol paint rendered through use references * fix: resolve currentColor against fixed color and match style fills for default paint * fix: treat alpha-zero fills as transparent in SVG tint detection * fix: resolve inherited and CSS fill for backgrounds and default paint * fix: resolve CSS currentColor and default-black use instances * fix: count default-filled polylines when detecting tintable SVGs * fix: resolve inherited fill and style/CSS opacity in SVG tint detection * fix: ignore display:none shapes and stop counting CSS color as paint * fix: only count CSS paints that match rendered elements * fix: match root for CSS currentColor and skip unreferenced defs tones * fix: count paint only on rendered shapes and filter hidden CSS currentColor * fix: resolve use-instance currentColor and skip hidden use default fills * fix: resolve CSS paints onto rendered painters and skip overridden use fills * fix: keep checking ancestor opacity after resolving paint opacity * fix: resolve CSS paints by specificity and skip transparent default fills * fix: apply CSS over presentation attributes and follow nested use targets * fix: strip CSS comments, honor visibility, and inherit paint through nested use * fix: skip transparent svg use references * Account for SVG filter colors * fix: propagate outer use color through nested currentColor references * fix: preserve url() id casing and record every nested use chain * fix: preserve SVGs whose filters recolor the source * refactor: detect monochrome icons via canvas pixel sampling Replace the SVG source parser with offscreen-canvas pixel sampling: draw the icon, read pixel data, and treat it as monochrome only when every non-transparent pixel is grayscale within tolerance and the image has some transparency (a fully opaque image would mask to a solid block). Verdicts are cached per src. An explicit monochrome flag on CustomIcon skips detection; sampling is the fallback. Image load failures and canvas taint from non-CORS cross-origin icons fall back to untinted rendering instead of throwing. * harden custom SVG icon handling across security, a11y, and perf Sanitize user-provided MCP iconPath server-side; the client-side DOMPurify pass was bypassable by posting iconPath straight to the API. Adds sanitizeMcpIconPath in @librechat/api (allowlist SVG sanitizer that preserves case-sensitive names) and runs it in the create/update controllers, plus a length cap on iconPath in the shared schema. - gate theme detection to same-origin/data sources so a remote icon is no longer auto-fetched from every viewer's browser - restore forced-colors (High Contrast) visibility and the broken-icon onError fallback for tinted icons - mark redundant icons decorative to avoid screen-reader double reads - base64-encode inlined SVG data URIs and bound the verdict cache - harden the client SVG sanitizer and guard FileReader failures - cover the tinted render branch, sanitizer allowlist, and edge cases * fix: preserve local SVG references while stripping external hrefs The hardened sanitizers dropped <use> and every href outright, blanking self-contained exporter output like <defs><path id="p"/></defs> <use href="#p"/> and gradients inheriting stops via href="#g". Re-allow <use> and href/xlink:href on both sanitizers, restricted to same-document fragments: the client uses a dedicated DOMPurify instance with an afterSanitizeAttributes hook (kept off the shared default instance), and the server mirrors the rule with a sanitize-html tag transform plus an empty allowedSchemes list as a second layer. External, protocol-relative, relative-path, and javascript: hrefs are still stripped, leaving the element inert. * fix: keep xlink namespace and safe filters in the server icon sanitizer The server allowlist stripped xmlns:xlink from the root while keeping xlink:href, leaving an unbound prefix that is a parse error once the icon is stored as an image/svg+xml data URI, so SVG 1.1 exporter output went blank after save. It also dropped <filter>/fe* primitives that the client sanitizer's svgFilters profile allows, so icons relying on effects like feDropShadow lost them between preview and reload. Allow xmlns:xlink and mirror the client's filter allowlist (elements plus their presentation attributes); feImage passes through the existing fragment-only href transform, so external references are still stripped. * fix: require empty pixels for tinting and block external url() references Two issues from review of the icon sanitizer and monochrome detector: - scanMonochrome flagged any pixel below full opacity as transparency, so an SVG that fills the whole canvas with a semi-transparent grayscale wash was tinted and rendered as a solid currentColor block. Require a genuinely empty pixel (alpha at or below the paint threshold) instead. - The fragment-only reference rule only covered href/xlink:href, so a url() in filter/fill/mask/clip-path/style kept external targets like filter="url(https://evil/f.svg#f)". Both sanitizers now strip any attribute carrying a non-fragment url(), preserving local url(#id). * fix: preserve internal SVG stylesheets while scrubbing their references Exporter SVGs that store multi-color paint in an internal <style> block (e.g. .red{fill:#e00} with class="red") lost all styling because the sanitizers dropped <style> outright, so multi-color logos rendered with default paints after upload. Re-allow <style> on both sanitizers and scrub its CSS: strip comments and @import at-rules and rewrite any non-fragment url() to none, keeping local url(#id) paints. These icons only render in inert <img>/CSS-mask contexts isolated from the host page (no script, and no subresource loads once external refs are scrubbed), so a script-free stylesheet is safe to keep; a premature </style> close still has its trailing markup re-sanitized by the parser. * fix: normalize icon value before deciding it is not an SVG data URI A posted iconPath with leading whitespace or C0 controls (e.g. "\n data:image/svg+xml,...") slipped past the anchored data-URI check, so sanitizeMcpIconPath returned it raw while a browser trims the prefix and still renders the SVG, keeping its external <image>/url() and other stripped content. Normalize the value the way URL parsing does, trimming leading/trailing C0 controls and spaces and removing embedded tab/newline, before the SVG check so these variants are sanitized too. * fix: cap sanitized icon length and re-encode as compact base64 The schema length check ran on the input, but sanitizeMcpIconPath then re-encoded the markup with encodeURIComponent, which expands SVG by well over the base64 input size (a 235KB base64 icon became a 374KB percent string). create stored that over-limit value, and editing the server resubmitted the prefilled value and failed MCPServerUserInputSchema. Re-encode the sanitized SVG as base64 (far more compact for angle-heavy markup, which sanitizing can itself grow via explicit close tags) and drop anything still over MAX_MCP_ICON_PATH_LENGTH, so a stored icon can never exceed the cap that a later edit re-validates against. * fix: resolve CSS escapes before stripping external SVG references A literal url(/@import matcher missed CSS-escaped references: a value like style="fill:u\72l(https://attacker/x)" or an escaped @import survived sanitization because the browser un-escapes \72 to r at tokenization time while the regex never saw a url(...). The external reference was then persisted and served to other clients. Un-escape CSS the way a browser does (single pass over \hex and \char escapes) before the url()/@import matchers run, on both the client and server sanitizers. Also scrub the multi-declaration style attribute in place instead of dropping it, so co-located local paint rules survive while escaped external references are neutralized. * fix: re-sanitize after scrubbing style blocks to block markup reintroduction scrubStyleBlocks runs after sanitizeHtml and splices un-escaped CSS back as raw markup, so an escaped sequence like \3c/style\3e\3cimage/\3e (inert text during the first pass) became a real </style><image href> element after unescaping, past the allowlist. Re-run the allowlist over the scrubbed result whenever a <style> block was rewritten, stripping any element the un-escaping surfaced while leaving legit local rules intact. The client sanitizer is unaffected: it sets the scrubbed CSS as a DOM text node, which serializes with < and > escaped, so no element is reintroduced. Added a regression test pinning that behavior too. * fix: make forced-colors icon tint override the inline background color The forced-colors rule for .custom-icon-tint had no !important, so it lost the cascade to the element's inline `background-color: currentColor` and the masked glyph still blanked out in Windows High Contrast — the exact regression the rule was meant to prevent. Verified in a real forced-colors render: without !important the tinted icon is invisible; with it the glyph paints in CanvasText and stays visible. * fix: enforce icon length cap in the sanitizer, not the schema The schema `.max()` on iconPath rejected the whole update at parse time. A server whose stored icon predates the cap (previous versions allowed large data-URI images) re-submits that value from the edit dialog, so the user was locked out of changing any field or clearing the bad icon. Drop the schema `.max()` and enforce MAX_MCP_ICON_PATH_LENGTH in sanitizeMcpIconPath for every value type: an over-cap SVG is compacted or dropped, an over-cap raster/URL is dropped. Editing a server with a pre-existing oversized icon now succeeds and clears the icon instead of failing validation. * fix: decode XML entities and parse quoted URLs in SVG CSS scrubbing Two more bypasses of the CSS reference scrubber, both live once the stored image/svg+xml is parsed by a viewer: - A <style> block reaches the scrubber as raw text, so an entity-encoded reference like @import (or @import) was never seen as @import; the browser decodes it at render time. Decode XML character references (numeric + the five predefined named) before the matchers run. - The url() regex excluded ')' even inside quotes, so a valid quoted URL like url("https://x/a)b") slipped through. Parse quoted and unquoted URL tokens separately so a ')' inside quotes stays part of the target. Applied to both the server (sanitizeMcpIconPath) and client (sanitizeSvg) scrubbers. Entity decoding also catches an entity-encoded </style> markup breakout, which the re-sanitize pass then strips. * fix: close custom icon review threads * fix: transpile sanitize-html's ESM dependency chain in api jest runs * fix: preserve marker definitions and fragment-only marker references * fix: keep object-cover sizing when tinting masked icons * fix: preserve textPath labels and currentColor color scopes in icon sanitizer * fix: preserve pattern coordinate-system attributes in icon sanitizer Keep patternUnits, patternContentUnits, and patternTransform so patterned SVGs do not fall back to objectBoundingBox after server-side sanitize. * refactor: sanitize icons with one shared DOMPurify policy The server re-implemented DOMPurify's SVG profiles as two hand-written sanitize-html allowlists, so every element and attribute the client kept had to be transcribed by hand, and each miss surfaced as an icon that previewed correctly and then lost its markers, patterns, filters, or xlink binding once stored. Run DOMPurify on jsdom instead and share the config and reference hook with the client, which drops both allowlists. Restrict url() values to same-document fragments on every attribute rather than on the marker properties alone, so external references in fill, stroke, filter, mask, and clip-path are stripped as well. Restore feDropShadow casing after sanitizing. DOMPurify has to parse as HTML, its XML mode drops filter primitives and gradients, and the HTML tag-name adjustment table predates that primitive, so it survived lowercased and left its filter empty once the stored icon was re-parsed as image/svg+xml. * fix: defer jsdom load until MCP icon sanitization jsdom and dompurify were imported at module scope, so every require('@librechat/api') paid their startup cost. Load them on first SVG sanitize instead. * fix: sort type import in MCP icon sanitizer The static-check import sorter wants value imports before type-only imports. Moving the DOMPurify type import after librechat-data-provider clears the drift. * fix: address PR review bot findings chatgpt-codex-connector: - Resolve icon URLs through new URL() instead of trusting a leading slash, so /\attacker.example/icon.svg is no longer treated as same-origin - Check every url() token in an SVG attribute rather than only the first, and reject values carrying a CSS escape that would decode into one - Forbid animateTransform, animateMotion, animateColor, and mpath, which the SVG profile admitted despite the policy intending to remove animation - Preserve the radial-gradient fr attribute the profile omits - Reject multi-tone grayscale in scanMonochrome, which a mask would flatten - Sample at 128px so a small chromatic accent is not averaged away - Settle a stalled icon load after 10s so its in-flight entry is released - Bound the decoded SVG before building a jsdom tree for it - Reject an oversized icon upload with a visible error instead of accepting it and silently clearing it on save * fix: address Codex findings and trim icon sanitizer comments - Bound icon files by size before reading or sanitizing them - Track tone spread across every painted pixel, not only solid ones - Settle monochrome detection on any sampling throw - Use named DOMPurify/JSDOM types and shorten PR comments * fix: percent-decode SVG data URI bodies before base64 decoding * fix: declare the SVG namespace on sanitized icons and keep icon rejections out of form validity
183 lines
7 KiB
JSON
183 lines
7 KiB
JSON
{
|
|
"name": "@librechat/api",
|
|
"version": "1.7.47",
|
|
"type": "commonjs",
|
|
"description": "MCP services for LibreChat",
|
|
"main": "dist/index.cjs",
|
|
"types": "./dist/index.d.cts",
|
|
"exports": {
|
|
".": {
|
|
"require": {
|
|
"types": "./dist/index.d.cts",
|
|
"default": "./dist/index.cjs"
|
|
}
|
|
},
|
|
"./telemetry": {
|
|
"require": {
|
|
"types": "./dist/telemetry.d.cts",
|
|
"default": "./dist/telemetry.cjs"
|
|
}
|
|
},
|
|
"./credentials": {
|
|
"require": {
|
|
"types": "./dist/credentials.d.cts",
|
|
"default": "./dist/credentials.cjs"
|
|
}
|
|
}
|
|
},
|
|
"scripts": {
|
|
"clean": "rimraf dist",
|
|
"build": "npm run clean && tsdown",
|
|
"build:dev": "npm run clean && tsdown",
|
|
"build:watch": "tsdown --watch",
|
|
"build:watch:prod": "tsdown --watch",
|
|
"test": "jest --coverage --watch --testPathIgnorePatterns=\"\\.*integration\\.|\\.*helper\\.|__tests__/helpers/|\\.*manual\\.spec\\.\"",
|
|
"test:ci": "jest --coverage --ci --testPathIgnorePatterns=\"\\.*integration\\.|\\.*helper\\.|__tests__/helpers/|\\.*manual\\.spec\\.\"",
|
|
"test:cache-integration:core": "jest --testPathPatterns=\"src/cache/.*\\.cache_integration\\.spec\\.ts$\" --coverage=false",
|
|
"test:cache-integration:cluster": "jest --testPathPatterns=\"src/cluster/.*\\.cache_integration\\.spec\\.ts$\" --coverage=false --runInBand",
|
|
"test:cache-integration:mcp": "jest --testPathPatterns=\"src/mcp/.*\\.cache_integration\\.spec\\.ts$\" --coverage=false",
|
|
"test:cache-integration:stream": "jest --testPathPatterns=\"src/stream/.*\\.stream_integration\\.spec\\.ts$\" --coverage=false --runInBand --forceExit",
|
|
"test:cache-integration": "npm run test:cache-integration:core && npm run test:cache-integration:cluster && npm run test:cache-integration:mcp && npm run test:cache-integration:stream",
|
|
"test:s3-integration": "jest --testPathPatterns=\"src/storage/s3/.*\\.integration\\.spec\\.ts$\" --coverage=false --runInBand",
|
|
"test:agents-integration": "jest --testPathPatterns=\"src/agents/.*\\.integration\\.spec\\.ts$\" --coverage=false --runInBand --forceExit",
|
|
"verify": "npm run test:ci",
|
|
"b:clean": "bun run rimraf dist",
|
|
"b:build": "bun run b:clean && bun run tsdown",
|
|
"b:build:dev": "bun run b:clean && bun run tsdown",
|
|
"start:everything-sse": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/examples/everything/sse.ts",
|
|
"start:everything": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/demo/everything.ts",
|
|
"start:filesystem": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/demo/filesystem.ts",
|
|
"start:servers": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/demo/servers.ts"
|
|
},
|
|
"repository": {
|
|
"type": "git",
|
|
"url": "git+https://github.com/danny-avila/LibreChat.git"
|
|
},
|
|
"author": "",
|
|
"license": "ISC",
|
|
"bugs": {
|
|
"url": "https://github.com/danny-avila/LibreChat/issues"
|
|
},
|
|
"homepage": "https://librechat.ai",
|
|
"devDependencies": {
|
|
"@babel/preset-env": "^7.29.5",
|
|
"@babel/preset-react": "^7.18.6",
|
|
"@babel/preset-typescript": "^7.21.0",
|
|
"@langchain/langgraph": "^1.4.5",
|
|
"@types/bun": "^1.2.15",
|
|
"@types/express": "^5.0.0",
|
|
"@types/express-session": "^1.18.2",
|
|
"@types/jest": "^29.5.2",
|
|
"@types/jsdom": "^21.1.7",
|
|
"@types/jsonwebtoken": "^9.0.0",
|
|
"@types/multer": "^1.4.13",
|
|
"@types/node": "^24.12.4",
|
|
"@types/node-fetch": "^2.6.13",
|
|
"@types/react": "^18.2.18",
|
|
"@types/sanitize-html": "^2.16.1",
|
|
"@types/supertest": "^7.2.0",
|
|
"@types/yauzl": "^2.10.3",
|
|
"aws-sdk-client-mock": "^4.1.0",
|
|
"babel-plugin-replace-ts-export-assignment": "^0.0.2",
|
|
"dedent": "^1.5.3",
|
|
"get-stream": "^6.0.1",
|
|
"jest": "^30.2.0",
|
|
"jest-junit": "^17.0.0",
|
|
"jszip": "^3.10.1",
|
|
"librechat-data-provider": "*",
|
|
"lodash": "^4.17.23",
|
|
"mammoth": "^1.11.0",
|
|
"mongodb": "^6.14.2",
|
|
"nanoid": "^3.3.18",
|
|
"pdfjs-dist": "^5.4.624",
|
|
"rimraf": "^6.1.3",
|
|
"ts-node": "^10.9.2",
|
|
"tsdown": "^0.22.2",
|
|
"typescript": "^5.9.3",
|
|
"winston": "^3.17.0",
|
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
|
|
"yauzl": "^3.2.1"
|
|
},
|
|
"publishConfig": {
|
|
"registry": "https://registry.npmjs.org/"
|
|
},
|
|
"peerDependencies": {
|
|
"@anthropic-ai/vertex-sdk": "^0.16.0",
|
|
"@aws-sdk/client-bedrock-runtime": "^3.1013.0",
|
|
"@aws-sdk/client-cloudfront": "^3.1042.0",
|
|
"@aws-sdk/client-s3": "^3.980.0",
|
|
"@aws-sdk/cloudfront-signer": "^3.1036.0",
|
|
"@aws-sdk/credential-providers": "^3.1045.0",
|
|
"@aws-sdk/s3-request-presigner": "^3.758.0",
|
|
"@azure/identity": "^4.13.1",
|
|
"@azure/search-documents": "^12.0.0",
|
|
"@azure/storage-blob": "^12.30.0",
|
|
"@google/genai": "^2.8.0",
|
|
"@keyv/redis": "5.1.6",
|
|
"@librechat/agents": "^3.7.21",
|
|
"@librechat/data-schemas": "*",
|
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
"@opentelemetry/api": "^1.9.0",
|
|
"@opentelemetry/instrumentation-express": "^0.56.0",
|
|
"@opentelemetry/instrumentation-http": "^0.207.0",
|
|
"@opentelemetry/instrumentation-ioredis": "^0.55.0",
|
|
"@opentelemetry/instrumentation-mongodb": "^0.60.0",
|
|
"@opentelemetry/instrumentation-mongoose": "^0.54.0",
|
|
"@opentelemetry/instrumentation-undici": "^0.18.0",
|
|
"@opentelemetry/resources": "^2.6.1",
|
|
"@opentelemetry/sdk-node": "^0.218.0",
|
|
"@opentelemetry/semantic-conventions": "^1.39.0",
|
|
"@opentelemetry/winston-transport": "^0.28.0",
|
|
"@redis/client": "5.10.0",
|
|
"@smithy/node-http-handler": "^4.4.5",
|
|
"ai-tokenizer": "^1.0.6",
|
|
"axios": "^1.20.0",
|
|
"connect-redis": "^8.1.0",
|
|
"dedent": "^1.5.3",
|
|
"dompurify": "^3.4.12",
|
|
"eventsource": "^3.0.2",
|
|
"express": "^5.1.0",
|
|
"express-session": "^1.18.2",
|
|
"firebase": "^11.0.2",
|
|
"form-data": "^4.0.4",
|
|
"get-stream": "^6.0.1",
|
|
"google-auth-library": "^9.15.1",
|
|
"https-proxy-agent": "^7.0.6",
|
|
"ioredis": "^5.3.2",
|
|
"js-yaml": "^4.2.0",
|
|
"jsdom": "^26.1.0",
|
|
"jsonwebtoken": "^9.0.0",
|
|
"jszip": "^3.10.1",
|
|
"jwks-rsa": "^3.2.0",
|
|
"keyv": "5.6.0",
|
|
"keyv-file": "^5.1.2",
|
|
"librechat-data-provider": "*",
|
|
"lodash": "^4.17.23",
|
|
"mammoth": "^1.11.0",
|
|
"mathjs": "^15.2.0",
|
|
"memorystore": "^1.6.7",
|
|
"mongodb": "^6.14.2",
|
|
"mongoose": "^8.24.1",
|
|
"nanoid": "^3.3.7",
|
|
"node-fetch": "2.7.0",
|
|
"pdfjs-dist": "^5.4.624",
|
|
"prom-client": "^15.1.3",
|
|
"rate-limit-redis": "^4.2.0",
|
|
"re2js": "^2.8.6",
|
|
"sanitize-html": "^2.17.7",
|
|
"sharp": "^0.35.3",
|
|
"undici": "^7.29.0",
|
|
"yauzl": "^3.2.1",
|
|
"zod": "^3.22.4"
|
|
},
|
|
"dependencies": {
|
|
"@langchain/langgraph-checkpoint": "^1.1.2",
|
|
"@langchain/langgraph-checkpoint-mongodb": "^1.4.0",
|
|
"cluster-key-slot": "^1.1.2",
|
|
"croner": "^10.0.1",
|
|
"express-rate-limit": "^8.5.1",
|
|
"helmet": "^8.3.0",
|
|
"proxy-from-env": "^2.1.0",
|
|
"re2js": "^2.8.6"
|
|
}
|
|
}
|