diff --git a/client/package-lock.json b/client/package-lock.json
index 225d2ba06..007edc5ac 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -16,6 +16,7 @@
"@dnd-kit/modifiers": "^9.0.0",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
+ "@documenso/embed-react": "^0.5.1",
"@emotion/is-prop-valid": "^1.4.0",
"@fingerprintjs/fingerprintjs": "^5.0.1",
"@firebase/analytics": "^0.10.19",
@@ -2564,6 +2565,16 @@
"react": ">=16.8.0"
}
},
+ "node_modules/@documenso/embed-react": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/@documenso/embed-react/-/embed-react-0.5.1.tgz",
+ "integrity": "sha512-PlkZ3vrdZVBTc0J3xfG2wtPVGmxCxWgpQ/SsdR2oBMdTwsR+rDbj9k+CeTv+M9Xi5tKbLr5Y78bS9Sb8K+ltTQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/@dotenvx/dotenvx": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.52.0.tgz",
diff --git a/client/package.json b/client/package.json
index b0cbdf6b8..95ac7a96a 100644
--- a/client/package.json
+++ b/client/package.json
@@ -15,6 +15,7 @@
"@dnd-kit/modifiers": "^9.0.0",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
+ "@documenso/embed-react": "^0.5.1",
"@emotion/is-prop-valid": "^1.4.0",
"@fingerprintjs/fingerprintjs": "^5.0.1",
"@firebase/analytics": "^0.10.19",
diff --git a/client/src/App/App.styles.scss b/client/src/App/App.styles.scss
index 657520e49..1701289af 100644
--- a/client/src/App/App.styles.scss
+++ b/client/src/App/App.styles.scss
@@ -475,3 +475,9 @@
margin-left: auto;
flex: 0 0 auto;
}
+
+
+.esignature-embed {
+width: 100%;
+height: 100%;
+}
\ No newline at end of file
diff --git a/client/src/components/esignature-modal/esignature-modal.container.jsx b/client/src/components/esignature-modal/esignature-modal.container.jsx
new file mode 100644
index 000000000..847efa1e2
--- /dev/null
+++ b/client/src/components/esignature-modal/esignature-modal.container.jsx
@@ -0,0 +1,70 @@
+import { Button, Modal } from "antd";
+import { useTranslation } from "react-i18next";
+import { connect } from "react-redux";
+import { createStructuredSelector } from "reselect";
+import { toggleModalVisible } from "../../redux/modals/modals.actions";
+import { selectEsignature } from "../../redux/modals/modals.selectors";
+import { EmbedUpdateDocumentV1 } from "@documenso/embed-react";
+import axios from "axios";
+
+const mapStateToProps = createStructuredSelector({
+ esignatureModal: selectEsignature
+});
+
+const mapDispatchToProps = (dispatch) => ({
+ toggleModalVisible: () => dispatch(toggleModalVisible("esignature"))
+});
+
+export function EsignatureModalContainer({ esignatureModal, toggleModalVisible }) {
+ const { t } = useTranslation();
+ const { open, context } = esignatureModal;
+ const { token, envelopeId, documentId } = context;
+
+ return (
+ {
+ toggleModalVisible();
+ }}
+ onCancel={() => {
+ toggleModalVisible();
+ }}
+ cancelButtonProps={{ style: { display: "none" } }}
+ width="90%"
+ destroyOnHidden
+ >
+
+ {token ? (
+
{
+ console.log("Document updated:", data.documentId);
+ }}
+ />
+ ) : (
+ No token...
+ )}
+
+
+
+ );
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(EsignatureModalContainer);
diff --git a/client/src/components/print-center-item/print-center-item.component.jsx b/client/src/components/print-center-item/print-center-item.component.jsx
index 7af2b15f1..e325e1daf 100644
--- a/client/src/components/print-center-item/print-center-item.component.jsx
+++ b/client/src/components/print-center-item/print-center-item.component.jsx
@@ -1,4 +1,4 @@
-import { MailOutlined, PrinterOutlined } from "@ant-design/icons";
+import { MailOutlined, PrinterOutlined, SignatureFilled } from "@ant-design/icons";
import { Space, Spin } from "antd";
import { useState } from "react";
import { connect } from "react-redux";
@@ -10,6 +10,8 @@ import { GenerateDocument } from "../../utils/RenderTemplate";
import LockWrapperComponent from "../lock-wrapper/lock-wrapper.component";
import { HasFeatureAccess } from "./../feature-wrapper/feature-wrapper.component";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
+import axios from "axios";
+import { setModalContext } from "../../redux/modals/modals.actions.js";
const mapStateToProps = createStructuredSelector({
printCenterModal: selectPrintCenter,
@@ -17,9 +19,25 @@ const mapStateToProps = createStructuredSelector({
technician: selectTechnician
});
-const mapDispatchToProps = () => ({});
+const mapDispatchToProps = (dispatch) => ({
+ setEsignatureContext: (context) =>
+ dispatch(
+ setModalContext({
+ context: context,
+ modal: "esignature"
+ })
+ )
+});
-export function PrintCenterItemComponent({ printCenterModal, item, id, bodyshop, disabled, technician }) {
+export function PrintCenterItemComponent({
+ printCenterModal,
+ setEsignatureContext,
+ item,
+ id,
+ bodyshop,
+ disabled,
+ technician
+}) {
const [loading, setLoading] = useState(false);
const { context } = printCenterModal;
const notification = useNotification();
@@ -39,6 +57,30 @@ export function PrintCenterItemComponent({ printCenterModal, item, id, bodyshop,
setLoading(false);
};
+ const esignatureGenerate = async () => {
+ setLoading(true);
+ try {
+ const {
+ data: { token, documentId, evnelopeId }
+ } = await axios.post("/esign/new", {
+ name: item.key,
+ variables: { id: id },
+ context,
+ bodyshop,
+ templateObject: {
+ name: item.key,
+ variables: { id: id }
+ }
+ });
+
+ setEsignatureContext({ context: { token, documentId, evnelopeId }, jobid: id });
+ } catch (error) {
+ console.log(error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
if (
disabled ||
(item.featureNameRestricted && !HasFeatureAccess({ featureName: item.featureNameRestricted, bodyshop }))
@@ -54,6 +96,7 @@ export function PrintCenterItemComponent({ printCenterModal, item, id, bodyshop,
{item.title}
+
{!technician ? (
import("../../components/print-center-modal/print-center-modal.container")
@@ -68,7 +69,9 @@ const FeatureRequestPage = lazyDev(() => import("../feature-request/feature-requ
const JobCostingModal = lazyDev(() => import("../../components/job-costing-modal/job-costing-modal.container"));
const ReportCenterModal = lazyDev(() => import("../../components/report-center-modal/report-center-modal.container"));
const BillEnterModalContainer = lazyDev(() => import("../../components/bill-enter-modal/bill-enter-modal.container"));
-const TimeTicketModalContainer = lazyDev(() => import("../../components/time-ticket-modal/time-ticket-modal.container"));
+const TimeTicketModalContainer = lazyDev(
+ () => import("../../components/time-ticket-modal/time-ticket-modal.container")
+);
const TimeTicketModalTask = lazyDev(
() => import("../../components/time-ticket-task-modal/time-ticket-task-modal.container")
);
@@ -110,7 +113,9 @@ const TtApprovals = lazyDev(() => import("../tt-approvals/tt-approvals.page.cont
const MyTasksPage = lazyDev(() => import("../tasks/myTasksPageContainer.jsx"));
const AllTasksPage = lazyDev(() => import("../tasks/allTasksPageContainer.jsx"));
-const TaskUpsertModalContainer = lazyDev(() => import("../../components/task-upsert-modal/task-upsert-modal.container"));
+const TaskUpsertModalContainer = lazyDev(
+ () => import("../../components/task-upsert-modal/task-upsert-modal.container")
+);
const { Content } = Layout;
const mapStateToProps = createStructuredSelector({
@@ -178,6 +183,7 @@ export function Manage({ conflict, bodyshop, partsManagementOnly, isDarkMode, cu
+
diff --git a/client/src/redux/modals/modals.reducer.js b/client/src/redux/modals/modals.reducer.js
index 0035ba17b..b7e67823f 100644
--- a/client/src/redux/modals/modals.reducer.js
+++ b/client/src/redux/modals/modals.reducer.js
@@ -27,7 +27,8 @@ const INITIAL_STATE = {
contractFinder: { ...baseModal },
inventoryUpsert: { ...baseModal },
ca_bc_eftTableConvert: { ...baseModal },
- cardPayment: { ...baseModal }
+ cardPayment: { ...baseModal },
+ esignature: { ...baseModal }
};
const modalsReducer = (state = INITIAL_STATE, action) => {
diff --git a/client/src/redux/modals/modals.selectors.js b/client/src/redux/modals/modals.selectors.js
index cd836a3d1..ad796f8da 100644
--- a/client/src/redux/modals/modals.selectors.js
+++ b/client/src/redux/modals/modals.selectors.js
@@ -36,3 +36,4 @@ export const selectInventoryUpsert = createSelector([selectModals], (modals) =>
export const selectCaBcEtfTableConvert = createSelector([selectModals], (modals) => modals.ca_bc_eftTableConvert);
export const selectCardPayment = createSelector([selectModals], (modals) => modals.cardPayment);
+export const selectEsignature = createSelector([selectModals], (modals) => modals.esignature);
diff --git a/package-lock.json b/package-lock.json
index a72ac3df6..0b3e1381f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17,6 +17,8 @@
"@aws-sdk/credential-provider-node": "^3.972.3",
"@aws-sdk/lib-storage": "^3.978.0",
"@aws-sdk/s3-request-presigner": "^3.978.0",
+ "@documenso/sdk-typescript": "^0.8.0",
+ "@jsreport/nodejs-client": "^4.1.0",
"@opensearch-project/opensearch": "^2.13.0",
"@socket.io/admin-ui": "^0.5.1",
"@socket.io/redis-adapter": "^8.3.0",
@@ -1400,6 +1402,18 @@
"kuler": "^2.0.0"
}
},
+ "node_modules/@documenso/sdk-typescript": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/@documenso/sdk-typescript/-/sdk-typescript-0.8.0.tgz",
+ "integrity": "sha512-Emzd5j+v8tA8gxtL+M/svVuzSOKMZw3/U4bS8zRoagvQEqkt+XNU2JraPEAJzxTjf3ww6EnlURXydbglBmR7AQ==",
+ "dependencies": {
+ "@modelcontextprotocol/sdk": "^1.26.0",
+ "zod": "^3.25.0 || ^4.0.0"
+ },
+ "bin": {
+ "mcp": "bin/mcp-server.js"
+ }
+ },
"node_modules/@esbuild/aix-ppc64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz",
@@ -2268,6 +2282,18 @@
"node": ">=6"
}
},
+ "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/@humanfs/core": {
"version": "0.19.1",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
@@ -2396,12 +2422,364 @@
"url": "https://opencollective.com/js-sdsl"
}
},
+ "node_modules/@jsreport/nodejs-client": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@jsreport/nodejs-client/-/nodejs-client-4.1.0.tgz",
+ "integrity": "sha512-QWupUQzMzxWFvY+AlSdUZGlinJv4cKhYmVE9rIe+he7rn4B24tezFmNdnrDcTSFv3hj4x7sTNqpeHT0fItfs5Q==",
+ "dependencies": {
+ "axios": "1.13.2",
+ "concat-stream": "2.0.0",
+ "mimic-response": "2.1.0"
+ },
+ "engines": {
+ "node": ">=22.18"
+ }
+ },
+ "node_modules/@jsreport/nodejs-client/node_modules/axios": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz",
+ "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==",
+ "license": "MIT",
+ "dependencies": {
+ "follow-redirects": "^1.15.6",
+ "form-data": "^4.0.4",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
"node_modules/@kurkle/color": {
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
"integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
"license": "MIT"
},
+ "node_modules/@modelcontextprotocol/sdk": {
+ "version": "1.27.1",
+ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.27.1.tgz",
+ "integrity": "sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==",
+ "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/@modelcontextprotocol/sdk/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/@modelcontextprotocol/sdk/node_modules/ajv": {
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
+ "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
+ "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/@modelcontextprotocol/sdk/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/@modelcontextprotocol/sdk/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/@modelcontextprotocol/sdk/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/@modelcontextprotocol/sdk/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/@modelcontextprotocol/sdk/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/@modelcontextprotocol/sdk/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/@modelcontextprotocol/sdk/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/@modelcontextprotocol/sdk/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/@modelcontextprotocol/sdk/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/@modelcontextprotocol/sdk/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/@modelcontextprotocol/sdk/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/@modelcontextprotocol/sdk/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/@modelcontextprotocol/sdk/node_modules/qs": {
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz",
+ "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/@modelcontextprotocol/sdk/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/@modelcontextprotocol/sdk/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/@modelcontextprotocol/sdk/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/@modelcontextprotocol/sdk/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/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz",
@@ -4270,6 +4648,45 @@
"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/ajv-formats/node_modules/ajv": {
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
+ "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
+ "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/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/ansi-colors": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
@@ -4728,6 +5145,100 @@
"node": "*"
}
},
+ "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/body-parser/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/body-parser/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/body-parser/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/body-parser/node_modules/qs": {
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz",
+ "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/body-parser/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/boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
@@ -6441,6 +6952,27 @@
"node": ">=0.8.x"
}
},
+ "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/expect-type": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz",
@@ -6497,6 +7029,24 @@
"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/express/node_modules/body-parser": {
"version": "1.20.3",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
@@ -6619,6 +7169,22 @@
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==",
"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/fast-xml-parser": {
"version": "5.3.4",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.4.tgz",
@@ -7374,6 +7940,15 @@
"node": ">= 0.4"
}
},
+ "node_modules/hono": {
+ "version": "4.12.3",
+ "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.3.tgz",
+ "integrity": "sha512-SFsVSjp8sj5UumXOOFlkZOG6XS9SJDKw0TbwFeV+AJ8xlST8kxK5Z/5EYa111UY8732lK2S/xB653ceuaoGwpg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=16.9.0"
+ }
+ },
"node_modules/hpagent": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz",
@@ -7632,6 +8207,15 @@
"url": "https://opencollective.com/ioredis"
}
},
+ "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",
@@ -7873,6 +8457,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "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/is-regex": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
@@ -8146,6 +8736,12 @@
"dev": true,
"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/json-stable-stringify-without-jsonify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
@@ -8645,6 +9241,18 @@
"node": ">= 0.6"
}
},
+ "node_modules/mimic-response": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
+ "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/minimalistic-assert": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
@@ -9358,6 +9966,15 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "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/possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
@@ -9590,6 +10207,66 @@
"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/raw-body/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/raw-body/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/raw-body/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/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@@ -9755,6 +10432,15 @@
"node": ">=0.10.0"
}
},
+ "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": {
"version": "2.0.0-next.5",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
@@ -9926,6 +10612,32 @@
"fsevents": "~2.3.2"
}
},
+ "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/router/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/rsa-pem-from-mod-exp": {
"version": "0.8.6",
"resolved": "https://registry.npmjs.org/rsa-pem-from-mod-exp/-/rsa-pem-from-mod-exp-0.8.6.tgz",
@@ -12196,6 +12908,24 @@
"engines": {
"node": ">= 14"
}
+ },
+ "node_modules/zod": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
+ "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
+ "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/package.json b/package.json
index 8f7c36816..ff7943be7 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,8 @@
"@aws-sdk/credential-provider-node": "^3.972.3",
"@aws-sdk/lib-storage": "^3.978.0",
"@aws-sdk/s3-request-presigner": "^3.978.0",
+ "@documenso/sdk-typescript": "^0.8.0",
+ "@jsreport/nodejs-client": "^4.1.0",
"@opensearch-project/opensearch": "^2.13.0",
"@socket.io/admin-ui": "^0.5.1",
"@socket.io/redis-adapter": "^8.3.0",
diff --git a/server.js b/server.js
index 33cbe014c..b73100863 100644
--- a/server.js
+++ b/server.js
@@ -128,6 +128,7 @@ const applyRoutes = ({ app }) => {
app.use("/sso", require("./server/routes/ssoRoutes"));
app.use("/integrations", require("./server/routes/intergrationRoutes"));
app.use("/chatter", require("./server/routes/chatterRoutes"));
+ app.use("/esign", require("./server/routes/eSignRoutes"));
// Default route for forbidden access
app.get("/", (req, res) => {
diff --git a/server/esign/esign-new.js b/server/esign/esign-new.js
new file mode 100644
index 000000000..387d49f8a
--- /dev/null
+++ b/server/esign/esign-new.js
@@ -0,0 +1,236 @@
+
+const { Documenso } = require("@documenso/sdk-typescript");
+const axios = require("axios");
+const { jsrAuthString } = require("../utils/utils");
+const DOCUMENSO_API_KEY = "api_asojim0czruv13ud";//Done on a by team basis,
+const documenso = new Documenso({
+ apiKey: DOCUMENSO_API_KEY,//Done on a by team basis,
+ serverURL: "https://stg-app.documenso.com/api/v2",
+});
+const jsreport = require("@jsreport/nodejs-client");
+
+
+async function distributeDocument(req, res) {
+ try {
+ const { documentId } = req.body;
+ const distributeResult = await documenso.documents.distribute({
+ documentId,
+ });
+ res.json({ success: true, distributeResult });
+ } catch (error) {
+ console.error("Error distributing document:", error?.data);
+ res.status(500).json({ error: "An error occurred while distributing the document." });
+ }
+}
+
+async function newEsignDocument(req, res) {
+
+ try {
+ const client = req.userGraphQLClient;
+ const { pdf: fileBuffer, esigFields } = await RenderTemplate({ client, req })
+ const fileBlob = new Blob([fileBuffer], { type: "application/pdf" });
+
+ const createDocumentResponse = await documenso.documents.create({
+ payload: {
+ title: `Repair Authorization - ${new Date().toLocaleString()}`,
+ recipients: [
+ {
+ email: "patrick.fic@convenient-brands.com",
+ name: "Customer Fullname",
+ role: "SIGNER",
+ }
+ ],
+ meta: {
+ timezone: "America/Vancouver",
+ dateFormat: "MM/dd/yyyy hh:mm a",
+ language: "en",
+ subject: "Repair Authorization for ABC Collision",
+ message: "To perform repairs on your vehicle, we must receive digital authorization. Please review and sign the document to proceed with repairs. ",
+ }
+ },
+ file: fileBlob
+ });
+
+ const documentResult = await documenso.documents.get({
+ documentId: createDocumentResponse.id,
+ });
+
+ if (esigFields && esigFields.length > 0) {
+ console.log("Adding placeholder fields.")
+ try {
+ // await axios.post(`https://stg-app.documenso.com/api/v2/envelope/field/create-many`, {
+ // envelopeId: createDocumentResponse.envelopeId,
+ // data: esigFields.map(sigField => ({ ...sigField, recipientId: result.recipients[0].id, }))
+ // }, {
+ // headers: {
+ // Authorization: DOCUMENSO_API_KEY
+ // }
+ // })
+ const fieldResult = await documenso.envelopes.fields.createMany({
+ envelopeId: createDocumentResponse.envelopeId,
+ data: esigFields.map(sigField => ({ ...sigField, recipientId: documentResult.recipients[0].id, }))
+
+ });
+ } catch (error) {
+ console.log("Error adding placeholders", JSON.stringify(error, null, 2));
+ }
+ }
+
+
+
+ const presignToken = await documenso.embedding.embeddingPresignCreateEmbeddingPresignToken({})
+
+ res.json({ token: presignToken.token, documentId: createDocumentResponse.id, envelopeId: createDocumentResponse.envelopeId });
+ }
+ catch (error) {
+ console.error("Error in newEsignDocument:", error);
+ res.status(500).json({ error: "An error occurred while creating the e-sign document." });
+ }
+}
+
+
+async function RenderTemplate({ req }) {
+ //TODO Refactor to pull
+ const jsrAuth = jsrAuthString()
+
+ const jsreportClient = new jsreport("https://reports.test.imex.online", process.env.JSR_USER, process.env.JSR_PASSWORD);
+ const { templateObject, bodyshop } = req.body;
+ let { contextData, useShopSpecificTemplate, shopSpecificFolder, esigFields } = await fetchContextData({ templateObject, jsrAuth, req });
+ //TODO - Refactor to pull template content and render on server instead of posting back to client for rendering. This is necessary to get the rendered PDF buffer that we can then upload to Documenso.
+ const { ignoreCustomMargins } = { ignoreCustomMargins: false }// Templates[templateObject.name];
+
+ let reportRequest = {
+ template: {
+ name: useShopSpecificTemplate ? `/${bodyshop.imexshopid}/${templateObject.name}` : `/${templateObject.name}`,
+
+ recipe: "chrome-pdf",
+ ...(!ignoreCustomMargins && {
+ chrome: {
+ marginTop:
+ bodyshop.logo_img_path &&
+ bodyshop.logo_img_path.headerMargin &&
+ bodyshop.logo_img_path.headerMargin > 36
+ ? bodyshop.logo_img_path.headerMargin
+ : "36px",
+ marginBottom:
+ bodyshop.logo_img_path &&
+ bodyshop.logo_img_path.footerMargin &&
+ bodyshop.logo_img_path.footerMargin > 50
+ ? bodyshop.logo_img_path.footerMargin
+ : "50px"
+ }
+ }),
+ },
+ data: {
+ ...contextData,
+ ...templateObject.variables,
+ ...templateObject.context,
+ headerpath: shopSpecificFolder ? `/${bodyshop.imexshopid}/header.html` : `/GENERIC/header.html`,
+ footerpath: shopSpecificFolder ? `/${bodyshop.imexshopid}/footer.html` : `/GENERIC/footer.html`,
+ bodyshop: bodyshop,
+ filters: templateObject?.filters,
+ sorters: templateObject?.sorters,
+ offset: bodyshop.timezone, //dayjs().utcOffset(),
+ defaultSorters: templateObject?.defaultSorters
+ }
+ };
+ const render = await jsreportClient.render(reportRequest);
+
+ //Check render object and download. It should be the PDF?
+ const pdfBuffer = await render.body()
+ return { pdf: pdfBuffer, esigFields }
+}
+
+const fetchContextData = async ({ templateObject, jsrAuth, req, }) => {
+ const { bodyshop } = req.body
+ const server = "https://reports.test.imex.online";
+ //jsreport.headers["FirebaseAuthorization"] = req.headers.authorization;
+
+
+
+ const folders = await axios.get(`${server}/odata/folders`, {
+ headers: { Authorization: jsrAuth }
+ });
+ const shopSpecificFolder = folders.data.value.find((f) => f.name === bodyshop.imexshopid);
+
+ const jsReportQueries = await axios.get(
+ `${server}/odata/assets?$filter=name eq '${templateObject.name}.query'`,
+ { headers: { Authorization: jsrAuth } }
+ );
+ const jsReportEsig = await axios.get(
+ `${server}/odata/assets?$filter=name eq '${templateObject.name}.esig'`,
+ { headers: { Authorization: jsrAuth } }
+ );
+
+ let templateQueryToExecute;
+ let esigFields;
+ let useShopSpecificTemplate = false;
+ // let shopSpecificTemplate;
+
+ if (shopSpecificFolder) {
+ let shopSpecificTemplate = jsReportQueries.data.value.find(
+ (f) => f?.folder?.shortid === shopSpecificFolder.shortid
+ );
+ if (shopSpecificTemplate) {
+ useShopSpecificTemplate = true;
+ templateQueryToExecute = atob(shopSpecificTemplate.content);
+ }
+ let shopSpecificEsig = jsReportEsig.data.value.find(
+ (f) => f?.folder?.shortid === shopSpecificFolder.shortid
+ );
+ if (shopSpecificEsig) {
+ esigFields = (atob(shopSpecificEsig.content));
+ }
+ }
+
+ if (!templateQueryToExecute) {
+ const generalTemplate = jsReportQueries.data.value.find((f) => !f.folder);
+ useShopSpecificTemplate = false;
+ templateQueryToExecute = atob(generalTemplate.content);
+ }
+ if (!esigFields) {
+ const generalTemplate = jsReportEsig.data.value.find((f) => !f.folder);
+ useShopSpecificTemplate = false;
+ if (generalTemplate && generalTemplate.content) {
+ esigFields = atob(generalTemplate?.content);
+ }
+ }
+
+ // Commented out for future revision debugging
+ // console.log('Template Object');
+ // console.dir(templateObject);
+ // console.log('Unmodified Query');
+ // console.dir(templateQueryToExecute);
+
+ // const hasFilters = templateObject?.filters?.length > 0;
+ // const hasSorters = templateObject?.sorters?.length > 0;
+ // const hasDefaultSorters = templateObject?.defaultSorters?.length > 0;
+ const client = req.userGraphQLClient;
+
+
+ // In the print center, we will never have sorters or filters.
+ // We have no template filters or sorters, so we can just execute the query and return the data
+ // if (!hasFilters && !hasSorters && !hasDefaultSorters) {
+ let contextData = {};
+ if (templateQueryToExecute) {
+ const data = await client.request(
+ templateQueryToExecute,
+ templateObject.variables,
+ );
+ contextData = data;
+ }
+ return {
+ contextData,
+ useShopSpecificTemplate,
+ shopSpecificFolder,
+ esigFields: esigFields ? JSON.parse(esigFields) : [] //TODO: Do the parsing earlier and harden this. Causes a lot of failures on mini format issues.
+ };
+ // }
+
+ // return await generateTemplate(templateQueryToExecute, templateObject, useShopSpecificTemplate, shopSpecificFolder);
+};
+
+module.exports = {
+ newEsignDocument,
+ distributeDocument
+}
diff --git a/server/esign/webhook.js b/server/esign/webhook.js
new file mode 100644
index 000000000..dc3adefd2
--- /dev/null
+++ b/server/esign/webhook.js
@@ -0,0 +1,150 @@
+
+const { Documenso } = require("@documenso/sdk-typescript");
+const fs = require("fs");
+const path = require("path");
+
+const documenso = new Documenso({
+ apiKey: "api_asojim0czruv13ud",//Done on a by team basis,
+ serverURL: "https://stg-app.documenso.com/api/v2",
+});
+
+
+
+async function esignWebhook(req, res) {
+ console.log("Esign Webhook Received:", req.body);
+ try {
+
+ const result = await documenso.documents.download({
+ documentId: req.body.payload.id,
+ });
+ result.resultingBuffer = Buffer.from(result.resultingArrayBuffer);
+ // Save the document to a file for testing purposes
+ const downloadsDir = path.join(__dirname, '../downloads');
+ if (!fs.existsSync(downloadsDir)) {
+ fs.mkdirSync(downloadsDir, { recursive: true });
+ }
+ const filePath = path.join(downloadsDir, `document_${req.body.payload.id}.pdf`);
+ fs.writeFileSync(filePath, result.resultingBuffer);
+
+ console.log(result)
+
+ res.sendStatus(200)
+ } catch (err) {
+ const downloadsDir = path.join(__dirname, '../downloads');
+ if (!fs.existsSync(downloadsDir)) {
+ fs.mkdirSync(downloadsDir, { recursive: true });
+ }
+ const filePath = path.join(downloadsDir, `document_${req.body.payload.id}.pdf`);
+ fs.writeFileSync(filePath, Buffer.from(err.body));
+ console.error("Error handling esign webhook:", err);
+ res.sendStatus(500)
+ }
+}
+
+
+
+module.exports = {
+ esignWebhook
+}
+
+// const sampleBody = {
+// event: "DOCUMENT_COMPLETED",
+// payload: {
+// Recipient: [
+// {
+// authOptions: {
+// accessAuth: [
+// ],
+// actionAuth: [
+// ],
+// },
+// documentDeletedAt: null,
+// documentId: 9827,
+// email: "patrick@imexsystems.ca",
+// expired: null,
+// id: 13311,
+// name: "Customer Fullname",
+// readStatus: "OPENED",
+// rejectionReason: null,
+// role: "SIGNER",
+// sendStatus: "SENT",
+// signedAt: "2026-01-30T18:29:12.648Z",
+// signingOrder: null,
+// signingStatus: "SIGNED",
+// templateId: null,
+// token: "uiEWIsXUPTbWHd7QedVgt",
+// },
+// ],
+// authOptions: {
+// globalAccessAuth: [
+// ],
+// globalActionAuth: [
+// ],
+// },
+// completedAt: "2026-01-30T18:29:16.279Z",
+// createdAt: "2026-01-30T18:28:48.861Z",
+// deletedAt: null,
+// documentMeta: {
+// allowDictateNextSigner: false,
+// dateFormat: "yyyy-MM-dd hh:mm a",
+// distributionMethod: "EMAIL",
+// drawSignatureEnabled: true,
+// emailSettings: {
+// documentCompleted: true,
+// documentDeleted: true,
+// documentPending: true,
+// ownerDocumentCompleted: true,
+// recipientRemoved: false,
+// recipientSigned: true,
+// recipientSigningRequest: true,
+// },
+// id: "cml17vfb200qjad1t2spxnc1n",
+// language: "en",
+// message: "To perform repairs on your vehicle, we must receive digital authorization. Please review and sign the document to proceed with repairs. ",
+// redirectUrl: null,
+// signingOrder: "PARALLEL",
+// subject: "Repair Authorization for ABC Collision",
+// timezone: "Etc/UTC",
+// typedSignatureEnabled: true,
+// uploadSignatureEnabled: true,
+// },
+// externalId: null,
+// formValues: null,
+// id: 9827,
+// recipients: [
+// {
+// authOptions: {
+// accessAuth: [
+// ],
+// actionAuth: [
+// ],
+// },
+// documentDeletedAt: null,
+// documentId: 9827,
+// email: "patrick@imexsystems.ca",
+// expired: null,
+// id: 13311,
+// name: "Customer Fullname",
+// readStatus: "OPENED",
+// rejectionReason: null,
+// role: "SIGNER",
+// sendStatus: "SENT",
+// signedAt: "2026-01-30T18:29:12.648Z",
+// signingOrder: null,
+// signingStatus: "SIGNED",
+// templateId: null,
+// token: "uiEWIsXUPTbWHd7QedVgt",
+// },
+// ],
+// source: "DOCUMENT",
+// status: "COMPLETED",
+// teamId: 742,
+// templateId: null,
+// title: "Repair Authorization - 1/30/2026, 6:28:48 PM",
+// updatedAt: "2026-01-30T18:29:16.280Z",
+// userId: 654,
+// visibility: "EVERYONE",
+// },
+// createdAt: "2026-01-30T18:29:18.504Z",
+// webhookEndpoint: "https://dev.patrickfic.com/esign/webhook",
+// }
\ No newline at end of file
diff --git a/server/routes/esignRoutes.js b/server/routes/esignRoutes.js
new file mode 100644
index 000000000..2541d658b
--- /dev/null
+++ b/server/routes/esignRoutes.js
@@ -0,0 +1,16 @@
+const express = require("express");
+const router = express.Router();
+
+const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware");
+const withUserGraphQLClientMiddleware = require("../middleware/withUserGraphQLClientMiddleware");
+const { newEsignDocument, distributeDocument } = require("../esign/esign-new");
+const { esignWebhook } = require("../esign/webhook");
+
+//router.use(validateFirebaseIdTokenMiddleware);
+
+router.post("/new", withUserGraphQLClientMiddleware, newEsignDocument);
+router.post("/distribute", withUserGraphQLClientMiddleware, distributeDocument);
+router.post("/webhook", withUserGraphQLClientMiddleware, esignWebhook);
+
+
+module.exports = router;
diff --git a/server/utils/utils.js b/server/utils/utils.js
index 7b7e61fc2..bd78094b3 100644
--- a/server/utils/utils.js
+++ b/server/utils/utils.js
@@ -2,6 +2,9 @@ exports.servertime = (req, res) => {
res.status(200).send(new Date());
};
+exports.jsrAuthString =() => {
+ return "Basic " + Buffer.from(`${process.env.JSR_USER}:${process.env.JSR_PASSWORD}`).toString("base64")
+}
exports.jsrAuth = async (req, res) => {
- res.send("Basic " + Buffer.from(`${process.env.JSR_USER}:${process.env.JSR_PASSWORD}`).toString("base64"));
+ res.send(exports.jsrAuthString());
};