-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Zod v4 #3301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Zod v4 #3301
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedToo many files! 130 files out of 280 files are above the max files limit of 150. You can disable this status message by setting the 📝 WalkthroughWalkthroughStandardized Zod usage and metadata across the codebase: removed the local Zod wrapper, switched many imports to the official "zod" package, replaced .openapi(...) with .meta(...), migrated numerous schema compositions from .merge(...) to .extend(...).shape (or .extend(...)), updated validator shorthands, and added related dependency upgrades. Changes
Sequence Diagram(s)(omitted) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 25
Note
Due to the large number of review comments, Critical severity comments were prioritized as inline comments.
♻️ Duplicate comments (10)
apps/web/lib/zod/schemas/leads.ts (1)
151-151: Verify.meta()method availability.Same concern as Line 22 - please ensure the
.meta()method is available in thezod-openapipackage version being used.apps/web/lib/actions/partners/revoke-program-invite.ts (1)
10-10: Verify the import syntax for Zod v4.Same concern as in check-account-exists.ts: ensure that
import z from "zod"works correctly with Zod v4.2.1. The standard pattern isimport { z } from "zod".apps/web/lib/actions/verify-workspace-setup.ts (1)
5-5: Verify the import syntax for Zod v4.Same import syntax concern: ensure
import z from "zod"works with Zod v4.2.1. Standard pattern isimport { z } from "zod".apps/web/lib/zod/schemas/customers.ts (1)
1-1: Verify the import syntax for Zod v4.Same import syntax concern: standard Zod pattern is
import { z } from "zod"rather than a default import. This is especially important for this schema file as it's likely imported by many other modules.apps/web/lib/actions/partners/update-partner-profile.ts (1)
24-24: Verify the import syntax for Zod v4.Same import syntax concern: ensure
import z from "zod"is valid for Zod v4.2.1. The standard pattern isimport { z } from "zod".apps/web/lib/zod/schemas/auth.ts (1)
1-1: Verify the import syntax.Same concern as in
apps/web/lib/openapi/folders/list-folders.ts- the import uses default import syntax which may not be correct for Zod v4.apps/web/lib/openapi/links/get-links.ts (1)
3-3: Verify the import syntax.Same import syntax concern as flagged in
apps/web/lib/openapi/folders/list-folders.ts.apps/web/lib/actions/send-test-webhook.ts (1)
4-4: Verify the import syntax.Same import syntax concern as flagged in other files.
apps/web/lib/openapi/links/bulk-create-links.ts (1)
7-7: Verify consistent import pattern.Same as bulk-delete-links.ts - ensure zod imports are consistent across the codebase.
apps/web/lib/openapi/analytics/index.ts (1)
4-4: Verify the import syntax for Zod.Same issue as in
apps/web/lib/zod/schemas/folders.ts- the import uses default import syntax instead of the conventional named import pattern. Please see the verification comment in that file.
🟠 Major comments (5)
apps/web/app/(ee)/api/programs/[programId]/applications/export/route.ts-19-20 (1)
19-20: Empty string input will produce invalid column IDs.In Zod 4,
.default()only replacesundefinedvalues, not empty strings. When thecolumnsquery parameter is an empty string (e.g.,?columns=), the current implementation will:
- Skip the
.default()(since the value is"", notundefined)- Transform
"".split(",")→[""]- Pass an array with one empty string element to downstream logic
This causes issues at:
- Line 59:
columnOrderMap[""]isundefined, assigning priority 999- Line 64:
schemaFields[columnIdToLabel[""]]creates a property with key"undefined"- Lines 72, 76:
result[columnIdToLabel[""]]sets anundefinedproperty on the result objectThis breaks CSV generation with malformed data.
🔎 Proposed fix to handle empty strings
const applicationsExportQuerySchema = z.object({ columns: z .string() .default(exportApplicationsColumnsDefault.join(",")) - .transform((v) => v?.split(",")), + .transform((v) => (v === "" ? exportApplicationsColumnsDefault.join(",") : v).split(",")), });Alternatively, to maintain the previous optional behavior with Zod 4:
const applicationsExportQuerySchema = z.object({ columns: z .string() + .optional() .default(exportApplicationsColumnsDefault.join(",")) - .transform((v) => v?.split(",")), + .transform((v) => v.split(",")), });apps/web/scripts/framer/1-process-framer-combined.ts-5-5 (1)
5-5: Fix the Zod import syntax.The import uses default import syntax (
import z from "zod"), but Zod v4 exportszas a named export. The correct import pattern isimport { z } from "zod".Suggested fix
-import z from "zod"; +import { z } from "zod";apps/web/lib/swr/use-customers-count.ts-4-4 (1)
4-4: Fix incorrect Zod import syntax.Change
import z from "zod"to a named import. Per project guidelines, all standard Zod imports should useimport { z } from "zod". This pattern affects 89+ files across the codebase and should be fixed systematically.🔎 Fix the import statement
-import z from "zod"; +import { z } from "zod";apps/web/lib/zod/schemas/analytics.ts-21-29 (1)
21-29: Use theerrorparameter inz.enum()to customize error messages for Zod v4.The current pattern of chaining
.refine()after.enum()is not the recommended approach in Zod v4 for customizing enum error messages. Instead, pass anerroroption directly to the enum constructor:const analyticsEvents = z.enum([...EVENT_TYPES, "composite"], { error: () => "Invalid event type. Valid event types are: clicks, leads, sales", }).default("clicks").describe( "The type of event to retrieve analytics for. Defaults to `clicks`.", );Alternatively, use
superRefine()if you need per-value logic. The.refine()after.enum()is redundant since the enum already validates the value.apps/web/lib/zod/schemas/oauth.ts-102-104 (1)
102-104: Fix error callback return format for Zod v4 compatibility.The error callback in
discriminatedUnionis returning an object with amessageproperty, which is the v3 errorMap format. In Zod v4, the error callback should return a string directly, not an object.Fix
export const tokenGrantSchema = z.discriminatedUnion( "grant_type", [authCodeExchangeSchema, refreshTokenSchema], { - error: () => ({ - message: "grant_type must be 'authorization_code' or 'refresh_token'", - }), + error: () => "grant_type must be 'authorization_code' or 'refresh_token'", }, );
🟡 Minor comments (10)
apps/web/lib/openapi/tags/delete-tag.ts-2-2 (1)
2-2: Use named import syntax for Zod.According to codebase conventions, standard
zodimports should use named import syntax instead of default import:import { z } from "zod";rather thanimport z from "zod";. While both syntaxes work, the named import is the preferred style.🔎 Fix the import syntax
-import z from "zod"; +import { z } from "zod";apps/web/lib/swr/use-workspace-preferences.ts-1-1 (1)
1-1: Remove@ts-nocheckand fix the underlying Zod import issue.The import at line 12 (
../zod/schemas/workspace-preferences) is valid and properly structured. However, the@ts-nocheckdirective is likely suppressing type errors that originate from a Zod v4 compatibility issue in the relatedupdate-workspace-preferences.tsfile.The actual issue:
update-workspace-preferences.ts(line 4) usesimport z from "zod", which is an incorrect default import. Zod v4 only exports named exports, so this should beimport { z } from "zod". This cascades into type errors whenupdateWorkspacePreferencesis imported and used in this file.Fix the zod import in
update-workspace-preferences.tsto resolve the root cause instead of suppressing errors with@ts-nocheck.apps/web/lib/ai/generate-filters.ts-9-9 (1)
9-9: Use named import for Zod.Change the default import to the named import pattern used throughout this codebase and per the project's standards:
Suggested fix
-import z from "zod"; +import { z } from "zod";This import is inconsistent with the rest of the codebase (e.g.,
generate-csv-mapping.tsline 6) and the project guideline for standard Zod usage.apps/web/lib/actions/update-workspace-preferences.ts-4-4 (1)
4-4: Align with project import convention for Zod.This file uses a default import pattern for Zod, but the project standardly uses named imports. Change to
import { z } from "zod";to match project convention.🔎 Proposed fix
-import z from "zod"; +import { z } from "zod";apps/web/lib/openapi/customers/get-customers.ts-2-2 (1)
2-2: Use named import syntax for zod.Change
import z from "zod";toimport { z } from "zod";. The zod package exportszas a named export, and this is the standard pattern used throughout the codebase.Proposed fix
-import z from "zod"; +import { z } from "zod";apps/web/lib/zod/schemas/misc.ts-35-42 (1)
35-42: Use theerrorparameter consistently across all validators for Zod v4 compatibility.The code uses the new
errorparameter forz.coerce.number()(lines 35, 44), which correctly accepts string values in Zod v4. However, it mixes in the deprecatedmessageparameter for.positive()(lines 36, 45) and.max()(line 47). For consistency with the v4 unified error handling approach, these should also useerror:Suggested fix
page: z.coerce .number({ error: "Page must be a number." }) .positive({ error: "Page must be greater than 0." }) .optional() .default(1) .describe("The page number for pagination.") .meta({ example: 1, }), pageSize: z.coerce .number({ error: "Page size must be a number." }) .positive({ error: "Page size must be greater than 0." }) .max(pageSize, { error: `Max page size is ${pageSize}.`, }) .optional() .default(pageSize) .describe("The number of items per page.") .meta({ example: 50, }),apps/web/lib/actions/check-account-exists.ts-6-6 (1)
6-6: Change the import syntax to use a named import instead of default import.The Zod library exports
zas a named export, not a default export. Line 6 should beimport { z } from "zod"instead ofimport z from "zod". Additionally, since this file uses only standard Zod validation (no OpenAPI-specific features), it should import directly from thezodpackage rather than@/lib/zod.apps/web/lib/openapi/links/bulk-delete-links.ts-2-2 (1)
2-2: Change import to use named import syntax.Line 2 should use
import { z } from "zod"instead of the default importimport z from "zod". The zod package exports a named export, not a default export.Recommended change:
-import z from "zod"; +import { z } from "zod";apps/web/lib/webhook/schemas.ts-31-31 (1)
31-31: Consider usingz.unknown()instead ofz.any()for metadata value validation to maintain type safety.While the change to
z.record(z.string(), z.any())correctly implements Zod v4's requirement to explicitly specify both key and value schemas, usingz.any()for the value type bypasses all type checking. Sincez.unknown()is also valid in Zod v4 and requires consumers to validate data before use, it would provide better type safety for the metadata field without sacrificing Zod v4 compatibility.Applies to lines 31 and 41.
apps/web/lib/zod/schemas/folders.ts-7-7 (1)
7-7: Change the import to use named export syntax.The codebase predominantly uses
import { z } from "zod"(found in 600+ files), with only a small subset using the default import pattern. All sibling files inapps/web/lib/zod/schemas/consistently use the named import. Zod exportszas a named export, makingimport { z } from "zod"the correct syntax.
🧹 Nitpick comments (6)
apps/web/lib/swr/use-links-count.ts (1)
4-4: Prefer named import for consistency with Zod conventions.The default import works but the idiomatic Zod pattern is to use a named import.
🔎 Suggested change
-import z from "zod"; +import { z } from "zod";apps/web/scripts/migrations/backfill-link-commissions.ts (1)
34-37: Consider removing the type assertion for consistency.While the explicit
undefinedvalues for optional parameters are acceptable, the type assertion on line 37 (as SaleEvent[]) is inconsistent with the safer approach taken inbackfill-missing-sales.ts(lines 49-72), where the type assertion was removed and defensive runtime checks were added instead.For consistency and type safety, consider either:
- Removing the type assertion and relying on TypeScript's inference, or
- Adding defensive runtime checks similar to those in
backfill-missing-sales.ts(lines 69-72)Option 1: Remove type assertion
- })) as SaleEvent[]; + }));Note: This assumes the return type of
getEventsis correctly inferred whenevent: "sales"is passed.apps/web/lib/zod/schemas/links.ts (1)
3-3: Use named import for Zod.The import should use the named export syntax for consistency with Zod's documentation and ecosystem standards.
🔎 Proposed fix
-import z from "zod"; +import { z } from "zod";Based on learnings, the standard pattern is
import { z } from "zod".apps/web/lib/tinybird/get-import-error-logs.ts (1)
1-1: Import path updated correctly.The change from the local Zod wrapper to the external "zod" package is correct. This file doesn't use OpenAPI extensions, so direct import from "zod" is appropriate per project conventions.
Optional: Consider named import syntax.
The codebase uses
import z from "zod"(default import). While this works, the more conventional pattern isimport { z } from "zod"(named import). If this is intentional across the project, no action needed.apps/web/lib/zod/schemas/sales.ts (1)
1-1: Consider using named import for consistency.This file uses the default import
import z from "zod", while other files in this PR (e.g.,oauth.ts,oauth-provider.ts) use the named importimport { z } from "zod". Both work in Zod v4, but using a consistent import style across the codebase improves maintainability.🔎 Suggested fix
-import z from "zod"; +import { z } from "zod";apps/web/lib/zod/schemas/analytics-response.ts (1)
3-3: Consider using named import for consistency.Same as
sales.ts- this file uses the default import while other files use named imports. Consider aligning with the named import styleimport { z } from "zod"for consistency.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (122)
apps/web/app/(ee)/api/admin/commissions/route.tsapps/web/app/(ee)/api/admin/payouts/route.tsapps/web/app/(ee)/api/campaigns/[campaignId]/preview/route.tsapps/web/app/(ee)/api/cron/send-batch-email/route.tsapps/web/app/(ee)/api/embed/referrals/leaderboard/route.tsapps/web/app/(ee)/api/programs/[programId]/applications/export/route.tsapps/web/app/(ee)/api/track/click/route.tsapps/web/app/api/ai/completion/route.tsapps/web/app/api/workspaces/[idOrSlug]/users/route.tsapps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/analytics/page-client.tsxapps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/add-edit-bounty-sheet.tsxapps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/confirm-create-bounty-modal.tsxapps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/payout-stats.tsxapps/web/lib/actions/add-edit-integration.tsapps/web/lib/actions/check-account-exists.tsapps/web/lib/actions/create-user-account.tsapps/web/lib/actions/enable-disable-webhook.tsapps/web/lib/actions/generate-client-secret.tsapps/web/lib/actions/get-integration-install-url.tsapps/web/lib/actions/partners/create-program-application.tsapps/web/lib/actions/partners/delete-program-invite.tsapps/web/lib/actions/partners/resend-program-invite.tsapps/web/lib/actions/partners/revoke-program-invite.tsapps/web/lib/actions/partners/update-online-presence.tsapps/web/lib/actions/partners/update-partner-notification-preference.tsapps/web/lib/actions/partners/update-partner-profile.tsapps/web/lib/actions/send-otp.tsapps/web/lib/actions/send-test-webhook.tsapps/web/lib/actions/submit-oauth-app-for-review.tsapps/web/lib/actions/update-workspace-notification-preference.tsapps/web/lib/actions/update-workspace-preferences.tsapps/web/lib/actions/update-workspace-store.tsapps/web/lib/actions/verify-workspace-setup.tsapps/web/lib/ai/generate-csv-mapping.tsapps/web/lib/ai/generate-filters.tsapps/web/lib/analytics/get-analytics.tsapps/web/lib/analytics/get-events.tsapps/web/lib/analytics/types.tsapps/web/lib/api/errors.tsapps/web/lib/api/sales/construct-reward-amount.tsapps/web/lib/firstpromoter/schemas.tsapps/web/lib/integrations/hubspot/oauth.tsapps/web/lib/integrations/oauth-provider.tsapps/web/lib/integrations/slack/oauth.tsapps/web/lib/openapi/analytics/index.tsapps/web/lib/openapi/customers/get-customers.tsapps/web/lib/openapi/domains/check-domain-status.tsapps/web/lib/openapi/domains/list-domains.tsapps/web/lib/openapi/events/index.tsapps/web/lib/openapi/folders/delete-folder.tsapps/web/lib/openapi/folders/list-folders.tsapps/web/lib/openapi/folders/update-folder.tsapps/web/lib/openapi/index.tsapps/web/lib/openapi/links/bulk-create-links.tsapps/web/lib/openapi/links/bulk-delete-links.tsapps/web/lib/openapi/links/bulk-update-links.tsapps/web/lib/openapi/links/delete-link.tsapps/web/lib/openapi/links/get-links-count.tsapps/web/lib/openapi/links/get-links.tsapps/web/lib/openapi/links/update-link.tsapps/web/lib/openapi/partners/list-partners.tsapps/web/lib/openapi/partners/retrieve-analytics.tsapps/web/lib/openapi/qr/index.tsapps/web/lib/openapi/tags/delete-tag.tsapps/web/lib/openapi/tags/get-tags.tsapps/web/lib/openapi/tags/update-tag.tsapps/web/lib/openapi/workspaces/get-workspace-info.tsapps/web/lib/openapi/workspaces/index.tsapps/web/lib/openapi/workspaces/update-workspace.tsapps/web/lib/partners/cutoff-period.tsapps/web/lib/paypal/oauth.tsapps/web/lib/swr/use-customers-count.tsapps/web/lib/swr/use-links-count.tsapps/web/lib/swr/use-workspace-preferences.tsapps/web/lib/tinybird/get-click-event.tsapps/web/lib/tinybird/get-import-error-logs.tsapps/web/lib/tinybird/get-lead-event.tsapps/web/lib/tinybird/get-lead-events.tsapps/web/lib/tinybird/get-webhook-events.tsapps/web/lib/tinybird/record-sale.tsapps/web/lib/webhook/qstash.tsapps/web/lib/webhook/schemas.tsapps/web/lib/webhook/types.tsapps/web/lib/zod/index.tsapps/web/lib/zod/schemas/analytics-response.tsapps/web/lib/zod/schemas/analytics.tsapps/web/lib/zod/schemas/auth.tsapps/web/lib/zod/schemas/bounties.tsapps/web/lib/zod/schemas/clicks.tsapps/web/lib/zod/schemas/commissions.tsapps/web/lib/zod/schemas/customers.tsapps/web/lib/zod/schemas/deep-links.tsapps/web/lib/zod/schemas/deprecated.tsapps/web/lib/zod/schemas/domains.tsapps/web/lib/zod/schemas/email-domains.tsapps/web/lib/zod/schemas/folders.tsapps/web/lib/zod/schemas/invoices.tsapps/web/lib/zod/schemas/leads.tsapps/web/lib/zod/schemas/links.tsapps/web/lib/zod/schemas/misc.tsapps/web/lib/zod/schemas/oauth.tsapps/web/lib/zod/schemas/opens.tsapps/web/lib/zod/schemas/partners.tsapps/web/lib/zod/schemas/payouts.tsapps/web/lib/zod/schemas/qr.tsapps/web/lib/zod/schemas/sales.tsapps/web/lib/zod/schemas/tags.tsapps/web/lib/zod/schemas/token.tsapps/web/lib/zod/schemas/usage.tsapps/web/lib/zod/schemas/utils.tsapps/web/lib/zod/schemas/utm.tsapps/web/lib/zod/schemas/workspaces.tsapps/web/package.jsonapps/web/scripts/framer/1-process-framer-combined.tsapps/web/scripts/migrations/backfill-customers.tsapps/web/scripts/migrations/backfill-link-commissions.tsapps/web/scripts/migrations/backfill-missing-sales.tsapps/web/ui/analytics/use-analytics-filters.tsxapps/web/ui/links/link-builder/tag-select.tsxapps/web/ui/links/short-link-input.tsxapps/web/ui/modals/import-csv-modal/field-mapping.tsxapps/web/ui/modals/link-builder/og-modal.tsx
💤 Files with no reviewable changes (2)
- apps/web/lib/openapi/workspaces/index.ts
- apps/web/lib/zod/index.ts
🧰 Additional context used
🧠 Learnings (40)
📓 Common learnings
Learnt from: devkiran
Repo: dubinc/dub PR: 0
File: :0-0
Timestamp: 2025-10-17T08:18:19.278Z
Learning: In the apps/web codebase, `@/lib/zod` should only be used for places that need OpenAPI extended zod schema. All other places should import from the standard `zod` package directly using `import { z } from "zod"`.
📚 Learning: 2025-10-15T01:05:43.266Z
Learnt from: steven-tey
Repo: dubinc/dub PR: 2958
File: apps/web/app/app.dub.co/(dashboard)/[slug]/settings/members/page-client.tsx:432-457
Timestamp: 2025-10-15T01:05:43.266Z
Learning: In apps/web/app/app.dub.co/(dashboard)/[slug]/settings/members/page-client.tsx, defer refactoring the custom MenuItem component (lines 432-457) to use the shared dub/ui MenuItem component to a future PR, as requested by steven-tey.
Applied to files:
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/add-edit-bounty-sheet.tsxapps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/confirm-create-bounty-modal.tsxapps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/payout-stats.tsxapps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/analytics/page-client.tsx
📚 Learning: 2025-09-12T17:31:10.548Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2833
File: apps/web/lib/actions/partners/approve-bounty-submission.ts:53-61
Timestamp: 2025-09-12T17:31:10.548Z
Learning: In approve-bounty-submission.ts, the logic `bounty.rewardAmount ?? rewardAmount` is intentional. Bounties with preset reward amounts should use those fixed amounts, and the rewardAmount override parameter is only used when bounty.rewardAmount is null/undefined (for custom reward bounties). This follows the design pattern where bounties are either "flat rate" (fixed amount) or "custom" (variable amount set during approval).
Applied to files:
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/add-edit-bounty-sheet.tsxapps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/confirm-create-bounty-modal.tsxapps/web/lib/api/sales/construct-reward-amount.tsapps/web/lib/zod/schemas/bounties.ts
📚 Learning: 2025-07-30T15:29:54.131Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2673
File: apps/web/ui/partners/rewards/rewards-logic.tsx:268-275
Timestamp: 2025-07-30T15:29:54.131Z
Learning: In apps/web/ui/partners/rewards/rewards-logic.tsx, when setting the entity field in a reward condition, dependent fields (attribute, operator, value) should be reset rather than preserved because different entities (customer vs sale) have different available attributes. Maintaining existing fields when the entity changes would create invalid state combinations and confusing UX.
Applied to files:
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/add-edit-bounty-sheet.tsxapps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/confirm-create-bounty-modal.tsxapps/web/lib/api/sales/construct-reward-amount.ts
📚 Learning: 2025-07-30T15:25:13.936Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2673
File: apps/web/ui/partners/rewards/add-edit-reward-sheet.tsx:56-66
Timestamp: 2025-07-30T15:25:13.936Z
Learning: In apps/web/ui/partners/rewards/add-edit-reward-sheet.tsx, the form schema uses partial condition objects to allow users to add empty/unconfigured condition fields without type errors, while submission validation uses strict schemas to ensure data integrity. This two-stage validation pattern improves UX by allowing progressive completion of complex forms.
Applied to files:
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/add-edit-bounty-sheet.tsx
📚 Learning: 2025-08-26T14:32:33.851Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2736
File: apps/web/lib/actions/partners/create-bounty-submission.ts:105-112
Timestamp: 2025-08-26T14:32:33.851Z
Learning: Non-performance bounties are required to have submissionRequirements. In create-bounty-submission.ts, it's appropriate to let the parsing fail if submissionRequirements is null for non-performance bounties, as this indicates a data integrity issue that should be caught.
Applied to files:
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/add-edit-bounty-sheet.tsxapps/web/lib/zod/schemas/bounties.ts
📚 Learning: 2025-10-17T08:18:19.278Z
Learnt from: devkiran
Repo: dubinc/dub PR: 0
File: :0-0
Timestamp: 2025-10-17T08:18:19.278Z
Learning: In the apps/web codebase, `@/lib/zod` should only be used for places that need OpenAPI extended zod schema. All other places should import from the standard `zod` package directly using `import { z } from "zod"`.
Applied to files:
apps/web/lib/actions/partners/delete-program-invite.tsapps/web/lib/tinybird/get-click-event.tsapps/web/lib/actions/partners/update-partner-profile.tsapps/web/lib/zod/schemas/invoices.tsapps/web/scripts/framer/1-process-framer-combined.tsapps/web/lib/openapi/links/bulk-create-links.tsapps/web/lib/analytics/get-events.tsapps/web/lib/tinybird/get-lead-events.tsapps/web/lib/tinybird/get-import-error-logs.tsapps/web/lib/openapi/folders/update-folder.tsapps/web/lib/actions/update-workspace-preferences.tsapps/web/lib/actions/add-edit-integration.tsapps/web/lib/openapi/qr/index.tsapps/web/lib/openapi/folders/delete-folder.tsapps/web/lib/actions/create-user-account.tsapps/web/lib/openapi/domains/check-domain-status.tsapps/web/lib/zod/schemas/opens.tsapps/web/lib/actions/partners/create-program-application.tsapps/web/lib/openapi/analytics/index.tsapps/web/lib/zod/schemas/clicks.tsapps/web/lib/openapi/domains/list-domains.tsapps/web/lib/actions/generate-client-secret.tsapps/web/lib/integrations/oauth-provider.tsapps/web/lib/api/errors.tsapps/web/lib/zod/schemas/deep-links.tsapps/web/lib/openapi/links/get-links-count.tsapps/web/lib/actions/partners/revoke-program-invite.tsapps/web/lib/zod/schemas/oauth.tsapps/web/lib/zod/schemas/customers.tsapps/web/lib/partners/cutoff-period.tsapps/web/lib/zod/schemas/utm.tsapps/web/lib/openapi/links/bulk-delete-links.tsapps/web/lib/actions/get-integration-install-url.tsapps/web/lib/openapi/workspaces/update-workspace.tsapps/web/lib/webhook/qstash.tsapps/web/lib/openapi/links/update-link.tsapps/web/lib/openapi/tags/get-tags.tsapps/web/lib/openapi/customers/get-customers.tsapps/web/lib/actions/update-workspace-notification-preference.tsapps/web/lib/actions/send-test-webhook.tsapps/web/lib/actions/partners/resend-program-invite.tsapps/web/lib/openapi/tags/update-tag.tsapps/web/lib/actions/submit-oauth-app-for-review.tsapps/web/lib/swr/use-links-count.tsapps/web/lib/zod/schemas/email-domains.tsapps/web/lib/openapi/links/delete-link.tsapps/web/lib/zod/schemas/workspaces.tsapps/web/lib/actions/verify-workspace-setup.tsapps/web/lib/actions/update-workspace-store.tsapps/web/lib/webhook/schemas.tsapps/web/package.jsonapps/web/lib/zod/schemas/qr.tsapps/web/lib/swr/use-customers-count.tsapps/web/lib/actions/check-account-exists.tsapps/web/lib/zod/schemas/token.tsapps/web/lib/openapi/tags/delete-tag.tsapps/web/lib/zod/schemas/partners.tsapps/web/lib/analytics/get-analytics.tsapps/web/lib/actions/partners/update-partner-notification-preference.tsapps/web/lib/tinybird/get-lead-event.tsapps/web/lib/openapi/workspaces/get-workspace-info.tsapps/web/lib/actions/enable-disable-webhook.tsapps/web/lib/zod/schemas/sales.tsapps/web/app/(ee)/api/embed/referrals/leaderboard/route.tsapps/web/lib/openapi/partners/list-partners.tsapps/web/lib/zod/schemas/misc.tsapps/web/lib/tinybird/get-webhook-events.tsapps/web/lib/webhook/types.tsapps/web/lib/openapi/links/bulk-update-links.tsapps/web/lib/zod/schemas/folders.tsapps/web/lib/openapi/folders/list-folders.tsapps/web/lib/openapi/events/index.tsapps/web/lib/zod/schemas/auth.tsapps/web/lib/openapi/partners/retrieve-analytics.tsapps/web/lib/actions/send-otp.tsapps/web/lib/zod/schemas/usage.tsapps/web/lib/tinybird/record-sale.tsapps/web/lib/zod/schemas/leads.tsapps/web/lib/zod/schemas/utils.tsapps/web/lib/zod/schemas/domains.tsapps/web/lib/openapi/links/get-links.tsapps/web/scripts/migrations/backfill-customers.tsapps/web/lib/openapi/index.tsapps/web/lib/zod/schemas/deprecated.tsapps/web/lib/analytics/types.tsapps/web/lib/zod/schemas/tags.tsapps/web/lib/zod/schemas/links.tsapps/web/lib/zod/schemas/analytics-response.ts
📚 Learning: 2025-06-06T07:59:03.120Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2177
File: apps/web/lib/api/links/bulk-create-links.ts:66-84
Timestamp: 2025-06-06T07:59:03.120Z
Learning: In apps/web/lib/api/links/bulk-create-links.ts, the team accepts the risk of potential undefined results from links.find() operations when building invalidLinks arrays, because existing links are fetched from the database based on the input links, so matches are expected to always exist.
Applied to files:
apps/web/lib/actions/partners/delete-program-invite.tsapps/web/lib/openapi/links/bulk-create-links.tsapps/web/lib/analytics/get-events.tsapps/web/scripts/migrations/backfill-link-commissions.tsapps/web/lib/openapi/links/bulk-delete-links.tsapps/web/lib/openapi/links/bulk-update-links.tsapps/web/lib/openapi/links/get-links.ts
📚 Learning: 2025-05-29T09:47:33.583Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2433
File: apps/web/app/api/workspaces/[idOrSlug]/billing/payment-methods/route.ts:74-76
Timestamp: 2025-05-29T09:47:33.583Z
Learning: When Zod enum validation is used (e.g., `z.enum(PAYMENT_METHOD_TYPES)`), it ensures the validated value is one of the valid enum values, making subsequent type casts to the corresponding TypeScript types safe without additional validation.
Applied to files:
apps/web/lib/zod/schemas/invoices.tsapps/web/lib/zod/schemas/tags.ts
📚 Learning: 2025-09-17T02:53:28.359Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2839
File: apps/web/lib/integrations/hubspot/schema.ts:5-12
Timestamp: 2025-09-17T02:53:28.359Z
Learning: HubSpot's OAuth token response returns `scopes` as an array of strings, not as a space-delimited string. The schema `scopes: z.array(z.string())` in hubSpotAuthTokenSchema is correct for HubSpot's actual API response format.
Applied to files:
apps/web/lib/integrations/hubspot/oauth.tsapps/web/lib/zod/schemas/oauth.tsapps/web/lib/zod/schemas/token.ts
📚 Learning: 2025-09-28T14:32:34.468Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2898
File: apps/web/lib/integrations/hubspot/oauth.ts:24-41
Timestamp: 2025-09-28T14:32:34.468Z
Learning: In the HubSpot OAuth implementation, the refreshToken() method uses the full hubSpotAuthTokenSchema to validate the refresh response, meaning the refresh endpoint returns all required fields including hub_id and scopes, so no need to merge with existing token data.
Applied to files:
apps/web/lib/integrations/hubspot/oauth.ts
📚 Learning: 2025-09-28T14:32:34.468Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2898
File: apps/web/lib/integrations/hubspot/oauth.ts:24-41
Timestamp: 2025-09-28T14:32:34.468Z
Learning: In the HubSpot OAuth implementation, the refresh token endpoint returns all required fields including hub_id and scopes, not just the minimal access_token/refresh_token/expires_in. The refreshToken() method successfully uses the full hubSpotAuthTokenSchema to validate the refresh response.
Applied to files:
apps/web/lib/integrations/hubspot/oauth.ts
📚 Learning: 2025-11-24T16:36:36.196Z
Learnt from: CR
Repo: dubinc/dub PR: 0
File: packages/hubspot-app/CLAUDE.md:0-0
Timestamp: 2025-11-24T16:36:36.196Z
Learning: Applies to packages/hubspot-app/app/*-hsmeta.json : If the `config.distribution` field is set to `marketplace` in the app component, the only valid `config.auth.type` value is `oauth`
Applied to files:
apps/web/lib/integrations/hubspot/oauth.ts
📚 Learning: 2025-10-15T01:52:37.048Z
Learnt from: steven-tey
Repo: dubinc/dub PR: 2958
File: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/members/page-client.tsx:270-303
Timestamp: 2025-10-15T01:52:37.048Z
Learning: In React components with dropdowns or form controls that show modals for confirmation (e.g., role selection, delete confirmation), local state should be reverted to match the prop value when the modal is cancelled. This prevents the UI from showing an unconfirmed change. The solution is to either: (1) pass an onClose callback to the modal that resets the local state, or (2) observe modal visibility state and reset on close. Example context: RoleCell component in apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/members/page-client.tsx where role dropdown should revert to user.role when UpdateUserModal is cancelled.
Applied to files:
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/confirm-create-bounty-modal.tsx
📚 Learning: 2025-10-02T22:46:22.739Z
Learnt from: steven-tey
Repo: dubinc/dub PR: 2924
File: apps/web/lib/api/conversions/track-lead.ts:7-7
Timestamp: 2025-10-02T22:46:22.739Z
Learning: In apps/web/lib/api/conversions/track-lead.ts, lead events are cached in Redis for 5 minutes (keys: `leadCache:${customer.id}` and `leadCache:${customer.id}:${stringifiedEventName}`) to provide immediate data availability while Tinybird ingestion happens asynchronously. This caching pattern allows for async-only recording without breaking "wait" mode semantics.
Applied to files:
apps/web/lib/tinybird/get-lead-events.tsapps/web/lib/tinybird/get-lead-event.tsapps/web/lib/zod/schemas/leads.ts
📚 Learning: 2025-06-18T20:26:25.177Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2538
File: apps/web/ui/partners/overview/blocks/commissions-block.tsx:16-27
Timestamp: 2025-06-18T20:26:25.177Z
Learning: In the Dub codebase, components that use workspace data (workspaceId, defaultProgramId) are wrapped in `WorkspaceAuth` which ensures these values are always available, making non-null assertions safe. This is acknowledged as a common pattern in their codebase, though not ideal.
Applied to files:
apps/web/lib/actions/update-workspace-preferences.tsapps/web/lib/zod/schemas/workspaces.ts
📚 Learning: 2025-10-06T15:48:45.956Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2935
File: packages/prisma/schema/workspace.prisma:21-36
Timestamp: 2025-10-06T15:48:45.956Z
Learning: In the Dub repository (dubinc/dub), Prisma schema changes are not managed with separate migration files. Do not flag missing Prisma migration files when schema changes are made to files like `packages/prisma/schema/workspace.prisma` or other schema files.
Applied to files:
apps/web/lib/actions/add-edit-integration.tsapps/web/lib/analytics/get-analytics.ts
📚 Learning: 2025-09-17T17:44:03.965Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2857
File: apps/web/lib/actions/partners/update-program.ts:96-0
Timestamp: 2025-09-17T17:44:03.965Z
Learning: In apps/web/lib/actions/partners/update-program.ts, the team prefers to keep the messagingEnabledAt update logic simple by allowing client-provided timestamps rather than implementing server-controlled timestamp logic to avoid added complexity.
Applied to files:
apps/web/lib/actions/partners/revoke-program-invite.tsapps/web/lib/actions/partners/update-partner-notification-preference.tsapps/web/lib/actions/partners/update-online-presence.ts
📚 Learning: 2025-06-19T01:46:45.723Z
Learnt from: steven-tey
Repo: dubinc/dub PR: 0
File: :0-0
Timestamp: 2025-06-19T01:46:45.723Z
Learning: PayPal webhook verification in the Dub codebase is handled at the route level in `apps/web/app/(ee)/api/paypal/webhook/route.ts` using the `verifySignature` function. Individual webhook handlers like `payoutsItemFailed` don't need to re-verify signatures since they're only called after successful verification.
Applied to files:
apps/web/lib/webhook/qstash.ts
📚 Learning: 2025-09-24T15:47:40.293Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2872
File: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/about-you-form.tsx:152-157
Timestamp: 2025-09-24T15:47:40.293Z
Learning: The Button component from dub/ui automatically adds type="button" when an onClick prop is passed, preventing accidental form submissions without requiring explicit type specification. The implementation uses: type={onClick ? "button" : type}
Applied to files:
apps/web/ui/links/link-builder/tag-select.tsx
📚 Learning: 2025-09-24T15:47:40.293Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2872
File: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/about-you-form.tsx:152-157
Timestamp: 2025-09-24T15:47:40.293Z
Learning: The Button component from dub/ui automatically adds type="button" when an onClick prop is passed, preventing accidental form submissions without requiring explicit type specification.
Applied to files:
apps/web/ui/links/link-builder/tag-select.tsx
📚 Learning: 2025-12-30T16:17:49.480Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3239
File: apps/web/app/(ee)/api/cron/aggregate-clicks/route.ts:265-273
Timestamp: 2025-12-30T16:17:49.480Z
Learning: In the Dub partner/rewards system, click rewards are always flat amounts specified in `amountInCents`. They never use percentage-based amounts (`amountInPercentage`) or duration fields (`maxDuration`), so when applying modifiers to click rewards (e.g., in resolveClickRewardAmount), only `amountInCents` needs to be transferred from the matched condition.
Applied to files:
apps/web/lib/api/sales/construct-reward-amount.ts
📚 Learning: 2025-08-26T14:20:23.943Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2736
File: apps/web/app/api/workspaces/[idOrSlug]/notification-preferences/route.ts:13-14
Timestamp: 2025-08-26T14:20:23.943Z
Learning: The updateNotificationPreference action in apps/web/lib/actions/update-notification-preference.ts already handles all notification preference types dynamically, including newBountySubmitted, through its schema validation using the notificationTypes enum and Prisma's dynamic field update pattern.
Applied to files:
apps/web/lib/actions/update-workspace-notification-preference.tsapps/web/lib/zod/schemas/bounties.tsapps/web/lib/actions/partners/update-partner-notification-preference.ts
📚 Learning: 2025-11-17T05:19:11.972Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3113
File: apps/web/app/(ee)/api/cron/payouts/charge-succeeded/send-paypal-payouts.ts:65-75
Timestamp: 2025-11-17T05:19:11.972Z
Learning: In the Dub codebase, `sendBatchEmail` (implemented in packages/email/src/send-via-resend.ts) handles filtering of emails with invalid `to` addresses internally. Call sites can safely use non-null assertions on email addresses because the email sending layer will filter out any entries with null/undefined `to` values before sending. This centralized validation pattern is intentional and removes the need for filtering at individual call sites.
Applied to files:
apps/web/lib/actions/partners/resend-program-invite.tsapps/web/app/(ee)/api/cron/send-batch-email/route.tsapps/web/app/(ee)/api/campaigns/[campaignId]/preview/route.ts
📚 Learning: 2025-12-18T16:55:57.098Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3244
File: apps/web/app/(ee)/api/cron/bounties/create-draft-submissions/route.ts:148-174
Timestamp: 2025-12-18T16:55:57.098Z
Learning: In the bounty system (e.g., apps/web/app/(ee)/api/cron/bounties/create-draft-submissions/route.ts), bounties cannot be created with workflow attributes `partnerEnrolledDays` and `partnerJoined`. Bounty workflows only support attributes available from partner link stats (clicks, sales, leads, conversions, saleAmount) and totalCommissions, which is a subset of the general WORKFLOW_ATTRIBUTES schema.
Applied to files:
apps/web/lib/zod/schemas/bounties.ts
📚 Learning: 2025-08-26T15:05:55.081Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2736
File: apps/web/lib/swr/use-bounty.ts:11-16
Timestamp: 2025-08-26T15:05:55.081Z
Learning: In the Dub codebase, workspace authentication and route structures prevent endless loading states when workspaceId or similar route parameters are missing, so gating SWR loading states on parameter availability is often unnecessary.
Applied to files:
apps/web/lib/swr/use-links-count.tsapps/web/lib/swr/use-customers-count.ts
📚 Learning: 2025-07-17T06:41:45.620Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2637
File: apps/web/app/(ee)/api/singular/webhook/route.ts:0-0
Timestamp: 2025-07-17T06:41:45.620Z
Learning: In the Singular integration (apps/web/app/(ee)/api/singular/webhook/route.ts), the event names in the singularToDubEvent object have intentionally different casing: "Copy GAID" and "copy IDFA". This casing difference is valid and should not be changed, as these are the correct event names expected from Singular.
Applied to files:
apps/web/lib/webhook/schemas.tsapps/web/lib/zod/schemas/analytics.ts
📚 Learning: 2025-11-24T16:36:36.196Z
Learnt from: CR
Repo: dubinc/dub PR: 0
File: packages/hubspot-app/CLAUDE.md:0-0
Timestamp: 2025-11-24T16:36:36.196Z
Learning: Applies to packages/hubspot-app/**/*-hsmeta.json : The `type` field in `-hsmeta.json` files defines the type of the component
Applied to files:
apps/web/lib/webhook/schemas.ts
📚 Learning: 2025-09-24T16:13:00.387Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2872
File: packages/prisma/schema/partner.prisma:151-153
Timestamp: 2025-09-24T16:13:00.387Z
Learning: In the Dub codebase, Prisma schemas use single-column indexes without brackets (e.g., `@index(partnerId)`) and multi-column indexes with brackets (e.g., `@index([programId, partnerId])`). This syntax pattern is consistently used throughout their schema files and works correctly with their Prisma version.
Applied to files:
apps/web/lib/analytics/get-analytics.ts
📚 Learning: 2025-11-12T22:23:10.414Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 3098
File: apps/web/lib/actions/partners/message-program.ts:49-58
Timestamp: 2025-11-12T22:23:10.414Z
Learning: In apps/web/lib/actions/partners/message-program.ts, when checking if a partner can continue messaging after messaging is disabled, the code intentionally requires `senderPartnerId: null` (program-initiated messages) to prevent partners from continuing to send junk messages. Only conversations started by the program should continue after messaging is disabled, as a spam prevention mechanism.
Applied to files:
apps/web/lib/actions/partners/update-partner-notification-preference.ts
📚 Learning: 2025-06-16T19:21:23.506Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2519
File: apps/web/ui/analytics/utils.ts:35-37
Timestamp: 2025-06-16T19:21:23.506Z
Learning: In the `useAnalyticsFilterOption` function in `apps/web/ui/analytics/utils.ts`, the pattern `options?.context ?? useContext(AnalyticsContext)` is intentionally designed as a complete replacement strategy, not a merge. When `options.context` is provided, it should contain all required fields (`baseApiPath`, `queryString`, `selectedTab`, `requiresUpgrade`) and completely replace the React context, not be merged with it. This is used for dependency injection or testing scenarios.
Applied to files:
apps/web/lib/zod/schemas/analytics.tsapps/web/ui/analytics/use-analytics-filters.tsxapps/web/lib/analytics/types.ts
📚 Learning: 2025-09-24T16:10:37.349Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2872
File: apps/web/ui/partners/partner-about.tsx:11-11
Timestamp: 2025-09-24T16:10:37.349Z
Learning: In the Dub codebase, the team prefers to import Icon as a runtime value from "dub/ui" and uses Icon as both a type and variable name in component props, even when this creates shadowing. This is their established pattern and should not be suggested for refactoring.
Applied to files:
apps/web/ui/links/short-link-input.tsxapps/web/ui/modals/link-builder/og-modal.tsx
📚 Learning: 2025-12-08T09:44:28.429Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3200
File: apps/web/lib/api/fraud/detect-duplicate-payout-method-fraud.ts:55-73
Timestamp: 2025-12-08T09:44:28.429Z
Learning: In apps/web/lib/api/fraud/detect-duplicate-payout-method-fraud.ts, the fraud event creation logic intentionally generates self-referential fraud events (where partnerId equals duplicatePartnerId) for partners with duplicate payout methods. This is by design to create raw events for all partners involved in a duplicate payout method scenario, regardless of whether they reference themselves.
Applied to files:
apps/web/lib/zod/schemas/payouts.ts
📚 Learning: 2025-12-15T16:45:51.667Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3213
File: apps/web/app/(ee)/api/cron/auto-approve-partner/route.ts:122-122
Timestamp: 2025-12-15T16:45:51.667Z
Learning: In cron endpoints under apps/web/app/(ee)/api/cron, continue using handleCronErrorResponse for error handling. Do not detect QStash callbacks or set Upstash-NonRetryable-Error headers in these cron routes, so QStash can retry cron errors via its native retry mechanism. The existing queueFailedRequestForRetry logic should remain limited to specific user-facing API endpoints (e.g., /api/track/lead, /api/track/sale, /api/links) to retry only transient Prisma/database errors. This pattern should apply to all cron endpoints under the cron directory in this codebase.
Applied to files:
apps/web/app/(ee)/api/cron/send-batch-email/route.ts
📚 Learning: 2025-08-25T21:03:24.285Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2736
File: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/bounty-card.tsx:1-1
Timestamp: 2025-08-25T21:03:24.285Z
Learning: In Next.js App Router, Server Components that use hooks can work without "use client" directive if they are only imported by Client Components, as they get "promoted" to run on the client side within the Client Component boundary.
Applied to files:
apps/web/lib/swr/use-workspace-preferences.ts
📚 Learning: 2025-09-18T16:33:17.719Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2858
File: apps/web/ui/partners/partner-application-tabs.tsx:1-1
Timestamp: 2025-09-18T16:33:17.719Z
Learning: When a React component in Next.js App Router uses non-serializable props (like setState functions), adding "use client" directive can cause serialization warnings. If the component is only imported by Client Components, it's better to omit the "use client" directive to avoid these warnings while still getting client-side execution through promotion.
Applied to files:
apps/web/lib/swr/use-workspace-preferences.ts
📚 Learning: 2025-08-18T02:31:22.282Z
Learnt from: steven-tey
Repo: dubinc/dub PR: 2756
File: apps/web/ui/webhooks/webhook-header.tsx:20-20
Timestamp: 2025-08-18T02:31:22.282Z
Learning: The Next.js redirect() function can be used in both Server Components and Client Components, as well as Route Handlers and Server Actions. It is not server-only as previously thought.
Applied to files:
apps/web/lib/swr/use-workspace-preferences.ts
📚 Learning: 2025-05-29T04:45:18.504Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2448
File: packages/email/src/templates/partner-program-summary.tsx:0-0
Timestamp: 2025-05-29T04:45:18.504Z
Learning: In the PartnerProgramSummary email template (packages/email/src/templates/partner-program-summary.tsx), the stat titles are hardcoded constants ("Clicks", "Leads", "Sales", "Earnings") that will always match the ICONS object keys after toLowerCase() conversion, so icon lookup failures are not possible.
Applied to files:
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/payout-stats.tsx
📚 Learning: 2025-10-31T19:45:25.702Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 3044
File: apps/web/lib/analytics/utils/get-interval-data.ts:31-0
Timestamp: 2025-10-31T19:45:25.702Z
Learning: In apps/web/lib/analytics/utils/get-interval-data.ts, the `mtd` and `qtd` interval functions are designed to work in both server and client contexts. When no timezone is provided, they intentionally fall back to `new Date()` (local timezone) because front-end code calls these methods without passing a timezone and should use the browser's local timezone for the user's context.
Applied to files:
apps/web/lib/zod/schemas/usage.ts
📚 Learning: 2025-10-29T08:57:50.049Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3025
File: apps/web/lib/zod/schemas/links.ts:251-255
Timestamp: 2025-10-29T08:57:50.049Z
Learning: In the Dub codebase, the `archived` field for links comes from the database as a number (0 or 1), not as a boolean or string, so checking `value === 1` in the parse function is the correct approach.
Applied to files:
apps/web/lib/zod/schemas/domains.ts
🧬 Code graph analysis (16)
apps/web/lib/integrations/hubspot/oauth.ts (2)
apps/web/lib/integrations/oauth-provider.ts (1)
OAuthProviderConfig(5-18)apps/web/lib/integrations/hubspot/schema.ts (1)
hubSpotAuthTokenSchema(8-15)
apps/web/lib/openapi/links/bulk-create-links.ts (1)
apps/web/lib/zod/schemas/links.ts (2)
LinkSchema(600-832)LinkErrorSchema(834-840)
apps/web/lib/openapi/analytics/index.ts (1)
apps/web/lib/zod/schemas/analytics-response.ts (1)
analyticsResponse(30-578)
apps/web/lib/integrations/slack/oauth.ts (2)
apps/web/lib/integrations/oauth-provider.ts (1)
OAuthProviderConfig(5-18)apps/web/lib/integrations/slack/schema.ts (1)
slackAuthTokenSchema(3-21)
apps/web/app/(ee)/api/admin/commissions/route.ts (1)
apps/web/lib/zod/schemas/analytics.ts (1)
analyticsQuerySchema(58-247)
apps/web/lib/paypal/oauth.ts (1)
apps/web/lib/integrations/oauth-provider.ts (1)
OAuthProviderConfig(5-18)
apps/web/lib/api/sales/construct-reward-amount.ts (1)
packages/utils/src/functions/currency-formatter.ts (1)
currencyFormatter(7-22)
apps/web/scripts/migrations/backfill-missing-sales.ts (1)
apps/web/lib/analytics/get-events.ts (1)
getEvents(30-176)
apps/web/lib/zod/schemas/bounties.ts (1)
apps/web/lib/zod/schemas/misc.ts (1)
booleanQuerySchema(24-29)
apps/web/lib/zod/schemas/partners.ts (1)
apps/web/lib/zod/schemas/analytics-response.ts (1)
analyticsResponse(30-578)
apps/web/lib/zod/schemas/analytics.ts (3)
apps/web/lib/analytics/constants.ts (3)
EVENT_TYPES(178-178)VALID_ANALYTICS_ENDPOINTS(64-91)OLD_ANALYTICS_ENDPOINTS(184-203)apps/web/lib/zod/schemas/misc.ts (1)
booleanQuerySchema(24-29)apps/web/lib/zod/schemas/utm.ts (1)
UTMTemplateSchema(51-90)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/payout-stats.tsx (1)
packages/utils/src/functions/currency-formatter.ts (1)
currencyFormatter(7-22)
apps/web/lib/zod/schemas/domains.ts (2)
apps/web/lib/zod/schemas/misc.ts (1)
booleanQuerySchema(24-29)apps/web/lib/zod/schemas/utils.ts (1)
parseUrlSchemaAllowEmpty(15-35)
apps/web/app/(ee)/api/programs/[programId]/applications/export/route.ts (1)
apps/web/lib/zod/schemas/partners.ts (1)
exportApplicationsColumnsDefault(101-110)
apps/web/lib/zod/schemas/tags.ts (1)
apps/web/lib/zod/schemas/misc.ts (1)
booleanQuerySchema(24-29)
apps/web/lib/zod/schemas/links.ts (2)
apps/web/lib/zod/schemas/misc.ts (1)
booleanQuerySchema(24-29)apps/web/lib/api/error-codes.ts (1)
ErrorCode(3-15)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
apps/web/lib/actions/partners/update-partner-notification-preference.ts
Outdated
Show resolved
Hide resolved
apps/web/lib/actions/update-workspace-notification-preference.ts
Outdated
Show resolved
Hide resolved
…RL validations across multiple files
This reverts commit 15cd6b4.
|
@coderabbitai do a final review and list out breaking changes, if any |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 12051 🏁 Script executed: Length of output: 5584 🏁 Script executed: Length of output: 3570 🏁 Script executed: Length of output: 1534 🏁 Script executed: Length of output: 2814 @devkiran I've completed a comprehensive final review. Here are all the breaking changes identified in this Zod v4 migration: 🚨 Critical Breaking Changes (API Contract Changes)1. Query Parameter Default Values ChangedBoolean query parameters now default to actual booleans instead of strings: Affected schemas:
Impact: Query string parsing behavior may differ. If clients rely on string coercion behavior, this could cause validation failures.
|
Summary by CodeRabbit
Bug Fixes
Chores
✏️ Tip: You can customize this high-level summary in your review settings.