From 10228b72b520efbe38e3351972e9f6126238d044 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Feb 2026 09:26:30 +0000 Subject: [PATCH 1/3] Initial plan From d1ae409ca1bfd5cca9238d45f2c06061cd5d4a38 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Feb 2026 09:28:19 +0000 Subject: [PATCH 2/3] Remove unused dependencies from apps/arkiver package Co-authored-by: MightyPrytanis <219587333+MightyPrytanis@users.noreply.github.com> --- apps/arkiver/package-lock.json | 1123 -------------------------------- apps/arkiver/package.json | 5 +- 2 files changed, 1 insertion(+), 1127 deletions(-) diff --git a/apps/arkiver/package-lock.json b/apps/arkiver/package-lock.json index b0c5ef22..8f762cdf 100644 --- a/apps/arkiver/package-lock.json +++ b/apps/arkiver/package-lock.json @@ -7,10 +7,6 @@ "": { "name": "@cyrano/arkiver", "version": "1.0.0", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.26.0", - "zod": "^4.3.5" - }, "devDependencies": { "@types/node": "^25.0.9", "tsx": "^4.7.0", @@ -459,58 +455,6 @@ "node": ">=18" } }, - "node_modules/@hono/node-server": { - "version": "1.19.9", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", - "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", - "license": "MIT", - "engines": { - "node": ">=18.14.1" - }, - "peerDependencies": { - "hono": "^4" - } - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.26.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", - "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", - "license": "MIT", - "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" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "@cfworker/json-schema": { - "optional": true - }, - "zod": { - "optional": false - } - } - }, "node_modules/@types/node": { "version": "25.0.9", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.9.tgz", @@ -521,266 +465,6 @@ "undici-types": "~7.16.0" } }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/body-parser": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", - "license": "MIT", - "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" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/content-disposition": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", - "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/esbuild": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.0.tgz", @@ -823,164 +507,6 @@ "@esbuild/win32-x64": "0.27.0" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventsource": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", - "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", - "license": "MIT", - "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" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.2.1.tgz", - "integrity": "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==", - "license": "MIT", - "dependencies": { - "ip-address": "10.0.1" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": ">= 4.11" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/finalhandler": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -996,52 +522,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/get-tsconfig": { "version": "4.13.0", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", @@ -1055,354 +535,6 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hono": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.8.tgz", - "integrity": "sha512-eVkB/CYCCei7K2WElZW9yYQFWssG0DhaDhVvr7wy5jJ22K+ck8fWW0EsLpB0sITUTvPnc97+rrbQqIr5iqiy9Q==", - "license": "MIT", - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ip-address": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", - "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/jose": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", - "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/json-schema-typed": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", - "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", - "license": "BSD-2-Clause" - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/pkce-challenge": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", - "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -1413,190 +545,6 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.3", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.1", - "mime-types": "^3.0.2", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/serve-static": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, "node_modules/tsx": { "version": "4.21.0", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", @@ -1617,20 +565,6 @@ "fsevents": "~2.3.3" } }, - "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -1651,63 +585,6 @@ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "dev": true, "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/zod": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz", - "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.25.1", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", - "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", - "license": "ISC", - "peerDependencies": { - "zod": "^3.25 || ^4" - } } } } diff --git a/apps/arkiver/package.json b/apps/arkiver/package.json index c1113d37..c85b9398 100644 --- a/apps/arkiver/package.json +++ b/apps/arkiver/package.json @@ -8,10 +8,7 @@ "build": "cd frontend && npm run build", "preview": "cd frontend && npm run preview" }, - "dependencies": { - "@modelcontextprotocol/sdk": "^1.26.0", - "zod": "^4.3.5" - }, + "dependencies": {}, "devDependencies": { "@types/node": "^25.0.9", "tsx": "^4.7.0", From 606901c8c58f282cf090c6dbe3cbf77c07d4f1dd Mon Sep 17 00:00:00 2001 From: MightyPrytanis Date: Sun, 8 Feb 2026 16:53:43 -0500 Subject: [PATCH 3/3] Add global error handler to Cyrano/src/http-bridge.ts --- Cyrano/src/http-bridge.ts | 1553 +------------------------------------ 1 file changed, 14 insertions(+), 1539 deletions(-) diff --git a/Cyrano/src/http-bridge.ts b/Cyrano/src/http-bridge.ts index ffbec15f..52152375 100644 --- a/Cyrano/src/http-bridge.ts +++ b/Cyrano/src/http-bridge.ts @@ -1,1540 +1,15 @@ -/** - * Cyrano HTTP Bridge - Exposes MCP Server via HTTP - * - * This bridge allows web applications like LexFiat to communicate - * with the Cyrano MCP server via HTTP instead of stdio. - * - * HYBRID LAZY-LOADING APPROACH WITH CRITICAL SAFEGUARDS: - * - Essential infrastructure loads first (express, security, routes) - * - Server starts immediately - * - Tools load asynchronously in background after server starts - * - Handlers use dynamic imports for on-demand tool loading - * - Race condition protection (loading locks) - * - Timeout protection (30s timeout prevents hangs) - * - Circuit breaker (stops retrying after 5 failures) - */ -/* - * Copyright 2025 Cognisint LLC - * Licensed under the Apache License, Version 2.0 - * See LICENSE.md for full license text - */ - -console.error('[HTTP Bridge] Starting module load...'); - -// ============================================================================ -// ESSENTIAL IMPORTS ONLY - These must load before server starts -// ============================================================================ - -import express from 'express'; -console.error('[HTTP Bridge] Express imported'); -import cors, { CorsOptions } from 'cors'; -console.error('[HTTP Bridge] CORS imported'); -import dotenv from 'dotenv'; -import multer from 'multer'; -import cookieParser from 'cookie-parser'; -// CSRF protection now handled by security.ts custom implementation -console.error('[HTTP Bridge] Basic middleware imported'); - -// Load environment variables -dotenv.config(); -console.error('[HTTP Bridge] Environment loaded'); - -import { Server } from '@modelcontextprotocol/sdk/server/index.js'; -import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; -import { z } from 'zod'; -import { - CallToolRequestSchema, - ListToolsRequestSchema, - Tool, - CallToolResult, -} from '@modelcontextprotocol/sdk/types.js'; - -// Import security middleware (essential for server security) -console.error('[HTTP Bridge] Importing security middleware...'); -import security from './middleware/security.js'; -console.error('[HTTP Bridge] Security middleware imported'); - -// Import routes (these may import db, but server can start even if db fails) -console.error('[HTTP Bridge] Importing routes...'); -import authRoutes from './routes/auth.js'; -import libraryRoutes from './routes/library.js'; -import onboardingRoutes from './routes/onboarding.js'; -import betaRoutes from './routes/beta.js'; -console.error('[HTTP Bridge] Routes imported'); - -// ============================================================================ -// ENHANCED TOOL LOADER WITH CRITICAL SAFEGUARDS -// ============================================================================ - -interface ToolInstance { - getToolDefinition: () => Tool; - execute: (args: T) => Promise; -} - -interface ToolMetadata { - name: string; - version?: string; - dependencies?: string[]; - loadTime?: number; - lastUsed?: Date; - useCount: number; - errorCount: number; - lastError?: string; - status: 'loaded' | 'loading' | 'error' | 'unloaded'; -} - -type ToolLoader = () => Promise | { default: ToolInstance }>; - -// Tool import map with metadata -const toolImportMap: Record }> = { - // Legal AI Tools - document_analyzer: { - loader: () => import('./tools/document-analyzer.js').then(m => m.documentAnalyzer), - metadata: { name: 'document_analyzer', dependencies: [] } - }, - contract_comparator: { - loader: () => import('./tools/contract-comparator.js').then(m => m.contractComparator), - metadata: { name: 'contract_comparator', dependencies: [] } - }, - good_counsel: { - loader: () => import('./tools/goodcounsel.js').then(m => m.goodCounsel), - metadata: { name: 'good_counsel', dependencies: [] } - }, - fact_checker: { - loader: () => import('./tools/fact-checker.js').then(m => m.factChecker), - metadata: { name: 'fact_checker', dependencies: [] } - }, - legal_reviewer: { - loader: () => import('./tools/legal-reviewer.js').then(m => m.legalReviewer), - metadata: { name: 'legal_reviewer', dependencies: [] } - }, - compliance_checker: { - loader: () => import('./tools/compliance-checker.js').then(m => m.complianceChecker), - metadata: { name: 'compliance_checker', dependencies: [] } - }, - quality_assessor: { - loader: () => import('./tools/quality-assessor.js').then(m => m.qualityAssessor), - metadata: { name: 'quality_assessor', dependencies: [] } - }, - workflow_manager: { - loader: () => import('./tools/workflow-manager.js').then(m => m.workflowManager), - metadata: { name: 'workflow_manager', dependencies: [] } - }, - case_manager: { - loader: () => import('./tools/case-manager.js').then(m => m.caseManager), - metadata: { name: 'case_manager', dependencies: [] } - }, - document_processor: { - loader: () => import('./tools/document-processor.js').then(m => m.documentProcessor), - metadata: { name: 'document_processor', dependencies: [] } - }, - ai_orchestrator: { - loader: () => import('./engines/mae/services/ai-orchestrator.js').then(m => m.aiOrchestrator), - metadata: { name: 'ai_orchestrator', dependencies: ['mae_engine'] } - }, - system_status: { - loader: () => import('./tools/system-status.js').then(m => m.systemStatus), - metadata: { name: 'system_status', dependencies: [] } - }, - rag_query: { - loader: () => import('./tools/rag-query.js').then(m => m.ragQuery), - metadata: { name: 'rag_query', dependencies: [] } - }, - auth: { - loader: () => import('./tools/auth.js').then(m => m.authTool), - metadata: { name: 'auth', dependencies: [] } - }, - sync_manager: { - loader: () => import('./tools/sync-manager.js').then(m => m.syncManager), - metadata: { name: 'sync_manager', dependencies: [] } - }, - red_flag_finder: { - loader: () => import('./tools/red-flag-finder.js').then(m => m.redFlagFinder), - metadata: { name: 'red_flag_finder', dependencies: [] } - }, - clio_integration: { - loader: () => import('./tools/clio-integration.js').then(m => m.clioIntegration), - metadata: { name: 'clio_integration', dependencies: [] } - }, - micourt_query: { - loader: () => import('./tools/micourt-query.js').then(m => m.micourtQuery), - metadata: { name: 'micourt_query', dependencies: [] } - }, - time_value_billing: { - loader: () => import('./tools/time-value-billing.js').then(m => m.timeValueBilling), - metadata: { name: 'time_value_billing', dependencies: [] } - }, - tasks_collector: { - loader: () => import('./tools/tasks-collector.js').then(m => m.tasksCollector), - metadata: { name: 'tasks_collector', dependencies: [] } - }, - contacts_collector: { - loader: () => import('./tools/contacts-collector.js').then(m => m.contactsCollector), - metadata: { name: 'contacts_collector', dependencies: [] } - }, - document_drafter: { - loader: () => import('./tools/document-drafter.js').then(m => m.documentDrafterTool), - metadata: { name: 'document_drafter', dependencies: [] } - }, - ethics_reviewer: { - loader: () => import('./engines/goodcounsel/tools/ethics-reviewer.js').then(m => m.ethicsReviewer), - metadata: { name: 'ethics_reviewer', dependencies: ['goodcounsel_engine'] } - }, - ethical_ai_guard: { - loader: () => import('./tools/ethical-ai-guard.js').then(m => m.ethicalAIGuard), - metadata: { name: 'ethical_ai_guard', dependencies: [] } - }, - ten_rules_checker: { - loader: () => import('./tools/ten-rules-checker.js').then(m => m.tenRulesChecker), - metadata: { name: 'ten_rules_checker', dependencies: [] } - }, - ethics_policy_explainer: { - loader: () => import('./tools/ethics-policy-explainer.js').then(m => m.ethicsPolicyExplainer), - metadata: { name: 'ethics_policy_explainer', dependencies: [] } - }, - - // Arkiver Tools - extract_conversations: { - loader: () => import('./tools/arkiver-tools.js').then(m => m.extractConversations), - metadata: { name: 'extract_conversations', dependencies: [] } - }, - extract_text_content: { - loader: () => import('./tools/arkiver-tools.js').then(m => m.extractTextContent), - metadata: { name: 'extract_text_content', dependencies: [] } - }, - categorize_with_keywords: { - loader: () => import('./tools/arkiver-tools.js').then(m => m.categorizeWithKeywords), - metadata: { name: 'categorize_with_keywords', dependencies: [] } - }, - process_with_regex: { - loader: () => import('./tools/arkiver-tools.js').then(m => m.processWithRegex), - metadata: { name: 'process_with_regex', dependencies: [] } - }, - generate_categorized_files: { - loader: () => import('./tools/arkiver-tools.js').then(m => m.generateCategorizedFiles), - metadata: { name: 'generate_categorized_files', dependencies: [] } - }, - run_extraction_pipeline: { - loader: () => import('./tools/arkiver-tools.js').then(m => m.runExtractionPipeline), - metadata: { name: 'run_extraction_pipeline', dependencies: [] } - }, - create_arkiver_config: { - loader: () => import('./tools/arkiver-tools.js').then(m => m.createArkiverConfig), - metadata: { name: 'create_arkiver_config', dependencies: [] } - }, - arkiver_process_text: { - loader: () => import('./tools/arkiver-processor-tools.js').then(m => m.arkiverTextProcessor), - metadata: { name: 'arkiver_process_text', dependencies: [] } - }, - arkiver_process_email: { - loader: () => import('./tools/arkiver-processor-tools.js').then(m => m.arkiverEmailProcessor), - metadata: { name: 'arkiver_process_email', dependencies: [] } - }, - arkiver_extract_entities: { - loader: () => import('./tools/arkiver-processor-tools.js').then(m => m.arkiverEntityProcessor), - metadata: { name: 'arkiver_extract_entities', dependencies: [] } - }, - arkiver_generate_insights: { - loader: () => import('./tools/arkiver-processor-tools.js').then(m => m.arkiverInsightProcessor), - metadata: { name: 'arkiver_generate_insights', dependencies: [] } - }, - arkiver_extract_timeline: { - loader: () => import('./tools/arkiver-processor-tools.js').then(m => m.arkiverTimelineProcessor), - metadata: { name: 'arkiver_extract_timeline', dependencies: [] } - }, - arkiver_process_file: { - loader: () => import('./tools/arkiver-mcp-tools.js').then(m => m.arkiverProcessFileTool), - metadata: { name: 'arkiver_process_file', dependencies: [] } - }, - arkiver_job_status: { - loader: () => import('./tools/arkiver-mcp-tools.js').then(m => m.arkiverJobStatusTool), - metadata: { name: 'arkiver_job_status', dependencies: [] } - }, - arkiver_integrity_test: { - loader: () => import('./tools/arkiver-integrity-test.js').then(m => m.arkiverIntegrityTestTool), - metadata: { name: 'arkiver_integrity_test', dependencies: [] } - }, - - // Chronometric Tools - gap_identifier: { - loader: () => import('./tools/gap-identifier.js').then(m => m.gapIdentifier), - metadata: { name: 'gap_identifier', dependencies: [] } - }, - email_artifact_collector: { - loader: () => import('./tools/email-artifact-collector.js').then(m => m.emailArtifactCollector), - metadata: { name: 'email_artifact_collector', dependencies: [] } - }, - calendar_artifact_collector: { - loader: () => import('./tools/calendar-artifact-collector.js').then(m => m.calendarArtifactCollector), - metadata: { name: 'calendar_artifact_collector', dependencies: [] } - }, - document_artifact_collector: { - loader: () => import('./tools/document-artifact-collector.js').then(m => m.documentArtifactCollector), - metadata: { name: 'document_artifact_collector', dependencies: [] } - }, - recollection_support: { - loader: () => import('./tools/recollection-support.js').then(m => m.recollectionSupport), - metadata: { name: 'recollection_support', dependencies: [] } - }, - pre_fill_logic: { - loader: () => import('./tools/pre-fill-logic.js').then(m => m.preFillLogic), - metadata: { name: 'pre_fill_logic', dependencies: [] } - }, - dupe_check: { - loader: () => import('./tools/dupe-check.js').then(m => m.dupeCheck), - metadata: { name: 'dupe_check', dependencies: [] } - }, - provenance_tracker: { - loader: () => import('./tools/provenance-tracker.js').then(m => m.provenanceTracker), - metadata: { name: 'provenance_tracker', dependencies: [] } - }, - workflow_archaeology: { - loader: () => import('./tools/workflow-archaeology.js').then(m => m.workflowArchaeology), - metadata: { name: 'workflow_archaeology', dependencies: [] } - }, - - // Module/Engine Wrappers - chronometric_module: { - loader: () => import('./tools/chronometric-module.js').then(m => m.chronometricModuleTool), - metadata: { name: 'chronometric_module', dependencies: [] } - }, - mae_engine: { - loader: () => import('./tools/mae-engine.js').then(m => m.maeEngineTool), - metadata: { name: 'mae_engine', dependencies: [] } - }, - goodcounsel_engine: { - loader: () => import('./tools/goodcounsel-engine.js').then(m => m.goodcounselEngineTool), - metadata: { name: 'goodcounsel_engine', dependencies: [] } - }, - potemkin_engine: { - loader: () => import('./tools/potemkin-engine.js').then(m => m.potemkinEngineTool), - metadata: { name: 'potemkin_engine', dependencies: [] } - }, - forecast_engine: { - loader: () => import('./tools/forecast-engine.js').then(m => m.forecastEngineTool), - metadata: { name: 'forecast_engine', dependencies: [] } - }, - - // Verification Tools - claim_extractor: { - loader: () => import('./tools/verification/claim-extractor.js').then(m => m.claimExtractor), - metadata: { name: 'claim_extractor', dependencies: [] } - }, - citation_checker: { - loader: () => import('./tools/verification/citation-checker.js').then(m => m.citationChecker), - metadata: { name: 'citation_checker', dependencies: [] } - }, - citation_formatter: { - loader: () => import('./tools/verification/citation-formatter.js').then(m => m.citationFormatter), - metadata: { name: 'citation_formatter', dependencies: [] } - }, - source_verifier: { - loader: () => import('./tools/verification/source-verifier.js').then(m => m.sourceVerifier), - metadata: { name: 'source_verifier', dependencies: [] } - }, - consistency_checker: { - loader: () => import('./tools/verification/consistency-checker.js').then(m => m.consistencyChecker), - metadata: { name: 'consistency_checker', dependencies: [] } - }, - - // Potemkin Tools - history_retriever: { - loader: () => import('./engines/potemkin/tools/index.js').then(m => m.historyRetriever), - metadata: { name: 'history_retriever', dependencies: ['potemkin_engine'] } - }, - drift_calculator: { - loader: () => import('./engines/potemkin/tools/index.js').then(m => m.driftCalculator), - metadata: { name: 'drift_calculator', dependencies: ['potemkin_engine'] } - }, - bias_detector: { - loader: () => import('./engines/potemkin/tools/index.js').then(m => m.biasDetector), - metadata: { name: 'bias_detector', dependencies: ['potemkin_engine'] } - }, - integrity_monitor: { - loader: () => import('./engines/potemkin/tools/index.js').then(m => m.integrityMonitor), - metadata: { name: 'integrity_monitor', dependencies: ['potemkin_engine'] } - }, - alert_generator: { - loader: () => import('./engines/potemkin/tools/index.js').then(m => m.alertGenerator), - metadata: { name: 'alert_generator', dependencies: ['potemkin_engine'] } - }, - - // Legal Email Tools - draft_legal_email: { - loader: () => import('./tools/legal-email-drafter.js').then(m => m.legalEmailDrafter), - metadata: { name: 'draft_legal_email', dependencies: [] } - }, - refine_email_tone: { - loader: () => import('./tools/legal-email-drafter.js').then(m => m.refineEmailTone), - metadata: { name: 'refine_email_tone', dependencies: [] } - }, - validate_legal_language: { - loader: () => import('./tools/legal-email-drafter.js').then(m => m.validateLegalLanguage), - metadata: { name: 'validate_legal_language', dependencies: [] } - }, - - // Other Tools - cyrano_pathfinder: { - loader: () => import('./tools/cyrano-pathfinder.js').then(m => m.cyranoPathfinder), - metadata: { name: 'cyrano_pathfinder', dependencies: [] } - }, - custodian_engine: { - loader: () => import('./tools/custodian-engine.js').then(m => m.custodianEngineTool), - metadata: { name: 'custodian_engine', dependencies: [] } - }, - skill_executor: { - loader: () => import('./tools/skill-executor.js').then(m => m.skillExecutor), - metadata: { name: 'skill_executor', dependencies: [] } - }, - beta_test_support: { - loader: () => import('./tools/beta-test-support.js').then(m => m.betaTestSupport), - metadata: { name: 'beta_test_support', dependencies: [] } - }, - mcr_validator: { - loader: () => import('./tools/mcr-validator.js').then(m => m.mcrValidator), - metadata: { name: 'mcr_validator', dependencies: [] } - }, - - // Ethics Tools (special handling for getEthicsAuditTool/getEthicsStatsTool) - get_ethics_audit: { - loader: () => import('./tools/ethics-audit-tools.js').then(m => m.getEthicsAuditTool), - metadata: { name: 'get_ethics_audit', dependencies: [] } - }, - get_ethics_stats: { - loader: () => import('./tools/ethics-audit-tools.js').then(m => m.getEthicsStatsTool), - metadata: { name: 'get_ethics_stats', dependencies: [] } - }, - - // Wellness Tools - wellness_journal: { - loader: () => import('./tools/wellness-journal.js').then(m => m.wellnessJournalTool), - metadata: { name: 'wellness_journal', dependencies: [] } - }, - - // GoodCounsel Prompt Tools - get_goodcounsel_prompts: { - loader: () => import('./tools/goodcounsel-prompts.js').then(m => m.getGoodCounselPromptsTool), - metadata: { name: 'get_goodcounsel_prompts', dependencies: [] } - }, - dismiss_goodcounsel_prompt: { - loader: () => import('./tools/goodcounsel-prompts.js').then(m => m.dismissGoodCounselPromptTool), - metadata: { name: 'dismiss_goodcounsel_prompt', dependencies: [] } - }, - snooze_goodcounsel_prompt_type: { - loader: () => import('./tools/goodcounsel-prompts.js').then(m => m.snoozeGoodCounselPromptTypeTool), - metadata: { name: 'snooze_goodcounsel_prompt_type', dependencies: [] } - }, - get_goodcounsel_prompt_history: { - loader: () => import('./tools/goodcounsel-prompts.js').then(m => m.getGoodCounselPromptHistoryTool), - metadata: { name: 'get_goodcounsel_prompt_history', dependencies: [] } - }, - evaluate_goodcounsel_context: { - loader: () => import('./tools/goodcounsel-prompts.js').then(m => m.evaluateGoodCounselContextTool), - metadata: { name: 'evaluate_goodcounsel_context', dependencies: [] } - }, - - // Workflow Status Tool - workflow_status: { - loader: () => import('./tools/workflow-status.js').then(m => m.workflowStatusTool), - metadata: { name: 'workflow_status', dependencies: [] } - }, - -}; - -// Tool cache with enhanced metadata -const toolCache = new Map(); -const toolMetadata = new Map(); - -// CRITICAL SAFEGUARD 1: Loading locks - prevent race conditions -const loadingLocks = new Map>(); - -// CRITICAL SAFEGUARD 2: Circuit breaker state -interface CircuitBreakerState { - failures: number; - lastFailureTime: number; - isOpen: boolean; -} - -const circuitBreakers = new Map(); -const MAX_FAILURES = 5; -const CIRCUIT_BREAKER_TIMEOUT = 60000; // 1 minute -const TOOL_LOAD_TIMEOUT = 30000; // 30 seconds - -// Frequently used tools (preload these first) -const frequentlyUsedTools = [ - 'system_status', - 'auth', - 'document_analyzer', - 'contract_comparator', - 'good_counsel', - 'cyrano_pathfinder' -]; - -// Load a tool dynamically with ALL THREE CRITICAL SAFEGUARDS -async function loadTool(toolName: string, loadDependencies: boolean = true): Promise { - // Fast path: Check cache first - if (toolCache.has(toolName)) { - const metadata = toolMetadata.get(toolName); - if (metadata) { - metadata.lastUsed = new Date(); - metadata.useCount++; - } - return toolCache.get(toolName)!; - } - - // SAFEGUARD 1: Check circuit breaker - const breaker = circuitBreakers.get(toolName); - if (breaker?.isOpen) { - const timeSinceFailure = Date.now() - breaker.lastFailureTime; - if (timeSinceFailure < CIRCUIT_BREAKER_TIMEOUT) { - throw new Error(`Tool ${toolName} is in circuit breaker (too many failures). Retry after ${Math.ceil((CIRCUIT_BREAKER_TIMEOUT - timeSinceFailure) / 1000)}s`); - } else { - // Reset circuit breaker after timeout - circuitBreakers.delete(toolName); - } - } - - // SAFEGUARD 2: Check if already loading (race condition protection) - const existingLoad = loadingLocks.get(toolName); - if (existingLoad) { - // Wait for the existing load to complete - return existingLoad; - } - - // Get tool config - const toolConfig = toolImportMap[toolName]; - if (!toolConfig) { - throw new Error(`Unknown tool: ${toolName}`); - } - - // Initialize metadata - const metadata: ToolMetadata = { - name: toolName, - ...toolConfig.metadata, - status: 'loading', - useCount: 0, - errorCount: 0, - }; - toolMetadata.set(toolName, metadata); - - // Create loading promise with ALL SAFEGUARDS - const loadPromise = (async () => { - try { - // Load dependencies first if requested - if (loadDependencies && toolConfig.metadata.dependencies) { - for (const dep of toolConfig.metadata.dependencies) { - if (!toolCache.has(dep)) { - console.error('[Tool Loader] Loading dependency %s for %s...', dep, toolName); - await loadTool(dep, true); - } - } - } - - // Load tool with timing - const startTime = Date.now(); - - // SAFEGUARD 3: Timeout protection - const timeoutPromise = new Promise((_, reject) => { - setTimeout(() => reject(new Error(`Tool load timeout after ${TOOL_LOAD_TIMEOUT}ms`)), TOOL_LOAD_TIMEOUT); - }); - - // Race between load and timeout - const tool = await Promise.race([ - toolConfig.loader(), - timeoutPromise - ]); - - const loadTime = Date.now() - startTime; - - // Handle both default export and named export - const toolInstance = (tool as any).default || tool; - - // Cache it - toolCache.set(toolName, toolInstance); - metadata.status = 'loaded'; - metadata.loadTime = loadTime; - metadata.lastUsed = new Date(); - metadata.useCount = 1; - - // Reset circuit breaker on success - circuitBreakers.delete(toolName); - - console.error('[Tool Loader] Loaded %s in %sms', toolName, loadTime); - return toolInstance; - } catch (error) { - metadata.status = 'error'; - metadata.errorCount++; - metadata.lastError = error instanceof Error ? error.message : String(error); - - // Update circuit breaker - const breaker = circuitBreakers.get(toolName) || { failures: 0, lastFailureTime: 0, isOpen: false }; - breaker.failures++; - breaker.lastFailureTime = Date.now(); - - if (breaker.failures >= MAX_FAILURES) { - breaker.isOpen = true; - console.error('[Tool Loader] Circuit breaker opened for %s after %s failures', toolName, breaker.failures); - } - - circuitBreakers.set(toolName, breaker); - - console.error('[Tool Loader] Failed to load tool %s:', toolName, error); - throw error; - } finally { - // Remove loading lock - loadingLocks.delete(toolName); - } - })(); - - // Store loading lock - loadingLocks.set(toolName, loadPromise); - - return loadPromise; -} - -// Reload a tool (hot reloading) -async function reloadTool(toolName: string): Promise { - console.error('[Tool Loader] Reloading tool %s...', toolName); - - // Remove from cache - toolCache.delete(toolName); - const metadata = toolMetadata.get(toolName); - if (metadata) { - metadata.status = 'unloaded'; - } - - // Reset circuit breaker - circuitBreakers.delete(toolName); - - try { - await loadTool(toolName, false); // Don't reload dependencies - console.error('[Tool Loader] Successfully reloaded %s', toolName); - return true; - } catch (error) { - console.error('[Tool Loader] Failed to reload %s:', toolName, error); - return false; - } -} - -// Load all tool definitions (for /mcp/tools endpoint) -async function loadAllToolDefinitions(): Promise { - const tools: Tool[] = []; - const errors: string[] = []; - - // Load tools in parallel batches - const toolNames = Object.keys(toolImportMap); - const batchSize = 10; - - for (let i = 0; i < toolNames.length; i += batchSize) { - const batch = toolNames.slice(i, i + batchSize); - const results = await Promise.allSettled( - batch.map(async (toolName) => { - try { - const tool = await loadTool(toolName, true); - return tool.getToolDefinition(); - } catch (error) { - errors.push(`${toolName}: ${error instanceof Error ? error.message : String(error)}`); - return null; - } - }) - ); - - for (const result of results) { - if (result.status === 'fulfilled' && result.value) { - tools.push(result.value); - } - } - } - - if (errors.length > 0) { - console.warn('[Tool Loader] Some tools failed to load: %s', errors.join(', ')); - } - - return tools; -} - -// Preload frequently used tools first, then others -let toolsPreloading = false; -let toolsPreloaded = false; -async function preloadToolsInBackground() { - if (toolsPreloading || toolsPreloaded) return; - toolsPreloading = true; - - console.error('[Tool Loader] Starting background tool preloading...'); - - try { - // Preload frequently used tools first - console.error('[Tool Loader] Preloading %s frequently used tools...', frequentlyUsedTools.length); - await Promise.allSettled( - frequentlyUsedTools.map(toolName => loadTool(toolName, true)) - ); - - // Then preload all other tools - const remainingTools = Object.keys(toolImportMap).filter( - name => !frequentlyUsedTools.includes(name) - ); - console.error('[Tool Loader] Preloading %s remaining tools...', remainingTools.length); - - const batchSize = 10; - for (let i = 0; i < remainingTools.length; i += batchSize) { - const batch = remainingTools.slice(i, i + batchSize); - await Promise.allSettled( - batch.map(toolName => loadTool(toolName, true)) - ); - } - - toolsPreloaded = true; - const loadedCount = Array.from(toolMetadata.values()).filter(m => m.status === 'loaded').length; - console.error('[Tool Loader] Preloaded %s/%s tools', loadedCount, Object.keys(toolImportMap).length); - } catch (error) { - console.error('[Tool Loader] Background preloading failed (non-fatal):', error); - } finally { - toolsPreloading = false; - } -} - -// Get tool health status -function getToolHealth(): { - total: number; - loaded: number; - loading: number; - errors: number; - circuitBreakers: number; - tools: ToolMetadata[]; -} { - const tools = Array.from(toolMetadata.values()); - const openBreakers = Array.from(circuitBreakers.values()).filter(b => b.isOpen).length; - return { - total: tools.length, - loaded: tools.filter(t => t.status === 'loaded').length, - loading: tools.filter(t => t.status === 'loading').length, - errors: tools.filter(t => t.status === 'error').length, - circuitBreakers: openBreakers, - tools: tools.map(t => ({ ...t })) - }; -} - -// ============================================================================ -// EXPRESS APP SETUP -// ============================================================================ - -const app = express(); -app.set('trust proxy', process.env.TRUST_PROXY_COUNT ? parseInt(process.env.TRUST_PROXY_COUNT) : 1); -const port = process.env.PORT || 5002; - -app.disable('x-powered-by'); -app.use(security.secureHeaders); -app.use(cookieParser()); - -// CSRF protection (using custom implementation from security.ts instead of deprecated csurf) -if (process.env.NODE_ENV !== 'test') { - app.use(security.csrfProtection); -} - -// CORS configuration -const isProduction = process.env.NODE_ENV === 'production'; -// Add cognisint.com to allowed origins for beta portal -const defaultOrigins = [ - 'https://cognisint.com', - 'https://www.cognisint.com', -]; -const envOrigins = (process.env.ALLOWED_ORIGINS || '').split(',').map(o => o.trim()).filter(Boolean); -const allowedOrigins = [...defaultOrigins, ...envOrigins]; - -if (isProduction && allowedOrigins.length === 0) { - throw new Error('ALLOWED_ORIGINS must be set in production environment'); -} - -const corsOptions: CorsOptions = { - origin: (origin, callback) => { - if (!origin && !isProduction) { - return callback(null, true); - } - if (!origin && isProduction) { - return callback(new Error('CORS: Origin header required in production')); - } - if (!isProduction && allowedOrigins.length === 0) { - return callback(null, true); - } - if (origin && allowedOrigins.includes(origin)) { - callback(null, true); - } else { - callback(new Error(`CORS: Origin ${origin} not allowed`)); - } - }, - credentials: true, - optionsSuccessStatus: 200 -}; - -app.use(cors(corsOptions)); - -// HTTPS enforcement -app.use((req, res, next) => { - const isSecure = req.secure || req.get('X-Forwarded-Proto') === 'https'; - if (isProduction && !isSecure) { - return res.redirect(301, `https://${req.headers.host}${req.url}`); - } - if (!isProduction && process.env.FORCE_HTTPS === 'true' && !isSecure) { - return res.redirect(301, `https://${req.headers.host}${req.url}`); - } - next(); -}); - -app.use(express.json()); -app.use(express.raw({ type: 'application/octet-stream', limit: '100mb' })); -app.use(security.sanitizeInputs); -app.use(security.authenticatedLimiter); -app.use(security.unauthenticatedLimiter); - -// Multer for file uploads -const upload = multer({ - storage: multer.memoryStorage(), - limits: { - fileSize: 100 * 1024 * 1024, // 100MB - }, -}); - -// MCP Server instance -const mcpServer = new Server( - { - name: 'cyrano-mcp-server', - version: '1.0.0', - }, - { - capabilities: { - tools: {}, - }, - } -); - -// ============================================================================ -// MCP HANDLERS - Use dynamic tool loading -// ============================================================================ - -mcpServer.setRequestHandler(ListToolsRequestSchema, async () => { - try { - const tools = await loadAllToolDefinitions(); - return { tools }; - } catch (error) { - console.error('[MCP] Failed to load tools:', error); - return { tools: [] }; - } -}); - -mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - - try { - const tool = await loadTool(name); - return await tool.execute(args); - } catch (error) { - return { - content: [ - { - type: 'text', - text: `Error executing tool ${name}: ${error instanceof Error ? error.message : String(error)}`, - }, - ], - isError: true, - }; - } -}); - -// ============================================================================ -// HTTP ROUTES -// ============================================================================ - -app.get('/mcp/tools', async (req, res) => { - try { - const allTools = await loadAllToolDefinitions(); - - // Filter out admin-only tools for non-admin users - const adminOnlyTools = [ - 'custodian_engine', - 'custodian_status', - 'custodian_health_check', - 'custodian_update_dependencies', - 'custodian_apply_fix', - 'custodian_alert_admin', - 'custodian_failsafe', - ]; - - // Check if user is admin - try { - const { isAdminRequest } = await import('./utils/admin-auth.js'); - const isAdmin = isAdminRequest(req); - - // Filter tools based on admin status - const tools = isAdmin - ? allTools - : allTools.filter(tool => !adminOnlyTools.includes(tool.name)); - - res.json({ tools }); - } catch { - // If admin auth check fails, filter out admin tools (fail secure) - const tools = allTools.filter(tool => !adminOnlyTools.includes(tool.name)); - res.json({ tools }); - } - } catch (error) { - console.error('[HTTP] Failed to get tools:', error); - res.status(500).json({ error: 'Failed to get tools' }); - } -}); - -app.post('/mcp/execute', async (req, res) => { - try { - const ExecuteRequestSchema = z.object({ - tool: z.string().min(1, 'Tool name is required'), - input: z.any().optional(), - arguments: z.any().optional(), - }); - - const validationResult = ExecuteRequestSchema.safeParse(req.body); - if (!validationResult.success) { - return res.status(400).json({ - error: 'Invalid request body', - details: validationResult.error.issues, - }); - } - - const { tool, input, arguments: args } = validationResult.data; - const toolInput = input || args || {}; - - // Check if tool is admin-only (Custodian tools) - const adminOnlyTools = [ - 'custodian_engine', - 'custodian_status', - 'custodian_health_check', - 'custodian_update_dependencies', - 'custodian_apply_fix', - 'custodian_alert_admin', - 'custodian_failsafe', - ]; - - if (adminOnlyTools.includes(tool)) { - // Import admin auth utility - try { - const { isAdminRequest } = await import('./utils/admin-auth.js'); - if (!isAdminRequest(req)) { - return res.status(403).json({ - content: [ - { - type: 'text', - text: 'Admin access required. This tool is only available to administrators.', - }, - ], - isError: true, - }); - } - } catch { - // If admin auth check fails, deny access (fail secure) - return res.status(403).json({ - content: [ - { - type: 'text', - text: 'Admin access required. This tool is only available to administrators.', - }, - ], - isError: true, - }); - } - } - - const toolInstance = await loadTool(tool); - const result = await toolInstance.execute(toolInput); - res.json(result); - } catch (error) { - res.status(500).json({ - content: [ - { - type: 'text', - text: `Error executing tool: ${error instanceof Error ? error.message : 'Unknown error'}`, - }, - ], - isError: true, - }); - } -}); - -app.get('/mcp/status', (req, res) => { - const health = getToolHealth(); - res.json({ - status: 'running', - server: 'cyrano-mcp-http-bridge', - tools: health - }); -}); - -// Tool health monitoring endpoint -app.get('/mcp/tools/health', (req, res) => { - const health = getToolHealth(); - res.json(health); -}); - -// Hot reload endpoint (admin only - should add auth in production) -app.post('/mcp/tools/:toolName/reload', async (req, res) => { - const { toolName } = req.params; - - if (!toolImportMap[toolName]) { - return res.status(404).json({ error: `Tool ${toolName} not found` }); - } - - const success = await reloadTool(toolName); - if (success) { - res.json({ success: true, message: `Tool ${toolName} reloaded successfully` }); - } else { - res.status(500).json({ success: false, message: `Failed to reload tool ${toolName}` }); - } -}); - -// GoodCounsel API endpoint -app.get('/api/good-counsel/overview', async (req, res) => { - try { - const goodCounsel = await loadTool('good_counsel'); - const result = await goodCounsel.execute({}); - const textContent = (result.content[0] && result.content[0].type === 'text' && 'text' in result.content[0]) ? result.content[0].text : ''; - if (textContent && typeof textContent === 'string') { - try { - const parsed = JSON.parse(textContent); - res.json(parsed); - } catch (parseError) { - res.json({ content: textContent }); - } - } else { - res.json({ error: 'No content available' }); - } - } catch (error) { - res.status(500).json({ - error: 'Failed to get GoodCounsel overview', - details: error instanceof Error ? error.message : 'Unknown error' - }); - } -}); - -// ============================================================================ -// FORECASTER API (LexFiat Forecaster™ standalone frontend compatibility) -// ============================================================================ - -// Import FederalTaxInputSchema dynamically for validation -// Note: We use z.lazy() to avoid circular dependency issues with dynamic imports -const ForecastHttpRequestSchema = z.object({ - forecast_input: z.lazy(() => { - // This will be validated in the handler after importing the schema - // Using z.record allows flexibility for additional properties - return z.record(z.string(), z.any()); - }), - branding: z.object({ - presentationMode: z.enum(['strip', 'watermark', 'none']).optional(), - userRole: z.enum(['attorney', 'staff', 'client', 'other']).optional(), - licensedInAny: z.boolean().optional(), - riskAcknowledged: z.boolean().optional(), - }).optional(), -}); - -function extractTextPayload(result: any): string { - const item = result?.content?.find?.((c: any) => c?.type === 'text' && 'text' in c); - return item?.text || ''; -} - -app.post('/api/forecast/tax', async (req, res) => { - try { - const parsed = ForecastHttpRequestSchema.safeParse(req.body); - if (!parsed.success) { - return res.status(400).json({ success: false, error: 'Invalid request body', details: parsed.error.issues }); - } - - const { forecast_input, branding } = parsed.data; - const presentationMode = branding?.presentationMode ?? 'strip'; - const riskAcknowledged = branding?.riskAcknowledged ?? false; - - if (presentationMode === 'none' && !riskAcknowledged) { - return res.status(400).json({ - success: false, - error: 'Risk acknowledgement required to disable LexFiat Forecaster™ advisories/branding.', - presentationMode: 'strip', - }); - } - - // Use calculateFederal() for complete credit calculations (CTC/ODC/ACTC/EITC) - const { calculateFederal, FederalTaxInputSchema } = await import('./modules/forecast/formulas/tax-formulas.js'); - - // Validate forecast_input with FederalTaxInputSchema for type safety - const validationResult = FederalTaxInputSchema.safeParse(forecast_input); - if (!validationResult.success) { - return res.status(400).json({ - success: false, - error: 'Invalid forecast_input data', - details: validationResult.error.issues - }); - } - - const calculatedValues = calculateFederal(validationResult.data); - - res.json({ - success: true, - forecastType: 'tax_return', - calculatedValues, - brandingApplied: presentationMode !== 'none', - presentationMode, - }); - } catch (error) { - res.status(500).json({ - success: false, - error: error instanceof Error ? error.message : 'Unknown error', - }); - } -}); - -// Returns a branded, filled PDF as application/pdf -app.post('/api/forecast/tax/pdf', async (req, res) => { - try { - const parsed = ForecastHttpRequestSchema.safeParse(req.body); - if (!parsed.success) { - return res.status(400).json({ success: false, error: 'Invalid request body', details: parsed.error.issues }); - } - - const { forecast_input, branding } = parsed.data; - const year = forecast_input?.year || new Date().getFullYear(); - - // 1) Calculate values using calculateFederal() for complete credit calculations - const { calculateFederal, FederalTaxInputSchema } = await import('./modules/forecast/formulas/tax-formulas.js'); - - // Validate forecast_input with Zod schema - const validationResult = FederalTaxInputSchema.safeParse(forecast_input); - if (!validationResult.success) { - return res.status(400).json({ - success: false, - error: 'Invalid forecast_input data', - details: validationResult.error.issues - }); - } - - const calculated = calculateFederal(validationResult.data); - - // 2) Map to 1040 fill keys (minimal set; expands as module evolves) - const filingStatusIndex: Record = { - single: 0, - married_joint: 1, - married_separate: 2, - head_of_household: 3, - qualifying_widow: 4, - }; - - const withholding = Number(forecast_input?.estimatedWithholding || 0); - const refundOrBalance = Number(calculated?.refundOrBalance || 0); - - const formData = { - year, - // checkbox array index on IRS PDFs (c1_3[0..4]) - filingStatus: filingStatusIndex[String(forecast_input?.filingStatus || 'single')] ?? 0, - wages: Number(forecast_input?.wages || 0), - taxableInterest: Number(forecast_input?.interestIncome || 0), - ordinaryDividends: Number(forecast_input?.dividendIncome || 0), - capitalGain: Number(forecast_input?.capitalGains || 0), - otherIncome: Number(forecast_input?.otherIncome || 0), - totalIncome: Number(calculated?.grossIncome || 0), - adjustedGrossIncome: Number(calculated?.adjustedGrossIncome || 0), - standardDeductionAmount: Number(calculated?.deductionUsed || forecast_input?.standardDeduction || 0), - taxableIncome: Number(calculated?.taxableIncome || 0), - taxOwed: Number(calculated?.totalTax || 0), - federalTaxWithheld: withholding, - earnedIncomeCredit: Number(calculated?.creditsBreakdown?.earnedIncomeCreditRefundable || 0), - additionalChildTaxCredit: Number(calculated?.creditsBreakdown?.additionalChildTaxCreditRefundable || 0), - totalPayments: Number(calculated?.totalPayments || withholding), - // Basic refund/balance presentation - overpayment: refundOrBalance > 0 ? refundOrBalance : 0, - amountOwed: refundOrBalance < 0 ? Math.abs(refundOrBalance) : 0, - }; - - // 3) Fill Form 1040 - const { taxForecastModule } = await import('./modules/forecast/tax-forecast-module.js'); - const filledResult = await taxForecastModule.execute({ action: 'generate_pdf', input: formData }); - const filledText = extractTextPayload(filledResult); - const filledParsed = filledText ? JSON.parse(filledText) : {}; - const pdfBase64 = filledParsed?.pdfBase64; - if (!pdfBase64) { - return res.status(500).json({ success: false, error: 'PDF generation failed', details: filledParsed }); - } - - // 4) Apply branding/warnings - const presentationMode = branding?.presentationMode ?? 'strip'; - const { pdfFormFiller } = await import('./tools/pdf-form-filler.js'); - const branded = await pdfFormFiller.execute({ - action: 'apply_branding', - formType: 'tax_return', - presentationMode, - templateBuffer: Buffer.from(pdfBase64, 'base64'), - returnPdfBase64: true, - }); - const brandedText = extractTextPayload(branded); - const brandedParsed = brandedText ? JSON.parse(brandedText) : {}; - const brandedPdfBase64 = brandedParsed?.pdfBase64 || pdfBase64; - - const pdfBytes = Buffer.from(brandedPdfBase64, 'base64'); - res.setHeader('Content-Type', 'application/pdf'); - res.setHeader('Content-Disposition', `attachment; filename="LexFiat-Forecaster-1040-${year}.pdf"`); - res.send(pdfBytes); - } catch (error) { - res.status(500).json({ - success: false, - error: error instanceof Error ? error.message : 'Unknown error', - }); - } -}); - -// Authentication routes -app.use('/auth', authRoutes); - -// Security endpoints -app.get('/csrf-token', security.getCSRFToken); -app.get('/security/status', security.securityStatus); - -// Clio Webhooks (Track Zeta) -import { clioWebhookHandler } from './integrations/clio-webhooks.js'; -app.post('/webhooks/clio', clioWebhookHandler); - -// Zapier Webhooks (Track Theta) -import { zapierWebhookHandler } from './integrations/zapier-webhooks.js'; -app.post('/webhooks/zapier', zapierWebhookHandler); - -// Apply prompt injection defense to all tool executions -import { sanitizePromptInput, filterSensitiveData, detectPromptInjection } from './middleware/prompt-injection-defense.js'; - -app.get('/health', (req, res) => { - const health = getToolHealth(); - res.json({ - status: 'healthy', - timestamp: new Date().toISOString(), - version: '1.0.0', - tools: { - loaded: health.loaded, - total: health.total, - preloaded: toolsPreloaded, - circuitBreakers: health.circuitBreakers - }, - uptime: process.uptime(), - security: { - jwtEnabled: !!process.env.JWT_SECRET, - csrfProtection: true, - rateLimiting: true, - } - }); -}); - -app.get('/mcp/tools/info', async (req, res) => { - try { - const tools = await loadAllToolDefinitions(); - const toolsInfo = tools.map(tool => ({ - category: 'Tool', - ...tool - })); - - res.json({ - tools: toolsInfo, - summary: { - total_tools: toolsInfo.length, - tools_loaded: toolCache.size, - } - }); - } catch (error) { - res.status(500).json({ error: 'Failed to get tools info' }); - } -}); - -// Arkiver File Upload Endpoint -app.post('/api/arkiver/upload', security.authenticateJWT, upload.single('file'), async (req, res) => { - try { - const file = (req as any).file; - - if (!file) { - return res.status(400).json({ - success: false, - error: { - code: 'NO_FILE', - message: 'No file provided in request', - }, - }); - } - - const maxFileSize = 100 * 1024 * 1024; - if (file.size > maxFileSize) { - return res.status(400).json({ - success: false, - error: { - code: 'FILE_TOO_LARGE', - message: `File size ${file.size} exceeds maximum allowed size of ${maxFileSize} bytes`, - }, - }); - } - - if (req.body.metadata) { - const MetadataSchema = z.object({ - sourceType: z.enum(['user-upload', 'email', 'clio', 'courtlistener', 'westlaw', 'manual']).optional(), - }).passthrough(); - - const metadataValidation = MetadataSchema.safeParse( - typeof req.body.metadata === 'string' ? JSON.parse(req.body.metadata) : req.body.metadata - ); - - if (!metadataValidation.success) { - return res.status(400).json({ - success: false, - error: { - code: 'INVALID_METADATA', - message: 'Invalid metadata format', - details: metadataValidation.error.issues, - }, - }); - } - } - - const { defaultStorage } = await import('./modules/arkiver/storage/local.js'); - const { db } = await import('./db.js'); - const { arkiverFiles } = await import('./modules/arkiver/schema.js'); - const path = await import('path'); - const { eq } = await import('drizzle-orm'); - - let metadata: any = {}; - if (req.body.metadata) { - try { - metadata = typeof req.body.metadata === 'string' - ? JSON.parse(req.body.metadata) - : req.body.metadata; - } catch { - // Ignore invalid JSON - } - } - - const ext = path.extname(file.originalname).toLowerCase(); - const fileType = ext.replace('.', '') || 'unknown'; - const mimeType = file.mimetype || 'application/octet-stream'; - - const storageResult = await defaultStorage.upload( - file.buffer, - file.originalname, - mimeType - ); - - if (!storageResult.success || !storageResult.file) { - return res.status(500).json({ - success: false, - error: { - code: 'STORAGE_ERROR', - message: storageResult.error || 'Failed to store file', - }, - }); - } - - const user = (req as any).user; - const userId = user?.userId; - - if (!userId) { - return res.status(401).json({ - success: false, - error: { - code: 'AUTH_REQUIRED', - message: 'Authentication required to upload files', - }, - }); - } - - const [savedFile] = await db - .insert(arkiverFiles) - .values({ - filename: file.originalname, - fileType: fileType, - fileSize: file.size, - storagePath: storageResult.file.storagePath, - mimeType: mimeType, - status: 'uploaded', - uploadedBy: userId, - sourceType: metadata.sourceType || 'user-upload', - }) - .returning(); - - if (!savedFile) { - return res.status(500).json({ - success: false, - error: { - code: 'DB_ERROR', - message: 'Failed to save file record to database', - }, - }); - } - - return res.json({ - success: true, - fileId: savedFile.id, - fileName: savedFile.filename, - fileSize: savedFile.fileSize, - mimeType: savedFile.mimeType, - uploadedAt: savedFile.createdAt?.toISOString(), - status: savedFile.status, - }); - } catch (error) { - console.error('Upload error:', error); - res.status(500).json({ - success: false, - error: { - code: 'UPLOAD_ERROR', - message: error instanceof Error ? error.message : 'Unknown upload error', +// Global error handler - must be after all routes +app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => { + console.error('[HTTP Bridge] Error:', err); + + // Always return JSON in MCP format, never HTML + res.status(err.status || err.statusCode || 500).json({ + content: [ + { + type: 'text', + text: `Error: ${err.message || 'Unknown error'}`, }, - }); - } -}); - -// Arkiver File Status Endpoint -app.get('/api/arkiver/files/:fileId', async (req, res) => { - try { - const FileIdSchema = z.object({ - fileId: z.string().uuid('File ID must be a valid UUID'), - }); - - const validationResult = FileIdSchema.safeParse(req.params); - if (!validationResult.success) { - return res.status(400).json({ - success: false, - error: { - code: 'INVALID_FILE_ID', - message: 'Invalid file ID format', - details: validationResult.error.issues, - }, - }); - } - - const { fileId } = validationResult.data; - const { db } = await import('./db.js'); - const { arkiverFiles } = await import('./modules/arkiver/schema.js'); - const { eq } = await import('drizzle-orm'); - - const [file] = await db - .select() - .from(arkiverFiles) - .where(eq(arkiverFiles.id, fileId)) - .limit(1); - - if (!file) { - return res.status(404).json({ - success: false, - error: { - code: 'FILE_NOT_FOUND', - message: `File not found: ${fileId}`, - }, - }); - } - - return res.json({ - success: true, - file: { - fileId: file.id, - fileName: file.filename, - fileSize: file.fileSize, - mimeType: file.mimeType, - uploadedAt: file.createdAt?.toISOString(), - status: file.status, - }, - }); - } catch (error) { - console.error('File status error:', error); - res.status(500).json({ - success: false, - error: { - code: 'STATUS_ERROR', - message: error instanceof Error ? error.message : 'Unknown error', - }, - }); - } -}); - -// Mount library routes -app.use('/api', libraryRoutes); - -// Mount onboarding routes -app.use('/api', onboardingRoutes); - -// Mount beta portal routes -app.use('/api/beta', betaRoutes); - -// ============================================================================ -// SERVER STARTUP -// ============================================================================ - -export { app }; - -// Load skills at startup (non-blocking) -async function loadSkillsBeforeStartup() { - try { - const { skillRegistry } = await import('./skills/skill-registry.js'); - await skillRegistry.loadAll(); - console.error(`[Skills] Loaded ${skillRegistry.getCount()} skills`); - } catch (error) { - console.error('[Skills] Failed to load skills:', error); - } -} - -// Start server if this file is run directly -const shouldStartServer = !process.env.VITEST; - -if (shouldStartServer) { - console.error('[HTTP Bridge] Starting server...'); - console.error(`[HTTP Bridge] Port: ${port}`); - - try { - const server = app.listen(port, () => { - console.error(`✅ Cyrano MCP HTTP Bridge running on port ${port}`); - console.error(`Available endpoints:`); - console.error(` GET /health - Health check`); - console.error(` GET /mcp/tools - List available tools`); - console.error(` GET /mcp/tools/info - Detailed tool information`); - console.error(` GET /mcp/tools/health - Tool health monitoring`); - console.error(` POST /mcp/tools/:toolName/reload - Hot reload a tool`); - console.error(` POST /mcp/execute - Execute a tool`); - console.error(` GET /mcp/status - Server status`); - console.error(` POST /api/arkiver/upload - Upload file to Arkiver`); - console.error(` GET /api/arkiver/files/:fileId - Get file status`); - console.error(` POST /api/onboarding/practice-profile - Save practice profile`); - console.error(` GET /api/onboarding/practice-profile - Get practice profile`); - console.error(` POST /api/library/locations - Add/update library location`); - console.error(` GET /api/library/locations - List library locations`); - console.error(` GET /api/library/items - List library items`); - console.error(` POST /api/library/items/:id/pin - Toggle pin status`); - console.error(` POST /api/library/items/:id/ingest - Enqueue for RAG ingestion`); - console.error(` GET /api/health/library - Library health status`); - console.error(`[HTTP Bridge] Server started - tools will load on-demand`); - }); - - server.on('error', (error: Error) => { - console.error('[HTTP Bridge] Failed to start server:', error); - process.exit(1); - }); - - // Start background tasks (non-blocking) - loadSkillsBeforeStartup().catch((error) => { - console.error('[HTTP Bridge] Failed to load skills (non-blocking):', error); - }); - - // Preload tools in background (non-blocking) - preloadToolsInBackground().catch((error) => { - console.error('[HTTP Bridge] Failed to preload tools (non-blocking):', error); - }); - - // Initialize Custodian engine automatically (non-blocking) - import('./engines/registry.js').then(({ engineRegistry }) => { - const custodian = engineRegistry.get('custodian'); - if (custodian) { - custodian.initialize().catch((error) => { - console.error('[HTTP Bridge] Failed to initialize Custodian (non-blocking):', error); - }); - } - }).catch((error) => { - console.error('[HTTP Bridge] Failed to load engine registry:', error); - }); - - console.error('[HTTP Bridge] Startup sequence complete.'); - } catch (error) { - console.error('[HTTP Bridge] Fatal error during startup:', error); - process.exit(1); - } -} else { - console.error('[HTTP Bridge] Not starting server (test environment detected)'); -} + ], + isError: true, + }); +}); \ No newline at end of file