From 75a40fbf436a88a39e8e8ba243c828ba3a18d264 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs Date: Mon, 8 Dec 2025 11:45:29 +0000 Subject: [PATCH] Delete apps/OpenSignServer/package-lock.json --- apps/OpenSign/package.json | 20 +-- .../public/locales/de/translation.json | 18 ++- .../public/locales/en/translation.json | 18 ++- .../public/locales/es/translation.json | 18 ++- .../public/locales/fr/translation.json | 20 ++- .../public/locales/hi/translation.json | 18 ++- .../public/locales/it/translation.json | 18 ++- apps/OpenSign/src/components/Header.jsx | 1 - .../src/components/pdf/Placeholder.jsx | 13 +- apps/OpenSign/src/constant/Utils.js | 115 +++++++++--------- apps/OpenSign/src/json/ReportJson.js | 20 +++ apps/OpenSign/src/pages/UserList.jsx | 70 ++++------- apps/OpenSign/src/primitives/SignerCell.jsx | 2 +- .../src/reports/template/TemplatesReport.jsx | 3 - .../cloud/customRoute/docxtopdf.js | 51 ++++++-- .../cloud/parsefunction/createBatchDocs.js | 1 - apps/OpenSignServer/index.js | 5 +- .../migrationdb/createContactIndex.js | 8 +- .../migrationdb/createDocumentIndex.js | 59 +++++++++ apps/OpenSignServer/migrationdb/index.js | 7 ++ apps/OpenSignServer/package.json | 18 +-- 21 files changed, 332 insertions(+), 171 deletions(-) create mode 100644 apps/OpenSignServer/migrationdb/createDocumentIndex.js create mode 100644 apps/OpenSignServer/migrationdb/index.js diff --git a/apps/OpenSign/package.json b/apps/OpenSign/package.json index 7223b03326..b4a0bda2ec 100644 --- a/apps/OpenSign/package.json +++ b/apps/OpenSign/package.json @@ -12,13 +12,13 @@ "axios": "^1.13.2", "date-fns-tz": "^3.2.0", "file-saver": "^2.0.5", - "i18next": "^25.6.3", + "i18next": "^25.7.1", "i18next-browser-languagedetector": "^8.2.0", "i18next-http-backend": "^3.0.2", "jszip": "^3.10.1", "jwt-decode": "^4.0.0", "moment": "^2.30.1", - "parse": "^7.0.2", + "parse": "^7.1.2", "pdf-lib": "^1.17.1", "pkijs": "^3.3.3", "print-js": "^1.6.0", @@ -28,7 +28,7 @@ "react": "^18.3.1", "react-bootstrap": "^2.10.10", "react-confetti": "^6.4.0", - "react-datepicker": "^8.9.0", + "react-datepicker": "^8.10.0", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", "react-dnd-multi-backend": "^9.0.0", @@ -41,7 +41,7 @@ "react-quill-new": "^3.6.0", "react-redux": "^9.2.0", "react-rnd": "^10.5.2", - "react-router": "^7.9.6", + "react-router": "^7.10.0", "react-scrollbars-custom": "^4.1.1", "react-select": "^5.10.2", "react-signature-canvas": "^1.1.0-alpha.2", @@ -103,7 +103,7 @@ "@testing-library/user-event": "^14.6.1", "@types/react": "^19.2.7", "@vitejs/plugin-react": "^5.1.1", - "@vitest/ui": "^4.0.13", + "@vitest/ui": "^4.0.15", "autoprefixer": "^10.4.22", "babel-loader": "^10.0.0", "commitizen": "^4.3.1", @@ -116,14 +116,18 @@ "jsdom": "^27.2.0", "lint-staged": "^16.2.7", "postcss": "^8.5.6", - "prettier": "^3.6.2", + "prettier": "^3.7.4", "pretty-quick": "^4.2.2", "rollup-plugin-node-polyfills": "^0.2.1", "tailwindcss": "^3.4.17", - "vite": "^7.2.4", + "tmp": "^0.2.5", + "vite": "^7.2.6", "vite-plugin-svgr": "^4.5.0", "vite-tsconfig-paths": "^5.1.4", - "vitest": "^4.0.13" + "vitest": "^4.0.15" + }, + "overrides": { + "tmp": "$tmp" }, "engines": { "node": "18 || 20 || 22" diff --git a/apps/OpenSign/public/locales/de/translation.json b/apps/OpenSign/public/locales/de/translation.json index 82426fb8d6..68a05ef04b 100644 --- a/apps/OpenSign/public/locales/de/translation.json +++ b/apps/OpenSign/public/locales/de/translation.json @@ -170,7 +170,8 @@ "Kiosk Mode": "Kiosk Modus", "Reset password": "Passwort zurücksetzen", "View formdata": "Formulardaten ansehen", - "Download all formdata": "Alle Formulardaten herunterladen" + "Download all formdata": "Alle Formulardaten herunterladen", + "API credits": "API-Credits" }, "report-heading": { "Sr.No": "Nr.", @@ -703,7 +704,7 @@ "select-date-format": "Wählen Sie ein Datumsformat", "quantity-of-credits": "Anzahl der Premium-Credits", "remaining-credits": "Verfügbare Premium-Credits:", - "remaining-credits-help": "Verwenden Sie Premium-Credits für API-Dokumentensignaturen, Massenversand oder die Einbettung der OpenSign-Integration auf Ihrer Website. Sie haben {{allowedcredits}} enthaltene Credits und {{addoncredits}} zusätzlich gekaufte Credits übrig.", + "remaining-credits-help": "Verwenden Sie Premium-Credits für die API-Dokumentensignatur, den Massenversand oder die Einbettung der OpenSign-Integration auf Ihrer Website. Sie haben noch {{allowedcredits}} inkludierte Credits und {{addoncredits}} zusätzlich gekaufte Credits übrig. Wenn Sie einen Teams- oder Enterprise-Plan nutzen, können diese Credits von allen Benutzern in Ihrem Unternehmen gemeinsam verwendet werden, sofern der Kontoadministrator für Ihr Konto kein Limit festgelegt hat.", "additional-credits": "Bitte kaufen Sie Premium-Credits hinzu", "quota-err-quicksend": "Kontingent erreicht, Sie haben nicht genügend Credits.", "buy-credits": "Premium-Credits kaufen", @@ -1296,5 +1297,16 @@ "view-formdata-paid-title-error": "Die Funktion 'Formulardaten anzeigen' ermöglicht es Ihnen, die von Unterzeichnern ausgefüllten Widget-Daten auszudrucken und herunterzuladen.", "view-formdata-paid-error": "Hinweis: Die Funktion 'Formulardaten anzeigen' ist nur für Dokumente verfügbar, die ab Version v2.32.0 erstellt wurden und keine doppelten Widget-Namen enthalten.", "download-all-formdata-paid-title-error": "Die Funktion 'Alle Formulardaten herunterladen' ermöglicht es Ihnen, die von Unterzeichnern ausgefüllten Widget-Daten für alle aus der Vorlage erstellten Dokumente herunterzuladen.", - "download-all-formdata-paid-error": "Hinweis: Die Funktion 'Alle Formulardaten herunterladen' ist nur für Vorlagen verfügbar, die ab Version v2.32.0 erstellt wurden und keine doppelten Widget-Namen enthalten." + "download-all-formdata-paid-error": "Hinweis: Die Funktion 'Alle Formulardaten herunterladen' ist nur für Vorlagen verfügbar, die ab Version v2.32.0 erstellt wurden und keine doppelten Widget-Namen enthalten.", + "api-token-not-found": "API-Token nicht gefunden.", + "sub-head-api-credits": "Legen Sie die maximale Anzahl von API-Credits fest, die dieser Benutzer verbrauchen darf.", + "consumed-credits": "Verbrauchte Credits", + "allowed-api-credits": "Zulässige API-Credits", + "allowed-api-credits-help": "Die zulässigen Credits sollten größer oder gleich den verbrauchten Credits sein.", + "Enter-allowed-api-credits": "Zulässige API-Credits eingeben", + "login-to-sandbox": "Im Sandbox-Modus anmelden", + "your-credits-usage": "Ihr Kreditverbrauch", + "remaining": "verbleibend", + "used": "verwendet", + "your-credits-usage-help": "Dies ist die Anzahl der Credits, die mit Ihrem API-Schlüssel verbraucht wurden." } \ No newline at end of file diff --git a/apps/OpenSign/public/locales/en/translation.json b/apps/OpenSign/public/locales/en/translation.json index 59db8ea215..8881102b10 100644 --- a/apps/OpenSign/public/locales/en/translation.json +++ b/apps/OpenSign/public/locales/en/translation.json @@ -170,7 +170,8 @@ "Kiosk Mode": "Kiosk Mode", "Reset password": "Reset password", "View formdata": "View formdata", - "Download all formdata": "Download all formdata" + "Download all formdata": "Download all formdata", + "API credits": "API credits" }, "report-heading": { "Sr.No": "Sr.No", @@ -704,7 +705,7 @@ "select-date-format": "Select a date format", "quantity-of-credits": "Quantity of premium credits", "remaining-credits": "Premium credits available:", - "remaining-credits-help": "Use premium credits for API document signing, bulk sending, or embedding OpenSign integration on your website. You have {{allowedcredits}} included credits and {{addoncredits}} additional purchased credits remaining.", + "remaining-credits-help": "Use premium credits for API document signing, bulk sending, or embedding OpenSign integration on your website. You have {{allowedcredits}} included credits and {{addoncredits}} additional purchased credits remaining. If you are on Teams or enterprise plan these are the credits that could be shared across all users in your company unless there is a limit set by the account admin for your account.", "additional-credits": "Please purchase premium credits", "quota-err-quicksend": "Quota reached, you don't have enough credits.", "buy-credits": "Buy premium credits", @@ -1297,5 +1298,16 @@ "view-formdata-paid-title-error": "The View Form Data feature lets you print and download the widget data filled in by signers while signing.", "view-formdata-paid-error": "Note: 'View Formdata' feature is only available for documents created on or after v2.32.0 that do not contain duplicate widget names.", "download-all-formdata-paid-title-error": "The Download All Form Data feature lets you download widget data filled in by signers for all documents created from the template.", - "download-all-formdata-paid-error": "Note: 'Download All Formdata' feature is only available for templates created on or after v2.32.0 that do not contain duplicate widget names." + "download-all-formdata-paid-error": "Note: 'Download All Formdata' feature is only available for templates created on or after v2.32.0 that do not contain duplicate widget names.", + "api-token-not-found": "API token not found.", + "sub-head-api-credits": " Define the maximum number of API credits this user is allowed to consume.", + "consumed-credits": "Consumed credits", + "allowed-api-credits": "Allowed API credits", + "allowed-api-credits-help": "The allowed credits should be greater than or equal to the consumed credits.", + "Enter-allowed-api-credits": "Enter allowed API credits", + "login-to-sandbox": "Login to sandbox", + "your-credits-usage": "Your credits usage", + "remaining": "remaining", + "used": "used", + "your-credits-usage-help": "This is the number of credits consumed with your API key." } \ No newline at end of file diff --git a/apps/OpenSign/public/locales/es/translation.json b/apps/OpenSign/public/locales/es/translation.json index 80ec919421..89b52d4aa5 100644 --- a/apps/OpenSign/public/locales/es/translation.json +++ b/apps/OpenSign/public/locales/es/translation.json @@ -170,7 +170,8 @@ "Kiosk Mode": "Modo Kiosco", "Reset password": "Restablecer contraseña", "View formdata": "Ver datos del formulario", - "Download all formdata": "Descargar todos los datos del formulario" + "Download all formdata": "Descargar todos los datos del formulario", + "API credits": "Créditos de API" }, "report-heading": { "Sr.No": "Nº", @@ -704,7 +705,7 @@ "select-date-format": "Selecciona un formato de fecha", "quantity-of-credits": "Cantidad de créditos premium", "remaining-credits": "Créditos premium disponibles:", - "remaining-credits-help": "Usa créditos premium para la API para la firma de documentos, envío en masa, o para incorporar la integración de OpenSign en tu página web. Te quedan {{allowedcredits}} créditos incluidos y {{addoncredits}} créditos comprados adicionalmente.", + "remaining-credits-help": "Utilice créditos premium para la firma de documentos mediante API, el envío masivo o para integrar OpenSign en su sitio web. Le quedan {{allowedcredits}} créditos incluidos y {{addoncredits}} créditos adicionales comprados. Si está en un plan Teams o Enterprise, estos créditos pueden compartirse entre todos los usuarios de su empresa, a menos que el administrador de la cuenta haya establecido un límite para su cuenta.", "additional-credits": "Por favor, compra créditos premium", "quota-err-quicksend": "Cuota alcanzada, no tienes créditos suficientes.", "buy-credits": "Comprar créditos premium", @@ -1297,5 +1298,16 @@ "view-formdata-paid-title-error": "La función 'Ver datos del formulario' le permite imprimir y descargar los datos de los widgets completados por los firmantes durante la firma.", "view-formdata-paid-error": "Nota: La función 'Ver datos del formulario' solo está disponible para documentos creados en o después de la versión v2.32.0 que no contengan nombres de widgets duplicados.", "download-all-formdata-paid-title-error": "La función 'Descargar todos los datos del formulario' le permite descargar los datos de los widgets completados por los firmantes para todos los documentos creados a partir de la plantilla.", - "download-all-formdata-paid-error": "Nota: La función 'Descargar todos los datos del formulario' solo está disponible para plantillas creadas en o después de la versión v2.32.0 que no contengan nombres de widgets duplicados." + "download-all-formdata-paid-error": "Nota: La función 'Descargar todos los datos del formulario' solo está disponible para plantillas creadas en o después de la versión v2.32.0 que no contengan nombres de widgets duplicados.", + "api-token-not-found": "Token de API no encontrado.", + "sub-head-api-credits": "Defina la cantidad máxima de créditos API que este usuario puede consumir.", + "consumed-credits": "Créditos consumidos", + "allowed-api-credits": "Créditos API permitidos", + "allowed-api-credits-help": "Los créditos permitidos deben ser mayores o iguales a los créditos consumidos.", + "Enter-allowed-api-credits": "Ingrese los créditos API permitidos", + "login-to-sandbox": "Iniciar sesión en sandbox", + "your-credits-usage": "Uso de sus créditos", + "remaining": "restantes", + "used": "usados", + "your-credits-usage-help": "Esta es la cantidad de créditos consumidos con su clave API." } \ No newline at end of file diff --git a/apps/OpenSign/public/locales/fr/translation.json b/apps/OpenSign/public/locales/fr/translation.json index 62a9785dd3..ca30aaf80a 100644 --- a/apps/OpenSign/public/locales/fr/translation.json +++ b/apps/OpenSign/public/locales/fr/translation.json @@ -206,7 +206,8 @@ "Kiosk Mode": "Mode Kiosque", "Reset password": "Réinitialiser le mot de passe", "View formdata": "Voir les données du formulaire", - "Download all formdata": "Télécharger toutes les données du formulaire" + "Download all formdata": "Télécharger toutes les données du formulaire", + "API credits": "Crédits API" }, "report-help": { "Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.", @@ -704,7 +705,7 @@ "quantity-of-credits": "Quantité de crédits de prime", "remaining-credits": "Crédits premium disponibles :", "additional-credits": "Veuillez acheter des crédits premium", - "remaining-credits-help": "Utilisez des crédits premium pour la signature de documents API, l'envoi groupé ou l'intégration d'OpenSign sur votre site Web. Il vous reste {{allowedcredits}} crédits inclus et {{addoncredits}} crédits achetés supplémentaires.", + "remaining-credits-help": "Utilisez des crédits premium pour la signature de documents via l'API, l'envoi groupé ou l'intégration d'OpenSign sur votre site Web. Il vous reste {{allowedcredits}} crédits inclus et {{addoncredits}} crédits supplémentaires achetés. Si vous êtes sur un plan Teams ou Enterprise, ces crédits peuvent être partagés entre tous les utilisateurs de votre entreprise, sauf si l'administrateur du compte a défini une limite pour votre compte.", "quota-err-quicksend": "Quota atteint, vous n'avez pas assez de crédits.", "buy-credits": "Acheter des crédits premium", "rotate-right": "Faire pivoter à droite", @@ -1293,8 +1294,19 @@ "duplicate-template-widget-error": "Vous ne pouvez pas dupliquer ce modèle car il contient des noms de widgets en double.", "credit-alert": "Alerte de crédit", "document-form-data": "Données du formulaire du document", - "view-formdata-paid-title-error": "La fonction 'Afficher les données du formulaire' vous permet d’imprimer et de télécharger les données des widgets remplies par les signataires lors de la signature.", + "view-formdata-paid-title-error": "La fonction 'Afficher les données du formulaire' vous permet d'imprimer et de télécharger les données des widgets remplies par les signataires lors de la signature.", "view-formdata-paid-error": "Remarque : La fonction 'Afficher les données du formulaire' est uniquement disponible pour les documents créés à partir de la version v2.32.0 et ne contenant pas de noms de widgets en double.", "download-all-formdata-paid-title-error": "La fonction 'Télécharger toutes les données du formulaire' vous permet de télécharger les données des widgets remplies par les signataires pour tous les documents créés à partir du modèle.", - "download-all-formdata-paid-error": "Remarque : La fonction 'Télécharger toutes les données du formulaire' est uniquement disponible pour les modèles créés à partir de la version v2.32.0 et ne contenant pas de noms de widgets en double." + "download-all-formdata-paid-error": "Remarque : La fonction 'Télécharger toutes les données du formulaire' est uniquement disponible pour les modèles créés à partir de la version v2.32.0 et ne contenant pas de noms de widgets en double.", + "api-token-not-found": "Jeton API introuvable.", + "sub-head-api-credits": "Définissez le nombre maximal de crédits API que cet utilisateur est autorisé à consommer.", + "consumed-credits": "Crédits consommés", + "allowed-api-credits": "Crédits API autorisés", + "allowed-api-credits-help": "Les crédits autorisés doivent être supérieurs ou égaux aux crédits consommés.", + "Enter-allowed-api-credits": "Saisissez les crédits API autorisés", + "login-to-sandbox": "Se connecter au sandbox", + "your-credits-usage": "Votre utilisation des crédits", + "remaining": "restants", + "used": "utilisés", + "your-credits-usage-help": "Ceci est le nombre de crédits consommés avec votre clé API." } \ No newline at end of file diff --git a/apps/OpenSign/public/locales/hi/translation.json b/apps/OpenSign/public/locales/hi/translation.json index 08b705c49d..c4b3f82946 100644 --- a/apps/OpenSign/public/locales/hi/translation.json +++ b/apps/OpenSign/public/locales/hi/translation.json @@ -170,7 +170,8 @@ "Kiosk Mode": "कियोस्क मोड", "Reset password": "पासवर्ड रीसेट करें", "View formdata": "फॉर्म डेटा देखें", - "Download all formdata": "सभी फॉर्म डेटा डाउनलोड करें" + "Download all formdata": "सभी फॉर्म डेटा डाउनलोड करें", + "API credits": "API क्रेडिट्स" }, "report-heading": { "Sr.No": "क्रमांक", @@ -703,7 +704,7 @@ "select-date-format": "एक दिनांक प्रारूप चुनें", "quantity-of-credits": "प्रीमियम क्रेडिट की मात्रा", "remaining-credits": "प्रीमियम क्रेडिट उपलब्ध:", - "remaining-credits-help": "अपनी वेबसाइट पर एपीआई दस्तावेज़ हस्ताक्षर, थोक भेजने या OpenSign एकीकरण को एम्बेड करने के लिए प्रीमियम क्रेडिट का उपयोग करें। आपके पास {{allowedcredits}} शामिल क्रेडिट और {{addoncredits}} अतिरिक्त खरीदे गए क्रेडिट शेष हैं।", + "remaining-credits-help": "API दस्तावेज़ साइनिंग, बल्क सेंडिंग या अपनी वेबसाइट पर OpenSign इंटीग्रेशन एम्बेड करने के लिए प्रीमियम क्रेडिट का उपयोग करें। आपके पास {{allowedcredits}} शामिल क्रेडिट और {{addoncredits}} अतिरिक्त खरीदे हुए क्रेडिट शेष हैं। यदि आप Teams या Enterprise प्लान पर हैं, तो ये क्रेडिट आपकी कंपनी के सभी उपयोगकर्ताओं के बीच साझा किए जा सकते हैं, जब तक कि आपके खाते के लिए अकाउंट एडमिन ने कोई सीमा निर्धारित न की हो।", "additional-credits": "कृपया प्रीमियम क्रेडिट खरीदें", "quota-err-quicksend": "कोटा पहुँच गया, आपके पास पर्याप्त क्रेडिट नहीं हैं।", "buy-credits": "प्रीमियम क्रेडिट खरीदें", @@ -1296,5 +1297,16 @@ "view-formdata-paid-title-error": "'फ़ॉर्म डेटा देखें' सुविधा आपको हस्ताक्षर करते समय साइनरों द्वारा भरे गए विजेट डेटा को प्रिंट और डाउनलोड करने की सुविधा देती है.", "view-formdata-paid-error": "नोट: 'फ़ॉर्म डेटा देखें' सुविधा केवल उन दस्तावेज़ों के लिए उपलब्ध है जो v2.32.0 या उसके बाद बनाए गए हों और जिनमें डुप्लिकेट विजेट नाम न हों.", "download-all-formdata-paid-title-error": "'सभी फ़ॉर्म डेटा डाउनलोड करें' सुविधा आपको टेम्पलेट से बनाए गए सभी दस्तावेज़ों के लिए साइनरों द्वारा भरे गए विजेट डेटा को डाउनलोड करने देती है.", - "download-all-formdata-paid-error": "नोट: 'सभी फ़ॉर्म डेटा डाउनलोड करें' सुविधा केवल उन टेम्पलेट्स के लिए उपलब्ध है जो v2.32.0 या उसके बाद बनाए गए हों और जिनमें डुप्लिकेट विजेट नाम न हों." + "download-all-formdata-paid-error": "नोट: 'सभी फ़ॉर्म डेटा डाउनलोड करें' सुविधा केवल उन टेम्पलेट्स के लिए उपलब्ध है जो v2.32.0 या उसके बाद बनाए गए हों और जिनमें डुप्लिकेट विजेट नाम न हों.", + "api-token-not-found": "API टोकन नहीं मिला।", + "sub-head-api-credits": "इस उपयोगकर्ता द्वारा उपभोग किए जाने वाले API क्रेडिट की अधिकतम संख्या निर्धारित करें।", + "consumed-credits": "उपयोग किए गए क्रेडिट", + "allowed-api-credits": "अनुमत API क्रेडिट", + "allowed-api-credits-help": "अनुमत क्रेडिट उपयोग किए गए क्रेडिट के बराबर या उससे अधिक होने चाहिए।", + "Enter-allowed-api-credits": "अनुमत API क्रेडिट दर्ज करें", + "login-to-sandbox": "सैंडबॉक्स में लॉगिन करें", + "your-credits-usage": "आपके क्रेडिट उपयोग", + "remaining": "शेष", + "used": "उपयोग किए गए", + "your-credits-usage-help": "यह आपके API कुंजी द्वारा उपभोग किए गए क्रेडिट की संख्या है।" } \ No newline at end of file diff --git a/apps/OpenSign/public/locales/it/translation.json b/apps/OpenSign/public/locales/it/translation.json index d9b6f98b44..a3818dd8dc 100644 --- a/apps/OpenSign/public/locales/it/translation.json +++ b/apps/OpenSign/public/locales/it/translation.json @@ -170,7 +170,8 @@ "Kiosk Mode": "Modalità Kiosk", "Reset password": "Reimposta password", "View formdata": "Visualizza i dati del modulo", - "Download all formdata": "Scarica tutti i dati del modulo" + "Download all formdata": "Scarica tutti i dati del modulo", + "API credits": "Crediti API" }, "report-heading": { "Sr.No": "Nr.", @@ -703,7 +704,7 @@ "select-date-format": "Seleziona un formato data", "quantity-of-credits": "Quantità di crediti premium", "remaining-credits": "Crediti premium disponibili:", - "remaining-credits-help": "Usa i crediti premium per firmare documenti API, invii in massa o per integrare OpenSign nel tuo sito web. Hai a disposizione {{allowedcredits}} crediti inclusi e {{addoncredits}} crediti acquistati aggiuntivi rimanenti.", + "remaining-credits-help": "Usa i crediti premium per la firma di documenti tramite API, l'invio massivo o per integrare OpenSign nel tuo sito web. Hai ancora {{allowedcredits}} crediti inclusi e {{addoncredits}} crediti aggiuntivi acquistati. Se sei in un piano Teams o Enterprise, questi crediti possono essere condivisi tra tutti gli utenti della tua azienda, a meno che l'amministratore dell'account non abbia impostato un limite specifico per il tuo account.", "additional-credits": "Acquista crediti premium", "quota-err-quicksend": "Quota raggiunta, non hai abbastanza crediti.", "buy-credits": "Acquista Crediti Premium", @@ -1296,5 +1297,16 @@ "view-formdata-paid-title-error": "La funzione 'Visualizza dati del modulo' consente di stampare e scaricare i dati dei widget compilati dai firmatari durante la firma.", "view-formdata-paid-error": "Nota: La funzione 'Visualizza dati del modulo' è disponibile solo per documenti creati dalla versione v2.32.0 in poi che non contengono nomi di widget duplicati.", "download-all-formdata-paid-title-error": "La funzione 'Scarica tutti i dati del modulo' consente di scaricare i dati dei widget compilati dai firmatari per tutti i documenti creati dal modello.", - "download-all-formdata-paid-error": "Nota: La funzione 'Scarica tutti i dati del modulo' è disponibile solo per modelli creati dalla versione v2.32.0 in poi che non contengano nomi di widget duplicati." + "download-all-formdata-paid-error": "Nota: La funzione 'Scarica tutti i dati del modulo' è disponibile solo per modelli creati dalla versione v2.32.0 in poi che non contengano nomi di widget duplicati.", + "api-token-not-found": "Token API non trovato.", + "sub-head-api-credits": "Definisci il numero massimo di crediti API che questo utente può consumare.", + "consumed-credits": "Crediti consumati", + "allowed-api-credits": "Crediti API consentiti", + "allowed-api-credits-help": "I crediti consentiti devono essere maggiori o uguali ai crediti consumati.", + "Enter-allowed-api-credits": "Inserisci i crediti API consentiti", + "login-to-sandbox": "Accedi alla sandbox", + "your-credits-usage": "Utilizzo dei tuoi crediti", + "remaining": "rimanenti", + "used": "usati", + "your-credits-usage-help": "Questo è il numero di crediti consumati con la tua chiave API." } \ No newline at end of file diff --git a/apps/OpenSign/src/components/Header.jsx b/apps/OpenSign/src/components/Header.jsx index 2ef7deb1e5..67c23db5dc 100644 --- a/apps/OpenSign/src/components/Header.jsx +++ b/apps/OpenSign/src/components/Header.jsx @@ -60,7 +60,6 @@ const Header = ({ isConsole, setIsLoggingOut }) => { setAppLogo(logo); } } - const handleLogout = async () => { setIsOpen(false); setIsLoggingOut(true); diff --git a/apps/OpenSign/src/components/pdf/Placeholder.jsx b/apps/OpenSign/src/components/pdf/Placeholder.jsx index 1ef82b0285..18caf8b832 100644 --- a/apps/OpenSign/src/components/pdf/Placeholder.jsx +++ b/apps/OpenSign/src/components/pdf/Placeholder.jsx @@ -216,16 +216,17 @@ function Placeholder(props) { //placeholder, template flow else if (props.isPlaceholder && !props.isDragging) { props.setCurrWidgetsDetails && props.setCurrWidgetsDetails(props.pos); - if ( - props.pos.key === props?.currWidgetsDetails?.key && - props?.data?.Role !== "prefill" - ) { - props.handleLinkUser(props.data.Id); + if (props?.data?.Role !== "prefill") { + //this condition is used open signers attach modal but it should only open when widgets already selected + if (props?.currWidgetsDetails?.key === props.pos?.key) { + props.handleLinkUser(props.data.Id); + } props.setUniqueId(props.data.Id); const checkIndex = props.xyPosition.findIndex( (data) => data.Id === props.data.Id ); props.setIsSelectId(checkIndex || 0); + props?.setRoleName(""); } else if (props?.data?.Role === "prefill") { dispatch(setIsShowModal({ [props.pos.key]: true })); props.setUniqueId(props?.data?.Id); @@ -658,6 +659,8 @@ function Placeholder(props) { onClick={() => { props.setCurrWidgetsDetails && props.setCurrWidgetsDetails(props.pos); + props?.setRoleName("prefill"); + props.setUniqueId(props?.data?.Id); }} style={{ fontFamily: "Arial, sans-serif", diff --git a/apps/OpenSign/src/constant/Utils.js b/apps/OpenSign/src/constant/Utils.js index cfb2145c48..a101c67bfc 100644 --- a/apps/OpenSign/src/constant/Utils.js +++ b/apps/OpenSign/src/constant/Utils.js @@ -3466,7 +3466,10 @@ export const updateDateWidgetsRes = ( return placeHolders?.map((item) => { if (item?.signerObjId === signerId || item?.Id === signerId) { // Sort page number placeholders - const sortedPlaceHolder = [...item.placeHolder] + const placeHolder = Array.isArray(item.placeHolder) + ? [...item.placeHolder] + : []; + const sortedPlaceHolder = placeHolder .sort((a, b) => a.pageNumber - b.pageNumber) .map((ph) => ({ ...ph, @@ -3981,74 +3984,68 @@ export const getSignerEmail = (data, signers) => { //function is used to delete widgets export const handleDeleteWidget = (key, Id, pageNumber, signerPos) => { - const updateData = []; + // Find the signer by ID + const signer = signerPos.find((item) => item.Id === Id); + if (!signer || !signer.placeHolder) return signerPos; - const filterSignerPos = signerPos.filter((data) => data.Id === Id); + const placeHolder = signer.placeHolder; - if (filterSignerPos.length > 0) { - const getPlaceHolder = filterSignerPos[0].placeHolder; + // Find the page inside placeHolder + const currentPage = placeHolder.find((p) => p.pageNumber === pageNumber); + if (!currentPage) return signerPos; - const getPageNumer = getPlaceHolder.filter( - (data) => data.pageNumber === pageNumber + // Remove widget from the selected page + const updatedPos = currentPage.pos.filter((w) => w.key !== key); + + // ------------------------------------------------------- + // CASE A → After deletion, page still has widgets then keep that widgets + // ------------------------------------------------------- + if (updatedPos.length > 0) { + const updatedPlaceHolder = placeHolder.map((p) => + p.pageNumber === pageNumber ? { ...p, pos: updatedPos } : p ); - if (getPageNumer.length > 0) { - const getXYdata = getPageNumer[0].pos.filter((data) => data.key !== key); + return signerPos.map((s) => + s.Id === Id ? { ...s, placeHolder: updatedPlaceHolder } : s + ); + } - if (getXYdata.length > 0) { - updateData.push(getXYdata); - const newUpdatePos = getPlaceHolder.map((obj) => { - if (obj.pageNumber === pageNumber) { - return { ...obj, pos: updateData[0] }; - } - return obj; - }); + // ------------------------------------------------------- + // CASE B → current page becomes empty → remove current page entirely and keep another pages which have widgets + // ------------------------------------------------------- + const remainPages = placeHolder.filter((p) => p.pageNumber !== pageNumber); - const newUpdateSigner = signerPos.map((obj) => { - if (obj.Id === Id) { - return { ...obj, placeHolder: newUpdatePos }; - } - return obj; - }); - return newUpdateSigner; - } else { - const getRemainPage = filterSignerPos[0].placeHolder.filter( - (data) => data.pageNumber !== pageNumber - ); - //condition to check placeholder length is greater than 1 do not need to remove whole placeholder - //array only resove particular widgets - if (getRemainPage && getRemainPage.length > 0) { - const newUpdatePos = filterSignerPos.map((obj) => { - if (obj.Id === Id) { - return { ...obj, placeHolder: getRemainPage }; - } - return obj; - }); - let signerupdate = []; - signerupdate = signerPos.filter((data) => data.Id !== Id); - signerupdate.push(newUpdatePos[0]); + //`remainPages` keep another pages's data which have widgets + if (remainPages.length > 0) { + const index = signerPos.findIndex((s) => s.Id === Id); + if (index === -1) return signerPos; - return signerupdate; - } else { - const updatedData = signerPos - .map((item) => { - if (item.Id === Id && item?.Role === "prefill") { - return null; // mark this item to remove - } - if (item.Id === Id) { - const updatedItem = { ...item }; - delete updatedItem.placeHolder; - return updatedItem; - } - return item; - }) - .filter(Boolean); // remove nulls (deleted items) + const newSignerPos = [...signerPos]; + newSignerPos[index] = { + ...newSignerPos[index], + placeHolder: remainPages + }; - return updatedData; - } - } - } + return newSignerPos; } + + // ------------------------------------------------------- + // CASE C → No pages have widgets after delete widgets + // Remove placeHolder field for particular signers, EXCEPT prefill role + // ------------------------------------------------------- + const updatedData = signerPos + .map((s) => { + if (s.Id === Id && s.Role === "prefill") return null; // remove whole signer + if (s.Id === Id) { + const updated = { ...s }; + delete updated.placeHolder; + return updated; + } + return s; + }) + .filter(Boolean); // remove nulls (deleted items) + + return updatedData; }; //function to convert formatted date to new Date() format export const getDefaultDate = (dateStr, format) => { diff --git a/apps/OpenSign/src/json/ReportJson.js b/apps/OpenSign/src/json/ReportJson.js index 399fcc6831..97ecbad199 100644 --- a/apps/OpenSign/src/json/ReportJson.js +++ b/apps/OpenSign/src/json/ReportJson.js @@ -533,3 +533,23 @@ export default function reportJson(id) { return null; } } + +export const usersActions = [ + { + btnId: "4741", + hoverLabel: "Delete", + btnColor: "op-btn-secondary", + btnIcon: "fa-light fa-trash", + redirectUrl: "", + action: "delete", + restrictAdmin: true + }, + { + btnId: "1910", + hoverLabel: "Reset password", + btnIcon: "fa-light fa-key", + redirectUrl: "", + action: "resetpassword", + restrictAdmin: true + } +]; diff --git a/apps/OpenSign/src/pages/UserList.jsx b/apps/OpenSign/src/pages/UserList.jsx index a52cd88659..951c6e6132 100644 --- a/apps/OpenSign/src/pages/UserList.jsx +++ b/apps/OpenSign/src/pages/UserList.jsx @@ -13,26 +13,8 @@ import { import DeleteUserModal from "../primitives/DeleteUserModal"; import axios from "axios"; import PasswordResetModal from "../primitives/PasswordResetModal"; +import { usersActions } from "../json/ReportJson"; -const actions = [ - { - btnId: "4741", - hoverLabel: "Delete", - btnColor: "op-btn-secondary", - btnIcon: "fa-light fa-trash", - redirectUrl: "", - action: "delete", - restrictAdmin: true - }, - { - btnId: "1910", - hoverLabel: "Reset password", - btnIcon: "fa-light fa-key", - redirectUrl: "", - action: "resetpassword", - restrictAdmin: true - }, -]; const heading = ["Sr.No", "Name", "Email", "Phone", "Role", "Team", "Active"]; const UserList = () => { const { t } = useTranslation(); @@ -342,7 +324,7 @@ const UserList = () => { {t(`report-heading.${item}`)} ))} - {actions?.length > 0 && ( + {usersActions?.length > 0 && ( {t("action")} @@ -429,8 +411,8 @@ const UserList = () => { {isAdmin && (
- {actions?.length > 0 && - actions.map((act, index) => ( + {usersActions?.length > 0 && + usersActions?.map((act, index) => ( {handleBtnVisibility(act, item) && (
{ )}
)} - - handleDeleteAccount(item) - } - deleteRes={deleteUserRes} - handleClose={handleCloseModal} - /> -
))}
)} + handleDeleteAccount(item)} + deleteRes={deleteUserRes} + handleClose={handleCloseModal} + /> + ))} diff --git a/apps/OpenSign/src/primitives/SignerCell.jsx b/apps/OpenSign/src/primitives/SignerCell.jsx index b1a9da1168..792fca79b7 100644 --- a/apps/OpenSign/src/primitives/SignerCell.jsx +++ b/apps/OpenSign/src/primitives/SignerCell.jsx @@ -158,7 +158,7 @@ const SignerCell = ({ reportName, item, handleRemovePrefill }) => { - {item.Placeholders.map( + {item?.Placeholders?.map( (x, i) => x.Role !== "prefill" && ( diff --git a/apps/OpenSign/src/reports/template/TemplatesReport.jsx b/apps/OpenSign/src/reports/template/TemplatesReport.jsx index f499a6a44d..87c12fbbf6 100644 --- a/apps/OpenSign/src/reports/template/TemplatesReport.jsx +++ b/apps/OpenSign/src/reports/template/TemplatesReport.jsx @@ -351,9 +351,6 @@ const TemplatesReport = (props) => { setError(t("duplicate-template-widget-error")); setIsModal({ [`duplicate_${item.objectId}`]: true }); } else { - const isPrefill = - item?.Placeholders?.some((p) => p?.Role === "prefill") ?? false; - setError(isPrefill ? t("duplicate-template-error") : ""); setIsModal({ [`duplicate_${item.objectId}`]: true }); } } else if (act.action === "rename") { diff --git a/apps/OpenSignServer/cloud/customRoute/docxtopdf.js b/apps/OpenSignServer/cloud/customRoute/docxtopdf.js index 436aa621e7..c64956609e 100644 --- a/apps/OpenSignServer/cloud/customRoute/docxtopdf.js +++ b/apps/OpenSignServer/cloud/customRoute/docxtopdf.js @@ -13,10 +13,13 @@ async function convertLibre(input, ext, opts) { } }); } -// -------------------- Concurrency limiter (no dependency) -------------------- -const MAX_CONCURRENCY = Number(process.env.DOCX2PDF_CONCURRENCY || 2); // 1 for tiny droplets + +// -------------------- Concurrency limiter -------------------- +// CRITICAL FIX: Reduced to 1 for CPU-intensive LibreOffice conversions +const MAX_CONCURRENCY = Number(process.env.DOCX2PDF_CONCURRENCY || 1); let active = 0; const queue = []; + function runWithLimit(task) { return new Promise((resolve, reject) => { const run = () => { @@ -34,7 +37,7 @@ function runWithLimit(task) { }); } -// -------------------- Timeout helper (async version = no TS hint) -------------------- +// -------------------- Timeout helper -------------------- /** * @template T * @param {Promise} promise @@ -58,6 +61,7 @@ export async function withTimeout(promise, ms, label = 'operation') { const storage = multer.memoryStorage(); export const upload = multer({ storage, + limits: { fileSize: 50 * 1024 * 1024 }, // 50MB hard limit at multer level fileFilter: (req, file, cb) => { const okExt = /\.docx$/i.test(file.originalname || ''); const okMime = @@ -109,14 +113,30 @@ export default async function docxtopdf(req, res) { return res.status(403).json({ error: 'Tenant not found for user.' }); } - // ---- DOCX -> PDF (buffer -> buffer), with concurrency + timeout ---- + // ---- DOCX -> PDF conversion with concurrency control and timeout ---- const fileName = `${generatePdfName(16)}.pdf`; - const pdfBuffer = await runWithLimit(() => - withTimeout(convertLibre(req.file.buffer, '.pdf', undefined), 60_000, 'DOCX->PDF') - ); + // FIX: Increased timeout to 90s for large files, added nice priority + const pdfBuffer = await runWithLimit(async () => { + // Log for monitoring + console.log(`[DOCX2PDF] Starting conversion, active: ${active}, queued: ${queue.length}`); + + const startTime = Date.now(); + try { + const result = await withTimeout( + convertLibre(req.file.buffer, '.pdf', undefined), + 90_000, // Increased from 60s to 90s + 'DOCX->PDF' + ); + console.log(`[DOCX2PDF] Completed in ${Date.now() - startTime}ms`); + return result; + } catch (error) { + console.error(`[DOCX2PDF] Failed after ${Date.now() - startTime}ms:`, error.message); + throw error; + } + }); - // ---- Upload PDF (no disk IO) ---- + // ---- Upload PDF ---- const activeFileAdapter = resUser.data.results[0]?.TenantId?.ActiveFileAdapter; let fileUrl; if (activeFileAdapter) { @@ -140,12 +160,23 @@ export default async function docxtopdf(req, res) { return res.status(200).json({ message: 'success.', url: fileUrl }); } catch (err) { - const msg = + // More specific error messages + let msg = err?.response?.data?.error || err?.response?.data || err?.message || 'Something went wrong.'; - console.log(`Error in docxtopdf: ${msg}`); // Friendly message to the client const message = 'We are currently experiencing some issues with processing DOCX files. Please upload the PDF version or contact us on support@opensignlabs.com'; + + if (msg.includes('timed out')) { + msg = + 'Document conversion is taking too long. Please try a smaller file or contact support@opensignlabs.com'; + } else if (msg.includes('too large') || msg.includes('size')) { + msg = + 'File is too large to process. Please reduce the file size or contact support@opensignlabs.com'; + } else { + msg = message; + } + console.error(`[DOCX2PDF] Error: ${msg}`); return res.status(400).json({ error: message }); } } diff --git a/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js b/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js index e52c6d52bb..20e5e96c45 100644 --- a/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js +++ b/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js @@ -192,7 +192,6 @@ async function batchQuery(userId, Documents, Ip, parseConfig, type, publicUrl) { }, }; }); - // console.log('requests ', requests); if (requests?.length > 0) { const newrequests = [requests?.[0]]; const response = await axios.post('batch', { requests: newrequests }, parseConfig); diff --git a/apps/OpenSignServer/index.js b/apps/OpenSignServer/index.js index 8f7e1d82a5..ff61b79e7b 100644 --- a/apps/OpenSignServer/index.js +++ b/apps/OpenSignServer/index.js @@ -17,7 +17,7 @@ import { exec } from 'child_process'; import { createTransport } from 'nodemailer'; import { appName, cloudServerUrl, serverAppId, smtpenable, smtpsecure, useLocal } from './Utils.js'; import { SSOAuth } from './auth/authadapter.js'; -import createContactIndex from './migrationdb/createContactIndex.js'; +import runDbMigrations from './migrationdb/index.js'; import { validateSignedLocalUrl } from './cloud/parsefunction/getSignedUrl.js'; import maintenance_mode_message from 'aws-sdk/lib/maintenance_mode_message.js'; let fsAdapter; @@ -119,6 +119,7 @@ export const config = { allowClientClassCreation: false, allowExpiredAuthDataToken: false, enableInsecureAuthAdapters: false, + databaseOptions: { allowPublicExplain: false }, encodeParseObjectInCloudFunction: true, ...(isMailAdapter === true ? { @@ -240,7 +241,7 @@ if (!process.env.TESTING) { console.log('opensign-server running on port ' + port + '.'); const isWindows = process.platform === 'win32'; // console.log('isWindows', isWindows); - createContactIndex(); + runDbMigrations(); const migrate = isWindows ? `set APPLICATION_ID=${serverAppId}&& set SERVER_URL=${cloudServerUrl}&& set MASTER_KEY=${process.env.MASTER_KEY}&& npx parse-dbtool migrate` : `APPLICATION_ID=${serverAppId} SERVER_URL=${cloudServerUrl} MASTER_KEY=${process.env.MASTER_KEY} npx parse-dbtool migrate`; diff --git a/apps/OpenSignServer/migrationdb/createContactIndex.js b/apps/OpenSignServer/migrationdb/createContactIndex.js index b117d2a9ad..01accec314 100644 --- a/apps/OpenSignServer/migrationdb/createContactIndex.js +++ b/apps/OpenSignServer/migrationdb/createContactIndex.js @@ -18,8 +18,7 @@ export default async function createContactIndex() { const migrationExists = await migrationCollection.findOne({ name: migrationName }); if (migrationExists) { - console.log(' INFO No migrations were executed, database schema was already up to date.'); - console.log(' SUCCESS Successfully ran indexed migrations directly on db.'); + console.log(' INFO The unqiue index for contracts_Contactbook is already present.'); return; } @@ -61,10 +60,9 @@ export default async function createContactIndex() { // Insert the document await migrationdb.insertOne(schemaDocument); - console.log(' Unique index created successfully.'); - console.log(' SUCCESS Successfully ran indexed migrations directly on db.'); + console.log(' SUCCESS The unqiue index for contracts_Contactbook is already created.'); } catch (error) { - console.log(' ERROR running indexed migration:', error); + console.log(' ERROR Running unqiue index for contracts_Contactbook migration:', error); } finally { await client.close(); } diff --git a/apps/OpenSignServer/migrationdb/createDocumentIndex.js b/apps/OpenSignServer/migrationdb/createDocumentIndex.js new file mode 100644 index 0000000000..35128344a8 --- /dev/null +++ b/apps/OpenSignServer/migrationdb/createDocumentIndex.js @@ -0,0 +1,59 @@ +import dotenv from 'dotenv'; +import { MongoClient } from 'mongodb'; +import { generateId } from '../Utils.js'; +dotenv.config({ quiet: true }); + +export default async function createDocumentIndex() { + // Provide the complete MongoDB connection URL with the database name + const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017/dev'; // Replace with your MongoDB URI + const client = new MongoClient(uri); + try { + await client.connect(); + const database = client.db(); + + const migrationCollection = database.collection('Migrationdb'); + const docMigration = 'documentIndex_1'; + + // Check if the migration has already been executed + const docMigrationExists = await migrationCollection.findOne({ name: docMigration }); + + if (docMigrationExists) { + console.log(' INFO The completed report index for contracts_document is already present.'); + return; + } + + const docCollection = database.collection('contracts_Document'); + + await docCollection.createIndex( + { _p_CreatedBy: 1, _updated_at: -1 }, + { + name: 'idx_docs_by_creator_recent_completed', + partialFilterExpression: { IsCompleted: true }, + } + ); + + await docCollection.createIndex( + { Signers: 1, _updated_at: -1 }, + { + name: 'idx_docs_by_signer_recent_completed', + partialFilterExpression: { IsCompleted: true }, + } + ); + + // Save the migration record in the migrationdb collection + await migrationCollection.insertOne({ + _id: generateId(10), + name: docMigration, + _created_at: new Date(), + _updated_at: new Date(), + executedAt: new Date(), + details: 'Created unique index on CreatedBy, IsImported, Email', + }); + + console.log(' SUCCESS The completed report index for contracts_document is created.'); + } catch (error) { + console.log(' ERROR Running completed report index for contracts_document migration:', error); + } finally { + await client.close(); + } +} diff --git a/apps/OpenSignServer/migrationdb/index.js b/apps/OpenSignServer/migrationdb/index.js new file mode 100644 index 0000000000..e0ae9398f6 --- /dev/null +++ b/apps/OpenSignServer/migrationdb/index.js @@ -0,0 +1,7 @@ +import createContactIndex from './createContactIndex.js'; +import createDocumentIndex from './createDocumentIndex.js'; + +export default async function runDbMigrations() { + await createContactIndex(); + await createDocumentIndex(); +} diff --git a/apps/OpenSignServer/package.json b/apps/OpenSignServer/package.json index 8433245a66..9adb779d56 100644 --- a/apps/OpenSignServer/package.json +++ b/apps/OpenSignServer/package.json @@ -18,10 +18,10 @@ "watch": "nodemon index.js" }, "dependencies": { - "@aws-sdk/client-s3": "^3.940.0", - "@aws-sdk/s3-request-presigner": "^3.940.0", + "@aws-sdk/client-s3": "^3.943.0", + "@aws-sdk/s3-request-presigner": "^3.943.0", "@parse/fs-files-adapter": "^3.0.0", - "@parse/push-adapter": "^7.0.0", + "@parse/push-adapter": "^8.0.2", "@parse/s3-files-adapter": "^4.2.0", "@pdf-lib/fontkit": "^1.1.1", "@signpdf/placeholder-pdf-lib": "^3.2.6", @@ -33,21 +33,21 @@ "cors": "^2.8.5", "date-fns-tz": "^3.2.0", "dotenv": "^17.2.3", - "express": "^5.1.0", + "express": "^5.2.1", "form-data": "^4.0.5", "generate-api-key": "^1.0.2", - "googleapis": "^166.0.0", + "googleapis": "^167.0.0", "libreoffice-convert": "^1.7.0", "mailgun.js": "^12.2.0", "mongodb": "^5.9.2", "multer": "^2.0.2", "multer-s3": "^3.0.1", - "node-forge": "^1.3.1", + "node-forge": "^1.3.3", "nodemailer": "^7.0.11", "p-limit": "^7.2.0", - "parse": "^7.0.2", + "parse": "^7.1.2", "parse-dbtool": "^1.2.0", - "parse-server": "^8.4.0", + "parse-server": "^8.5.0", "parse-server-api-mail-adapter": "^5.0.2", "pdf-lib": "^1.17.1", "posthog-node": "^5.14.0", @@ -65,7 +65,7 @@ "mongodb-runner": "^5.11.1", "nodemon": "^3.1.11", "nyc": "^17.1.0", - "prettier": "^3.6.2" + "prettier": "^3.7.4" }, "overrides": { "ws": "$ws",