diff --git a/client/package-lock.json b/client/package-lock.json index 999ddbe88..c9188c87b 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -9,7 +9,7 @@ "version": "0.2.1", "hasInstallScript": true, "dependencies": { - "@amplitude/analytics-browser": "^2.27.0", + "@amplitude/analytics-browser": "^2.29.0", "@ant-design/pro-layout": "^7.22.6", "@apollo/client": "^3.13.9", "@emotion/is-prop-valid": "^1.4.0", @@ -20,21 +20,21 @@ "@firebase/firestore": "^4.9.2", "@firebase/messaging": "^0.12.22", "@jsreport/browser-client": "^3.1.0", - "@reduxjs/toolkit": "^2.9.1", - "@sentry/cli": "^2.56.1", + "@reduxjs/toolkit": "^2.9.2", + "@sentry/cli": "^2.57.0", "@sentry/react": "^9.43.0", - "@sentry/vite-plugin": "^4.4.0", + "@sentry/vite-plugin": "^4.6.0", "@splitsoftware/splitio-react": "^2.5.0", "@tanem/react-nprogress": "^5.0.56", - "antd": "^5.27.5", + "antd": "^5.27.6", "apollo-link-logger": "^2.0.1", "apollo-link-sentry": "^4.4.0", "autosize": "^6.0.1", - "axios": "^1.12.2", + "axios": "^1.13.1", "classnames": "^2.5.1", "css-box-model": "^1.2.1", "dayjs": "^1.11.18", - "dayjs-business-days2": "^1.3.0", + "dayjs-business-days2": "^1.3.1", "dinero.js": "^1.9.1", "dotenv": "^17.2.3", "env-cmd": "^10.1.0", @@ -43,7 +43,7 @@ "i18next": "^25.6.0", "i18next-browser-languagedetector": "^8.2.0", "immutability-helper": "^3.1.1", - "libphonenumber-js": "^1.12.24", + "libphonenumber-js": "^1.12.25", "lightningcss": "^1.30.2", "logrocket": "^9.0.2", "markerjs2": "^2.32.7", @@ -51,7 +51,7 @@ "normalize-url": "^8.1.0", "object-hash": "^3.0.0", "phone": "^3.1.67", - "posthog-js": "^1.276.0", + "posthog-js": "^1.281.0", "prop-types": "^15.8.1", "query-string": "^9.3.1", "raf-schd": "^4.0.3", @@ -79,7 +79,7 @@ "redux": "^5.0.1", "redux-actions": "^3.0.3", "redux-persist": "^6.0.0", - "redux-saga": "^1.3.0", + "redux-saga": "^1.4.2", "redux-state-sync": "^3.1.4", "reselect": "^5.1.1", "sass": "^1.93.2", @@ -93,31 +93,31 @@ "devDependencies": { "@ant-design/icons": "^6.1.0", "@babel/plugin-proposal-private-property-in-object": "^7.21.11", - "@babel/preset-react": "^7.27.1", + "@babel/preset-react": "^7.28.5", "@dotenvx/dotenvx": "^1.51.0", "@emotion/babel-plugin": "^11.13.5", "@emotion/react": "^11.14.0", "@eslint/js": "^9.38.0", "@playwright/test": "^1.56.1", - "@sentry/webpack-plugin": "^4.4.0", + "@sentry/webpack-plugin": "^4.6.0", "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.0", "@vitejs/plugin-react": "^4.6.0", - "browserslist": "^4.26.3", + "browserslist": "^4.27.0", "browserslist-to-esbuild": "^2.1.1", "chalk": "^5.6.2", "eslint": "^9.38.0", "eslint-plugin-react": "^7.37.5", "globals": "^15.15.0", "jsdom": "^26.0.0", - "memfs": "^4.49.0", + "memfs": "^4.50.0", "os-browserify": "^0.3.0", "playwright": "^1.56.1", "react-error-overlay": "^6.1.0", "redux-logger": "^3.0.6", "source-map-explorer": "^2.5.3", - "vite": "^7.1.10", + "vite": "^7.1.12", "vite-plugin-babel": "^1.3.2", "vite-plugin-eslint": "^1.8.1", "vite-plugin-node-polyfills": "^0.24.0", @@ -141,16 +141,17 @@ "license": "MIT" }, "node_modules/@amplitude/analytics-browser": { - "version": "2.27.0", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-browser/-/analytics-browser-2.27.0.tgz", - "integrity": "sha512-1LBCLmnr7aUpLtOp64lpr8GzN3vPKM0fwiM/7tWJ9XU9/GKA+k3CUSjI8OdERKrw2yVywujoAVQo4anGZXYIDA==", + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/@amplitude/analytics-browser/-/analytics-browser-2.29.0.tgz", + "integrity": "sha512-e+9tdTisSjj//BhMK4Ej8rhldfhcZXurxsfqns2DyXjf+bxLQwO32ZTIbfQMy+CAiRwVRc2nuZXyfFCpW2DgMA==", "license": "MIT", "dependencies": { - "@amplitude/analytics-core": "^2.28.0", - "@amplitude/plugin-autocapture-browser": "^1.15.3", - "@amplitude/plugin-network-capture-browser": "^1.6.9", - "@amplitude/plugin-page-view-tracking-browser": "^2.5.3", - "@amplitude/plugin-web-vitals-browser": "^0.1.0-beta.31", + "@amplitude/analytics-core": "^2.30.0", + "@amplitude/plugin-autocapture-browser": "^1.16.2", + "@amplitude/plugin-network-capture-browser": "^1.6.11", + "@amplitude/plugin-page-url-enrichment-browser": "^0.5.0", + "@amplitude/plugin-page-view-tracking-browser": "^2.5.5", + "@amplitude/plugin-web-vitals-browser": "^0.1.0-beta.33", "tslib": "^2.4.1" } }, @@ -161,9 +162,9 @@ "license": "MIT" }, "node_modules/@amplitude/analytics-core": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-core/-/analytics-core-2.28.0.tgz", - "integrity": "sha512-Wj/xUHhiHk2xH0/lp5IgHlzyKJOIb/WkpWP8W66wf3EaLJwX0AtPWMEb557BHbYBG/KXonp6ob9DyD0xbW38dg==", + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/@amplitude/analytics-core/-/analytics-core-2.30.0.tgz", + "integrity": "sha512-oWz13sQmfCRa9prfYcURPVNHQQOf0/rDEK7PjBi0m0nKXs+QaHu/Tq2y4F6f4K66YDsT7zYYO4DpkS+QJM3/Sw==", "license": "MIT", "dependencies": { "@amplitude/analytics-connector": "^1.6.4", @@ -171,34 +172,44 @@ } }, "node_modules/@amplitude/plugin-autocapture-browser": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@amplitude/plugin-autocapture-browser/-/plugin-autocapture-browser-1.15.3.tgz", - "integrity": "sha512-WPYw81fFdTzUxEzM3/lTalsxLNGDKFklGnDaHoLFB4LxL5XfIyC+lBnOls+9zjt7dyV0qvq5YzunbFNT2ysR8g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@amplitude/plugin-autocapture-browser/-/plugin-autocapture-browser-1.16.2.tgz", + "integrity": "sha512-0ariOP5g8xsPlKUrC91DviG9nKuaC4hYPHu5OHpUcU/LdWiKG1k+w5qawUq+KIsyTCAFRbTHn+XoJPjhm6Mbcg==", "license": "MIT", "dependencies": { - "@amplitude/analytics-core": "^2.28.0", + "@amplitude/analytics-core": "^2.30.0", "rxjs": "^7.8.1", "tslib": "^2.4.1" } }, "node_modules/@amplitude/plugin-network-capture-browser": { - "version": "1.6.9", - "resolved": "https://registry.npmjs.org/@amplitude/plugin-network-capture-browser/-/plugin-network-capture-browser-1.6.9.tgz", - "integrity": "sha512-dBp0FiXGwreFfEZvWBqe+VbbwSRsljRwdYdtSQvBeYriBWZp7g3rD02xmt8zjlWxMpQTAE0wLjAi7E01NclBXg==", + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@amplitude/plugin-network-capture-browser/-/plugin-network-capture-browser-1.6.11.tgz", + "integrity": "sha512-kGbSZ5omr9842kzBN/Wx31kq59RcyclEhpsX2lDxkuHn4el+nhylztx2mNYJyEmeNmdV68MfA1IFkA//ZJzebA==", "license": "MIT", "dependencies": { - "@amplitude/analytics-core": "^2.28.0", + "@amplitude/analytics-core": "^2.30.0", "rxjs": "^7.8.1", "tslib": "^2.4.1" } }, - "node_modules/@amplitude/plugin-page-view-tracking-browser": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@amplitude/plugin-page-view-tracking-browser/-/plugin-page-view-tracking-browser-2.5.3.tgz", - "integrity": "sha512-zqdZ01mScGHwvxoCLiz+qClA7sbryozeX2BmRt4mxkk9qkukKuMs2xGijgUDqsrWX0UbkYczFZhPbhm+4Jti9g==", + "node_modules/@amplitude/plugin-page-url-enrichment-browser": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@amplitude/plugin-page-url-enrichment-browser/-/plugin-page-url-enrichment-browser-0.5.0.tgz", + "integrity": "sha512-MJOCHQa3H5t2khPuGwgGX36tuA7ohDwzXyuPVZbY6fN3qRT9LAE686VuvQSXH9365yHMcWp2vPkdn8Ju3i9IUw==", "license": "MIT", "dependencies": { - "@amplitude/analytics-core": "^2.28.0", + "@amplitude/analytics-core": "^2.30.0", + "tslib": "^2.4.1" + } + }, + "node_modules/@amplitude/plugin-page-view-tracking-browser": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/@amplitude/plugin-page-view-tracking-browser/-/plugin-page-view-tracking-browser-2.5.5.tgz", + "integrity": "sha512-pSeYW3YjdFdJEA8WFQbWwaez4q1hwr4alg+Z7y1DU0hoQ91ADxCrFDQ2zoTSyBZfu/paWx1Gds1v4sYjsgh5Bw==", + "license": "MIT", + "dependencies": { + "@amplitude/analytics-core": "^2.30.0", "tslib": "^2.4.1" } }, @@ -2185,15 +2196,15 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.27.1.tgz", - "integrity": "sha512-oJHWh2gLhU9dW9HHr42q0cI0/iHHXTLGe39qvpAZZzagHy0MzYLCnCVV0symeRvzmjHyVU7mw2K06E6u/JwbhA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.28.5.tgz", + "integrity": "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-transform-react-display-name": "^7.27.1", + "@babel/plugin-transform-react-display-name": "^7.28.0", "@babel/plugin-transform-react-jsx": "^7.27.1", "@babel/plugin-transform-react-jsx-development": "^7.27.1", "@babel/plugin-transform-react-pure-annotations": "^7.27.1" @@ -3419,9 +3430,9 @@ } }, "node_modules/@posthog/core": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@posthog/core/-/core-1.3.0.tgz", - "integrity": "sha512-hxLL8kZNHH098geedcxCz8y6xojkNYbmJEW+1vFXsmPcExyCXIUUJ/34X6xa9GcprKxd0Wsx3vfJQLQX4iVPhw==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@posthog/core/-/core-1.4.0.tgz", + "integrity": "sha512-jmW8/I//YOHAfjzokqas+Qtc2T57Ux8d2uIJu7FLcMGxywckHsl6od59CD18jtUzKToQdjQhV6Y3429qj+KeNw==", "license": "MIT" }, "node_modules/@protobufjs/aspromise": { @@ -3664,17 +3675,17 @@ } }, "node_modules/@redux-saga/core": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.3.0.tgz", - "integrity": "sha512-L+i+qIGuyWn7CIg7k1MteHGfttKPmxwZR5E7OsGikCL2LzYA0RERlaUY00Y3P3ZV2EYgrsYlBrGs6cJP5OKKqA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.4.2.tgz", + "integrity": "sha512-nIMLGKo6jV6Wc1sqtVQs1iqbB3Kq20udB/u9XEaZQisT6YZ0NRB8+4L6WqD/E+YziYutd27NJbG8EWUPkb7c6Q==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.6.3", - "@redux-saga/deferred": "^1.2.1", - "@redux-saga/delay-p": "^1.2.1", - "@redux-saga/is": "^1.1.3", - "@redux-saga/symbols": "^1.1.3", - "@redux-saga/types": "^1.2.1", + "@babel/runtime": "^7.28.4", + "@redux-saga/deferred": "^1.3.1", + "@redux-saga/delay-p": "^1.3.1", + "@redux-saga/is": "^1.2.1", + "@redux-saga/symbols": "^1.2.1", + "@redux-saga/types": "^1.3.1", "typescript-tuple": "^2.2.1" }, "funding": { @@ -3683,46 +3694,46 @@ } }, "node_modules/@redux-saga/deferred": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.2.1.tgz", - "integrity": "sha512-cmin3IuuzMdfQjA0lG4B+jX+9HdTgHZZ+6u3jRAOwGUxy77GSlTi4Qp2d6PM1PUoTmQUR5aijlA39scWWPF31g==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.3.1.tgz", + "integrity": "sha512-0YZ4DUivWojXBqLB/TmuRRpDDz7tyq1I0AuDV7qi01XlLhM5m51W7+xYtIckH5U2cMlv9eAuicsfRAi1XHpXIg==", "license": "MIT" }, "node_modules/@redux-saga/delay-p": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.2.1.tgz", - "integrity": "sha512-MdiDxZdvb1m+Y0s4/hgdcAXntpUytr9g0hpcOO1XFVyyzkrDu3SKPgBFOtHn7lhu7n24ZKIAT1qtKyQjHqRd+w==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.3.1.tgz", + "integrity": "sha512-597I7L5MXbD/1i3EmcaOOjL/5suxJD7p5tnbV1PiWnE28c2cYiIHqmSMK2s7us2/UrhOL2KTNBiD0qBg6KnImg==", "license": "MIT", "dependencies": { - "@redux-saga/symbols": "^1.1.3" + "@redux-saga/symbols": "^1.2.1" } }, "node_modules/@redux-saga/is": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.3.tgz", - "integrity": "sha512-naXrkETG1jLRfVfhOx/ZdLj0EyAzHYbgJWkXbB3qFliPcHKiWbv/ULQryOAEKyjrhiclmr6AMdgsXFyx7/yE6Q==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@redux-saga/is/-/is-1.2.1.tgz", + "integrity": "sha512-x3aWtX3GmQfEvn8dh0ovPbsXgK9JjpiR24wKztpGbZP8JZUWWvUgKrvnWZ/T/4iphOBftyVc9VrIwhAnsM+OFA==", "license": "MIT", "dependencies": { - "@redux-saga/symbols": "^1.1.3", - "@redux-saga/types": "^1.2.1" + "@redux-saga/symbols": "^1.2.1", + "@redux-saga/types": "^1.3.1" } }, "node_modules/@redux-saga/symbols": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.3.tgz", - "integrity": "sha512-hCx6ZvU4QAEUojETnX8EVg4ubNLBFl1Lps4j2tX7o45x/2qg37m3c6v+kSp8xjDJY+2tJw4QB3j8o8dsl1FDXg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.2.1.tgz", + "integrity": "sha512-3dh+uDvpBXi7EUp/eO+N7eFM4xKaU4yuGBXc50KnZGzIrR/vlvkTFQsX13zsY8PB6sCFYAgROfPSRUj8331QSA==", "license": "MIT" }, "node_modules/@redux-saga/types": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@redux-saga/types/-/types-1.2.1.tgz", - "integrity": "sha512-1dgmkh+3so0+LlBWRhGA33ua4MYr7tUOj+a9Si28vUi0IUFNbff1T3sgpeDJI/LaC75bBYnQ0A3wXjn0OrRNBA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@redux-saga/types/-/types-1.3.1.tgz", + "integrity": "sha512-YRCrJdhQLobGIQ8Cj1sta3nn6DrZDTSUnrIYhS2e5V590BmfVDleKoAquclAiKSBKWJwmuXTb+b4BL6rSHnahw==", "license": "MIT" }, "node_modules/@reduxjs/toolkit": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.9.1.tgz", - "integrity": "sha512-sETJ3qO72y7L7WiR5K54UFLT3jRzAtqeBPVO15xC3bGA6kDqCH8m/v7BKCPH4czydXzz/1lPEGLvew7GjOO3Qw==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.9.2.tgz", + "integrity": "sha512-ZAYu/NXkl/OhqTz7rfPaAhY0+e8Fr15jqNxte/2exKUxvHyQ/hcqmdekiN1f+Lcw3pE+34FCgX+26zcUE3duCg==", "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", @@ -4385,9 +4396,9 @@ } }, "node_modules/@sentry/babel-plugin-component-annotate": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-4.4.0.tgz", - "integrity": "sha512-Pzjpn9MZg6yR61ThJgOoD28dLNCj457O0/t8d276K+Bzf8iOZKbrNO4sltp1vUB1yqhV+ulvIZO8xu8ABohtsg==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-4.6.0.tgz", + "integrity": "sha512-3soTX50JPQQ51FSbb4qvNBf4z/yP7jTdn43vMTp9E4IxvJ9HKJR7OEuKkCMszrZmWsVABXl02msqO7QisePdiQ==", "license": "MIT", "engines": { "node": ">= 14" @@ -4410,14 +4421,14 @@ } }, "node_modules/@sentry/bundler-plugin-core": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@sentry/bundler-plugin-core/-/bundler-plugin-core-4.4.0.tgz", - "integrity": "sha512-WTGhgwxzyolzOg0sudULK0rRgLndtsEiBt4QwltKW/WYArMtFyf286aZx19uQ+rD+bSx3Il81SD23nqDOTtnzg==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sentry/bundler-plugin-core/-/bundler-plugin-core-4.6.0.tgz", + "integrity": "sha512-Fub2XQqrS258jjS8qAxLLU1k1h5UCNJ76i8m4qZJJdogWWaF8t00KnnTyp9TEDJzrVD64tRXS8+HHENxmeUo3g==", "license": "MIT", "dependencies": { "@babel/core": "^7.18.5", - "@sentry/babel-plugin-component-annotate": "4.4.0", - "@sentry/cli": "^2.51.0", + "@sentry/babel-plugin-component-annotate": "4.6.0", + "@sentry/cli": "^2.57.0", "dotenv": "^16.3.1", "find-up": "^5.0.0", "glob": "^9.3.2", @@ -4441,9 +4452,9 @@ } }, "node_modules/@sentry/cli": { - "version": "2.56.1", - "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.56.1.tgz", - "integrity": "sha512-VDAIg+gmjNtJS5VUZQMDSK9RaKC9hYQi3PoXpNa+owNfQNk60bCi8z8jkbWRcKbNGn3V51WqvrQAqLoNAdPc9w==", + "version": "2.57.0", + "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.57.0.tgz", + "integrity": "sha512-oC4HPrVIX06GvUTgK0i+WbNgIA9Zl5YEcwf9N4eWFJJmjonr2j4SML9Hn2yNENbUWDgwepy4MLod3P8rM4bk/w==", "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { @@ -4460,20 +4471,20 @@ "node": ">= 10" }, "optionalDependencies": { - "@sentry/cli-darwin": "2.56.1", - "@sentry/cli-linux-arm": "2.56.1", - "@sentry/cli-linux-arm64": "2.56.1", - "@sentry/cli-linux-i686": "2.56.1", - "@sentry/cli-linux-x64": "2.56.1", - "@sentry/cli-win32-arm64": "2.56.1", - "@sentry/cli-win32-i686": "2.56.1", - "@sentry/cli-win32-x64": "2.56.1" + "@sentry/cli-darwin": "2.57.0", + "@sentry/cli-linux-arm": "2.57.0", + "@sentry/cli-linux-arm64": "2.57.0", + "@sentry/cli-linux-i686": "2.57.0", + "@sentry/cli-linux-x64": "2.57.0", + "@sentry/cli-win32-arm64": "2.57.0", + "@sentry/cli-win32-i686": "2.57.0", + "@sentry/cli-win32-x64": "2.57.0" } }, "node_modules/@sentry/cli-darwin": { - "version": "2.56.1", - "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.56.1.tgz", - "integrity": "sha512-zfhT8MrvB5x/xRdIVGwg+sG0Cx3i0G6RH2zCrdQ/moWn8TfkwsM0O1k/AxpwbpcRfAHCkVb04CU/yKciKwg2KA==", + "version": "2.57.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.57.0.tgz", + "integrity": "sha512-v1wYQU3BcCO+Z3OVxxO+EnaW4oQhuOza6CXeYZ0z5ftza9r0QQBLz3bcZKTVta86xraNm0z8GDlREwinyddOxQ==", "license": "BSD-3-Clause", "optional": true, "os": [ @@ -4484,9 +4495,9 @@ } }, "node_modules/@sentry/cli-linux-arm": { - "version": "2.56.1", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.56.1.tgz", - "integrity": "sha512-fNB/Ng11HrkGOSEIDg+fc3zfTCV7q6kJddp6ndK3QlYFsCffRSnclaX1SMp+mqxdWkHqe1kkp85OY8G/x5uAWw==", + "version": "2.57.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.57.0.tgz", + "integrity": "sha512-uNHB8xyygqfMd1/6tFzl9NUkuVefg7jdZtM/vVCQVaF/rJLWZ++Wms+LLhYyKXKN8yd7J9wy7kTEl4Qu4jWbGQ==", "cpu": [ "arm" ], @@ -4502,9 +4513,9 @@ } }, "node_modules/@sentry/cli-linux-arm64": { - "version": "2.56.1", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.56.1.tgz", - "integrity": "sha512-AypXIwZvOMJb9RgjI/98hTAd06FcOjqjIm6G9IR0OI4pJCOcaAXz9NKXdJqxpZd7phSMJnD+Bx/8iYOUPeY73A==", + "version": "2.57.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.57.0.tgz", + "integrity": "sha512-Kh1jTsMV5Fy/RvB381N/woXe1qclRMqsG6kM3Gq6m6afEF/+k3PyQdNW3HXAola6d63EptokLtxPG2xjWQ+w9Q==", "cpu": [ "arm64" ], @@ -4520,9 +4531,9 @@ } }, "node_modules/@sentry/cli-linux-i686": { - "version": "2.56.1", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.56.1.tgz", - "integrity": "sha512-vnH+WJEsUq7Lf7xc9udzE/M4hoDXXsniFFYr/7BvdnXtCQlNNaWFMXHbEDYAql3baIlHkWoG8cEHWuB/YKyniw==", + "version": "2.57.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.57.0.tgz", + "integrity": "sha512-EYXghoK/tKd0zqz+KD/ewXXE3u1HLCwG89krweveytBy/qw7M5z58eFvw+iGb1Vnbl1f/fRD0G4E0AbEsPfmpg==", "cpu": [ "x86", "ia32" @@ -4539,9 +4550,9 @@ } }, "node_modules/@sentry/cli-linux-x64": { - "version": "2.56.1", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.56.1.tgz", - "integrity": "sha512-3/BlKe5Vdnia36MeovghHJD8lbcum5TFIxLp+PSfH2sVb09+5Jo0L95oRTI2JkD8Fs+QNssvTqTxJj5eIo/n+A==", + "version": "2.57.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.57.0.tgz", + "integrity": "sha512-CyZrP/ssHmAPLSzfd4ydy7icDnwmDD6o3QjhkWwVFmCd+9slSBMQxpIqpamZmrWE6X4R+xBRbSUjmdoJoZ5yMw==", "cpu": [ "x64" ], @@ -4557,9 +4568,9 @@ } }, "node_modules/@sentry/cli-win32-arm64": { - "version": "2.56.1", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-arm64/-/cli-win32-arm64-2.56.1.tgz", - "integrity": "sha512-Gg8RV7CV7Tz4fiR1EN1Af5AVhJsnEXiZvfvfQXI4lp51MKAhcxZIMtEfg9HaWsn3Dm/wgwYBinyeywfWbTXYDg==", + "version": "2.57.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-arm64/-/cli-win32-arm64-2.57.0.tgz", + "integrity": "sha512-wji/GGE4Lh5I/dNCsuVbg6fRvttvZRG6db1yPW1BSvQRh8DdnVy1CVp+HMqSq0SRy/S4z60j2u+m4yXMoCL+5g==", "cpu": [ "arm64" ], @@ -4573,9 +4584,9 @@ } }, "node_modules/@sentry/cli-win32-i686": { - "version": "2.56.1", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.56.1.tgz", - "integrity": "sha512-6u6a060yC3i76Ze1apqgWr5luQSyhuD5ND84eWfh/UbddsEa42UHjoVHOiBwmpZqf/hvNZAtzLnE4NCvU4zOMg==", + "version": "2.57.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.57.0.tgz", + "integrity": "sha512-hWvzyD7bTPh3b55qvJ1Okg3Wbl0Km8xcL6KvS7gfBl6uss+I6RldmQTP0gJKdHSdf/QlJN1FK0b7bLnCB3wHsg==", "cpu": [ "x86", "ia32" @@ -4590,9 +4601,9 @@ } }, "node_modules/@sentry/cli-win32-x64": { - "version": "2.56.1", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.56.1.tgz", - "integrity": "sha512-11cdflajBrDWlRZqI9MOu7ok2vnPzFjKmbU3YvBYWQapNE+HHAsWdsRL/u/P1RmU62vj7Y42iSUcj6x1SNrdPw==", + "version": "2.57.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.57.0.tgz", + "integrity": "sha512-QWYV/Y0sbpDSTyA4XQBOTaid4a6H2Iwa1Z8UI+qNxFlk0ADSEgIqo2NrRHDU8iRnghTkecQNX1NTt/7mXN3f/A==", "cpu": [ "x64" ], @@ -4653,12 +4664,12 @@ } }, "node_modules/@sentry/vite-plugin": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@sentry/vite-plugin/-/vite-plugin-4.4.0.tgz", - "integrity": "sha512-sOq1xJj5URIa/c4fSJomjOjp7l0ljk4WWRjol6ERwJ5wntOKDrw5Y7T1ZbyiDGD8/ndzQnn4Od03Z+jSvpqwog==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sentry/vite-plugin/-/vite-plugin-4.6.0.tgz", + "integrity": "sha512-fMR2d+EHwbzBa0S1fp45SNUTProxmyFBp+DeBWWQOSP9IU6AH6ea2rqrpMAnp/skkcdW4z4LSRrOEpMZ5rWXLw==", "license": "MIT", "dependencies": { - "@sentry/bundler-plugin-core": "4.4.0", + "@sentry/bundler-plugin-core": "4.6.0", "unplugin": "1.0.1" }, "engines": { @@ -4666,13 +4677,13 @@ } }, "node_modules/@sentry/webpack-plugin": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@sentry/webpack-plugin/-/webpack-plugin-4.4.0.tgz", - "integrity": "sha512-s9Js4v++pbZaKu6ddG1LSXbSKfM71UxkS6PzmOWj4HyTHdiZr+469tbdanTJwz8XO87neFAP1mteuo1Cur3iHg==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sentry/webpack-plugin/-/webpack-plugin-4.6.0.tgz", + "integrity": "sha512-i9Yy2kXCbFKlRST09fV1HsI0naJAfeXxoiUPyh5iCgSo2w7ZwEUlk0tJhupnHZzfSa3OSg01+vVNeeyLYM4tdA==", "dev": true, "license": "MIT", "dependencies": { - "@sentry/bundler-plugin-core": "4.4.0", + "@sentry/bundler-plugin-core": "4.6.0", "unplugin": "1.0.1", "uuid": "^9.0.0" }, @@ -5481,9 +5492,9 @@ } }, "node_modules/antd": { - "version": "5.27.5", - "resolved": "https://registry.npmjs.org/antd/-/antd-5.27.5.tgz", - "integrity": "sha512-Ehd9mqtHvJ1clon1yJ/1BTV6eX/3SH2YXZZPTHUk8XdzXFwUioI+Lht47s+MaHIUBY77RnZrmtKwwR+VVu0l7A==", + "version": "5.27.6", + "resolved": "https://registry.npmjs.org/antd/-/antd-5.27.6.tgz", + "integrity": "sha512-70HrjVbzDXvtiUQ5MP1XdNudr/wGAk9Ivaemk6f36yrAeJurJSmZ8KngOIilolLRHdGuNc6/Vk+4T1OZpSjpag==", "license": "MIT", "dependencies": { "@ant-design/colors": "^7.2.1", @@ -5896,9 +5907,9 @@ } }, "node_modules/axios": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", - "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.1.tgz", + "integrity": "sha512-hU4EGxxt+j7TQijx1oYdAjw4xuIp1wRQSsbMFwSthCWeBQur1eF+qJ5iQ5sN3Tw8YRzQNKb8jszgBdMDVqwJcw==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -6027,9 +6038,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.12", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.12.tgz", - "integrity": "sha512-vAPMQdnyKCBtkmQA6FMCBvU9qFIppS3nzyXnEM+Lo2IAhG4Mpjv9cCxMudhgV3YdNNJv6TNqXy97dfRVL2LmaQ==", + "version": "2.8.21", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.21.tgz", + "integrity": "sha512-JU0h5APyQNsHOlAM7HnQnPToSDQoEBZqzu/YBlqDnEeymPnZDREeXJA3KBMQee+dKteAxZ2AtvQEvVYdZf241Q==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -6272,9 +6283,9 @@ } }, "node_modules/browserslist": { - "version": "4.26.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", - "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.27.0.tgz", + "integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==", "funding": [ { "type": "opencollective", @@ -6291,11 +6302,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.8.9", - "caniuse-lite": "^1.0.30001746", - "electron-to-chromium": "^1.5.227", - "node-releases": "^2.0.21", - "update-browserslist-db": "^1.1.3" + "baseline-browser-mapping": "^2.8.19", + "caniuse-lite": "^1.0.30001751", + "electron-to-chromium": "^1.5.238", + "node-releases": "^2.0.26", + "update-browserslist-db": "^1.1.4" }, "bin": { "browserslist": "cli.js" @@ -6472,9 +6483,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001748", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001748.tgz", - "integrity": "sha512-5P5UgAr0+aBmNiplks08JLw+AW/XG/SurlgZLgB1dDLfAw7EfRGxIwzPHxdSCGY/BTKDqIVyJL87cCN6s0ZR0w==", + "version": "1.0.30001751", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", + "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", "funding": [ { "type": "opencollective", @@ -7246,12 +7257,12 @@ "license": "MIT" }, "node_modules/dayjs-business-days2": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/dayjs-business-days2/-/dayjs-business-days2-1.3.0.tgz", - "integrity": "sha512-OgDBnsNmlk9+vmRQaP4yFisXs29WDk0ItUUctIagmO6OIoxhf4vArTov5i+G4vjT9Sz8NXOLMLrOVP0X0lG/Hw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dayjs-business-days2/-/dayjs-business-days2-1.3.1.tgz", + "integrity": "sha512-zn5Athg9GGjuW7MJGz9qZKgpf1HzkK/jvHnUaR1P1TvDBmQ5Dc3auRbQJxkOcgmuK0XM+QG/Nxxe10IMHjw+4w==", "license": "MIT", "dependencies": { - "dayjs": "^1.11.13" + "dayjs": "^1.11.18" } }, "node_modules/debug": { @@ -7605,9 +7616,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.231", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.231.tgz", - "integrity": "sha512-cyl6vqZGkEBnz/PmvFHn/u9G/hbo+FF2CNAOXriG87QOeLsUdifCZ9UbHNscE9wGdrC8XstNMli0CbQnZQ+fkA==", + "version": "1.5.243", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.243.tgz", + "integrity": "sha512-ZCphxFW3Q1TVhcgS9blfut1PX8lusVi2SvXQgmEEnK4TCmE1JhH2JkjJN+DNt0pJJwfBri5AROBnz2b/C+YU9g==", "license": "ISC" }, "node_modules/elliptic": { @@ -10350,9 +10361,9 @@ } }, "node_modules/libphonenumber-js": { - "version": "1.12.24", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.24.tgz", - "integrity": "sha512-l5IlyL9AONj4voSd7q9xkuQOL4u8Ty44puTic7J88CmdXkxfGsRfoVLXHCxppwehgpb/Chdb80FFehHqjN3ItQ==", + "version": "1.12.25", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.25.tgz", + "integrity": "sha512-u90tUu/SEF8b+RaDKCoW7ZNFDakyBtFlX1ex3J+VH+ElWes/UaitJLt/w4jGu8uAE41lltV/s+kMVtywcMEg7g==", "license": "MIT" }, "node_modules/lightningcss": { @@ -10768,9 +10779,9 @@ } }, "node_modules/memfs": { - "version": "4.49.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.49.0.tgz", - "integrity": "sha512-L9uC9vGuc4xFybbdOpRLoOAOq1YEBBsocCs5NVW32DfU+CZWWIn3OVF+lB8Gp4ttBVSMazwrTrjv8ussX/e3VQ==", + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.50.0.tgz", + "integrity": "sha512-N0LUYQMUA1yS5tJKmMtU9yprPm6ZIg24yr/OVv/7t6q0kKDIho4cBbXRi1XKttUmNYDYgF/q45qrKE/UhGO0CA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -11529,9 +11540,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.23", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz", - "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==", + "version": "2.0.26", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.26.tgz", + "integrity": "sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==", "license": "MIT" }, "node_modules/node-stdlib-browser": { @@ -12333,28 +12344,16 @@ "license": "MIT" }, "node_modules/posthog-js": { - "version": "1.276.0", - "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.276.0.tgz", - "integrity": "sha512-FYZE1037LrAoKKeUU0pUL7u8WwNK2BVeg5TFApwquVPUdj9h7u5Z077A313hPN19Ar+7Y+VHxqYqdHc4VNsVgw==", + "version": "1.281.0", + "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.281.0.tgz", + "integrity": "sha512-t3sAlgVozpU1W1ppiF5zLG6eBRPUs0hmtxN8R1V7P0qZFmnECshAAk2cBxCsxEanadT3iUpS8Z7crBytATqWQQ==", "license": "SEE LICENSE IN LICENSE", "dependencies": { - "@posthog/core": "1.3.0", + "@posthog/core": "1.4.0", "core-js": "^3.38.1", "fflate": "^0.4.8", "preact": "^10.19.3", "web-vitals": "^4.2.4" - }, - "peerDependencies": { - "@rrweb/types": "2.0.0-alpha.17", - "rrweb-snapshot": "2.0.0-alpha.17" - }, - "peerDependenciesMeta": { - "@rrweb/types": { - "optional": true - }, - "rrweb-snapshot": { - "optional": true - } } }, "node_modules/posthog-js/node_modules/core-js": { @@ -13839,12 +13838,12 @@ } }, "node_modules/redux-saga": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.3.0.tgz", - "integrity": "sha512-J9RvCeAZXSTAibFY0kGw6Iy4EdyDNW7k6Q+liwX+bsck7QVsU78zz8vpBRweEfANxnnlG/xGGeOvf6r8UXzNJQ==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.4.2.tgz", + "integrity": "sha512-QLIn/q+7MX/B+MkGJ/K6R3//60eJ4QNy65eqPsJrfGezbxdh1Jx+37VRKE2K4PsJnNET5JufJtgWdT30WBa+6w==", "license": "MIT", "dependencies": { - "@redux-saga/core": "^1.3.0" + "@redux-saga/core": "^1.4.2" } }, "node_modules/redux-state-sync": { @@ -16172,9 +16171,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", "funding": [ { "type": "opencollective", @@ -16356,9 +16355,9 @@ } }, "node_modules/vite": { - "version": "7.1.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.10.tgz", - "integrity": "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA==", + "version": "7.1.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.12.tgz", + "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==", "dev": true, "license": "MIT", "dependencies": { diff --git a/client/package.json b/client/package.json index 6a823354e..0dc5fec92 100644 --- a/client/package.json +++ b/client/package.json @@ -8,7 +8,7 @@ "private": true, "proxy": "http://localhost:4000", "dependencies": { - "@amplitude/analytics-browser": "^2.27.0", + "@amplitude/analytics-browser": "^2.29.0", "@ant-design/pro-layout": "^7.22.6", "@apollo/client": "^3.13.9", "@emotion/is-prop-valid": "^1.4.0", @@ -19,21 +19,21 @@ "@firebase/firestore": "^4.9.2", "@firebase/messaging": "^0.12.22", "@jsreport/browser-client": "^3.1.0", - "@reduxjs/toolkit": "^2.9.1", - "@sentry/cli": "^2.56.1", + "@reduxjs/toolkit": "^2.9.2", + "@sentry/cli": "^2.57.0", "@sentry/react": "^9.43.0", - "@sentry/vite-plugin": "^4.4.0", + "@sentry/vite-plugin": "^4.6.0", "@splitsoftware/splitio-react": "^2.5.0", "@tanem/react-nprogress": "^5.0.56", - "antd": "^5.27.5", + "antd": "^5.27.6", "apollo-link-logger": "^2.0.1", "apollo-link-sentry": "^4.4.0", "autosize": "^6.0.1", - "axios": "^1.12.2", + "axios": "^1.13.1", "classnames": "^2.5.1", "css-box-model": "^1.2.1", "dayjs": "^1.11.18", - "dayjs-business-days2": "^1.3.0", + "dayjs-business-days2": "^1.3.1", "dinero.js": "^1.9.1", "dotenv": "^17.2.3", "env-cmd": "^10.1.0", @@ -42,7 +42,7 @@ "i18next": "^25.6.0", "i18next-browser-languagedetector": "^8.2.0", "immutability-helper": "^3.1.1", - "libphonenumber-js": "^1.12.24", + "libphonenumber-js": "^1.12.25", "lightningcss": "^1.30.2", "logrocket": "^9.0.2", "markerjs2": "^2.32.7", @@ -50,7 +50,7 @@ "normalize-url": "^8.1.0", "object-hash": "^3.0.0", "phone": "^3.1.67", - "posthog-js": "^1.276.0", + "posthog-js": "^1.281.0", "prop-types": "^15.8.1", "query-string": "^9.3.1", "raf-schd": "^4.0.3", @@ -78,7 +78,7 @@ "redux": "^5.0.1", "redux-actions": "^3.0.3", "redux-persist": "^6.0.0", - "redux-saga": "^1.3.0", + "redux-saga": "^1.4.2", "redux-state-sync": "^3.1.4", "reselect": "^5.1.1", "sass": "^1.93.2", @@ -135,31 +135,31 @@ "devDependencies": { "@ant-design/icons": "^6.1.0", "@babel/plugin-proposal-private-property-in-object": "^7.21.11", - "@babel/preset-react": "^7.27.1", + "@babel/preset-react": "^7.28.5", "@dotenvx/dotenvx": "^1.51.0", "@emotion/babel-plugin": "^11.13.5", "@emotion/react": "^11.14.0", "@eslint/js": "^9.38.0", "@playwright/test": "^1.56.1", - "@sentry/webpack-plugin": "^4.4.0", + "@sentry/webpack-plugin": "^4.6.0", "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.0", "@vitejs/plugin-react": "^4.6.0", - "browserslist": "^4.26.3", + "browserslist": "^4.27.0", "browserslist-to-esbuild": "^2.1.1", "chalk": "^5.6.2", "eslint": "^9.38.0", "eslint-plugin-react": "^7.37.5", "globals": "^15.15.0", "jsdom": "^26.0.0", - "memfs": "^4.49.0", + "memfs": "^4.50.0", "os-browserify": "^0.3.0", "playwright": "^1.56.1", "react-error-overlay": "^6.1.0", "redux-logger": "^3.0.6", "source-map-explorer": "^2.5.3", - "vite": "^7.1.10", + "vite": "^7.1.12", "vite-plugin-babel": "^1.3.2", "vite-plugin-eslint": "^1.8.1", "vite-plugin-node-polyfills": "^0.24.0", diff --git a/package-lock.json b/package-lock.json index 5c58ab74f..d8167d5b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,30 +9,30 @@ "version": "0.2.0", "license": "UNLICENSED", "dependencies": { - "@aws-sdk/client-cloudwatch-logs": "^3.913.0", - "@aws-sdk/client-elasticache": "^3.913.0", - "@aws-sdk/client-s3": "^3.913.0", - "@aws-sdk/client-secrets-manager": "^3.913.0", - "@aws-sdk/client-ses": "^3.913.0", - "@aws-sdk/credential-provider-node": "^3.913.0", - "@aws-sdk/lib-storage": "^3.913.0", - "@aws-sdk/s3-request-presigner": "^3.913.0", + "@aws-sdk/client-cloudwatch-logs": "^3.919.0", + "@aws-sdk/client-elasticache": "^3.919.0", + "@aws-sdk/client-s3": "^3.919.0", + "@aws-sdk/client-secrets-manager": "^3.919.0", + "@aws-sdk/client-ses": "^3.919.0", + "@aws-sdk/credential-provider-node": "^3.919.0", + "@aws-sdk/lib-storage": "^3.919.0", + "@aws-sdk/s3-request-presigner": "^3.919.0", "@opensearch-project/opensearch": "^2.13.0", "@socket.io/admin-ui": "^0.5.1", "@socket.io/redis-adapter": "^8.3.0", "archiver": "^7.0.1", "aws4": "^1.13.2", - "axios": "^1.12.2", + "axios": "^1.13.1", "axios-curlirize": "^2.0.0", "better-queue": "^3.8.12", - "bullmq": "^5.61.0", + "bullmq": "^5.62.0", "chart.js": "^4.5.1", - "cloudinary": "^2.7.0", + "cloudinary": "^2.8.0", "compression": "^1.8.1", "cookie-parser": "^1.4.7", "cors": "^2.8.5", "crisp-status-reporter": "^1.2.2", - "dd-trace": "^5.72.0", + "dd-trace": "^5.74.0", "dinero.js": "^1.9.1", "dotenv": "^17.2.3", "express": "^4.21.1", @@ -41,8 +41,8 @@ "graphql": "^16.11.0", "graphql-request": "^6.1.0", "intuit-oauth": "^4.2.1", - "ioredis": "^5.8.1", - "json-2-csv": "^5.5.9", + "ioredis": "^5.8.2", + "json-2-csv": "^5.5.10", "jsonwebtoken": "^9.0.2", "juice": "^11.0.3", "lodash": "^4.17.21", @@ -57,11 +57,11 @@ "recursive-diff": "^1.0.9", "rimraf": "^6.0.1", "skia-canvas": "^3.0.8", - "soap": "^1.5.0", + "soap": "^1.6.0", "socket.io": "^4.8.1", "socket.io-adapter": "^2.5.5", "ssh2-sftp-client": "^11.0.0", - "twilio": "^5.10.3", + "twilio": "^5.10.4", "uuid": "^11.1.0", "winston": "^3.18.3", "winston-cloudwatch": "^6.3.0", @@ -289,51 +289,51 @@ } }, "node_modules/@aws-sdk/client-cloudwatch-logs": { - "version": "3.913.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch-logs/-/client-cloudwatch-logs-3.913.0.tgz", - "integrity": "sha512-ztaUBCI6ps90O5sERy5ZP8aGC2+Ks9kvOJrdpGFMKcTVtyHP1xTB/FDfNvmz2s25S8W7yeCokvs1fvoKcLyniQ==", + "version": "3.919.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch-logs/-/client-cloudwatch-logs-3.919.0.tgz", + "integrity": "sha512-eOmhLDeHeond8UrkJpvQfmuCV227qHr8pxE42Oys5eP0LKjT3SJSLjS5mYqwmR1UQ57S5du05wqXzk8WPCCfMQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.911.0", - "@aws-sdk/credential-provider-node": "3.913.0", - "@aws-sdk/middleware-host-header": "3.910.0", - "@aws-sdk/middleware-logger": "3.910.0", - "@aws-sdk/middleware-recursion-detection": "3.910.0", - "@aws-sdk/middleware-user-agent": "3.911.0", - "@aws-sdk/region-config-resolver": "3.910.0", - "@aws-sdk/types": "3.910.0", - "@aws-sdk/util-endpoints": "3.910.0", - "@aws-sdk/util-user-agent-browser": "3.910.0", - "@aws-sdk/util-user-agent-node": "3.911.0", - "@smithy/config-resolver": "^4.3.2", - "@smithy/core": "^3.16.1", - "@smithy/eventstream-serde-browser": "^4.2.2", - "@smithy/eventstream-serde-config-resolver": "^4.3.2", - "@smithy/eventstream-serde-node": "^4.2.2", - "@smithy/fetch-http-handler": "^5.3.3", - "@smithy/hash-node": "^4.2.2", - "@smithy/invalid-dependency": "^4.2.2", - "@smithy/middleware-content-length": "^4.2.2", - "@smithy/middleware-endpoint": "^4.3.3", - "@smithy/middleware-retry": "^4.4.3", - "@smithy/middleware-serde": "^4.2.2", - "@smithy/middleware-stack": "^4.2.2", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/node-http-handler": "^4.4.1", - "@smithy/protocol-http": "^5.3.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", - "@smithy/url-parser": "^4.2.2", + "@aws-sdk/core": "3.916.0", + "@aws-sdk/credential-provider-node": "3.919.0", + "@aws-sdk/middleware-host-header": "3.914.0", + "@aws-sdk/middleware-logger": "3.914.0", + "@aws-sdk/middleware-recursion-detection": "3.919.0", + "@aws-sdk/middleware-user-agent": "3.916.0", + "@aws-sdk/region-config-resolver": "3.914.0", + "@aws-sdk/types": "3.914.0", + "@aws-sdk/util-endpoints": "3.916.0", + "@aws-sdk/util-user-agent-browser": "3.914.0", + "@aws-sdk/util-user-agent-node": "3.916.0", + "@smithy/config-resolver": "^4.4.0", + "@smithy/core": "^3.17.1", + "@smithy/eventstream-serde-browser": "^4.2.3", + "@smithy/eventstream-serde-config-resolver": "^4.3.3", + "@smithy/eventstream-serde-node": "^4.2.3", + "@smithy/fetch-http-handler": "^5.3.4", + "@smithy/hash-node": "^4.2.3", + "@smithy/invalid-dependency": "^4.2.3", + "@smithy/middleware-content-length": "^4.2.3", + "@smithy/middleware-endpoint": "^4.3.5", + "@smithy/middleware-retry": "^4.4.5", + "@smithy/middleware-serde": "^4.2.3", + "@smithy/middleware-stack": "^4.2.3", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/node-http-handler": "^4.4.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/smithy-client": "^4.9.1", + "@smithy/types": "^4.8.0", + "@smithy/url-parser": "^4.2.3", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.2", - "@smithy/util-defaults-mode-node": "^4.2.3", - "@smithy/util-endpoints": "^3.2.2", - "@smithy/util-middleware": "^4.2.2", - "@smithy/util-retry": "^4.2.2", + "@smithy/util-defaults-mode-browser": "^4.3.4", + "@smithy/util-defaults-mode-node": "^4.2.6", + "@smithy/util-endpoints": "^3.2.3", + "@smithy/util-middleware": "^4.2.3", + "@smithy/util-retry": "^4.2.3", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" @@ -343,50 +343,50 @@ } }, "node_modules/@aws-sdk/client-elasticache": { - "version": "3.913.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-elasticache/-/client-elasticache-3.913.0.tgz", - "integrity": "sha512-LYCyJt8wrI7WQeOefDaYNnABdoR0RaAcSZ9tplrYL2MRFsX8tmk4pfPU+0ceJpuvI8/P4QnkTw2K7ZpxkZqnAg==", + "version": "3.919.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-elasticache/-/client-elasticache-3.919.0.tgz", + "integrity": "sha512-hHXFmXi9FJUrHs0DBNPJ1sF9+FLwARL0/YPZurX1mvyylkX9RwwowbQGItf3pGnPPh8LNoVV+8PVnTCHjkGBrA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.911.0", - "@aws-sdk/credential-provider-node": "3.913.0", - "@aws-sdk/middleware-host-header": "3.910.0", - "@aws-sdk/middleware-logger": "3.910.0", - "@aws-sdk/middleware-recursion-detection": "3.910.0", - "@aws-sdk/middleware-user-agent": "3.911.0", - "@aws-sdk/region-config-resolver": "3.910.0", - "@aws-sdk/types": "3.910.0", - "@aws-sdk/util-endpoints": "3.910.0", - "@aws-sdk/util-user-agent-browser": "3.910.0", - "@aws-sdk/util-user-agent-node": "3.911.0", - "@smithy/config-resolver": "^4.3.2", - "@smithy/core": "^3.16.1", - "@smithy/fetch-http-handler": "^5.3.3", - "@smithy/hash-node": "^4.2.2", - "@smithy/invalid-dependency": "^4.2.2", - "@smithy/middleware-content-length": "^4.2.2", - "@smithy/middleware-endpoint": "^4.3.3", - "@smithy/middleware-retry": "^4.4.3", - "@smithy/middleware-serde": "^4.2.2", - "@smithy/middleware-stack": "^4.2.2", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/node-http-handler": "^4.4.1", - "@smithy/protocol-http": "^5.3.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", - "@smithy/url-parser": "^4.2.2", + "@aws-sdk/core": "3.916.0", + "@aws-sdk/credential-provider-node": "3.919.0", + "@aws-sdk/middleware-host-header": "3.914.0", + "@aws-sdk/middleware-logger": "3.914.0", + "@aws-sdk/middleware-recursion-detection": "3.919.0", + "@aws-sdk/middleware-user-agent": "3.916.0", + "@aws-sdk/region-config-resolver": "3.914.0", + "@aws-sdk/types": "3.914.0", + "@aws-sdk/util-endpoints": "3.916.0", + "@aws-sdk/util-user-agent-browser": "3.914.0", + "@aws-sdk/util-user-agent-node": "3.916.0", + "@smithy/config-resolver": "^4.4.0", + "@smithy/core": "^3.17.1", + "@smithy/fetch-http-handler": "^5.3.4", + "@smithy/hash-node": "^4.2.3", + "@smithy/invalid-dependency": "^4.2.3", + "@smithy/middleware-content-length": "^4.2.3", + "@smithy/middleware-endpoint": "^4.3.5", + "@smithy/middleware-retry": "^4.4.5", + "@smithy/middleware-serde": "^4.2.3", + "@smithy/middleware-stack": "^4.2.3", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/node-http-handler": "^4.4.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/smithy-client": "^4.9.1", + "@smithy/types": "^4.8.0", + "@smithy/url-parser": "^4.2.3", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.2", - "@smithy/util-defaults-mode-node": "^4.2.3", - "@smithy/util-endpoints": "^3.2.2", - "@smithy/util-middleware": "^4.2.2", - "@smithy/util-retry": "^4.2.2", + "@smithy/util-defaults-mode-browser": "^4.3.4", + "@smithy/util-defaults-mode-node": "^4.2.6", + "@smithy/util-endpoints": "^3.2.3", + "@smithy/util-middleware": "^4.2.3", + "@smithy/util-retry": "^4.2.3", "@smithy/util-utf8": "^4.2.0", - "@smithy/util-waiter": "^4.2.2", + "@smithy/util-waiter": "^4.2.3", "tslib": "^2.6.2" }, "engines": { @@ -394,66 +394,66 @@ } }, "node_modules/@aws-sdk/client-s3": { - "version": "3.913.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.913.0.tgz", - "integrity": "sha512-YdWHIXn+TltH1MbMkBrFl8Ocxj/PJXleacQ1U5AZRAt8EqxctYkeTNB/+XYS5x6ieYQ4uWnF7sF74sJx+KTpwg==", + "version": "3.919.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.919.0.tgz", + "integrity": "sha512-UEPH2B9RnsS7Jo/oXe5DGrqQhWvRj6YBkLr7bsAZoYl4Sj1RbwDimiyGbhbuarnX5wCjpwSW860CFmShh/1z5w==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.911.0", - "@aws-sdk/credential-provider-node": "3.913.0", - "@aws-sdk/middleware-bucket-endpoint": "3.910.0", - "@aws-sdk/middleware-expect-continue": "3.910.0", - "@aws-sdk/middleware-flexible-checksums": "3.911.0", - "@aws-sdk/middleware-host-header": "3.910.0", - "@aws-sdk/middleware-location-constraint": "3.913.0", - "@aws-sdk/middleware-logger": "3.910.0", - "@aws-sdk/middleware-recursion-detection": "3.910.0", - "@aws-sdk/middleware-sdk-s3": "3.911.0", - "@aws-sdk/middleware-ssec": "3.910.0", - "@aws-sdk/middleware-user-agent": "3.911.0", - "@aws-sdk/region-config-resolver": "3.910.0", - "@aws-sdk/signature-v4-multi-region": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@aws-sdk/util-endpoints": "3.910.0", - "@aws-sdk/util-user-agent-browser": "3.910.0", - "@aws-sdk/util-user-agent-node": "3.911.0", - "@aws-sdk/xml-builder": "3.911.0", - "@smithy/config-resolver": "^4.3.2", - "@smithy/core": "^3.16.1", - "@smithy/eventstream-serde-browser": "^4.2.2", - "@smithy/eventstream-serde-config-resolver": "^4.3.2", - "@smithy/eventstream-serde-node": "^4.2.2", - "@smithy/fetch-http-handler": "^5.3.3", - "@smithy/hash-blob-browser": "^4.2.3", - "@smithy/hash-node": "^4.2.2", - "@smithy/hash-stream-node": "^4.2.2", - "@smithy/invalid-dependency": "^4.2.2", - "@smithy/md5-js": "^4.2.2", - "@smithy/middleware-content-length": "^4.2.2", - "@smithy/middleware-endpoint": "^4.3.3", - "@smithy/middleware-retry": "^4.4.3", - "@smithy/middleware-serde": "^4.2.2", - "@smithy/middleware-stack": "^4.2.2", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/node-http-handler": "^4.4.1", - "@smithy/protocol-http": "^5.3.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", - "@smithy/url-parser": "^4.2.2", + "@aws-sdk/core": "3.916.0", + "@aws-sdk/credential-provider-node": "3.919.0", + "@aws-sdk/middleware-bucket-endpoint": "3.914.0", + "@aws-sdk/middleware-expect-continue": "3.917.0", + "@aws-sdk/middleware-flexible-checksums": "3.919.0", + "@aws-sdk/middleware-host-header": "3.914.0", + "@aws-sdk/middleware-location-constraint": "3.914.0", + "@aws-sdk/middleware-logger": "3.914.0", + "@aws-sdk/middleware-recursion-detection": "3.919.0", + "@aws-sdk/middleware-sdk-s3": "3.916.0", + "@aws-sdk/middleware-ssec": "3.914.0", + "@aws-sdk/middleware-user-agent": "3.916.0", + "@aws-sdk/region-config-resolver": "3.914.0", + "@aws-sdk/signature-v4-multi-region": "3.916.0", + "@aws-sdk/types": "3.914.0", + "@aws-sdk/util-endpoints": "3.916.0", + "@aws-sdk/util-user-agent-browser": "3.914.0", + "@aws-sdk/util-user-agent-node": "3.916.0", + "@aws-sdk/xml-builder": "3.914.0", + "@smithy/config-resolver": "^4.4.0", + "@smithy/core": "^3.17.1", + "@smithy/eventstream-serde-browser": "^4.2.3", + "@smithy/eventstream-serde-config-resolver": "^4.3.3", + "@smithy/eventstream-serde-node": "^4.2.3", + "@smithy/fetch-http-handler": "^5.3.4", + "@smithy/hash-blob-browser": "^4.2.4", + "@smithy/hash-node": "^4.2.3", + "@smithy/hash-stream-node": "^4.2.3", + "@smithy/invalid-dependency": "^4.2.3", + "@smithy/md5-js": "^4.2.3", + "@smithy/middleware-content-length": "^4.2.3", + "@smithy/middleware-endpoint": "^4.3.5", + "@smithy/middleware-retry": "^4.4.5", + "@smithy/middleware-serde": "^4.2.3", + "@smithy/middleware-stack": "^4.2.3", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/node-http-handler": "^4.4.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/smithy-client": "^4.9.1", + "@smithy/types": "^4.8.0", + "@smithy/url-parser": "^4.2.3", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.2", - "@smithy/util-defaults-mode-node": "^4.2.3", - "@smithy/util-endpoints": "^3.2.2", - "@smithy/util-middleware": "^4.2.2", - "@smithy/util-retry": "^4.2.2", - "@smithy/util-stream": "^4.5.2", + "@smithy/util-defaults-mode-browser": "^4.3.4", + "@smithy/util-defaults-mode-node": "^4.2.6", + "@smithy/util-endpoints": "^3.2.3", + "@smithy/util-middleware": "^4.2.3", + "@smithy/util-retry": "^4.2.3", + "@smithy/util-stream": "^4.5.4", "@smithy/util-utf8": "^4.2.0", - "@smithy/util-waiter": "^4.2.2", + "@smithy/util-waiter": "^4.2.3", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" }, @@ -462,48 +462,48 @@ } }, "node_modules/@aws-sdk/client-secrets-manager": { - "version": "3.913.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.913.0.tgz", - "integrity": "sha512-VX54DUb5eWSgxzA34Ym95HoBG5i0dEno4JnV6RR+dKQoiKmrnbnGKmHc3GsAH8lw4vFoz8epcthKG8iaryLRIw==", + "version": "3.919.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.919.0.tgz", + "integrity": "sha512-mVTriVpy20c5alM52/TE46uuhMniVRHD5Mi617r+g1Y2Zk7s14qlDVAcw44gzs7toWjJNvdXMeWHuz0WnXokFQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.911.0", - "@aws-sdk/credential-provider-node": "3.913.0", - "@aws-sdk/middleware-host-header": "3.910.0", - "@aws-sdk/middleware-logger": "3.910.0", - "@aws-sdk/middleware-recursion-detection": "3.910.0", - "@aws-sdk/middleware-user-agent": "3.911.0", - "@aws-sdk/region-config-resolver": "3.910.0", - "@aws-sdk/types": "3.910.0", - "@aws-sdk/util-endpoints": "3.910.0", - "@aws-sdk/util-user-agent-browser": "3.910.0", - "@aws-sdk/util-user-agent-node": "3.911.0", - "@smithy/config-resolver": "^4.3.2", - "@smithy/core": "^3.16.1", - "@smithy/fetch-http-handler": "^5.3.3", - "@smithy/hash-node": "^4.2.2", - "@smithy/invalid-dependency": "^4.2.2", - "@smithy/middleware-content-length": "^4.2.2", - "@smithy/middleware-endpoint": "^4.3.3", - "@smithy/middleware-retry": "^4.4.3", - "@smithy/middleware-serde": "^4.2.2", - "@smithy/middleware-stack": "^4.2.2", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/node-http-handler": "^4.4.1", - "@smithy/protocol-http": "^5.3.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", - "@smithy/url-parser": "^4.2.2", + "@aws-sdk/core": "3.916.0", + "@aws-sdk/credential-provider-node": "3.919.0", + "@aws-sdk/middleware-host-header": "3.914.0", + "@aws-sdk/middleware-logger": "3.914.0", + "@aws-sdk/middleware-recursion-detection": "3.919.0", + "@aws-sdk/middleware-user-agent": "3.916.0", + "@aws-sdk/region-config-resolver": "3.914.0", + "@aws-sdk/types": "3.914.0", + "@aws-sdk/util-endpoints": "3.916.0", + "@aws-sdk/util-user-agent-browser": "3.914.0", + "@aws-sdk/util-user-agent-node": "3.916.0", + "@smithy/config-resolver": "^4.4.0", + "@smithy/core": "^3.17.1", + "@smithy/fetch-http-handler": "^5.3.4", + "@smithy/hash-node": "^4.2.3", + "@smithy/invalid-dependency": "^4.2.3", + "@smithy/middleware-content-length": "^4.2.3", + "@smithy/middleware-endpoint": "^4.3.5", + "@smithy/middleware-retry": "^4.4.5", + "@smithy/middleware-serde": "^4.2.3", + "@smithy/middleware-stack": "^4.2.3", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/node-http-handler": "^4.4.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/smithy-client": "^4.9.1", + "@smithy/types": "^4.8.0", + "@smithy/url-parser": "^4.2.3", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.2", - "@smithy/util-defaults-mode-node": "^4.2.3", - "@smithy/util-endpoints": "^3.2.2", - "@smithy/util-middleware": "^4.2.2", - "@smithy/util-retry": "^4.2.2", + "@smithy/util-defaults-mode-browser": "^4.3.4", + "@smithy/util-defaults-mode-node": "^4.2.6", + "@smithy/util-endpoints": "^3.2.3", + "@smithy/util-middleware": "^4.2.3", + "@smithy/util-retry": "^4.2.3", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" @@ -513,50 +513,50 @@ } }, "node_modules/@aws-sdk/client-ses": { - "version": "3.913.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.913.0.tgz", - "integrity": "sha512-jUF1mN+webeAgkNXS/tl6KpJyUbsAWxQGsQgsWoHwaNCSnxMDBEyPmgBnzbqf2CrybIa7zmzaqCO0z6FgKeZRg==", + "version": "3.919.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.919.0.tgz", + "integrity": "sha512-1guBkprQdR1j/JEpHzoarCtaNZC/wjMeIxCN7EuuTI4UHioActkOu8FFqWX0DC5QU5PH126pOCAbWfkpmu+ruQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.911.0", - "@aws-sdk/credential-provider-node": "3.913.0", - "@aws-sdk/middleware-host-header": "3.910.0", - "@aws-sdk/middleware-logger": "3.910.0", - "@aws-sdk/middleware-recursion-detection": "3.910.0", - "@aws-sdk/middleware-user-agent": "3.911.0", - "@aws-sdk/region-config-resolver": "3.910.0", - "@aws-sdk/types": "3.910.0", - "@aws-sdk/util-endpoints": "3.910.0", - "@aws-sdk/util-user-agent-browser": "3.910.0", - "@aws-sdk/util-user-agent-node": "3.911.0", - "@smithy/config-resolver": "^4.3.2", - "@smithy/core": "^3.16.1", - "@smithy/fetch-http-handler": "^5.3.3", - "@smithy/hash-node": "^4.2.2", - "@smithy/invalid-dependency": "^4.2.2", - "@smithy/middleware-content-length": "^4.2.2", - "@smithy/middleware-endpoint": "^4.3.3", - "@smithy/middleware-retry": "^4.4.3", - "@smithy/middleware-serde": "^4.2.2", - "@smithy/middleware-stack": "^4.2.2", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/node-http-handler": "^4.4.1", - "@smithy/protocol-http": "^5.3.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", - "@smithy/url-parser": "^4.2.2", + "@aws-sdk/core": "3.916.0", + "@aws-sdk/credential-provider-node": "3.919.0", + "@aws-sdk/middleware-host-header": "3.914.0", + "@aws-sdk/middleware-logger": "3.914.0", + "@aws-sdk/middleware-recursion-detection": "3.919.0", + "@aws-sdk/middleware-user-agent": "3.916.0", + "@aws-sdk/region-config-resolver": "3.914.0", + "@aws-sdk/types": "3.914.0", + "@aws-sdk/util-endpoints": "3.916.0", + "@aws-sdk/util-user-agent-browser": "3.914.0", + "@aws-sdk/util-user-agent-node": "3.916.0", + "@smithy/config-resolver": "^4.4.0", + "@smithy/core": "^3.17.1", + "@smithy/fetch-http-handler": "^5.3.4", + "@smithy/hash-node": "^4.2.3", + "@smithy/invalid-dependency": "^4.2.3", + "@smithy/middleware-content-length": "^4.2.3", + "@smithy/middleware-endpoint": "^4.3.5", + "@smithy/middleware-retry": "^4.4.5", + "@smithy/middleware-serde": "^4.2.3", + "@smithy/middleware-stack": "^4.2.3", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/node-http-handler": "^4.4.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/smithy-client": "^4.9.1", + "@smithy/types": "^4.8.0", + "@smithy/url-parser": "^4.2.3", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.2", - "@smithy/util-defaults-mode-node": "^4.2.3", - "@smithy/util-endpoints": "^3.2.2", - "@smithy/util-middleware": "^4.2.2", - "@smithy/util-retry": "^4.2.2", + "@smithy/util-defaults-mode-browser": "^4.3.4", + "@smithy/util-defaults-mode-node": "^4.2.6", + "@smithy/util-endpoints": "^3.2.3", + "@smithy/util-middleware": "^4.2.3", + "@smithy/util-retry": "^4.2.3", "@smithy/util-utf8": "^4.2.0", - "@smithy/util-waiter": "^4.2.2", + "@smithy/util-waiter": "^4.2.3", "tslib": "^2.6.2" }, "engines": { @@ -564,47 +564,47 @@ } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.911.0.tgz", - "integrity": "sha512-N9QAeMvN3D1ZyKXkQp4aUgC4wUMuA5E1HuVCkajc0bq1pnH4PIke36YlrDGGREqPlyLFrXCkws2gbL5p23vtlg==", + "version": "3.919.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.919.0.tgz", + "integrity": "sha512-9DVw/1DCzZ9G7Jofnhpg/XDC3wdJ3NAJdNWY1TrgE5ZcpTM+UTIQMGyaljCv9rgxggutHBgmBI5lP3YMcPk9ZQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.911.0", - "@aws-sdk/middleware-host-header": "3.910.0", - "@aws-sdk/middleware-logger": "3.910.0", - "@aws-sdk/middleware-recursion-detection": "3.910.0", - "@aws-sdk/middleware-user-agent": "3.911.0", - "@aws-sdk/region-config-resolver": "3.910.0", - "@aws-sdk/types": "3.910.0", - "@aws-sdk/util-endpoints": "3.910.0", - "@aws-sdk/util-user-agent-browser": "3.910.0", - "@aws-sdk/util-user-agent-node": "3.911.0", - "@smithy/config-resolver": "^4.3.2", - "@smithy/core": "^3.16.1", - "@smithy/fetch-http-handler": "^5.3.3", - "@smithy/hash-node": "^4.2.2", - "@smithy/invalid-dependency": "^4.2.2", - "@smithy/middleware-content-length": "^4.2.2", - "@smithy/middleware-endpoint": "^4.3.3", - "@smithy/middleware-retry": "^4.4.3", - "@smithy/middleware-serde": "^4.2.2", - "@smithy/middleware-stack": "^4.2.2", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/node-http-handler": "^4.4.1", - "@smithy/protocol-http": "^5.3.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", - "@smithy/url-parser": "^4.2.2", + "@aws-sdk/core": "3.916.0", + "@aws-sdk/middleware-host-header": "3.914.0", + "@aws-sdk/middleware-logger": "3.914.0", + "@aws-sdk/middleware-recursion-detection": "3.919.0", + "@aws-sdk/middleware-user-agent": "3.916.0", + "@aws-sdk/region-config-resolver": "3.914.0", + "@aws-sdk/types": "3.914.0", + "@aws-sdk/util-endpoints": "3.916.0", + "@aws-sdk/util-user-agent-browser": "3.914.0", + "@aws-sdk/util-user-agent-node": "3.916.0", + "@smithy/config-resolver": "^4.4.0", + "@smithy/core": "^3.17.1", + "@smithy/fetch-http-handler": "^5.3.4", + "@smithy/hash-node": "^4.2.3", + "@smithy/invalid-dependency": "^4.2.3", + "@smithy/middleware-content-length": "^4.2.3", + "@smithy/middleware-endpoint": "^4.3.5", + "@smithy/middleware-retry": "^4.4.5", + "@smithy/middleware-serde": "^4.2.3", + "@smithy/middleware-stack": "^4.2.3", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/node-http-handler": "^4.4.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/smithy-client": "^4.9.1", + "@smithy/types": "^4.8.0", + "@smithy/url-parser": "^4.2.3", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.2", - "@smithy/util-defaults-mode-node": "^4.2.3", - "@smithy/util-endpoints": "^3.2.2", - "@smithy/util-middleware": "^4.2.2", - "@smithy/util-retry": "^4.2.2", + "@smithy/util-defaults-mode-browser": "^4.3.4", + "@smithy/util-defaults-mode-node": "^4.2.6", + "@smithy/util-endpoints": "^3.2.3", + "@smithy/util-middleware": "^4.2.3", + "@smithy/util-retry": "^4.2.3", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, @@ -613,22 +613,22 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.911.0.tgz", - "integrity": "sha512-k4QG9A+UCq/qlDJFmjozo6R0eXXfe++/KnCDMmajehIE9kh+b/5DqlGvAmbl9w4e92LOtrY6/DN3mIX1xs4sXw==", + "version": "3.916.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.916.0.tgz", + "integrity": "sha512-1JHE5s6MD5PKGovmx/F1e01hUbds/1y3X8rD+Gvi/gWVfdg5noO7ZCerpRsWgfzgvCMZC9VicopBqNHCKLykZA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.910.0", - "@aws-sdk/xml-builder": "3.911.0", - "@smithy/core": "^3.16.1", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/property-provider": "^4.2.2", - "@smithy/protocol-http": "^5.3.2", - "@smithy/signature-v4": "^5.3.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", + "@aws-sdk/types": "3.914.0", + "@aws-sdk/xml-builder": "3.914.0", + "@smithy/core": "^3.17.1", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/property-provider": "^4.2.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/signature-v4": "^5.3.3", + "@smithy/smithy-client": "^4.9.1", + "@smithy/types": "^4.8.0", "@smithy/util-base64": "^4.3.0", - "@smithy/util-middleware": "^4.2.2", + "@smithy/util-middleware": "^4.2.3", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, @@ -637,15 +637,15 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.911.0.tgz", - "integrity": "sha512-6FWRwWn3LUZzLhqBXB+TPMW2ijCWUqGICSw8bVakEdODrvbiv1RT/MVUayzFwz/ek6e6NKZn6DbSWzx07N9Hjw==", + "version": "3.916.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.916.0.tgz", + "integrity": "sha512-3gDeqOXcBRXGHScc6xb7358Lyf64NRG2P08g6Bu5mv1Vbg9PKDyCAZvhKLkG7hkdfAM8Yc6UJNhbFxr1ud/tCQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/property-provider": "^4.2.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/core": "3.916.0", + "@aws-sdk/types": "3.914.0", + "@smithy/property-provider": "^4.2.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -653,20 +653,20 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.911.0.tgz", - "integrity": "sha512-xUlwKmIUW2fWP/eM3nF5u4CyLtOtyohlhGJ5jdsJokr3MrQ7w0tDITO43C9IhCn+28D5UbaiWnKw5ntkw7aVfA==", + "version": "3.916.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.916.0.tgz", + "integrity": "sha512-NmooA5Z4/kPFJdsyoJgDxuqXC1C6oPMmreJjbOPqcwo6E/h2jxaG8utlQFgXe5F9FeJsMx668dtxVxSYnAAqHQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/fetch-http-handler": "^5.3.3", - "@smithy/node-http-handler": "^4.4.1", - "@smithy/property-provider": "^4.2.2", - "@smithy/protocol-http": "^5.3.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", - "@smithy/util-stream": "^4.5.2", + "@aws-sdk/core": "3.916.0", + "@aws-sdk/types": "3.914.0", + "@smithy/fetch-http-handler": "^5.3.4", + "@smithy/node-http-handler": "^4.4.3", + "@smithy/property-provider": "^4.2.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/smithy-client": "^4.9.1", + "@smithy/types": "^4.8.0", + "@smithy/util-stream": "^4.5.4", "tslib": "^2.6.2" }, "engines": { @@ -674,23 +674,23 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.913.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.913.0.tgz", - "integrity": "sha512-iR4c4NQ1OSRKQi0SxzpwD+wP1fCy+QNKtEyCajuVlD0pvmoIHdrm5THK9e+2/7/SsQDRhOXHJfLGxHapD74WJw==", + "version": "3.919.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.919.0.tgz", + "integrity": "sha512-fAWVfh0P54UFbyAK4tmIPh/X3COFAyXYSp8b2Pc1R6GRwDDMvrAigwGJuyZS4BmpPlXij1gB0nXbhM5Yo4MMMA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.911.0", - "@aws-sdk/credential-provider-env": "3.911.0", - "@aws-sdk/credential-provider-http": "3.911.0", - "@aws-sdk/credential-provider-process": "3.911.0", - "@aws-sdk/credential-provider-sso": "3.911.0", - "@aws-sdk/credential-provider-web-identity": "3.911.0", - "@aws-sdk/nested-clients": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/credential-provider-imds": "^4.2.2", - "@smithy/property-provider": "^4.2.2", - "@smithy/shared-ini-file-loader": "^4.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/core": "3.916.0", + "@aws-sdk/credential-provider-env": "3.916.0", + "@aws-sdk/credential-provider-http": "3.916.0", + "@aws-sdk/credential-provider-process": "3.916.0", + "@aws-sdk/credential-provider-sso": "3.919.0", + "@aws-sdk/credential-provider-web-identity": "3.919.0", + "@aws-sdk/nested-clients": "3.919.0", + "@aws-sdk/types": "3.914.0", + "@smithy/credential-provider-imds": "^4.2.3", + "@smithy/property-provider": "^4.2.3", + "@smithy/shared-ini-file-loader": "^4.3.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -698,22 +698,22 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.913.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.913.0.tgz", - "integrity": "sha512-HQPLkKDxS83Q/nZKqg9bq4igWzYQeOMqhpx5LYs4u1GwsKeCsYrrfz12Iu4IHNWPp9EnGLcmdfbfYuqZGrsaSQ==", + "version": "3.919.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.919.0.tgz", + "integrity": "sha512-GL5filyxYS+eZq8ZMQnY5hh79Wxor7Rljo0SUJxZVwEj8cf3zY0MMuwoXU1HQrVabvYtkPDOWSreX8GkIBtBCw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.911.0", - "@aws-sdk/credential-provider-http": "3.911.0", - "@aws-sdk/credential-provider-ini": "3.913.0", - "@aws-sdk/credential-provider-process": "3.911.0", - "@aws-sdk/credential-provider-sso": "3.911.0", - "@aws-sdk/credential-provider-web-identity": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/credential-provider-imds": "^4.2.2", - "@smithy/property-provider": "^4.2.2", - "@smithy/shared-ini-file-loader": "^4.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/credential-provider-env": "3.916.0", + "@aws-sdk/credential-provider-http": "3.916.0", + "@aws-sdk/credential-provider-ini": "3.919.0", + "@aws-sdk/credential-provider-process": "3.916.0", + "@aws-sdk/credential-provider-sso": "3.919.0", + "@aws-sdk/credential-provider-web-identity": "3.919.0", + "@aws-sdk/types": "3.914.0", + "@smithy/credential-provider-imds": "^4.2.3", + "@smithy/property-provider": "^4.2.3", + "@smithy/shared-ini-file-loader": "^4.3.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -721,16 +721,16 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.911.0.tgz", - "integrity": "sha512-mKshhV5jRQffZjbK9x7bs+uC2IsYKfpzYaBamFsEov3xtARCpOiKaIlM8gYKFEbHT2M+1R3rYYlhhl9ndVWS2g==", + "version": "3.916.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.916.0.tgz", + "integrity": "sha512-SXDyDvpJ1+WbotZDLJW1lqP6gYGaXfZJrgFSXIuZjHb75fKeNRgPkQX/wZDdUvCwdrscvxmtyJorp2sVYkMcvA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/property-provider": "^4.2.2", - "@smithy/shared-ini-file-loader": "^4.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/core": "3.916.0", + "@aws-sdk/types": "3.914.0", + "@smithy/property-provider": "^4.2.3", + "@smithy/shared-ini-file-loader": "^4.3.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -738,18 +738,18 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.911.0.tgz", - "integrity": "sha512-JAxd4uWe0Zc9tk6+N0cVxe9XtJVcOx6Ms0k933ZU9QbuRMH6xti/wnZxp/IvGIWIDzf5fhqiGyw5MSyDeI5b1w==", + "version": "3.919.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.919.0.tgz", + "integrity": "sha512-oN1XG/frOc2K2KdVwRQjLTBLM1oSFJLtOhuV/6g9N0ASD+44uVJai1CF9JJv5GjHGV+wsqAt+/Dzde0tZEXirA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-sso": "3.911.0", - "@aws-sdk/core": "3.911.0", - "@aws-sdk/token-providers": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/property-provider": "^4.2.2", - "@smithy/shared-ini-file-loader": "^4.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/client-sso": "3.919.0", + "@aws-sdk/core": "3.916.0", + "@aws-sdk/token-providers": "3.919.0", + "@aws-sdk/types": "3.914.0", + "@smithy/property-provider": "^4.2.3", + "@smithy/shared-ini-file-loader": "^4.3.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -757,17 +757,17 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.911.0.tgz", - "integrity": "sha512-urIbXWWG+cm54RwwTFQuRwPH0WPsMFSDF2/H9qO2J2fKoHRURuyblFCyYG3aVKZGvFBhOizJYexf5+5w3CJKBw==", + "version": "3.919.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.919.0.tgz", + "integrity": "sha512-Wi7RmyWA8kUJ++/8YceC7U5r4LyvOHGCnJLDHliP8rOC8HLdSgxw/Upeq3WmC+RPw1zyGOtEDRS/caop2xLXEA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.911.0", - "@aws-sdk/nested-clients": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/property-provider": "^4.2.2", - "@smithy/shared-ini-file-loader": "^4.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/core": "3.916.0", + "@aws-sdk/nested-clients": "3.919.0", + "@aws-sdk/types": "3.914.0", + "@smithy/property-provider": "^4.2.3", + "@smithy/shared-ini-file-loader": "^4.3.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -775,14 +775,14 @@ } }, "node_modules/@aws-sdk/lib-storage": { - "version": "3.913.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.913.0.tgz", - "integrity": "sha512-IOlCRCvq+DmN9d3o9LLBiGt9CFQDp11joKgZ4CziUQ59qkHonkaf0GOt6Oo4zITGBegJ0FvKsWj+sDgYoQ1U9g==", + "version": "3.919.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.919.0.tgz", + "integrity": "sha512-rhUAYZvnbDgahHZUzAGlbgMvfFN76c6MQYGYmEmJk3w/k0bmEQHV8xGGF1s1jrVZH66dXKv6kJCrqCbqaHi/ZQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^4.2.2", - "@smithy/middleware-endpoint": "^4.3.3", - "@smithy/smithy-client": "^4.8.1", + "@smithy/abort-controller": "^4.2.3", + "@smithy/middleware-endpoint": "^4.3.5", + "@smithy/smithy-client": "^4.9.1", "buffer": "5.6.0", "events": "3.3.0", "stream-browserify": "3.0.0", @@ -792,20 +792,20 @@ "node": ">=18.0.0" }, "peerDependencies": { - "@aws-sdk/client-s3": "^3.913.0" + "@aws-sdk/client-s3": "^3.919.0" } }, "node_modules/@aws-sdk/middleware-bucket-endpoint": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.910.0.tgz", - "integrity": "sha512-8ZfA0WARwvAKQQ7vmoQTg6xFEewFqsQCltQIHd7NtNs3CLF1aU06Ixp0i7Mp68k6dUj9WJJO7mz3I5VFOecqHQ==", + "version": "3.914.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.914.0.tgz", + "integrity": "sha512-mHLsVnPPp4iq3gL2oEBamfpeETFV0qzxRHmcnCfEP3hualV8YF8jbXGmwPCPopUPQDpbYDBHYtXaoClZikCWPQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.910.0", + "@aws-sdk/types": "3.914.0", "@aws-sdk/util-arn-parser": "3.893.0", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/protocol-http": "^5.3.2", - "@smithy/types": "^4.7.1", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/types": "^4.8.0", "@smithy/util-config-provider": "^4.2.0", "tslib": "^2.6.2" }, @@ -814,14 +814,14 @@ } }, "node_modules/@aws-sdk/middleware-expect-continue": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.910.0.tgz", - "integrity": "sha512-jtnsBlxuRyRbK52WdNSry28Tn4ljIqUfUEzDFYWDTEymEGPpVguQKPudW/6M5BWEDmNsv3ai/X+fXd0GZ1fE/Q==", + "version": "3.917.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.917.0.tgz", + "integrity": "sha512-UPBq1ZP2CaxwbncWSbVqkhYXQrmfNiqAtHyBxi413hjRVZ4JhQ1UyH7pz5yqiG8zx2/+Po8cUD4SDUwJgda4nw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.910.0", - "@smithy/protocol-http": "^5.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/types": "3.914.0", + "@smithy/protocol-http": "^5.3.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -829,22 +829,22 @@ } }, "node_modules/@aws-sdk/middleware-flexible-checksums": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.911.0.tgz", - "integrity": "sha512-ZeS5zPKRCBMqpO8e0S/isfDWBt8AtG604PopKFFqEowbbV8cf6ms3hddNZRajTHvaoWBlU7Fbcn0827RWJnBdw==", + "version": "3.919.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.919.0.tgz", + "integrity": "sha512-br56Wg1o5hLrMXX2iMjq12Cno/jsx9l2Y0KDI7hD4NFWycKCdsUpI1sjm8Asj18JbrbNWiCeAbFFlzcD8h+4wg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", - "@aws-sdk/core": "3.911.0", - "@aws-sdk/types": "3.910.0", + "@aws-sdk/core": "3.916.0", + "@aws-sdk/types": "3.914.0", "@smithy/is-array-buffer": "^4.2.0", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/protocol-http": "^5.3.2", - "@smithy/types": "^4.7.1", - "@smithy/util-middleware": "^4.2.2", - "@smithy/util-stream": "^4.5.2", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/types": "^4.8.0", + "@smithy/util-middleware": "^4.2.3", + "@smithy/util-stream": "^4.5.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, @@ -853,14 +853,14 @@ } }, "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.910.0.tgz", - "integrity": "sha512-F9Lqeu80/aTM6S/izZ8RtwSmjfhWjIuxX61LX+/9mxJyEkgaECRxv0chsLQsLHJumkGnXRy/eIyMLBhcTPF5vg==", + "version": "3.914.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.914.0.tgz", + "integrity": "sha512-7r9ToySQ15+iIgXMF/h616PcQStByylVkCshmQqcdeynD/lCn2l667ynckxW4+ql0Q+Bo/URljuhJRxVJzydNA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.910.0", - "@smithy/protocol-http": "^5.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/types": "3.914.0", + "@smithy/protocol-http": "^5.3.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -868,13 +868,13 @@ } }, "node_modules/@aws-sdk/middleware-location-constraint": { - "version": "3.913.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.913.0.tgz", - "integrity": "sha512-iudUrAYV4ZyweYL0hW/VaJzJRjFVruHpK0NukwECs0FZ76Zn17/smbkFIeiaRdGi9cqQdRk9PfhKPvbufnnhPg==", + "version": "3.914.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.914.0.tgz", + "integrity": "sha512-Mpd0Sm9+GN7TBqGnZg1+dO5QZ/EOYEcDTo7KfvoyrXScMlxvYm9fdrUVMmLdPn/lntweZGV3uNrs+huasGOOTA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.910.0", - "@smithy/types": "^4.7.1", + "@aws-sdk/types": "3.914.0", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -882,13 +882,13 @@ } }, "node_modules/@aws-sdk/middleware-logger": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.910.0.tgz", - "integrity": "sha512-3LJyyfs1USvRuRDla1pGlzGRtXJBXD1zC9F+eE9Iz/V5nkmhyv52A017CvKWmYoR0DM9dzjLyPOI0BSSppEaTw==", + "version": "3.914.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.914.0.tgz", + "integrity": "sha512-/gaW2VENS5vKvJbcE1umV4Ag3NuiVzpsANxtrqISxT3ovyro29o1RezW/Avz/6oJqjnmgz8soe9J1t65jJdiNg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.910.0", - "@smithy/types": "^4.7.1", + "@aws-sdk/types": "3.914.0", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -896,15 +896,15 @@ } }, "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.910.0.tgz", - "integrity": "sha512-m/oLz0EoCy+WoIVBnXRXJ4AtGpdl0kPE7U+VH9TsuUzHgxY1Re/176Q1HWLBRVlz4gr++lNsgsMWEC+VnAwMpw==", + "version": "3.919.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.919.0.tgz", + "integrity": "sha512-q3MAUxLQve4rTfAannUCx2q1kAHkBBsxt6hVUpzi63KC4lBLScc1ltr7TI+hDxlfGRWGo54jRegb2SsY9Jm+Mw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.910.0", - "@aws/lambda-invoke-store": "^0.0.1", - "@smithy/protocol-http": "^5.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/types": "3.914.0", + "@aws/lambda-invoke-store": "^0.1.1", + "@smithy/protocol-http": "^5.3.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -912,23 +912,23 @@ } }, "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.911.0.tgz", - "integrity": "sha512-P0mIIW/QkAGNvFu15Jqa5NSmHeQvZkkQY8nbQpCT3tGObZe4wRsq5u1mOS+CJp4DIBbRZuHeX7ohbX5kPMi4dg==", + "version": "3.916.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.916.0.tgz", + "integrity": "sha512-pjmzzjkEkpJObzmTthqJPq/P13KoNFuEi/x5PISlzJtHofCNcyXeVAQ90yvY2dQ6UXHf511Rh1/ytiKy2A8M0g==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.911.0", - "@aws-sdk/types": "3.910.0", + "@aws-sdk/core": "3.916.0", + "@aws-sdk/types": "3.914.0", "@aws-sdk/util-arn-parser": "3.893.0", - "@smithy/core": "^3.16.1", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/protocol-http": "^5.3.2", - "@smithy/signature-v4": "^5.3.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", + "@smithy/core": "^3.17.1", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/signature-v4": "^5.3.3", + "@smithy/smithy-client": "^4.9.1", + "@smithy/types": "^4.8.0", "@smithy/util-config-provider": "^4.2.0", - "@smithy/util-middleware": "^4.2.2", - "@smithy/util-stream": "^4.5.2", + "@smithy/util-middleware": "^4.2.3", + "@smithy/util-stream": "^4.5.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, @@ -937,13 +937,13 @@ } }, "node_modules/@aws-sdk/middleware-ssec": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.910.0.tgz", - "integrity": "sha512-Ikb0WrIiOeaZo9UmeoVrO4GH2OHiMTKSbr5raTW8nTCArED8iTVZiBF6As+JicZMLSNiBiYSb7EjDihWQ0DrTQ==", + "version": "3.914.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.914.0.tgz", + "integrity": "sha512-V1Oae/oLVbpNb9uWs+v80GKylZCdsbqs2c2Xb1FsAUPtYeSnxFuAWsF3/2AEMSSpFe0dTC5KyWr/eKl2aim9VQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.910.0", - "@smithy/types": "^4.7.1", + "@aws-sdk/types": "3.914.0", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -951,17 +951,17 @@ } }, "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.911.0.tgz", - "integrity": "sha512-rY3LvGvgY/UI0nmt5f4DRzjEh8135A2TeHcva1bgOmVfOI4vkkGfA20sNRqerOkSO6hPbkxJapO50UJHFzmmyA==", + "version": "3.916.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.916.0.tgz", + "integrity": "sha512-mzF5AdrpQXc2SOmAoaQeHpDFsK2GE6EGcEACeNuoESluPI2uYMpuuNMYrUufdnIAIyqgKlis0NVxiahA5jG42w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@aws-sdk/util-endpoints": "3.910.0", - "@smithy/core": "^3.16.1", - "@smithy/protocol-http": "^5.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/core": "3.916.0", + "@aws-sdk/types": "3.914.0", + "@aws-sdk/util-endpoints": "3.916.0", + "@smithy/core": "^3.17.1", + "@smithy/protocol-http": "^5.3.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -969,47 +969,47 @@ } }, "node_modules/@aws-sdk/nested-clients": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.911.0.tgz", - "integrity": "sha512-lp/sXbdX/S0EYaMYPVKga0omjIUbNNdFi9IJITgKZkLC6CzspihIoHd5GIdl4esMJevtTQQfkVncXTFkf/a4YA==", + "version": "3.919.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.919.0.tgz", + "integrity": "sha512-5D9OQsMPkbkp4KHM7JZv/RcGCpr3E1L7XX7U9sCxY+sFGeysltoviTmaIBXsJ2IjAJbBULtf0G/J+2cfH5OP+w==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.911.0", - "@aws-sdk/middleware-host-header": "3.910.0", - "@aws-sdk/middleware-logger": "3.910.0", - "@aws-sdk/middleware-recursion-detection": "3.910.0", - "@aws-sdk/middleware-user-agent": "3.911.0", - "@aws-sdk/region-config-resolver": "3.910.0", - "@aws-sdk/types": "3.910.0", - "@aws-sdk/util-endpoints": "3.910.0", - "@aws-sdk/util-user-agent-browser": "3.910.0", - "@aws-sdk/util-user-agent-node": "3.911.0", - "@smithy/config-resolver": "^4.3.2", - "@smithy/core": "^3.16.1", - "@smithy/fetch-http-handler": "^5.3.3", - "@smithy/hash-node": "^4.2.2", - "@smithy/invalid-dependency": "^4.2.2", - "@smithy/middleware-content-length": "^4.2.2", - "@smithy/middleware-endpoint": "^4.3.3", - "@smithy/middleware-retry": "^4.4.3", - "@smithy/middleware-serde": "^4.2.2", - "@smithy/middleware-stack": "^4.2.2", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/node-http-handler": "^4.4.1", - "@smithy/protocol-http": "^5.3.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", - "@smithy/url-parser": "^4.2.2", + "@aws-sdk/core": "3.916.0", + "@aws-sdk/middleware-host-header": "3.914.0", + "@aws-sdk/middleware-logger": "3.914.0", + "@aws-sdk/middleware-recursion-detection": "3.919.0", + "@aws-sdk/middleware-user-agent": "3.916.0", + "@aws-sdk/region-config-resolver": "3.914.0", + "@aws-sdk/types": "3.914.0", + "@aws-sdk/util-endpoints": "3.916.0", + "@aws-sdk/util-user-agent-browser": "3.914.0", + "@aws-sdk/util-user-agent-node": "3.916.0", + "@smithy/config-resolver": "^4.4.0", + "@smithy/core": "^3.17.1", + "@smithy/fetch-http-handler": "^5.3.4", + "@smithy/hash-node": "^4.2.3", + "@smithy/invalid-dependency": "^4.2.3", + "@smithy/middleware-content-length": "^4.2.3", + "@smithy/middleware-endpoint": "^4.3.5", + "@smithy/middleware-retry": "^4.4.5", + "@smithy/middleware-serde": "^4.2.3", + "@smithy/middleware-stack": "^4.2.3", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/node-http-handler": "^4.4.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/smithy-client": "^4.9.1", + "@smithy/types": "^4.8.0", + "@smithy/url-parser": "^4.2.3", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.2", - "@smithy/util-defaults-mode-node": "^4.2.3", - "@smithy/util-endpoints": "^3.2.2", - "@smithy/util-middleware": "^4.2.2", - "@smithy/util-retry": "^4.2.2", + "@smithy/util-defaults-mode-browser": "^4.3.4", + "@smithy/util-defaults-mode-node": "^4.2.6", + "@smithy/util-endpoints": "^3.2.3", + "@smithy/util-middleware": "^4.2.3", + "@smithy/util-retry": "^4.2.3", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, @@ -1018,16 +1018,14 @@ } }, "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.910.0.tgz", - "integrity": "sha512-gzQAkuHI3xyG6toYnH/pju+kc190XmvnB7X84vtN57GjgdQJICt9So/BD0U6h+eSfk9VBnafkVrAzBzWMEFZVw==", + "version": "3.914.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.914.0.tgz", + "integrity": "sha512-KlmHhRbn1qdwXUdsdrJ7S/MAkkC1jLpQ11n+XvxUUUCGAJd1gjC7AjxPZUM7ieQ2zcb8bfEzIU7al+Q3ZT0u7Q==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.910.0", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/types": "^4.7.1", - "@smithy/util-config-provider": "^4.2.0", - "@smithy/util-middleware": "^4.2.2", + "@aws-sdk/types": "3.914.0", + "@smithy/config-resolver": "^4.4.0", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -1035,18 +1033,18 @@ } }, "node_modules/@aws-sdk/s3-request-presigner": { - "version": "3.913.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.913.0.tgz", - "integrity": "sha512-vM8waw7LQPYhHWHTNb259CxrkswVijnsSmqVA6ehxUWGgZVV5uGvRDwIgZxPFE9BBWzxig5u/vP31i1+cW2lnw==", + "version": "3.919.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.919.0.tgz", + "integrity": "sha512-eMrSACGFU9iSm3Eil9qA+Ordnroc7OWFr37cJBsZSBrolIPYmzg/AYYOBllS2c1Z4Qh//StLAkeVDyRM0vDfHw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/signature-v4-multi-region": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@aws-sdk/util-format-url": "3.910.0", - "@smithy/middleware-endpoint": "^4.3.3", - "@smithy/protocol-http": "^5.3.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", + "@aws-sdk/signature-v4-multi-region": "3.916.0", + "@aws-sdk/types": "3.914.0", + "@aws-sdk/util-format-url": "3.914.0", + "@smithy/middleware-endpoint": "^4.3.5", + "@smithy/protocol-http": "^5.3.3", + "@smithy/smithy-client": "^4.9.1", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -1054,16 +1052,16 @@ } }, "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.911.0.tgz", - "integrity": "sha512-SJ4dUcY9+HPDIMCHiskT8F7JrRVZF2Y1NUN0Yiy6VUHSULgq2MDlIzSQpNICnmXhk1F1E1B2jJG9XtPYrvtqUg==", + "version": "3.916.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.916.0.tgz", + "integrity": "sha512-fuzUMo6xU7e0NBzBA6TQ4FUf1gqNbg4woBSvYfxRRsIfKmSMn9/elXXn4sAE5UKvlwVQmYnb6p7dpVRPyFvnQA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/middleware-sdk-s3": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/protocol-http": "^5.3.2", - "@smithy/signature-v4": "^5.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/middleware-sdk-s3": "3.916.0", + "@aws-sdk/types": "3.914.0", + "@smithy/protocol-http": "^5.3.3", + "@smithy/signature-v4": "^5.3.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -1071,17 +1069,17 @@ } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.911.0.tgz", - "integrity": "sha512-O1c5F1pbEImgEe3Vr8j1gpWu69UXWj3nN3vvLGh77hcrG5dZ8I27tSP5RN4Labm8Dnji/6ia+vqSYpN8w6KN5A==", + "version": "3.919.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.919.0.tgz", + "integrity": "sha512-6aFv4lzXbfbkl0Pv37Us8S/ZkqplOQZIEgQg7bfMru7P96Wv2jVnDGsEc5YyxMnnRyIB90naQ5JgslZ4rkpknw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.911.0", - "@aws-sdk/nested-clients": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/property-provider": "^4.2.2", - "@smithy/shared-ini-file-loader": "^4.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/core": "3.916.0", + "@aws-sdk/nested-clients": "3.919.0", + "@aws-sdk/types": "3.914.0", + "@smithy/property-provider": "^4.2.3", + "@smithy/shared-ini-file-loader": "^4.3.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -1089,12 +1087,12 @@ } }, "node_modules/@aws-sdk/types": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.910.0.tgz", - "integrity": "sha512-o67gL3vjf4nhfmuSUNNkit0d62QJEwwHLxucwVJkR/rw9mfUtAWsgBs8Tp16cdUbMgsyQtCQilL8RAJDoGtadQ==", + "version": "3.914.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.914.0.tgz", + "integrity": "sha512-kQWPsRDmom4yvAfyG6L1lMmlwnTzm1XwMHOU+G5IFlsP4YEaMtXidDzW/wiivY0QFrhfCz/4TVmu0a2aPU57ug==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.7.1", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -1114,15 +1112,15 @@ } }, "node_modules/@aws-sdk/util-endpoints": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.910.0.tgz", - "integrity": "sha512-6XgdNe42ibP8zCQgNGDWoOF53RfEKzpU/S7Z29FTTJ7hcZv0SytC0ZNQQZSx4rfBl036YWYwJRoJMlT4AA7q9A==", + "version": "3.916.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.916.0.tgz", + "integrity": "sha512-bAgUQwvixdsiGNcuZSDAOWbyHlnPtg8G8TyHD6DTfTmKTHUW6tAn+af/ZYJPXEzXhhpwgJqi58vWnsiDhmr7NQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.910.0", - "@smithy/types": "^4.7.1", - "@smithy/url-parser": "^4.2.2", - "@smithy/util-endpoints": "^3.2.2", + "@aws-sdk/types": "3.914.0", + "@smithy/types": "^4.8.0", + "@smithy/url-parser": "^4.2.3", + "@smithy/util-endpoints": "^3.2.3", "tslib": "^2.6.2" }, "engines": { @@ -1130,14 +1128,14 @@ } }, "node_modules/@aws-sdk/util-format-url": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.910.0.tgz", - "integrity": "sha512-cYfgDGxZnrAq7wvntBjW6/ZewRcwywOE1Q9KKPO05ZHXpWCrqKNkx0JG8h2xlu+2qX6lkLZS+NyFAlwCQa0qfA==", + "version": "3.914.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.914.0.tgz", + "integrity": "sha512-QpdkoQjvPaYyzZwgk41vFyHQM5s0DsrsbQ8IoPUggQt4HaJUvmL1ShwMcSldbgdzwiRMqXUK8q7jrqUvkYkY6w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.910.0", - "@smithy/querystring-builder": "^4.2.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/types": "3.914.0", + "@smithy/querystring-builder": "^4.2.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -1157,27 +1155,27 @@ } }, "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.910.0.tgz", - "integrity": "sha512-iOdrRdLZHrlINk9pezNZ82P/VxO/UmtmpaOAObUN+xplCUJu31WNM2EE/HccC8PQw6XlAudpdA6HDTGiW6yVGg==", + "version": "3.914.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.914.0.tgz", + "integrity": "sha512-rMQUrM1ECH4kmIwlGl9UB0BtbHy6ZuKdWFrIknu8yGTRI/saAucqNTh5EI1vWBxZ0ElhK5+g7zOnUuhSmVQYUA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.910.0", - "@smithy/types": "^4.7.1", + "@aws-sdk/types": "3.914.0", + "@smithy/types": "^4.8.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.911.0.tgz", - "integrity": "sha512-3l+f6ooLF6Z6Lz0zGi7vSKSUYn/EePPizv88eZQpEAFunBHv+CSVNPtxhxHfkm7X9tTsV4QGZRIqo3taMLolmA==", + "version": "3.916.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.916.0.tgz", + "integrity": "sha512-CwfWV2ch6UdjuSV75ZU99N03seEUb31FIUrXBnwa6oONqj/xqXwrxtlUMLx6WH3OJEE4zI3zt5PjlTdGcVwf4g==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/middleware-user-agent": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/middleware-user-agent": "3.916.0", + "@aws-sdk/types": "3.914.0", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -1193,12 +1191,12 @@ } }, "node_modules/@aws-sdk/xml-builder": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.911.0.tgz", - "integrity": "sha512-/yh3oe26bZfCVGrIMRM9Z4hvvGJD+qx5tOLlydOkuBkm72aXON7D9+MucjJXTAcI8tF2Yq+JHa0478eHQOhnLg==", + "version": "3.914.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.914.0.tgz", + "integrity": "sha512-k75evsBD5TcIjedycYS7QXQ98AmOtbnxRJOPtCo0IwYRmy7UvqgS/gBL5SmrIqeV6FDSYRQMgdBxSMp6MLmdew==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.7.1", + "@smithy/types": "^4.8.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" }, @@ -1225,9 +1223,9 @@ } }, "node_modules/@aws/lambda-invoke-store": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.0.1.tgz", - "integrity": "sha512-ORHRQ2tmvnBXc8t/X9Z8IcSbBA4xTLKuN873FopzklHMeqBst7YG0d+AX97inkvDX+NChYtSr+qGfcqGFaI8Zw==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.1.1.tgz", + "integrity": "sha512-RcLam17LdlbSOSp9VxmUu1eI6Mwxp+OwhD2QhiSNmNCzoDb0EeUXTD2n/WbcnrAYMGlmf05th6QYq23VqvJqpA==", "license": "Apache-2.0", "engines": { "node": ">=18.0.0" @@ -1254,9 +1252,9 @@ } }, "node_modules/@datadog/flagging-core": { - "version": "0.1.0-preview.10", - "resolved": "https://registry.npmjs.org/@datadog/flagging-core/-/flagging-core-0.1.0-preview.10.tgz", - "integrity": "sha512-E1jRY80xqgL9Hie3vGbQUiK8FXijeN+h9DHXourcPgw+F2fiQ3m1sLTNrjrZTOOpKfhJE/lvahssQpMRtQh1TA==", + "version": "0.1.0-preview.12", + "resolved": "https://registry.npmjs.org/@datadog/flagging-core/-/flagging-core-0.1.0-preview.12.tgz", + "integrity": "sha512-3oI/8dNpGkZaYf77KJpZMNoYpnkwCq3Dgy0UChEz6JX2jtxbwv1sQFAaG1z078T/FwPnB2hMuO5zLXKkx53StA==", "license": "MIT", "dependencies": { "spark-md5": "^3.0.2" @@ -1272,9 +1270,9 @@ "license": "Apache-2.0" }, "node_modules/@datadog/native-appsec": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/@datadog/native-appsec/-/native-appsec-10.2.1.tgz", - "integrity": "sha512-FwRVo+otgNaz6vN74XVrBT8GdLwxPwAqOjH4Y9VQJaC1RiHmzRCMr77AhHFme1xi7zPG2LQqQN/cmOzG+sbrtQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@datadog/native-appsec/-/native-appsec-10.3.0.tgz", + "integrity": "sha512-FjNhxKetbBVGiq+dl8NYoi/95IAYU+W7PjBceNP7Qkvbt8uhy+KTlQVW1A2X67mK0CKHahDTesBMaPwY9zhflw==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -1309,12 +1307,12 @@ } }, "node_modules/@datadog/openfeature-node-server": { - "version": "0.1.0-preview.10", - "resolved": "https://registry.npmjs.org/@datadog/openfeature-node-server/-/openfeature-node-server-0.1.0-preview.10.tgz", - "integrity": "sha512-btTKlz80Gn2Xj0m2LR9ZKkoB/Wybu4mFa86wPJv3G1IKU61wgPpvdIILDEwDz+lg5gLjxxeJM50r4tP82bEteQ==", + "version": "0.1.0-preview.12", + "resolved": "https://registry.npmjs.org/@datadog/openfeature-node-server/-/openfeature-node-server-0.1.0-preview.12.tgz", + "integrity": "sha512-bzh2zk84bobSyOzcF6wxzFIKcEQV2M2QP5nWLfDNOPl4tS/qxoTpi3hvT8a6TnPvXmSZrcfB2JUq54qaT3BnKw==", "license": "MIT", "dependencies": { - "@datadog/flagging-core": "0.1.0-preview.10", + "@datadog/flagging-core": "0.1.0-preview.12", "@openfeature/server-sdk": "~1.18.0" }, "engines": { @@ -2286,15 +2284,16 @@ } }, "node_modules/@smithy/config-resolver": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.3.2.tgz", - "integrity": "sha512-F/G+VaulIebINyfvcoXmODgIc7JU/lxWK9/iI0Divxyvd2QWB7/ZcF7JKwMssWI6/zZzlMkq/Pt6ow2AOEebPw==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.0.tgz", + "integrity": "sha512-Kkmz3Mup2PGp/HNJxhCWkLNdlajJORLSjwkcfrj0E7nu6STAEdcMR1ir5P9/xOmncx8xXfru0fbUYLlZog/cFg==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.3.2", - "@smithy/types": "^4.7.1", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/types": "^4.8.0", "@smithy/util-config-provider": "^4.2.0", - "@smithy/util-middleware": "^4.2.2", + "@smithy/util-endpoints": "^3.2.3", + "@smithy/util-middleware": "^4.2.3", "tslib": "^2.6.2" }, "engines": { @@ -2302,18 +2301,18 @@ } }, "node_modules/@smithy/core": { - "version": "3.16.1", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.16.1.tgz", - "integrity": "sha512-yRx5ag3xEQ/yGvyo80FVukS7ZkeUP49Vbzg0MjfHLkuCIgg5lFtaEJfZR178KJmjWPqLU4d0P4k7SKgF9UkOaQ==", + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.17.1.tgz", + "integrity": "sha512-V4Qc2CIb5McABYfaGiIYLTmo/vwNIK7WXI5aGveBd9UcdhbOMwcvIMxIw/DJj1S9QgOMa/7FBkarMdIC0EOTEQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/middleware-serde": "^4.2.2", - "@smithy/protocol-http": "^5.3.2", - "@smithy/types": "^4.7.1", + "@smithy/middleware-serde": "^4.2.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/types": "^4.8.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-middleware": "^4.2.2", - "@smithy/util-stream": "^4.5.2", + "@smithy/util-middleware": "^4.2.3", + "@smithy/util-stream": "^4.5.4", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" @@ -2323,15 +2322,15 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.2.tgz", - "integrity": "sha512-hOjFTK+4mfehDnfjNkPqHUKBKR2qmlix5gy7YzruNbTdeoBE3QkfNCPvuCK2r05VUJ02QQ9bz2G41CxhSexsMw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.3.tgz", + "integrity": "sha512-hA1MQ/WAHly4SYltJKitEsIDVsNmXcQfYBRv2e+q04fnqtAX5qXaybxy/fhUeAMCnQIdAjaGDb04fMHQefWRhw==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.3.2", - "@smithy/property-provider": "^4.2.2", - "@smithy/types": "^4.7.1", - "@smithy/url-parser": "^4.2.2", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/property-provider": "^4.2.3", + "@smithy/types": "^4.8.0", + "@smithy/url-parser": "^4.2.3", "tslib": "^2.6.2" }, "engines": { @@ -2409,14 +2408,14 @@ } }, "node_modules/@smithy/fetch-http-handler": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.3.tgz", - "integrity": "sha512-cipIcM3xQ5NdIVwcRb37LaQwIxZNMEZb/ZOPmLFS9uGo9TGx2dGCyMBj9oT7ypH4TUD/kOTc/qHmwQzthrSk+g==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.4.tgz", + "integrity": "sha512-bwigPylvivpRLCm+YK9I5wRIYjFESSVwl8JQ1vVx/XhCw0PtCi558NwTnT2DaVCl5pYlImGuQTSwMsZ+pIavRw==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.3.2", - "@smithy/querystring-builder": "^4.2.2", - "@smithy/types": "^4.7.1", + "@smithy/protocol-http": "^5.3.3", + "@smithy/querystring-builder": "^4.2.3", + "@smithy/types": "^4.8.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" }, @@ -2425,14 +2424,14 @@ } }, "node_modules/@smithy/hash-blob-browser": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.3.tgz", - "integrity": "sha512-ZYd5FYhyvD4PCnqa1vO1tzqQ1s9fWs+el8DJZUfHumvq9wl7UXoLAqof+lAqSe/mVsf2I4tclf9BbTr6NL/pjQ==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.4.tgz", + "integrity": "sha512-W7eIxD+rTNsLB/2ynjmbdeP7TgxRXprfvqQxKFEfy9HW2HeD7t+g+KCIrY0pIn/GFjA6/fIpH+JQnfg5TTk76Q==", "license": "Apache-2.0", "dependencies": { "@smithy/chunked-blob-reader": "^5.2.0", "@smithy/chunked-blob-reader-native": "^4.2.1", - "@smithy/types": "^4.7.1", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -2522,18 +2521,18 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.3.3.tgz", - "integrity": "sha512-CfxQ6X9L87/3C67Po6AGWXsx8iS4w2BO8vQEZJD6hwqg2vNRC/lMa2O5wXYCG9tKotdZ0R8KG33TS7kpUnYKiw==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.3.5.tgz", + "integrity": "sha512-SIzKVTvEudFWJbxAaq7f2GvP3jh2FHDpIFI6/VAf4FOWGFZy0vnYMPSRj8PGYI8Hjt29mvmwSRgKuO3bK4ixDw==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.16.1", - "@smithy/middleware-serde": "^4.2.2", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/shared-ini-file-loader": "^4.3.2", - "@smithy/types": "^4.7.1", - "@smithy/url-parser": "^4.2.2", - "@smithy/util-middleware": "^4.2.2", + "@smithy/core": "^3.17.1", + "@smithy/middleware-serde": "^4.2.3", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/shared-ini-file-loader": "^4.3.3", + "@smithy/types": "^4.8.0", + "@smithy/url-parser": "^4.2.3", + "@smithy/util-middleware": "^4.2.3", "tslib": "^2.6.2" }, "engines": { @@ -2541,18 +2540,18 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.3.tgz", - "integrity": "sha512-EHnKGeFuzbmER4oSl/VJDxPLi+aiZUb3nk5KK8eNwHjMhI04jHlui2ZkaBzMfNmXOgymaS6zV//fyt6PSnI1ow==", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.5.tgz", + "integrity": "sha512-DCaXbQqcZ4tONMvvdz+zccDE21sLcbwWoNqzPLFlZaxt1lDtOE2tlVpRSwcTOJrjJSUThdgEYn7HrX5oLGlK9A==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.3.2", - "@smithy/protocol-http": "^5.3.2", - "@smithy/service-error-classification": "^4.2.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", - "@smithy/util-middleware": "^4.2.2", - "@smithy/util-retry": "^4.2.2", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/service-error-classification": "^4.2.3", + "@smithy/smithy-client": "^4.9.1", + "@smithy/types": "^4.8.0", + "@smithy/util-middleware": "^4.2.3", + "@smithy/util-retry": "^4.2.3", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" }, @@ -2561,13 +2560,13 @@ } }, "node_modules/@smithy/middleware-serde": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.2.tgz", - "integrity": "sha512-tDMPMBCsA1GBxanShhPvQYwdiau3NmctUp+eELMhUTDua+EUrugXlaKCnTMMoEB5mbHFebdv81uJPkVP02oihA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.3.tgz", + "integrity": "sha512-8g4NuUINpYccxiCXM5s1/V+uLtts8NcX4+sPEbvYQDZk4XoJfDpq5y2FQxfmUL89syoldpzNzA0R9nhzdtdKnQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.3.2", - "@smithy/types": "^4.7.1", + "@smithy/protocol-http": "^5.3.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -2575,12 +2574,12 @@ } }, "node_modules/@smithy/middleware-stack": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.2.tgz", - "integrity": "sha512-7rgzDyLOQouh1bC6gOXnCGSX2dqvbOclgClsFkj735xQM2CHV63Ams8odNZGJgcqnBsEz44V/pDGHU6ALEUD+w==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.3.tgz", + "integrity": "sha512-iGuOJkH71faPNgOj/gWuEGS6xvQashpLwWB1HjHq1lNNiVfbiJLpZVbhddPuDbx9l4Cgl0vPLq5ltRfSaHfspA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.7.1", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -2603,15 +2602,15 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.1.tgz", - "integrity": "sha512-9gKJoL45MNyOCGTG082nmx0A6KrbLVQ+5QSSKyzRi0AzL0R81u3wC1+nPvKXgTaBdAKM73fFPdCBHpmtipQwdQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.3.tgz", + "integrity": "sha512-MAwltrDB0lZB/H6/2M5PIsISSwdI5yIh6DaBB9r0Flo9nx3y0dzl/qTMJPd7tJvPdsx6Ks/cwVzheGNYzXyNbQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^4.2.2", - "@smithy/protocol-http": "^5.3.2", - "@smithy/querystring-builder": "^4.2.2", - "@smithy/types": "^4.7.1", + "@smithy/abort-controller": "^4.2.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/querystring-builder": "^4.2.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -2645,12 +2644,12 @@ } }, "node_modules/@smithy/querystring-builder": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.2.tgz", - "integrity": "sha512-YgXvq89o+R/8zIoeuXYv8Ysrbwgjx+iVYu9QbseqZjMDAhIg/FRt7jis0KASYFtd/Cnsnz4/nYTJXkJDWe8wHg==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.3.tgz", + "integrity": "sha512-LOVCGCmwMahYUM/P0YnU/AlDQFjcu+gWbFJooC417QRB/lDJlWSn8qmPSDp+s4YVAHOgtgbNG4sR+SxF/VOcJQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.7.1", + "@smithy/types": "^4.8.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" }, @@ -2659,12 +2658,12 @@ } }, "node_modules/@smithy/querystring-parser": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.2.tgz", - "integrity": "sha512-DczOD2yJy3NXcv1JvhjFC7bIb/tay6nnIRD/qrzBaju5lrkVBOwCT3Ps37tra20wy8PicZpworStK7ZcI9pCRQ==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.3.tgz", + "integrity": "sha512-cYlSNHcTAX/wc1rpblli3aUlLMGgKZ/Oqn8hhjFASXMCXjIqeuQBei0cnq2JR8t4RtU9FpG6uyl6PxyArTiwKA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.7.1", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -2672,12 +2671,12 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.2.tgz", - "integrity": "sha512-1X17cMLwe/vb4RpZbQVpJ1xQQ7fhQKggMdt3qjdV3+6QNllzvUXyS3WFnyaFWLyaGqfYHKkNONbO1fBCMQyZtQ==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.3.tgz", + "integrity": "sha512-NkxsAxFWwsPsQiwFG2MzJ/T7uIR6AQNh1SzcxSUnmmIqIQMlLRQDKhc17M7IYjiuBXhrQRjQTo3CxX+DobS93g==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.7.1" + "@smithy/types": "^4.8.0" }, "engines": { "node": ">=18.0.0" @@ -2716,17 +2715,17 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.8.1.tgz", - "integrity": "sha512-N5wK57pVThzLVK5NgmHxocTy5auqGDGQ+JsL5RjCTriPt8JLYgXT0Awa915zCpzc9hXHDOKqDX5g9BFdwkSfUA==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.9.1.tgz", + "integrity": "sha512-Ngb95ryR5A9xqvQFT5mAmYkCwbXvoLavLFwmi7zVg/IowFPCfiqRfkOKnbc/ZRL8ZKJ4f+Tp6kSu6wjDQb8L/g==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.16.1", - "@smithy/middleware-endpoint": "^4.3.3", - "@smithy/middleware-stack": "^4.2.2", - "@smithy/protocol-http": "^5.3.2", - "@smithy/types": "^4.7.1", - "@smithy/util-stream": "^4.5.2", + "@smithy/core": "^3.17.1", + "@smithy/middleware-endpoint": "^4.3.5", + "@smithy/middleware-stack": "^4.2.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/types": "^4.8.0", + "@smithy/util-stream": "^4.5.4", "tslib": "^2.6.2" }, "engines": { @@ -2746,13 +2745,13 @@ } }, "node_modules/@smithy/url-parser": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.2.tgz", - "integrity": "sha512-s2EYKukaswzjiHJCss6asB1F4zjRc0E/MFyceAKzb3+wqKA2Z/+Gfhb5FP8xVVRHBAvBkregaQAydifgbnUlCw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.3.tgz", + "integrity": "sha512-I066AigYvY3d9VlU3zG9XzZg1yT10aNqvCaBTw9EPgu5GrsEl1aUkcMvhkIXascYH1A8W0LQo3B1Kr1cJNcQEw==", "license": "Apache-2.0", "dependencies": { - "@smithy/querystring-parser": "^4.2.2", - "@smithy/types": "^4.7.1", + "@smithy/querystring-parser": "^4.2.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -2823,14 +2822,14 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.2.tgz", - "integrity": "sha512-6JvKHZ5GORYkEZ2+yJKEHp6dQQKng+P/Mu3g3CDy0fRLQgXEO8be+FLrBGGb4kB9lCW6wcQDkN7kRiGkkVAXgg==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.4.tgz", + "integrity": "sha512-qI5PJSW52rnutos8Bln8nwQZRpyoSRN6k2ajyoUHNMUzmWqHnOJCnDELJuV6m5PML0VkHI+XcXzdB+6awiqYUw==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^4.2.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", + "@smithy/property-provider": "^4.2.3", + "@smithy/smithy-client": "^4.9.1", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -2838,17 +2837,17 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.3.tgz", - "integrity": "sha512-bkTGuMmKvghfCh9NayADrQcjngoF8P+XTgID5r3rm+8LphFiuM6ERqpBS95YyVaLjDetnKus9zK/bGlkQOOtNQ==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.6.tgz", + "integrity": "sha512-c6M/ceBTm31YdcFpgfgQAJaw3KbaLuRKnAz91iMWFLSrgxRpYm03c3bu5cpYojNMfkV9arCUelelKA7XQT36SQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/config-resolver": "^4.3.2", - "@smithy/credential-provider-imds": "^4.2.2", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/property-provider": "^4.2.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", + "@smithy/config-resolver": "^4.4.0", + "@smithy/credential-provider-imds": "^4.2.3", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/property-provider": "^4.2.3", + "@smithy/smithy-client": "^4.9.1", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -2895,13 +2894,13 @@ } }, "node_modules/@smithy/util-retry": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.2.tgz", - "integrity": "sha512-TlbnWAOoCuG2PgY0Hi3BGU1w2IXs3xDsD4E8WDfKRZUn2qx3wRA9mbYnmpWHPswTJCz2L+ebh+9OvD42sV4mNw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.3.tgz", + "integrity": "sha512-lLPWnakjC0q9z+OtiXk+9RPQiYPNAovt2IXD3CP4LkOnd9NpUsxOjMx1SnoUVB7Orb7fZp67cQMtTBKMFDvOGg==", "license": "Apache-2.0", "dependencies": { - "@smithy/service-error-classification": "^4.2.2", - "@smithy/types": "^4.7.1", + "@smithy/service-error-classification": "^4.2.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -2909,14 +2908,14 @@ } }, "node_modules/@smithy/util-stream": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.2.tgz", - "integrity": "sha512-RWYVuQVKtNbr7E0IxV8XHDId714yHPTxU6dHScd6wSMWAXboErzTG7+xqcL+K3r0Xg0cZSlfuNhl1J0rzMLSSw==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.4.tgz", + "integrity": "sha512-+qDxSkiErejw1BAIXUFBSfM5xh3arbz1MmxlbMCKanDDZtVEQ7PSKW9FQS0Vud1eI/kYn0oCTVKyNzRlq+9MUw==", "license": "Apache-2.0", "dependencies": { - "@smithy/fetch-http-handler": "^5.3.3", - "@smithy/node-http-handler": "^4.4.1", - "@smithy/types": "^4.7.1", + "@smithy/fetch-http-handler": "^5.3.4", + "@smithy/node-http-handler": "^4.4.3", + "@smithy/types": "^4.8.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", @@ -3837,9 +3836,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", - "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.1.tgz", + "integrity": "sha512-hU4EGxxt+j7TQijx1oYdAjw4xuIp1wRQSsbMFwSthCWeBQur1eF+qJ5iQ5sN3Tw8YRzQNKb8jszgBdMDVqwJcw==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -4031,9 +4030,9 @@ } }, "node_modules/bullmq": { - "version": "5.61.0", - "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.61.0.tgz", - "integrity": "sha512-khaTjc1JnzaYFl4FrUtsSsqugAW/urRrcZ9Q0ZE+REAw8W+gkHFqxbGlutOu6q7j7n91wibVaaNlOUMdiEvoSQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.62.0.tgz", + "integrity": "sha512-Q+UwvZs53FeYeJgkGuhtnUBh+rgvi4kvoLiCLBcc36ukB1UvE3/Lw5jx7rDCEgTMWSSyUClpnGpP+B8lGE64GQ==", "license": "MIT", "dependencies": { "cron-parser": "^4.9.0", @@ -4315,9 +4314,9 @@ } }, "node_modules/cloudinary": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-2.7.0.tgz", - "integrity": "sha512-qrqDn31+qkMCzKu1GfRpzPNAO86jchcNwEHCUiqvPHNSFqu7FTNF9FuAkBUyvM1CFFgFPu64NT0DyeREwLwK0w==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-2.8.0.tgz", + "integrity": "sha512-s7frvR0HnQXeJsQSIsbLa/I09IMb1lOnVLEDH5b5E53WTiCYgrNNOBGV/i/nLHwrcEOUkqjfSwP1+enXWNYmdw==", "license": "MIT", "dependencies": { "lodash": "^4.17.21", @@ -4813,17 +4812,17 @@ } }, "node_modules/dd-trace": { - "version": "5.72.0", - "resolved": "https://registry.npmjs.org/dd-trace/-/dd-trace-5.72.0.tgz", - "integrity": "sha512-3lH4RIJqzpjIvEISkbDBqPB7M4XDwrcj3r4zcF0LXgKYdyzU/Ebo/8uy+0XWaQBqj2kYERDw2lpJVLb0AbzNdw==", + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/dd-trace/-/dd-trace-5.74.0.tgz", + "integrity": "sha512-BeQiMDsl07EjQjX2y+klz4fuTRXRLQidH4WdtGUtLcww6W5W0TmY5PD0ZYqUZ8df9+mMsQ57fseh7hSoTDR3vw==", "hasInstallScript": true, "license": "(Apache-2.0 OR BSD-3-Clause)", "dependencies": { "@datadog/libdatadog": "0.7.0", - "@datadog/native-appsec": "10.2.1", + "@datadog/native-appsec": "10.3.0", "@datadog/native-iast-taint-tracking": "4.0.0", "@datadog/native-metrics": "3.1.1", - "@datadog/openfeature-node-server": "0.1.0-preview.10", + "@datadog/openfeature-node-server": "0.1.0-preview.12", "@datadog/pprof": "5.11.1", "@datadog/sketches-js": "2.1.1", "@datadog/wasm-js-rewriter": "4.0.1", @@ -4861,7 +4860,7 @@ }, "peerDependencies": { "@openfeature/core": "^1.9.0", - "@openfeature/server-sdk": "~1.18.0" + "@openfeature/server-sdk": "~1.20.0" }, "peerDependenciesMeta": { "@openfeature/core": { @@ -7006,9 +7005,9 @@ } }, "node_modules/ioredis": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.8.1.tgz", - "integrity": "sha512-Qho8TgIamqEPdgiMadJwzRMW3TudIg6vpg4YONokGDudy4eqRIJtDbVX72pfLBcWxvbn3qm/40TyGUObdW4tLQ==", + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.8.2.tgz", + "integrity": "sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q==", "license": "MIT", "dependencies": { "@ioredis/commands": "1.4.0", @@ -7538,9 +7537,9 @@ } }, "node_modules/json-2-csv": { - "version": "5.5.9", - "resolved": "https://registry.npmjs.org/json-2-csv/-/json-2-csv-5.5.9.tgz", - "integrity": "sha512-l4g6GZVHrsN+5SKkpOmGNSvho+saDZwXzj/xmcO0lJAgklzwsiqy70HS5tA9djcRvBEybZ9IF6R1MDFTEsaOGQ==", + "version": "5.5.10", + "resolved": "https://registry.npmjs.org/json-2-csv/-/json-2-csv-5.5.10.tgz", + "integrity": "sha512-Dep8wO3Fr5wNjQevO2Z8Y7yeee/nYSGRsi7q6zJDKEVHxXkXT+v21vxHmDX923UzmCXXkSo62HaTz6eTWzFLaw==", "license": "MIT", "dependencies": { "deeks": "3.1.0", @@ -9914,9 +9913,9 @@ } }, "node_modules/soap": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/soap/-/soap-1.5.0.tgz", - "integrity": "sha512-cT3+rKhABIkR7VkG0rtVlctQgBiKflq66jIRvpfiSxPph0Kx/pXhRWmGpvQ22crvswOhVypU/Idr88xjD15gWA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/soap/-/soap-1.6.0.tgz", + "integrity": "sha512-koOlNMAONSSVP38WakXEWz3WaYFupJJ08eicwrIvQsv9k2Qwz5JLLS6COqJVpIVCwffcqf8InMs+NYPw1bLOjA==", "license": "MIT", "dependencies": { "axios": "^1.12.2", @@ -10762,9 +10761,9 @@ "license": "Unlicense" }, "node_modules/twilio": { - "version": "5.10.3", - "resolved": "https://registry.npmjs.org/twilio/-/twilio-5.10.3.tgz", - "integrity": "sha512-msve3uADprpG+LRlthOxBUJWZDczGe+mdzotG7Wluaf8nn8fSIK0n2fX3INR26Xedeea/azmAdLK0c2rJhIHpQ==", + "version": "5.10.4", + "resolved": "https://registry.npmjs.org/twilio/-/twilio-5.10.4.tgz", + "integrity": "sha512-5dUsT3/O1+WxyJop2a6a4r92NAgtEQL7+oSU4t466NPhDaPOOBH/uomxnYHD5GWouYo7CZ/B7XSOwlhEUAHpWg==", "license": "MIT", "dependencies": { "axios": "^1.12.0", diff --git a/package.json b/package.json index 1af924f81..3d3cb8ae1 100644 --- a/package.json +++ b/package.json @@ -18,30 +18,30 @@ "job-totals-fixtures:local": "docker exec node-app /usr/bin/node /app/download-job-totals-fixtures.js" }, "dependencies": { - "@aws-sdk/client-cloudwatch-logs": "^3.913.0", - "@aws-sdk/client-elasticache": "^3.913.0", - "@aws-sdk/client-s3": "^3.913.0", - "@aws-sdk/client-secrets-manager": "^3.913.0", - "@aws-sdk/client-ses": "^3.913.0", - "@aws-sdk/credential-provider-node": "^3.913.0", - "@aws-sdk/lib-storage": "^3.913.0", - "@aws-sdk/s3-request-presigner": "^3.913.0", + "@aws-sdk/client-cloudwatch-logs": "^3.919.0", + "@aws-sdk/client-elasticache": "^3.919.0", + "@aws-sdk/client-s3": "^3.919.0", + "@aws-sdk/client-secrets-manager": "^3.919.0", + "@aws-sdk/client-ses": "^3.919.0", + "@aws-sdk/credential-provider-node": "^3.919.0", + "@aws-sdk/lib-storage": "^3.919.0", + "@aws-sdk/s3-request-presigner": "^3.919.0", "@opensearch-project/opensearch": "^2.13.0", "@socket.io/admin-ui": "^0.5.1", "@socket.io/redis-adapter": "^8.3.0", "archiver": "^7.0.1", "aws4": "^1.13.2", - "axios": "^1.12.2", + "axios": "^1.13.1", "axios-curlirize": "^2.0.0", "better-queue": "^3.8.12", - "bullmq": "^5.61.0", + "bullmq": "^5.62.0", "chart.js": "^4.5.1", - "cloudinary": "^2.7.0", + "cloudinary": "^2.8.0", "compression": "^1.8.1", "cookie-parser": "^1.4.7", "cors": "^2.8.5", "crisp-status-reporter": "^1.2.2", - "dd-trace": "^5.72.0", + "dd-trace": "^5.74.0", "dinero.js": "^1.9.1", "dotenv": "^17.2.3", "express": "^4.21.1", @@ -50,8 +50,8 @@ "graphql": "^16.11.0", "graphql-request": "^6.1.0", "intuit-oauth": "^4.2.1", - "ioredis": "^5.8.1", - "json-2-csv": "^5.5.9", + "ioredis": "^5.8.2", + "json-2-csv": "^5.5.10", "jsonwebtoken": "^9.0.2", "juice": "^11.0.3", "lodash": "^4.17.21", @@ -66,11 +66,11 @@ "recursive-diff": "^1.0.9", "rimraf": "^6.0.1", "skia-canvas": "^3.0.8", - "soap": "^1.5.0", + "soap": "^1.6.0", "socket.io": "^4.8.1", "socket.io-adapter": "^2.5.5", "ssh2-sftp-client": "^11.0.0", - "twilio": "^5.10.3", + "twilio": "^5.10.4", "uuid": "^11.1.0", "winston": "^3.18.3", "winston-cloudwatch": "^6.3.0", diff --git a/server.js b/server.js index 4a79c234e..b96eff093 100644 --- a/server.js +++ b/server.js @@ -123,7 +123,7 @@ const applyRoutes = ({ app }) => { app.use("/payroll", require("./server/routes/payrollRoutes")); app.use("/sso", require("./server/routes/ssoRoutes")); app.use("/integrations", require("./server/routes/intergrationRoutes")); - app.use("/rr", require("./server/rr/rrRoutes")); + app.use("/rr", require("./server/rr")); // Default route for forbidden access app.get("/", (req, res) => { diff --git a/server/rr/index.js b/server/rr/index.js new file mode 100644 index 000000000..3853ca4dc --- /dev/null +++ b/server/rr/index.js @@ -0,0 +1 @@ +module.exports = require("./rrRoutes"); diff --git a/server/rr/lib/index.cjs b/server/rr/lib/index.cjs new file mode 100644 index 000000000..a77ec9741 --- /dev/null +++ b/server/rr/lib/index.cjs @@ -0,0 +1 @@ +"use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function t({routing:e={},sender:t={},creationDateTime:r,bodId:n}={}){const o={Sender:{Component:t.component??"Rome",Task:t.task??"CU",ReferenceId:t.referenceId??"Query",CreatorNameCode:t.creator??"RCI",SenderNameCode:t.senderName??"RCI"},CreationDateTime:r??(new Date).toISOString().replace(/\.\d{3}Z$/,"Z"),BODId:n??E.v4(),Destination:{DestinationNameCode:"RR",DealerNumber:e.dealerNumber||"",StoreNumber:e.storeNumber||"",AreaNumber:e.areaNumber||""}},a={bod:"{{#BODId}}{{BODId}}{{/BODId}}",creation:"{{CreationDateTime}}",sender:"\n \n {{Sender.Component}}\n {{Sender.Task}}\n {{#Sender.ReferenceId}}{{Sender.ReferenceId}}{{/Sender.ReferenceId}}\n {{#Sender.CreatorNameCode}}{{Sender.CreatorNameCode}}{{/Sender.CreatorNameCode}}\n {{#Sender.SenderNameCode}}{{Sender.SenderNameCode}}{{/Sender.SenderNameCode}}\n ".trim(),dest:"\n \n {{Destination.DestinationNameCode}}\n {{#Destination.DealerNumber}}{{Destination.DealerNumber}}{{/Destination.DealerNumber}}\n {{#Destination.StoreNumber}}{{Destination.StoreNumber}}{{/Destination.StoreNumber}}\n {{#Destination.AreaNumber}}{{Destination.AreaNumber}}{{/Destination.AreaNumber}}\n ".trim()},s=`\n${["bod","creation","sender","dest"].map(e=>a[e]).join("\n")}\n`;return j.default.render(s,o).trim()}function r(e,t=2){const r=" ".repeat(t);return String(e).split("\n").map(e=>e.length?r+e:e).join("\n")}function n(e){return String(e??"").replace(/&/g,"&").replace(//g,">")}function o(e,t){if(null==e)return null;if(Array.isArray(e)){for(const r of e){const e=o(r,t);if(null!=e)return e}return null}if("object"!=typeof e)return null;for(const[r,n]of Object.entries(e)){if(t(r,n))return n;const e=o(n,t);if(null!=e)return e}return null}function a(e,t,r=[]){if(null==e)return r;if(Array.isArray(e)){for(const n of e)a(n,t,r);return r}if("object"!=typeof e)return r;for(const[n,o]of Object.entries(e))t(n,o)&&r.push(o),a(o,t,r);return r}function s(e){return null==e?[]:Array.isArray(e)?e:[e]}function i(e,t){if(e&&"object"==typeof e)return function(e){if(null!=e)return"string"==typeof e||"number"==typeof e||"boolean"==typeof e?String(e):"object"==typeof e&&"#text"in e?String(e["#text"]):void 0}(e[t])}function l(e,t){const r=i(e,t);if(Q(r))return r;const n=function(e,t){if(e&&"object"==typeof e)return e.$&&Q(e.$[t])?e.$[t]:Q(e[`@_${t}`])?e[`@_${t}`]:Q(e[`@${t}`])?e[`@${t}`]:e._attributes&&Q(e._attributes[t])?e._attributes[t]:e.attributes&&Q(e.attributes[t])?e.attributes[t]:void 0}(e,t);return Q(n)?n:void 0}function c(e,t){if(e&&"object"==typeof e)return null!=e[`@_${t}`]?e[`@_${t}`]:void 0}function m(e){if(null!=e){if("string"==typeof e)return e;if("number"==typeof e)return String(e);if("object"==typeof e){if(null!=e._)return String(e._);if(null!=e["#text"])return String(e["#text"]);if(null!=e.text)return String(e.text)}}}function u(e){return a(e,e=>/(GenTransStatus|TransStatus)$/i.test(e)).flatMap(s)[0]}function p(e){if(e)return{status:(c(e,"Status")||e.Status||m(e)||"").toString().trim()||void 0,statusCode:(c(e,"StatusCode")||e.StatusCode||"").toString().trim()||void 0,message:e.Message&&m(e.Message)||e.GenTransStatus&&m(e.GenTransStatus)||e.TransStatus&&m(e.TransStatus)||m(e)||void 0}}function d(e){if(e)return{status:(c(e,"Status")||e.Status||m(e)||"").toString().trim()||void 0,date:(c(e,"Date")||e.Date||"").toString().trim()||void 0,time:(c(e,"Time")||e.Time||"").toString().trim()||void 0,outsdRoNo:(c(e,"OutsdRoNo")||e.OutsdRoNo||"").toString().trim()||void 0,dmsRoNo:(c(e,"DMSRoNo")||e.DMSRoNo||"").toString().trim()||void 0,errorMessage:(c(e,"ErrorMessage")||e.ErrorMessage||"").toString().trim()||void 0}}function y(e){return s((e?.rey_RomeCustServVehComb??e??{}).CustServVehComb).map(e=>{const t=e?.NameContactId??void 0,r=t?.NameId??void 0,n=r?.IndName?H(r.IndName):void 0,o=r?.BusName?H(r.BusName):void 0,a=t&&{NameId:r&&{...H(r)||{},...n?{IndName:n}:{},...o?{BusName:o}:{}},Address:s(t?.Address).map(e=>H(e)||{}),ContactOptions:s(t?.ContactOptions).map(e=>H(e)||{}),Phone:s(t?.Phone).map(e=>H(e)||{}),Email:s(t?.Email).map(e=>H(e)||{})},i=s(e?.ServVehicle).map(e=>{const t=e?.Vehicle,r=t?.VehicleDetail,n=t&&{...H(t)||{},...r?{VehicleDetail:H(r)}:{}},o=e?.VehicleServInfo,a=o?.VehExtWarranty,i=o?.Advisor,l=i?.ContactInfo,c=o&&{...H(o)||{},...a?{VehExtWarranty:H(a)}:{},...i?{Advisor:l?{ContactInfo:H(l)||{}}:{Advisor:{}}}:{},...e?.VehicleServInfo?.VehServComments?{VehServComments:s(e.VehicleServInfo.VehServComments).map(e=>Y(e))}:{}};return{...n?{Vehicle:n}:{},...c?{VehicleServInfo:c}:{}}}),l=s(e?.Message).map(e=>({...H(e)||{},Text:Y(e)})),c={};return a&&(c.NameContactId=a),i.length&&(c.ServVehicle=i),l.length&&(c.Message=l),c})}function g(e,t){if(null!=e)return String("string"==typeof e||"number"==typeof e?e:e[t]||"")}function N(e,...t){if(e)for(const r of t){if(e.$&&null!=e.$[r])return e.$[r];if(null!=e[`@_${r}`])return e[`@_${r}`];if(null!=e[r]&&"object"!=typeof e[r])return e[r]}}function T(e){const t=function(e){const t=o(e,e=>"rey_RomeCustomerResponse"===e||e.endsWith(":rey_RomeCustomerResponse"));return t?a(t,e=>"TransStatus"===e||e.endsWith(":TransStatus")).flatMap(s)[0]:void console.log("No rey_RomeCustomerResponse found in root")}(e);if(!t)return{dmsRecKey:void 0};const r=N(t,"DMSRecKey");return{dmsRecKey:null!=r?String(r):void 0,status:N(t,"Status"),statusCode:N(t,"StatusCode")}}function b(e){if(null==e)return;const t=String(e).toUpperCase().replace(/[^A-Z0-9 ]+/g,"");if(!t)throw new k(`Invalid string: ${e}. Must contain A-Z, 0-9, or space`);return t}function x(e){return e?String(e).toUpperCase():void 0}function C(e={}){const t=x(e.ibFlag)||(e.firstName?"I":"B");if("I"!==t&&"B"!==t)throw new k("ibFlag must be 'I' or 'B'");const r=e.lastName||e.customerName;if(!r)throw new k("lastName or customerName required");if("I"===t&&!e.firstName)throw new k("firstName required when ibFlag='I'");const n=x(e.customerType);if(n&&!["R","W","I"].includes(n))throw new k("customerType must be 'R', 'W', 'I', Retail, Wholesale, or Internal");const o=(e.addresses||[]).map(e=>{const t={Type:x(e.type)||"P",Addr1:e.line1?String(e.line1):void 0,Addr2:e.line2?String(e.line2):void 0,City:e.city?String(e.city):void 0,State:e.state?String(e.state):void 0,Zip:e.postalCode?String(e.postalCode):void 0,County:e.county?String(e.county):void 0,Country:e.country?String(e.country):void 0};if(!t.Addr1)throw new k("Address requires line1");return t}),a=(e.phones||[]).map(e=>{const t={Type:x(e.type)||"H",Num:e.number?String(e.number):void 0,Ext:e.extension?String(e.extension):void 0};if(!t.Num)throw new k("Phone requires number");return t}),s=e.emails?.[0]?.address?{MailTo:String(e.emails[0].address)}:void 0,i=e.personal,l=i?{Gender:x(i.gender),OtherName:b(i.otherName),AnniversaryDate:i.anniversaryDate?String(i.anniversaryDate):void 0,EmployerName:b(i.employerName),EmployerPhone:i.employerPhone?String(i.employerPhone):void 0,Occupation:b(i.occupation),OptOut:i.optOut?String(i.optOut):void 0,OptOutUse:i.optOutUse?String(i.optOutUse):void 0,BirthDates:(i.birthDates||[]).map(e=>({Type:x(e.type)||"P",date:e.date?String(e.date):void 0})).filter(e=>e.date),SSNs:(i.ssns||[]).map(e=>({Type:x(e.type)||"P",ssn:e.ssn?String(e.ssn):void 0})).filter(e=>e.ssn),DriverInfo:i.driver?[{Type:x(i.driver.type)||"P",LicNum:i.driver.licenseNumber?String(i.driver.licenseNumber):void 0,LicState:i.driver.licenseState?String(i.driver.licenseState):void 0,LicExpDate:i.driver.licenseExpDate?String(i.driver.licenseExpDate):void 0}].filter(e=>e.LicNum):void 0,CustChildren:(i.children||[]).map(e=>({ChildName:b(e.name)})).filter(e=>e.ChildName)}:void 0,c=e.dms,m=c?{TaxExemptNum:c.taxExemptNum?String(c.taxExemptNum):void 0,SalesTerritory:c.salesTerritory?String(c.salesTerritory):void 0,DeliveryRoute:c.deliveryRoute?String(c.deliveryRoute):void 0,SalesmanNum:c.salesmanNum?String(c.salesmanNum):void 0,LastContactMethod:c.lastContactMethod?String(c.lastContactMethod):void 0,Followups:(c.followups||[]).map(e=>({Type:x(e.type),Value:x(e.value)})).filter(e=>e.Type&&e.Value)}:void 0;return{custCateg:n||"R",createdBy:e.createdBy?String(e.createdBy):void 0,contactInfo:{IBFlag:t,LastName:b(r),FirstName:b(e.firstName),MidName:b(e.midName),Salut:b(e.salut),Suffix:b(e.suffix),Addresses:o,Phones:a,Email:s},custPersonal:l,dmsCustInfo:m}}function f(e){const t=o(e,e=>"rey_RomeServVehicleInsertResponse"===e||e.endsWith(":rey_RomeServVehicleInsertResponse"))||e,r=o(t,e=>"GenTransStatus"===e||e.endsWith(":GenTransStatus"));return{status:r?l(r,"Status"):void 0,statusCode:r?l(r,"StatusCode"):void 0}}function R(e,t){const r=Array.isArray(t)?t.map(e=>e.toLowerCase()):[String(t).toLowerCase()],n=[e];for(;n.length;){const e=n.pop();if(Z(e))for(const t of Object.keys(e)){const o=e[t],a=X(t).toLowerCase();if(r.includes(a))return o;if(Z(o))n.push(o);else if(Array.isArray(o))for(const e of o)Z(e)&&n.push(e)}}}function S(e,t){if(e&&Z(e)){if(null!=e.$?.[t])return e.$[t];if(null!=e[`@${t}`])return e[`@${t}`];if(null!=e[`@_${t}`])return e[`@_${t}`]}}function v(e){if(null!=e){if("string"==typeof e)return e;if("number"==typeof e)return String(e);if(Z(e)){if(null!=e._)return String(e._);if(null!=e["#text"])return String(e["#text"]);if(null!=e.text)return String(e.text)}}}function O(e){const t=R(e,["CreateBSMRepairOrderResp","UpdateBSMRepairOrderResp"])||e,r=R(t,"RoRecordStatus")||{};return{status:S(r,"Status")||v(R(r,"Status")),date:S(r,"Date")||v(R(r,"Date")),time:S(r,"Time")||v(R(r,"Time")),outsdRoNo:S(r,"OutsdRoNo")||v(R(r,"OutsdRoNo")),dmsRoNo:S(r,"DMSRoNo")||v(R(r,"DMSRoNo")),errorMessage:S(r,"ErrorMessage")||v(R(r,"ErrorMessage"))}}function F(e={},r={}){const n=function(e){if(!e)throw new Error("department is required (S, P, B, SERVICE, PARTS, BODY)");const t=String(e).trim().toUpperCase();if("S"===t||"P"===t||"B"===t)return t;if("SERVICE"===t)return"S";if("PART"===t||"PARTS"===t)return"P";if("BODY"===t||"BODYSHOP"===t||"BODY SHOP"===t)return"B";throw new Error(`Invalid department: ${e}. Must be S, P, B, SERVICE, PARTS, BODY, BODYSHOP, or BODY SHOP`)}(e.department),o=e.advisorNumber?String(e.advisorNumber).trim():void 0,a=t({routing:r.routing,sender:r?.envelope?.sender,creationDateTime:r?.envelope?.creationDateTime,bodId:r?.envelope?.bodId});return{starXml:j.default.render('\n\n {{{ApplicationArea}}}\n \n \n \n\n',{ApplicationArea:a,DepartmentType:n,AdvisorNumber:o}),routing:r.routing,envelope:r.envelope,xsdFilename:"rey_RomeGetAdvisorsReq.xsd",elementName:"rey_RomeGetAdvisorsReq",postParse:e=>function(e,t={}){const r=t?.department;var n;return(e=>{const t=e?.Advisor;return t?Array.isArray(t)?t:[t]:[]})((n=e,n?.rey_RomeGetAdvisorsResp??n??{})).map(e=>({advisorId:J(e,"AdvisorNumber"),firstName:J(e,"FirstName"),lastName:J(e,"LastName"),department:r}))}(e,{department:n})}}function I(e){return null==e?void 0:String(e)}function h(e,t){if(e)return null!=e[t]?"object"!=typeof e[t]?I(e[t]):I(e[t]["#text"]):null!=e[`@_${t}`]?I(e[`@_${t}`]):void 0}function w(e){const t=e?.meta?.statusBlocks?.transaction?.message;if(t)return String(t);return String((e?.meta?.status?.Message??e?.meta?.status?.message)||e?.message||"")}function P(e,t){return Math.min(1e4,e*Math.pow(2,t))}function D(e){return e+Math.floor(250*Math.random())}function A(e){return new Promise(t=>setTimeout(t,e))}function M(e){return/lock|in use|record.*busy/i.test(String(e||""))}Object.defineProperty(exports,"__esModule",{value:!0});const V=require("mustache"),E=require("uuid"),L=require("axios"),_=require("fast-xml-parser"),j=e(V),B=e(L);class q extends Error{constructor(e,t={}){super(e),this.name="RRTransportError",this.meta=t}}class U extends Error{constructor(e,t={}){super(e),this.name="RRVendorStatusError",this.meta=t,this.retryable=!!t.retryable}}class k extends Error{constructor(e,t={}){super(e),this.name="RRValidationError",this.meta=t}}const G=Object.freeze({__proto__:null,RRTransportError:q,RRVendorStatusError:U,RRValidationError:k}),$={info:(...e)=>console.log("[rr-rome]",...e),warn:(...e)=>console.warn("[rr-rome]",...e),error:(...e)=>console.error("[rr-rome]",...e),debug:(...e)=>{process.env.RR_DEBUG&&console.log("[rr-rome][debug]",...e)}},Q=e=>null!=e&&""!==String(e).trim(),W=new _.XMLParser({ignoreAttributes:!1,attributeNamePrefix:"@_",parseAttributeValue:!1,parseTagValue:!1,isArray:e=>["Advisor"].includes(e)}),H=e=>{if(!e||"object"!=typeof e)return;const t={};for(const[r,n]of Object.entries(e))r.startsWith("@_")&&(t[r.slice(2)]=n);return Object.keys(t).length?t:void 0},Y=e=>{if(null!=e)return"string"==typeof e?e:e["#text"]},X=e=>{if("string"!=typeof e)return"";let t=e.includes("}")?e.split("}").pop():e;return t=t.includes(":")?t.split(":").pop():t,t.startsWith("rey_")&&(t=t.slice(4)),t},Z=e=>e&&"object"==typeof e&&!Array.isArray(e),J=(e,t)=>((e,t)=>e?.[`@_${t}`])(e,t)??i(e,t);exports.RRClient=class{constructor(e){if(!e?.baseUrl)throw new Error("RRClient requires baseUrl");if(!e?.username)throw new Error("RRClient requires username");if(!e?.password)throw new Error("RRClient requires password");this.cfg={wssePasswordType:"Text",timeoutMs:3e4,logger:$,retries:{max:3},...e},this.mask={password:!0}}async _send(e){const{starXml:t,routing:o,envelope:i,postParse:l}=e,y=this.cfg.logger||$,{bodId:g,creationDateTime:N,sender:T}=function(e){return{bodId:e?.bodId||E.v4(),creationDateTime:e?.creationDateTime||new Date,sender:e?.sender||{}}}(i),b=function({username:e,password:t,wssePasswordType:o="Text",starContentXml:a}){const s=function(e){return`\n \n \n \n${r(e,10)}\n \n \n \n `.trim()}(a);return`\n \n \n${r(function(e,t,r){const o="Digest"===r?' Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"':' Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"';return`\n \n \n ${n(e)}\n ${n(t)}\n \n \n `.trim()}(e,t,o),8)}\n \n \n${r(s,8)}\n \n \n `.trim()}({username:this.cfg.username,password:this.cfg.password,wssePasswordType:this.cfg.wssePasswordType||"Text",routing:o,sender:T,creationDateTime:(x=N,"string"==typeof x?x:(x instanceof Date?x:new Date).toISOString().replace(/\.\d{3}Z$/,"Z")),bodId:g,starContentXml:t});var x;"1"===process.env.RR_DUMP_ENVELOPE&&console.log(`[rr] Soap envelope about to send (${e?.elementName}): \n`+b+"\n");const C=async()=>{const t=await async function({baseUrl:e,envelopeXml:t,timeoutMs:r=3e4,logger:n}){try{const n=await B.default.post(e,t,{timeout:r,headers:{"Content-Type":"text/xml; charset=utf-8",SOAPAction:"http://www.starstandards.org/webservices/2005/10/transport/ProcessMessage"},responseType:"text",validateStatus:()=>!0});if(n.status>=200&&n.status<300)return String(n.data??"");throw new q(`HTTP ${n.status}: ${function(e){const t=String(e??"");return t.length>1024?t.slice(0,1024)+"…":t}(n.data)}`,{status:n.status,body:n.data})}catch(e){if(B.default.isAxiosError(e))throw new q(`Network error: ${e.message}`,{cause:e});throw e}}({baseUrl:this.cfg.baseUrl,envelopeXml:b,timeoutMs:this.cfg.timeoutMs,logger:y}),r=function(e){const t=W.parse(e),r=t?.Envelope||t?.["soapenv:Envelope"]||t,n=r?.Body||r?.["soapenv:Body"]||r?.["S:Body"]||r?.["soap:Body"],o=n?.ProcessMessageResponse||n?.["ns2:ProcessMessageResponse"]||n?.["trans:ProcessMessageResponse"]||n,a=o?.payload||o?.["ns2:payload"]||o;return a?.content||a?.["ns2:content"]||a}(t),n=function(e){const t=u(e),r=a(e,e=>/RoRecordStatus$/i.test(e)).flatMap(s)[0];return{transaction:p(t),roRecord:d(r)}}(r),o=function(e){const t=String("ApplicationArea").toLowerCase(),r=[e];for(;r.length;){const e=r.pop();if(e&&"object"==typeof e)for(const[n,o]of Object.entries(e)){if(n.toLowerCase().endsWith(t))return o;o&&"object"==typeof o&&r.push(o)}}}(r),{status:i,norm:g}=function(e){const t=u(e)||a(e,e=>/Status$/i.test(e)).flatMap(s)[0]||{},r=(c(t,"Status")||t.Status||"").toString().trim();let n=(c(t,"StatusCode")||t.StatusCode||"").toString().trim();const o=t.Message&&m(t.Message)||m(t)||"";!n&&/success/i.test(r)&&(n="0");const i=Number(n);let l="FAIL";return/success/i.test(r)||0===i?l="SUCCESS":2!==i&&213!==i||(l="NO_MATCH"),{status:{Status:r,StatusCode:n,Message:o},norm:{kind:l,code:Number.isFinite(i)?i:void 0,message:o}}}(r);if("1"===process.env.RR_DUMP_STATUS&&(console.log("[rr] Status blocks:"),console.dir(n,{depth:null,colors:!0})),"1"===process.env.RR_DUMP_APPLICATION&&(console.log("[rr] ApplicationArea:"),console.dir(o,{depth:null,colors:!0})),"FAIL"===g.kind){const e=i?.StatusCode;throw new U(`Vendor status failure: ${e??""} ${i?.Message||i?.["#text"]||""}`.trim(),{status:i,resXml:t})}const N={success:"SUCCESS"===g.kind||"NO_MATCH"===g.kind,statusBlocks:n,applicationArea:o,xml:{request:b,response:t},parsed:r};if("function"==typeof l)try{N.data=l(r)}catch(e){y?.warn?.(`postParse failed: ${e?.message||e}`)}return"1"===process.env.RR_DUMP_XML&&console.log(`[rr] Full response XML (${e?.elementName}):\n`+t+"\n"),N?.data&&"1"===process.env.RR_DUMP_DATA&&(console.log(`[rr] Parsed response data (${e?.elementName}):\n`),console.dir(N.data,{depth:null,colors:!0})),N};try{return await async function(e,{max:t=3,logger:r}){let n,o=0;for(;o=t)break;const s=D(P(400,o));r?.warn?.(`Retrying attempt ${o}/${t} in ${s}ms: ${e.message}`),await A(s)}throw n}(C,{max:this.cfg.retries?.max??3,logger:y})}catch(e){if(e instanceof q||e instanceof U)throw e;throw new q(`Unexpected error: ${e?.message||e}`,{cause:e})}}async combinedSearch(e,r){return this._send(function(e={},r={}){if(!e||"object"!=typeof e)throw new k("combinedSearch requires a query object");const n=function(e){if(!e)return"";const t=String(e).trim().toLowerCase();return"telephone"===t?"phone":"lic"===t||"plate"===t?"license":"vin"===t||"partvin"===t?"vin":"name"===t?"name":"nameRecId"===t||"custId"===t?"nameRecId":"stkNo"===t||"stock"===t?"stkNo":t}(e.kind),o={MaxRecs:Math.min(Number(e.maxResults||e.maxRecs||50),50)};if("phone"===n){const t=g(e.phone,"phone");if(!t)throw new k("combinedSearch phone value missing");o.Phone=t}else if("license"===n){const t=g(e.license,"license");if(!t)throw new k("combinedSearch license value missing");o.LicenseNum=t}else if("vin"===n){const t=g(e.vin,"vin");if(!t)throw new k("combinedSearch vin value missing");o.PartVIN=t}else if("name"===n){const t=e.name;if(!t||"object"!=typeof t)throw new k("combinedSearch name requires { fname, lname, mname } or { name }");if(t.fname&&t.lname&&t.mname)o.FullName={FName:String(t.fname),LName:String(t.lname),MName:String(t.mname)};else{if(!t.name)throw new k("combinedSearch name requires { fname, lname, mname } or { name }");o.LName=String(t.name)}}else if("nameRecId"===n){const t=g(e.nameRecId,"custId");if(!t)throw new k("combinedSearch nameRecId value missing");o.NameRecId=t}else{if("stkNo"!==n)throw new k(`Unsupported CombinedSearch kind: ${e.kind}`);{const t=g(e.stkNo,"stkNo");if(!t)throw new k("combinedSearch stkNo value missing");o.StkNo=t}}if(1!==[o.Phone,o.LicenseNum,o.PartVIN,o.LName,o.FullName,o.NameRecId,o.StkNo].filter(Boolean).length)throw new k("combinedSearch requires exactly one search criterion");o.VehData={MakePfx:e.make||"ANY",Model:e.model||"ANY",Year:e.year||"ANY"};const a=t({routing:r.routing,sender:{component:"Rome",task:"CVC",referenceId:"Query",creator:"RCI",senderName:"RCI"},order:"creation-bod-sender-destination"});return{starXml:j.default.render('\n\n {{{ApplicationArea}}}\n \n \n {{#Phone}}{{/Phone}}\n {{#PartVIN}}{{/PartVIN}}\n {{#LicenseNum}}{{/LicenseNum}}\n {{#LName}}{{/LName}}\n {{#FullName}}{{/FullName}}\n {{#NameRecId}}{{/NameRecId}}\n {{#StkNo}}{{/StkNo}}\n \n \n \n\n',{ApplicationArea:a,...o}),routing:r.routing,envelope:r.envelope,elementName:"rey_RomeCustServVehCombReq",xsdFilename:"rey_RomeCustServVehCombReq.xsd",postParse:y}}(e,r))}async insertCustomer(e,r){return this._send(function(e,r){if(!r?.routing?.dealerNumber)throw new k("routing.dealerNumber required");const n=C(e),o=t({routing:r.routing,sender:{component:"Rome",task:"CU",referenceId:"Insert"},order:"sender-creation-bod-destination"});return{starXml:j.default.render('\n\n {{{ApplicationArea}}}\n \n \n {{#C.contactInfo.Addresses}}\n \n {{/C.contactInfo.Addresses}}\n {{#C.contactInfo.Phones}}\n \n {{/C.contactInfo.Phones}}\n {{#C.contactInfo.Email}}\n \n {{/C.contactInfo.Email}}\n \n {{#C.custPersonal}}\n \n {{#BirthDates}}\n \n {{/BirthDates}}\n {{#SSNs}}\n \n {{/SSNs}}\n {{#DriverInfo}}\n \n {{/DriverInfo}}\n {{#CustChildren}}\n \n {{/CustChildren}}\n \n {{/C.custPersonal}}\n {{#C.dmsCustInfo}}\n \n {{#Followups}}\n \n {{/Followups}}\n \n {{/C.dmsCustInfo}}\n \n\n',{ApplicationArea:o,C:n}),routing:r.routing,envelope:r.envelope,postParse:T,xsdFilename:"rey_RomeCustomerInsertReq.xsd",elementName:"rey_RomeCustomerInsertReq"}}(e,r))}async updateCustomer(e,r){return this._send(function(e,r){if(!r?.routing?.dealerNumber)throw new k("routing.dealerNumber required");if(!e.nameRecId)throw new k("nameRecId or customerId required");const n=x(e.ibFlag);if("I"!==n&&"B"!==n)throw new k("ibFlag required ('I' or 'B')");const o=C(e);o.contactInfo.NameRecId=String(e.nameRecId);const a=t({routing:r.routing,sender:{component:"Rome",task:"CU",referenceId:"Update"},order:"sender-creation-bod-destination"});return{starXml:j.default.render('\n\n {{{ApplicationArea}}}\n \n \n {{#C.contactInfo.Addresses}}\n \n {{/C.contactInfo.Addresses}}\n {{#C.contactInfo.Phones}}\n \n {{/C.contactInfo.Phones}}\n {{#C.contactInfo.Email}}\n \n {{/C.contactInfo.Email}}\n \n {{#C.custPersonal}}\n \n {{#BirthDates}}\n \n {{/BirthDates}}\n {{#SSNs}}\n \n {{/SSNs}}\n {{#DriverInfo}}\n \n {{/DriverInfo}}\n {{#CustChildren}}\n \n {{/CustChildren}}\n \n {{/C.custPersonal}}\n {{#C.dmsCustInfo}}\n \n {{#Followups}}\n \n {{/Followups}}\n \n {{/C.dmsCustInfo}}\n \n\n',{ApplicationArea:a,C:o}),routing:r.routing,envelope:r.envelope,postParse:T,xsdFilename:"rey_RomeCustomerUpdateReq.xsd",elementName:"rey_RomeCustomerUpdateReq"}}(e,r))}async insertServiceVehicle(e,r){return this._send(function(e={},r={}){if(!r?.routing?.dealerNumber)throw new k("routing.dealerNumber is required");const n=t({routing:r.routing,sender:r?.envelope?.sender??{component:"Rome",task:"SV",referenceId:"Insert"},creationDateTime:r?.envelope?.creationDateTime,bodId:r?.envelope?.bodId}),o=function(e={}){const t=e.vin;if(!t)throw new k("insertServiceVehicle: vin is required");const r=e.vehicleServInfo?.customerNo;if(!r)throw new k("insertServiceVehicle: vehicleServInfo.customerNo (or customerNo) is required");return{VIN:String(t),ModelDesc:e.modelDesc,Carline:e.carline,ExtClrDesc:e.extClrDesc,IntClrDesc:e.intClrDesc,TrimDesc:e.trimDesc,BodyStyle:e.bodyStyle,EngineDesc:e.engineDesc,TransDesc:e.transDesc,Year:e.year,Odometer:e.odometer,OdometerUnits:e.odometerUnits,LicNo:e.vehicleDetail?.licNo,CustomerNo:String(r),vehicleServInfo:{salesmanNo:e.vehicleServInfo?.salesmanNo,inServiceDate:e.vehicleServInfo?.inServiceDate,mileage:e.vehicleServInfo?.mileage,teamCode:e.vehicleServInfo?.teamCode,vehExtWarranty:(()=>{const t=e.vehicleServInfo?.vehExtWarranty;if(!t)return;const r={contractNumber:t.contractNumber,expirationDate:t.expirationDate,expirationMileage:t.expirationMileage};return Object.values(r).some(e=>null!=e&&""!==e)?r:void 0})(),advisor:(()=>{const t=e.vehicleServInfo?.advisor,r=t?.contactInfo?.nameRecId;return r?{contactInfo:{nameRecId:String(r)}}:void 0})()}}}(e);return{starXml:j.default.render('\n\n {{{ApplicationArea}}}\n\n \n {{#V.Year}}{{.}}{{/V.Year}}\n {{#V.Odometer}}{{.}}{{/V.Odometer}}\n {{#V.OdometerUnits}}{{.}}{{/V.OdometerUnits}}\n\n {{#V.LicNo}}{{/V.LicNo}}\n \n\n \n {{#V.vehicleServInfo.salesmanNo}}{{.}}{{/V.vehicleServInfo.salesmanNo}}\n {{#V.vehicleServInfo.inServiceDate}}{{.}}{{/V.vehicleServInfo.inServiceDate}}\n {{#V.vehicleServInfo.mileage}}{{.}}{{/V.vehicleServInfo.mileage}}\n {{#V.vehicleServInfo.teamCode}}{{.}}{{/V.vehicleServInfo.teamCode}}\n\n {{#V.vehicleServInfo.vehExtWarranty}}\n \n {{#contractNumber}}{{.}}{{/contractNumber}}\n {{#expirationDate}}{{.}}{{/expirationDate}}\n {{#expirationMileage}}{{.}}{{/expirationMileage}}\n \n {{/V.vehicleServInfo.vehExtWarranty}}\n\n {{#V.vehicleServInfo.advisor}}\n \n \n \n {{/V.vehicleServInfo.advisor}}\n \n\n',{ApplicationArea:n,V:o}),routing:r.routing,envelope:r.envelope,postParse:f,xsdFilename:"rey_RomeServVehicleInsertReq.xsd",elementName:"rey_RomeServVehicleInsertReq"}}(e,r))}async getAdvisors(e,t){return this._send(F(e,t))}async createRepairOrder(e,r){return this._send(function(e={},r={}){if(!r?.routing?.dealerNumber)throw new k("routing.dealerNumber required");if(!e?.customerNo)throw new k("customerNo (CustNo) required");if(!e?.departmentType)throw new k("departmentType (DeptType) required");if(!e?.vin)throw new k("vin (Vin) required");if(!e?.outsdRoNo)throw new k("outsdRoNo required");const n={customerNo:e.customerNo,advisorNo:e.advisorNo,tagNo:e.tagNo,outsdRoNo:e.outsdRoNo,departmentType:e.departmentType,vin:e.vin,mileageIn:e.mileageIn,roComment:e.roComment,estimate:e.estimate?{parts:e.estimate.parts,labor:e.estimate.labor,total:e.estimate.total}:void 0,tax:e.tax?{payType:e.tax.payType,taxCode:e.tax.taxCode,txblGrossAmt:e.tax.txblGrossAmt,grossTaxAmt:e.tax.grossTaxAmt}:void 0,rolabor:e.rolabor?{ops:e.rolabor.ops?.map(e=>({opCode:e.opCode,jobNo:e.jobNo,custPayTypeFlag:e.custPayTypeFlag,custTxblNtxblFlag:e.custTxblNtxblFlag,warrPayTypeFlag:e.warrPayTypeFlag,warrTxblNtxblFlag:e.warrTxblNtxblFlag,intrPayTypeFlag:e.intrPayTypeFlag,intrTxblNtxblFlag:e.intrTxblNtxblFlag,vlrCode:e.vlrCode,bill:e.bill?{payType:e.bill.payType,jobTotalHrs:e.bill.jobTotalHrs,billTime:e.bill.billTime,billRate:e.bill.billRate}:void 0,ccc:e.ccc?{cause:e.ccc.cause,complaint:e.ccc.complaint,correction:e.ccc.correction}:void 0,amount:e.amount?{payType:e.amount.payType,amtType:e.amount.amtType,custPrice:e.amount.custPrice,totalAmt:e.amount.totalAmt}:void 0}))}:void 0,ropart:e.ropart?{jobs:e.ropart.jobs?.map(e=>({opCode:e.opCode,jobNo:e.jobNo,lines:e.lines?.map(e=>({partNo:e.partNo,partNoDesc:e.partNoDesc,qtyOrd:e.partQty,sale:e.sale,cost:e.cost,addDeleteFlag:e.addDeleteFlag}))}))}:void 0,rogg:e.rogg?{roNo:e.rogg.roNo,ops:e.rogg.ops?.map(e=>({opCode:e.opCode,jobNo:e.jobNo,lines:e.lines?.map(e=>({breakOut:e.breakOut,itemType:e.itemType,itemDesc:e.itemDesc,custQty:e.custQty,warrQty:e.warrQty,intrQty:e.intrQty,custPayTypeFlag:e.custPayTypeFlag,warrPayTypeFlag:e.warrPayTypeFlag,intrPayTypeFlag:e.intrPayTypeFlag,custTxblNtxblFlag:e.custTxblNtxblFlag,warrTxblNtxblFlag:e.warrTxblNtxblFlag,intrTxblNtxblFlag:e.intrTxblNtxblFlag,amount:e.amount?{payType:e.amount.payType,amtType:e.amount.amtType,custPrice:e.amount.custPrice,dlrCost:e.amount.dlrCost}:void 0}))}))}:void 0,romisc:e.romisc?{roNo:e.romisc.roNo,ops:e.romisc.ops?.map(e=>({opCode:e.opCode,jobNo:e.jobNo,lines:e.lines?.map(e=>({miscCode:e.miscCode,custPayTypeFlag:e.custPayTypeFlag,warrPayTypeFlag:e.warrPayTypeFlag,intrPayTypeFlag:e.intrPayTypeFlag,custTxblNtxblFlag:e.custTxblNtxblFlag,warrTxblNtxblFlag:e.warrTxblNtxblFlag,intrTxblNtxblFlag:e.intrTxblNtxblFlag,codeAmt:e.codeAmt}))}))}:void 0};if(n.tax?.payType&&!["All","Cust","Intr","Warr"].includes(n.tax.payType))throw new k("tax.payType must be one of: All, Cust, Intr, Warr");if(n.rolabor?.ops?.some(e=>e.custTxblNtxblFlag&&!["T","N"].includes(e.custTxblNtxblFlag)||e.warrTxblNtxblFlag&&!["T","N"].includes(e.warrTxblNtxblFlag)||e.intrTxblNtxblFlag&&!["T","N"].includes(e.intrTxblNtxblFlag)))throw new k("Taxable flags (CustTxblNTxblFlag, WarrTxblNTxblFlag, IntrTxblNTxblFlag) must be 'T' or 'N'");if(n.rogg?.ops?.some(e=>e.lines?.some(e=>e.itemType&&!["G","P","S","F"].includes(e.itemType))))throw new k("rogg.ops.lines.itemType must be one of: G, P, S, F");const o={...r?.envelope||{},sender:{component:r?.envelope?.sender?.component??"Rome",task:r?.envelope?.sender?.task??"BSMRO",referenceId:r?.envelope?.sender?.referenceId??"Insert",creatorNameCode:r?.envelope?.sender?.creatorNameCode??"RCI",senderNameCode:r?.envelope?.sender?.senderNameCode??"RCI"}},a=t({routing:r.routing,sender:o.sender,creationDateTime:o.creationDateTime,bodId:o.bodId});return{starXml:j.default.render('\n\n {{{ApplicationArea}}}\n \n \n {{#RO.roComment}}\n \n {{/RO.roComment}}\n\n {{#RO.estimate}}\n \n {{/RO.estimate}}\n\n {{#RO.tax}}\n \n {{/RO.tax}}\n \n\n {{#RO.rolabor}}\n \n {{#RO.rolabor.ops}}\n \n {{#bill}}\n \n {{/bill}}\n\n {{#ccc}}\n \n {{/ccc}}\n\n {{#amount}}\n \n {{/amount}}\n \n {{/RO.rolabor.ops}}\n \n {{/RO.rolabor}}\n\n {{#RO.ropart}}\n \n {{#RO.ropart.jobs}}\n \n {{#lines}}\n \n {{/lines}}\n \n {{/RO.ropart.jobs}}\n \n {{/RO.ropart}}\n\n {{#RO.rogg}}\n \n {{#RO.rogg.ops}}\n \n {{#lines}}\n \n {{#amount}}\n \n {{/amount}}\n \n {{/lines}}\n \n {{/RO.rogg.ops}}\n \n {{/RO.rogg}}\n\n {{#RO.romisc}}\n \n {{#RO.romisc.ops}}\n \n {{#lines}}\n \n {{/lines}}\n \n {{/RO.romisc.ops}}\n \n {{/RO.romisc}}\n \n\n',{ApplicationArea:a,RO:n}),routing:r.routing,envelope:o,postParse:O,xsdFilename:"rey_RomeCreateBSMRepairOrderReq.xsd"}}(e,r))}async updateRepairOrder(e,r){return this._send(function(e={},r={}){if(!r?.routing?.dealerNumber)throw new k("routing.dealerNumber required");if(!e?.finalUpdate)throw new k("finalUpdate (FinalUpdate) required");if(!["Y","N"].includes(e.finalUpdate))throw new k("finalUpdate must be 'Y' or 'N'");if(!e?.outsdRoNo)throw new k(" outsdRoNo");const n={finalUpdate:e.finalUpdate||"N",roNo:e.roNo,customerNo:e.customerNo,tagNo:e.tagNo,outsdRoNo:e.outsdRoNo,departmentType:e.departmentType,vin:e.vin,mileageIn:e.mileageIn,mileageOut:e.mileageOut,roComment:e.roComment,estimate:e.estimate?{estimateType:e.estimate.estimateType}:void 0,tax:e.tax?{payType:e.tax.payType,taxCode:e.tax.taxCode,txblGrossAmt:e.tax.txblGrossAmt,grossTaxAmt:e.tax.grossTaxAmt}:void 0,rolabor:e.rolabor?{ops:e.rolabor.ops?.map(e=>({opCode:e.opCode,jobNo:e.jobNo,custPayTypeFlag:e.custPayTypeFlag,custTxblNtxblFlag:e.custTxblNtxblFlag,warrPayTypeFlag:e.warrPayTypeFlag,warrTxblNtxblFlag:e.warrTxblNtxblFlag,intrPayTypeFlag:e.intrPayTypeFlag,intrTxblNtxblFlag:e.intrTxblNtxblFlag,vlrCode:e.vlrCode,bill:e.bill?{payType:e.bill.payType,jobTotalHrs:e.bill.jobTotalHrs,billTime:e.bill.billTime,billRate:e.bill.billRate}:void 0,ccc:e.ccc?{cause:e.ccc.cause,complaint:e.ccc.complaint,correction:e.ccc.correction}:void 0,amount:e.amount?{payType:e.amount.payType,amtType:e.amount.amtType,custPrice:e.amount.custPrice}:void 0}))}:void 0,ropart:e.ropart?{jobs:e.ropart.jobs?.map(e=>({opCode:e.opCode,jobNo:e.jobNo,lines:e.lines?.map(e=>({partNo:e.partNo,partNoDesc:e.partNoDesc,qtyOrd:e.partQty,sale:e.sale,cost:e.cost,addDeleteFlag:e.addDeleteFlag}))}))}:void 0,rogg:e.rogg?{roNo:e.rogg.roNo,ops:e.rogg.ops?.map(e=>({opCode:e.opCode,jobNo:e.jobNo,lines:e.lines?.map(e=>({breakOut:e.breakOut,itemType:e.itemType,itemDesc:e.itemDesc,custQty:e.custQty,warrQty:e.warrQty,intrQty:e.intrQty,custPayTypeFlag:e.custPayTypeFlag,warrPayTypeFlag:e.warrPayTypeFlag,intrPayTypeFlag:e.intrPayTypeFlag,custTxblNtxblFlag:e.custTxblNtxblFlag,warrTxblNtxblFlag:e.warrTxblNtxblFlag,intrTxblNtxblFlag:e.intrTxblNtxblFlag,amount:e.amount?{payType:e.amount.payType,amtType:e.amount.amtType,custPrice:e.amount.custPrice,dlrCost:e.amount.dlrCost}:void 0}))}))}:void 0,romisc:e.romisc?{roNo:e.romisc.roNo,ops:e.romisc.ops?.map(e=>({opCode:e.opCode,jobNo:e.jobNo,lines:e.lines?.map(e=>({miscCode:e.miscCode,custPayTypeFlag:e.custPayTypeFlag,warrPayTypeFlag:e.warrPayTypeFlag,intrPayTypeFlag:e.intrPayTypeFlag,custTxblNtxblFlag:e.custTxblNtxblFlag,warrTxblNtxblFlag:e.warrTxblNtxblFlag,intrTxblNtxblFlag:e.intrTxblNtxblFlag,codeAmt:e.codeAmt}))}))}:void 0};if(n.tax?.payType&&!["All","Cust","Intr","Warr"].includes(n.tax.payType))throw new k("tax.payType must be one of: All, Cust, Intr, Warr");if(n.rolabor?.ops?.some(e=>e.custTxblNtxblFlag&&!["T","N"].includes(e.custTxblNtxblFlag)||e.warrTxblNtxblFlag&&!["T","N"].includes(e.warrTxblNtxblFlag)||e.intrTxblNtxblFlag&&!["T","N"].includes(e.intrTxblNtxblFlag)))throw new k("Taxable flags (CustTxblNTxblFlag, WarrTxblNTxblFlag, IntrTxblNTxblFlag) must be 'T' or 'N'");if(n.rogg?.ops?.some(e=>e.lines?.some(e=>e.itemType&&!["G","P","S","F"].includes(e.itemType))))throw new k("rogg.ops.lines.itemType must be one of: G, P, S, F");const o={...r?.envelope||{},sender:{component:r?.envelope?.sender?.component??"Rome",task:r?.envelope?.sender?.task??"BSMRO",referenceId:r?.envelope?.sender?.referenceId??"Update",creatorNameCode:r?.envelope?.sender?.creatorNameCode??"RCI",senderNameCode:r?.envelope?.sender?.senderNameCode??"RCI"}},a=t({routing:r.routing,sender:o.sender,creationDateTime:o.creationDateTime,bodId:o.bodId});return{starXml:j.default.render('\n\n {{{ApplicationArea}}}\n \n \n {{#RO.roComment}}\n \n {{/RO.roComment}}\n\n {{#RO.estimate}}\n \n {{/RO.estimate}}\n\n {{#RO.tax}}\n \n {{/RO.tax}}\n \n\n {{#RO.rolabor}}\n \n {{#RO.rolabor.ops}}\n \n {{#bill}}\n \n {{/bill}}\n\n {{#ccc}}\n \n {{/ccc}}\n\n {{#amount}}\n \n {{/amount}}\n \n {{/RO.rolabor.ops}}\n \n {{/RO.rolabor}}\n\n {{#RO.ropart}}\n \n {{#RO.ropart.jobs}}\n \n {{#lines}}\n \n {{/lines}}\n \n {{/RO.ropart.jobs}}\n \n {{/RO.ropart}}\n\n {{#RO.rogg}}\n \n {{#RO.rogg.ops}}\n \n {{#lines}}\n \n {{#amount}}\n \n {{/amount}}\n \n {{/lines}}\n \n {{/RO.rogg.ops}}\n \n {{/RO.rogg}}\n\n {{#RO.romisc}}\n \n {{#RO.romisc.ops}}\n \n {{#lines}}\n \n {{/lines}}\n \n {{/RO.romisc.ops}}\n \n {{/RO.romisc}}\n \n\n',{ApplicationArea:a,RO:n}),routing:r.routing,envelope:o,postParse:O,xsdFilename:"rey_RomeUpdateBSMRepairOrderReq.xsd",elementName:"rey_RomeUpdateBSMRepairOrderReq"}}(e,r))}async getParts(e,r){return this._send(function(e={},r={}){const n=e.roNumber?String(e.roNumber).trim():void 0;if(!n)throw new k("getParts: roNumber required");const o=t({routing:r.routing,sender:{component:"Rome",task:"RCT",referenceId:"Query",creator:"RCI",senderName:"RCI"}});return{starXml:j.default.render('\n\n {{{ApplicationArea}}}\n \n\n',{ApplicationArea:o,RoNumber:n}),routing:r.routing,envelope:r.envelope,xsdFilename:"rey_RomeGetPartsReq.xsd",elementName:"rey_RomeGetPartsReq",postParse:e=>function(e){return e?.rey_RomeGetPartsResp?.RoParts?.map(e=>({partNumber:h(e,"PartNumber"),partDescription:h(e,"PartDescription"),quantityOrdered:h(e,"QuantityOrdered"),quantityShipped:h(e,"QuantityShipped"),price:h(e,"Price"),cost:h(e,"Cost"),processedFlag:h(e,"ProcessedFlag"),addOrDelete:h(e,"AddOrDelete")}))||[]}(e)}}(e,r))}},exports.errors=G; diff --git a/server/rr/lib/index.mjs b/server/rr/lib/index.mjs new file mode 100644 index 000000000..b76b4e31a --- /dev/null +++ b/server/rr/lib/index.mjs @@ -0,0 +1 @@ +function e({routing:e={},sender:t={},creationDateTime:r,bodId:n}={}){const o={Sender:{Component:t.component??"Rome",Task:t.task??"CU",ReferenceId:t.referenceId??"Query",CreatorNameCode:t.creator??"RCI",SenderNameCode:t.senderName??"RCI"},CreationDateTime:r??(new Date).toISOString().replace(/\.\d{3}Z$/,"Z"),BODId:n??V(),Destination:{DestinationNameCode:"RR",DealerNumber:e.dealerNumber||"",StoreNumber:e.storeNumber||"",AreaNumber:e.areaNumber||""}},a={bod:"{{#BODId}}{{BODId}}{{/BODId}}",creation:"{{CreationDateTime}}",sender:"\n \n {{Sender.Component}}\n {{Sender.Task}}\n {{#Sender.ReferenceId}}{{Sender.ReferenceId}}{{/Sender.ReferenceId}}\n {{#Sender.CreatorNameCode}}{{Sender.CreatorNameCode}}{{/Sender.CreatorNameCode}}\n {{#Sender.SenderNameCode}}{{Sender.SenderNameCode}}{{/Sender.SenderNameCode}}\n ".trim(),dest:"\n \n {{Destination.DestinationNameCode}}\n {{#Destination.DealerNumber}}{{Destination.DealerNumber}}{{/Destination.DealerNumber}}\n {{#Destination.StoreNumber}}{{Destination.StoreNumber}}{{/Destination.StoreNumber}}\n {{#Destination.AreaNumber}}{{Destination.AreaNumber}}{{/Destination.AreaNumber}}\n ".trim()},s=`\n${["bod","creation","sender","dest"].map(e=>a[e]).join("\n")}\n`;return M.render(s,o).trim()}function t(e,t=2){const r=" ".repeat(t);return String(e).split("\n").map(e=>e.length?r+e:e).join("\n")}function r(e){return String(e??"").replace(/&/g,"&").replace(//g,">")}function n(e,t){if(null==e)return null;if(Array.isArray(e)){for(const r of e){const e=n(r,t);if(null!=e)return e}return null}if("object"!=typeof e)return null;for(const[r,o]of Object.entries(e)){if(t(r,o))return o;const e=n(o,t);if(null!=e)return e}return null}function o(e,t,r=[]){if(null==e)return r;if(Array.isArray(e)){for(const n of e)o(n,t,r);return r}if("object"!=typeof e)return r;for(const[n,a]of Object.entries(e))t(n,a)&&r.push(a),o(a,t,r);return r}function a(e){return null==e?[]:Array.isArray(e)?e:[e]}function s(e,t){if(e&&"object"==typeof e)return function(e){if(null!=e)return"string"==typeof e||"number"==typeof e||"boolean"==typeof e?String(e):"object"==typeof e&&"#text"in e?String(e["#text"]):void 0}(e[t])}function i(e,t){const r=s(e,t);if(k(r))return r;const n=function(e,t){if(e&&"object"==typeof e)return e.$&&k(e.$[t])?e.$[t]:k(e[`@_${t}`])?e[`@_${t}`]:k(e[`@${t}`])?e[`@${t}`]:e._attributes&&k(e._attributes[t])?e._attributes[t]:e.attributes&&k(e.attributes[t])?e.attributes[t]:void 0}(e,t);return k(n)?n:void 0}function l(e,t){if(e&&"object"==typeof e)return null!=e[`@_${t}`]?e[`@_${t}`]:void 0}function c(e){if(null!=e){if("string"==typeof e)return e;if("number"==typeof e)return String(e);if("object"==typeof e){if(null!=e._)return String(e._);if(null!=e["#text"])return String(e["#text"]);if(null!=e.text)return String(e.text)}}}function m(e){return o(e,e=>/(GenTransStatus|TransStatus)$/i.test(e)).flatMap(a)[0]}function p(e){if(e)return{status:(l(e,"Status")||e.Status||c(e)||"").toString().trim()||void 0,statusCode:(l(e,"StatusCode")||e.StatusCode||"").toString().trim()||void 0,message:e.Message&&c(e.Message)||e.GenTransStatus&&c(e.GenTransStatus)||e.TransStatus&&c(e.TransStatus)||c(e)||void 0}}function u(e){if(e)return{status:(l(e,"Status")||e.Status||c(e)||"").toString().trim()||void 0,date:(l(e,"Date")||e.Date||"").toString().trim()||void 0,time:(l(e,"Time")||e.Time||"").toString().trim()||void 0,outsdRoNo:(l(e,"OutsdRoNo")||e.OutsdRoNo||"").toString().trim()||void 0,dmsRoNo:(l(e,"DMSRoNo")||e.DMSRoNo||"").toString().trim()||void 0,errorMessage:(l(e,"ErrorMessage")||e.ErrorMessage||"").toString().trim()||void 0}}function d(e){return a((e?.rey_RomeCustServVehComb??e??{}).CustServVehComb).map(e=>{const t=e?.NameContactId??void 0,r=t?.NameId??void 0,n=r?.IndName?$(r.IndName):void 0,o=r?.BusName?$(r.BusName):void 0,s=t&&{NameId:r&&{...$(r)||{},...n?{IndName:n}:{},...o?{BusName:o}:{}},Address:a(t?.Address).map(e=>$(e)||{}),ContactOptions:a(t?.ContactOptions).map(e=>$(e)||{}),Phone:a(t?.Phone).map(e=>$(e)||{}),Email:a(t?.Email).map(e=>$(e)||{})},i=a(e?.ServVehicle).map(e=>{const t=e?.Vehicle,r=t?.VehicleDetail,n=t&&{...$(t)||{},...r?{VehicleDetail:$(r)}:{}},o=e?.VehicleServInfo,s=o?.VehExtWarranty,i=o?.Advisor,l=i?.ContactInfo,c=o&&{...$(o)||{},...s?{VehExtWarranty:$(s)}:{},...i?{Advisor:l?{ContactInfo:$(l)||{}}:{Advisor:{}}}:{},...e?.VehicleServInfo?.VehServComments?{VehServComments:a(e.VehicleServInfo.VehServComments).map(e=>Q(e))}:{}};return{...n?{Vehicle:n}:{},...c?{VehicleServInfo:c}:{}}}),l=a(e?.Message).map(e=>({...$(e)||{},Text:Q(e)})),c={};return s&&(c.NameContactId=s),i.length&&(c.ServVehicle=i),l.length&&(c.Message=l),c})}function y(e,t){if(null!=e)return String("string"==typeof e||"number"==typeof e?e:e[t]||"")}function g(e,...t){if(e)for(const r of t){if(e.$&&null!=e.$[r])return e.$[r];if(null!=e[`@_${r}`])return e[`@_${r}`];if(null!=e[r]&&"object"!=typeof e[r])return e[r]}}function N(e){const t=function(e){const t=n(e,e=>"rey_RomeCustomerResponse"===e||e.endsWith(":rey_RomeCustomerResponse"));return t?o(t,e=>"TransStatus"===e||e.endsWith(":TransStatus")).flatMap(a)[0]:void console.log("No rey_RomeCustomerResponse found in root")}(e);if(!t)return{dmsRecKey:void 0};const r=g(t,"DMSRecKey");return{dmsRecKey:null!=r?String(r):void 0,status:g(t,"Status"),statusCode:g(t,"StatusCode")}}function T(e){if(null==e)return;const t=String(e).toUpperCase().replace(/[^A-Z0-9 ]+/g,"");if(!t)throw new j(`Invalid string: ${e}. Must contain A-Z, 0-9, or space`);return t}function b(e){return e?String(e).toUpperCase():void 0}function x(e={}){const t=b(e.ibFlag)||(e.firstName?"I":"B");if("I"!==t&&"B"!==t)throw new j("ibFlag must be 'I' or 'B'");const r=e.lastName||e.customerName;if(!r)throw new j("lastName or customerName required");if("I"===t&&!e.firstName)throw new j("firstName required when ibFlag='I'");const n=b(e.customerType);if(n&&!["R","W","I"].includes(n))throw new j("customerType must be 'R', 'W', 'I', Retail, Wholesale, or Internal");const o=(e.addresses||[]).map(e=>{const t={Type:b(e.type)||"P",Addr1:e.line1?String(e.line1):void 0,Addr2:e.line2?String(e.line2):void 0,City:e.city?String(e.city):void 0,State:e.state?String(e.state):void 0,Zip:e.postalCode?String(e.postalCode):void 0,County:e.county?String(e.county):void 0,Country:e.country?String(e.country):void 0};if(!t.Addr1)throw new j("Address requires line1");return t}),a=(e.phones||[]).map(e=>{const t={Type:b(e.type)||"H",Num:e.number?String(e.number):void 0,Ext:e.extension?String(e.extension):void 0};if(!t.Num)throw new j("Phone requires number");return t}),s=e.emails?.[0]?.address?{MailTo:String(e.emails[0].address)}:void 0,i=e.personal,l=i?{Gender:b(i.gender),OtherName:T(i.otherName),AnniversaryDate:i.anniversaryDate?String(i.anniversaryDate):void 0,EmployerName:T(i.employerName),EmployerPhone:i.employerPhone?String(i.employerPhone):void 0,Occupation:T(i.occupation),OptOut:i.optOut?String(i.optOut):void 0,OptOutUse:i.optOutUse?String(i.optOutUse):void 0,BirthDates:(i.birthDates||[]).map(e=>({Type:b(e.type)||"P",date:e.date?String(e.date):void 0})).filter(e=>e.date),SSNs:(i.ssns||[]).map(e=>({Type:b(e.type)||"P",ssn:e.ssn?String(e.ssn):void 0})).filter(e=>e.ssn),DriverInfo:i.driver?[{Type:b(i.driver.type)||"P",LicNum:i.driver.licenseNumber?String(i.driver.licenseNumber):void 0,LicState:i.driver.licenseState?String(i.driver.licenseState):void 0,LicExpDate:i.driver.licenseExpDate?String(i.driver.licenseExpDate):void 0}].filter(e=>e.LicNum):void 0,CustChildren:(i.children||[]).map(e=>({ChildName:T(e.name)})).filter(e=>e.ChildName)}:void 0,c=e.dms,m=c?{TaxExemptNum:c.taxExemptNum?String(c.taxExemptNum):void 0,SalesTerritory:c.salesTerritory?String(c.salesTerritory):void 0,DeliveryRoute:c.deliveryRoute?String(c.deliveryRoute):void 0,SalesmanNum:c.salesmanNum?String(c.salesmanNum):void 0,LastContactMethod:c.lastContactMethod?String(c.lastContactMethod):void 0,Followups:(c.followups||[]).map(e=>({Type:b(e.type),Value:b(e.value)})).filter(e=>e.Type&&e.Value)}:void 0;return{custCateg:n||"R",createdBy:e.createdBy?String(e.createdBy):void 0,contactInfo:{IBFlag:t,LastName:T(r),FirstName:T(e.firstName),MidName:T(e.midName),Salut:T(e.salut),Suffix:T(e.suffix),Addresses:o,Phones:a,Email:s},custPersonal:l,dmsCustInfo:m}}function C(e){const t=n(e,e=>"rey_RomeServVehicleInsertResponse"===e||e.endsWith(":rey_RomeServVehicleInsertResponse"))||e,r=n(t,e=>"GenTransStatus"===e||e.endsWith(":GenTransStatus"));return{status:r?i(r,"Status"):void 0,statusCode:r?i(r,"StatusCode"):void 0}}function R(e,t){const r=Array.isArray(t)?t.map(e=>e.toLowerCase()):[String(t).toLowerCase()],n=[e];for(;n.length;){const e=n.pop();if(H(e))for(const t of Object.keys(e)){const o=e[t],a=W(t).toLowerCase();if(r.includes(a))return o;if(H(o))n.push(o);else if(Array.isArray(o))for(const e of o)H(e)&&n.push(e)}}}function f(e,t){if(e&&H(e)){if(null!=e.$?.[t])return e.$[t];if(null!=e[`@${t}`])return e[`@${t}`];if(null!=e[`@_${t}`])return e[`@_${t}`]}}function S(e){if(null!=e){if("string"==typeof e)return e;if("number"==typeof e)return String(e);if(H(e)){if(null!=e._)return String(e._);if(null!=e["#text"])return String(e["#text"]);if(null!=e.text)return String(e.text)}}}function v(e){const t=R(e,["CreateBSMRepairOrderResp","UpdateBSMRepairOrderResp"])||e,r=R(t,"RoRecordStatus")||{};return{status:f(r,"Status")||S(R(r,"Status")),date:f(r,"Date")||S(R(r,"Date")),time:f(r,"Time")||S(R(r,"Time")),outsdRoNo:f(r,"OutsdRoNo")||S(R(r,"OutsdRoNo")),dmsRoNo:f(r,"DMSRoNo")||S(R(r,"DMSRoNo")),errorMessage:f(r,"ErrorMessage")||S(R(r,"ErrorMessage"))}}function O(t={},r={}){const n=function(e){if(!e)throw new Error("department is required (S, P, B, SERVICE, PARTS, BODY)");const t=String(e).trim().toUpperCase();if("S"===t||"P"===t||"B"===t)return t;if("SERVICE"===t)return"S";if("PART"===t||"PARTS"===t)return"P";if("BODY"===t||"BODYSHOP"===t||"BODY SHOP"===t)return"B";throw new Error(`Invalid department: ${e}. Must be S, P, B, SERVICE, PARTS, BODY, BODYSHOP, or BODY SHOP`)}(t.department),o=t.advisorNumber?String(t.advisorNumber).trim():void 0,a=e({routing:r.routing,sender:r?.envelope?.sender,creationDateTime:r?.envelope?.creationDateTime,bodId:r?.envelope?.bodId});return{starXml:M.render('\n\n {{{ApplicationArea}}}\n \n \n \n\n',{ApplicationArea:a,DepartmentType:n,AdvisorNumber:o}),routing:r.routing,envelope:r.envelope,xsdFilename:"rey_RomeGetAdvisorsReq.xsd",elementName:"rey_RomeGetAdvisorsReq",postParse:e=>function(e,t={}){const r=t?.department;var n;return(e=>{const t=e?.Advisor;return t?Array.isArray(t)?t:[t]:[]})((n=e,n?.rey_RomeGetAdvisorsResp??n??{})).map(e=>({advisorId:Y(e,"AdvisorNumber"),firstName:Y(e,"FirstName"),lastName:Y(e,"LastName"),department:r}))}(e,{department:n})}}function F(e){return null==e?void 0:String(e)}function I(e,t){if(e)return null!=e[t]?"object"!=typeof e[t]?F(e[t]):F(e[t]["#text"]):null!=e[`@_${t}`]?F(e[`@_${t}`]):void 0}function h(e){const t=e?.meta?.statusBlocks?.transaction?.message;if(t)return String(t);return String((e?.meta?.status?.Message??e?.meta?.status?.message)||e?.message||"")}function w(e,t){return Math.min(1e4,e*Math.pow(2,t))}function P(e){return e+Math.floor(250*Math.random())}function D(e){return new Promise(t=>setTimeout(t,e))}function A(e){return/lock|in use|record.*busy/i.test(String(e||""))}import M from"mustache";import{v4 as V}from"uuid";import E from"axios";import{XMLParser as L}from"fast-xml-parser";class _ extends Error{constructor(e,t={}){super(e),this.name="RRTransportError",this.meta=t}}class B extends Error{constructor(e,t={}){super(e),this.name="RRVendorStatusError",this.meta=t,this.retryable=!!t.retryable}}class j extends Error{constructor(e,t={}){super(e),this.name="RRValidationError",this.meta=t}}const q=Object.freeze({__proto__:null,RRTransportError:_,RRVendorStatusError:B,RRValidationError:j}),U={info:(...e)=>console.log("[rr-rome]",...e),warn:(...e)=>console.warn("[rr-rome]",...e),error:(...e)=>console.error("[rr-rome]",...e),debug:(...e)=>{process.env.RR_DEBUG&&console.log("[rr-rome][debug]",...e)}},k=e=>null!=e&&""!==String(e).trim(),G=new L({ignoreAttributes:!1,attributeNamePrefix:"@_",parseAttributeValue:!1,parseTagValue:!1,isArray:e=>["Advisor"].includes(e)}),$=e=>{if(!e||"object"!=typeof e)return;const t={};for(const[r,n]of Object.entries(e))r.startsWith("@_")&&(t[r.slice(2)]=n);return Object.keys(t).length?t:void 0},Q=e=>{if(null!=e)return"string"==typeof e?e:e["#text"]},W=e=>{if("string"!=typeof e)return"";let t=e.includes("}")?e.split("}").pop():e;return t=t.includes(":")?t.split(":").pop():t,t.startsWith("rey_")&&(t=t.slice(4)),t},H=e=>e&&"object"==typeof e&&!Array.isArray(e),Y=(e,t)=>((e,t)=>e?.[`@_${t}`])(e,t)??s(e,t);class X{constructor(e){if(!e?.baseUrl)throw new Error("RRClient requires baseUrl");if(!e?.username)throw new Error("RRClient requires username");if(!e?.password)throw new Error("RRClient requires password");this.cfg={wssePasswordType:"Text",timeoutMs:3e4,logger:U,retries:{max:3},...e},this.mask={password:!0}}async _send(e){const{starXml:n,routing:s,envelope:i,postParse:d}=e,y=this.cfg.logger||U,{bodId:g,creationDateTime:N,sender:T}=function(e){return{bodId:e?.bodId||V(),creationDateTime:e?.creationDateTime||new Date,sender:e?.sender||{}}}(i),b=function({username:e,password:n,wssePasswordType:o="Text",starContentXml:a}){const s=function(e){return`\n \n \n \n${t(e,10)}\n \n \n \n `.trim()}(a);return`\n \n \n${t(function(e,t,n){const o="Digest"===n?' Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"':' Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"';return`\n \n \n ${r(e)}\n ${r(t)}\n \n \n `.trim()}(e,n,o),8)}\n \n \n${t(s,8)}\n \n \n `.trim()}({username:this.cfg.username,password:this.cfg.password,wssePasswordType:this.cfg.wssePasswordType||"Text",routing:s,sender:T,creationDateTime:(x=N,"string"==typeof x?x:(x instanceof Date?x:new Date).toISOString().replace(/\.\d{3}Z$/,"Z")),bodId:g,starContentXml:n});var x;"1"===process.env.RR_DUMP_ENVELOPE&&console.log(`[rr] Soap envelope about to send (${e?.elementName}): \n`+b+"\n");const C=async()=>{const t=await async function({baseUrl:e,envelopeXml:t,timeoutMs:r=3e4,logger:n}){try{const n=await E.post(e,t,{timeout:r,headers:{"Content-Type":"text/xml; charset=utf-8",SOAPAction:"http://www.starstandards.org/webservices/2005/10/transport/ProcessMessage"},responseType:"text",validateStatus:()=>!0});if(n.status>=200&&n.status<300)return String(n.data??"");throw new _(`HTTP ${n.status}: ${function(e){const t=String(e??"");return t.length>1024?t.slice(0,1024)+"…":t}(n.data)}`,{status:n.status,body:n.data})}catch(e){if(E.isAxiosError(e))throw new _(`Network error: ${e.message}`,{cause:e});throw e}}({baseUrl:this.cfg.baseUrl,envelopeXml:b,timeoutMs:this.cfg.timeoutMs,logger:y}),r=function(e){const t=G.parse(e),r=t?.Envelope||t?.["soapenv:Envelope"]||t,n=r?.Body||r?.["soapenv:Body"]||r?.["S:Body"]||r?.["soap:Body"],o=n?.ProcessMessageResponse||n?.["ns2:ProcessMessageResponse"]||n?.["trans:ProcessMessageResponse"]||n,a=o?.payload||o?.["ns2:payload"]||o;return a?.content||a?.["ns2:content"]||a}(t),n=function(e){const t=m(e),r=o(e,e=>/RoRecordStatus$/i.test(e)).flatMap(a)[0];return{transaction:p(t),roRecord:u(r)}}(r),s=function(e){const t=String("ApplicationArea").toLowerCase(),r=[e];for(;r.length;){const e=r.pop();if(e&&"object"==typeof e)for(const[n,o]of Object.entries(e)){if(n.toLowerCase().endsWith(t))return o;o&&"object"==typeof o&&r.push(o)}}}(r),{status:i,norm:g}=function(e){const t=m(e)||o(e,e=>/Status$/i.test(e)).flatMap(a)[0]||{},r=(l(t,"Status")||t.Status||"").toString().trim();let n=(l(t,"StatusCode")||t.StatusCode||"").toString().trim();const s=t.Message&&c(t.Message)||c(t)||"";!n&&/success/i.test(r)&&(n="0");const i=Number(n);let p="FAIL";return/success/i.test(r)||0===i?p="SUCCESS":2!==i&&213!==i||(p="NO_MATCH"),{status:{Status:r,StatusCode:n,Message:s},norm:{kind:p,code:Number.isFinite(i)?i:void 0,message:s}}}(r);if("1"===process.env.RR_DUMP_STATUS&&(console.log("[rr] Status blocks:"),console.dir(n,{depth:null,colors:!0})),"1"===process.env.RR_DUMP_APPLICATION&&(console.log("[rr] ApplicationArea:"),console.dir(s,{depth:null,colors:!0})),"FAIL"===g.kind){const e=i?.StatusCode;throw new B(`Vendor status failure: ${e??""} ${i?.Message||i?.["#text"]||""}`.trim(),{status:i,resXml:t})}const N={success:"SUCCESS"===g.kind||"NO_MATCH"===g.kind,statusBlocks:n,applicationArea:s,xml:{request:b,response:t},parsed:r};if("function"==typeof d)try{N.data=d(r)}catch(e){y?.warn?.(`postParse failed: ${e?.message||e}`)}return"1"===process.env.RR_DUMP_XML&&console.log(`[rr] Full response XML (${e?.elementName}):\n`+t+"\n"),N?.data&&"1"===process.env.RR_DUMP_DATA&&(console.log(`[rr] Parsed response data (${e?.elementName}):\n`),console.dir(N.data,{depth:null,colors:!0})),N};try{return await async function(e,{max:t=3,logger:r}){let n,o=0;for(;o=t)break;const s=P(w(400,o));r?.warn?.(`Retrying attempt ${o}/${t} in ${s}ms: ${e.message}`),await D(s)}throw n}(C,{max:this.cfg.retries?.max??3,logger:y})}catch(e){if(e instanceof _||e instanceof B)throw e;throw new _(`Unexpected error: ${e?.message||e}`,{cause:e})}}async combinedSearch(t,r){return this._send(function(t={},r={}){if(!t||"object"!=typeof t)throw new j("combinedSearch requires a query object");const n=function(e){if(!e)return"";const t=String(e).trim().toLowerCase();return"telephone"===t?"phone":"lic"===t||"plate"===t?"license":"vin"===t||"partvin"===t?"vin":"name"===t?"name":"nameRecId"===t||"custId"===t?"nameRecId":"stkNo"===t||"stock"===t?"stkNo":t}(t.kind),o={MaxRecs:Math.min(Number(t.maxResults||t.maxRecs||50),50)};if("phone"===n){const e=y(t.phone,"phone");if(!e)throw new j("combinedSearch phone value missing");o.Phone=e}else if("license"===n){const e=y(t.license,"license");if(!e)throw new j("combinedSearch license value missing");o.LicenseNum=e}else if("vin"===n){const e=y(t.vin,"vin");if(!e)throw new j("combinedSearch vin value missing");o.PartVIN=e}else if("name"===n){const e=t.name;if(!e||"object"!=typeof e)throw new j("combinedSearch name requires { fname, lname, mname } or { name }");if(e.fname&&e.lname&&e.mname)o.FullName={FName:String(e.fname),LName:String(e.lname),MName:String(e.mname)};else{if(!e.name)throw new j("combinedSearch name requires { fname, lname, mname } or { name }");o.LName=String(e.name)}}else if("nameRecId"===n){const e=y(t.nameRecId,"custId");if(!e)throw new j("combinedSearch nameRecId value missing");o.NameRecId=e}else{if("stkNo"!==n)throw new j(`Unsupported CombinedSearch kind: ${t.kind}`);{const e=y(t.stkNo,"stkNo");if(!e)throw new j("combinedSearch stkNo value missing");o.StkNo=e}}if(1!==[o.Phone,o.LicenseNum,o.PartVIN,o.LName,o.FullName,o.NameRecId,o.StkNo].filter(Boolean).length)throw new j("combinedSearch requires exactly one search criterion");o.VehData={MakePfx:t.make||"ANY",Model:t.model||"ANY",Year:t.year||"ANY"};const a=e({routing:r.routing,sender:{component:"Rome",task:"CVC",referenceId:"Query",creator:"RCI",senderName:"RCI"},order:"creation-bod-sender-destination"});return{starXml:M.render('\n\n {{{ApplicationArea}}}\n \n \n {{#Phone}}{{/Phone}}\n {{#PartVIN}}{{/PartVIN}}\n {{#LicenseNum}}{{/LicenseNum}}\n {{#LName}}{{/LName}}\n {{#FullName}}{{/FullName}}\n {{#NameRecId}}{{/NameRecId}}\n {{#StkNo}}{{/StkNo}}\n \n \n \n\n',{ApplicationArea:a,...o}),routing:r.routing,envelope:r.envelope,elementName:"rey_RomeCustServVehCombReq",xsdFilename:"rey_RomeCustServVehCombReq.xsd",postParse:d}}(t,r))}async insertCustomer(t,r){return this._send(function(t,r){if(!r?.routing?.dealerNumber)throw new j("routing.dealerNumber required");const n=x(t),o=e({routing:r.routing,sender:{component:"Rome",task:"CU",referenceId:"Insert"},order:"sender-creation-bod-destination"});return{starXml:M.render('\n\n {{{ApplicationArea}}}\n \n \n {{#C.contactInfo.Addresses}}\n \n {{/C.contactInfo.Addresses}}\n {{#C.contactInfo.Phones}}\n \n {{/C.contactInfo.Phones}}\n {{#C.contactInfo.Email}}\n \n {{/C.contactInfo.Email}}\n \n {{#C.custPersonal}}\n \n {{#BirthDates}}\n \n {{/BirthDates}}\n {{#SSNs}}\n \n {{/SSNs}}\n {{#DriverInfo}}\n \n {{/DriverInfo}}\n {{#CustChildren}}\n \n {{/CustChildren}}\n \n {{/C.custPersonal}}\n {{#C.dmsCustInfo}}\n \n {{#Followups}}\n \n {{/Followups}}\n \n {{/C.dmsCustInfo}}\n \n\n',{ApplicationArea:o,C:n}),routing:r.routing,envelope:r.envelope,postParse:N,xsdFilename:"rey_RomeCustomerInsertReq.xsd",elementName:"rey_RomeCustomerInsertReq"}}(t,r))}async updateCustomer(t,r){return this._send(function(t,r){if(!r?.routing?.dealerNumber)throw new j("routing.dealerNumber required");if(!t.nameRecId)throw new j("nameRecId or customerId required");const n=b(t.ibFlag);if("I"!==n&&"B"!==n)throw new j("ibFlag required ('I' or 'B')");const o=x(t);o.contactInfo.NameRecId=String(t.nameRecId);const a=e({routing:r.routing,sender:{component:"Rome",task:"CU",referenceId:"Update"},order:"sender-creation-bod-destination"});return{starXml:M.render('\n\n {{{ApplicationArea}}}\n \n \n {{#C.contactInfo.Addresses}}\n \n {{/C.contactInfo.Addresses}}\n {{#C.contactInfo.Phones}}\n \n {{/C.contactInfo.Phones}}\n {{#C.contactInfo.Email}}\n \n {{/C.contactInfo.Email}}\n \n {{#C.custPersonal}}\n \n {{#BirthDates}}\n \n {{/BirthDates}}\n {{#SSNs}}\n \n {{/SSNs}}\n {{#DriverInfo}}\n \n {{/DriverInfo}}\n {{#CustChildren}}\n \n {{/CustChildren}}\n \n {{/C.custPersonal}}\n {{#C.dmsCustInfo}}\n \n {{#Followups}}\n \n {{/Followups}}\n \n {{/C.dmsCustInfo}}\n \n\n',{ApplicationArea:a,C:o}),routing:r.routing,envelope:r.envelope,postParse:N,xsdFilename:"rey_RomeCustomerUpdateReq.xsd",elementName:"rey_RomeCustomerUpdateReq"}}(t,r))}async insertServiceVehicle(t,r){return this._send(function(t={},r={}){if(!r?.routing?.dealerNumber)throw new j("routing.dealerNumber is required");const n=e({routing:r.routing,sender:r?.envelope?.sender??{component:"Rome",task:"SV",referenceId:"Insert"},creationDateTime:r?.envelope?.creationDateTime,bodId:r?.envelope?.bodId}),o=function(e={}){const t=e.vin;if(!t)throw new j("insertServiceVehicle: vin is required");const r=e.vehicleServInfo?.customerNo;if(!r)throw new j("insertServiceVehicle: vehicleServInfo.customerNo (or customerNo) is required");return{VIN:String(t),ModelDesc:e.modelDesc,Carline:e.carline,ExtClrDesc:e.extClrDesc,IntClrDesc:e.intClrDesc,TrimDesc:e.trimDesc,BodyStyle:e.bodyStyle,EngineDesc:e.engineDesc,TransDesc:e.transDesc,Year:e.year,Odometer:e.odometer,OdometerUnits:e.odometerUnits,LicNo:e.vehicleDetail?.licNo,CustomerNo:String(r),vehicleServInfo:{salesmanNo:e.vehicleServInfo?.salesmanNo,inServiceDate:e.vehicleServInfo?.inServiceDate,mileage:e.vehicleServInfo?.mileage,teamCode:e.vehicleServInfo?.teamCode,vehExtWarranty:(()=>{const t=e.vehicleServInfo?.vehExtWarranty;if(!t)return;const r={contractNumber:t.contractNumber,expirationDate:t.expirationDate,expirationMileage:t.expirationMileage};return Object.values(r).some(e=>null!=e&&""!==e)?r:void 0})(),advisor:(()=>{const t=e.vehicleServInfo?.advisor,r=t?.contactInfo?.nameRecId;return r?{contactInfo:{nameRecId:String(r)}}:void 0})()}}}(t);return{starXml:M.render('\n\n {{{ApplicationArea}}}\n\n \n {{#V.Year}}{{.}}{{/V.Year}}\n {{#V.Odometer}}{{.}}{{/V.Odometer}}\n {{#V.OdometerUnits}}{{.}}{{/V.OdometerUnits}}\n\n {{#V.LicNo}}{{/V.LicNo}}\n \n\n \n {{#V.vehicleServInfo.salesmanNo}}{{.}}{{/V.vehicleServInfo.salesmanNo}}\n {{#V.vehicleServInfo.inServiceDate}}{{.}}{{/V.vehicleServInfo.inServiceDate}}\n {{#V.vehicleServInfo.mileage}}{{.}}{{/V.vehicleServInfo.mileage}}\n {{#V.vehicleServInfo.teamCode}}{{.}}{{/V.vehicleServInfo.teamCode}}\n\n {{#V.vehicleServInfo.vehExtWarranty}}\n \n {{#contractNumber}}{{.}}{{/contractNumber}}\n {{#expirationDate}}{{.}}{{/expirationDate}}\n {{#expirationMileage}}{{.}}{{/expirationMileage}}\n \n {{/V.vehicleServInfo.vehExtWarranty}}\n\n {{#V.vehicleServInfo.advisor}}\n \n \n \n {{/V.vehicleServInfo.advisor}}\n \n\n',{ApplicationArea:n,V:o}),routing:r.routing,envelope:r.envelope,postParse:C,xsdFilename:"rey_RomeServVehicleInsertReq.xsd",elementName:"rey_RomeServVehicleInsertReq"}}(t,r))}async getAdvisors(e,t){return this._send(O(e,t))}async createRepairOrder(t,r){return this._send(function(t={},r={}){if(!r?.routing?.dealerNumber)throw new j("routing.dealerNumber required");if(!t?.customerNo)throw new j("customerNo (CustNo) required");if(!t?.departmentType)throw new j("departmentType (DeptType) required");if(!t?.vin)throw new j("vin (Vin) required");if(!t?.outsdRoNo)throw new j("outsdRoNo required");const n={customerNo:t.customerNo,advisorNo:t.advisorNo,tagNo:t.tagNo,outsdRoNo:t.outsdRoNo,departmentType:t.departmentType,vin:t.vin,mileageIn:t.mileageIn,roComment:t.roComment,estimate:t.estimate?{parts:t.estimate.parts,labor:t.estimate.labor,total:t.estimate.total}:void 0,tax:t.tax?{payType:t.tax.payType,taxCode:t.tax.taxCode,txblGrossAmt:t.tax.txblGrossAmt,grossTaxAmt:t.tax.grossTaxAmt}:void 0,rolabor:t.rolabor?{ops:t.rolabor.ops?.map(e=>({opCode:e.opCode,jobNo:e.jobNo,custPayTypeFlag:e.custPayTypeFlag,custTxblNtxblFlag:e.custTxblNtxblFlag,warrPayTypeFlag:e.warrPayTypeFlag,warrTxblNtxblFlag:e.warrTxblNtxblFlag,intrPayTypeFlag:e.intrPayTypeFlag,intrTxblNtxblFlag:e.intrTxblNtxblFlag,vlrCode:e.vlrCode,bill:e.bill?{payType:e.bill.payType,jobTotalHrs:e.bill.jobTotalHrs,billTime:e.bill.billTime,billRate:e.bill.billRate}:void 0,ccc:e.ccc?{cause:e.ccc.cause,complaint:e.ccc.complaint,correction:e.ccc.correction}:void 0,amount:e.amount?{payType:e.amount.payType,amtType:e.amount.amtType,custPrice:e.amount.custPrice,totalAmt:e.amount.totalAmt}:void 0}))}:void 0,ropart:t.ropart?{jobs:t.ropart.jobs?.map(e=>({opCode:e.opCode,jobNo:e.jobNo,lines:e.lines?.map(e=>({partNo:e.partNo,partNoDesc:e.partNoDesc,qtyOrd:e.partQty,sale:e.sale,cost:e.cost,addDeleteFlag:e.addDeleteFlag}))}))}:void 0,rogg:t.rogg?{roNo:t.rogg.roNo,ops:t.rogg.ops?.map(e=>({opCode:e.opCode,jobNo:e.jobNo,lines:e.lines?.map(e=>({breakOut:e.breakOut,itemType:e.itemType,itemDesc:e.itemDesc,custQty:e.custQty,warrQty:e.warrQty,intrQty:e.intrQty,custPayTypeFlag:e.custPayTypeFlag,warrPayTypeFlag:e.warrPayTypeFlag,intrPayTypeFlag:e.intrPayTypeFlag,custTxblNtxblFlag:e.custTxblNtxblFlag,warrTxblNtxblFlag:e.warrTxblNtxblFlag,intrTxblNtxblFlag:e.intrTxblNtxblFlag,amount:e.amount?{payType:e.amount.payType,amtType:e.amount.amtType,custPrice:e.amount.custPrice,dlrCost:e.amount.dlrCost}:void 0}))}))}:void 0,romisc:t.romisc?{roNo:t.romisc.roNo,ops:t.romisc.ops?.map(e=>({opCode:e.opCode,jobNo:e.jobNo,lines:e.lines?.map(e=>({miscCode:e.miscCode,custPayTypeFlag:e.custPayTypeFlag,warrPayTypeFlag:e.warrPayTypeFlag,intrPayTypeFlag:e.intrPayTypeFlag,custTxblNtxblFlag:e.custTxblNtxblFlag,warrTxblNtxblFlag:e.warrTxblNtxblFlag,intrTxblNtxblFlag:e.intrTxblNtxblFlag,codeAmt:e.codeAmt}))}))}:void 0};if(n.tax?.payType&&!["All","Cust","Intr","Warr"].includes(n.tax.payType))throw new j("tax.payType must be one of: All, Cust, Intr, Warr");if(n.rolabor?.ops?.some(e=>e.custTxblNtxblFlag&&!["T","N"].includes(e.custTxblNtxblFlag)||e.warrTxblNtxblFlag&&!["T","N"].includes(e.warrTxblNtxblFlag)||e.intrTxblNtxblFlag&&!["T","N"].includes(e.intrTxblNtxblFlag)))throw new j("Taxable flags (CustTxblNTxblFlag, WarrTxblNTxblFlag, IntrTxblNTxblFlag) must be 'T' or 'N'");if(n.rogg?.ops?.some(e=>e.lines?.some(e=>e.itemType&&!["G","P","S","F"].includes(e.itemType))))throw new j("rogg.ops.lines.itemType must be one of: G, P, S, F");const o={...r?.envelope||{},sender:{component:r?.envelope?.sender?.component??"Rome",task:r?.envelope?.sender?.task??"BSMRO",referenceId:r?.envelope?.sender?.referenceId??"Insert",creatorNameCode:r?.envelope?.sender?.creatorNameCode??"RCI",senderNameCode:r?.envelope?.sender?.senderNameCode??"RCI"}},a=e({routing:r.routing,sender:o.sender,creationDateTime:o.creationDateTime,bodId:o.bodId});return{starXml:M.render('\n\n {{{ApplicationArea}}}\n \n \n {{#RO.roComment}}\n \n {{/RO.roComment}}\n\n {{#RO.estimate}}\n \n {{/RO.estimate}}\n\n {{#RO.tax}}\n \n {{/RO.tax}}\n \n\n {{#RO.rolabor}}\n \n {{#RO.rolabor.ops}}\n \n {{#bill}}\n \n {{/bill}}\n\n {{#ccc}}\n \n {{/ccc}}\n\n {{#amount}}\n \n {{/amount}}\n \n {{/RO.rolabor.ops}}\n \n {{/RO.rolabor}}\n\n {{#RO.ropart}}\n \n {{#RO.ropart.jobs}}\n \n {{#lines}}\n \n {{/lines}}\n \n {{/RO.ropart.jobs}}\n \n {{/RO.ropart}}\n\n {{#RO.rogg}}\n \n {{#RO.rogg.ops}}\n \n {{#lines}}\n \n {{#amount}}\n \n {{/amount}}\n \n {{/lines}}\n \n {{/RO.rogg.ops}}\n \n {{/RO.rogg}}\n\n {{#RO.romisc}}\n \n {{#RO.romisc.ops}}\n \n {{#lines}}\n \n {{/lines}}\n \n {{/RO.romisc.ops}}\n \n {{/RO.romisc}}\n \n\n',{ApplicationArea:a,RO:n}),routing:r.routing,envelope:o,postParse:v,xsdFilename:"rey_RomeCreateBSMRepairOrderReq.xsd"}}(t,r))}async updateRepairOrder(t,r){return this._send(function(t={},r={}){if(!r?.routing?.dealerNumber)throw new j("routing.dealerNumber required");if(!t?.finalUpdate)throw new j("finalUpdate (FinalUpdate) required");if(!["Y","N"].includes(t.finalUpdate))throw new j("finalUpdate must be 'Y' or 'N'");if(!t?.outsdRoNo)throw new j(" outsdRoNo");const n={finalUpdate:t.finalUpdate||"N",roNo:t.roNo,customerNo:t.customerNo,tagNo:t.tagNo,outsdRoNo:t.outsdRoNo,departmentType:t.departmentType,vin:t.vin,mileageIn:t.mileageIn,mileageOut:t.mileageOut,roComment:t.roComment,estimate:t.estimate?{estimateType:t.estimate.estimateType}:void 0,tax:t.tax?{payType:t.tax.payType,taxCode:t.tax.taxCode,txblGrossAmt:t.tax.txblGrossAmt,grossTaxAmt:t.tax.grossTaxAmt}:void 0,rolabor:t.rolabor?{ops:t.rolabor.ops?.map(e=>({opCode:e.opCode,jobNo:e.jobNo,custPayTypeFlag:e.custPayTypeFlag,custTxblNtxblFlag:e.custTxblNtxblFlag,warrPayTypeFlag:e.warrPayTypeFlag,warrTxblNtxblFlag:e.warrTxblNtxblFlag,intrPayTypeFlag:e.intrPayTypeFlag,intrTxblNtxblFlag:e.intrTxblNtxblFlag,vlrCode:e.vlrCode,bill:e.bill?{payType:e.bill.payType,jobTotalHrs:e.bill.jobTotalHrs,billTime:e.bill.billTime,billRate:e.bill.billRate}:void 0,ccc:e.ccc?{cause:e.ccc.cause,complaint:e.ccc.complaint,correction:e.ccc.correction}:void 0,amount:e.amount?{payType:e.amount.payType,amtType:e.amount.amtType,custPrice:e.amount.custPrice}:void 0}))}:void 0,ropart:t.ropart?{jobs:t.ropart.jobs?.map(e=>({opCode:e.opCode,jobNo:e.jobNo,lines:e.lines?.map(e=>({partNo:e.partNo,partNoDesc:e.partNoDesc,qtyOrd:e.partQty,sale:e.sale,cost:e.cost,addDeleteFlag:e.addDeleteFlag}))}))}:void 0,rogg:t.rogg?{roNo:t.rogg.roNo,ops:t.rogg.ops?.map(e=>({opCode:e.opCode,jobNo:e.jobNo,lines:e.lines?.map(e=>({breakOut:e.breakOut,itemType:e.itemType,itemDesc:e.itemDesc,custQty:e.custQty,warrQty:e.warrQty,intrQty:e.intrQty,custPayTypeFlag:e.custPayTypeFlag,warrPayTypeFlag:e.warrPayTypeFlag,intrPayTypeFlag:e.intrPayTypeFlag,custTxblNtxblFlag:e.custTxblNtxblFlag,warrTxblNtxblFlag:e.warrTxblNtxblFlag,intrTxblNtxblFlag:e.intrTxblNtxblFlag,amount:e.amount?{payType:e.amount.payType,amtType:e.amount.amtType,custPrice:e.amount.custPrice,dlrCost:e.amount.dlrCost}:void 0}))}))}:void 0,romisc:t.romisc?{roNo:t.romisc.roNo,ops:t.romisc.ops?.map(e=>({opCode:e.opCode,jobNo:e.jobNo,lines:e.lines?.map(e=>({miscCode:e.miscCode,custPayTypeFlag:e.custPayTypeFlag,warrPayTypeFlag:e.warrPayTypeFlag,intrPayTypeFlag:e.intrPayTypeFlag,custTxblNtxblFlag:e.custTxblNtxblFlag,warrTxblNtxblFlag:e.warrTxblNtxblFlag,intrTxblNtxblFlag:e.intrTxblNtxblFlag,codeAmt:e.codeAmt}))}))}:void 0};if(n.tax?.payType&&!["All","Cust","Intr","Warr"].includes(n.tax.payType))throw new j("tax.payType must be one of: All, Cust, Intr, Warr");if(n.rolabor?.ops?.some(e=>e.custTxblNtxblFlag&&!["T","N"].includes(e.custTxblNtxblFlag)||e.warrTxblNtxblFlag&&!["T","N"].includes(e.warrTxblNtxblFlag)||e.intrTxblNtxblFlag&&!["T","N"].includes(e.intrTxblNtxblFlag)))throw new j("Taxable flags (CustTxblNTxblFlag, WarrTxblNTxblFlag, IntrTxblNTxblFlag) must be 'T' or 'N'");if(n.rogg?.ops?.some(e=>e.lines?.some(e=>e.itemType&&!["G","P","S","F"].includes(e.itemType))))throw new j("rogg.ops.lines.itemType must be one of: G, P, S, F");const o={...r?.envelope||{},sender:{component:r?.envelope?.sender?.component??"Rome",task:r?.envelope?.sender?.task??"BSMRO",referenceId:r?.envelope?.sender?.referenceId??"Update",creatorNameCode:r?.envelope?.sender?.creatorNameCode??"RCI",senderNameCode:r?.envelope?.sender?.senderNameCode??"RCI"}},a=e({routing:r.routing,sender:o.sender,creationDateTime:o.creationDateTime,bodId:o.bodId});return{starXml:M.render('\n\n {{{ApplicationArea}}}\n \n \n {{#RO.roComment}}\n \n {{/RO.roComment}}\n\n {{#RO.estimate}}\n \n {{/RO.estimate}}\n\n {{#RO.tax}}\n \n {{/RO.tax}}\n \n\n {{#RO.rolabor}}\n \n {{#RO.rolabor.ops}}\n \n {{#bill}}\n \n {{/bill}}\n\n {{#ccc}}\n \n {{/ccc}}\n\n {{#amount}}\n \n {{/amount}}\n \n {{/RO.rolabor.ops}}\n \n {{/RO.rolabor}}\n\n {{#RO.ropart}}\n \n {{#RO.ropart.jobs}}\n \n {{#lines}}\n \n {{/lines}}\n \n {{/RO.ropart.jobs}}\n \n {{/RO.ropart}}\n\n {{#RO.rogg}}\n \n {{#RO.rogg.ops}}\n \n {{#lines}}\n \n {{#amount}}\n \n {{/amount}}\n \n {{/lines}}\n \n {{/RO.rogg.ops}}\n \n {{/RO.rogg}}\n\n {{#RO.romisc}}\n \n {{#RO.romisc.ops}}\n \n {{#lines}}\n \n {{/lines}}\n \n {{/RO.romisc.ops}}\n \n {{/RO.romisc}}\n \n\n',{ApplicationArea:a,RO:n}),routing:r.routing,envelope:o,postParse:v,xsdFilename:"rey_RomeUpdateBSMRepairOrderReq.xsd",elementName:"rey_RomeUpdateBSMRepairOrderReq"}}(t,r))}async getParts(t,r){return this._send(function(t={},r={}){const n=t.roNumber?String(t.roNumber).trim():void 0;if(!n)throw new j("getParts: roNumber required");const o=e({routing:r.routing,sender:{component:"Rome",task:"RCT",referenceId:"Query",creator:"RCI",senderName:"RCI"}});return{starXml:M.render('\n\n {{{ApplicationArea}}}\n \n\n',{ApplicationArea:o,RoNumber:n}),routing:r.routing,envelope:r.envelope,xsdFilename:"rey_RomeGetPartsReq.xsd",elementName:"rey_RomeGetPartsReq",postParse:e=>function(e){return e?.rey_RomeGetPartsResp?.RoParts?.map(e=>({partNumber:I(e,"PartNumber"),partDescription:I(e,"PartDescription"),quantityOrdered:I(e,"QuantityOrdered"),quantityShipped:I(e,"QuantityShipped"),price:I(e,"Price"),cost:I(e,"Cost"),processedFlag:I(e,"ProcessedFlag"),addOrDelete:I(e,"AddOrDelete")}))||[]}(e)}}(t,r))}}export{X as RRClient,q as errors}; diff --git a/server/rr/lib/types.cjs b/server/rr/lib/types.cjs new file mode 100644 index 000000000..9dcc48a23 --- /dev/null +++ b/server/rr/lib/types.cjs @@ -0,0 +1,3 @@ +'use strict'; +// CJS access point for JSDoc typedefs +module.exports = require('./types.js'); diff --git a/server/rr/lib/types.js b/server/rr/lib/types.js new file mode 100644 index 000000000..d16b60a27 --- /dev/null +++ b/server/rr/lib/types.js @@ -0,0 +1,144 @@ +/** + * @typedef {Object} RRClientConfig + * @property {string} baseUrl Base URL of the Rome endpoint + * @property {string} username WS-Security username + * @property {string} password WS-Security password + * @property {'Text'|'Digest'} [wssePasswordType] Password type (defaults to Text) + * @property {number} [timeoutMs] Request timeout in milliseconds + * @property {{max?: number}} [retries] Retry configuration + * @property {{ info:Function, warn:Function, error:Function, debug:Function }} [logger] Custom logger implementation + */ + +/** Dealer/store routing (required each call). */ +export const _routingDoc = null; +/** + * @typedef {Object} Routing + * @property {string} dealerNumber + * @property {string} [storeNumber] + * @property {string} [areaNumber] + */ + +/** Optional envelope overrides; BODId/CreationDateTime auto-generated if omitted. */ +export const _envelopeDoc = null; +/** + * @typedef {Object} EnvelopeOptions + * @property {string} [bodId] + * @property {string|Date} [creationDateTime] + * @property {{ component?: string, task?: string, referenceId?: string }} [sender] + */ + +/** Per-call options */ +export const _callOptionsDoc = null; +/** + * @typedef {Object} CallOptions + * @property {Routing} routing + * @property {EnvelopeOptions} [envelope] + */ + +/** @template T @typedef {Object} RRResult { @property {boolean} success @property {T} [data] @property {any} parsed @property {{request:string,response:string}} xml @property {{transaction?:any,roRecord?:any}} [statusBlocks] @property {any} [applicationArea] } */ + +/** @typedef {Object} CombinedSearchName { @property {string} [fname] @property {string} [lname] @property {string} [mname] @property {string} [name] } */ +/** @typedef {Object} CombinedSearchQuery + * @property {'phone'|'license'|'vin'|'name'|'nameRecId'|'stkNo'} kind Search kind (only one criterion allowed) + * @property {string|number|{phone:string}} [phone] Phone number criterion + * @property {string|number|{license:string}} [license] License plate criterion + * @property {string|number|{vin:string}} [vin] VIN criterion + * @property {CombinedSearchName} [name] Customer name criterion + * @property {string|number|{custId:string}|{nameRecId:string}} [nameRecId] Name record ID criterion + * @property {string|number|{stkNo:string}} [stkNo] Stock number criterion + * @property {number} [maxResults] Max results (capped at 50) + * @property {string} [make] Vehicle make filter + * @property {string|number} [model] Vehicle model filter + * @property {string|number} [year] Vehicle year filter +} */ +/** @typedef {Object} CombinedSearchVehicleDetail { @property {string} [LicNo] } */ +/** @typedef {Object} CombinedSearchVehicle { @property {string} [Vin] @property {string} [VehicleMake] @property {string|number} [VehicleYr] @property {string} [MdlNo] @property {string} [ModelDesc] @property {string} [Carline] @property {string} [ExtClrDesc] @property {string} [IntClrDesc] @property {string} [MakeName] @property {CombinedSearchVehicleDetail} [VehicleDetail] } */ +/** @typedef {Object} CombinedSearchVehicleWarranty { @property {string} [ContractNumber] @property {string} [ExpirationDate] @property {string|number} [ExpirationMileage] } */ +/** @typedef {Object} CombinedSearchAdvisorContactInfo { @property {string|number} [NameRecId] } */ +/** @typedef {Object} CombinedSearchAdvisor { @property {CombinedSearchAdvisorContactInfo} [ContactInfo] } */ +/** @typedef {Object} CombinedSearchVehicleServInfo { @property {string|number} [CustomerNo] @property {string|number} [SalesmanNo] @property {string|number} [InServiceDate] @property {string|number} [Mileage] @property {string} [TeamCode] @property {CombinedSearchVehicleWarranty} [VehExtWarranty] @property {CombinedSearchAdvisor} [Advisor] @property {string[]} [VehServComments] } */ +/** @typedef {Object} CombinedSearchServVehicle { @property {CombinedSearchVehicle} [Vehicle] @property {CombinedSearchVehicleServInfo} [VehicleServInfo] } */ +/** @typedef {Object} CombinedSearchNameId { @property {string|number} [NameRecId] @property {'I'|'B'} [IBFlag] @property {Object} [IndName] @property {Object} [BusName] } */ +/** @typedef {Object} CombinedSearchNameContactId { @property {CombinedSearchNameId} [NameId] @property {Object[]} [Address] @property {Object[]} [ContactOptions] @property {Object[]} [Phone] @property {Object[]} [Email] } */ +/** @typedef {Object} CombinedSearchMessage { @property {string|number} [MessageNo] @property {string} [Text] } */ +/** @typedef {Object} CombinedSearchBlock { @property {CombinedSearchNameContactId} [NameContactId] @property {CombinedSearchServVehicle[]} [ServVehicle] @property {CombinedSearchMessage[]} [Message] } */ + +/** @typedef {Object} CustomerAddress { @property {'P'|'B'|'M'|'S'|'D'} [type] @property {string} line1 @property {string} [line2] @property {string} [city] @property {string} [state] @property {string} [postalCode] @property {string} [county] @property {string} [country] } */ +/** @typedef {Object} CustomerPhone { @property {'H'|'W'|'M'|'C'|'F'} [type] @property {string|number} number @property {string|number} [extension] } */ +/** @typedef {Object} CustomerEmail { @property {string} address } */ +/** @typedef {Object} CustomerBirthDate { @property {'P'|'S'} [type] @property {string} date } */ +/** @typedef {Object} CustomerSSN { @property {'P'|'S'} [type] @property {string} ssn } */ +/** @typedef {Object} CustomerDriver { @property {'P'|'S'} [type] @property {string} licenseNumber @property {string} [licenseState] @property {string} [licenseExpDate] } */ +/** @typedef {Object} CustomerChild { @property {string} name } */ +/** @typedef {Object} CustomerPersonal { @property {'M'|'F'|'U'} [gender] @property {string} [otherName] @property {string} [anniversaryDate] @property {string} [employerName] @property {string} [employerPhone] @property {string} [occupation] @property {string} [optOut] @property {string} [optOutUse] @property {CustomerBirthDate[]} [birthDates] @property {CustomerSSN[]} [ssns] @property {CustomerDriver} [driver] @property {CustomerChild[]} [children] } */ +/** @typedef {Object} CustomerDmsFollowup { @property {string} type @property {string} value } */ +/** @typedef {Object} CustomerDmsInfo { @property {string} [taxExemptNum] @property {string} [salesTerritory] @property {string} [deliveryRoute] @property {string} [salesmanNum] @property {string} [lastContactMethod] @property {CustomerDmsFollowup[]} [followups] } */ +/** @typedef {Object} InsertCustomerPayload + * @property {'I'|'B'} [ibFlag] Individual/Business flag (auto-inferred if omitted) + * @property {'R'|'W'|'I'|'Retail'|'Wholesale'|'Internal'} [customerType] Customer type + * @property {string} [createdBy] Username or identifier creating the record + * @property {string} [customerName] Business name (alias for lastName when business) + * @property {string} [lastName] Last name or business name + * @property {string} [firstName] First name (required for individuals) + * @property {string} [midName] Middle name + * @property {string} [salut] Salutation + * @property {string} [suffix] Suffix + * @property {CustomerAddress[]} [addresses] Addresses list (line1 required per address) + * @property {CustomerPhone[]} [phones] Phone numbers list (number required per phone) + * @property {CustomerEmail[]} [emails] Email list (first entry used) + * @property {CustomerPersonal} [personal] Personal details + * @property {CustomerDmsInfo} [dms] DMS-specific supplemental info + */ +/** @typedef {InsertCustomerPayload & { nameRecId: string|number }} UpdateCustomerPayload */ +/** @typedef {Object} CustomerResponseData { @property {string|undefined} dmsRecKey @property {string|undefined} status @property {string|undefined} statusCode } */ + +/** @typedef {Object} ServiceVehicleDetail { @property {string} [licNo] } */ +/** @typedef {Object} ServiceVehicleWarranty { @property {string} [contractNumber] @property {string} [expirationDate] @property {string|number} [expirationMileage] } */ +/** @typedef {Object} ServiceVehicleAdvisorContactInfo { @property {string|number} nameRecId } */ +/** @typedef {Object} ServiceVehicleServInfo { @property {string|number} customerNo @property {string|number} [salesmanNo] @property {string|number} [inServiceDate] @property {string|number} [mileage] @property {string} [teamCode] @property {ServiceVehicleWarranty} [vehExtWarranty] @property {{contactInfo?: ServiceVehicleAdvisorContactInfo}} [advisor] } */ +/** @typedef {Object} InsertServiceVehiclePayload { @property {string} vin @property {string} [modelDesc] @property {string} [carline] @property {string} [extClrDesc] @property {string} [intClrDesc] @property {string} [trimDesc] @property {string} [bodyStyle] @property {string} [engineDesc] @property {string} [transDesc] @property {string|number} [year] @property {string|number} [odometer] @property {string} [odometerUnits] @property {ServiceVehicleDetail} [vehicleDetail] @property {ServiceVehicleServInfo} vehicleServInfo } */ +/** @typedef {Object} ServiceVehicleResponseData { @property {string|undefined} status @property {string|undefined} statusCode } */ + +/** @typedef {Object} RepairOrderEstimate { @property {string|number} [parts] @property {string|number} [labor] @property {string|number} [total] @property {string} [estimateType] } */ +/** @typedef {Object} RepairOrderTax { @property {'All'|'Cust'|'Intr'|'Warr'} [payType] @property {string} [taxCode] @property {string|number} [txblGrossAmt] @property {string|number} [grossTaxAmt] } */ +/** @typedef {Object} RepairOrderLaborBill { @property {'All'|'Cust'|'Intr'|'Warr'} [payType] @property {string|number} [jobTotalHrs] @property {string|number} [billTime] @property {string|number} [billRate] } */ +/** @typedef {Object} RepairOrderLaborCCC { @property {string} [cause] @property {string} [complaint] @property {string} [correction] } */ +/** @typedef {Object} RepairOrderLaborAmount { @property {'All'|'Cust'|'Intr'|'Warr'} [payType] @property {string} [amtType] @property {string|number} [custPrice] @property {string|number} [totalAmt] } */ +/** @typedef {Object} RepairOrderLaborOp { @property {string} [opCode] @property {string|number} [jobNo] @property {'T'|'N'} [custTxblNtxblFlag] @property {'T'|'N'} [warrTxblNtxblFlag] @property {'T'|'N'} [intrTxblNtxblFlag] @property {string} [custPayTypeFlag] @property {string} [warrPayTypeFlag] @property {string} [intrPayTypeFlag] @property {string} [vlrCode] @property {RepairOrderLaborBill} [bill] @property {RepairOrderLaborCCC} [ccc] @property {RepairOrderLaborAmount} [amount] } */ +/** @typedef {Object} RepairOrderLabor { @property {RepairOrderLaborOp[]} [ops] } */ +/** @typedef {Object} RepairOrderPartLine { @property {string} [partNo] @property {string} [partNoDesc] @property {string|number} [partQty] @property {string|number} [sale] @property {string|number} [cost] @property {string} [addDeleteFlag] } */ +/** @typedef {Object} RepairOrderPartJob { @property {string} [opCode] @property {string|number} [jobNo] @property {RepairOrderPartLine[]} [lines] } */ +/** @typedef {Object} RepairOrderPart { @property {RepairOrderPartJob[]} [jobs] } */ +/** @typedef {Object} RepairOrderGGLineAmount { @property {'All'|'Cust'|'Intr'|'Warr'} [payType] @property {string} [amtType] @property {string|number} [custPrice] @property {string|number} [dlrCost] } */ +/** @typedef {Object} RepairOrderGGLine { @property {string} [breakOut] @property {'G'|'P'|'S'|'F'} [itemType] @property {string} [itemDesc] @property {string|number} [custQty] @property {string|number} [warrQty] @property {string|number} [intrQty] @property {'T'|'N'} [custTxblNtxblFlag] @property {'T'|'N'} [warrTxblNtxblFlag] @property {'T'|'N'} [intrTxblNtxblFlag] @property {string} [custPayTypeFlag] @property {string} [warrPayTypeFlag] @property {string} [intrPayTypeFlag] @property {RepairOrderGGLineAmount} [amount] } */ +/** @typedef {Object} RepairOrderGGOp { @property {string} [opCode] @property {string|number} [jobNo] @property {RepairOrderGGLine[]} [lines] } */ +/** @typedef {Object} RepairOrderGG { @property {string|number} [roNo] @property {RepairOrderGGOp[]} [ops] } */ +/** @typedef {Object} RepairOrderMiscLine { @property {string} [miscCode] @property {'T'|'N'} [custTxblNtxblFlag] @property {'T'|'N'} [warrTxblNtxblFlag] @property {'T'|'N'} [intrTxblNtxblFlag] @property {string} [custPayTypeFlag] @property {string} [warrPayTypeFlag] @property {string} [intrPayTypeFlag] @property {string|number} [codeAmt] } */ +/** @typedef {Object} RepairOrderMiscOp { @property {string} [opCode] @property {string|number} [jobNo] @property {RepairOrderMiscLine[]} [lines] } */ +/** @typedef {Object} RepairOrderMisc { @property {string|number} [roNo] @property {RepairOrderMiscOp[]} [ops] } */ +/** @typedef {Object} CreateRepairOrderPayload + * @property {string|number} customerNo Customer number (CustNo) + * @property {string|number} departmentType Department type (DeptType) + * @property {string} vin Vehicle VIN (Vin) + * @property {string|number} outsdRoNo External RO identifier + * @property {string|number} [advisorNo] Advisor number + * @property {string|number} [tagNo] Tag number + * @property {string|number} [mileageIn] Mileage in value + * @property {string} [roComment] Repair order comment + * @property {RepairOrderEstimate} [estimate] Repair order estimate block + * @property {RepairOrderTax} [tax] Tax block + * @property {RepairOrderLabor} [rolabor] Labor operations + * @property {RepairOrderPart} [ropart] Parts jobs/lines + * @property {RepairOrderGG} [rogg] General goods lines + * @property {RepairOrderMisc} [romisc] Miscellaneous charges + */ +/** @typedef {Object} UpdateRepairOrderPayload { @property {'Y'|'N'} finalUpdate @property {string|number} outsdRoNo @property {string|number} [roNo] @property {string|number} [customerNo] @property {string|number} [tagNo] @property {string|number} [departmentType] @property {string} [vin] @property {string|number} [mileageIn] @property {string|number} [mileageOut] @property {string} [roComment] @property {RepairOrderEstimate} [estimate] @property {RepairOrderTax} [tax] @property {RepairOrderLabor} [rolabor] @property {RepairOrderPart} [ropart] @property {RepairOrderGG} [rogg] @property {RepairOrderMisc} [romisc] } */ +/** @typedef {Object} RepairOrderData { @property {string|undefined} status @property {string|undefined} date @property {string|undefined} time @property {string|undefined} outsdRoNo @property {string|undefined} dmsRoNo @property {string|undefined} errorMessage } */ + +/** @typedef {Object} GetAdvisorsParams { @property {'S'|'P'|'B'|'SERVICE'|'PARTS'|'BODY'|'BODYSHOP'|'BODY SHOP'} department @property {string|number} [advisorNumber] @property {number} [maxResults] } */ +/** @typedef {Object} AdvisorRow { @property {string|number|undefined} advisorId @property {string|undefined} firstName @property {string|undefined} lastName @property {'S'|'P'|'B'|undefined} department } */ +/** @typedef {Object} GetPartsParams { @property {string|number} roNumber } */ +/** @typedef {Object} PartRow { @property {string|undefined} partNumber @property {string|undefined} partDescription @property {string|number|undefined} quantityOrdered @property {string|number|undefined} quantityShipped @property {string|number|undefined} price @property {string|number|undefined} cost @property {string|undefined} processedFlag @property {string|undefined} addOrDelete } */ + +// Marker exports (no runtime impact) +export const _extendedTypesDoc = null; diff --git a/server/rr/lib/types/types.d.ts b/server/rr/lib/types/types.d.ts new file mode 100644 index 000000000..c37a04a51 --- /dev/null +++ b/server/rr/lib/types/types.d.ts @@ -0,0 +1,1035 @@ +/** + * @typedef {Object} RRClientConfig + * @property {string} baseUrl Base URL of the Rome endpoint + * @property {string} username WS-Security username + * @property {string} password WS-Security password + * @property {'Text'|'Digest'} [wssePasswordType] Password type (defaults to Text) + * @property {number} [timeoutMs] Request timeout in milliseconds + * @property {{max?: number}} [retries] Retry configuration + * @property {{ info:Function, warn:Function, error:Function, debug:Function }} [logger] Custom logger implementation + */ +/** Dealer/store routing (required each call). */ +export const _routingDoc: any; +/** + * @typedef {Object} Routing + * @property {string} dealerNumber + * @property {string} [storeNumber] + * @property {string} [areaNumber] + */ +/** Optional envelope overrides; BODId/CreationDateTime auto-generated if omitted. */ +export const _envelopeDoc: any; +/** + * @typedef {Object} EnvelopeOptions + * @property {string} [bodId] + * @property {string|Date} [creationDateTime] + * @property {{ component?: string, task?: string, referenceId?: string }} [sender] + */ +/** Per-call options */ +export const _callOptionsDoc: any; +/** + * @typedef {Object} CallOptions + * @property {Routing} routing + * @property {EnvelopeOptions} [envelope] + */ +/** @template T @typedef {Object} RRResult { @property {boolean} success @property {T} [data] @property {any} parsed @property {{request:string,response:string}} xml @property {{transaction?:any,roRecord?:any}} [statusBlocks] @property {any} [applicationArea] } */ +/** @typedef {Object} CombinedSearchName { @property {string} [fname] @property {string} [lname] @property {string} [mname] @property {string} [name] } */ +/** @typedef {Object} CombinedSearchQuery + * @property {'phone'|'license'|'vin'|'name'|'nameRecId'|'stkNo'} kind Search kind (only one criterion allowed) + * @property {string|number|{phone:string}} [phone] Phone number criterion + * @property {string|number|{license:string}} [license] License plate criterion + * @property {string|number|{vin:string}} [vin] VIN criterion + * @property {CombinedSearchName} [name] Customer name criterion + * @property {string|number|{custId:string}|{nameRecId:string}} [nameRecId] Name record ID criterion + * @property {string|number|{stkNo:string}} [stkNo] Stock number criterion + * @property {number} [maxResults] Max results (capped at 50) + * @property {string} [make] Vehicle make filter + * @property {string|number} [model] Vehicle model filter + * @property {string|number} [year] Vehicle year filter +} */ +/** @typedef {Object} CombinedSearchVehicleDetail { @property {string} [LicNo] } */ +/** @typedef {Object} CombinedSearchVehicle { @property {string} [Vin] @property {string} [VehicleMake] @property {string|number} [VehicleYr] @property {string} [MdlNo] @property {string} [ModelDesc] @property {string} [Carline] @property {string} [ExtClrDesc] @property {string} [IntClrDesc] @property {string} [MakeName] @property {CombinedSearchVehicleDetail} [VehicleDetail] } */ +/** @typedef {Object} CombinedSearchVehicleWarranty { @property {string} [ContractNumber] @property {string} [ExpirationDate] @property {string|number} [ExpirationMileage] } */ +/** @typedef {Object} CombinedSearchAdvisorContactInfo { @property {string|number} [NameRecId] } */ +/** @typedef {Object} CombinedSearchAdvisor { @property {CombinedSearchAdvisorContactInfo} [ContactInfo] } */ +/** @typedef {Object} CombinedSearchVehicleServInfo { @property {string|number} [CustomerNo] @property {string|number} [SalesmanNo] @property {string|number} [InServiceDate] @property {string|number} [Mileage] @property {string} [TeamCode] @property {CombinedSearchVehicleWarranty} [VehExtWarranty] @property {CombinedSearchAdvisor} [Advisor] @property {string[]} [VehServComments] } */ +/** @typedef {Object} CombinedSearchServVehicle { @property {CombinedSearchVehicle} [Vehicle] @property {CombinedSearchVehicleServInfo} [VehicleServInfo] } */ +/** @typedef {Object} CombinedSearchNameId { @property {string|number} [NameRecId] @property {'I'|'B'} [IBFlag] @property {Object} [IndName] @property {Object} [BusName] } */ +/** @typedef {Object} CombinedSearchNameContactId { @property {CombinedSearchNameId} [NameId] @property {Object[]} [Address] @property {Object[]} [ContactOptions] @property {Object[]} [Phone] @property {Object[]} [Email] } */ +/** @typedef {Object} CombinedSearchMessage { @property {string|number} [MessageNo] @property {string} [Text] } */ +/** @typedef {Object} CombinedSearchBlock { @property {CombinedSearchNameContactId} [NameContactId] @property {CombinedSearchServVehicle[]} [ServVehicle] @property {CombinedSearchMessage[]} [Message] } */ +/** @typedef {Object} CustomerAddress { @property {'P'|'B'|'M'|'S'|'D'} [type] @property {string} line1 @property {string} [line2] @property {string} [city] @property {string} [state] @property {string} [postalCode] @property {string} [county] @property {string} [country] } */ +/** @typedef {Object} CustomerPhone { @property {'H'|'W'|'M'|'C'|'F'} [type] @property {string|number} number @property {string|number} [extension] } */ +/** @typedef {Object} CustomerEmail { @property {string} address } */ +/** @typedef {Object} CustomerBirthDate { @property {'P'|'S'} [type] @property {string} date } */ +/** @typedef {Object} CustomerSSN { @property {'P'|'S'} [type] @property {string} ssn } */ +/** @typedef {Object} CustomerDriver { @property {'P'|'S'} [type] @property {string} licenseNumber @property {string} [licenseState] @property {string} [licenseExpDate] } */ +/** @typedef {Object} CustomerChild { @property {string} name } */ +/** @typedef {Object} CustomerPersonal { @property {'M'|'F'|'U'} [gender] @property {string} [otherName] @property {string} [anniversaryDate] @property {string} [employerName] @property {string} [employerPhone] @property {string} [occupation] @property {string} [optOut] @property {string} [optOutUse] @property {CustomerBirthDate[]} [birthDates] @property {CustomerSSN[]} [ssns] @property {CustomerDriver} [driver] @property {CustomerChild[]} [children] } */ +/** @typedef {Object} CustomerDmsFollowup { @property {string} type @property {string} value } */ +/** @typedef {Object} CustomerDmsInfo { @property {string} [taxExemptNum] @property {string} [salesTerritory] @property {string} [deliveryRoute] @property {string} [salesmanNum] @property {string} [lastContactMethod] @property {CustomerDmsFollowup[]} [followups] } */ +/** @typedef {Object} InsertCustomerPayload + * @property {'I'|'B'} [ibFlag] Individual/Business flag (auto-inferred if omitted) + * @property {'R'|'W'|'I'|'Retail'|'Wholesale'|'Internal'} [customerType] Customer type + * @property {string} [createdBy] Username or identifier creating the record + * @property {string} [customerName] Business name (alias for lastName when business) + * @property {string} [lastName] Last name or business name + * @property {string} [firstName] First name (required for individuals) + * @property {string} [midName] Middle name + * @property {string} [salut] Salutation + * @property {string} [suffix] Suffix + * @property {CustomerAddress[]} [addresses] Addresses list (line1 required per address) + * @property {CustomerPhone[]} [phones] Phone numbers list (number required per phone) + * @property {CustomerEmail[]} [emails] Email list (first entry used) + * @property {CustomerPersonal} [personal] Personal details + * @property {CustomerDmsInfo} [dms] DMS-specific supplemental info + */ +/** @typedef {InsertCustomerPayload & { nameRecId: string|number }} UpdateCustomerPayload */ +/** @typedef {Object} CustomerResponseData { @property {string|undefined} dmsRecKey @property {string|undefined} status @property {string|undefined} statusCode } */ +/** @typedef {Object} ServiceVehicleDetail { @property {string} [licNo] } */ +/** @typedef {Object} ServiceVehicleWarranty { @property {string} [contractNumber] @property {string} [expirationDate] @property {string|number} [expirationMileage] } */ +/** @typedef {Object} ServiceVehicleAdvisorContactInfo { @property {string|number} nameRecId } */ +/** @typedef {Object} ServiceVehicleServInfo { @property {string|number} customerNo @property {string|number} [salesmanNo] @property {string|number} [inServiceDate] @property {string|number} [mileage] @property {string} [teamCode] @property {ServiceVehicleWarranty} [vehExtWarranty] @property {{contactInfo?: ServiceVehicleAdvisorContactInfo}} [advisor] } */ +/** @typedef {Object} InsertServiceVehiclePayload { @property {string} vin @property {string} [modelDesc] @property {string} [carline] @property {string} [extClrDesc] @property {string} [intClrDesc] @property {string} [trimDesc] @property {string} [bodyStyle] @property {string} [engineDesc] @property {string} [transDesc] @property {string|number} [year] @property {string|number} [odometer] @property {string} [odometerUnits] @property {ServiceVehicleDetail} [vehicleDetail] @property {ServiceVehicleServInfo} vehicleServInfo } */ +/** @typedef {Object} ServiceVehicleResponseData { @property {string|undefined} status @property {string|undefined} statusCode } */ +/** @typedef {Object} RepairOrderEstimate { @property {string|number} [parts] @property {string|number} [labor] @property {string|number} [total] @property {string} [estimateType] } */ +/** @typedef {Object} RepairOrderTax { @property {'All'|'Cust'|'Intr'|'Warr'} [payType] @property {string} [taxCode] @property {string|number} [txblGrossAmt] @property {string|number} [grossTaxAmt] } */ +/** @typedef {Object} RepairOrderLaborBill { @property {'All'|'Cust'|'Intr'|'Warr'} [payType] @property {string|number} [jobTotalHrs] @property {string|number} [billTime] @property {string|number} [billRate] } */ +/** @typedef {Object} RepairOrderLaborCCC { @property {string} [cause] @property {string} [complaint] @property {string} [correction] } */ +/** @typedef {Object} RepairOrderLaborAmount { @property {'All'|'Cust'|'Intr'|'Warr'} [payType] @property {string} [amtType] @property {string|number} [custPrice] @property {string|number} [totalAmt] } */ +/** @typedef {Object} RepairOrderLaborOp { @property {string} [opCode] @property {string|number} [jobNo] @property {'T'|'N'} [custTxblNtxblFlag] @property {'T'|'N'} [warrTxblNtxblFlag] @property {'T'|'N'} [intrTxblNtxblFlag] @property {string} [custPayTypeFlag] @property {string} [warrPayTypeFlag] @property {string} [intrPayTypeFlag] @property {string} [vlrCode] @property {RepairOrderLaborBill} [bill] @property {RepairOrderLaborCCC} [ccc] @property {RepairOrderLaborAmount} [amount] } */ +/** @typedef {Object} RepairOrderLabor { @property {RepairOrderLaborOp[]} [ops] } */ +/** @typedef {Object} RepairOrderPartLine { @property {string} [partNo] @property {string} [partNoDesc] @property {string|number} [partQty] @property {string|number} [sale] @property {string|number} [cost] @property {string} [addDeleteFlag] } */ +/** @typedef {Object} RepairOrderPartJob { @property {string} [opCode] @property {string|number} [jobNo] @property {RepairOrderPartLine[]} [lines] } */ +/** @typedef {Object} RepairOrderPart { @property {RepairOrderPartJob[]} [jobs] } */ +/** @typedef {Object} RepairOrderGGLineAmount { @property {'All'|'Cust'|'Intr'|'Warr'} [payType] @property {string} [amtType] @property {string|number} [custPrice] @property {string|number} [dlrCost] } */ +/** @typedef {Object} RepairOrderGGLine { @property {string} [breakOut] @property {'G'|'P'|'S'|'F'} [itemType] @property {string} [itemDesc] @property {string|number} [custQty] @property {string|number} [warrQty] @property {string|number} [intrQty] @property {'T'|'N'} [custTxblNtxblFlag] @property {'T'|'N'} [warrTxblNtxblFlag] @property {'T'|'N'} [intrTxblNtxblFlag] @property {string} [custPayTypeFlag] @property {string} [warrPayTypeFlag] @property {string} [intrPayTypeFlag] @property {RepairOrderGGLineAmount} [amount] } */ +/** @typedef {Object} RepairOrderGGOp { @property {string} [opCode] @property {string|number} [jobNo] @property {RepairOrderGGLine[]} [lines] } */ +/** @typedef {Object} RepairOrderGG { @property {string|number} [roNo] @property {RepairOrderGGOp[]} [ops] } */ +/** @typedef {Object} RepairOrderMiscLine { @property {string} [miscCode] @property {'T'|'N'} [custTxblNtxblFlag] @property {'T'|'N'} [warrTxblNtxblFlag] @property {'T'|'N'} [intrTxblNtxblFlag] @property {string} [custPayTypeFlag] @property {string} [warrPayTypeFlag] @property {string} [intrPayTypeFlag] @property {string|number} [codeAmt] } */ +/** @typedef {Object} RepairOrderMiscOp { @property {string} [opCode] @property {string|number} [jobNo] @property {RepairOrderMiscLine[]} [lines] } */ +/** @typedef {Object} RepairOrderMisc { @property {string|number} [roNo] @property {RepairOrderMiscOp[]} [ops] } */ +/** @typedef {Object} CreateRepairOrderPayload + * @property {string|number} customerNo Customer number (CustNo) + * @property {string|number} departmentType Department type (DeptType) + * @property {string} vin Vehicle VIN (Vin) + * @property {string|number} outsdRoNo External RO identifier + * @property {string|number} [advisorNo] Advisor number + * @property {string|number} [tagNo] Tag number + * @property {string|number} [mileageIn] Mileage in value + * @property {string} [roComment] Repair order comment + * @property {RepairOrderEstimate} [estimate] Repair order estimate block + * @property {RepairOrderTax} [tax] Tax block + * @property {RepairOrderLabor} [rolabor] Labor operations + * @property {RepairOrderPart} [ropart] Parts jobs/lines + * @property {RepairOrderGG} [rogg] General goods lines + * @property {RepairOrderMisc} [romisc] Miscellaneous charges + */ +/** @typedef {Object} UpdateRepairOrderPayload { @property {'Y'|'N'} finalUpdate @property {string|number} outsdRoNo @property {string|number} [roNo] @property {string|number} [customerNo] @property {string|number} [tagNo] @property {string|number} [departmentType] @property {string} [vin] @property {string|number} [mileageIn] @property {string|number} [mileageOut] @property {string} [roComment] @property {RepairOrderEstimate} [estimate] @property {RepairOrderTax} [tax] @property {RepairOrderLabor} [rolabor] @property {RepairOrderPart} [ropart] @property {RepairOrderGG} [rogg] @property {RepairOrderMisc} [romisc] } */ +/** @typedef {Object} RepairOrderData { @property {string|undefined} status @property {string|undefined} date @property {string|undefined} time @property {string|undefined} outsdRoNo @property {string|undefined} dmsRoNo @property {string|undefined} errorMessage } */ +/** @typedef {Object} GetAdvisorsParams { @property {'S'|'P'|'B'|'SERVICE'|'PARTS'|'BODY'|'BODYSHOP'|'BODY SHOP'} department @property {string|number} [advisorNumber] @property {number} [maxResults] } */ +/** @typedef {Object} AdvisorRow { @property {string|number|undefined} advisorId @property {string|undefined} firstName @property {string|undefined} lastName @property {'S'|'P'|'B'|undefined} department } */ +/** @typedef {Object} GetPartsParams { @property {string|number} roNumber } */ +/** @typedef {Object} PartRow { @property {string|undefined} partNumber @property {string|undefined} partDescription @property {string|number|undefined} quantityOrdered @property {string|number|undefined} quantityShipped @property {string|number|undefined} price @property {string|number|undefined} cost @property {string|undefined} processedFlag @property {string|undefined} addOrDelete } */ +export const _extendedTypesDoc: any; +export type RRClientConfig = { + /** + * Base URL of the Rome endpoint + */ + baseUrl: string; + /** + * WS-Security username + */ + username: string; + /** + * WS-Security password + */ + password: string; + /** + * Password type (defaults to Text) + */ + wssePasswordType?: "Text" | "Digest"; + /** + * Request timeout in milliseconds + */ + timeoutMs?: number; + /** + * Retry configuration + */ + retries?: { + max?: number; + }; + /** + * Custom logger implementation + */ + logger?: { + info: Function; + warn: Function; + error: Function; + debug: Function; + }; +}; +export type Routing = { + dealerNumber: string; + storeNumber?: string; + areaNumber?: string; +}; +export type EnvelopeOptions = { + bodId?: string; + creationDateTime?: string | Date; + sender?: { + component?: string; + task?: string; + referenceId?: string; + }; +}; +export type CallOptions = { + routing: Routing; + envelope?: EnvelopeOptions; +}; +/** + * { + */ +export type RRResult = { + success: boolean; + data?: T; + parsed: any; + xml: { + request: string; + response: string; + }; + statusBlocks?: { + transaction?: any; + roRecord?: any; + }; + /** + * } + */ + applicationArea?: any; +}; +/** + * { + */ +export type CombinedSearchName = { + fname?: string; + lname?: string; + mname?: string; + /** + * } + */ + name?: string; +}; +export type CombinedSearchQuery = { + /** + * Search kind (only one criterion allowed) + */ + kind: "phone" | "license" | "vin" | "name" | "nameRecId" | "stkNo"; + /** + * Phone number criterion + */ + phone?: string | number | { + phone: string; + }; + /** + * License plate criterion + */ + license?: string | number | { + license: string; + }; + /** + * VIN criterion + */ + vin?: string | number | { + vin: string; + }; + /** + * Customer name criterion + */ + name?: CombinedSearchName; + /** + * Name record ID criterion + */ + nameRecId?: string | number | { + custId: string; + } | { + nameRecId: string; + }; + /** + * Stock number criterion + */ + stkNo?: string | number | { + stkNo: string; + }; + /** + * Max results (capped at 50) + */ + maxResults?: number; + /** + * Vehicle make filter + */ + make?: string; + /** + * Vehicle model filter + */ + model?: string | number; + /** + * Vehicle year filter + * } + */ + year?: string | number; +}; +/** + * { + */ +export type CombinedSearchVehicleDetail = { + /** + * } + */ + LicNo?: string; +}; +/** + * { + */ +export type CombinedSearchVehicle = { + Vin?: string; + VehicleMake?: string; + VehicleYr?: string | number; + MdlNo?: string; + ModelDesc?: string; + Carline?: string; + ExtClrDesc?: string; + IntClrDesc?: string; + MakeName?: string; + /** + * } + */ + VehicleDetail?: CombinedSearchVehicleDetail; +}; +/** + * { + */ +export type CombinedSearchVehicleWarranty = { + ContractNumber?: string; + ExpirationDate?: string; + /** + * } + */ + ExpirationMileage?: string | number; +}; +/** + * { + */ +export type CombinedSearchAdvisorContactInfo = { + /** + * } + */ + NameRecId?: string | number; +}; +/** + * { + */ +export type CombinedSearchAdvisor = { + /** + * } + */ + ContactInfo?: CombinedSearchAdvisorContactInfo; +}; +/** + * { + */ +export type CombinedSearchVehicleServInfo = { + CustomerNo?: string | number; + SalesmanNo?: string | number; + InServiceDate?: string | number; + Mileage?: string | number; + TeamCode?: string; + VehExtWarranty?: CombinedSearchVehicleWarranty; + Advisor?: CombinedSearchAdvisor; + /** + * } + */ + VehServComments?: string[]; +}; +/** + * { + */ +export type CombinedSearchServVehicle = { + Vehicle?: CombinedSearchVehicle; + /** + * } + */ + VehicleServInfo?: CombinedSearchVehicleServInfo; +}; +/** + * { + */ +export type CombinedSearchNameId = { + NameRecId?: string | number; + IBFlag?: "I" | "B"; + IndName?: any; + /** + * } + */ + BusName?: any; +}; +/** + * { + */ +export type CombinedSearchNameContactId = { + NameId?: CombinedSearchNameId; + Address?: any[]; + ContactOptions?: any[]; + Phone?: any[]; + /** + * } + */ + Email?: any[]; +}; +/** + * { + */ +export type CombinedSearchMessage = { + MessageNo?: string | number; + /** + * } + */ + Text?: string; +}; +/** + * { + */ +export type CombinedSearchBlock = { + NameContactId?: CombinedSearchNameContactId; + ServVehicle?: CombinedSearchServVehicle[]; + /** + * } + */ + Message?: CombinedSearchMessage[]; +}; +/** + * { + */ +export type CustomerAddress = { + type?: "P" | "B" | "M" | "S" | "D"; + line1: string; + line2?: string; + city?: string; + state?: string; + postalCode?: string; + county?: string; + /** + * } + */ + country?: string; +}; +/** + * { + */ +export type CustomerPhone = { + type?: "H" | "W" | "M" | "C" | "F"; + number: string | number; + /** + * } + */ + extension?: string | number; +}; +/** + * { + */ +export type CustomerEmail = { + /** + * } + */ + address: string; +}; +/** + * { + */ +export type CustomerBirthDate = { + type?: "P" | "S"; + /** + * } + */ + date: string; +}; +/** + * { + */ +export type CustomerSSN = { + type?: "P" | "S"; + /** + * } + */ + ssn: string; +}; +/** + * { + */ +export type CustomerDriver = { + type?: "P" | "S"; + licenseNumber: string; + licenseState?: string; + /** + * } + */ + licenseExpDate?: string; +}; +/** + * { + */ +export type CustomerChild = { + /** + * } + */ + name: string; +}; +/** + * { + */ +export type CustomerPersonal = { + gender?: "M" | "F" | "U"; + otherName?: string; + anniversaryDate?: string; + employerName?: string; + employerPhone?: string; + occupation?: string; + optOut?: string; + optOutUse?: string; + birthDates?: CustomerBirthDate[]; + ssns?: CustomerSSN[]; + driver?: CustomerDriver; + /** + * } + */ + children?: CustomerChild[]; +}; +/** + * { + */ +export type CustomerDmsFollowup = { + type: string; + /** + * } + */ + value: string; +}; +/** + * { + */ +export type CustomerDmsInfo = { + taxExemptNum?: string; + salesTerritory?: string; + deliveryRoute?: string; + salesmanNum?: string; + lastContactMethod?: string; + /** + * } + */ + followups?: CustomerDmsFollowup[]; +}; +export type InsertCustomerPayload = { + /** + * Individual/Business flag (auto-inferred if omitted) + */ + ibFlag?: "I" | "B"; + /** + * Customer type + */ + customerType?: "R" | "W" | "I" | "Retail" | "Wholesale" | "Internal"; + /** + * Username or identifier creating the record + */ + createdBy?: string; + /** + * Business name (alias for lastName when business) + */ + customerName?: string; + /** + * Last name or business name + */ + lastName?: string; + /** + * First name (required for individuals) + */ + firstName?: string; + /** + * Middle name + */ + midName?: string; + /** + * Salutation + */ + salut?: string; + /** + * Suffix + */ + suffix?: string; + /** + * Addresses list (line1 required per address) + */ + addresses?: CustomerAddress[]; + /** + * Phone numbers list (number required per phone) + */ + phones?: CustomerPhone[]; + /** + * Email list (first entry used) + */ + emails?: CustomerEmail[]; + /** + * Personal details + */ + personal?: CustomerPersonal; + /** + * DMS-specific supplemental info + */ + dms?: CustomerDmsInfo; +}; +export type UpdateCustomerPayload = InsertCustomerPayload & { + nameRecId: string | number; +}; +/** + * { + */ +export type CustomerResponseData = { + dmsRecKey: string | undefined; + status: string | undefined; + /** + * } + */ + statusCode: string | undefined; +}; +/** + * { + */ +export type ServiceVehicleDetail = { + /** + * } + */ + licNo?: string; +}; +/** + * { + */ +export type ServiceVehicleWarranty = { + contractNumber?: string; + expirationDate?: string; + /** + * } + */ + expirationMileage?: string | number; +}; +/** + * { + */ +export type ServiceVehicleAdvisorContactInfo = { + /** + * } + */ + nameRecId: string | number; +}; +/** + * { + */ +export type ServiceVehicleServInfo = { + customerNo: string | number; + salesmanNo?: string | number; + inServiceDate?: string | number; + mileage?: string | number; + teamCode?: string; + vehExtWarranty?: ServiceVehicleWarranty; + /** + * } + */ + advisor?: { + contactInfo?: ServiceVehicleAdvisorContactInfo; + }; +}; +/** + * { + */ +export type InsertServiceVehiclePayload = { + vin: string; + modelDesc?: string; + carline?: string; + extClrDesc?: string; + intClrDesc?: string; + trimDesc?: string; + bodyStyle?: string; + engineDesc?: string; + transDesc?: string; + year?: string | number; + odometer?: string | number; + odometerUnits?: string; + vehicleDetail?: ServiceVehicleDetail; + /** + * } + */ + vehicleServInfo: ServiceVehicleServInfo; +}; +/** + * { + */ +export type ServiceVehicleResponseData = { + status: string | undefined; + /** + * } + */ + statusCode: string | undefined; +}; +/** + * { + */ +export type RepairOrderEstimate = { + parts?: string | number; + labor?: string | number; + total?: string | number; + /** + * } + */ + estimateType?: string; +}; +/** + * { + */ +export type RepairOrderTax = { + payType?: "All" | "Cust" | "Intr" | "Warr"; + taxCode?: string; + txblGrossAmt?: string | number; + /** + * } + */ + grossTaxAmt?: string | number; +}; +/** + * { + */ +export type RepairOrderLaborBill = { + payType?: "All" | "Cust" | "Intr" | "Warr"; + jobTotalHrs?: string | number; + billTime?: string | number; + /** + * } + */ + billRate?: string | number; +}; +/** + * { + */ +export type RepairOrderLaborCCC = { + cause?: string; + complaint?: string; + /** + * } + */ + correction?: string; +}; +/** + * { + */ +export type RepairOrderLaborAmount = { + payType?: "All" | "Cust" | "Intr" | "Warr"; + amtType?: string; + custPrice?: string | number; + /** + * } + */ + totalAmt?: string | number; +}; +/** + * { + */ +export type RepairOrderLaborOp = { + opCode?: string; + jobNo?: string | number; + custTxblNtxblFlag?: "T" | "N"; + warrTxblNtxblFlag?: "T" | "N"; + intrTxblNtxblFlag?: "T" | "N"; + custPayTypeFlag?: string; + warrPayTypeFlag?: string; + intrPayTypeFlag?: string; + vlrCode?: string; + bill?: RepairOrderLaborBill; + ccc?: RepairOrderLaborCCC; + /** + * } + */ + amount?: RepairOrderLaborAmount; +}; +/** + * { + */ +export type RepairOrderLabor = { + /** + * } + */ + ops?: RepairOrderLaborOp[]; +}; +/** + * { + */ +export type RepairOrderPartLine = { + partNo?: string; + partNoDesc?: string; + partQty?: string | number; + sale?: string | number; + cost?: string | number; + /** + * } + */ + addDeleteFlag?: string; +}; +/** + * { + */ +export type RepairOrderPartJob = { + opCode?: string; + jobNo?: string | number; + /** + * } + */ + lines?: RepairOrderPartLine[]; +}; +/** + * { + */ +export type RepairOrderPart = { + /** + * } + */ + jobs?: RepairOrderPartJob[]; +}; +/** + * { + */ +export type RepairOrderGGLineAmount = { + payType?: "All" | "Cust" | "Intr" | "Warr"; + amtType?: string; + custPrice?: string | number; + /** + * } + */ + dlrCost?: string | number; +}; +/** + * { + */ +export type RepairOrderGGLine = { + breakOut?: string; + itemType?: "G" | "P" | "S" | "F"; + itemDesc?: string; + custQty?: string | number; + warrQty?: string | number; + intrQty?: string | number; + custTxblNtxblFlag?: "T" | "N"; + warrTxblNtxblFlag?: "T" | "N"; + intrTxblNtxblFlag?: "T" | "N"; + custPayTypeFlag?: string; + warrPayTypeFlag?: string; + intrPayTypeFlag?: string; + /** + * } + */ + amount?: RepairOrderGGLineAmount; +}; +/** + * { + */ +export type RepairOrderGGOp = { + opCode?: string; + jobNo?: string | number; + /** + * } + */ + lines?: RepairOrderGGLine[]; +}; +/** + * { + */ +export type RepairOrderGG = { + roNo?: string | number; + /** + * } + */ + ops?: RepairOrderGGOp[]; +}; +/** + * { + */ +export type RepairOrderMiscLine = { + miscCode?: string; + custTxblNtxblFlag?: "T" | "N"; + warrTxblNtxblFlag?: "T" | "N"; + intrTxblNtxblFlag?: "T" | "N"; + custPayTypeFlag?: string; + warrPayTypeFlag?: string; + intrPayTypeFlag?: string; + /** + * } + */ + codeAmt?: string | number; +}; +/** + * { + */ +export type RepairOrderMiscOp = { + opCode?: string; + jobNo?: string | number; + /** + * } + */ + lines?: RepairOrderMiscLine[]; +}; +/** + * { + */ +export type RepairOrderMisc = { + roNo?: string | number; + /** + * } + */ + ops?: RepairOrderMiscOp[]; +}; +export type CreateRepairOrderPayload = { + /** + * Customer number (CustNo) + */ + customerNo: string | number; + /** + * Department type (DeptType) + */ + departmentType: string | number; + /** + * Vehicle VIN (Vin) + */ + vin: string; + /** + * External RO identifier + */ + outsdRoNo: string | number; + /** + * Advisor number + */ + advisorNo?: string | number; + /** + * Tag number + */ + tagNo?: string | number; + /** + * Mileage in value + */ + mileageIn?: string | number; + /** + * Repair order comment + */ + roComment?: string; + /** + * Repair order estimate block + */ + estimate?: RepairOrderEstimate; + /** + * Tax block + */ + tax?: RepairOrderTax; + /** + * Labor operations + */ + rolabor?: RepairOrderLabor; + /** + * Parts jobs/lines + */ + ropart?: RepairOrderPart; + /** + * General goods lines + */ + rogg?: RepairOrderGG; + /** + * Miscellaneous charges + */ + romisc?: RepairOrderMisc; +}; +/** + * { + */ +export type UpdateRepairOrderPayload = { + finalUpdate: "Y" | "N"; + outsdRoNo: string | number; + roNo?: string | number; + customerNo?: string | number; + tagNo?: string | number; + departmentType?: string | number; + vin?: string; + mileageIn?: string | number; + mileageOut?: string | number; + roComment?: string; + estimate?: RepairOrderEstimate; + tax?: RepairOrderTax; + rolabor?: RepairOrderLabor; + ropart?: RepairOrderPart; + rogg?: RepairOrderGG; + /** + * } + */ + romisc?: RepairOrderMisc; +}; +/** + * { + */ +export type RepairOrderData = { + status: string | undefined; + date: string | undefined; + time: string | undefined; + outsdRoNo: string | undefined; + dmsRoNo: string | undefined; + /** + * } + */ + errorMessage: string | undefined; +}; +/** + * { + */ +export type GetAdvisorsParams = { + department: "S" | "P" | "B" | "SERVICE" | "PARTS" | "BODY" | "BODYSHOP" | "BODY SHOP"; + advisorNumber?: string | number; + /** + * } + */ + maxResults?: number; +}; +/** + * { + */ +export type AdvisorRow = { + advisorId: string | number | undefined; + firstName: string | undefined; + lastName: string | undefined; + /** + * } + */ + department: "S" | "P" | "B" | undefined; +}; +/** + * { + */ +export type GetPartsParams = { + /** + * } + */ + roNumber: string | number; +}; +/** + * { + */ +export type PartRow = { + partNumber: string | undefined; + partDescription: string | undefined; + quantityOrdered: string | number | undefined; + quantityShipped: string | number | undefined; + price: string | number | undefined; + cost: string | number | undefined; + processedFlag: string | undefined; + /** + * } + */ + addOrDelete: string | undefined; +}; diff --git a/server/rr/resolveRRConfigHttp.js b/server/rr/resolveRRConfigHttp.js new file mode 100644 index 000000000..42746d36e --- /dev/null +++ b/server/rr/resolveRRConfigHttp.js @@ -0,0 +1,32 @@ +const { getRRConfigForBodyshop } = require("./rr-config"); +const { RrApiError } = require("./rr-error"); + +/** + * Extracts bodyshopId from body, job, or header and loads RR config. + * @returns {Promise<{ bodyshopId: string, config: any }>} + */ +async function resolveRRConfigHttp(req) { + const body = req?.body || {}; + + const fromBody = body.bodyshopId; + const fromJob = body.job && (body.job.shopid || body.job.bodyshopId); + const fromHeader = typeof req.get === "function" ? req.get("x-bodyshop-id") : undefined; + + const bodyshopId = fromBody || fromJob || fromHeader; + + if (!bodyshopId) { + throw new RrApiError( + "Missing bodyshopId (expected in body.bodyshopId, body.job.shopid/bodyshopId, or x-bodyshop-id header)", + "BAD_REQUEST" + ); + } + + const config = await getRRConfigForBodyshop(bodyshopId); + if (!config?.dealerNumber) { + throw new RrApiError(`RR config not found for bodyshopId=${bodyshopId} (missing dealerNumber)`, "NOT_CONFIGURED"); + } + + return { bodyshopId, config }; +} + +module.exports = { resolveRRConfigHttp }; diff --git a/server/rr/rr-client.js b/server/rr/rr-client.js new file mode 100644 index 000000000..66b51df95 --- /dev/null +++ b/server/rr/rr-client.js @@ -0,0 +1,25 @@ +const { RRClient } = require("./lib/index.cjs"); + +/** + * Build an RR client using env credentials. + * @param {{logger?: {debug?:Function,info?:Function,warn?:Function,error?:Function}}} opts + */ +function makeRRClient({ logger } = {}) { + const baseUrl = process.env.RR_BASE_URL; + const username = process.env.RR_USERNAME; + const password = process.env.RR_PASSWORD; + + if (!baseUrl || !username || !password) { + throw new Error("RR creds missing (RR_BASE_URL, RR_USERNAME, RR_PASSWORD)."); + } + + return new RRClient({ + baseUrl, + username, + password, + logger + // retries: { max: 3 }, // optional: override retry policy + }); +} + +module.exports = { makeRRClient }; diff --git a/server/rr/rr-config.js b/server/rr/rr-config.js index fc8366860..9d1011cf4 100644 --- a/server/rr/rr-config.js +++ b/server/rr/rr-config.js @@ -1,81 +1,63 @@ -// server/rr/rr-config.js +/** + * Loads per-bodyshop RR routing from Hasura. + * Expected table fields (adapt if your schema differs): + * - bodyshops.id = $bodyshopId + * - bodyshops.rr_dealerid (string) + * - bodyshops.rr_configuration JSON { storeNumber?, branchNumber? } + * + * Requires env: + * HASURA_GRAPHQL_ENDPOINT, HASURA_ADMIN_SECRET + */ const { GraphQLClient, gql } = require("graphql-request"); -/** - * Fetch the bodyshop row (dealer + per-shop RR json). - * No fallback to env for dealer/store/branch. - */ -async function fetchBodyshopRRRow(bodyshopId) { - if (!bodyshopId) throw new Error("Missing bodyshopId for RR config."); +const HASURA_URL = process.env.HASURA_GRAPHQL_ENDPOINT || process.env.HASURA_URL; +const HASURA_SECRET = process.env.HASURA_ADMIN_SECRET || process.env.HASURA_GRAPHQL_ADMIN_SECRET; - const endpoint = process.env.GRAPHQL_ENDPOINT; - if (!endpoint) throw new Error("GRAPHQL_ENDPOINT env var is required."); - - const headers = {}; - if (process.env.HASURA_ADMIN_SECRET) { - headers["x-hasura-admin-secret"] = process.env.HASURA_ADMIN_SECRET; - } else if (process.env.GRAPHQL_BEARER) { - headers["authorization"] = `Bearer ${process.env.GRAPHQL_BEARER}`; - } - - const client = new GraphQLClient(endpoint, { headers }); - - const Q = gql` - query BodyshopRR($id: uuid!) { - bodyshops_by_pk(id: $id) { - rr_dealerid - rr_configuration - } - } - `; - - const { bodyshops_by_pk: bs } = await client.request(Q, { id: bodyshopId }); - if (!bs) throw new Error("Bodyshop not found."); - if (!bs.rr_dealerid) throw new Error("Bodyshop is not configured for RR (missing rr_dealerid)."); - - let cfgJson = bs.rr_configuration || {}; - if (typeof cfgJson === "string") { - try { - cfgJson = JSON.parse(cfgJson); - } catch { - cfgJson = {}; - } - } - - return { - dealerNumber: bs.rr_dealerid, - storeNumber: cfgJson.storeNumber, - branchNumber: cfgJson.branchNumber - }; +if (!HASURA_URL || !HASURA_SECRET) { + // Warn loudly at startup; you can hard fail if you prefer + console.warn("[RR] HASURA env not set (HASURA_GRAPHQL_ENDPOINT / HASURA_ADMIN_SECRET)."); } +const client = HASURA_URL + ? new GraphQLClient(HASURA_URL, { + headers: { "x-hasura-admin-secret": HASURA_SECRET } + }) + : null; + +const Q_BODYSHOP_RR = gql` + query RR_Config($id: uuid!) { + bodyshops_by_pk(id: $id) { + id + rr_dealerid + rr_configuration + } + } +`; + /** - * Build the full RR config object used by downstream code. - * - Dealer/Store/Branch: from DB (required) - * - Transport/BaseURL/creds/PPSysId: from env (deployment-wide) + * @param {string} bodyshopId + * @returns {Promise<{dealerNumber:string, storeNumber?:string, areaNumber?:string}>} */ async function getRRConfigForBodyshop(bodyshopId) { - const { dealerNumber, storeNumber, branchNumber } = await fetchBodyshopRRRow(bodyshopId); + if (!client) throw new Error("Hasura client not configured."); - const rrTransport = (process.env.RR_TRANSPORT || "STAR").toUpperCase(); - return { - // Per-bodyshop (DB) - dealerNumber, - storeNumber, - branchNumber, + const data = await client.request(Q_BODYSHOP_RR, { id: bodyshopId }); + const row = data?.bodyshops_by_pk; + if (!row) throw new Error(`Bodyshop not found: ${bodyshopId}`); - // Duplicate snake_case for legacy call-sites that expect it - dealer_number: dealerNumber, - store_number: storeNumber, - branch_number: branchNumber, + const dealerNumber = row.rr_dealerid; - // Deployment-wide (env) - baseUrl: process.env.RR_BASE_URL, - username: process.env.RR_USERNAME, - password: process.env.RR_PASSWORD, - ppsysId: process.env.RR_PPSYSID, - rrTransport - }; + const cfg = row.rr_configuration || {}; + + if (!dealerNumber) { + throw new Error(`RR not configured for bodyshop ${bodyshopId} (missing rr_dealerid).`); + } + + // The RR client expects "areaNumber" (Rome "branch") + const storeNumber = cfg.storeNumber || cfg.store_no || cfg.store || null; + const areaNumber = cfg.branchNumber || cfg.branch_no || cfg.branch || null; + + return { dealerNumber, storeNumber, areaNumber }; } module.exports = { getRRConfigForBodyshop }; diff --git a/server/rr/rr-constants.js b/server/rr/rr-constants.js deleted file mode 100644 index 280bc9396..000000000 --- a/server/rr/rr-constants.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * STAR-only constants for Reynolds & Reynolds (Rome/RCI) - * Used by rr-helpers.js to build and send SOAP requests. - * - * IMPORTANT: - * - Only rr-test.js should fall back to ENV for dealer/store/branch. - * - All runtime code (sockets/routes/jobs) must pass per-bodyshop - * values from the database (see rr-config.js#getRRConfigForBodyshop). - */ - -exports.RR_NS = Object.freeze({ - SOAP_ENV: "http://schemas.xmlsoap.org/soap/envelope/", - SOAP_ENC: "http://schemas.xmlsoap.org/soap/encoding/", - XSD: "http://www.w3.org/2001/XMLSchema", - XSI: "http://www.w3.org/2001/XMLSchema-instance", - WSSE: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", - WSU: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", - STAR_TRANSPORT: "http://www.starstandards.org/webservices/2005/10/transport", - STAR_BUSINESS: "http://www.starstandards.org/STAR" -}); - -const RR_STAR_SOAP_ACTION = "http://www.starstandards.org/webservices/2005/10/transport/ProcessMessage"; -exports.RR_SOAP_ACTION = RR_STAR_SOAP_ACTION; - -const RR_SOAP_HEADERS = { - "Content-Type": "text/xml; charset=utf-8", - SOAPAction: RR_STAR_SOAP_ACTION -}; -// Export if other modules need default STAR headers -exports.RR_SOAP_HEADERS = RR_SOAP_HEADERS; - -// All STAR-supported actions (mapped to Mustache templates) -exports.RR_ACTIONS = Object.freeze({ - CombinedSearch: { template: "CombinedSearch" }, - GetAdvisors: { template: "GetAdvisors" }, - GetParts: { template: "GetParts" }, - InsertCustomer: { template: "InsertCustomer" }, - InsertServiceVehicle: { template: "InsertServiceVehicle" }, - CreateRepairOrder: { template: "CreateRepairOrder" }, - UpdateCustomer: { template: "UpdateCustomer" }, - UpdateRepairOrder: { template: "UpdateRepairOrder" } -}); - -/** - * Base config loader (environment-driven) - * - * ⚠️ Policy: - * - Only rr-test.js should rely on the ENV values for dealer/store/branch. - * - All other call sites must inject per-bodyshop values from DB. - */ -exports.getBaseRRConfig = function getBaseRRConfig() { - return { - baseUrl: process.env.RR_BASE_URL, - username: process.env.RR_USERNAME, - password: process.env.RR_PASSWORD, - ppsysId: process.env.RR_PPSYSID, // optional legacy identifier - - // ❗ These are ONLY for rr-test.js fallback. - dealerNumber: process.env.RR_DEALER_NUMBER, - storeNumber: process.env.RR_STORE_NUMBER, - branchNumber: process.env.RR_BRANCH_NUMBER || "01", - - wssePasswordType: process.env.RR_WSSE_PASSWORD_TYPE || "Text", - timeout: Number(process.env.RR_TIMEOUT_MS || 30000) - }; -}; - -/** - * Normalize dealer/store/branch field names (camelCase vs snake_case). - * Safe to use in helpers to tolerate mixed callers during migration. - */ -exports.normalizeRRDealerFields = function normalizeRRDealerFields(cfg = {}) { - const dealerNumber = cfg.dealerNumber ?? cfg.dealer_number; - const storeNumber = cfg.storeNumber ?? cfg.store_number; - const branchNumber = cfg.branchNumber ?? cfg.branch_number; - return { dealerNumber, storeNumber, branchNumber }; -}; diff --git a/server/rr/rr-customer.js b/server/rr/rr-customer.js index 71f09c993..34e7523f1 100644 --- a/server/rr/rr-customer.js +++ b/server/rr/rr-customer.js @@ -1,99 +1,17 @@ -/** - * @file rr-customer.js - * @description Rome (Reynolds & Reynolds) Customer Insert / Update integration. - * Maps internal customer objects to Rome XML schemas and executes RCI calls. - */ +const { withClient } = require("../rr/withClient"); -const { MakeRRCall } = require("./rr-helpers"); -const { mapCustomerInsert, mapCustomerUpdate } = require("./rr-mappers"); -const RRLogger = require("./rr-logger"); -const { RrApiError } = require("./rr-error"); - -/** - * Insert a new customer into Rome. - * @param {Socket} socket - WebSocket connection for logging context - * @param {Object} customer - Hasura customer record - * @param {Object} bodyshopConfig - DMS configuration - * @returns {Promise} result - */ -async function insertCustomer(socket, customer, bodyshopConfig) { - const action = "InsertCustomer"; - const template = "InsertCustomer"; - - try { - RRLogger(socket, "info", `Starting RR ${action} for customer ${customer.id}`); - - const data = mapCustomerInsert(customer, bodyshopConfig); - - const resultXml = await MakeRRCall({ - action, - body: { template, data }, - socket, - dealerConfig: bodyshopConfig, - jobid: customer.id - }); - - RRLogger(socket, "debug", `${action} completed successfully`, { customerId: customer.id }); - - return { - success: true, - dms: "Rome", - action, - customerId: customer.id, - xml: resultXml - }; - } catch (error) { - RRLogger(socket, "error", `Error in ${action} for customer ${customer.id}`, { - message: error.message, - stack: error.stack - }); - throw new RrApiError(`RR InsertCustomer failed: ${error.message}`, "INSERT_CUSTOMER_ERROR"); - } +async function insertCustomer({ bodyshopId, payload }) { + return withClient(bodyshopId, async (client, routing) => { + const res = await client.insertCustomer(payload, { routing }); + return res; + }); } -/** - * Update an existing customer in Rome. - * @param {Socket} socket - * @param {Object} customer - * @param {Object} bodyshopConfig - * @returns {Promise} - */ -async function updateCustomer(socket, customer, bodyshopConfig) { - const action = "UpdateCustomer"; - const template = "UpdateCustomer"; - - try { - RRLogger(socket, "info", `Starting RR ${action} for customer ${customer.id}`); - - const data = mapCustomerUpdate(customer, bodyshopConfig); - - const resultXml = await MakeRRCall({ - action, - body: { template, data }, - socket, - dealerConfig: bodyshopConfig, - jobid: customer.id - }); - - RRLogger(socket, "debug", `${action} completed successfully`, { customerId: customer.id }); - - return { - success: true, - dms: "Rome", - action, - customerId: customer.id, - xml: resultXml - }; - } catch (error) { - RRLogger(socket, "error", `Error in ${action} for customer ${customer.id}`, { - message: error.message, - stack: error.stack - }); - throw new RrApiError(`RR UpdateCustomer failed: ${error.message}`, "UPDATE_CUSTOMER_ERROR"); - } +async function updateCustomer({ bodyshopId, payload }) { + return withClient(bodyshopId, async (client, routing) => { + const res = await client.updateCustomer(payload, { routing }); + return res; + }); } -module.exports = { - insertCustomer, - updateCustomer -}; +module.exports = { insertCustomer, updateCustomer }; diff --git a/server/rr/rr-error.js b/server/rr/rr-error.js index f801a121d..6f345f9b7 100644 --- a/server/rr/rr-error.js +++ b/server/rr/rr-error.js @@ -1,48 +1,11 @@ -/** - * @file rr-error.js - * @description Custom error types for the Reynolds & Reynolds (Rome) integration. - */ - -/** - * Base RR API Error class — always structured with a message and a code. - */ class RrApiError extends Error { - /** - * @param {string} message - Human-readable message - * @param {string} [code="RR_ERROR"] - Short machine-readable error code - * @param {Object} [details] - Optional structured metadata - */ - constructor(message, code = "RR_ERROR", details = {}) { + constructor(message, code, meta) { super(message); this.name = "RrApiError"; - this.code = code; - this.details = details; - } - - toJSON() { - return { - name: this.name, - code: this.code, - message: this.message, - details: this.details - }; + this.code = code || "RR_API_ERROR"; + if (meta) this.meta = meta; + Error.captureStackTrace?.(this, RrApiError); } } -/** - * Helper to normalize thrown errors into a consistent RrApiError instance. - */ -function toRrError(err, defaultCode = "RR_ERROR") { - if (!err) return new RrApiError("Unknown RR error", defaultCode); - if (err instanceof RrApiError) return err; - if (typeof err === "string") return new RrApiError(err, defaultCode); - const msg = err.message || "Unspecified RR error"; - const code = err.code || defaultCode; - const details = err.details || {}; - return new RrApiError(msg, code, details); -} - -module.exports = { - RrApiError, - toRrError -}; +module.exports = { RrApiError }; diff --git a/server/rr/rr-helpers.js b/server/rr/rr-helpers.js deleted file mode 100644 index 58c8fc199..000000000 --- a/server/rr/rr-helpers.js +++ /dev/null @@ -1,351 +0,0 @@ -/** - * STAR-only SOAP transport + template rendering for Reynolds & Reynolds (Rome/RCI). - * - Renders Mustache STAR business templates (rey_*Req rooted with STAR ns) - * - Builds STAR SOAP envelope (ProcessMessage/payload/content + ApplicationArea) - * - Posts to RCI endpoint with STAR SOAPAction (full URI) - * - Parses XML response (faults + STAR payload result) - */ - -"use strict"; - -const fs = require("fs/promises"); -const path = require("path"); -const axios = require("axios"); -const mustache = require("mustache"); -const { XMLParser } = require("fast-xml-parser"); -const RRLogger = require("./rr-logger"); -const { - RR_ACTIONS, - RR_SOAP_HEADERS, - RR_SOAP_ACTION, - RR_NS, - getBaseRRConfig, - normalizeRRDealerFields -} = require("./rr-constants"); -const { RrApiError } = require("./rr-error"); -const xmlFormatter = require("xml-formatter"); - -/** - * Collapse Mustache-induced whitespace and pretty print. - * - strips inner XML decl - * - removes lines that are only whitespace - * - collapses inter-tag whitespace - * - formats with consistent indentation - */ -function prettyPrintXml(xml) { - let s = xml; - - // strip any inner XML declaration - s = s.replace(/^\s*<\?xml[^>]*\?>\s*/i, ""); - - // remove lines that are only whitespace - s = s.replace(/^[\t ]*(?:\r?\n)/gm, ""); - - // collapse whitespace strictly between tags (not inside text nodes) - s = s.replace(/>\s+<"); - - // final pretty print - return xmlFormatter(s, { - indentation: " ", - collapseContent: true, // keep short elements on one line - lineSeparator: "\n", - strictMode: false - }); -} - -// ---------- Public action map (compat with rr-test.js) ---------- -const RRActions = Object.fromEntries(Object.entries(RR_ACTIONS).map(([k]) => [k, { action: k }])); - -// ---------- Template cache ---------- -const templateCache = new Map(); - -async function loadTemplate(templateName) { - if (templateCache.has(templateName)) return templateCache.get(templateName); - const filePath = path.join(__dirname, "xml-templates", `${templateName}.xml`); - const tpl = await fs.readFile(filePath, "utf8"); - templateCache.set(templateName, tpl); - return tpl; -} - -async function renderXmlTemplate(templateName, data) { - const tpl = await loadTemplate(templateName); - // Render and strip any XML declaration to keep a single root element for the BOD - const rendered = mustache.render(tpl, { STAR_NS: RR_NS.STAR_BUSINESS, ...(data || {}) }); - return rendered.replace(/^\s*<\?xml[^>]*\?>\s*/i, ""); -} - -/** - * Resolve RR config for STAR transport. - * - * Policy: - * - Base (transport) settings (baseUrl, username, password, ppsysId, wssePasswordType, timeout) come from env. - * - Dealer identifiers (dealer/store/branch) MUST be provided by the caller (DB-driven). - * - We DO NOT fall back to env for dealer/store/branch here. Only rr-test.js is allowed to do that. - */ -async function resolveRRConfig(_socket, bodyshopConfig) { - const baseEnv = getBaseRRConfig(); - - const { dealerNumber, storeNumber, branchNumber } = normalizeRRDealerFields(bodyshopConfig || {}); - if (!dealerNumber || !storeNumber || !branchNumber) { - throw new Error( - "Missing dealer/store/branch in RR config. These must be loaded from the database (no env fallback here)." - ); - } - - return { - baseUrl: bodyshopConfig?.baseUrl || baseEnv.baseUrl, - username: bodyshopConfig?.username || baseEnv.username, - password: bodyshopConfig?.password || baseEnv.password, - ppsysId: bodyshopConfig?.ppsysId || baseEnv.ppsysId, - wssePasswordType: bodyshopConfig?.wssePasswordType || baseEnv.wssePasswordType || "Text", - timeout: baseEnv.timeout, - - // canonical identifiers (DB-driven only) - dealerNumber, - storeNumber, - branchNumber - }; -} - -// ---------- Response parsing ---------- -function parseRRResponse(xml) { - const parser = new XMLParser({ - ignoreAttributes: false, - removeNSPrefix: true - }); - - const doc = parser.parse(xml); - - // Envelope/Body - const body = - doc?.Envelope?.Body || - doc?.["soapenv:Envelope"]?.["soapenv:Body"] || - doc?.["SOAP-ENV:Envelope"]?.["SOAP-ENV:Body"] || - doc?.["S:Envelope"]?.["S:Body"] || - doc?.Body || - doc; - - // SOAP Fault? - const fault = body?.Fault || body?.["soap:Fault"]; - if (fault) { - return { - success: false, - code: fault.faultcode || "SOAP_FAULT", - message: fault.faultstring || "Unknown SOAP Fault", - raw: xml - }; - } - - // STAR transport path: ProcessMessage/payload/content - const processMessage = body?.ProcessMessage || body?.["ns0:ProcessMessage"] || body?.["ProcessMessageResponse"]; - - if (processMessage?.payload?.content) { - const content = processMessage.payload.content; - if (content && typeof content === "object") { - const keys = Object.keys(content).filter((k) => k !== "@_id"); - const respKey = keys.find((k) => /Resp$/.test(k)) || (keys[0] === "ApplicationArea" && keys[1]) || keys[0]; - - const respNode = respKey ? content[respKey] : content; - - const resultCode = respNode?.ResultCode || respNode?.ResponseCode || respNode?.StatusCode || "OK"; - const resultMessage = respNode?.ResultMessage || respNode?.ResponseMessage || respNode?.StatusMessage || null; - - return { - success: ["OK", "Success"].includes(String(resultCode)), - code: resultCode, - message: resultMessage, - raw: xml, - parsed: respNode - }; - } - } - - // Fallback: first element under Body (just in case) - const keys = body && typeof body === "object" ? Object.keys(body) : []; - const respNode = keys.length ? body[keys[0]] : body; - - const resultCode = respNode?.ResultCode || respNode?.ResponseCode || "OK"; - const resultMessage = respNode?.ResultMessage || respNode?.ResponseMessage || null; - - return { - success: resultCode === "OK" || resultCode === "Success", - code: resultCode, - message: resultMessage, - raw: xml, - parsed: respNode - }; -} - -// ---------- STAR envelope helpers ---------- -function wrapWithApplicationArea(innerXml, { CreationDateTime, BODId, Sender, Destination }) { - // Strip any inner XML declaration (idempotent) - let xml = innerXml.replace(/^\s*<\?xml[^>]*\?>\s*/i, ""); - - const appArea = ` - - ${CreationDateTime} - ${BODId} - - ${Sender?.Component ? `${Sender.Component}` : ""} - ${Sender?.Task ? `${Sender.Task}` : ""} - ${Sender?.ReferenceId ? `${Sender.ReferenceId}` : ""} - - - RR - ${Destination?.DealerNumber ? `${Destination.DealerNumber}` : ""} - ${Destination?.StoreNumber ? `${Destination.StoreNumber}` : ""} - ${Destination?.AreaNumber ? `${Destination.AreaNumber}` : ""} - -`.trim(); - - // Inject right after the opening tag of the root element - xml = xml.replace(/^(\s*<[^!?][^>]*>)/, `$1\n${appArea}\n`); - - return xml; -} - -const TASK_BY_ACTION = { - CreateRepairOrder: { Task: "BSMRO", ReferenceId: "Insert" }, - UpdateRepairOrder: { Task: "BSMRO", ReferenceId: "Update" }, - InsertCustomer: { Task: "CU", ReferenceId: "Insert" }, - UpdateCustomer: { Task: "CU", ReferenceId: "Update" }, - InsertServiceVehicle: { Task: "SV", ReferenceId: "Insert" } -}; - -async function buildStarEnvelope(innerBusinessXml, creds, appArea = {}, action) { - const now = new Date().toISOString(); - - // Derive sensible defaults for Sender from action, unless caller provided explicit values - const senderDefaults = - appArea?.Sender || - (action && TASK_BY_ACTION[action] ? { Component: "Rome", ...TASK_BY_ACTION[action] } : { Component: "Rome" }); - - const payloadWithAppArea = wrapWithApplicationArea(innerBusinessXml, { - CreationDateTime: appArea.CreationDateTime || now, - BODId: appArea.BODId || `BOD-${Date.now()}`, - Sender: senderDefaults, - Destination: appArea.Destination || { - DealerNumber: creds.dealerNumber, - StoreNumber: String(creds.storeNumber ?? "").padStart(2, "0"), - AreaNumber: String(creds.branchNumber || "01").padStart(2, "0") - } - }); - - return ` - - - - - ${creds.username} - ${creds.password} - - - - - - - - ${payloadWithAppArea} - - - - -`; -} - -// ---------- Main transport (STAR only) ---------- -async function MakeRRCall({ - action, - body, - appArea, // <-- allow explicit ApplicationArea overrides at the top level - socket, - dealerConfig, // required in runtime code; rr-test.js can still pass env-inflated cfg - retries = 1, - jobid -}) { - if (!action || !RR_ACTIONS[action]) { - throw new Error(`Invalid RR action: ${action}`); - } - - // Prefer explicit dealerConfig from caller; otherwise enforce DB-provided config via resolveRRConfig - const cfg = dealerConfig || (await resolveRRConfig(socket, undefined)); - const baseUrl = cfg.baseUrl; - if (!baseUrl) throw new Error("Missing RR base URL"); - - // Render STAR business body - const templateName = body?.template || action; - const renderedBusiness = await renderXmlTemplate(templateName, body?.data || {}); - - // Build STAR envelope (use explicit appArea if provided; else accept body.appArea; else derive from action) - const selectedAppArea = appArea || body?.appArea || {}; - const envelope = await buildStarEnvelope(renderedBusiness, cfg, selectedAppArea, action); - const formattedEnvelope = prettyPrintXml(envelope); - - // Guardrails - if (!formattedEnvelope.includes("")) { - throw new Error("STAR envelope malformed: missing ProcessMessage/ApplicationArea"); - } - - const headers = { ...RR_SOAP_HEADERS, SOAPAction: RR_SOAP_ACTION }; - - RRLogger(socket, "debug", `Sending RR SOAP request`, { - action, - soapAction: RR_SOAP_ACTION, - endpoint: baseUrl, - jobid, - mode: "STAR" - }); - - try { - const { data: responseXml } = await axios.post(baseUrl, formattedEnvelope, { - headers, - timeout: cfg.timeout - // Some RCI tenants require Basic in addition to WSSE - // auth: { username: cfg.username, password: cfg.password } - }); - - const parsed = parseRRResponse(responseXml); - - if (!parsed.success) { - RRLogger(socket, "error", `RR ${action} failed`, { - code: parsed.code, - message: parsed.message - }); - throw new RrApiError(parsed.message || `RR ${action} failed`, parsed.code || "RR_ERROR"); - } - - RRLogger(socket, "info", `RR ${action} success`, { - result: parsed.code, - message: parsed.message - }); - - return responseXml; - } catch (err) { - if (retries > 0) { - RRLogger(socket, "warn", `Retrying RR ${action} (${retries - 1} left)`, { - error: err.message - }); - return MakeRRCall({ - action, - body, - appArea: selectedAppArea, - socket, - dealerConfig: cfg, - retries: retries - 1, - jobid - }); - } - - RRLogger(socket, "error", `RR ${action} failed permanently`, { error: err.message }); - throw err; - } -} - -module.exports = { - MakeRRCall, - renderXmlTemplate, - resolveRRConfig, - parseRRResponse, - buildStarEnvelope, - RRActions -}; diff --git a/server/rr/rr-job-export.js b/server/rr/rr-job-export.js index 2f7031837..3a9922bd7 100644 --- a/server/rr/rr-job-export.js +++ b/server/rr/rr-job-export.js @@ -1,158 +1,68 @@ -/** - * @file rr-job-export.js - * @description End-to-end export of a Hasura "job" to Reynolds & Reynolds (Rome). - * Orchestrates Customer (insert/update), optional Vehicle insert, and RO (create/update), - * mirroring behavior of PBS/Fortellis exporters for parity. - */ +const { withClient } = require("./withClient"); -const RRLogger = require("./rr-logger"); -const { RrApiError } = require("./rr-error"); +async function exportJobToRR({ bodyshopId, job, logger }) { + return withClient(bodyshopId, logger, async (client, routing) => { + // 1) Upsert Customer + const custPayload = mapJobToCustomer(job); + const custRes = job.customer?.nameRecId + ? await client.updateCustomer(custPayload, { routing }) + : await client.insertCustomer(custPayload, { routing }); -const customerApi = require("./rr-customer"); -const roApi = require("./rr-repair-orders"); -const { MakeRRCall } = require("./rr-helpers"); // for optional vehicle insert -const { mapServiceVehicle } = require("./rr-mappers"); + const customerNo = custRes?.data?.dmsRecKey || job.customer?.customerNo; + if (!customerNo) throw new Error("Failed to resolve customerNo from RR response."); -/** - * Decide if we should CREATE or UPDATE an entity in Rome based on external IDs - */ -function decideAction({ customer, vehicle, job }) { - const hasCustId = !!(customer?.external_id || customer?.rr_customer_id); - const hasVehId = !!(vehicle?.external_id || vehicle?.rr_vehicle_id); - const hasRoId = !!(job?.external_id || job?.rr_repair_order_id || job?.dms_repair_order_id); - - return { - customerAction: hasCustId ? "update" : "insert", - vehicleAction: hasVehId ? "skip" : "insert", // Rome often generates vehicle IDs on RO create; we insert only if we have enough data and no id - repairOrderAction: hasRoId ? "update" : "create" - }; -} - -/** - * Normalize a stage result to a consistent structure. - */ -function stageOk(name, extra = {}) { - return { stage: name, success: true, ...extra }; -} -function stageFail(name, error) { - return { stage: name, success: false, error: error?.message || String(error) }; -} - -/** - * Export a job into Rome (Customer → Vehicle → RepairOrder). - * @param {Socket} socket - logging context (may be null in batch) - * @param {Object} job - Hasura job object (must include customer, vehicle, lines, totals) - * @param {Object} bodyshopConfig - per-shop RR config (dealer/store/branch + creds) - * @param {Object} options - { insertVehicleIfMissing: boolean } - * @returns {Promise} normalized result - */ -async function exportJobToRR(socket, job, bodyshopConfig, options = {}) { - const { customer = {}, vehicle = {} } = job || {}; - const { insertVehicleIfMissing = true } = options; - - const actions = decideAction({ customer, vehicle, job }); - - const stages = []; - const summary = { - dms: "Rome", - jobid: job?.id, - ro_action: actions.repairOrderAction, - customer_action: actions.customerAction, - vehicle_action: insertVehicleIfMissing ? actions.vehicleAction : "skip" - }; - - RRLogger(socket, "info", `RR Export start`, summary); - - // ---- 1) Customer ---- - try { - if (actions.customerAction === "insert") { - const res = await customerApi.insertCustomer(socket, customer, bodyshopConfig); - stages.push(stageOk("customer.insert")); - summary.customer_xml = res.xml; - } else { - const res = await customerApi.updateCustomer(socket, customer, bodyshopConfig); - stages.push(stageOk("customer.update")); - summary.customer_xml = res.xml; + // 2) Ensure Service Vehicle (optional, if VIN present) + if (job?.vehicle?.vin) { + await client.insertServiceVehicle( + { + vin: job.vehicle.vin, + vehicleServInfo: { customerNo } + }, + { routing } + ); } - } catch (error) { - stages.push(stageFail(`customer.${actions.customerAction}`, error)); - RRLogger(socket, "error", `RR customer ${actions.customerAction} failed`, { - jobid: job?.id, - error: error.message - }); - throw new RrApiError(`Customer ${actions.customerAction} failed: ${error.message}`, "RR_CUSTOMER_ERROR"); - } - // ---- 2) Vehicle (optional explicit insert) ---- - if (insertVehicleIfMissing && actions.vehicleAction === "insert") { - try { - // Only insert when we have at least VIN or plate+state/year - const hasMinimumIdentity = !!(vehicle?.vin || (vehicle?.license_plate && vehicle?.license_state)); - if (hasMinimumIdentity) { - const data = mapServiceVehicle(vehicle, customer, bodyshopConfig); - const xml = await MakeRRCall({ - action: "InsertServiceVehicle", - body: { template: "InsertServiceVehicle", data }, - socket, - dealerConfig: bodyshopConfig, - jobid: job?.id - }); - stages.push(stageOk("vehicle.insert")); - summary.vehicle_xml = xml; - } else { - stages.push(stageOk("vehicle.skip", { reason: "insufficient_identity" })); - } - } catch (error) { - stages.push(stageFail("vehicle.insert", error)); - RRLogger(socket, "error", `RR vehicle insert failed`, { - jobid: job?.id, - error: error.message - }); - // Non-fatal for the overall export — many flows let RO creation create/associate vehicle. - } - } else { - stages.push(stageOk("vehicle.skip", { reason: actions.vehicleAction === "skip" ? "already_has_id" : "disabled" })); - } + // 3) Create RO + const roHeader = { + customerNo, + departmentType: "B", + vin: job?.vehicle?.vin, + outsdRoNo: job?.roExternal || job?.id, + advisorNo: job?.advisorNo, + mileageIn: job?.mileageIn + }; - // ---- 3) Repair Order ---- - try { - let res; - if (actions.repairOrderAction === "create") { - res = await roApi.createRepairOrder(socket, job, bodyshopConfig); - stages.push(stageOk("ro.create")); - } else { - res = await roApi.updateRepairOrder(socket, job, bodyshopConfig); - stages.push(stageOk("ro.update")); - } - summary.ro_xml = res.xml; - } catch (error) { - stages.push(stageFail(`ro.${actions.repairOrderAction}`, error)); - RRLogger(socket, "error", `RR RO ${actions.repairOrderAction} failed`, { - jobid: job?.id, - error: error.message - }); - throw new RrApiError(`RepairOrder ${actions.repairOrderAction} failed: ${error.message}`, "RR_RO_ERROR"); - } - - const result = { - success: true, - ...summary, - stages - }; - - RRLogger(socket, "info", `RR Export finished`, { - jobid: job?.id, - result: { - success: result.success, - customer_action: summary.customer_action, - vehicle_action: summary.vehicle_action, - ro_action: summary.ro_action - } + const roBody = mapJobToRO(job); // extend if you want lines/tax/etc + const roRes = await client.createRepairOrder({ ...roHeader, ...roBody }, { routing }); + return roRes?.data; }); - - return result; } -module.exports = { - exportJobToRR -}; +function mapJobToCustomer(job) { + const c = job?.customer || {}; + return { + nameRecId: c.nameRecId, + firstName: c.firstName || c.given_name, + lastName: c.lastName || c.family_name, + phone: c.phone || c.mobile, + email: c.email, + address: { + line1: c.address1, + line2: c.address2, + city: c.city, + state: c.province || c.state, + postalCode: c.postal || c.zip + } + }; +} + +function mapJobToRO(job) { + return { + // rolabor: [...], + // roparts: [...], + // estimate: {...}, + // tax: {...} + }; +} + +module.exports = { exportJobToRR }; diff --git a/server/rr/rr-logger.js b/server/rr/rr-logger.js index c2dc531f8..0fdd8f187 100644 --- a/server/rr/rr-logger.js +++ b/server/rr/rr-logger.js @@ -1,55 +1,16 @@ -/** - * @file rr-logger.js - * @description Structured logger for Reynolds & Reynolds (Rome) integration. - * Mirrors PBS/Fortellis log shape for consistent log parsing. - */ +const logger = require("../utils/logger"); -const util = require("util"); -const dayjs = require("dayjs"); - -/** - * @typedef {Object} LogContext - * @property {string} [jobid] - * @property {string} [action] - * @property {string} [stage] - * @property {string} [endpoint] - * @property {Object} [meta] - */ - -/** - * Emit a structured log event to console, Socket.IO, or upstream logger. - * @param {Socket|null} socket - Optional socket for WsLogger passthrough - * @param {"info"|"debug"|"warn"|"error"} level - * @param {string} message - Primary log message - * @param {LogContext|any} [context] - */ -function RRLogger(socket, level, message, context = {}) { - const logEvent = { - source: "RR", - level, - timestamp: dayjs().toISOString(), - message, - ...context - }; - - // Console log (stdout/stderr) - const serialized = `[RR] ${logEvent.timestamp} [${level.toUpperCase()}] ${message}`; - if (level === "error" || level === "warn") { - console.error(serialized, context ? util.inspect(context, { depth: 4, colors: false }) : ""); - } else { - console.log(serialized, context ? util.inspect(context, { depth: 4, colors: false }) : ""); - } - - // Optional: forward to WsLogger (if your socket is configured that way) - try { - if (socket && typeof socket.emit === "function") { - socket.emit("rr-log-event", logEvent); - } else if (global.WsLogger && typeof global.WsLogger.createLogEvent === "function") { - global.WsLogger.createLogEvent(socket, level.toUpperCase(), message, context.jobid, context); +function RRLogger(socket) { + return function log(level = "info", message = "", ctx = {}) { + // Console + const fn = logger.logger[level] || logger.log; + fn(`[RR] ${new Date().toISOString()} [${level.toUpperCase()}] ${message}`, ctx); + try { + socket?.emit?.("RR:LOG", { level, message, ctx, ts: Date.now() }); + } catch { + /* ignore */ } - } catch (e) { - console.error("[RRLogger] forwarding error", e.message); - } + }; } module.exports = RRLogger; diff --git a/server/rr/rr-lookup.js b/server/rr/rr-lookup.js index 9341f4c95..ff18f0552 100644 --- a/server/rr/rr-lookup.js +++ b/server/rr/rr-lookup.js @@ -1,136 +1,24 @@ -/** - * @file rr-lookup.js - * @description Rome (Reynolds & Reynolds) lookup operations — Advisors, Parts, and CombinedSearch - */ +const { withClient } = require("./withClient"); -const { MakeRRCall, parseRRResponse } = require("./rr-helpers"); -const { mapAdvisorLookup, mapPartsLookup, mapCombinedSearch } = require("./rr-mappers"); -const RRLogger = require("./rr-logger"); -const { RrApiError } = require("./rr-error"); - -/** - * Get a list of service advisors from Rome. - */ -async function getAdvisors(socket, criteria = {}, bodyshopConfig) { - const action = "GetAdvisors"; - const template = "GetAdvisors"; - - try { - RRLogger(socket, "info", `Starting RR ${action} lookup`); - const data = mapAdvisorLookup(criteria, bodyshopConfig); - - const resultXml = await MakeRRCall({ - action, - body: { template, data }, - socket, - dealerConfig: bodyshopConfig - }); - - const parsed = parseRRResponse(resultXml); - if (!parsed.success) throw new RrApiError(parsed.message, parsed.code); - - const advisors = parsed.parsed?.Advisors?.Advisor || parsed.parsed?.AdvisorList?.Advisor || []; - const advisorList = Array.isArray(advisors) ? advisors : [advisors]; - - RRLogger(socket, "debug", `${action} lookup returned ${advisorList.length} advisors`); - return { success: true, dms: "Rome", action, advisors: advisorList }; - } catch (error) { - RRLogger(socket, "error", `Error in ${action} lookup`, { - message: error.message, - stack: error.stack - }); - throw new RrApiError(`RR ${action} failed: ${error.message}`, "GET_ADVISORS_ERROR"); - } +async function getAdvisors({ bodyshopId, ...criteria }) { + return withClient(bodyshopId, async (client, routing) => { + const res = await client.getAdvisors(criteria, { routing }); + return res; + }); } -/** - * Get parts information from Rome. - */ -async function getParts(socket, criteria = {}, bodyshopConfig) { - const action = "GetParts"; - const template = "GetParts"; - - try { - RRLogger(socket, "info", `Starting RR ${action} lookup`); - const data = mapPartsLookup(criteria, bodyshopConfig); - - const resultXml = await MakeRRCall({ - action, - body: { template, data }, - socket, - dealerConfig: bodyshopConfig - }); - - const parsed = parseRRResponse(resultXml); - if (!parsed.success) throw new RrApiError(parsed.message, parsed.code); - - const parts = parsed.parsed?.Parts?.Part || parsed.parsed?.PartList?.Part || []; - const partList = Array.isArray(parts) ? parts : [parts]; - - RRLogger(socket, "debug", `${action} lookup returned ${partList.length} parts`); - return { success: true, dms: "Rome", action, parts: partList }; - } catch (error) { - RRLogger(socket, "error", `Error in ${action} lookup`, { - message: error.message, - stack: error.stack - }); - throw new RrApiError(`RR ${action} failed: ${error.message}`, "GET_PARTS_ERROR"); - } +async function getParts({ bodyshopId, ...criteria }) { + return withClient(bodyshopId, async (client, routing) => { + const res = await client.getParts(criteria, { routing }); + return res; + }); } -/** - * Perform a combined customer / vehicle / company search. - * Equivalent to Rome CombinedSearchRq / Resp. - * @param {Socket} socket - * @param {Object} criteria - { VIN, LicensePlate, CustomerName, Phone, Email } - * @param {Object} bodyshopConfig - * @returns {Promise} { customers, vehicles, companies } - */ -async function combinedSearch(socket, criteria = {}, bodyshopConfig) { - const action = "CombinedSearch"; - const template = "CombinedSearch"; - - try { - RRLogger(socket, "info", `Starting RR ${action} request`); - const data = mapCombinedSearch(criteria, bodyshopConfig); - - const resultXml = await MakeRRCall({ - action, - body: { template, data }, - socket, - dealerConfig: bodyshopConfig - }); - - const parsed = parseRRResponse(resultXml); - if (!parsed.success) throw new RrApiError(parsed.message, parsed.code); - - const customers = parsed.parsed?.Customers?.Customer || []; - const vehicles = parsed.parsed?.Vehicles?.ServiceVehicle || []; - const companies = parsed.parsed?.Companies?.Company || []; - - const result = { - customers: Array.isArray(customers) ? customers : [customers], - vehicles: Array.isArray(vehicles) ? vehicles : [vehicles], - companies: Array.isArray(companies) ? companies : [companies] - }; - - RRLogger( - socket, - "debug", - `${action} returned ${result.customers.length} customers, ${result.vehicles.length} vehicles, ${result.companies.length} companies` - ); - return { success: true, dms: "Rome", action, ...result }; - } catch (error) { - RRLogger(socket, "error", `Error in ${action}`, { - message: error.message, - stack: error.stack - }); - throw new RrApiError(`RR ${action} failed: ${error.message}`, "COMBINED_SEARCH_ERROR"); - } +async function combinedSearch({ bodyshopId, ...query }) { + return withClient(bodyshopId, async (client, routing) => { + const res = await client.combinedSearch(query, { routing }); + return res; + }); } -module.exports = { - getAdvisors, - getParts, - combinedSearch -}; +module.exports = { getAdvisors, getParts, combinedSearch }; diff --git a/server/rr/rr-mappers.js b/server/rr/rr-mappers.js deleted file mode 100644 index 601f62019..000000000 --- a/server/rr/rr-mappers.js +++ /dev/null @@ -1,428 +0,0 @@ -/** - * @file rr-mappers.js - * @description Maps internal ImEX (Hasura) entities into Rome (Reynolds & Reynolds) XML structures. - * Each function returns a plain JS object that matches Mustache templates in xml-templates/. - */ - -const dayjs = require("dayjs"); -const { normalizeRRDealerFields } = require("./rr-constants"); - -/** - * Utility: formats date/time to R&R’s preferred format (ISO or yyyy-MM-dd). - */ -const formatDate = (val) => { - if (!val) return undefined; - return dayjs(val).format("YYYY-MM-DD"); -}; - -/** - * Utility: safely pick numeric values and stringify for XML. - */ -const num = (val) => (val != null ? String(val) : undefined); - -const toBoolStr = (v) => (v === true ? "true" : v === false ? "false" : undefined); -const hasAny = (obj) => !!obj && Object.values(obj).some((v) => v !== undefined && v !== null && v !== ""); - -/** - * Pull canonical Dealer/Store/Branch fields from cfg (tolerate snake_case during migration). - * Enforces DB-provided values upstream (no env fallback here). - */ -function getDSB(cfg) { - const { dealerNumber, storeNumber, branchNumber } = normalizeRRDealerFields(cfg || {}); - return { dealerNumber, storeNumber, branchNumber }; -} - -/** - * Normalize an address-like object to the template's
block. - */ -function mapAddress(addr) { - if (!addr) return undefined; - const out = { - Line1: addr.line1, - Line2: addr.line2, - City: addr.city, - State: addr.state, - PostalCode: addr.postal_code || addr.postalCode, - Country: addr.country - }; - return hasAny(out) ? out : undefined; -} - -// -// ===================== CUSTOMER ===================== -// - -/** - * Map internal customer record to Rome CustomerInsertRq. - */ -function mapCustomerInsert(src) { - const name = src.company_name?.trim() || [src.first_name, src.last_name].filter(Boolean).join(" ").trim(); - return { - CustomerNumber: src.external_id, // optional - CustomerType: src.type === "BUSINESS" ? "BUSINESS" : "RETAIL", - CustomerName: name, - DisplayName: src.display_name || name, - Language: src.language || "EN", - TaxExempt: src.tax_exempt ? "Y" : "N", - Active: src.active ? "Y" : "N", - Addresses: (src.addresses || []).map((a) => ({ - Type: a.type || "P", - Line1: a.line1, - Line2: a.line2, - City: a.city, - State: a.state, - PostalCode: a.postal_code, - Country: a.country - })), - Phones: (src.phones || []).map((p) => ({ - Type: p.type || "H", - Number: p.number, - Extension: p.extension, - Preferred: p.preferred ? "Y" : "N" - })), - Emails: (src.emails || []).map((e) => ({ - Type: e.type || "W", - Address: e.address, - Preferred: e.preferred ? "Y" : "N" - })) - }; -} - -/** - * Map internal customer record to Rome CustomerUpdateRq. - */ -function mapCustomerUpdate(customer, bodyshopConfig) { - if (!customer) return {}; - return { - ...mapCustomerInsert(customer, bodyshopConfig), - RequestId: `CUST-UPDATE-${customer.id}` - }; -} - -// -// ===================== VEHICLE ===================== -// - -/** - * Map vehicle to Rome ServiceVehicleAddRq. - */ -function mapServiceVehicle(vehicle, ownerCustomer, bodyshopConfig) { - if (!vehicle) return {}; - const { dealerNumber, storeNumber, branchNumber } = getDSB(bodyshopConfig); - - return { - DealerCode: bodyshopConfig?.dealer_code || "ROME", - DealerNumber: dealerNumber, - StoreNumber: storeNumber, - BranchNumber: branchNumber, - RequestId: `VEH-${vehicle.id}`, - - CustomerId: ownerCustomer?.external_id, - - VIN: vehicle.vin, - UnitNumber: vehicle.unit_number, - StockNumber: vehicle.stock_number, - Year: num(vehicle.year), - Make: vehicle.make, - Model: vehicle.model, - Trim: vehicle.trim, - BodyStyle: vehicle.body_style, - Transmission: vehicle.transmission, - Engine: vehicle.engine, - FuelType: vehicle.fuel_type, - DriveType: vehicle.drive_type, - Color: vehicle.color, - LicensePlate: vehicle.license_plate, - LicenseState: vehicle.license_state, - Odometer: num(vehicle.odometer), - OdometerUnits: vehicle.odometer_units || "KM", - InServiceDate: formatDate(vehicle.in_service_date), - - Insurance: vehicle.insurance - ? { - CompanyName: vehicle.insurance.company, - PolicyNumber: vehicle.insurance.policy, - ExpirationDate: formatDate(vehicle.insurance.expiration_date) - } - : undefined, - - Warranty: vehicle.warranty - ? { - WarrantyCompany: vehicle.warranty.company, - WarrantyNumber: vehicle.warranty.number, - WarrantyType: vehicle.warranty.type, - ExpirationDate: formatDate(vehicle.warranty.expiration_date) - } - : undefined, - - VehicleNotes: vehicle.notes?.length ? { Items: vehicle.notes.map((n) => n.text || n) } : undefined - }; -} - -// -// ===================== REPAIR ORDER ===================== -// - -/** - * Map internal job to Rome RepairOrderInsertRq. - * NOTE: The CreateRepairOrder.xml template expects *flat* fields for Customer and ServiceVehicle - * (no {{#Customer}} or {{#ServiceVehicle}} sections). Therefore, we flatten those values here. - */ -function mapRepairOrderCreate(job, bodyshopConfig) { - if (!job) return {}; - const { dealerNumber, storeNumber, branchNumber } = getDSB(bodyshopConfig); - - const cust = job.customer || {}; - const veh = job.vehicle || {}; - - // Prefer a concrete address on the customer, fall back to job-level - const customerAddress = cust.address || job.customer_address || job.address || undefined; - - return { - // Routing/meta we keep available for logging or other templates - DealerCode: bodyshopConfig?.dealer_code || "ROME", - DealerNumber: dealerNumber, - StoreNumber: storeNumber, - BranchNumber: branchNumber, - RequestId: `RO-${job.id}`, - Environment: process.env.NODE_ENV, - - // Header fields - RepairOrderNumber: job.ro_number, - DmsRepairOrderId: job.external_id, - - OpenDate: formatDate(job.open_date), - PromisedDate: formatDate(job.promised_date), - CloseDate: formatDate(job.close_date), - - ServiceAdvisorId: job.advisor_id, - TechnicianId: job.technician_id, - Department: job.department, - ProfitCenter: job.profit_center, - - ROType: job.ro_type, - Status: job.status, - IsBodyShop: "true", - DRPFlag: toBoolStr(!!job.drp_flag) || "false", - - // Customer block is FLAT (template does not use {{#Customer}} section) - CustomerId: cust.external_id, - CustomerName: cust.full_name || [cust.first_name, cust.last_name].filter(Boolean).join(" ").trim() || undefined, - PhoneNumber: cust.phone, - EmailAddress: cust.email, - Address: mapAddress(customerAddress), - - // ServiceVehicle block is FLAT (template does not use {{#ServiceVehicle}} section) - VehicleId: veh.external_id, - VIN: veh.vin, - LicensePlate: veh.license_plate, - Year: num(veh.year), - Make: veh.make, - Model: veh.model, - Odometer: num(veh.odometer), - Color: veh.color, - - // Lines - JobLines: (job.joblines || []).map((l, i) => ({ - Sequence: i + 1, - ParentSequence: l.parent_sequence, - LineType: l.line_type, - Category: l.category, - OpCode: l.op_code, - Description: l.description, - LaborHours: num(l.labor_hours), - LaborRate: num(l.labor_rate), - PartNumber: l.part_number, - PartDescription: l.part_description, - Quantity: num(l.quantity), - UnitPrice: num(l.unit_price), - ExtendedPrice: num(l.extended_price), - DiscountAmount: num(l.discount_amount), - TaxCode: l.tax_code, - GLAccount: l.gl_account, - ControlNumber: l.control_number, - Taxes: l.taxes?.length - ? { - Items: l.taxes.map((t) => ({ - Code: t.code, - Amount: num(t.amount), - Rate: num(t.rate) - })) - } - : undefined - })), - - // Totals - Totals: hasAny({ - Currency: job.currency || "CAD", - LaborTotal: job.totals?.labor, - PartsTotal: job.totals?.parts, - MiscTotal: job.totals?.misc, - DiscountTotal: job.totals?.discount, - TaxTotal: job.totals?.tax, - GrandTotal: job.totals?.grand - }) - ? { - Currency: job.currency || "CAD", - LaborTotal: num(job.totals?.labor), - PartsTotal: num(job.totals?.parts), - MiscTotal: num(job.totals?.misc), - DiscountTotal: num(job.totals?.discount), - TaxTotal: num(job.totals?.tax), - GrandTotal: num(job.totals?.grand) - } - : undefined, - - // Payments - Payments: job.payments?.length - ? { - Items: job.payments.map((p) => ({ - PayerType: p.payer_type, - PayerName: p.payer_name, - Amount: num(p.amount), - Method: p.method, - Reference: p.reference, - ControlNumber: p.control_number - })) - } - : undefined, - - // Insurance - Insurance: job.insurance - ? { - CompanyName: job.insurance.company, - ClaimNumber: job.insurance.claim_number, - AdjusterName: job.insurance.adjuster_name, - AdjusterPhone: job.insurance.adjuster_phone - } - : undefined, - - // Notes - Notes: job.notes?.length ? { Items: job.notes.map((n) => n.text || n) } : undefined - }; -} - -/** - * Map for repair order updates. - */ -function mapRepairOrderUpdate(job, bodyshopConfig) { - return { - ...mapRepairOrderCreate(job, bodyshopConfig), - RequestId: `RO-UPDATE-${job.id}` - }; -} - -// -// ===================== LOOKUPS ===================== -// - -function mapAdvisorLookup(criteria, bodyshopConfig) { - const { dealerNumber, storeNumber, branchNumber } = getDSB(bodyshopConfig); - return { - DealerCode: bodyshopConfig?.dealer_code || "ROME", - DealerNumber: dealerNumber, - StoreNumber: storeNumber, - BranchNumber: branchNumber, - RequestId: `LOOKUP-ADVISOR-${Date.now()}`, - SearchCriteria: { - Department: criteria.department || "Body Shop", - Status: criteria.status || "ACTIVE" - } - }; -} - -function mapPartsLookup(criteria, bodyshopConfig) { - const { dealerNumber, storeNumber, branchNumber } = getDSB(bodyshopConfig); - return { - DealerCode: bodyshopConfig?.dealer_code || "ROME", - DealerNumber: dealerNumber, - StoreNumber: storeNumber, - BranchNumber: branchNumber, - RequestId: `LOOKUP-PART-${Date.now()}`, - SearchCriteria: { - PartNumber: criteria.part_number, - Description: criteria.description, - Make: criteria.make, - Model: criteria.model, - Year: num(criteria.year), - Category: criteria.category, - MaxResults: criteria.max_results || 25 - } - }; -} - -function mapCombinedSearch(criteria = {}, bodyshopConfig) { - const { dealerNumber, storeNumber, branchNumber } = getDSB(bodyshopConfig); - - // accept nested or flat input - const c = criteria || {}; - const cust = c.customer || c.Customer || {}; - const veh = c.vehicle || c.Vehicle || {}; - const comp = c.company || c.Company || {}; - - // build optional blocks only if they have at least one value - const customerBlock = { - FirstName: cust.firstName || cust.FirstName || c.firstName, - LastName: cust.lastName || cust.LastName || c.lastName, - PhoneNumber: cust.phoneNumber || cust.PhoneNumber || c.phoneNumber || c.phone, - EmailAddress: cust.email || cust.EmailAddress || c.email, - CompanyName: cust.companyName || cust.CompanyName || c.companyName, - CustomerId: cust.customerId || cust.CustomerId || c.customerId - }; - const vehicleBlock = { - VIN: veh.vin || veh.VIN || c.vin, - LicensePlate: veh.licensePlate || veh.LicensePlate || c.licensePlate, - Make: veh.make || veh.Make || c.make, - Model: veh.model || veh.Model || c.model, - Year: veh.year != null ? String(veh.year) : c.year != null ? String(c.year) : undefined, - VehicleId: veh.vehicleId || veh.VehicleId || c.vehicleId - }; - const companyBlock = { - Name: comp.name || comp.Name || c.companyName, - Phone: comp.phone || comp.Phone || c.companyPhone - }; - - return { - DealerCode: bodyshopConfig?.dealer_code || "ROME", - DealerName: bodyshopConfig?.dealer_name, - DealerNumber: dealerNumber, - StoreNumber: storeNumber, - BranchNumber: branchNumber, - - RequestId: c.requestId || `COMBINED-${Date.now()}`, - Environment: process.env.NODE_ENV, - - // Only include these blocks when they have content; Mustache {{#Block}} respects undefined - Customer: hasAny(customerBlock) ? customerBlock : undefined, - Vehicle: hasAny(vehicleBlock) ? vehicleBlock : undefined, // template wraps as - Company: hasAny(companyBlock) ? companyBlock : undefined, - - // Search behavior flags - SearchMode: c.searchMode || c.SearchMode, // EXACT | PARTIAL - ExactMatch: toBoolStr(c.exactMatch ?? c.ExactMatch), - PartialMatch: toBoolStr(c.partialMatch ?? c.PartialMatch), - CaseInsensitive: toBoolStr(c.caseInsensitive ?? c.CaseInsensitive), - - // Result shaping (default to true when unspecified) - ReturnCustomers: toBoolStr(c.returnCustomers ?? c.ReturnCustomers ?? true), - ReturnVehicles: toBoolStr(c.returnVehicles ?? c.ReturnVehicles ?? true), - ReturnCompanies: toBoolStr(c.returnCompanies ?? c.ReturnCompanies ?? true), - - // Paging / sorting - MaxResults: c.maxResults ?? c.MaxResults, - PageNumber: c.pageNumber ?? c.PageNumber, - SortBy: c.sortBy ?? c.SortBy, // e.g., NAME, VIN, PARTNUMBER - SortDirection: c.sortDirection ?? c.SortDirection // ASC | DESC - }; -} - -module.exports = { - mapCustomerInsert, - mapCustomerUpdate, - mapServiceVehicle, - mapRepairOrderCreate, - mapRepairOrderUpdate, - mapAdvisorLookup, - mapPartsLookup, - mapCombinedSearch -}; diff --git a/server/rr/rr-repair-orders.js b/server/rr/rr-repair-orders.js index 8a7f66107..a89040987 100644 --- a/server/rr/rr-repair-orders.js +++ b/server/rr/rr-repair-orders.js @@ -1,165 +1,17 @@ -/** - * @file rr-repair-orders.js - * @description Rome (Reynolds & Reynolds) Repair Order Integration. - * Handles creation and updates of repair orders (BSMRepairOrderRq/Resp). - */ +const { withClient } = require("./withClient"); -"use strict"; - -const { MakeRRCall } = require("./rr-helpers"); -const { mapRepairOrderCreate, mapRepairOrderUpdate } = require("./rr-mappers"); -const RRLogger = require("./rr-logger"); -const { RrApiError } = require("./rr-error"); - -/** - * Very light sanity checks before we build XML. - * We keep these minimal because the mapper may derive some fields. - * Throws RrApiError when a required precondition is missing. - * @param {"CreateRepairOrder"|"UpdateRepairOrder"} action - * @param {Object} job - */ -function preflight(action, job) { - if (!job || !job.id) { - throw new RrApiError("Missing job payload or job.id", "RR_BAD_JOB_PAYLOAD"); - } - // VIN is almost always required for BSM RO flows - const vin = job?.vehicle?.vin || job?.vehicle?.VIN || job?.VIN || job?.vin; - if (!vin) { - throw new RrApiError("Missing VIN on job.vehicle", "RR_MISSING_VIN"); - } - - if (action === "UpdateRepairOrder") { - // If your mapper expects a DMS RO number or an external RO number, - // you can tighten this guard based on your schema, e.g.: - // const hasKey = job?.dms_ro_no || job?.external_ro_number || job?.roNumber; - // if (!hasKey) throw new RrApiError("Missing RO key for update", "RR_MISSING_RO_KEY"); - } +async function createRepairOrder({ bodyshopId, payload }) { + return withClient(bodyshopId, async (client, routing) => { + const res = await client.createRepairOrder(payload, { routing }); + return res; + }); } -/** - * Build an explicit ApplicationArea override so the envelope is always correct, - * even if the helper falls back to defaults. We include routing info - * and set Task/ReferenceId for BSM repair orders. - * @param {"CreateRepairOrder"|"UpdateRepairOrder"} action - * @param {Object} cfg - */ -function buildAppArea(action, cfg) { - const isCreate = action === "CreateRepairOrder"; - return { - Sender: { - Component: "Rome", - Task: "BSMRO", - ReferenceId: isCreate ? "Insert" : "Update" - }, - Destination: { - DealerNumber: cfg?.DealerNumber || cfg?.dealerNumber, - StoreNumber: cfg?.StoreNumber || cfg?.storeNumber, - AreaNumber: cfg?.AreaNumber || cfg?.areaNumber, - DestinationNameCode: "RR" - } - // CreationDateTime and BODId will be provided by rr-helpers if omitted. - }; +async function updateRepairOrder({ bodyshopId, payload }) { + return withClient(bodyshopId, async (client, routing) => { + const res = await client.updateRepairOrder(payload, { routing }); + return res; + }); } -/** - * Create a new repair order in Rome. - * @param {Socket} socket - active socket connection - * @param {Object} job - Hasura job object (including vehicle, customer, joblines) - * @param {Object} bodyshopConfig - DMS config for current bodyshop - * @returns {Promise} normalized result - */ -async function createRepairOrder(socket, job, bodyshopConfig) { - const action = "CreateRepairOrder"; - const template = "CreateRepairOrder"; // maps to xml-templates/CreateRepairOrder.xml - - try { - RRLogger(socket, "info", `Starting RR ${action} for job ${job?.id}`, { - jobid: job?.id, - dealer: bodyshopConfig?.DealerNumber || bodyshopConfig?.dealerNumber, - store: bodyshopConfig?.StoreNumber || bodyshopConfig?.storeNumber, - area: bodyshopConfig?.AreaNumber || bodyshopConfig?.areaNumber - }); - - preflight(action, job); - const data = mapRepairOrderCreate(job, bodyshopConfig); - - const resultXml = await MakeRRCall({ - action, - body: { template, data }, - appArea: buildAppArea(action, bodyshopConfig), - socket, - dealerConfig: bodyshopConfig, - jobid: job.id - }); - - RRLogger(socket, "debug", `${action} completed successfully`, { jobid: job.id }); - - return { - success: true, - dms: "Rome", - jobid: job.id, - action, - xml: resultXml - }; - } catch (error) { - RRLogger(socket, "error", `Error in ${action} for job ${job?.id}`, { - message: error?.message, - stack: error?.stack - }); - throw new RrApiError(`RR CreateRepairOrder failed: ${error.message}`, "CREATE_RO_ERROR"); - } -} - -/** - * Update an existing repair order in Rome. - * @param {Socket} socket - * @param {Object} job - * @param {Object} bodyshopConfig - * @returns {Promise} - */ -async function updateRepairOrder(socket, job, bodyshopConfig) { - const action = "UpdateRepairOrder"; - const template = "UpdateRepairOrder"; - - try { - RRLogger(socket, "info", `Starting RR ${action} for job ${job?.id}`, { - jobid: job?.id, - dealer: bodyshopConfig?.DealerNumber || bodyshopConfig?.dealerNumber, - store: bodyshopConfig?.StoreNumber || bodyshopConfig?.storeNumber, - area: bodyshopConfig?.AreaNumber || bodyshopConfig?.areaNumber - }); - - preflight(action, job); - const data = mapRepairOrderUpdate(job, bodyshopConfig); - - const resultXml = await MakeRRCall({ - action, - body: { template, data }, - appArea: buildAppArea(action, bodyshopConfig), - socket, - dealerConfig: bodyshopConfig, - jobid: job.id - }); - - RRLogger(socket, "debug", `${action} completed successfully`, { jobid: job.id }); - - return { - success: true, - dms: "Rome", - jobid: job.id, - action, - xml: resultXml - }; - } catch (error) { - RRLogger(socket, "error", `Error in ${action} for job ${job?.id}`, { - message: error?.message, - stack: error?.stack - }); - throw new RrApiError(`RR UpdateRepairOrder failed: ${error.message}`, "UPDATE_RO_ERROR"); - } -} - -module.exports = { - createRepairOrder, - updateRepairOrder -}; +module.exports = { createRepairOrder, updateRepairOrder }; diff --git a/server/rr/rr-test.js b/server/rr/rr-test.js deleted file mode 100644 index 6a677efa0..000000000 --- a/server/rr/rr-test.js +++ /dev/null @@ -1,484 +0,0 @@ -#!/usr/bin/env node -/** - * rr-test.js — end-to-end exerciser for Reynolds "Rome"/STAR actions. - * - * Key improvements vs prior version: - * - Prints FULL XML responses (no truncation). - * - CombinedSearch now sends at least one search criterion by default. - * - InsertCustomer sets required IBFlag + LastName/FirstName. - * - Orchestrates dependent steps (CombinedSearch → InsertCustomer → InsertVehicle → Create/Update RO). - * - * Usage examples: - * node rr-test.js --ping - * node rr-test.js --all - * node rr-test.js --combined --last "SMITH" --phone 9375550001 --vin 1FTFW1E50JFA00000 - * - * Common flags: - * --first, --last, --phone, --email, --vin, --plate, --advisor, --max N - * - * Env fallbacks: - * RR_TEST_LAST, RR_TEST_FIRST, RR_TEST_PHONE, RR_TEST_EMAIL, RR_TEST_VIN, RR_TEST_PLATE, RR_TEST_PARTDESC - * - * Dealer creds/env (used only in this test harness; runtime pulls from DB): - * RR_DEALER_NUMBER, RR_STORE_NUMBER, RR_AREA_NUMBER, RR_USERNAME, RR_PASSWORD, RR_ENDPOINT - */ - -const path = require("path"); -const fs = require("fs"); -const fsp = require("fs/promises"); -const minimist = require("minimist"); -const dayjs = require("dayjs"); -const { XMLParser } = require("fast-xml-parser"); - -// Load dev env if present -const envPath = path.resolve(__dirname, "../../.env.development"); -if (fs.existsSync(envPath)) { - require("dotenv").config({ path: envPath }); - console.log(envPath); - console.log( - `[dotenv@${require("dotenv/package.json").version}] injecting env (${Object.keys(process.env).length}) from ../../.env.development` - ); -} - -const { MakeRRCall, parseRRResponse } = require("./rr-helpers"); -const RRLogger = require("./rr-logger"); - -// CLI flags -const argv = minimist(process.argv.slice(2)); -const FLAG = (k, d) => (argv[k] !== undefined ? argv[k] : d); - -// For templates that expect STAR NS in {{STAR_NS}} -const STAR_NS = "http://www.starstandards.org/STAR"; - -// Basic XML parser for optional extractions -const parser = new XMLParser({ ignoreAttributes: false, removeNSPrefix: true }); - -// Ensure templates exist -async function verifyTemplates() { - const required = [ - "CombinedSearch", - "GetAdvisors", - "GetParts", - "InsertCustomer", - "UpdateCustomer", - "InsertServiceVehicle", - "CreateRepairOrder", - "UpdateRepairOrder" - ]; - for (const t of required) { - const p = path.join(__dirname, "xml-templates", `${t}.xml`); - await fsp.readFile(p, "utf8"); - } - console.log("✅ Templates verified."); -} - -// Format AppArea per action (Sender.Task/ReferenceId) -function appAreaFor(action, cfg) { - const pad2 = (x) => String(x ?? "").padStart(2, "0"); - const base = { - CreationDateTime: new Date().toISOString(), - BODId: `BOD-${Date.now()}`, - Sender: { Component: "Rome", CreatorNameCode: "RCI", SenderNameCode: "RCI" }, - Destination: { - DealerNumber: cfg.dealerNumber, - StoreNumber: pad2(cfg.storeNumber), - AreaNumber: pad2(cfg.branchNumber || "01") - } - }; - switch (action) { - case "CreateRepairOrder": - return { ...base, Sender: { ...base.Sender, Task: "BSMRO", ReferenceId: "Insert" } }; - case "UpdateRepairOrder": - return { ...base, Sender: { ...base.Sender, Task: "BSMRO", ReferenceId: "Update" } }; - case "InsertCustomer": - return { ...base, Sender: { ...base.Sender, Task: "CU", ReferenceId: "Insert" } }; - case "UpdateCustomer": - return { ...base, Sender: { ...base.Sender, Task: "CU", ReferenceId: "Update" } }; - case "InsertServiceVehicle": - return { ...base, Sender: { ...base.Sender, Task: "SV", ReferenceId: "Insert" } }; - case "CombinedSearch": - return { ...base, Sender: { ...base.Sender, Task: "SV", ReferenceId: "Query" } }; - case "GetAdvisors": - return { ...base, Sender: { ...base.Sender, Task: "RCI", ReferenceId: "Lookup" } }; - case "GetParts": - return { ...base, Sender: { ...base.Sender, Task: "RCI", ReferenceId: "Lookup" } }; - default: - return base; - } -} - -// Build cfg for test harness (env fallbacks allowed here) -function cfgFromEnv() { - return { - baseUrl: - process.env.RR_ENDPOINT || process.env.RR_BASE_URL || "https://b2b-test.reyrey.com/Sync/RCI/Rome/Receive.ashx", - username: process.env.RR_USERNAME || "Rome", - password: process.env.RR_PASSWORD || "", - timeout: Number(process.env.RR_TIMEOUT || 30000), - dealerNumber: process.env.RR_DEALER_NUMBER || "PPERASV02000000", - storeNumber: process.env.RR_STORE_NUMBER || "05", - branchNumber: process.env.RR_AREA_NUMBER || "03" - }; -} - -// Utility: get a value from parsed JSON or raw XML (element or attribute) -function findFirstId(parsed, rawXml, keyRegex) { - // search parsed object - if (parsed && typeof parsed === "object") { - const stack = [parsed]; - while (stack.length) { - const cur = stack.pop(); - if (cur && typeof cur === "object") { - for (const [k, v] of Object.entries(cur)) { - if (keyRegex.test(k) && (typeof v === "string" || typeof v === "number")) { - const s = String(v).trim(); - if (s) return s; - } - if (v && typeof v === "object") stack.push(v); - } - } - } - } - // search raw XML: value or Key="value" - if (rawXml) { - const re1 = new RegExp(`<([A-Za-z0-9:_-]*${keyRegex.source}[A-Za-z0-9:_-]*)>([^<]+)`, "i"); - const m1 = re1.exec(rawXml); - if (m1 && m1[2]) return m1[2].trim(); - const re2 = new RegExp(`${keyRegex.source}="([^"]+)"`, "i"); - const m2 = re2.exec(rawXml); - if (m2 && m2[1]) return m2[1].trim(); - } - return undefined; -} - -// Call wrapper: prints FULL XML -async function callRR(action, dataObj, cfg) { - const respXml = await MakeRRCall({ - action, - dealerConfig: cfg, - body: { data: { STAR_NS, ...dataObj }, appArea: appAreaFor(action, cfg) } - }); - const parsed = parseRRResponse(respXml); - return { respXml, parsed }; -} - -// --------- Individual Steps (full XML printed) --------- - -async function stepGetAdvisors(ctx) { - const cfg = ctx.cfg; - const data = { - SearchCriteria: { - Department: FLAG("dept", "B"), // critical to avoid 201 - Status: FLAG("status", "ACTIVE"), - MaxResults: Number(FLAG("max", 5)) || 5 - } - }; - const { respXml, parsed } = await callRR("GetAdvisors", data, cfg); - - console.log("\n[GetAdvisors] RESPONSE (FULL):\n"); - console.log(respXml); - - const advId = - findFirstId(parsed.parsed, respXml, /(Advisor(ID|No|Number)?|AdvNo)/i) || - findFirstId(parsed.parsed, respXml, /(Employee(ID|No|Number)?)/i); - if (advId) ctx.advisorId = advId; - - return { ok: true, code: parsed.code, advisorId: advId || null }; -} - -async function stepCombinedSearch(ctx) { - const cfg = ctx.cfg; - - // Provide at least one criterion by default to avoid 201 - const defaultLast = FLAG("last", process.env.RR_TEST_LAST || "SMITH"); - const defaultPhone = FLAG("phone", process.env.RR_TEST_PHONE || ""); - const defaultVin = FLAG("vin", process.env.RR_TEST_VIN || ""); - - const data = { - MaxResults: Number(FLAG("max", 5)) || 5, - Customer: {}, - Vehicle: {} - }; - if (defaultLast) data.Customer.LastName = defaultLast; - if (defaultPhone) data.Customer.PhoneNumber = defaultPhone; - if (defaultVin) data.Vehicle.VIN = defaultVin; - - const { respXml, parsed } = await callRR("CombinedSearch", data, cfg); - - console.log("\n[CombinedSearch] RESPONSE (FULL):\n"); - console.log(respXml); - - const custId = findFirstId(parsed.parsed, respXml, /(Cust(omer)?(No|Id|ID|Number|Key)|NameRecId)/i); - const vehId = findFirstId(parsed.parsed, respXml, /(Veh(icle)?(No|Id|ID|Number|Key))/i); - const vin = findFirstId(parsed.parsed, respXml, /VIN/i); - - if (custId) ctx.customerId = custId; - if (vehId) ctx.vehicleId = vehId; - if (vin) ctx.vin = vin; - - return { ok: true, code: parsed.code, customerId: custId || null, vehicleId: vehId || null, vin: vin || null }; -} - -async function stepInsertCustomer(ctx) { - const cfg = ctx.cfg; - - // RR requires IBFlag and LastName for individual customers - const ts = dayjs().format("YYYYMMDD-HHmmss"); - const firstName = FLAG("first", process.env.RR_TEST_FIRST || "QA"); - const lastName = FLAG("last", process.env.RR_TEST_LAST || "Test"); - const email = FLAG("email", process.env.RR_TEST_EMAIL || `qa.${ts}@example.com`); - const phone = FLAG( - "phone", - process.env.RR_TEST_PHONE || `937555${String(Math.floor(Math.random() * 10000)).padStart(4, "0")}` - ); - - const data = { - IBFlag: "I", // <== REQUIRED (I=Individual, B=Business) - FirstName: firstName, // <== REQUIRED with IBFlag=I - LastName: lastName, // <== REQUIRED with IBFlag=I - Active: "Y", - Phones: [{ Type: "Mobile", CountryCode: "1", Number: phone, Preferred: "Y" }], - Emails: [{ Type: "Personal", Address: email, Preferred: "Y" }], - Addresses: [ - { - Type: "Home", - Line1: "123 Test St", - City: "Dayton", - State: "OH", - PostalCode: "45402", - Country: "US", - IsPrimary: "Y" - } - ] - }; - - const { respXml, parsed } = await callRR("InsertCustomer", data, cfg); - - console.log("\n[InsertCustomer] RESPONSE (FULL):\n"); - console.log(respXml); - - // RR often returns the new customer key as DMSRecKey attribute in TransStatus - const custId = findFirstId(parsed.parsed, respXml, /(DMSRecKey|Cust(omer)?(No|Id|ID|Number|Key)|NameRecId)/i); - - if (custId) ctx.customerId = custId; - return { ok: !!custId, code: parsed.code, customerId: custId || null }; -} - -async function stepUpdateCustomer(ctx) { - const cfg = ctx.cfg; - if (!ctx.customerId) return { ok: false, code: "NO_CONTEXT", message: "No customerId" }; - - const data = { - CustomerId: ctx.customerId, - Emails: [{ Type: "Personal", Address: `qa.${dayjs().format("HHmmss")}@example.com`, Preferred: "Y" }] - }; - - const { respXml, parsed } = await callRR("UpdateCustomer", data, cfg); - - console.log("\n[UpdateCustomer] RESPONSE (FULL):\n"); - console.log(respXml); - - return { ok: parsed.success, code: parsed.code }; -} - -async function stepInsertServiceVehicle(ctx) { - const cfg = ctx.cfg; - if (!ctx.customerId) return { ok: false, code: "NO_CONTEXT", message: "No customerId" }; - - const vin = - FLAG("vin", process.env.RR_TEST_VIN) || - `1FTFW1E50JFA${String(Math.floor(Math.random() * 1000000)).padStart(6, "0")}`; - - const data = { - CustomerId: ctx.customerId, - VIN: vin, - Year: "2018", - Make: "FORD", - Model: "F-150", - Color: "WHITE", - LicensePlate: - FLAG("plate", process.env.RR_TEST_PLATE) || `QA${String(Math.floor(Math.random() * 100000)).padStart(5, "0")}`, - LicenseState: "OH", - Odometer: "123456", - OdometerUnits: "MI" - }; - - const { respXml, parsed } = await callRR("InsertServiceVehicle", data, cfg); - - console.log("\n[InsertServiceVehicle] RESPONSE (FULL):\n"); - console.log(respXml); - - const vehId = findFirstId(parsed.parsed, respXml, /(Veh(icle)?(No|Id|ID|Number|Key))/i); - if (vehId) ctx.vehicleId = vehId; - ctx.vin = vin; - - return { ok: parsed.success || !!vehId, code: parsed.code, vehicleId: vehId || null, vin }; -} - -async function stepCreateRepairOrder(ctx) { - const cfg = ctx.cfg; - if (!ctx.customerId) return { ok: false, code: "NO_CONTEXT", message: "No customerId" }; - - const roNumber = `BSM-${dayjs().format("MMDD-HHmmss")}-${String(Math.floor(Math.random() * 1000)).padStart(3, "0")}`; - - const data = { - RepairOrderNumber: roNumber, - Department: "B", - ROType: "INS", - Status: "OPEN", - IsBodyShop: "Y", - ServiceAdvisorId: ctx.advisorId || FLAG("advisor", process.env.RR_TEST_ADVISOR) || undefined, - Customer: { - CustomerId: ctx.customerId, - FirstName: FLAG("first", process.env.RR_TEST_FIRST || "QA"), - LastName: FLAG("last", process.env.RR_TEST_LAST || "Test"), - PhoneNumber: FLAG("phone", process.env.RR_TEST_PHONE || "9375550000"), - EmailAddress: FLAG("email", process.env.RR_TEST_EMAIL || "qa@example.com") - }, - ServiceVehicle: { - VIN: ctx.vin || FLAG("vin", process.env.RR_TEST_VIN) || undefined, - Odometer: "4321" - }, - Totals: { - Currency: "USD", - LaborTotal: "0", - PartsTotal: "0", - MiscTotal: "0", - DiscountTotal: "0", - TaxTotal: "0", - GrandTotal: "0" - } - }; - - const respXml = await MakeRRCall({ - action: "CreateRepairOrder", - dealerConfig: cfg, - body: { data: { STAR_NS, ...data }, appArea: appAreaFor("CreateRepairOrder", cfg) } - }); - - const parsed = parseRRResponse(respXml); - - console.log("\n[CreateRepairOrder] RESPONSE (FULL):\n"); - console.log(respXml); - - const roNo = findFirstId(parsed.parsed, respXml, /(DMSRoNo|RO?No|OutsdRoNo|RepairOrder(Id|Number))/i) || roNumber; - - ctx.roNumber = roNo; - - return { ok: parsed.success, code: parsed.code, roNumber: roNo }; -} - -async function stepUpdateRepairOrder(ctx) { - const cfg = ctx.cfg; - if (!ctx.roNumber) return { ok: false, code: "NO_CONTEXT", message: "No roNumber" }; - - const data = { - RepairOrderNumber: ctx.roNumber, - Department: "B", - Status: "OPEN", - Totals: { LaborTotal: "0", PartsTotal: "0", MiscTotal: "0", TaxTotal: "0", GrandTotal: "0" } - }; - - const { respXml, parsed } = await callRR("UpdateRepairOrder", data, cfg); - - console.log("\n[UpdateRepairOrder] RESPONSE (FULL):\n"); - console.log(respXml); - - return { ok: parsed.success, code: parsed.code }; -} - -async function stepGetParts(ctx) { - const cfg = ctx.cfg; - - const data = { - MaxResults: Number(FLAG("max", 5)) || 5, - SearchMode: "Description", - Description: FLAG("partdesc", process.env.RR_TEST_PARTDESC || "clip") - }; - - const { respXml, parsed } = await callRR("GetParts", data, cfg); - - console.log("\n[GetParts] RESPONSE (FULL):\n"); - console.log(respXml); - - return { ok: parsed.success, code: parsed.code }; -} - -// --------- Runner --------- - -async function runAll() { - await verifyTemplates(); - - const cfg = cfgFromEnv(); - const ctx = { cfg }; - - const results = []; - - async function runStep(name, fn) { - const t0 = Date.now(); - try { - const res = await fn(ctx); - results.push({ step: name, ok: !!res.ok, code: res.code || "OK", ms: Date.now() - t0 }); - console.log(`\n✔ ${name} done in ${Date.now() - t0}ms`); - return res; - } catch (err) { - results.push({ step: name, ok: false, code: err.code || "ERR", ms: Date.now() - t0, error: err.message }); - console.error(`\n✖ ${name} failed: ${err.message}`); - throw err; - } - } - - // Sequence (dependencies respected) - await runStep("GetAdvisors", stepGetAdvisors); - await runStep("CombinedSearch", stepCombinedSearch); - - if (!ctx.customerId) await runStep("InsertCustomer", stepInsertCustomer); - if (!ctx.vehicleId) await runStep("InsertServiceVehicle", stepInsertServiceVehicle); - - await runStep("CreateRepairOrder", stepCreateRepairOrder); - await runStep("UpdateRepairOrder", stepUpdateRepairOrder); - await runStep("GetParts", stepGetParts); - - // Summary - console.log("\n=== SUMMARY ==="); - console.table(results.map((r) => ({ step: r.step, ok: r.ok ? "✅" : "❌", code: r.code, ms: r.ms }))); - const failed = results.some((r) => !r.ok); - console.log(`Total: ${results.reduce((a, r) => a + r.ms, 0)}ms | Status: ${failed ? "FAIL" : "PASS"}`); - if (failed) process.exitCode = 1; -} - -// Entrypoint -(async () => { - if (FLAG("ping", false)) { - await verifyTemplates(); - const cfg = cfgFromEnv(); - console.log("\n▶ Calling Rome action: GetAdvisors"); - const r = await stepGetAdvisors({ cfg }); - if (r.ok) console.log("\n✅ RR call completed.\n"); - return; - } - - if (FLAG("all", true)) { - await runAll(); - return; - } - - // Individual flags (optional) - await verifyTemplates(); - const cfg = cfgFromEnv(); - const ctx = { cfg }; - const want = []; - if (FLAG("get-advisors", false)) want.push(stepGetAdvisors); - if (FLAG("combined", false)) want.push(stepCombinedSearch); - if (FLAG("insert-customer", false)) want.push(stepInsertCustomer); - if (FLAG("update-customer", false)) want.push(stepUpdateCustomer); - if (FLAG("insert-vehicle", false)) want.push(stepInsertServiceVehicle); - if (FLAG("create-ro", false)) want.push(stepCreateRepairOrder); - if (FLAG("update-ro", false)) want.push(stepUpdateRepairOrder); - if (FLAG("get-parts", false)) want.push(stepGetParts); - - for (const fn of want) { - const res = await fn(ctx).catch((e) => ({ ok: false, code: "ERR", error: e.message })); - console.log(res); - } -})(); diff --git a/server/rr/rr-wsdl.js b/server/rr/rr-wsdl.js deleted file mode 100644 index 58e9bb5b9..000000000 --- a/server/rr/rr-wsdl.js +++ /dev/null @@ -1,126 +0,0 @@ -/** - * @file rr-wsdl.js - * @description Lightweight service description + utilities for the Rome (R&R) SOAP actions. - * - Maps actions to SOAPAction headers (from rr-constants) - * - Maps actions to Mustache template filenames (xml-templates/*.xml) - * - Provides verification helpers to ensure templates exist - * - Provides normalized SOAP headers used by the transport - */ - -const path = require("path"); -const fs = require("fs/promises"); -const { RR_ACTIONS, RR_SOAP_HEADERS } = require("./rr-constants"); -const mustache = require("mustache"); - -// ---- Action <-> Template wiring ---- -// Keep action names consistent with rr-helpers / rr-lookup / rr-repair-orders / rr-customer -const ACTION_TEMPLATES = Object.freeze({ - InsertCustomer: "InsertCustomer", - UpdateCustomer: "UpdateCustomer", - InsertServiceVehicle: "InsertServiceVehicle", - CreateRepairOrder: "CreateRepairOrder", - UpdateRepairOrder: "UpdateRepairOrder", - GetAdvisors: "GetAdvisors", - GetParts: "GetParts", - CombinedSearch: "CombinedSearch" -}); - -/** - * Get the SOAPAction string for a known action. - * Throws if action is unknown. - */ -function getSoapAction(action) { - const entry = RR_ACTIONS[action]; - if (!entry) { - const known = Object.keys(RR_ACTIONS).join(", "); - throw new Error(`Unknown RR action "${action}". Known: ${known}`); - } - return entry.soapAction; -} - -/** - * Get the template filename (without extension) for a known action. - * e.g., "CreateRepairOrder" -> "CreateRepairOrder" - */ -function getTemplateForAction(action) { - const tpl = ACTION_TEMPLATES[action]; - if (!tpl) { - const known = Object.keys(ACTION_TEMPLATES).join(", "); - throw new Error(`No template mapping for RR action "${action}". Known: ${known}`); - } - return tpl; -} - -/** - * Build headers for a SOAP request, including SOAPAction. - * Consumers: rr-helpers (transport). - */ -function buildSoapHeadersForAction(action) { - return { - ...RR_SOAP_HEADERS, - SOAPAction: getSoapAction(action) - }; -} - -/** - * List all known actions with their SOAPAction + template. - * Useful for diagnostics (e.g., /rr/actions route). - */ -function listActions() { - return Object.keys(ACTION_TEMPLATES).map((action) => ({ - action, - soapAction: getSoapAction(action), - template: getTemplateForAction(action) - })); -} - -/** - * Verify that every required template exists in xml-templates/. - * Returns an array of issues; empty array means all good. - */ -async function verifyTemplatesExist() { - const issues = []; - const baseDir = path.join(__dirname, "xml-templates"); - - for (const [action, tpl] of Object.entries(ACTION_TEMPLATES)) { - const filePath = path.join(baseDir, `${tpl}.xml`); - try { - const contents = await fs.readFile(filePath, "utf8"); // throws if missing - try { - // Parse-only to catch “Unclosed section …” and similar - mustache.parse(contents); - } catch (parseErr) { - issues.push({ action, template: tpl, error: `Mustache parse error: ${parseErr.message}`, filePath }); - } - } catch { - issues.push({ action, template: tpl, error: `Missing file: ${filePath}` }); - } - } - return issues; -} -/** - * Quick assert that throws if any template is missing. - * You can call this once during boot and log the result. - */ -async function assertTemplates() { - const issues = await verifyTemplatesExist(); - if (issues.length) { - const msg = - "RR xml-templates verification failed:\n" + - issues.map((i) => ` - ${i.action} -> ${i.template}.xml :: ${i.error}`).join("\n"); - throw new Error(msg); - } -} - -module.exports = { - // Maps / helpers - ACTION_TEMPLATES, - listActions, - getSoapAction, - getTemplateForAction, - buildSoapHeadersForAction, - - // Verification - verifyTemplatesExist, - assertTemplates -}; diff --git a/server/rr/rrRoutes.js b/server/rr/rrRoutes.js index ebf4b5b2c..6339f3212 100644 --- a/server/rr/rrRoutes.js +++ b/server/rr/rrRoutes.js @@ -1,18 +1,5 @@ -/** - * @file rrRoutes.js - * @description Express routes for Reynolds & Reynolds (Rome) integration. - * Endpoints: - * - POST /rr/customer/insert - * - POST /rr/customer/update - * - POST /rr/repair-order/create - * - POST /rr/repair-order/update - * - POST /rr/lookup/advisors - * - POST /rr/lookup/parts - * - POST /rr/lookup/combined-search - * - POST /rr/export/job - * - GET /rr/actions - * - GET /rr/templates/verify - */ +// server/rr/rrRoutes.js +"use strict"; const express = require("express"); const router = express.Router(); @@ -20,19 +7,12 @@ const router = express.Router(); const RRLogger = require("./rr-logger"); const { RrApiError } = require("./rr-error"); -// Domain modules -const customerApi = require("./rr-customer"); // insertCustomer, updateCustomer -const roApi = require("./rr-repair-orders"); // createRepairOrder, updateRepairOrder -const lookupApi = require("./rr-lookup"); // getAdvisors, getParts, combinedSearch -const { exportJobToRR } = require("./rr-job-export"); // orchestrator +const customerApi = require("./rr-customer"); +const roApi = require("./rr-repair-orders"); +const lookupApi = require("./rr-lookup"); +const { exportJobToRR } = require("./rr-job-export"); -// Diagnostics -const { listActions, verifyTemplatesExist } = require("./rr-wsdl"); - -// DB-driven RR config (no env fallback for dealer/store/branch here) -const { getRRConfigForBodyshop } = require("./rr-config"); - -// -------------------- Helpers -------------------- +// --- helpers --- function ok(res, payload = {}) { return res.json({ success: true, ...payload }); @@ -44,174 +24,144 @@ function fail(res, error, status = 400) { } function socketOf(req) { - // If you stash a socket/logging context on the app, grab it; otherwise null - return (req.app && req.app.get && req.app.get("socket")) || null; + try { + return req.app?.get?.("socket") || null; + } catch { + return null; + } } -/** - * Resolve the per-bodyshop RR config strictly from DB. - * Looks for bodyshopId in: - * - req.body.bodyshopId - * - req.body.job?.shopid - * - x-bodyshop-id header - * Throws if not found. - */ -async function resolveRRConfigHttp(req) { - const candidateHeader = req.get && req.get("x-bodyshop-id"); - const body = req.body || {}; - const bodyshopId = body.bodyshopId || (body.job && (body.job.shopid || body.job.bodyshopId)) || candidateHeader; - +function requireBodyshopId(req) { + const body = req?.body || {}; + const fromBody = body.bodyshopId; + const fromJob = body.job && (body.job.shopid || body.job.bodyshopId); + const fromHeader = typeof req.get === "function" ? req.get("x-bodyshop-id") : undefined; + const bodyshopId = fromBody || fromJob || fromHeader; if (!bodyshopId) { throw new RrApiError( - "Missing bodyshopId (expected in body.bodyshopId, body.job.shopid, or x-bodyshop-id header)", + "Missing bodyshopId (in body.bodyshopId, body.job.shopid/bodyshopId, or x-bodyshop-id header)", "BAD_REQUEST" ); } - - return getRRConfigForBodyshop(bodyshopId); + return bodyshopId; } -// -------------------- Customers -------------------- +// --- customers --- router.post("/rr/customer/insert", async (req, res) => { const socket = socketOf(req); - const { customer } = req.body || {}; - try { + const bodyshopId = requireBodyshopId(req); + const { customer } = req.body || {}; if (!customer) throw new RrApiError("Missing 'customer' in request body", "BAD_REQUEST"); - const cfg = await resolveRRConfigHttp(req); // DB-driven, required - const result = await customerApi.insertCustomer(socket, customer, cfg); - return ok(res, result); - } catch (err) { - RRLogger(socket, "error", "RR /customer/insert failed", { err: err.message }); - return fail(res, err); + const result = await customerApi.insertCustomer({ bodyshopId, payload: customer }); + RRLogger(socket)("info", "RR customer insert", { bodyshopId }); + return ok(res, { data: result.data }); + } catch (e) { + RRLogger(socket)("error", "RR /rr/customer/insert failed", { error: e.message }); + return fail(res, e); } }); router.post("/rr/customer/update", async (req, res) => { const socket = socketOf(req); - const { customer } = req.body || {}; - try { + const bodyshopId = requireBodyshopId(req); + const { customer } = req.body || {}; if (!customer) throw new RrApiError("Missing 'customer' in request body", "BAD_REQUEST"); - const cfg = await resolveRRConfigHttp(req); - const result = await customerApi.updateCustomer(socket, customer, cfg); - return ok(res, result); - } catch (err) { - RRLogger(socket, "error", "RR /customer/update failed", { err: err.message }); - return fail(res, err); + const result = await customerApi.updateCustomer({ bodyshopId, payload: customer }); + RRLogger(socket)("info", "RR customer update", { bodyshopId }); + return ok(res, { data: result.data }); + } catch (e) { + RRLogger(socket)("error", "RR /rr/customer/update failed", { error: e.message }); + return fail(res, e); } }); -// -------------------- Repair Orders -------------------- +// --- repair orders --- router.post("/rr/repair-order/create", async (req, res) => { const socket = socketOf(req); - const { job } = req.body || {}; - try { - if (!job) throw new RrApiError("Missing 'job' in request body", "BAD_REQUEST"); - const cfg = await resolveRRConfigHttp(req); - const result = await roApi.createRepairOrder(socket, job, cfg); - return ok(res, result); - } catch (err) { - RRLogger(socket, "error", "RR /repair-order/create failed", { err: err.message }); - return fail(res, err); + const bodyshopId = requireBodyshopId(req); + const { ro } = req.body || {}; + if (!ro) throw new RrApiError("Missing 'ro' in request body", "BAD_REQUEST"); + const result = await roApi.createRepairOrder({ bodyshopId, payload: ro }); + RRLogger(socket)("info", "RR create RO", { bodyshopId }); + return ok(res, { data: result.data }); + } catch (e) { + RRLogger(socket)("error", "RR /rr/repair-order/create failed", { error: e.message }); + return fail(res, e); } }); router.post("/rr/repair-order/update", async (req, res) => { const socket = socketOf(req); - const { job } = req.body || {}; - try { - if (!job) throw new RrApiError("Missing 'job' in request body", "BAD_REQUEST"); - const cfg = await resolveRRConfigHttp(req); - const result = await roApi.updateRepairOrder(socket, job, cfg); - return ok(res, result); - } catch (err) { - RRLogger(socket, "error", "RR /repair-order/update failed", { err: err.message }); - return fail(res, err); + const bodyshopId = requireBodyshopId(req); + const { ro } = req.body || {}; + if (!ro) throw new RrApiError("Missing 'ro' in request body", "BAD_REQUEST"); + const result = await roApi.updateRepairOrder({ bodyshopId, payload: ro }); + RRLogger(socket)("info", "RR update RO", { bodyshopId }); + return ok(res, { data: result.data }); + } catch (e) { + RRLogger(socket)("error", "RR /rr/repair-order/update failed", { error: e.message }); + return fail(res, e); } }); -// -------------------- Lookups -------------------- +// --- lookups --- router.post("/rr/lookup/advisors", async (req, res) => { const socket = socketOf(req); - const { criteria = {} } = req.body || {}; - try { - const cfg = await resolveRRConfigHttp(req); - const result = await lookupApi.getAdvisors(socket, criteria, cfg); - return ok(res, result); - } catch (err) { - RRLogger(socket, "error", "RR /lookup/advisors failed", { err: err.message }); - return fail(res, err); + const bodyshopId = requireBodyshopId(req); + const result = await lookupApi.getAdvisors({ bodyshopId, ...req.body }); + return ok(res, { data: result.data }); + } catch (e) { + RRLogger(socket)("error", "RR /rr/lookup/advisors failed", { error: e.message }); + return fail(res, e); } }); router.post("/rr/lookup/parts", async (req, res) => { const socket = socketOf(req); - const { criteria = {} } = req.body || {}; - try { - const cfg = await resolveRRConfigHttp(req); - const result = await lookupApi.getParts(socket, criteria, cfg); - return ok(res, result); - } catch (err) { - RRLogger(socket, "error", "RR /lookup/parts failed", { err: err.message }); - return fail(res, err); + const bodyshopId = requireBodyshopId(req); + const result = await lookupApi.getParts({ bodyshopId, ...req.body }); + return ok(res, { data: result.data }); + } catch (e) { + RRLogger(socket)("error", "RR /rr/lookup/parts failed", { error: e.message }); + return fail(res, e); } }); router.post("/rr/lookup/combined-search", async (req, res) => { const socket = socketOf(req); - const { criteria = {} } = req.body || {}; - try { - const cfg = await resolveRRConfigHttp(req); - const result = await lookupApi.combinedSearch(socket, criteria, cfg); - return ok(res, result); - } catch (err) { - RRLogger(socket, "error", "RR /lookup/combined-search failed", { err: err.message }); - return fail(res, err); + const bodyshopId = requireBodyshopId(req); + const result = await lookupApi.combinedSearch({ bodyshopId, ...req.body }); + return ok(res, { data: result.data }); + } catch (e) { + RRLogger(socket)("error", "RR /rr/lookup/combined-search failed", { error: e.message }); + return fail(res, e); } }); -// -------------------- Orchestrated export -------------------- +// --- export orchestrator --- router.post("/rr/export/job", async (req, res) => { const socket = socketOf(req); - const { job, options = {} } = req.body || {}; - + const logger = (level, message, ctx) => RRLogger(socket)(level, message, ctx); try { + const bodyshopId = requireBodyshopId(req); + const { job, options = {} } = req.body || {}; if (!job) throw new RrApiError("Missing 'job' in request body", "BAD_REQUEST"); - const cfg = await resolveRRConfigHttp(req); - const result = await exportJobToRR(socket, job, cfg, options); - return ok(res, result); - } catch (err) { - RRLogger(socket, "error", "RR /export/job failed", { err: err.message }); - return fail(res, err); - } -}); - -// -------------------- Diagnostics -------------------- - -router.get("/rr/actions", (_req, res) => { - try { - return ok(res, { actions: listActions() }); - } catch (err) { - return fail(res, err); - } -}); - -router.get("/rr/templates/verify", async (_req, res) => { - try { - const issues = await verifyTemplatesExist(); - return ok(res, { ok: issues.length === 0, issues }); - } catch (err) { - return fail(res, err); + const data = await exportJobToRR({ bodyshopId, job, logger, ...options }); + return ok(res, { data }); + } catch (e) { + RRLogger(socket)("error", "RR /rr/export/job failed", { error: e.message }); + return fail(res, e); } }); diff --git a/server/rr/withClient.js b/server/rr/withClient.js new file mode 100644 index 000000000..2b5b64ba9 --- /dev/null +++ b/server/rr/withClient.js @@ -0,0 +1,11 @@ +const { getRRConfigForBodyshop } = require("./rr-config"); +const { makeRRClient } = require("./rr-client"); +const logger = require("../utils/logger"); + +async function withClient(bodyshopId, fn) { + const routing = await getRRConfigForBodyshop(bodyshopId); + const client = makeRRClient({ logger }); + return fn(client, routing); +} + +module.exports = { withClient }; diff --git a/server/rr/xml-templates/CombinedSearch.xml b/server/rr/xml-templates/CombinedSearch.xml deleted file mode 100644 index 9190d0470..000000000 --- a/server/rr/xml-templates/CombinedSearch.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - {{#Customer.PhoneNumber}}{{/Customer.PhoneNumber}} - - {{#Customer.FirstName}}{{Customer.FirstName}}{{/Customer.FirstName}} - {{#Customer.LastName}}{{Customer.LastName}}{{/Customer.LastName}} - {{#Customer.EmailAddress}}{{Customer.EmailAddress}}{{/Customer.EmailAddress}} - - {{#Vehicle.VIN}}{{Vehicle.VIN}}{{/Vehicle.VIN}} - {{#Vehicle.LicensePlate}}{{Vehicle.LicensePlate}}{{/Vehicle.LicensePlate}} - - - diff --git a/server/rr/xml-templates/CreateRepairOrder.xml b/server/rr/xml-templates/CreateRepairOrder.xml deleted file mode 100644 index 0220d63df..000000000 --- a/server/rr/xml-templates/CreateRepairOrder.xml +++ /dev/null @@ -1,123 +0,0 @@ - - - - {{RepairOrderNumber}} - {{#DmsRepairOrderId}}{{DmsRepairOrderId}}{{/DmsRepairOrderId}} - {{#OpenDate}}{{OpenDate}}{{/OpenDate}} - {{#PromisedDate}}{{PromisedDate}}{{/PromisedDate}} - {{#CloseDate}}{{CloseDate}}{{/CloseDate}} - {{#ServiceAdvisorId}}{{ServiceAdvisorId}}{{/ServiceAdvisorId}} - {{#TechnicianId}}{{TechnicianId}}{{/TechnicianId}} - {{#Department}}{{Department}}{{/Department}} - {{#ProfitCenter}}{{ProfitCenter}}{{/ProfitCenter}} - {{#ROType}}{{ROType}}{{/ROType}} - {{#Status}}{{Status}}{{/Status}} - {{#IsBodyShop}}{{IsBodyShop}}{{/IsBodyShop}} - {{#DRPFlag}}{{DRPFlag}}{{/DRPFlag}} - - - {{#CustomerId}}{{CustomerId}}{{/CustomerId}} - {{#CustomerName}}{{CustomerName}}{{/CustomerName}} - {{#PhoneNumber}}{{PhoneNumber}}{{/PhoneNumber}} - {{#EmailAddress}}{{EmailAddress}}{{/EmailAddress}} - {{#Address}} -
- {{#Line1}}{{Line1}}{{/Line1}} - {{#Line2}}{{Line2}}{{/Line2}} - {{#City}}{{City}}{{/City}} - {{#State}}{{State}}{{/State}} - {{#PostalCode}}{{PostalCode}}{{/PostalCode}} - {{#Country}}{{Country}}{{/Country}} -
- {{/Address}} -
- - - {{#VehicleId}}{{VehicleId}}{{/VehicleId}} - {{#VIN}}{{VIN}}{{/VIN}} - {{#LicensePlate}}{{LicensePlate}}{{/LicensePlate}} - {{#Year}}{{Year}}{{/Year}} - {{#Make}}{{Make}}{{/Make}} - {{#Model}}{{Model}}{{/Model}} - {{#Odometer}}{{Odometer}}{{/Odometer}} - {{#Color}}{{Color}}{{/Color}} - - - {{#JobLines}} - - {{Sequence}} - {{#ParentSequence}}{{ParentSequence}}{{/ParentSequence}} - {{#LineType}}{{LineType}}{{/LineType}} - {{#Category}}{{Category}}{{/Category}} - {{#OpCode}}{{OpCode}}{{/OpCode}} - {{#Description}}{{Description}}{{/Description}} - {{#LaborHours}}{{LaborHours}}{{/LaborHours}} - {{#LaborRate}}{{LaborRate}}{{/LaborRate}} - {{#PartNumber}}{{PartNumber}}{{/PartNumber}} - {{#PartDescription}}{{PartDescription}}{{/PartDescription}} - {{#Quantity}}{{Quantity}}{{/Quantity}} - {{#UnitPrice}}{{UnitPrice}}{{/UnitPrice}} - {{#ExtendedPrice}}{{ExtendedPrice}}{{/ExtendedPrice}} - {{#DiscountAmount}}{{DiscountAmount}}{{/DiscountAmount}} - {{#TaxCode}}{{TaxCode}}{{/TaxCode}} - {{#GLAccount}}{{GLAccount}}{{/GLAccount}} - {{#ControlNumber}}{{ControlNumber}}{{/ControlNumber}} - - {{#Taxes}} - - {{#Items}} - - {{Code}} - {{Amount}} - {{#Rate}}{{Rate}}{{/Rate}} - - {{/Items}} - - {{/Taxes}} - - {{/JobLines}} - - {{#Totals}} - - {{#Currency}}{{Currency}}{{/Currency}} - {{#LaborTotal}}{{LaborTotal}}{{/LaborTotal}} - {{#PartsTotal}}{{PartsTotal}}{{/PartsTotal}} - {{#MiscTotal}}{{MiscTotal}}{{/MiscTotal}} - {{#DiscountTotal}}{{DiscountTotal}}{{/DiscountTotal}} - {{#TaxTotal}}{{TaxTotal}}{{/TaxTotal}} - {{GrandTotal}} - - {{/Totals}} - - {{#Payments}} - - {{#Items}} - - {{PayerType}} - {{#PayerName}}{{PayerName}}{{/PayerName}} - {{Amount}} - {{#Method}}{{Method}}{{/Method}} - {{#Reference}}{{Reference}}{{/Reference}} - {{#ControlNumber}}{{ControlNumber}}{{/ControlNumber}} - - {{/Items}} - - {{/Payments}} - - {{#Insurance}} - - {{#CompanyName}}{{CompanyName}}{{/CompanyName}} - {{#ClaimNumber}}{{ClaimNumber}}{{/ClaimNumber}} - {{#AdjusterName}}{{AdjusterName}}{{/AdjusterName}} - {{#AdjusterPhone}}{{AdjusterPhone}}{{/AdjusterPhone}} - - {{/Insurance}} - - {{#Notes}} - - {{#Items}}{{.}}{{/Items}} - - {{/Notes}} -
-
-
diff --git a/server/rr/xml-templates/GetAdvisors.xml b/server/rr/xml-templates/GetAdvisors.xml deleted file mode 100644 index 653c1769a..000000000 --- a/server/rr/xml-templates/GetAdvisors.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - {{#SearchCriteria.AdvisorId}}{{SearchCriteria.AdvisorId}}{{/SearchCriteria.AdvisorId}} - {{#SearchCriteria.FirstName}}{{SearchCriteria.FirstName}}{{/SearchCriteria.FirstName}} - {{#SearchCriteria.LastName}}{{SearchCriteria.LastName}}{{/SearchCriteria.LastName}} - {{#SearchCriteria.Department}}{{SearchCriteria.Department}}{{/SearchCriteria.Department}} - {{#SearchCriteria.Status}}{{SearchCriteria.Status}}{{/SearchCriteria.Status}} - {{#SearchCriteria.IncludeInactive}}{{SearchCriteria.IncludeInactive}}{{/SearchCriteria.IncludeInactive}} - {{#SearchCriteria.PageNumber}}{{SearchCriteria.PageNumber}}{{/SearchCriteria.PageNumber}} - {{#SearchCriteria.SortBy}}{{SearchCriteria.SortBy}}{{/SearchCriteria.SortBy}} - {{#SearchCriteria.SortDirection}}{{SearchCriteria.SortDirection}}{{/SearchCriteria.SortDirection}} - - - diff --git a/server/rr/xml-templates/GetParts.xml b/server/rr/xml-templates/GetParts.xml deleted file mode 100644 index 02103e5cf..000000000 --- a/server/rr/xml-templates/GetParts.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - {{#PartNumber}}{{PartNumber}}{{/PartNumber}} - {{#Description}}{{Description}}{{/Description}} - {{#Make}}{{Make}}{{/Make}} - {{#Model}}{{Model}}{{/Model}} - {{#Year}}{{Year}}{{/Year}} - {{#Vendor}}{{Vendor}}{{/Vendor}} - {{#Category}}{{Category}}{{/Category}} - {{#Brand}}{{Brand}}{{/Brand}} - {{#IsOEM}}{{IsOEM}}{{/IsOEM}} - {{#IsAftermarket}}{{IsAftermarket}}{{/IsAftermarket}} - {{#InStock}}{{InStock}}{{/InStock}} - {{#Warehouse}}{{Warehouse}}{{/Warehouse}} - {{#Location}}{{Location}}{{/Location}} - {{#MinPrice}}{{MinPrice}}{{/MinPrice}} - {{#MaxPrice}}{{MaxPrice}}{{/MaxPrice}} - {{#Currency}}{{Currency}}{{/Currency}} - {{#SearchMode}}{{SearchMode}}{{/SearchMode}} - {{#SortBy}}{{SortBy}}{{/SortBy}} - {{#SortDirection}}{{SortDirection}}{{/SortDirection}} - - - diff --git a/server/rr/xml-templates/InsertCustomer.xml b/server/rr/xml-templates/InsertCustomer.xml deleted file mode 100644 index b9cdea69b..000000000 --- a/server/rr/xml-templates/InsertCustomer.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - {{#CustomerNumber}}{{CustomerNumber}}{{/CustomerNumber}} - {{#CustomerType}} - {{CustomerType}}{{/CustomerType}} - {{CustomerName}} - {{#DisplayName}}{{DisplayName}}{{/DisplayName}} - {{#Language}}{{Language}}{{/Language}} - {{#GroupName}}{{GroupName}}{{/GroupName}} - {{#TaxExempt}}{{TaxExempt}}{{/TaxExempt}} - {{#DiscountLevel}}{{DiscountLevel}}{{/DiscountLevel}} - {{#Active}}{{Active}}{{/Active}} - {{#Addresses}} -
- {{#Type}}{{Type}}{{/Type}} - {{#Line1}}{{Line1}}{{/Line1}} - {{#Line2}}{{Line2}}{{/Line2}} - {{#City}}{{City}}{{/City}} - {{#State}}{{State}}{{/State}} - {{#PostalCode}}{{PostalCode}}{{/PostalCode}} - {{#Country}}{{Country}}{{/Country}} -
- {{/Addresses}} - {{#Phones}} - - {{Type}} - {{Number}} - {{#Extension}}{{Extension}}{{/Extension}} - {{#Preferred}}{{Preferred}}{{/Preferred}} - - {{/Phones}} - {{#Emails}} - - {{Type}} -
{{Address}}
- {{#Preferred}}{{Preferred}}{{/Preferred}} -
- {{/Emails}} - {{#Insurance}} - - {{#CompanyName}}{{CompanyName}}{{/CompanyName}} - {{#PolicyNumber}}{{PolicyNumber}}{{/PolicyNumber}} - {{#ExpirationDate}}{{ExpirationDate}}{{/ExpirationDate}} - {{#ContactName}}{{ContactName}}{{/ContactName}} - {{#ContactPhone}}{{ContactPhone}}{{/ContactPhone}} - - {{/Insurance}} - {{#LinkedAccounts}} - - {{Type}} - {{AccountNumber}} - {{#CreditLimit}}{{CreditLimit}}{{/CreditLimit}} - - {{/LinkedAccounts}} - {{#Notes}} - - {{#Items}}{{.}}{{/Items}} - - {{/Notes}} -
-
-
diff --git a/server/rr/xml-templates/InsertServiceVehicle.xml b/server/rr/xml-templates/InsertServiceVehicle.xml deleted file mode 100644 index faecf40d7..000000000 --- a/server/rr/xml-templates/InsertServiceVehicle.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - {{#CustomerId}}{{CustomerId}}{{/CustomerId}} - {{#VIN}}{{VIN}}{{/VIN}} - {{#UnitNumber}}{{UnitNumber}}{{/UnitNumber}} - {{#StockNumber}}{{StockNumber}}{{/StockNumber}} - {{#Year}}{{Year}}{{/Year}} - {{#Make}}{{Make}}{{/Make}} - {{#Model}}{{Model}}{{/Model}} - {{#Trim}}{{Trim}}{{/Trim}} - {{#BodyStyle}}{{BodyStyle}}{{/BodyStyle}} - {{#Transmission}}{{Transmission}}{{/Transmission}} - {{#Engine}}{{Engine}}{{/Engine}} - {{#FuelType}}{{FuelType}}{{/FuelType}} - {{#DriveType}}{{DriveType}}{{/DriveType}} - {{#Color}}{{Color}}{{/Color}} - {{#LicensePlate}}{{LicensePlate}}{{/LicensePlate}} - {{#LicenseState}}{{LicenseState}}{{/LicenseState}} - {{#RegistrationExpiry}}{{RegistrationExpiry}}{{/RegistrationExpiry}} - {{#Odometer}}{{Odometer}}{{/Odometer}} - {{#OdometerUnits}} - {{OdometerUnits}}{{/OdometerUnits}} - {{#InServiceDate}}{{InServiceDate}}{{/InServiceDate}} - {{#Ownership}} - - {{#OwnerId}}{{OwnerId}}{{/OwnerId}} - {{#OwnerName}}{{OwnerName}}{{/OwnerName}} - {{#OwnershipType}} - {{OwnershipType}}{{/OwnershipType}} - - {{/Ownership}} - {{#Insurance}} - - {{#CompanyName}}{{CompanyName}}{{/CompanyName}} - {{#PolicyNumber}}{{PolicyNumber}}{{/PolicyNumber}} - {{#ExpirationDate}}{{ExpirationDate}}{{/ExpirationDate}} - {{#ContactName}}{{ContactName}}{{/ContactName}} - {{#ContactPhone}}{{ContactPhone}}{{/ContactPhone}} - - {{/Insurance}} - {{#Warranty}} - - {{#WarrantyCompany}}{{WarrantyCompany}}{{/WarrantyCompany}} - {{#WarrantyNumber}}{{WarrantyNumber}}{{/WarrantyNumber}} - {{#WarrantyType}}{{WarrantyType}}{{/WarrantyType}} - {{#ExpirationDate}}{{ExpirationDate}}{{/ExpirationDate}} - - {{/Warranty}} - {{#VehicleNotes}} - - {{#Items}}{{.}}{{/Items}} - - {{/VehicleNotes}} - - - diff --git a/server/rr/xml-templates/UpdateCustomer.xml b/server/rr/xml-templates/UpdateCustomer.xml deleted file mode 100644 index c6db8d216..000000000 --- a/server/rr/xml-templates/UpdateCustomer.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - {{CustomerId}} - {{#CustomerType}} - {{CustomerType}}{{/CustomerType}} - {{#CustomerName}}{{CustomerName}}{{/CustomerName}} - {{#DisplayName}}{{DisplayName}}{{/DisplayName}} - {{#PreferredName}}{{PreferredName}}{{/PreferredName}} - {{#Language}}{{Language}}{{/Language}} - {{#GroupName}}{{GroupName}}{{/GroupName}} - {{#TaxExempt}}{{TaxExempt}}{{/TaxExempt}} - {{#DiscountLevel}}{{DiscountLevel}}{{/DiscountLevel}} - {{#Active}}{{Active}}{{/Active}} - {{#Addresses}} -
- {{#AddressId}}{{AddressId}}{{/AddressId}} - {{#Type}} - {{Type}}{{/Type}} - {{#Line1}}{{Line1}}{{/Line1}} - {{#Line2}}{{Line2}}{{/Line2}} - {{#City}}{{City}}{{/City}} - {{#State}}{{State}}{{/State}} - {{#PostalCode}}{{PostalCode}}{{/PostalCode}} - {{#Country}}{{Country}}{{/Country}} - {{#IsPrimary}}{{IsPrimary}}{{/IsPrimary}} - {{#IsDeleted}}{{IsDeleted}}{{/IsDeleted}} -
- {{/Addresses}} - {{#Phones}} - - {{#PhoneId}}{{PhoneId}}{{/PhoneId}} - {{#Type}}{{Type}}{{/Type}} - {{#Number}}{{Number}}{{/Number}} - {{#Extension}}{{Extension}}{{/Extension}} - {{#Preferred}}{{Preferred}}{{/Preferred}} - {{#IsDeleted}}{{IsDeleted}}{{/IsDeleted}} - - {{/Phones}} - {{#Emails}} - - {{#EmailId}}{{EmailId}}{{/EmailId}} - {{#Type}}{{Type}}{{/Type}} - {{#Address}}
{{Address}}
{{/Address}} - {{#Preferred}}{{Preferred}}{{/Preferred}} - {{#IsDeleted}}{{IsDeleted}}{{/IsDeleted}} -
- {{/Emails}} - {{#DriverLicense}} - - {{#LicenseNumber}}{{LicenseNumber}}{{/LicenseNumber}} - {{#LicenseState}}{{LicenseState}}{{/LicenseState}} - {{#ExpirationDate}}{{ExpirationDate}}{{/ExpirationDate}} - - {{/DriverLicense}} - {{#Insurance}} - - {{#CompanyName}}{{CompanyName}}{{/CompanyName}} - {{#PolicyNumber}}{{PolicyNumber}}{{/PolicyNumber}} - {{#ExpirationDate}}{{ExpirationDate}}{{/ExpirationDate}} - {{#ContactName}}{{ContactName}}{{/ContactName}} - {{#ContactPhone}}{{ContactPhone}}{{/ContactPhone}} - - {{/Insurance}} - {{#LinkedAccounts}} - - {{#AccountId}}{{AccountId}}{{/AccountId}} - {{Type}} - - {{#AccountNumber}}{{AccountNumber}}{{/AccountNumber}} - {{#CreditLimit}}{{CreditLimit}}{{/CreditLimit}} - {{#IsDeleted}}{{IsDeleted}}{{/IsDeleted}} - - {{/LinkedAccounts}} - - {{#Notes}} - - {{#Items}}{{.}}{{/Items}} - - {{/Notes}} -
-
-
diff --git a/server/rr/xml-templates/UpdateRepairOrder.xml b/server/rr/xml-templates/UpdateRepairOrder.xml deleted file mode 100644 index 85a1d4428..000000000 --- a/server/rr/xml-templates/UpdateRepairOrder.xml +++ /dev/null @@ -1,123 +0,0 @@ - - - - {{RepairOrderNumber}} - {{#DmsRepairOrderId}}{{DmsRepairOrderId}}{{/DmsRepairOrderId}} - {{#OpenDate}}{{OpenDate}}{{/OpenDate}} - {{#PromisedDate}}{{PromisedDate}}{{/PromisedDate}} - {{#CloseDate}}{{CloseDate}}{{/CloseDate}} - {{#ServiceAdvisorId}}{{ServiceAdvisorId}}{{/ServiceAdvisorId}} - {{#TechnicianId}}{{TechnicianId}}{{/TechnicianId}} - {{#Department}}{{Department}}{{/Department}} - {{#ProfitCenter}}{{ProfitCenter}}{{/ProfitCenter}} - {{#ROType}}{{ROType}}{{/ROType}} - {{#Status}}{{Status}}{{/Status}} - {{#IsBodyShop}}{{IsBodyShop}}{{/IsBodyShop}} - {{#DRPFlag}}{{DRPFlag}}{{/DRPFlag}} - - - {{#CustomerId}}{{CustomerId}}{{/CustomerId}} - {{#CustomerName}}{{CustomerName}}{{/CustomerName}} - {{#PhoneNumber}}{{PhoneNumber}}{{/PhoneNumber}} - {{#EmailAddress}}{{EmailAddress}}{{/EmailAddress}} - {{#Address}} -
- {{#Line1}}{{Line1}}{{/Line1}} - {{#Line2}}{{Line2}}{{/Line2}} - {{#City}}{{City}}{{/City}} - {{#State}}{{State}}{{/State}} - {{#PostalCode}}{{PostalCode}}{{/PostalCode}} - {{#Country}}{{Country}}{{/Country}} -
- {{/Address}} -
- - - {{#VehicleId}}{{VehicleId}}{{/VehicleId}} - {{#VIN}}{{VIN}}{{/VIN}} - {{#LicensePlate}}{{LicensePlate}}{{/LicensePlate}} - {{#Year}}{{Year}}{{/Year}} - {{#Make}}{{Make}}{{/Make}} - {{#Model}}{{Model}}{{/Model}} - {{#Odometer}}{{Odometer}}{{/Odometer}} - {{#Color}}{{Color}}{{/Color}} - - - {{#JobLines}} - - {{Sequence}} - {{#ParentSequence}}{{ParentSequence}}{{/ParentSequence}} - {{#LineType}}{{LineType}}{{/LineType}} - {{#Category}}{{Category}}{{/Category}} - {{#OpCode}}{{OpCode}}{{/OpCode}} - {{#Description}}{{Description}}{{/Description}} - {{#LaborHours}}{{LaborHours}}{{/LaborHours}} - {{#LaborRate}}{{LaborRate}}{{/LaborRate}} - {{#PartNumber}}{{PartNumber}}{{/PartNumber}} - {{#PartDescription}}{{PartDescription}}{{/PartDescription}} - {{#Quantity}}{{Quantity}}{{/Quantity}} - {{#UnitPrice}}{{UnitPrice}}{{/UnitPrice}} - {{#ExtendedPrice}}{{ExtendedPrice}}{{/ExtendedPrice}} - {{#DiscountAmount}}{{DiscountAmount}}{{/DiscountAmount}} - {{#TaxCode}}{{TaxCode}}{{/TaxCode}} - {{#GLAccount}}{{GLAccount}}{{/GLAccount}} - {{#ControlNumber}}{{ControlNumber}}{{/ControlNumber}} - - {{#Taxes}} - - {{#Items}} - - {{Code}} - {{Amount}} - {{#Rate}}{{Rate}}{{/Rate}} - - {{/Items}} - - {{/Taxes}} - - {{/JobLines}} - - {{#Totals}} - - {{#Currency}}{{Currency}}{{/Currency}} - {{#LaborTotal}}{{LaborTotal}}{{/LaborTotal}} - {{#PartsTotal}}{{PartsTotal}}{{/PartsTotal}} - {{#MiscTotal}}{{MiscTotal}}{{/MiscTotal}} - {{#DiscountTotal}}{{DiscountTotal}}{{/DiscountTotal}} - {{#TaxTotal}}{{TaxTotal}}{{/TaxTotal}} - {{GrandTotal}} - - {{/Totals}} - - {{#Payments}} - - {{#Items}} - - {{PayerType}} - {{#PayerName}}{{PayerName}}{{/PayerName}} - {{Amount}} - {{#Method}}{{Method}}{{/Method}} - {{#Reference}}{{Reference}}{{/Reference}} - {{#ControlNumber}}{{ControlNumber}}{{/ControlNumber}} - - {{/Items}} - - {{/Payments}} - - {{#Insurance}} - - {{#CompanyName}}{{CompanyName}}{{/CompanyName}} - {{#ClaimNumber}}{{ClaimNumber}}{{/ClaimNumber}} - {{#AdjusterName}}{{AdjusterName}}{{/AdjusterName}} - {{#AdjusterPhone}}{{AdjusterPhone}}{{/AdjusterPhone}} - - {{/Insurance}} - - {{#Notes}} - - {{#Items}}{{.}}{{/Items}} - - {{/Notes}} -
-
-
diff --git a/server/web-sockets/redisSocketEvents.js b/server/web-sockets/redisSocketEvents.js index 7861c5c2b..4038c5aa9 100644 --- a/server/web-sockets/redisSocketEvents.js +++ b/server/web-sockets/redisSocketEvents.js @@ -5,7 +5,6 @@ const { FortellisJobExport, FortellisSelectedCustomer } = require("../fortellis/ const CdkCalculateAllocations = require("../cdk/cdk-calculate-allocations").default; const { exportJobToRR } = require("../rr/rr-job-export"); const lookupApi = require("../rr/rr-lookup"); -const { getRRConfigForBodyshop } = require("../rr/rr-config"); const redisSocketEvents = ({ io, @@ -341,94 +340,122 @@ const redisSocketEvents = ({ }); }; + // Reynolds & Reynolds socket events (uses new client-backed ops) const registerRREvents = (socket) => { + const log = (level, message, ctx) => RRLogger(socket)(level, message, ctx); + + const resolveBodyshopId = (payload, job) => + payload?.bodyshopId || socket.bodyshopId || job?.shopid || job?.bodyshopId; + + const resolveJobId = (explicitJobId, payload, job) => + explicitJobId || + payload?.jobid || + payload?.txEnvelope?.jobid || + job?.id || + payload?.txEnvelope?.job?.id || + null; + // Orchestrated Export (Customer → Vehicle → Repair Order) socket.on("rr-export-job", async (payload = {}) => { try { - // Back-compat: old callers: { jobid, txEnvelope }; new: { job, options } - // Prefer direct job, otherwise try txEnvelope.job const job = payload.job || payload.txEnvelope?.job; const options = payload.options || payload.txEnvelope?.options || {}; - // Resolve per-bodyshop RR config strictly from DB: - const bodyshopId = payload.bodyshopId || socket.bodyshopId || job?.shopid; - const cfg = await getRRConfigForBodyshop(bodyshopId); + const bodyshopId = resolveBodyshopId(payload, job); + const jobid = resolveJobId(payload.jobid, payload, job); if (!job) { - RRLogger(socket, "error", "RR export missing job payload"); + log("error", "RR export missing job payload", { jobid }); + return; + } + if (!bodyshopId) { + log("error", "RR export missing bodyshopId", { jobid }); return; } - const result = await exportJobToRR(socket, job, cfg, options); - // Broadcast to bodyshop room for UI to pick up - const room = getBodyshopRoom(socket.bodyshopId); - io.to(room).emit("rr-export-job:result", { jobid: job.id, result }); + const result = await exportJobToRR({ bodyshopId, job, logger: log, ...options }); + + // Broadcast keyed by bodyshop + include jobid + const room = getBodyshopRoom(bodyshopId); + io.to(room).emit("rr-export-job:result", { jobid, bodyshopId, result }); } catch (error) { - RRLogger(socket, "error", `Error during RR export: ${error.message}`); - logger.log("rr-job-export-error", "error", null, null, { message: error.message, stack: error.stack }); + const jobid = resolveJobId(payload?.jobid, payload, payload?.job || payload?.txEnvelope?.job); + log("error", `Error during RR export: ${error.message}`, { jobid, stack: error.stack }); + logger.log("rr-job-export-error", "error", null, null, { jobid, message: error.message, stack: error.stack }); } }); - // Combined search + // Combined search (customer/vehicle) socket.on("rr-lookup-combined", async ({ jobid, params } = {}, cb) => { try { - const cfg = await getRRConfigForBodyshop(socket.bodyshopId); - const data = await lookupApi.combinedSearch(socket, params || {}, cfg); - cb?.(data); + const bodyshopId = resolveBodyshopId({ bodyshopId: params?.bodyshopId }, null); + const resolvedJobId = resolveJobId(jobid, { jobid }, null); + if (!bodyshopId) throw new Error("Missing bodyshopId"); + + const res = await lookupApi.combinedSearch({ bodyshopId, ...(params || {}) }); + cb?.({ jobid: resolvedJobId, data: res?.data ?? res }); } catch (e) { - RRLogger(socket, "error", `RR combined lookup error: ${e.message}`); - cb?.(null); + log("error", `RR combined lookup error: ${e.message}`, { jobid }); + cb?.({ jobid, error: e.message }); } }); // Get Advisors socket.on("rr-get-advisors", async ({ jobid, params } = {}, cb) => { try { - const cfg = await getRRConfigForBodyshop(socket.bodyshopId); - const data = await lookupApi.getAdvisors(socket, params || {}, cfg); - cb?.(data); + const bodyshopId = resolveBodyshopId({ bodyshopId: params?.bodyshopId }, null); + const resolvedJobId = resolveJobId(jobid, { jobid }, null); + if (!bodyshopId) throw new Error("Missing bodyshopId"); + + const res = await lookupApi.getAdvisors({ bodyshopId, ...(params || {}) }); + cb?.({ jobid: resolvedJobId, data: res?.data ?? res }); } catch (e) { - RRLogger(socket, "error", `RR get advisors error: ${e.message}`); - cb?.(null); + log("error", `RR get advisors error: ${e.message}`, { jobid }); + cb?.({ jobid, error: e.message }); } }); // Get Parts socket.on("rr-get-parts", async ({ jobid, params } = {}, cb) => { try { - const cfg = await getRRConfigForBodyshop(socket.bodyshopId); - const data = await lookupApi.getParts(socket, params || {}, cfg); - cb?.(data); + const bodyshopId = resolveBodyshopId({ bodyshopId: params?.bodyshopId }, null); + const resolvedJobId = resolveJobId(jobid, { jobid }, null); + if (!bodyshopId) throw new Error("Missing bodyshopId"); + + const res = await lookupApi.getParts({ bodyshopId, ...(params || {}) }); + cb?.({ jobid: resolvedJobId, data: res?.data ?? res }); } catch (e) { - RRLogger(socket, "error", `RR get parts error: ${e.message}`); - cb?.(null); + log("error", `RR get parts error: ${e.message}`, { jobid }); + cb?.({ jobid, error: e.message }); } }); - // (Optional) Selected customer — only keep this if you actually implement it for RR + // Optional: Selected customer — currently a no-op for RR socket.on("rr-selected-customer", async ({ jobid, selectedCustomerId } = {}) => { - try { - RRLogger(socket, "info", "rr-selected-customer not implemented for RR (no-op)", { - jobid, - selectedCustomerId - }); - // If later you add support, call your implementation here. - } catch (error) { - RRLogger(socket, "error", `Error during RR selected-customer: ${error.message}`); - logger.log("rr-selected-customer-error", "error", null, null, { message: error.message, stack: error.stack }); - } + const resolvedJobId = resolveJobId(jobid, { jobid }, null); + log("info", "rr-selected-customer not implemented for RR (no-op)", { + jobid: resolvedJobId, + selectedCustomerId + }); }); - // Calculate allocations (unchanged — CDK utility) + // Calculate allocations (CDK utility unchanged) socket.on("rr-calculate-allocations", async (jobid, callback) => { try { - const allocations = await CdkCalculateAllocations(socket, jobid); - callback(allocations); + const resolvedJobId = resolveJobId(jobid, { jobid }, null); + const allocations = await CdkCalculateAllocations(socket, resolvedJobId); + callback({ jobid: resolvedJobId, allocations }); } catch (error) { - RRLogger(socket, "error", `Error during RR calculate allocations: ${error.message}`); - logger.log("rr-calc-allocations-error", "error", null, null, { message: error.message, stack: error.stack }); + log("error", `Error during RR calculate allocations: ${error.message}`, { jobid, stack: error.stack }); + logger.log("rr-calc-allocations-error", "error", null, null, { + jobid, + message: error.message, + stack: error.stack + }); + callback?.({ jobid, error: error.message }); } }); }; + // Call Handlers registerRoomAndBroadcastEvents(socket); registerUpdateEvents(socket);