From 935076ee2c6a8fed337edde5d2117e193119fae5 Mon Sep 17 00:00:00 2001 From: Pedro Ladeira Date: Fri, 3 Jul 2026 14:02:55 -0300 Subject: [PATCH 1/7] consolidate program resource add/update input schemas --- .../program-resources/add-program-resource.ts | 45 +-------------- .../update-program-resource.ts | 49 +---------------- apps/web/lib/zod/schemas/program-resources.ts | 55 +++++++++++++++++++ 3 files changed, 59 insertions(+), 90 deletions(-) diff --git a/apps/web/lib/actions/partners/program-resources/add-program-resource.ts b/apps/web/lib/actions/partners/program-resources/add-program-resource.ts index 1e0f26c8427..f166dc1dd04 100644 --- a/apps/web/lib/actions/partners/program-resources/add-program-resource.ts +++ b/apps/web/lib/actions/partners/program-resources/add-program-resource.ts @@ -4,59 +4,18 @@ import { createId } from "@/lib/api/create-id"; import { getDefaultProgramIdOrThrow } from "@/lib/api/programs/get-default-program-id-or-throw"; import { prisma } from "@/lib/prisma"; import { + addProgramResourceSchema, programResourceColorSchema, programResourceFileSchema, programResourceLinkSchema, - programResourceLinkUrlSchema, } from "@/lib/zod/schemas/program-resources"; import { R2_URL } from "@dub/utils"; -import * as z from "zod/v4"; import { authActionClient } from "../../safe-action"; import { throwIfNoPermission } from "../../throw-if-no-permission"; import { MAX_PROGRAM_RESOURCE_FILE_SIZE_BYTES } from "./constants"; -// Base schema for all resource types -const baseResourceSchema = z.object({ - workspaceId: z.string(), - name: z.string().min(1, "Name is required"), -}); - -// Schema for logo resources -const logoResourceSchema = baseResourceSchema.extend({ - resourceType: z.literal("logo"), - key: z.string(), - fileSize: z.number().int().positive(), -}); - -// Schema for file resources -const fileResourceSchema = baseResourceSchema.extend({ - resourceType: z.literal("file"), - key: z.string(), - fileSize: z.number().int().positive(), -}); - -// Schema for color resources -const colorResourceSchema = baseResourceSchema.extend({ - resourceType: z.literal("color"), - color: z.string(), // Hex color code -}); - -// Schema for link resources -const linkResourceSchema = baseResourceSchema.extend({ - resourceType: z.literal("link"), - url: programResourceLinkUrlSchema, -}); - -// Combined schema that can handle any resource type -const addResourceSchema = z.discriminatedUnion("resourceType", [ - logoResourceSchema, - fileResourceSchema, - colorResourceSchema, - linkResourceSchema, -]); - export const addProgramResourceAction = authActionClient - .inputSchema(addResourceSchema) + .inputSchema(addProgramResourceSchema) .action(async ({ ctx, parsedInput }) => { const { workspace } = ctx; const { name, resourceType } = parsedInput; diff --git a/apps/web/lib/actions/partners/program-resources/update-program-resource.ts b/apps/web/lib/actions/partners/program-resources/update-program-resource.ts index 885b2b2b66d..41f36b34d5f 100644 --- a/apps/web/lib/actions/partners/program-resources/update-program-resource.ts +++ b/apps/web/lib/actions/partners/program-resources/update-program-resource.ts @@ -7,61 +7,16 @@ import { programResourceColorSchema, programResourceFileSchema, programResourceLinkSchema, - programResourceLinkUrlSchema, programResourcesSchema, + updateProgramResourceSchema, } from "@/lib/zod/schemas/program-resources"; import { R2_URL } from "@dub/utils"; -import * as z from "zod/v4"; import { authActionClient } from "../../safe-action"; import { throwIfNoPermission } from "../../throw-if-no-permission"; import { MAX_PROGRAM_RESOURCE_FILE_SIZE_BYTES } from "./constants"; -// Base schema for all resource types -const baseUpdateSchema = z.object({ - workspaceId: z.string(), - resourceId: z.string(), -}); - -// Schema for logo resources -const updateLogoSchema = baseUpdateSchema.extend({ - resourceType: z.literal("logo"), - name: z.string().min(1).optional(), - key: z.string().optional(), - fileSize: z.number().int().positive().optional(), -}); - -// Schema for file resources -const updateFileSchema = baseUpdateSchema.extend({ - resourceType: z.literal("file"), - name: z.string().min(1).optional(), - key: z.string().optional(), - fileSize: z.number().int().positive().optional(), -}); - -// Schema for color resources -const updateColorSchema = baseUpdateSchema.extend({ - resourceType: z.literal("color"), - name: z.string().min(1).optional(), - color: z.string().optional(), -}); - -// Schema for link resources -const updateLinkSchema = baseUpdateSchema.extend({ - resourceType: z.literal("link"), - name: z.string().min(1).optional(), - url: programResourceLinkUrlSchema.optional(), -}); - -// Combined schema that can handle any resource type -const updateResourceSchema = z.discriminatedUnion("resourceType", [ - updateLogoSchema, - updateFileSchema, - updateColorSchema, - updateLinkSchema, -]); - export const updateProgramResourceAction = authActionClient - .inputSchema(updateResourceSchema) + .inputSchema(updateProgramResourceSchema) .action(async ({ ctx, parsedInput }) => { const { workspace } = ctx; const { resourceId, resourceType } = parsedInput; diff --git a/apps/web/lib/zod/schemas/program-resources.ts b/apps/web/lib/zod/schemas/program-resources.ts index c701f7d2fc7..787bf2135fb 100644 --- a/apps/web/lib/zod/schemas/program-resources.ts +++ b/apps/web/lib/zod/schemas/program-resources.ts @@ -44,3 +44,58 @@ export type ProgramResourceFile = z.infer; export type ProgramResourceColor = z.infer; export type ProgramResourceLink = z.infer; export type ProgramResources = z.infer; + +const baseResourceInputSchema = z.object({ + workspaceId: z.string(), + name: z.string().min(1, "Name is required"), +}); + +// logo and file share the same input fields +const fileResourceInputFields = { + key: z.string(), + fileSize: z.number().int().positive(), +}; + +const logoResourceInputSchema = baseResourceInputSchema.extend({ + resourceType: z.literal("logo"), + ...fileResourceInputFields, +}); +const fileResourceInputSchema = baseResourceInputSchema.extend({ + resourceType: z.literal("file"), + ...fileResourceInputFields, +}); +const colorResourceInputSchema = baseResourceInputSchema.extend({ + resourceType: z.literal("color"), + color: z.string(), +}); +const linkResourceInputSchema = baseResourceInputSchema.extend({ + resourceType: z.literal("link"), + url: programResourceLinkUrlSchema, +}); + +export const addProgramResourceSchema = z.discriminatedUnion("resourceType", [ + logoResourceInputSchema, + fileResourceInputSchema, + colorResourceInputSchema, + linkResourceInputSchema, +]); + +// Update = add variants + resourceId, with mutable fields optional. +// resourceType stays required so the discriminated union still works. +export const updateProgramResourceSchema = z.discriminatedUnion( + "resourceType", + [ + logoResourceInputSchema + .partial({ name: true, key: true, fileSize: true }) + .extend({ resourceId: z.string() }), + fileResourceInputSchema + .partial({ name: true, key: true, fileSize: true }) + .extend({ resourceId: z.string() }), + colorResourceInputSchema + .partial({ name: true, color: true }) + .extend({ resourceId: z.string() }), + linkResourceInputSchema + .partial({ name: true, url: true }) + .extend({ resourceId: z.string() }), + ], +); From 57fd089777e9501ab926c928a6ab5ee523626c24 Mon Sep 17 00:00:00 2001 From: Kiran K Date: Mon, 6 Jul 2026 17:26:04 +0530 Subject: [PATCH 2/7] Consolidate program resource schemas and simplify actions --- .../program-resources/add-program-resource.ts | 6 +----- .../delete-program-resource.ts | 19 +++++-------------- .../update-program-resource.ts | 15 +++++---------- apps/web/lib/zod/schemas/program-resources.ts | 19 +++++++++++-------- 4 files changed, 22 insertions(+), 37 deletions(-) diff --git a/apps/web/lib/actions/partners/program-resources/add-program-resource.ts b/apps/web/lib/actions/partners/program-resources/add-program-resource.ts index f166dc1dd04..9df5b735780 100644 --- a/apps/web/lib/actions/partners/program-resources/add-program-resource.ts +++ b/apps/web/lib/actions/partners/program-resources/add-program-resource.ts @@ -27,11 +27,9 @@ export const addProgramResourceAction = authActionClient const programId = getDefaultProgramIdOrThrow(workspace); - // Verify the program exists and belongs to the workspace - const program = await prisma.program.findUnique({ + const program = await prisma.program.findUniqueOrThrow({ where: { id: programId, - workspaceId: workspace.id, }, select: { id: true, @@ -39,8 +37,6 @@ export const addProgramResourceAction = authActionClient }, }); - if (!program) throw new Error("Program not found"); - const currentResources = (program.resources as any) || { logos: [], colors: [], diff --git a/apps/web/lib/actions/partners/program-resources/delete-program-resource.ts b/apps/web/lib/actions/partners/program-resources/delete-program-resource.ts index 07ce4cebca5..5b646541307 100644 --- a/apps/web/lib/actions/partners/program-resources/delete-program-resource.ts +++ b/apps/web/lib/actions/partners/program-resources/delete-program-resource.ts @@ -4,21 +4,13 @@ import { getDefaultProgramIdOrThrow } from "@/lib/api/programs/get-default-progr import { prisma } from "@/lib/prisma"; import { storage } from "@/lib/storage"; import { - PROGRAM_RESOURCE_TYPES, + deleteProgramResourceSchema, programResourcesSchema, } from "@/lib/zod/schemas/program-resources"; import { R2_URL } from "@dub/utils"; -import * as z from "zod/v4"; import { authActionClient } from "../../safe-action"; import { throwIfNoPermission } from "../../throw-if-no-permission"; -// Schema for deleting a program resource -const deleteProgramResourceSchema = z.object({ - workspaceId: z.string(), - resourceType: z.enum(PROGRAM_RESOURCE_TYPES), - resourceId: z.string(), -}); - export const deleteProgramResourceAction = authActionClient .inputSchema(deleteProgramResourceSchema) .action(async ({ ctx, parsedInput }) => { @@ -32,11 +24,9 @@ export const deleteProgramResourceAction = authActionClient const programId = getDefaultProgramIdOrThrow(workspace); - // Verify the program exists and belongs to the workspace - const program = await prisma.program.findUnique({ + const program = await prisma.program.findUniqueOrThrow({ where: { id: programId, - workspaceId: workspace.id, }, select: { id: true, @@ -44,8 +34,9 @@ export const deleteProgramResourceAction = authActionClient }, }); - if (!program) throw new Error("Program not found"); - if (!program.resources) throw new Error("Program resources not found"); + if (!program.resources) { + throw new Error("Program resources not found"); + } // Create a copy of the current resources to update const updatedResources = { ...(program.resources as any) }; diff --git a/apps/web/lib/actions/partners/program-resources/update-program-resource.ts b/apps/web/lib/actions/partners/program-resources/update-program-resource.ts index 41f36b34d5f..198e42fd804 100644 --- a/apps/web/lib/actions/partners/program-resources/update-program-resource.ts +++ b/apps/web/lib/actions/partners/program-resources/update-program-resource.ts @@ -28,11 +28,9 @@ export const updateProgramResourceAction = authActionClient const programId = getDefaultProgramIdOrThrow(workspace); - // Verify the program exists and belongs to the workspace - const program = await prisma.program.findUnique({ + const program = await prisma.program.findUniqueOrThrow({ where: { id: programId, - workspaceId: workspace.id, }, select: { id: true, @@ -40,8 +38,9 @@ export const updateProgramResourceAction = authActionClient }, }); - if (!program) throw new Error("Program not found"); - if (!program.resources) throw new Error("Program resources not found"); + if (!program.resources) { + throw new Error("Program resources not found."); + } const currentResources = program.resources as any; const updatedResources = { ...currentResources }; @@ -127,7 +126,7 @@ export const updateProgramResourceAction = authActionClient id: program.id, }, data: { - resources: programResourcesSchema.parse(updatedResources) as any, + resources: programResourcesSchema.parse(updatedResources), }, }); @@ -144,8 +143,4 @@ export const updateProgramResourceAction = authActionClient ); } } - - return { - success: true, - }; }); diff --git a/apps/web/lib/zod/schemas/program-resources.ts b/apps/web/lib/zod/schemas/program-resources.ts index 787bf2135fb..3d12a41b340 100644 --- a/apps/web/lib/zod/schemas/program-resources.ts +++ b/apps/web/lib/zod/schemas/program-resources.ts @@ -1,11 +1,6 @@ import * as z from "zod/v4"; -export const PROGRAM_RESOURCE_TYPES = [ - "logo", - "file", - "color", - "link", -] as const; +const PROGRAM_RESOURCE_TYPES = ["logo", "file", "color", "link"] as const; export type ProgramResourceType = (typeof PROGRAM_RESOURCE_TYPES)[number]; @@ -23,7 +18,7 @@ export const programResourceColorSchema = z.object({ }); // Allow http(s) and mailto links, but block dangerous schemes (e.g. javascript:, data:) -export const programResourceLinkUrlSchema = z.url({ +const programResourceLinkUrlSchema = z.url({ protocol: /^(https?|mailto)$/, }); @@ -43,7 +38,6 @@ export const programResourcesSchema = z.object({ export type ProgramResourceFile = z.infer; export type ProgramResourceColor = z.infer; export type ProgramResourceLink = z.infer; -export type ProgramResources = z.infer; const baseResourceInputSchema = z.object({ workspaceId: z.string(), @@ -60,14 +54,17 @@ const logoResourceInputSchema = baseResourceInputSchema.extend({ resourceType: z.literal("logo"), ...fileResourceInputFields, }); + const fileResourceInputSchema = baseResourceInputSchema.extend({ resourceType: z.literal("file"), ...fileResourceInputFields, }); + const colorResourceInputSchema = baseResourceInputSchema.extend({ resourceType: z.literal("color"), color: z.string(), }); + const linkResourceInputSchema = baseResourceInputSchema.extend({ resourceType: z.literal("link"), url: programResourceLinkUrlSchema, @@ -99,3 +96,9 @@ export const updateProgramResourceSchema = z.discriminatedUnion( .extend({ resourceId: z.string() }), ], ); + +export const deleteProgramResourceSchema = z.object({ + workspaceId: z.string(), + resourceType: z.enum(PROGRAM_RESOURCE_TYPES), + resourceId: z.string(), +}); From 39cb7e655c0fd7fd3e410cb961b5f20bb5e28082 Mon Sep 17 00:00:00 2001 From: Kiran K Date: Mon, 6 Jul 2026 17:35:37 +0530 Subject: [PATCH 3/7] format --- .../app/(ee)/api/admin/revenue/get-rolling-payout-fees.ts | 5 ++++- apps/web/lib/partners/get-partner-bank-account.ts | 6 +++--- apps/web/lib/webhook/failure.ts | 2 +- apps/web/lib/webhook/transform.ts | 2 +- apps/web/ui/messages/messages-panel.tsx | 7 ++++++- apps/web/ui/modals/send-test-webhook-modal.tsx | 2 +- apps/web/ui/webhooks/folder-selector.tsx | 4 +--- 7 files changed, 17 insertions(+), 11 deletions(-) diff --git a/apps/web/app/(ee)/api/admin/revenue/get-rolling-payout-fees.ts b/apps/web/app/(ee)/api/admin/revenue/get-rolling-payout-fees.ts index 336a6f4e719..d470d13cdcf 100644 --- a/apps/web/app/(ee)/api/admin/revenue/get-rolling-payout-fees.ts +++ b/apps/web/app/(ee)/api/admin/revenue/get-rolling-payout-fees.ts @@ -13,7 +13,10 @@ export function computeRollingAveragePayoutFees( for (let i = 0; i < timeseries.length; i++) { const windowStart = subMonths(timeseries[i].date, windowMonths); - while (windowStartIdx < i && timeseries[windowStartIdx].date < windowStart) { + while ( + windowStartIdx < i && + timeseries[windowStartIdx].date < windowStart + ) { windowSum -= timeseries[windowStartIdx].fees; windowStartIdx++; } diff --git a/apps/web/lib/partners/get-partner-bank-account.ts b/apps/web/lib/partners/get-partner-bank-account.ts index b134d0c7d7a..52da8177824 100644 --- a/apps/web/lib/partners/get-partner-bank-account.ts +++ b/apps/web/lib/partners/get-partner-bank-account.ts @@ -1,6 +1,4 @@ -import { prisma } from "@/lib/prisma"; import { stripe } from "@/lib/stripe"; -import { waitUntil } from "@vercel/functions"; import Stripe from "stripe"; import * as z from "zod/v4"; @@ -41,7 +39,9 @@ export const getPartnerBankAccount = async (stripeAccount: string) => { if (isApplicationAccessRevoked) { // TODO: recompute payout state + reset payoutsEnabledAt / payoutMethodHash if needed - console.warn("No account connected – application access may have been revoked.") + console.warn( + "No account connected – application access may have been revoked.", + ); } return null; diff --git a/apps/web/lib/webhook/failure.ts b/apps/web/lib/webhook/failure.ts index feb4a88faa7..e398a8e5f3c 100644 --- a/apps/web/lib/webhook/failure.ts +++ b/apps/web/lib/webhook/failure.ts @@ -3,11 +3,11 @@ import { sendEmail } from "@dub/email"; import WebhookDisabled from "@dub/email/templates/webhook-disabled"; import WebhookFailed from "@dub/email/templates/webhook-failed"; import { Webhook } from "@prisma/client"; +import { syncWorkspaceWebhookStatus } from "./click-webhook-workspaces"; import { WEBHOOK_FAILURE_DISABLE_THRESHOLD, WEBHOOK_FAILURE_NOTIFY_THRESHOLDS, } from "./constants"; -import { syncWorkspaceWebhookStatus } from "./click-webhook-workspaces"; export const handleWebhookFailure = async (webhookId: string) => { const webhook = await prisma.webhook.update({ diff --git a/apps/web/lib/webhook/transform.ts b/apps/web/lib/webhook/transform.ts index 55e75ec44b4..8b66d9b5a7d 100644 --- a/apps/web/lib/webhook/transform.ts +++ b/apps/web/lib/webhook/transform.ts @@ -6,10 +6,10 @@ import { nanoid, toCamelCase } from "@dub/utils"; import { ExpandedLink, transformLink } from "../api/links/utils/transform-link"; import { generateRandomName } from "../names"; import { ClickEventTB } from "../types"; -import type { WebhookTrigger } from "./types"; import { clickEventSchema } from "../zod/schemas/clicks"; import { WEBHOOK_EVENT_ID_PREFIX } from "./constants"; import { leadWebhookEventSchema, saleWebhookEventSchema } from "./schemas"; +import type { WebhookTrigger } from "./types"; export const transformClickEventData = ( data: ClickEventTB & { diff --git a/apps/web/ui/messages/messages-panel.tsx b/apps/web/ui/messages/messages-panel.tsx index cf209c04ebd..58adce41b6f 100644 --- a/apps/web/ui/messages/messages-panel.tsx +++ b/apps/web/ui/messages/messages-panel.tsx @@ -1,4 +1,9 @@ -import { Message, MessageAttachment, PartnerProps, ProgramProps } from "@/lib/types"; +import { + Message, + MessageAttachment, + PartnerProps, + ProgramProps, +} from "@/lib/types"; import { AnimatedSizeContainer, Check2, diff --git a/apps/web/ui/modals/send-test-webhook-modal.tsx b/apps/web/ui/modals/send-test-webhook-modal.tsx index b8281e25f32..cec9ee9f239 100644 --- a/apps/web/ui/modals/send-test-webhook-modal.tsx +++ b/apps/web/ui/modals/send-test-webhook-modal.tsx @@ -1,8 +1,8 @@ import { sendTestWebhookEvent } from "@/lib/actions/send-test-webhook"; import useWorkspace from "@/lib/swr/use-workspace"; import { WebhookProps } from "@/lib/types"; -import type { WebhookTrigger } from "@/lib/webhook/types"; import { WEBHOOK_TRIGGER_DESCRIPTIONS } from "@/lib/webhook/constants"; +import type { WebhookTrigger } from "@/lib/webhook/types"; import { Button, Combobox, ComboboxOption, Modal } from "@dub/ui"; import { useAction } from "next-safe-action/hooks"; import { diff --git a/apps/web/ui/webhooks/folder-selector.tsx b/apps/web/ui/webhooks/folder-selector.tsx index 3a0f99da62f..f9a23050811 100644 --- a/apps/web/ui/webhooks/folder-selector.tsx +++ b/apps/web/ui/webhooks/folder-selector.tsx @@ -13,9 +13,7 @@ const MAX_DISPLAYED_FOLDERS = 10; const getFolderOption = (folder: Folder) => ({ value: folder.id, label: folder.name, - icon: ( - - ), + icon: , meta: { folder, }, From 478a299e0d148c5366d6a0ad50cd498890a7f292 Mon Sep 17 00:00:00 2001 From: Steven Tey Date: Mon, 6 Jul 2026 09:25:43 -0700 Subject: [PATCH 4/7] small improvements to billing page --- .../(dashboard)/[slug]/(ee)/settings/billing/page.tsx | 2 +- .../[slug]/(ee)/settings/billing/payment-methods.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/page.tsx b/apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/page.tsx index 229620c6f9f..f33d7475566 100644 --- a/apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/page.tsx +++ b/apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/page.tsx @@ -6,7 +6,7 @@ import PlanUsage from "./plan-usage"; export default function WorkspaceBilling() { return ( - + diff --git a/apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/payment-methods.tsx b/apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/payment-methods.tsx index 71c3fedb630..b680213c255 100644 --- a/apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/payment-methods.tsx +++ b/apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/payment-methods.tsx @@ -32,7 +32,7 @@ export default function PaymentMethods() { const router = useRouter(); const { paymentMethods, defaultPaymentMethodId } = usePaymentMethods(); const [isLoading, setIsLoading] = useState(false); - const { slug, stripeId, plan, role } = useWorkspace(); + const { slug, stripeId, role } = useWorkspace(); const regularPaymentMethods = paymentMethods?.filter( (pm) => !DIRECT_DEBIT_PAYMENT_METHOD_TYPES.includes(pm.type), @@ -55,7 +55,7 @@ export default function PaymentMethods() { router.push(url); }; - if (plan === "free") { + if (!stripeId) { return null; } From b5fe97da60e0f94b835fb45ef4f9f74948f94978 Mon Sep 17 00:00:00 2001 From: Kiran K Date: Mon, 6 Jul 2026 22:26:03 +0530 Subject: [PATCH 5/7] Fix nullable link date fields coercing to epoch in webhooks --- apps/web/lib/webhook/sample-events/link-clicked.json | 2 +- apps/web/lib/zod/schemas/links.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/web/lib/webhook/sample-events/link-clicked.json b/apps/web/lib/webhook/sample-events/link-clicked.json index bf82f2ecfa1..3cb74a4c127 100644 --- a/apps/web/lib/webhook/sample-events/link-clicked.json +++ b/apps/web/lib/webhook/sample-events/link-clicked.json @@ -27,7 +27,7 @@ "partnerId": "pn_cm0lcuvtz000xcutmqw4a7wi3", "programId": "prog_CYCu7IMAapjkRpTnr8F1azjN", "archived": false, - "expiresAt": "1970-01-01T00:00:00.000Z", + "expiresAt": null, "expiredUrl": null, "disabledAt": null, "password": null, diff --git a/apps/web/lib/zod/schemas/links.ts b/apps/web/lib/zod/schemas/links.ts index 467394de13b..ef8fc557477 100644 --- a/apps/web/lib/zod/schemas/links.ts +++ b/apps/web/lib/zod/schemas/links.ts @@ -861,11 +861,11 @@ export const linkEventSchema = LinkSchema.extend({ // coerce date fields createdAt: z.coerce.date(), updatedAt: z.coerce.date(), - lastClicked: z.coerce.date(), - expiresAt: z.coerce.date(), - disabledAt: z.coerce.date(), - testCompletedAt: z.coerce.date(), - testStartedAt: z.coerce.date(), + lastClicked: z.coerce.date().nullable(), + expiresAt: z.coerce.date().nullable(), + disabledAt: z.coerce.date().nullable(), + testCompletedAt: z.coerce.date().nullable(), + testStartedAt: z.coerce.date().nullable(), // userId can be null userId: z.string().nullable(), }); From f00c309b9bf40dd9998d40a27671e56c0a9678f6 Mon Sep 17 00:00:00 2001 From: Kiran K Date: Mon, 6 Jul 2026 22:28:18 +0530 Subject: [PATCH 6/7] Update lead-created.json --- apps/web/lib/webhook/sample-events/lead-created.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/lib/webhook/sample-events/lead-created.json b/apps/web/lib/webhook/sample-events/lead-created.json index ca8c14da7c8..f832117216d 100644 --- a/apps/web/lib/webhook/sample-events/lead-created.json +++ b/apps/web/lib/webhook/sample-events/lead-created.json @@ -36,7 +36,7 @@ "partnerId": "pn_cm0lcuvtz000xcutmqw4a7wi3", "programId": "prog_CYCu7IMAapjkRpTnr8F1azjN", "archived": false, - "expiresAt": "1970-01-01T00:00:00.000Z", + "expiresAt": null, "expiredUrl": null, "disabledAt": null, "password": null, From fda939a2fb21f3895dc26232345445984c8ac49e Mon Sep 17 00:00:00 2001 From: Kiran K Date: Mon, 6 Jul 2026 22:28:20 +0530 Subject: [PATCH 7/7] Update sale-created.json --- apps/web/lib/webhook/sample-events/sale-created.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/lib/webhook/sample-events/sale-created.json b/apps/web/lib/webhook/sample-events/sale-created.json index fddf43098dd..26f4d074606 100644 --- a/apps/web/lib/webhook/sample-events/sale-created.json +++ b/apps/web/lib/webhook/sample-events/sale-created.json @@ -36,7 +36,7 @@ "partnerId": "pn_cm0lcuvtz000xcutmqw4a7wi3", "programId": "prog_CYCu7IMAapjkRpTnr8F1azjN", "archived": false, - "expiresAt": "1970-01-01T00:00:00.000Z", + "expiresAt": null, "expiredUrl": null, "disabledAt": null, "password": null,