From 5df393295853cbd888f839cceeabb4665f739543 Mon Sep 17 00:00:00 2001 From: Catalin Pit Date: Mon, 24 Nov 2025 12:45:31 +0200 Subject: [PATCH 1/3] fix: update branding logic (#2238) Update branding logic to ensure company details are displayed only when branding is enabled --- packages/email/template-components/template-footer.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/email/template-components/template-footer.tsx b/packages/email/template-components/template-footer.tsx index 0f90ec281..58b015c4d 100644 --- a/packages/email/template-components/template-footer.tsx +++ b/packages/email/template-components/template-footer.tsx @@ -23,7 +23,7 @@ export const TemplateFooter = ({ isDocument = true }: TemplateFooterProps) => { )} - {branding.brandingCompanyDetails ? ( + {branding.brandingEnabled && branding.brandingCompanyDetails && ( {branding.brandingCompanyDetails.split('\n').map((line, idx) => { return ( @@ -34,7 +34,9 @@ export const TemplateFooter = ({ isDocument = true }: TemplateFooterProps) => { ); })} - ) : ( + )} + + {!branding.brandingEnabled && ( Documenso, Inc.
From e364b08b6a3248b50081642457ddd448300a4362 Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Tue, 25 Nov 2025 11:43:23 +1100 Subject: [PATCH 2/3] fix: optimize webhook routing (#2236) --- apps/remix/app/routes/api+/webhook.trigger.ts | 1 + .../internal/execute-webhook.handler.ts | 92 +++++++++---------- .../server-only/webhooks/trigger/handler.ts | 1 + .../webhooks/trigger/trigger-webhook.ts | 36 +++----- 4 files changed, 60 insertions(+), 70 deletions(-) diff --git a/apps/remix/app/routes/api+/webhook.trigger.ts b/apps/remix/app/routes/api+/webhook.trigger.ts index 582c86296..d7ed16a96 100644 --- a/apps/remix/app/routes/api+/webhook.trigger.ts +++ b/apps/remix/app/routes/api+/webhook.trigger.ts @@ -1,3 +1,4 @@ +// Todo: [Webhooks] delete file after deployment. import { handlerTriggerWebhooks } from '@documenso/lib/server-only/webhooks/trigger/handler'; import type { Route } from './+types/webhook.trigger'; diff --git a/packages/lib/jobs/definitions/internal/execute-webhook.handler.ts b/packages/lib/jobs/definitions/internal/execute-webhook.handler.ts index a357ea51f..2e1799d70 100644 --- a/packages/lib/jobs/definitions/internal/execute-webhook.handler.ts +++ b/packages/lib/jobs/definitions/internal/execute-webhook.handler.ts @@ -22,53 +22,51 @@ export const run = async ({ const { webhookUrl: url, secret } = webhook; - await io.runTask('execute-webhook', async () => { - const payloadData = { - event, - payload: data, - createdAt: new Date().toISOString(), - webhookEndpoint: url, - }; + const payloadData = { + event, + payload: data, + createdAt: new Date().toISOString(), + webhookEndpoint: url, + }; - const response = await fetch(url, { - method: 'POST', - body: JSON.stringify(payloadData), - headers: { - 'Content-Type': 'application/json', - 'X-Documenso-Secret': secret ?? '', - }, - }); - - const body = await response.text(); - - let responseBody: Prisma.InputJsonValue | Prisma.JsonNullValueInput = Prisma.JsonNull; - - try { - responseBody = JSON.parse(body); - } catch (err) { - responseBody = body; - } - - await prisma.webhookCall.create({ - data: { - url, - event, - status: response.ok ? WebhookCallStatus.SUCCESS : WebhookCallStatus.FAILED, - requestBody: payloadData as Prisma.InputJsonValue, - responseCode: response.status, - responseBody, - responseHeaders: Object.fromEntries(response.headers.entries()), - webhookId: webhook.id, - }, - }); - - if (!response.ok) { - throw new Error(`Webhook execution failed with status ${response.status}`); - } - - return { - success: response.ok, - status: response.status, - }; + const response = await fetch(url, { + method: 'POST', + body: JSON.stringify(payloadData), + headers: { + 'Content-Type': 'application/json', + 'X-Documenso-Secret': secret ?? '', + }, }); + + const body = await response.text(); + + let responseBody: Prisma.InputJsonValue | Prisma.JsonNullValueInput = Prisma.JsonNull; + + try { + responseBody = JSON.parse(body); + } catch (err) { + responseBody = body; + } + + await prisma.webhookCall.create({ + data: { + url, + event, + status: response.ok ? WebhookCallStatus.SUCCESS : WebhookCallStatus.FAILED, + requestBody: payloadData as Prisma.InputJsonValue, + responseCode: response.status, + responseBody, + responseHeaders: Object.fromEntries(response.headers.entries()), + webhookId: webhook.id, + }, + }); + + if (!response.ok) { + throw new Error(`Webhook execution failed with status ${response.status}`); + } + + return { + success: response.ok, + status: response.status, + }; }; diff --git a/packages/lib/server-only/webhooks/trigger/handler.ts b/packages/lib/server-only/webhooks/trigger/handler.ts index 55d287bac..3b99cc092 100644 --- a/packages/lib/server-only/webhooks/trigger/handler.ts +++ b/packages/lib/server-only/webhooks/trigger/handler.ts @@ -13,6 +13,7 @@ export type HandlerTriggerWebhooksResponse = error: string; }; +// Todo: [Webhooks] delete after deployment. export const handlerTriggerWebhooks = async (req: Request) => { const signature = req.headers.get('x-webhook-signature'); diff --git a/packages/lib/server-only/webhooks/trigger/trigger-webhook.ts b/packages/lib/server-only/webhooks/trigger/trigger-webhook.ts index 998da6e53..49c18e048 100644 --- a/packages/lib/server-only/webhooks/trigger/trigger-webhook.ts +++ b/packages/lib/server-only/webhooks/trigger/trigger-webhook.ts @@ -1,7 +1,6 @@ import type { WebhookTriggerEvents } from '@prisma/client'; -import { NEXT_PRIVATE_INTERNAL_WEBAPP_URL } from '../../../constants/app'; -import { sign } from '../../crypto/sign'; +import { jobs } from '../../../jobs/client'; import { getAllWebhooksByEventTrigger } from '../get-all-webhooks-by-event-trigger'; export type TriggerWebhookOptions = { @@ -13,35 +12,26 @@ export type TriggerWebhookOptions = { export const triggerWebhook = async ({ event, data, userId, teamId }: TriggerWebhookOptions) => { try { - const body = { - event, - data, - userId, - teamId, - }; - const registeredWebhooks = await getAllWebhooksByEventTrigger({ event, userId, teamId }); if (registeredWebhooks.length === 0) { return; } - const signature = sign(body); - - await Promise.race([ - fetch(`${NEXT_PRIVATE_INTERNAL_WEBAPP_URL()}/api/webhook/trigger`, { - method: 'POST', - headers: { - 'content-type': 'application/json', - 'x-webhook-signature': signature, - }, - body: JSON.stringify(body), + await Promise.allSettled( + registeredWebhooks.map(async (webhook) => { + await jobs.triggerJob({ + name: 'internal.execute-webhook', + payload: { + event, + webhookId: webhook.id, + data, + }, + }); }), - new Promise((_, reject) => { - setTimeout(() => reject(new Error('Request timeout')), 500); - }), - ]).catch(() => null); + ); } catch (err) { + console.error(err); throw new Error(`Failed to trigger webhook`); } }; From 91642ddf0b68213da254210cfcf87cc9b439d31e Mon Sep 17 00:00:00 2001 From: Lucas Smith Date: Tue, 25 Nov 2025 11:44:47 +1100 Subject: [PATCH 3/3] fix: add missing properties for template/use (#2234) Adds the `override` and `attachments` properties to the `api/v2/templates/use` endpoint that were previously missing. --- .../trpc/server/template-router/router.ts | 6 +++- .../trpc/server/template-router/schema.ts | 30 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/packages/trpc/server/template-router/router.ts b/packages/trpc/server/template-router/router.ts index 44a66a349..7e547b157 100644 --- a/packages/trpc/server/template-router/router.ts +++ b/packages/trpc/server/template-router/router.ts @@ -457,8 +457,10 @@ export const templateRouter = router({ recipients, distributeDocument, customDocumentDataId, - prefillFields, folderId, + prefillFields, + override, + attachments, } = input; ctx.logger.info({ @@ -495,6 +497,8 @@ export const templateRouter = router({ requestMetadata: ctx.metadata, folderId, prefillFields, + override, + attachments, }); if (distributeDocument) { diff --git a/packages/trpc/server/template-router/schema.ts b/packages/trpc/server/template-router/schema.ts index b6f4c32de..1ddaf8857 100644 --- a/packages/trpc/server/template-router/schema.ts +++ b/packages/trpc/server/template-router/schema.ts @@ -133,12 +133,42 @@ export const ZCreateDocumentFromTemplateRequestSchema = z.object({ 'The ID of the folder to create the document in. If not provided, the document will be created in the root folder.', ) .optional(), + prefillFields: z .array(ZFieldMetaPrefillFieldsSchema) .describe( 'The fields to prefill on the document before sending it out. Useful when you want to create a document from an existing template and pre-fill the fields with specific values.', ) .optional(), + + override: z + .object({ + title: z.string().min(1).max(255).optional(), + subject: ZDocumentMetaSubjectSchema.optional(), + message: ZDocumentMetaMessageSchema.optional(), + timezone: ZDocumentMetaTimezoneSchema.optional(), + dateFormat: ZDocumentMetaDateFormatSchema.optional(), + redirectUrl: ZDocumentMetaRedirectUrlSchema.optional(), + distributionMethod: ZDocumentMetaDistributionMethodSchema.optional(), + emailSettings: ZDocumentEmailSettingsSchema.optional(), + language: ZDocumentMetaLanguageSchema.optional(), + typedSignatureEnabled: ZDocumentMetaTypedSignatureEnabledSchema.optional(), + uploadSignatureEnabled: ZDocumentMetaUploadSignatureEnabledSchema.optional(), + drawSignatureEnabled: ZDocumentMetaDrawSignatureEnabledSchema.optional(), + allowDictateNextSigner: z.boolean().optional(), + }) + .describe('Override values from the template for the created document.') + .optional(), + + attachments: z + .array( + z.object({ + label: z.string().min(1, 'Label is required'), + data: z.string().url('Must be a valid URL'), + type: ZEnvelopeAttachmentTypeSchema.optional().default('link'), + }), + ) + .optional(), }); export const ZCreateDocumentFromTemplateResponseSchema = ZDocumentSchema;