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/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.
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`);
}
};
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;