diff --git a/apps/openpage-api/package.json b/apps/openpage-api/package.json index 0a82e1fff..f2ca53995 100644 --- a/apps/openpage-api/package.json +++ b/apps/openpage-api/package.json @@ -12,11 +12,14 @@ "dependencies": { "@documenso/prisma": "*", "luxon": "^3.7.2", - "next": "15.5.12" + "next": "15.5.12", + "react": "^18", + "react-dom": "^18" }, "devDependencies": { "@types/node": "^20", "@types/react": "18.3.27", + "@types/react-dom": "^18", "typescript": "5.6.2" } } diff --git a/package-lock.json b/package-lock.json index 89276da45..325bd8871 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,8 @@ "@ts-rest/core": "^3.52.1", "@ts-rest/open-api": "^3.52.1", "@ts-rest/serverless": "^3.52.1", + "@types/react": "18.3.27", + "@types/react-dom": "^18", "dotenv": "^17.2.3", "dotenv-cli": "^11.0.0", "husky": "^9.1.7", @@ -57,6 +59,7 @@ "prisma-extension-kysely": "^3.0.0", "prisma-json-types-generator": "^3.6.2", "prisma-kysely": "^2.3.0", + "react-dom": "^18", "rimraf": "^6.1.2", "superjson": "^2.2.5", "syncpack": "^14.0.0-alpha.27", @@ -100,6 +103,26 @@ "typescript": "^5.9.3" } }, + "apps/docs/node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "apps/docs/node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, "apps/docs/node_modules/react": { "version": "19.2.4", "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", @@ -109,31 +132,38 @@ "node": ">=0.10.0" } }, - "apps/docs/node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "apps/docs/node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" }, - "engines": { - "node": ">=14.17" + "peerDependencies": { + "react": "^19.2.4" } }, + "apps/docs/node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, "apps/openpage-api": { "name": "@documenso/openpage-api", "version": "1.0.0", "dependencies": { "@documenso/prisma": "*", "luxon": "^3.7.2", - "next": "15.5.12" + "next": "15.5.12", + "react": "^18", + "react-dom": "^18" }, "devDependencies": { "@types/node": "^20", "@types/react": "18.3.27", + "@types/react-dom": "^18", "typescript": "5.6.2" } }, @@ -147,17 +177,6 @@ "undici-types": "~6.21.0" } }, - "apps/openpage-api/node_modules/@types/react": { - "version": "18.3.27", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", - "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.2.2" - } - }, "apps/openpage-api/node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -362,27 +381,6 @@ "undici-types": "~6.21.0" } }, - "apps/remix/node_modules/@types/react": { - "version": "18.3.27", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", - "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.2.2" - } - }, - "apps/remix/node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^18.0.0" - } - }, "apps/remix/node_modules/lucide-react": { "version": "0.554.0", "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.554.0.tgz", @@ -392,19 +390,6 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "apps/remix/node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, "apps/remix/node_modules/tailwindcss": { "version": "3.4.19", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", @@ -13465,26 +13450,26 @@ "version": "15.7.15", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "dev": true, "license": "MIT" }, "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "version": "18.3.27", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", + "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", "license": "MIT", "dependencies": { + "@types/prop-types": "*", "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "dev": true, "license": "MIT", "peerDependencies": { - "@types/react": "^19.2.0" + "@types/react": "^18.0.0" } }, "node_modules/@types/resolve": { @@ -24659,23 +24644,18 @@ } }, "node_modules/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", "dependencies": { - "scheduler": "^0.27.0" + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^19.2.4" + "react": "^18.3.1" } }, - "node_modules/react-dom/node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" - }, "node_modules/react-draggable": { "version": "4.4.6", "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.6.tgz", @@ -29762,27 +29742,6 @@ "typescript": "5.6.2" } }, - "packages/ui/node_modules/@types/react": { - "version": "18.3.27", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", - "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.2.2" - } - }, - "packages/ui/node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^18.0.0" - } - }, "packages/ui/node_modules/lucide-react": { "version": "0.554.0", "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.554.0.tgz", @@ -29792,19 +29751,6 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "packages/ui/node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, "packages/ui/node_modules/tailwind-merge": { "version": "1.14.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.14.0.tgz", diff --git a/package.json b/package.json index 6ec72cadd..c258869fd 100644 --- a/package.json +++ b/package.json @@ -76,12 +76,15 @@ "prisma-extension-kysely": "^3.0.0", "prisma-json-types-generator": "^3.6.2", "prisma-kysely": "^2.3.0", + "react-dom": "^18", "rimraf": "^6.1.2", "superjson": "^2.2.5", "syncpack": "^14.0.0-alpha.27", "turbo": "^1.13.4", "vite": "^7.2.4", "vite-plugin-static-copy": "^3.1.4", + "@types/react": "18.3.27", + "@types/react-dom": "^18", "zod-openapi": "^4.2.4", "zod-prisma-types": "3.3.5" }, diff --git a/packages/api/v1/implementation.ts b/packages/api/v1/implementation.ts index 3181537f5..dcde5466d 100644 --- a/packages/api/v1/implementation.ts +++ b/packages/api/v1/implementation.ts @@ -189,7 +189,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, { fields: parsedMetaFields, }, }; - } catch (err) { + } catch { return { status: 404, body: { @@ -276,7 +276,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, { status: 200, body: { downloadUrl: url }, }; - } catch (err) { + } catch { return { status: 500, body: { @@ -341,7 +341,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, { completedAt: deletedDocument.completedAt, }, }; - } catch (err) { + } catch { return { status: 404, body: { @@ -478,7 +478,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, { })), }, }; - } catch (err) { + } catch { return { status: 404, body: { @@ -593,7 +593,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, { template: fullTemplate, }, }; - } catch (err) { + } catch { return { status: 404, body: { @@ -637,7 +637,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, { updatedAt: deletedTemplate.updatedAt, }, }; - } catch (err) { + } catch { return { status: 404, body: { @@ -1077,7 +1077,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, { message: 'Document resend successfully initiated', }, }; - } catch (err) { + } catch { return { status: 500, body: { @@ -1185,7 +1185,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, { signingUrl: `${NEXT_PUBLIC_WEBAPP_URL()}/sign/${newRecipient.token}`, }, }; - } catch (err) { + } catch { return { status: 500, body: { diff --git a/packages/email/transports/mailchannels.ts b/packages/email/transports/mailchannels.ts index 45b12f739..bed9c3f49 100644 --- a/packages/email/transports/mailchannels.ts +++ b/packages/email/transports/mailchannels.ts @@ -54,13 +54,11 @@ export class MailChannelsTransport implements Transport { const mailCc = this.toMailChannelsAddresses(mail.data.cc); const mailBcc = this.toMailChannelsAddresses(mail.data.bcc); - const from: MailChannelsAddress = - typeof mail.data.from === 'string' - ? { email: mail.data.from } - : { - email: mail.data.from?.address, - name: mail.data.from?.name, - }; + const [from] = this.toMailChannelsAddresses(mail.data.from); + + if (!from) { + return callback(new Error('Missing required field "from"'), null); + } const requestHeaders: Record = { 'Content-Type': 'application/json', @@ -70,56 +68,15 @@ export class MailChannelsTransport implements Transport { requestHeaders['X-Auth-Token'] = this._options.apiKey; } - fetch(this._options.endpoint, { - method: 'POST', - headers: requestHeaders, - body: JSON.stringify({ - from: from, - subject: mail.data.subject, - personalizations: [ - { - to: mailTo, - cc: mailCc.length > 0 ? mailCc : undefined, - bcc: mailBcc.length > 0 ? mailBcc : undefined, - dkim_domain: env('NEXT_PRIVATE_MAILCHANNELS_DKIM_DOMAIN') || undefined, - dkim_selector: env('NEXT_PRIVATE_MAILCHANNELS_DKIM_SELECTOR') || undefined, - dkim_private_key: env('NEXT_PRIVATE_MAILCHANNELS_DKIM_PRIVATE_KEY') || undefined, - }, - ], - content: [ - { - type: 'text/plain', - value: mail.data.text?.toString('utf-8') ?? '', - }, - { - type: 'text/html', - value: mail.data.html?.toString('utf-8') ?? '', - }, - ], - }), - }) - .then((res) => { - if (res.status >= 200 && res.status <= 299) { - return callback(null, { - messageId: '', - envelope: { - from: mail.data.from, - to: mail.data.to, - }, - accepted: mail.data.to, - rejected: [], - pending: [], - }); - } - - res - .json() - .then((data) => callback(new Error(`MailChannels error: ${data.message}`), null)) - .catch((err) => callback(err, null)); - }) - .catch((err) => { - return callback(err, null); - }); + void this.sendMailRequest({ + callback, + from, + mail, + mailBcc, + mailCc, + mailTo, + requestHeaders, + }); } /** @@ -154,4 +111,72 @@ export class MailChannelsTransport implements Transport { }, ]; } + + private async sendMailRequest({ + callback, + from, + mail, + mailBcc, + mailCc, + mailTo, + requestHeaders, + }: { + callback: (_err: Error | null, _info: SentMessageInfo) => void; + from: MailChannelsAddress; + mail: MailMessage; + mailBcc: Array; + mailCc: Array; + mailTo: Array; + requestHeaders: Record; + }) { + try { + const response = await fetch(this._options.endpoint, { + method: 'POST', + headers: requestHeaders, + body: JSON.stringify({ + from, + subject: mail.data.subject, + personalizations: [ + { + to: mailTo, + cc: mailCc.length > 0 ? mailCc : undefined, + bcc: mailBcc.length > 0 ? mailBcc : undefined, + dkim_domain: env('NEXT_PRIVATE_MAILCHANNELS_DKIM_DOMAIN') || undefined, + dkim_selector: env('NEXT_PRIVATE_MAILCHANNELS_DKIM_SELECTOR') || undefined, + dkim_private_key: env('NEXT_PRIVATE_MAILCHANNELS_DKIM_PRIVATE_KEY') || undefined, + }, + ], + content: [ + { + type: 'text/plain', + value: mail.data.text?.toString('utf-8') ?? '', + }, + { + type: 'text/html', + value: mail.data.html?.toString('utf-8') ?? '', + }, + ], + }), + }); + + if (response.status >= 200 && response.status <= 299) { + return callback(null, { + messageId: '', + envelope: { + from: mail.data.from, + to: mail.data.to, + }, + accepted: mail.data.to, + rejected: [], + pending: [], + }); + } + + const data = await response.json(); + + return callback(new Error(`MailChannels error: ${data.message}`), null); + } catch (error) { + return callback(error instanceof Error ? error : new Error('Failed to send email'), null); + } + } } diff --git a/packages/lib/client-only/hooks/use-analytics.ts b/packages/lib/client-only/hooks/use-analytics.ts index 92a92c40c..840ac1777 100644 --- a/packages/lib/client-only/hooks/use-analytics.ts +++ b/packages/lib/client-only/hooks/use-analytics.ts @@ -39,7 +39,7 @@ export function useAnalytics() { * * @param eventFlag The event to check against feature flags to determine whether tracking is enabled. */ - const startSessionRecording = (eventFlag?: string) => { + const startSessionRecording = (_eventFlag?: string) => { return; // const isSessionRecordingEnabled = featureFlags.getFlag(FEATURE_FLAG_GLOBAL_SESSION_RECORDING); // const isSessionRecordingEnabledForEvent = Boolean(eventFlag && featureFlags.getFlag(eventFlag)); diff --git a/packages/lib/client-only/hooks/use-copy-share-link.ts b/packages/lib/client-only/hooks/use-copy-share-link.ts index a8bef34af..6f9f58164 100644 --- a/packages/lib/client-only/hooks/use-copy-share-link.ts +++ b/packages/lib/client-only/hooks/use-copy-share-link.ts @@ -40,7 +40,7 @@ export function useCopyShareLink({ onSuccess, onError }: UseCopyShareLinkOptions } onSuccess?.(); - } catch (e) { + } catch { onError?.(); } }; diff --git a/packages/lib/client-only/hooks/use-copy-to-clipboard.ts b/packages/lib/client-only/hooks/use-copy-to-clipboard.ts index 7ca41d404..f6644bc5f 100644 --- a/packages/lib/client-only/hooks/use-copy-to-clipboard.ts +++ b/packages/lib/client-only/hooks/use-copy-to-clipboard.ts @@ -14,13 +14,16 @@ export function useCopyToClipboard(): [CopiedValue, CopyFn] { return false; } - const isClipboardApiSupported = Boolean(typeof ClipboardItem && navigator.clipboard.write); + const isClipboardApiSupported = + typeof ClipboardItem !== 'undefined' && typeof navigator.clipboard.write === 'function'; // Try to save to clipboard then save it in the state if worked try { - isClipboardApiSupported - ? await handleClipboardApiCopy(text, blobType) - : await handleWriteTextCopy(text); + if (isClipboardApiSupported) { + await handleClipboardApiCopy(text, blobType); + } else { + await handleWriteTextCopy(text); + } setCopiedText(await text); return true; @@ -41,7 +44,7 @@ export function useCopyToClipboard(): [CopiedValue, CopyFn] { const handleClipboardApiCopy = async (value: CopyValue, blobType = 'text/plain') => { try { await navigator.clipboard.write([new ClipboardItem({ [blobType]: value })]); - } catch (e) { + } catch { // Fallback attempt. await handleWriteTextCopy(value); } diff --git a/packages/lib/client-only/hooks/use-editor-fields.ts b/packages/lib/client-only/hooks/use-editor-fields.ts index 6b0b37776..eb118f52c 100644 --- a/packages/lib/client-only/hooks/use-editor-fields.ts +++ b/packages/lib/client-only/hooks/use-editor-fields.ts @@ -251,7 +251,7 @@ export const useEditorFields = ({ const getFieldByFormId = useCallback( (formId: string): TLocalField | undefined => { - return localFields.find((field) => field.formId === formId) as TLocalField | undefined; + return localFields.find((field) => field.formId === formId); }, [localFields], ); diff --git a/packages/lib/client-only/hooks/use-element-scale-size.ts b/packages/lib/client-only/hooks/use-element-scale-size.ts index 1c8ab320e..842586639 100644 --- a/packages/lib/client-only/hooks/use-element-scale-size.ts +++ b/packages/lib/client-only/hooks/use-element-scale-size.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/consistent-type-assertions */ -import { RefObject, useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; /** * Calculate the width and height of a text element. diff --git a/packages/lib/client-only/providers/envelope-editor-provider.tsx b/packages/lib/client-only/providers/envelope-editor-provider.tsx index bdcfd3217..1b2fe946f 100644 --- a/packages/lib/client-only/providers/envelope-editor-provider.tsx +++ b/packages/lib/client-only/providers/envelope-editor-provider.tsx @@ -276,7 +276,7 @@ export const EnvelopeEditorProvider = ({ [envelope.recipients], ); - const { refetch: reloadEnvelope, isLoading: isReloadingEnvelope } = trpc.envelope.get.useQuery( + const { refetch: reloadEnvelope, isLoading: _isReloadingEnvelope } = trpc.envelope.get.useQuery( { envelopeId: envelope.id, }, diff --git a/packages/lib/client-only/providers/envelope-render-provider.tsx b/packages/lib/client-only/providers/envelope-render-provider.tsx index d9fb64cb6..b79d511aa 100644 --- a/packages/lib/client-only/providers/envelope-render-provider.tsx +++ b/packages/lib/client-only/providers/envelope-render-provider.tsx @@ -189,7 +189,7 @@ export const EnvelopeRenderProvider = ({ }, [envelope.envelopeItems]); const recipientIds = useMemo( - () => recipients.map((recipient) => recipient.id).sort(), + () => recipients.map((recipient) => recipient.id).sort((left, right) => left - right), [recipients], ); diff --git a/packages/lib/constants/date-formats.ts b/packages/lib/constants/date-formats.ts index 1f9b75929..5d319f1c7 100644 --- a/packages/lib/constants/date-formats.ts +++ b/packages/lib/constants/date-formats.ts @@ -170,5 +170,8 @@ export const convertToLocalSystemFormat = ( }; export const isValidDateFormat = (dateFormat: unknown): dateFormat is ValidDateFormat => { - return VALID_DATE_FORMAT_VALUES.includes(dateFormat as ValidDateFormat); + return ( + typeof dateFormat === 'string' && + VALID_DATE_FORMAT_VALUES.some((validDateFormat) => validDateFormat === dateFormat) + ); }; diff --git a/packages/lib/constants/i18n.ts b/packages/lib/constants/i18n.ts index 42c9cdd94..027088a4e 100644 --- a/packages/lib/constants/i18n.ts +++ b/packages/lib/constants/i18n.ts @@ -73,4 +73,5 @@ export const SUPPORTED_LANGUAGES: Record = { } satisfies Record; export const isValidLanguageCode = (code: unknown): code is SupportedLanguageCodes => - SUPPORTED_LANGUAGE_CODES.includes(code as SupportedLanguageCodes); + typeof code === 'string' && + SUPPORTED_LANGUAGE_CODES.some((languageCode) => languageCode === code); diff --git a/packages/lib/jobs/client/inngest.ts b/packages/lib/jobs/client/inngest.ts index 702fc1de7..64d127263 100644 --- a/packages/lib/jobs/client/inngest.ts +++ b/packages/lib/jobs/client/inngest.ts @@ -91,11 +91,11 @@ export class InngestJobProvider extends BaseJobProvider { return { wait: step.sleep, logger: { - info: ctx.logger.info, - debug: ctx.logger.debug, - error: ctx.logger.error, - warn: ctx.logger.warn, - log: ctx.logger.info, + info: (...args) => ctx.logger.info(...args), + debug: (...args) => ctx.logger.debug(...args), + error: (...args) => ctx.logger.error(...args), + warn: (...args) => ctx.logger.warn(...args), + log: (...args) => ctx.logger.info(...args), }, runTask: async (cacheKey, callback) => { const result = await step.run(cacheKey, callback); diff --git a/packages/lib/jobs/definitions/internal/execute-webhook.handler.ts b/packages/lib/jobs/definitions/internal/execute-webhook.handler.ts index 2e1799d70..fde7c6e7c 100644 --- a/packages/lib/jobs/definitions/internal/execute-webhook.handler.ts +++ b/packages/lib/jobs/definitions/internal/execute-webhook.handler.ts @@ -7,7 +7,7 @@ import type { TExecuteWebhookJobDefinition } from './execute-webhook'; export const run = async ({ payload, - io, + io: _io, }: { payload: TExecuteWebhookJobDefinition; io: JobRunIO; @@ -28,10 +28,11 @@ export const run = async ({ createdAt: new Date().toISOString(), webhookEndpoint: url, }; + const requestBody: Prisma.InputJsonValue = JSON.parse(JSON.stringify(payloadData)); const response = await fetch(url, { method: 'POST', - body: JSON.stringify(payloadData), + body: JSON.stringify(requestBody), headers: { 'Content-Type': 'application/json', 'X-Documenso-Secret': secret ?? '', @@ -44,7 +45,7 @@ export const run = async ({ try { responseBody = JSON.parse(body); - } catch (err) { + } catch { responseBody = body; } @@ -53,7 +54,7 @@ export const run = async ({ url, event, status: response.ok ? WebhookCallStatus.SUCCESS : WebhookCallStatus.FAILED, - requestBody: payloadData as Prisma.InputJsonValue, + requestBody, responseCode: response.status, responseBody, responseHeaders: Object.fromEntries(response.headers.entries()), diff --git a/packages/lib/server-only/admin/admin-find-unsealed-documents.ts b/packages/lib/server-only/admin/admin-find-unsealed-documents.ts index 41eefc9e8..2a368f2b6 100644 --- a/packages/lib/server-only/admin/admin-find-unsealed-documents.ts +++ b/packages/lib/server-only/admin/admin-find-unsealed-documents.ts @@ -91,9 +91,13 @@ export const adminFindUnsealedDocuments = async ({ ]); const count = Number(countResult[0]?.count ?? 0); + const formattedData: AdminUnsealedDocument[] = data.map((document) => ({ + ...document, + id: String(document.id), + })); return { - data: data as unknown as AdminUnsealedDocument[], + data: formattedData, count, currentPage: Math.max(page, 1), perPage, diff --git a/packages/lib/server-only/admin/get-organisation-detailed-insights.ts b/packages/lib/server-only/admin/get-organisation-detailed-insights.ts index 100c32b31..3c8bb289b 100644 --- a/packages/lib/server-only/admin/get-organisation-detailed-insights.ts +++ b/packages/lib/server-only/admin/get-organisation-detailed-insights.ts @@ -32,7 +32,7 @@ export type TeamInsights = { export type UserInsights = { id: number; - name: string; + name: string | null; email: string; documentCount: number; signedDocumentCount: number; @@ -98,7 +98,7 @@ export async function getOrganisationDetailedInsights({ case 'documents': return await getDocumentInsights(organisationId, offset, perPage, createdAtFrom); default: - throw new Error(`Invalid view: ${view}`); + throw new Error('Invalid view'); } })(); @@ -149,9 +149,14 @@ async function getTeamInsights( const [teams, countResult] = await Promise.all([teamsQuery.execute(), countQuery.execute()]); const count = Number(countResult[0]?.count || 0); + const teamInsights: TeamInsights[] = teams.map((team) => ({ + ...team, + memberCount: Number(team.memberCount), + documentCount: Number(team.documentCount), + })); return { - teams: teams as TeamInsights[], + teams: teamInsights, users: [], documents: [], totalPages: Math.ceil(Number(count) / perPage), @@ -208,10 +213,15 @@ async function getUserInsights( const [users, countResult] = await Promise.all([usersQuery.execute(), countQuery.execute()]); const count = Number(countResult[0]?.count || 0); + const userInsights: UserInsights[] = users.map((user) => ({ + ...user, + documentCount: Number(user.documentCount), + signedDocumentCount: Number(user.signedDocumentCount), + })); return { teams: [], - users: users as UserInsights[], + users: userInsights, documents: [], totalPages: Math.ceil(Number(count) / perPage), }; @@ -223,18 +233,13 @@ async function getDocumentInsights( perPage: number, createdAtFrom: Date | null, ): Promise { - let documentsQuery = kyselyPrisma.$kysely + const documentsQuery = kyselyPrisma.$kysely .selectFrom('Envelope as e') .innerJoin('Team as t', 'e.teamId', 't.id') .where('t.organisationId', '=', organisationId) .where('e.deletedAt', 'is', null) - .where(() => sql`e.type = ${EnvelopeType.DOCUMENT}::"EnvelopeType"`); - - if (createdAtFrom) { - documentsQuery = documentsQuery.where('e.createdAt', '>=', createdAtFrom); - } - - documentsQuery = documentsQuery + .where(() => sql`e.type = ${EnvelopeType.DOCUMENT}::"EnvelopeType"`) + .$if(!!createdAtFrom, (qb) => qb.where('e.createdAt', '>=', createdAtFrom!)) .select([ 'e.id as id', 'e.title as title', @@ -247,33 +252,33 @@ async function getDocumentInsights( .limit(perPage) .offset(offset); - let countQuery = kyselyPrisma.$kysely + const countQuery = kyselyPrisma.$kysely .selectFrom('Envelope as e') .innerJoin('Team as t', 'e.teamId', 't.id') .where('t.organisationId', '=', organisationId) .where('e.deletedAt', 'is', null) - .where(() => sql`e.type = ${EnvelopeType.DOCUMENT}::"EnvelopeType"`); - - if (createdAtFrom) { - countQuery = countQuery.where('e.createdAt', '>=', createdAtFrom); - } - - countQuery = countQuery.select(({ fn }) => [fn.countAll().as('count')]); + .where(() => sql`e.type = ${EnvelopeType.DOCUMENT}::"EnvelopeType"`) + .$if(!!createdAtFrom, (qb) => qb.where('e.createdAt', '>=', createdAtFrom!)) + .select(sql`count(*)`.as('count')); const [documents, countResult] = await Promise.all([ documentsQuery.execute(), - countQuery.execute(), + countQuery.executeTakeFirst(), ]); - - const count = Number((countResult[0] as { count: number })?.count || 0); + const count = Number(countResult?.count || 0); + const documentInsights: DocumentInsights[] = documents.map((document) => ({ + title: document.title, + status: document.status, + createdAt: document.createdAt, + completedAt: document.completedAt, + teamName: document.teamName, + id: String(document.id), + })); return { teams: [], users: [], - documents: documents.map((doc) => ({ - ...doc, - id: String((doc as { id: number }).id), - })) as DocumentInsights[], + documents: documentInsights, totalPages: Math.ceil(Number(count) / perPage), }; } diff --git a/packages/lib/server-only/ai/pdf-to-images.ts b/packages/lib/server-only/ai/pdf-to-images.ts index e14128278..b982e7d14 100644 --- a/packages/lib/server-only/ai/pdf-to-images.ts +++ b/packages/lib/server-only/ai/pdf-to-images.ts @@ -47,7 +47,7 @@ export type PdfToImagesOptions = { export const pdfToImages = async (pdfBytes: Uint8Array, options: PdfToImagesOptions = {}) => { const { scale = 2 } = options; - const task = await pdfjsLib.getDocument({ + const task = pdfjsLib.getDocument({ data: pdfBytes, CanvasFactory: SkiaCanvasFactory, }); diff --git a/packages/lib/server-only/envelope/duplicate-envelope.ts b/packages/lib/server-only/envelope/duplicate-envelope.ts index c83bc85a2..e949b7941 100644 --- a/packages/lib/server-only/envelope/duplicate-envelope.ts +++ b/packages/lib/server-only/envelope/duplicate-envelope.ts @@ -4,6 +4,7 @@ import { omit } from 'remeda'; import { prisma } from '@documenso/prisma'; import { AppError, AppErrorCode } from '../../errors/app-error'; +import { ZFieldMetaSchema } from '../../types/field-meta'; import { ZWebhookDocumentSchema, mapEnvelopeToWebhookDocumentPayload, @@ -158,7 +159,7 @@ export const duplicateEnvelope = async ({ id, userId, teamId }: DuplicateEnvelop height: field.height, customText: '', inserted: false, - fieldMeta: field.fieldMeta as PrismaJson.FieldMeta, + fieldMeta: field.fieldMeta ? ZFieldMetaSchema.parse(field.fieldMeta) : undefined, })), }, }, diff --git a/packages/lib/server-only/envelope/get-envelope-for-direct-template-signing.ts b/packages/lib/server-only/envelope/get-envelope-for-direct-template-signing.ts index d6be78773..6cc0f15f4 100644 --- a/packages/lib/server-only/envelope/get-envelope-for-direct-template-signing.ts +++ b/packages/lib/server-only/envelope/get-envelope-for-direct-template-signing.ts @@ -25,7 +25,7 @@ export type GetRecipientEnvelopeByTokenOptions = { export const getEnvelopeForDirectTemplateSigning = async ({ token, userId, - accessAuth, + accessAuth: _accessAuth, }: GetRecipientEnvelopeByTokenOptions): Promise => { if (!token) { throw new AppError(AppErrorCode.NOT_FOUND, { diff --git a/packages/lib/server-only/envelope/update-envelope.ts b/packages/lib/server-only/envelope/update-envelope.ts index d2cf256bd..e1709aa9d 100644 --- a/packages/lib/server-only/envelope/update-envelope.ts +++ b/packages/lib/server-only/envelope/update-envelope.ts @@ -193,12 +193,12 @@ export const updateEnvelope = async ({ isDeepEqual(documentGlobalActionAuth, newGlobalActionAuth); const isDocumentVisibilitySame = data.visibility === undefined || data.visibility === envelope.visibility; - const isFolderSame = data.folderId === undefined || data.folderId === envelope.folderId; - const isTemplateTypeSame = + const _isFolderSame = data.folderId === undefined || data.folderId === envelope.folderId; + const _isTemplateTypeSame = data.templateType === undefined || data.templateType === envelope.templateType; - const isPublicDescriptionSame = + const _isPublicDescriptionSame = data.publicDescription === undefined || data.publicDescription === envelope.publicDescription; - const isPublicTitleSame = + const _isPublicTitleSame = data.publicTitle === undefined || data.publicTitle === envelope.publicTitle; const auditLogs: CreateDocumentAuditLogDataResponse[] = []; diff --git a/packages/lib/server-only/konva/skia-backend.ts b/packages/lib/server-only/konva/skia-backend.ts index bdcd4ec64..57ce2e5c3 100644 --- a/packages/lib/server-only/konva/skia-backend.ts +++ b/packages/lib/server-only/konva/skia-backend.ts @@ -27,6 +27,7 @@ Konva.Util['createCanvasElement'] = () => { get: () => node, }); + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions return node as unknown as HTMLCanvasElement; }; @@ -34,6 +35,7 @@ Konva.Util.createImageElement = () => { const node = new Image(); node.toString = () => '[object HTMLImageElement]'; + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions return node as unknown as HTMLImageElement; }; diff --git a/packages/lib/server-only/pdf/add-rejection-stamp-to-pdf.ts b/packages/lib/server-only/pdf/add-rejection-stamp-to-pdf.ts index b80aa0249..8ed99bc66 100644 --- a/packages/lib/server-only/pdf/add-rejection-stamp-to-pdf.ts +++ b/packages/lib/server-only/pdf/add-rejection-stamp-to-pdf.ts @@ -6,7 +6,7 @@ import { NEXT_PRIVATE_INTERNAL_WEBAPP_URL } from '../../constants/app'; * Adds a rejection stamp to each page of a PDF document. * The stamp is placed in the center of the page. */ -export async function addRejectionStampToPdf(pdf: PDF, reason: string): Promise { +export async function addRejectionStampToPdf(pdf: PDF, _reason: string): Promise { const pages = pdf.getPages(); const fontBytes = await fetch(`${NEXT_PRIVATE_INTERNAL_WEBAPP_URL()}/fonts/noto-sans.ttf`).then( diff --git a/packages/lib/server-only/pdf/insert-field-in-pdf-v1.ts b/packages/lib/server-only/pdf/insert-field-in-pdf-v1.ts index e339c2b68..ef86b91c2 100644 --- a/packages/lib/server-only/pdf/insert-field-in-pdf-v1.ts +++ b/packages/lib/server-only/pdf/insert-field-in-pdf-v1.ts @@ -694,10 +694,10 @@ const setTextFieldFontSize = (textField: PDFTextField, font: PDFFont, fontSize: try { textField.setFontSize(fontSize); - } catch (err) { + } catch { let da = textField.acroField.getDefaultAppearance() ?? ''; - da += `\n ${setFontAndSize(font.name, fontSize)}`; + da += `\n ${String(setFontAndSize(font.name, fontSize))}`; textField.acroField.setDefaultAppearance(da); } diff --git a/packages/lib/server-only/pdf/render-audit-logs.ts b/packages/lib/server-only/pdf/render-audit-logs.ts index 53874e96e..f7bc4d759 100644 --- a/packages/lib/server-only/pdf/render-audit-logs.ts +++ b/packages/lib/server-only/pdf/render-audit-logs.ts @@ -51,7 +51,7 @@ const parser = new UAParser(); const textMutedForegroundLight = '#929DAE'; const textForeground = '#000'; const textMutedForeground = '#64748B'; -const textBase = 10; +const _textBase = 10; const textSm = 9; const textXs = 8; const fontMedium = '500'; diff --git a/packages/lib/server-only/pdf/render-certificate.ts b/packages/lib/server-only/pdf/render-certificate.ts index 9991e447a..bf993de11 100644 --- a/packages/lib/server-only/pdf/render-certificate.ts +++ b/packages/lib/server-only/pdf/render-certificate.ts @@ -75,13 +75,13 @@ const getDevice = (userAgent?: string | null): string => { return `${result.os.name} - ${result.browser.name} ${result.browser.version}`; }; -const textMutedForegroundLight = '#929DAE'; -const textForeground = '#000'; +const _textMutedForegroundLight = '#929DAE'; +const _textForeground = '#000'; const textMutedForeground = '#64748B'; const textRejectedRed = '#dc2626'; const textBase = 10; const textSm = 9; -const textXs = 8; +const _textXs = 8; const fontMedium = '500'; const columnWidthPercentages = [30, 30, 40]; diff --git a/packages/lib/server-only/profile/set-avatar-image.ts b/packages/lib/server-only/profile/set-avatar-image.ts index a67a6fe08..8b4b63c0a 100644 --- a/packages/lib/server-only/profile/set-avatar-image.ts +++ b/packages/lib/server-only/profile/set-avatar-image.ts @@ -33,7 +33,7 @@ export const setAvatarImage = async ({ userId, target, bytes, - requestMetadata, + requestMetadata: _requestMetadata, }: SetAvatarImageOptions) => { let oldAvatarImageId: string | null = null; diff --git a/packages/lib/server-only/public-api/test-credentials.ts b/packages/lib/server-only/public-api/test-credentials.ts index 76b5a84a1..692d83445 100644 --- a/packages/lib/server-only/public-api/test-credentials.ts +++ b/packages/lib/server-only/public-api/test-credentials.ts @@ -13,7 +13,7 @@ export const testCredentialsHandler = async (req: Request) => { return Response.json({ name: result.team?.name ?? result.user.name, }); - } catch (err) { + } catch { return Response.json( { message: 'Internal Server Error', diff --git a/packages/lib/server-only/team/delete-team-email.ts b/packages/lib/server-only/team/delete-team-email.ts index 4e4b538e5..a50c1f096 100644 --- a/packages/lib/server-only/team/delete-team-email.ts +++ b/packages/lib/server-only/team/delete-team-email.ts @@ -99,7 +99,7 @@ export const deleteTeamEmail = async ({ userId, userEmail, teamId }: DeleteTeamE html, text, }); - } catch (e) { + } catch { // Todo: Teams - Alert us. // We don't want to prevent a user from revoking access because an email could not be sent. } diff --git a/packages/lib/server-only/user/service-accounts/deleted-account.ts b/packages/lib/server-only/user/service-accounts/deleted-account.ts index 38c2b8fcb..9d61febeb 100644 --- a/packages/lib/server-only/user/service-accounts/deleted-account.ts +++ b/packages/lib/server-only/user/service-accounts/deleted-account.ts @@ -13,7 +13,7 @@ export const deletedServiceAccountEmail = () => { const { hostname } = new URL(process.env.NEXT_PUBLIC_WEBAPP_URL || 'http://localhost:3000'); return `deleted-account@${hostname}`; - } catch (error) { + } catch { return LEGACY_DELETED_ACCOUNT_EMAIL; } }; diff --git a/packages/lib/server-only/user/service-accounts/legacy-service-account.ts b/packages/lib/server-only/user/service-accounts/legacy-service-account.ts index 3299c2a47..9de886ea8 100644 --- a/packages/lib/server-only/user/service-accounts/legacy-service-account.ts +++ b/packages/lib/server-only/user/service-accounts/legacy-service-account.ts @@ -13,7 +13,7 @@ export const legacyServiceAccountEmail = () => { const { hostname } = new URL(process.env.NEXT_PUBLIC_WEBAPP_URL || 'http://localhost:3000'); return `serviceaccount@${hostname}`; - } catch (error) { + } catch { return LEGACY_SERVICE_ACCOUNT_EMAIL; } }; diff --git a/packages/lib/server-only/webhooks/trigger/generate-sample-data.ts b/packages/lib/server-only/webhooks/trigger/generate-sample-data.ts index 86b63a23f..7bfeba7fb 100644 --- a/packages/lib/server-only/webhooks/trigger/generate-sample-data.ts +++ b/packages/lib/server-only/webhooks/trigger/generate-sample-data.ts @@ -545,5 +545,5 @@ export const generateSampleWebhookPayload = ( }; } - throw new Error(`Unsupported event type: ${event}`); + throw new Error('Unsupported event type'); }; diff --git a/packages/lib/server-only/webhooks/zapier/validateApiToken.ts b/packages/lib/server-only/webhooks/zapier/validateApiToken.ts index 45e2b7522..fec08d06f 100644 --- a/packages/lib/server-only/webhooks/zapier/validateApiToken.ts +++ b/packages/lib/server-only/webhooks/zapier/validateApiToken.ts @@ -14,7 +14,7 @@ export const validateApiToken = async ({ authorization }: ValidateApiTokenOption } return await getApiTokenByToken({ token }); - } catch (err) { + } catch { throw new Error(`Failed to validate API token`); } }; diff --git a/packages/lib/types/field-meta.ts b/packages/lib/types/field-meta.ts index e4ed9be40..ed9ace692 100644 --- a/packages/lib/types/field-meta.ts +++ b/packages/lib/types/field-meta.ts @@ -418,5 +418,3 @@ export const ZEnvelopeFieldAndMetaSchema = z.discriminatedUnion('type', [ fieldMeta: ZDropdownFieldMeta.optional().default(FIELD_DROPDOWN_META_DEFAULT_VALUES), }), ]); - -type TEnvelopeFieldAndMeta = z.infer; diff --git a/packages/lib/universal/field-renderer/field-renderer.ts b/packages/lib/universal/field-renderer/field-renderer.ts index 8f66084e2..244853c16 100644 --- a/packages/lib/universal/field-renderer/field-renderer.ts +++ b/packages/lib/universal/field-renderer/field-renderer.ts @@ -11,7 +11,7 @@ export const MIN_FIELD_WIDTH_PX = 36; export type FieldToRender = Pick< Field, - 'envelopeItemId' | 'recipientId' | 'type' | 'page' | 'customText' | 'inserted' | 'recipientId' + 'envelopeItemId' | 'recipientId' | 'type' | 'page' | 'customText' | 'inserted' > & { renderId: string; // A unique ID for the field in the render. width: number; diff --git a/packages/lib/universal/field-renderer/render-checkbox-field.ts b/packages/lib/universal/field-renderer/render-checkbox-field.ts index 00e499c63..b15b74258 100644 --- a/packages/lib/universal/field-renderer/render-checkbox-field.ts +++ b/packages/lib/universal/field-renderer/render-checkbox-field.ts @@ -30,7 +30,8 @@ export const renderCheckboxFieldElement = ( const { fieldWidth, fieldHeight } = calculateFieldPosition(field, pageWidth, pageHeight); - const checkboxMeta: TCheckboxFieldMeta | null = (field.fieldMeta as TCheckboxFieldMeta) || null; + const checkboxMeta: TCheckboxFieldMeta | null = + field.fieldMeta?.type === 'checkbox' ? field.fieldMeta : null; const checkboxValues = checkboxMeta?.values || []; const isFirstRender = !pageLayer.findOne(`#${field.renderId}`); @@ -131,6 +132,7 @@ export const renderCheckboxFieldElement = ( }); const checkedValues: number[] = field.customText ? parseCheckboxCustomText(field.customText) : []; + const isReadOnly = checkboxMeta?.readOnly ?? false; checkboxValues.forEach(({ value, checked }, index) => { const isCheckboxChecked = match(mode) @@ -138,7 +140,7 @@ export const renderCheckboxFieldElement = ( .with('sign', () => checkedValues.includes(index)) .with('export', () => { // If it's read-only, check the originally checked state. - if (checkboxMeta.readOnly) { + if (isReadOnly) { return checked; } diff --git a/packages/lib/universal/field-renderer/render-dropdown-field.ts b/packages/lib/universal/field-renderer/render-dropdown-field.ts index 4d8e826f7..4b75fd5d9 100644 --- a/packages/lib/universal/field-renderer/render-dropdown-field.ts +++ b/packages/lib/universal/field-renderer/render-dropdown-field.ts @@ -54,7 +54,8 @@ export const renderDropdownFieldElement = ( const { fieldWidth, fieldHeight } = calculateFieldPosition(field, pageWidth, pageHeight); - const dropdownMeta: TDropdownFieldMeta | null = (field.fieldMeta as TDropdownFieldMeta) || null; + const dropdownMeta: TDropdownFieldMeta | null = + field.fieldMeta?.type === 'dropdown' ? field.fieldMeta : null; let selectedValue = translations?.[FieldType.DROPDOWN] || 'Select Option'; diff --git a/packages/lib/universal/field-renderer/render-field.ts b/packages/lib/universal/field-renderer/render-field.ts index d7000389a..88a20eef1 100644 --- a/packages/lib/universal/field-renderer/render-field.ts +++ b/packages/lib/universal/field-renderer/render-field.ts @@ -28,7 +28,7 @@ export type FieldRenderMode = 'edit' | 'sign' | 'export'; export type FieldToRender = Pick< Field, - 'envelopeItemId' | 'recipientId' | 'type' | 'page' | 'customText' | 'inserted' | 'recipientId' + 'envelopeItemId' | 'recipientId' | 'type' | 'page' | 'customText' | 'inserted' > & { renderId: string; // A unique ID for the field in the render. width: number; diff --git a/packages/lib/universal/field-renderer/render-generic-text-field.ts b/packages/lib/universal/field-renderer/render-generic-text-field.ts index 6b90e48da..d977f0d5e 100644 --- a/packages/lib/universal/field-renderer/render-generic-text-field.ts +++ b/packages/lib/universal/field-renderer/render-generic-text-field.ts @@ -20,12 +20,29 @@ import { calculateFieldPosition } from './field-renderer'; const DEFAULT_TEXT_X_PADDING = 6; +const getGenericTextFieldMeta = (field: FieldToRender): GenericTextFieldTypeMetas | undefined => { + const fieldMeta = field.fieldMeta; + + if ( + fieldMeta?.type === 'initials' || + fieldMeta?.type === 'name' || + fieldMeta?.type === 'email' || + fieldMeta?.type === 'date' || + fieldMeta?.type === 'text' || + fieldMeta?.type === 'number' + ) { + return fieldMeta; + } + + return undefined; +}; + const upsertFieldText = (field: FieldToRender, options: RenderFieldElementOptions): Konva.Text => { const { pageWidth, pageHeight, mode = 'edit', pageLayer, translations } = options; const { fieldWidth, fieldHeight } = calculateFieldPosition(field, pageWidth, pageHeight); - const fieldMeta = field.fieldMeta as GenericTextFieldTypeMetas | undefined; + const fieldMeta = getGenericTextFieldMeta(field); const fieldTypeName = translations?.[field.type] || field.type; diff --git a/packages/lib/universal/field-renderer/render-radio-field.ts b/packages/lib/universal/field-renderer/render-radio-field.ts index ebeaa70cb..067197ad1 100644 --- a/packages/lib/universal/field-renderer/render-radio-field.ts +++ b/packages/lib/universal/field-renderer/render-radio-field.ts @@ -27,7 +27,8 @@ export const renderRadioFieldElement = ( ) => { const { pageWidth, pageHeight, pageLayer, mode, color } = options; - const radioMeta: TRadioFieldMeta | null = (field.fieldMeta as TRadioFieldMeta) || null; + const radioMeta: TRadioFieldMeta | null = + field.fieldMeta?.type === 'radio' ? field.fieldMeta : null; const radioValues = radioMeta?.values || []; const isFirstRender = !pageLayer.findOne(`#${field.renderId}`); @@ -122,6 +123,7 @@ export const renderRadioFieldElement = ( }); const { fieldWidth, fieldHeight } = calculateFieldPosition(field, pageWidth, pageHeight); + const isReadOnly = radioMeta?.readOnly ?? false; radioValues.forEach(({ value, checked }, index) => { const isRadioValueChecked = match(mode) @@ -129,7 +131,7 @@ export const renderRadioFieldElement = ( .with('sign', () => index.toString() === field.customText) .with('export', () => { // If it's read-only, check the originally checked state. - if (radioMeta.readOnly) { + if (isReadOnly) { return checked; } diff --git a/packages/lib/universal/upload/get-file.ts b/packages/lib/universal/upload/get-file.ts index ac62b1744..132e7b6c1 100644 --- a/packages/lib/universal/upload/get-file.ts +++ b/packages/lib/universal/upload/get-file.ts @@ -13,7 +13,7 @@ export type GetFileOptions = { * * - Lucas, 2025-11-04 */ -const getFile = async ({ type, data }: GetFileOptions) => { +const _getFile = async ({ type, data }: GetFileOptions) => { return await match(type) .with(DocumentDataType.BYTES, () => getFileFromBytes(data)) .with(DocumentDataType.BYTES_64, () => getFileFromBytes64(data)) diff --git a/packages/lib/utils/envelope-download.ts b/packages/lib/utils/envelope-download.ts index 82e1dd2cd..e0eed5110 100644 --- a/packages/lib/utils/envelope-download.ts +++ b/packages/lib/utils/envelope-download.ts @@ -26,7 +26,7 @@ export const getEnvelopeItemPdfUrl = (options: EnvelopeItemPdfUrlOptions) => { const version = options.version; return token - ? `${NEXT_PUBLIC_WEBAPP_URL()}/api/files/token/${token}/envelopeItem/${id}/download/${version}${presignToken ? `?presignToken=${presignToken}` : ''}` + ? `${NEXT_PUBLIC_WEBAPP_URL()}/api/files/token/${token}/envelopeItem/${id}/download/${version}` : `${NEXT_PUBLIC_WEBAPP_URL()}/api/files/envelope/${envelopeId}/envelopeItem/${id}/download/${version}`; } diff --git a/packages/lib/utils/fields.ts b/packages/lib/utils/fields.ts index ec26192eb..b7888df16 100644 --- a/packages/lib/utils/fields.ts +++ b/packages/lib/utils/fields.ts @@ -53,8 +53,8 @@ export const validateFieldsUninserted = (): boolean => { const innerDiv = element.querySelector('div'); const hasError = innerDiv?.getAttribute('data-error') === 'true'; - if (hasError) { - errorElements.push(element as HTMLElement); + if (hasError && element instanceof HTMLElement) { + errorElements.push(element); } else { element.removeAttribute('data-error'); } diff --git a/packages/trpc/server/admin-router/update-organisation-member-role.ts b/packages/trpc/server/admin-router/update-organisation-member-role.ts index bfb12256b..7338c86c8 100644 --- a/packages/trpc/server/admin-router/update-organisation-member-role.ts +++ b/packages/trpc/server/admin-router/update-organisation-member-role.ts @@ -151,7 +151,7 @@ export const updateOrganisationMemberRoleRoute = adminProcedure return; } - const targetRole = role as OrganisationMemberRole; + const targetRole: OrganisationMemberRole = role; if (currentOrganisationRole === targetRole) { throw new AppError(AppErrorCode.INVALID_REQUEST, { diff --git a/packages/trpc/server/document-router/access-auth-request-2fa-email.ts b/packages/trpc/server/document-router/access-auth-request-2fa-email.ts index 986705b98..a35d793cf 100644 --- a/packages/trpc/server/document-router/access-auth-request-2fa-email.ts +++ b/packages/trpc/server/document-router/access-auth-request-2fa-email.ts @@ -30,8 +30,6 @@ export const accessAuthRequest2FAEmailRoute = procedure assertRateLimit(rateLimitResult); - const user = ctx.user; - // Get document and recipient by token const envelope = await prisma.envelope.findFirst({ where: { diff --git a/packages/trpc/server/folder-router/router.ts b/packages/trpc/server/folder-router/router.ts index 755b23452..8af9893b0 100644 --- a/packages/trpc/server/folder-router/router.ts +++ b/packages/trpc/server/folder-router/router.ts @@ -174,7 +174,7 @@ export const folderRouter = router({ folderId: parentId, type, }); - } catch (error) { + } catch { throw new AppError(AppErrorCode.NOT_FOUND, { message: 'Parent folder not found', }); diff --git a/packages/trpc/server/webhook-router/find-webhook-calls.ts b/packages/trpc/server/webhook-router/find-webhook-calls.ts index fa3bc0966..4b1fb5755 100644 --- a/packages/trpc/server/webhook-router/find-webhook-calls.ts +++ b/packages/trpc/server/webhook-router/find-webhook-calls.ts @@ -1,4 +1,4 @@ -import { Prisma, WebhookCallStatus, WebhookTriggerEvents } from '@prisma/client'; +import type { Prisma, WebhookCallStatus, WebhookTriggerEvents } from '@prisma/client'; import { TEAM_MEMBER_ROLE_PERMISSIONS_MAP } from '@documenso/lib/constants/teams'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; diff --git a/packages/trpc/server/webhook-router/resend-webhook-call.ts b/packages/trpc/server/webhook-router/resend-webhook-call.ts index abb0ca34e..e016bdfcc 100644 --- a/packages/trpc/server/webhook-router/resend-webhook-call.ts +++ b/packages/trpc/server/webhook-router/resend-webhook-call.ts @@ -1,8 +1,7 @@ -import { Prisma, WebhookCallStatus, WebhookTriggerEvents } from '@prisma/client'; +import { Prisma, WebhookCallStatus } from '@prisma/client'; import { TEAM_MEMBER_ROLE_PERMISSIONS_MAP } from '@documenso/lib/constants/teams'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; -import type { FindResultResponse } from '@documenso/lib/types/search-params'; import { buildTeamWhereQuery } from '@documenso/lib/utils/teams'; import { prisma } from '@documenso/prisma'; @@ -62,7 +61,7 @@ export const resendWebhookCallRoute = authenticatedProcedure try { responseBody = JSON.parse(body); - } catch (err) { + } catch { responseBody = body; } diff --git a/packages/trpc/server/webhook-router/resend-webhook-call.types.ts b/packages/trpc/server/webhook-router/resend-webhook-call.types.ts index f34b9ebc6..d75ba994d 100644 --- a/packages/trpc/server/webhook-router/resend-webhook-call.types.ts +++ b/packages/trpc/server/webhook-router/resend-webhook-call.types.ts @@ -1,4 +1,3 @@ -import { WebhookCallStatus, WebhookTriggerEvents } from '@prisma/client'; import { z } from 'zod'; import WebhookCallSchema from '@documenso/prisma/generated/zod/modelSchema/WebhookCallSchema'; diff --git a/packages/ui/components/document/document-global-auth-access-select.tsx b/packages/ui/components/document/document-global-auth-access-select.tsx index d5e99ba74..e576d19c1 100644 --- a/packages/ui/components/document/document-global-auth-access-select.tsx +++ b/packages/ui/components/document/document-global-auth-access-select.tsx @@ -39,17 +39,13 @@ export const DocumentGlobalAuthAccessSelect = ({ })), ]; - // Convert string array to Option array for MultiSelect - const selectedOptions = - (value - ?.map((val) => authOptions.find((option) => option.value === val)) - .filter(Boolean) as Option[]) || []; + const getSelectedOptions = (selectedValues?: string[]) => + selectedValues + ?.map((selectedValue) => authOptions.find((option) => option.value === selectedValue)) + .filter((option): option is Option => option !== undefined) ?? []; - // Convert default value to Option array - const defaultOptions = - (defaultValue - ?.map((val) => authOptions.find((option) => option.value === val)) - .filter(Boolean) as Option[]) || []; + const selectedOptions = getSelectedOptions(value); + const defaultOptions = getSelectedOptions(defaultValue); const handleChange = (options: Option[]) => { const values = options.map((option) => option.value); @@ -79,7 +75,7 @@ export const DocumentGlobalAuthAccessTooltip = () => ( - +

Document access diff --git a/packages/ui/components/document/document-global-auth-action-select.tsx b/packages/ui/components/document/document-global-auth-action-select.tsx index a2e872fd2..b83d1cc3f 100644 --- a/packages/ui/components/document/document-global-auth-action-select.tsx +++ b/packages/ui/components/document/document-global-auth-action-select.tsx @@ -39,17 +39,13 @@ export const DocumentGlobalAuthActionSelect = ({ })), ]; - // Convert string array to Option array for MultiSelect - const selectedOptions = - (value - ?.map((val) => authOptions.find((option) => option.value === val)) - .filter(Boolean) as Option[]) || []; + const getSelectedOptions = (selectedValues?: string[]) => + selectedValues + ?.map((selectedValue) => authOptions.find((option) => option.value === selectedValue)) + .filter((option): option is Option => option !== undefined) ?? []; - // Convert default value to Option array - const defaultOptions = - (defaultValue - ?.map((val) => authOptions.find((option) => option.value === val)) - .filter(Boolean) as Option[]) || []; + const selectedOptions = getSelectedOptions(value); + const defaultOptions = getSelectedOptions(defaultValue); const handleChange = (options: Option[]) => { const values = options.map((option) => option.value); @@ -79,7 +75,7 @@ export const DocumentGlobalAuthActionTooltip = () => ( - +

Global recipient action authentication

diff --git a/packages/ui/components/document/envelope-recipient-field-tooltip.tsx b/packages/ui/components/document/envelope-recipient-field-tooltip.tsx index 721834bc7..0439b5f7e 100644 --- a/packages/ui/components/document/envelope-recipient-field-tooltip.tsx +++ b/packages/ui/components/document/envelope-recipient-field-tooltip.tsx @@ -56,7 +56,7 @@ export function EnvelopeRecipientFieldTooltip({ field, showFieldStatus = false, showRecipientTooltip = false, - showRecipientColors = false, + showRecipientColors: _showRecipientColors = false, }: EnvelopeRecipientFieldTooltipProps) { const { t } = useLingui(); @@ -145,7 +145,7 @@ export function EnvelopeRecipientFieldTooltip({ > + {extractInitials(field.recipient.name || field.recipient.email)} @@ -191,12 +191,12 @@ export function EnvelopeRecipientFieldTooltip({

-

+

{getRecipientDisplayText(field.recipient)}