Copy disabled (too large)
Download .txt
Showing preview only (13,548K chars total). Download the full file to get everything.
Repository: dubinc/dub
Branch: main
Commit: 055ca7e99042
Files: 3991
Total size: 12.1 MB
Directory structure:
gitextract_j4v7jeo4/
├── .github/
│ └── workflows/
│ ├── apply-issue-labels-to-pr.yml
│ ├── deploy-embed-script.yml
│ ├── e2e.yaml
│ ├── playwright.yaml
│ └── prettier.yaml
├── .gitignore
├── .prettierignore
├── LICENSE.md
├── README.md
├── SECURITY.md
├── apps/
│ └── web/
│ ├── app/
│ │ ├── (ee)/
│ │ │ ├── LICENSE.md
│ │ │ ├── README.md
│ │ │ ├── admin.dub.co/
│ │ │ │ ├── (auth)/
│ │ │ │ │ ├── layout.tsx
│ │ │ │ │ └── login/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── (dashboard)/
│ │ │ │ │ ├── analytics/
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── commissions/
│ │ │ │ │ │ ├── client.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── ban-link.tsx
│ │ │ │ │ │ ├── delete-partner-account.tsx
│ │ │ │ │ │ ├── impersonate-user.tsx
│ │ │ │ │ │ ├── impersonate-workspace.tsx
│ │ │ │ │ │ ├── refresh-domain.tsx
│ │ │ │ │ │ ├── reset-login-attempts.tsx
│ │ │ │ │ │ └── user-info.tsx
│ │ │ │ │ ├── events/
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── layout-nav-client.tsx
│ │ │ │ │ ├── layout.tsx
│ │ │ │ │ ├── links/
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── page.tsx
│ │ │ │ │ ├── payouts/
│ │ │ │ │ │ ├── client.tsx
│ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ └── paypal/
│ │ │ │ │ │ ├── client.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ └── revenue/
│ │ │ │ │ ├── client.tsx
│ │ │ │ │ └── page.tsx
│ │ │ │ └── layout.tsx
│ │ │ ├── api/
│ │ │ │ ├── admin/
│ │ │ │ │ ├── analytics/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── ban/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── commissions/
│ │ │ │ │ │ ├── get-commissions-timeseries.ts
│ │ │ │ │ │ ├── get-top-program-by-commissions.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── delete-partner-account/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── events/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── impersonate/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── links/
│ │ │ │ │ │ ├── [linkId]/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── ban/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── count/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── payouts/
│ │ │ │ │ │ ├── paypal/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── refresh-domain/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── reset-login-attempts/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── revenue/
│ │ │ │ │ ├── get-top-programs-by-sales.ts
│ │ │ │ │ └── route.ts
│ │ │ │ ├── audit-logs/
│ │ │ │ │ └── export/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── auth/
│ │ │ │ │ └── saml/
│ │ │ │ │ ├── authorize/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── callback/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── token/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── userinfo/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── verify/
│ │ │ │ │ └── route.tsx
│ │ │ │ ├── bounties/
│ │ │ │ │ ├── [bountyId]/
│ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ ├── submissions/
│ │ │ │ │ │ │ ├── [submissionId]/
│ │ │ │ │ │ │ │ ├── approve/
│ │ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ │ └── reject/
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── sync-social-metrics/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── count/
│ │ │ │ │ │ └── submissions/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── route.ts
│ │ │ │ ├── campaigns/
│ │ │ │ │ ├── [campaignId]/
│ │ │ │ │ │ ├── duplicate/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── events/
│ │ │ │ │ │ │ ├── count/
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── preview/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ └── summary/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── count/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── route.ts
│ │ │ │ ├── commissions/
│ │ │ │ │ ├── [commissionId]/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── count/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── export/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── route.ts
│ │ │ │ │ └── timeseries/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── cron/
│ │ │ │ │ ├── aggregate-clicks/
│ │ │ │ │ │ ├── resolve-click-reward-amount.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── bounties/
│ │ │ │ │ │ ├── create-draft-submissions/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── notify-partners/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── queue-sync-social-metrics/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── sync-social-metrics/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── campaigns/
│ │ │ │ │ │ └── broadcast/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── cleanup/
│ │ │ │ │ │ ├── demo-embed-partners/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── e2e-tests/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── expired-tokens/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── link-retention/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── rejected-applications/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── unenrolled-partners/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── discount-codes/
│ │ │ │ │ │ ├── create/
│ │ │ │ │ │ │ ├── queue-batches/
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── delete/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── disposable-emails/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── domains/
│ │ │ │ │ │ ├── delete/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── renewal-payments/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── renewal-reminders/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── transfer/
│ │ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ ├── update/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── verify/
│ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ └── utils.ts
│ │ │ │ │ ├── email-domains/
│ │ │ │ │ │ ├── update/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── verify/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── export/
│ │ │ │ │ │ ├── commissions/
│ │ │ │ │ │ │ ├── fetch-commissions-batch.ts
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── customers/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── events/
│ │ │ │ │ │ │ ├── fetch-events-batch.ts
│ │ │ │ │ │ │ ├── partner/
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ └── workspace/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── links/
│ │ │ │ │ │ │ ├── fetch-links-batch.ts
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── partners/
│ │ │ │ │ │ ├── fetch-partners-batch.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── folders/
│ │ │ │ │ │ └── delete/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── framer/
│ │ │ │ │ │ └── backfill-leads-batch/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── fraud/
│ │ │ │ │ │ └── summary/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── fx-rates/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── groups/
│ │ │ │ │ │ ├── create-default-links/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── remap-default-links/
│ │ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ ├── remap-discount-codes/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── sync-utm/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── update-default-links/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── import/
│ │ │ │ │ │ ├── bitly/
│ │ │ │ │ │ │ ├── fetch-utils.ts
│ │ │ │ │ │ │ ├── queue-import.ts
│ │ │ │ │ │ │ ├── rate-limit.ts
│ │ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ │ ├── sanitize-json.ts
│ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ ├── csv/
│ │ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ ├── firstpromoter/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── partnerstack/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── rebrandly/
│ │ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ ├── rewardful/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── short/
│ │ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ └── tolt/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── invoices/
│ │ │ │ │ │ └── retry-failed/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── links/
│ │ │ │ │ │ ├── [linkId]/
│ │ │ │ │ │ │ └── complete-tests/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── delete/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── invalidate-for-discounts/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── invalidate-for-partners/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── messages/
│ │ │ │ │ │ ├── notify-partner/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── notify-program/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── network/
│ │ │ │ │ │ ├── calculate-program-similarities/
│ │ │ │ │ │ │ ├── calculate-category-similarity.ts
│ │ │ │ │ │ │ ├── calculate-partner-similarity.ts
│ │ │ │ │ │ │ ├── calculate-performance-similarity.ts
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── update-partner-discoverability/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── partner-platforms/
│ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ └── youtube/
│ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ └── youtube-channel-schema.ts
│ │ │ │ │ ├── partner-program-summary/
│ │ │ │ │ │ ├── process/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── partners/
│ │ │ │ │ │ ├── auto-approve/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── auto-reject/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── ban/
│ │ │ │ │ │ │ ├── cancel-commissions.ts
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── deactivate/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── merge-accounts/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── payouts/
│ │ │ │ │ │ ├── aggregate-due-commissions/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── balance-available/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── charge-succeeded/
│ │ │ │ │ │ │ ├── queue-external-payouts.ts
│ │ │ │ │ │ │ ├── queue-stripe-payouts.ts
│ │ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ │ ├── send-paypal-payouts.ts
│ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ ├── force-withdrawals/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── payout-failed/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── payout-paid/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── process/
│ │ │ │ │ │ │ ├── process-payouts.ts
│ │ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ │ ├── split-payouts.ts
│ │ │ │ │ │ │ └── updates/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── reminders/
│ │ │ │ │ │ │ ├── partners/
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ └── program-owners/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── send-stripe-payout/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── pending-applications-summary/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── program-application-reminder/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── programs/
│ │ │ │ │ │ └── deactivate/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── send-batch-email/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── shopify/
│ │ │ │ │ │ └── order-paid/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── streams/
│ │ │ │ │ │ ├── update-partner-stats/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── update-workspace-clicks/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── trigger-withdrawal/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── usage/
│ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ └── utils.ts
│ │ │ │ │ ├── utils.ts
│ │ │ │ │ ├── welcome-user/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── workflows/
│ │ │ │ │ │ └── [workflowId]/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── workspaces/
│ │ │ │ │ └── delete/
│ │ │ │ │ ├── delete-workspace-customers.ts
│ │ │ │ │ ├── delete-workspace-domains.ts
│ │ │ │ │ ├── delete-workspace-folders.ts
│ │ │ │ │ ├── delete-workspace-links.ts
│ │ │ │ │ ├── delete-workspace.ts
│ │ │ │ │ ├── route.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── customers/
│ │ │ │ │ ├── [id]/
│ │ │ │ │ │ ├── activity/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ └── stripe-invoices/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── count/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── export/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── route.ts
│ │ │ │ │ └── search-stripe/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── discount-codes/
│ │ │ │ │ ├── [discountCodeId]/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── route.ts
│ │ │ │ ├── domains/
│ │ │ │ │ ├── register/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── status/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── e2e/
│ │ │ │ │ ├── bounties/
│ │ │ │ │ │ └── [bountyId]/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── enrollments/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── guard.ts
│ │ │ │ │ ├── notification-emails/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── trigger-workflow/
│ │ │ │ │ │ └── [workflowId]/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── workflows/
│ │ │ │ │ ├── [workflowId]/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── route.ts
│ │ │ │ ├── email-domains/
│ │ │ │ │ ├── [domain]/
│ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ └── verify/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── route.ts
│ │ │ │ ├── embed/
│ │ │ │ │ └── referrals/
│ │ │ │ │ ├── analytics/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── earnings/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── leaderboard/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── links/
│ │ │ │ │ │ ├── [linkId]/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── token/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── events/
│ │ │ │ │ ├── export/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── route.ts
│ │ │ │ ├── fraud/
│ │ │ │ │ ├── events/
│ │ │ │ │ │ ├── count/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── groups/
│ │ │ │ │ │ ├── count/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── rules/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── groups/
│ │ │ │ │ ├── [groupIdOrSlug]/
│ │ │ │ │ │ ├── default/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── default-links/
│ │ │ │ │ │ │ ├── [defaultLinkId]/
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── partners/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── count/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── route.ts
│ │ │ │ │ └── rules/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── hubspot/
│ │ │ │ │ ├── callback/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── webhook/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── messages/
│ │ │ │ │ ├── count/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── route.ts
│ │ │ │ ├── mock/
│ │ │ │ │ └── rewardful/
│ │ │ │ │ ├── affiliates/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── campaigns/
│ │ │ │ │ │ ├── [campaignId]/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── campaigns.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── commissions/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── referrals/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── network/
│ │ │ │ │ ├── partners/
│ │ │ │ │ │ ├── count/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── invites-usage/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── programs/
│ │ │ │ │ ├── count/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── route.ts
│ │ │ │ ├── partner-profile/
│ │ │ │ │ ├── invites/
│ │ │ │ │ │ ├── accept/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── messages/
│ │ │ │ │ │ ├── count/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── notification-preferences/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── payouts/
│ │ │ │ │ │ ├── count/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ └── settings/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── postbacks/
│ │ │ │ │ │ ├── [postbackId]/
│ │ │ │ │ │ │ ├── events/
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ ├── rotate-secret/
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ │ └── send-test/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── programs/
│ │ │ │ │ │ ├── [programId]/
│ │ │ │ │ │ │ ├── activity-logs/
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ ├── analytics/
│ │ │ │ │ │ │ │ ├── export/
│ │ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ ├── bounties/
│ │ │ │ │ │ │ │ ├── [bountyId]/
│ │ │ │ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ │ │ │ └── social-content-stats/
│ │ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ ├── customers/
│ │ │ │ │ │ │ │ ├── [customerId]/
│ │ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ │ ├── count/
│ │ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ ├── earnings/
│ │ │ │ │ │ │ │ ├── count/
│ │ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ │ │ └── timeseries/
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ ├── events/
│ │ │ │ │ │ │ │ ├── export/
│ │ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ ├── groups/
│ │ │ │ │ │ │ │ └── [groupIdOrSlug]/
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ ├── links/
│ │ │ │ │ │ │ │ ├── [linkId]/
│ │ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ ├── referrals/
│ │ │ │ │ │ │ │ ├── count/
│ │ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ ├── resources/
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── count/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── rewind/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── route.ts
│ │ │ │ │ └── users/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── partners/
│ │ │ │ │ ├── [partnerId]/
│ │ │ │ │ │ ├── application-risks/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── comments/
│ │ │ │ │ │ │ ├── count/
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── cross-program-summary/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── analytics/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── ban/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── count/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── deactivate/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── export/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── links/
│ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ └── upsert/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── platforms/
│ │ │ │ │ │ └── callback/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── route.ts
│ │ │ │ ├── payouts/
│ │ │ │ │ ├── [payoutId]/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── count/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── route.ts
│ │ │ │ ├── paypal/
│ │ │ │ │ ├── callback/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── webhook/
│ │ │ │ │ ├── payouts-item-failed.ts
│ │ │ │ │ ├── payouts-item-succeeded.ts
│ │ │ │ │ ├── route.ts
│ │ │ │ │ ├── utils.ts
│ │ │ │ │ └── verify-signature.ts
│ │ │ │ ├── programs/
│ │ │ │ │ ├── [programId]/
│ │ │ │ │ │ ├── applications/
│ │ │ │ │ │ │ ├── [applicationId]/
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ └── export/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── discounts/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── payouts/
│ │ │ │ │ │ │ └── eligible/
│ │ │ │ │ │ │ ├── count/
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── referrals/
│ │ │ │ │ │ │ ├── count/
│ │ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── resources/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── rewardful/
│ │ │ │ │ └── campaigns/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── rewards/
│ │ │ │ │ ├── [rewardId]/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── route.ts
│ │ │ │ ├── scim/
│ │ │ │ │ └── v2.0/
│ │ │ │ │ └── [...directory]/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── shopify/
│ │ │ │ │ ├── integration/
│ │ │ │ │ │ ├── callback/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── webhook/
│ │ │ │ │ │ ├── app-uninstalled.ts
│ │ │ │ │ │ ├── customers-data-request.ts
│ │ │ │ │ │ ├── customers-redact.ts
│ │ │ │ │ │ ├── orders-paid.ts
│ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ └── shop-redact.ts
│ │ │ │ │ └── pixel/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── singular/
│ │ │ │ │ └── webhook/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── stripe/
│ │ │ │ │ ├── connect/
│ │ │ │ │ │ ├── v2/
│ │ │ │ │ │ │ └── webhook/
│ │ │ │ │ │ │ ├── outbound-payment-failed.ts
│ │ │ │ │ │ │ ├── outbound-payment-posted.ts
│ │ │ │ │ │ │ ├── outbound-payment-returned.ts
│ │ │ │ │ │ │ ├── recipient-account-closed.ts
│ │ │ │ │ │ │ ├── recipient-configuration-updated.ts
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── webhook/
│ │ │ │ │ │ ├── account-application-deauthorized.ts
│ │ │ │ │ │ ├── account-updated.ts
│ │ │ │ │ │ ├── balance-available.ts
│ │ │ │ │ │ ├── payout-failed.ts
│ │ │ │ │ │ ├── payout-paid.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── integration/
│ │ │ │ │ │ ├── callback/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ └── webhook/
│ │ │ │ │ │ ├── account-application-deauthorized.ts
│ │ │ │ │ │ ├── charge-refunded.ts
│ │ │ │ │ │ ├── checkout-session-completed.ts
│ │ │ │ │ │ ├── coupon-deleted.ts
│ │ │ │ │ │ ├── customer-created.ts
│ │ │ │ │ │ ├── customer-subscription-created.ts
│ │ │ │ │ │ ├── customer-subscription-deleted.ts
│ │ │ │ │ │ ├── customer-updated.ts
│ │ │ │ │ │ ├── invoice-paid.ts
│ │ │ │ │ │ ├── promotion-code-updated.ts
│ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ ├── sandbox/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── test/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── utils/
│ │ │ │ │ │ ├── create-new-customer.ts
│ │ │ │ │ │ ├── get-connected-customer.ts
│ │ │ │ │ │ ├── get-promotion-code.ts
│ │ │ │ │ │ ├── get-subscription-product-id.ts
│ │ │ │ │ │ └── update-customer-with-stripe-customer-id.ts
│ │ │ │ │ └── webhook/
│ │ │ │ │ ├── charge-failed.ts
│ │ │ │ │ ├── charge-refunded.ts
│ │ │ │ │ ├── charge-succeeded.ts
│ │ │ │ │ ├── checkout-session-completed.ts
│ │ │ │ │ ├── customer-subscription-deleted.ts
│ │ │ │ │ ├── customer-subscription-updated.ts
│ │ │ │ │ ├── invoice-payment-failed.tsx
│ │ │ │ │ ├── payment-intent-requires-action.ts
│ │ │ │ │ ├── route.ts
│ │ │ │ │ ├── transfer-reversed.ts
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── process-domain-renewal-failure.ts
│ │ │ │ │ ├── process-payout-invoice-failure.ts
│ │ │ │ │ ├── send-cancellation-feedback.ts
│ │ │ │ │ └── update-workspace-plan.ts
│ │ │ │ ├── track/
│ │ │ │ │ ├── click/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── lead/
│ │ │ │ │ │ ├── client/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── open/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── sale/
│ │ │ │ │ │ ├── client/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── visit/
│ │ │ │ │ └── route.ts
│ │ │ │ └── workflows/
│ │ │ │ └── partner-approved/
│ │ │ │ └── route.ts
│ │ │ ├── app.dub.co/
│ │ │ │ ├── (new-program)/
│ │ │ │ │ ├── [slug]/
│ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ └── program/
│ │ │ │ │ │ └── new/
│ │ │ │ │ │ ├── form.tsx
│ │ │ │ │ │ ├── overview/
│ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ ├── partners/
│ │ │ │ │ │ │ ├── form.tsx
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── rewards/
│ │ │ │ │ │ │ ├── form.tsx
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── step-page.tsx
│ │ │ │ │ │ └── support/
│ │ │ │ │ │ ├── form.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── header.tsx
│ │ │ │ │ ├── layout.tsx
│ │ │ │ │ ├── sidebar-context.tsx
│ │ │ │ │ └── steps.tsx
│ │ │ │ ├── embed/
│ │ │ │ │ ├── referrals/
│ │ │ │ │ │ ├── activity.tsx
│ │ │ │ │ │ ├── add-edit-link.tsx
│ │ │ │ │ │ ├── dynamic-height-messenger.tsx
│ │ │ │ │ │ ├── earnings-summary.tsx
│ │ │ │ │ │ ├── earnings.tsx
│ │ │ │ │ │ ├── faq.tsx
│ │ │ │ │ │ ├── leaderboard.tsx
│ │ │ │ │ │ ├── links-list.tsx
│ │ │ │ │ │ ├── links.tsx
│ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ ├── quickstart.tsx
│ │ │ │ │ │ ├── resources.tsx
│ │ │ │ │ │ ├── theme-options.ts
│ │ │ │ │ │ ├── token.tsx
│ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ └── utils.ts
│ │ │ │ │ └── use-embed-token.ts
│ │ │ │ ├── invoices/
│ │ │ │ │ └── [invoiceId]/
│ │ │ │ │ ├── domain-renewal-invoice.tsx
│ │ │ │ │ ├── partner-payout-invoice.tsx
│ │ │ │ │ └── route.tsx
│ │ │ │ └── layout.tsx
│ │ │ └── partners.dub.co/
│ │ │ ├── (apply)/
│ │ │ │ └── [programSlug]/
│ │ │ │ ├── (default)/
│ │ │ │ │ ├── apply/
│ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ └── success/
│ │ │ │ │ │ ├── cta-buttons.tsx
│ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ ├── pixel-conversion.tsx
│ │ │ │ │ │ └── screenshot.tsx
│ │ │ │ │ ├── apply-button.tsx
│ │ │ │ │ ├── header.tsx
│ │ │ │ │ ├── layout.tsx
│ │ │ │ │ └── page.tsx
│ │ │ │ └── (group-level)/
│ │ │ │ └── [groupSlug]/
│ │ │ │ ├── apply/
│ │ │ │ │ ├── page.tsx
│ │ │ │ │ └── success/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ └── page.tsx
│ │ │ ├── (auth-login-register)/
│ │ │ │ ├── (generic)/
│ │ │ │ │ ├── layout.tsx
│ │ │ │ │ ├── login/
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ └── register/
│ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── (program)/
│ │ │ │ │ └── [programSlug]/
│ │ │ │ │ ├── layout.tsx
│ │ │ │ │ ├── login/
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ └── register/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── partner-banner.tsx
│ │ │ │ ├── program-logos.tsx
│ │ │ │ └── side-panel.tsx
│ │ │ ├── (auth-other)/
│ │ │ │ ├── auth/
│ │ │ │ │ ├── confirm-email-change/
│ │ │ │ │ │ └── [token]/
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ └── reset-password/
│ │ │ │ │ └── [token]/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── forgot-password/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── invite/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ ├── logo.tsx
│ │ │ │ └── unsubscribe/
│ │ │ │ └── [token]/
│ │ │ │ └── page.tsx
│ │ │ ├── (dashboard)/
│ │ │ │ ├── account/
│ │ │ │ │ └── settings/
│ │ │ │ │ ├── page.tsx
│ │ │ │ │ └── security/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── auth.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ ├── messages/
│ │ │ │ │ ├── [programSlug]/
│ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── layout.tsx
│ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── payouts/
│ │ │ │ │ ├── page.tsx
│ │ │ │ │ ├── partner-payout-details-sheet.tsx
│ │ │ │ │ ├── partner-payout-settings-button.tsx
│ │ │ │ │ ├── partner-payout-settings-sheet.tsx
│ │ │ │ │ ├── payout-stats.tsx
│ │ │ │ │ ├── payout-table.tsx
│ │ │ │ │ └── use-payout-filters.tsx
│ │ │ │ ├── profile/
│ │ │ │ │ ├── about-you-form.tsx
│ │ │ │ │ ├── how-you-work-form.tsx
│ │ │ │ │ ├── industry-interests-modal.tsx
│ │ │ │ │ ├── members/
│ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── notifications/
│ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ ├── page.tsx
│ │ │ │ │ ├── postbacks/
│ │ │ │ │ │ ├── [id]/
│ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── add-postback-button.tsx
│ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── profile-details-form.tsx
│ │ │ │ │ ├── profile-discovery-guide.tsx
│ │ │ │ │ ├── settings-row.tsx
│ │ │ │ │ └── use-partner-discovery-requirements.ts
│ │ │ │ ├── programs/
│ │ │ │ │ ├── [programSlug]/
│ │ │ │ │ │ ├── (enrolled)/
│ │ │ │ │ │ │ ├── analytics/
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── auth.tsx
│ │ │ │ │ │ │ ├── bounties/
│ │ │ │ │ │ │ │ ├── [bountyId]/
│ │ │ │ │ │ │ │ │ ├── bounty-performance-section.tsx
│ │ │ │ │ │ │ │ │ ├── bounty-submissions-table.tsx
│ │ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ ├── bounty-card.tsx
│ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── customers/
│ │ │ │ │ │ │ │ ├── (index)/
│ │ │ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ │ │ ├── referrals/
│ │ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ │ └── use-partner-customer-filters.tsx
│ │ │ │ │ │ │ │ └── [customerId]/
│ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── earnings/
│ │ │ │ │ │ │ │ ├── earnings-composite-chart.tsx
│ │ │ │ │ │ │ │ ├── earnings-table.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── events/
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── hide-program-details-button.tsx
│ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ ├── links/
│ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ │ ├── partner-link-card.tsx
│ │ │ │ │ │ │ │ └── partner-link-controls.tsx
│ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ ├── payouts-card.tsx
│ │ │ │ │ │ │ ├── resources/
│ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── share-earnings-modal.tsx
│ │ │ │ │ │ │ └── unapproved-program-page.tsx
│ │ │ │ │ │ ├── apply/
│ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ └── program-sidebar.tsx
│ │ │ │ │ │ └── invite/
│ │ │ │ │ │ ├── accept-program-invite-button.tsx
│ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ └── program-invite-confetti.tsx
│ │ │ │ │ ├── invitations/
│ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── marketplace/
│ │ │ │ │ │ ├── [programSlug]/
│ │ │ │ │ │ │ ├── header-controls.tsx
│ │ │ │ │ │ │ ├── loading.tsx
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── featured-program-card.tsx
│ │ │ │ │ │ ├── featured-programs.tsx
│ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ ├── marketplace-empty-state.tsx
│ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ ├── program-card.tsx
│ │ │ │ │ │ ├── program-sort.tsx
│ │ │ │ │ │ ├── program-status-badge.tsx
│ │ │ │ │ │ └── use-program-network-filters.tsx
│ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ └── page.tsx
│ │ │ │ └── rewind/
│ │ │ │ └── 2025/
│ │ │ │ ├── conclusion.tsx
│ │ │ │ ├── intro.tsx
│ │ │ │ ├── page-client.tsx
│ │ │ │ ├── page.tsx
│ │ │ │ ├── rewind.tsx
│ │ │ │ └── share-rewind-modal.tsx
│ │ │ ├── (onboarding)/
│ │ │ │ ├── layout.tsx
│ │ │ │ └── onboarding/
│ │ │ │ ├── onboarding-form.tsx
│ │ │ │ ├── page.tsx
│ │ │ │ ├── payouts/
│ │ │ │ │ ├── page.tsx
│ │ │ │ │ └── payout-provider.tsx
│ │ │ │ └── platforms/
│ │ │ │ ├── page-client.tsx
│ │ │ │ └── page.tsx
│ │ │ ├── (redirects)/
│ │ │ │ └── apply/
│ │ │ │ └── [programSlug]/
│ │ │ │ └── [[...slug]]/
│ │ │ │ └── page.tsx
│ │ │ ├── invoices/
│ │ │ │ └── [payoutId]/
│ │ │ │ └── route.tsx
│ │ │ └── layout.tsx
│ │ ├── [domain]/
│ │ │ ├── browser-graphic.tsx
│ │ │ ├── layout.tsx
│ │ │ ├── not-found/
│ │ │ │ └── page.tsx
│ │ │ ├── page.tsx
│ │ │ ├── placeholder.tsx
│ │ │ └── stats/
│ │ │ └── [key]/
│ │ │ └── page.tsx
│ │ ├── api/
│ │ │ ├── (old)/
│ │ │ │ └── projects/
│ │ │ │ ├── [slug]/
│ │ │ │ │ ├── domains/
│ │ │ │ │ │ ├── [domain]/
│ │ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ │ └── verify/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── default/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── links/
│ │ │ │ │ │ ├── [linkId]/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── bulk/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── count/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── info/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── random/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── route.ts
│ │ │ │ │ └── tags/
│ │ │ │ │ ├── [id]/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── route.ts
│ │ │ │ └── route.ts
│ │ │ ├── activity-logs/
│ │ │ │ └── route.ts
│ │ │ ├── ai/
│ │ │ │ ├── completion/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── support-chat/
│ │ │ │ │ ├── route.ts
│ │ │ │ │ └── upload/
│ │ │ │ │ └── route.ts
│ │ │ │ └── sync-embeddings/
│ │ │ │ ├── fetch-plausible-pageviews.ts
│ │ │ │ └── route.ts
│ │ │ ├── analytics/
│ │ │ │ ├── [eventType]/
│ │ │ │ │ ├── [endpoint]/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── route.ts
│ │ │ │ ├── dashboard/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── export/
│ │ │ │ │ └── route.ts
│ │ │ │ └── route.ts
│ │ │ ├── auth/
│ │ │ │ ├── [...nextauth]/
│ │ │ │ │ └── route.tsx
│ │ │ │ └── reset-password/
│ │ │ │ └── route.ts
│ │ │ ├── callback/
│ │ │ │ ├── bitly/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── plain/
│ │ │ │ │ ├── partner/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── utils.ts
│ │ │ │ │ └── workspace/
│ │ │ │ │ └── route.ts
│ │ │ │ └── stripe/
│ │ │ │ └── route.ts
│ │ │ ├── dashboards/
│ │ │ │ ├── [id]/
│ │ │ │ │ └── route.ts
│ │ │ │ └── route.ts
│ │ │ ├── docs/
│ │ │ │ └── guides/
│ │ │ │ └── [guide]/
│ │ │ │ └── route.ts
│ │ │ ├── domains/
│ │ │ │ ├── [domain]/
│ │ │ │ │ ├── primary/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── route.ts
│ │ │ │ │ ├── transfer/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── validate/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── verify/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── client/
│ │ │ │ │ ├── register/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── saved/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── count/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── default/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── route.ts
│ │ │ │ └── search-availability/
│ │ │ │ └── route.ts
│ │ │ ├── dub/
│ │ │ │ └── webhook/
│ │ │ │ ├── lead-created.ts
│ │ │ │ ├── route.ts
│ │ │ │ └── sale-created.ts
│ │ │ ├── folders/
│ │ │ │ ├── [folderId]/
│ │ │ │ │ ├── dashboard/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── route.ts
│ │ │ │ │ └── users/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── access-requests/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── count/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── permissions/
│ │ │ │ │ └── route.ts
│ │ │ │ └── route.ts
│ │ │ ├── integrations/
│ │ │ │ ├── route.ts
│ │ │ │ └── uninstall/
│ │ │ │ └── route.ts
│ │ │ ├── links/
│ │ │ │ ├── [linkId]/
│ │ │ │ │ ├── dashboard/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── route.ts
│ │ │ │ │ └── transfer/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── bulk/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── count/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── exists/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── export/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── iframeable/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── info/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── metatags/
│ │ │ │ │ ├── route.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── random/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── route.ts
│ │ │ │ ├── sync/
│ │ │ │ │ └── route.ts
│ │ │ │ └── upsert/
│ │ │ │ └── route.ts
│ │ │ ├── me/
│ │ │ │ └── route.ts
│ │ │ ├── misc/
│ │ │ │ ├── check-favicon/
│ │ │ │ │ └── route.ts
│ │ │ │ └── check-workspace-slug/
│ │ │ │ └── route.ts
│ │ │ ├── oauth/
│ │ │ │ ├── apps/
│ │ │ │ │ ├── [appId]/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── route.ts
│ │ │ │ ├── authorize/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── token/
│ │ │ │ │ ├── exchange-code-for-token.ts
│ │ │ │ │ ├── refresh-access-token.ts
│ │ │ │ │ └── route.ts
│ │ │ │ └── userinfo/
│ │ │ │ └── route.ts
│ │ │ ├── og/
│ │ │ │ ├── analytics/
│ │ │ │ │ └── route.tsx
│ │ │ │ ├── avatar/
│ │ │ │ │ └── [[...seed]]/
│ │ │ │ │ └── route.tsx
│ │ │ │ ├── load-google-font.ts
│ │ │ │ ├── partner-earnings/
│ │ │ │ │ └── route.tsx
│ │ │ │ ├── partner-rewind/
│ │ │ │ │ └── route.tsx
│ │ │ │ └── program/
│ │ │ │ └── route.tsx
│ │ │ ├── postbacks/
│ │ │ │ └── callback/
│ │ │ │ └── route.ts
│ │ │ ├── providers/
│ │ │ │ └── route.ts
│ │ │ ├── qr/
│ │ │ │ └── route.tsx
│ │ │ ├── resend/
│ │ │ │ └── webhook/
│ │ │ │ ├── email-bounced.ts
│ │ │ │ ├── email-delivered.ts
│ │ │ │ ├── email-opened.ts
│ │ │ │ └── route.ts
│ │ │ ├── resumes/
│ │ │ │ └── upload-url/
│ │ │ │ └── route.ts
│ │ │ ├── route.ts
│ │ │ ├── slack/
│ │ │ │ ├── callback/
│ │ │ │ │ └── route.ts
│ │ │ │ └── slash-commands/
│ │ │ │ └── route.ts
│ │ │ ├── supported-countries/
│ │ │ │ └── route.ts
│ │ │ ├── tags/
│ │ │ │ ├── [id]/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── count/
│ │ │ │ │ └── route.ts
│ │ │ │ └── route.ts
│ │ │ ├── tokens/
│ │ │ │ ├── [id]/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── embed/
│ │ │ │ │ └── referrals/
│ │ │ │ │ └── route.ts
│ │ │ │ └── route.ts
│ │ │ ├── unsplash/
│ │ │ │ ├── download/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── search/
│ │ │ │ │ └── route.ts
│ │ │ │ └── utils.ts
│ │ │ ├── user/
│ │ │ │ ├── notification-preferences/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── password/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── referrals-token/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── route.ts
│ │ │ │ ├── set-password/
│ │ │ │ │ └── route.ts
│ │ │ │ └── tokens/
│ │ │ │ └── route.ts
│ │ │ ├── utm/
│ │ │ │ ├── [id]/
│ │ │ │ │ └── route.ts
│ │ │ │ └── route.ts
│ │ │ ├── webhooks/
│ │ │ │ ├── [webhookId]/
│ │ │ │ │ ├── events/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── route.ts
│ │ │ │ ├── callback/
│ │ │ │ │ └── route.ts
│ │ │ │ └── route.ts
│ │ │ └── workspaces/
│ │ │ ├── [idOrSlug]/
│ │ │ │ ├── billing/
│ │ │ │ │ ├── cancel/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── invoices/
│ │ │ │ │ │ ├── [invoiceId]/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── manage/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── payment-methods/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── upgrade/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── usage/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── import/
│ │ │ │ │ ├── [importId]/
│ │ │ │ │ │ └── download/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── bitly/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── csv/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── rebrandly/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── short/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── invites/
│ │ │ │ │ ├── accept/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── decline/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── reset/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── route.ts
│ │ │ │ ├── notification-preferences/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── route.ts
│ │ │ │ ├── saml/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── scim/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── stats/
│ │ │ │ │ └── [endpoint]/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── upload-url/
│ │ │ │ │ └── route.ts
│ │ │ │ └── users/
│ │ │ │ └── route.ts
│ │ │ └── route.ts
│ │ ├── app.dub.co/
│ │ │ ├── (auth)/
│ │ │ │ ├── auth/
│ │ │ │ │ ├── confirm-email-change/
│ │ │ │ │ │ └── [token]/
│ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── reset-password/
│ │ │ │ │ │ └── [token]/
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ └── saml/
│ │ │ │ │ ├── form.tsx
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── customer-logos.tsx
│ │ │ │ ├── forgot-password/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── invites/
│ │ │ │ │ └── [code]/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ ├── login/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── oauth/
│ │ │ │ │ └── authorize/
│ │ │ │ │ ├── authorize-form.tsx
│ │ │ │ │ ├── loading.tsx
│ │ │ │ │ ├── page.tsx
│ │ │ │ │ └── scopes-requested.tsx
│ │ │ │ ├── register/
│ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── side-panel.tsx
│ │ │ │ └── unsubscribe/
│ │ │ │ └── [token]/
│ │ │ │ ├── page.tsx
│ │ │ │ └── unsubscribe-form.tsx
│ │ │ ├── (dashboard)/
│ │ │ │ ├── [slug]/
│ │ │ │ │ ├── (ee)/
│ │ │ │ │ │ ├── customers/
│ │ │ │ │ │ │ ├── [customerId]/
│ │ │ │ │ │ │ │ ├── earnings/
│ │ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ │ └── sales/
│ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── events/
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── program/
│ │ │ │ │ │ │ ├── analytics/
│ │ │ │ │ │ │ │ ├── analytics-chart.tsx
│ │ │ │ │ │ │ │ ├── analytics-partners-table.tsx
│ │ │ │ │ │ │ │ ├── analytics-timeseries-chart.tsx
│ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ │ └── partner-analytics-filter-cell.tsx
│ │ │ │ │ │ │ ├── auth.tsx
│ │ │ │ │ │ │ ├── bounties/
│ │ │ │ │ │ │ │ ├── [bountyId]/
│ │ │ │ │ │ │ │ │ ├── bounty-header.tsx
│ │ │ │ │ │ │ │ │ ├── bounty-info.tsx
│ │ │ │ │ │ │ │ │ ├── bounty-submission-details-sheet.tsx
│ │ │ │ │ │ │ │ │ ├── bounty-submission-row-menu.tsx
│ │ │ │ │ │ │ │ │ ├── bounty-submissions-table.tsx
│ │ │ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ │ │ └── use-bounty-submission-filters.tsx
│ │ │ │ │ │ │ │ ├── add-edit-bounty/
│ │ │ │ │ │ │ │ │ ├── add-edit-bounty-sheet.tsx
│ │ │ │ │ │ │ │ │ ├── bounty-amount-input.tsx
│ │ │ │ │ │ │ │ │ ├── bounty-criteria-manual-submission.tsx
│ │ │ │ │ │ │ │ │ ├── bounty-criteria-social-metrics.tsx
│ │ │ │ │ │ │ │ │ ├── bounty-criteria.tsx
│ │ │ │ │ │ │ │ │ ├── bounty-form-context.tsx
│ │ │ │ │ │ │ │ │ ├── bounty-logic.tsx
│ │ │ │ │ │ │ │ │ ├── confirm-create-bounty-modal.tsx
│ │ │ │ │ │ │ │ │ └── use-add-edit-bounty-form.ts
│ │ │ │ │ │ │ │ ├── bounty-action-button.tsx
│ │ │ │ │ │ │ │ ├── bounty-card.tsx
│ │ │ │ │ │ │ │ ├── bounty-list.tsx
│ │ │ │ │ │ │ │ ├── create-bounty-button.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── campaigns/
│ │ │ │ │ │ │ │ ├── [campaignId]/
│ │ │ │ │ │ │ │ │ ├── campaign-action-bar.tsx
│ │ │ │ │ │ │ │ │ ├── campaign-controls.tsx
│ │ │ │ │ │ │ │ │ ├── campaign-editor-skeleton.tsx
│ │ │ │ │ │ │ │ │ ├── campaign-editor.tsx
│ │ │ │ │ │ │ │ │ ├── campaign-events-columns.tsx
│ │ │ │ │ │ │ │ │ ├── campaign-events-modal.tsx
│ │ │ │ │ │ │ │ │ ├── campaign-events.tsx
│ │ │ │ │ │ │ │ │ ├── campaign-form-context.tsx
│ │ │ │ │ │ │ │ │ ├── campaign-groups-selector.tsx
│ │ │ │ │ │ │ │ │ ├── campaign-metrics.tsx
│ │ │ │ │ │ │ │ │ ├── duplicate-logic-warning.tsx
│ │ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ │ │ ├── send-email-preview-modal.tsx
│ │ │ │ │ │ │ │ │ ├── transactional-campaign-logic.tsx
│ │ │ │ │ │ │ │ │ ├── use-campaign-confirmation-modals.tsx
│ │ │ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ │ │ ├── campaign-stats.tsx
│ │ │ │ │ │ │ │ ├── campaign-status-badges.tsx
│ │ │ │ │ │ │ │ ├── campaign-type-badges.tsx
│ │ │ │ │ │ │ │ ├── campaign-type-icon.tsx
│ │ │ │ │ │ │ │ ├── campaigns-page-content.tsx
│ │ │ │ │ │ │ │ ├── campaigns-table.tsx
│ │ │ │ │ │ │ │ ├── campaigns-upsell.tsx
│ │ │ │ │ │ │ │ ├── create-campaign-button.tsx
│ │ │ │ │ │ │ │ ├── delete-campaign-modal.tsx
│ │ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ │ ├── use-campaign.tsx
│ │ │ │ │ │ │ │ ├── use-campaigns-count.tsx
│ │ │ │ │ │ │ │ └── use-campaigns-filters.tsx
│ │ │ │ │ │ │ ├── coming-soon-page.tsx
│ │ │ │ │ │ │ ├── commissions/
│ │ │ │ │ │ │ │ ├── [commissionId]/
│ │ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ ├── commission-popover-buttons.tsx
│ │ │ │ │ │ │ │ ├── commissions-stats.tsx
│ │ │ │ │ │ │ │ ├── commissions-table.tsx
│ │ │ │ │ │ │ │ ├── create-clawback-sheet.tsx
│ │ │ │ │ │ │ │ ├── create-commission-button.tsx
│ │ │ │ │ │ │ │ ├── create-commission-sheet.tsx
│ │ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ │ └── use-commission-filters.tsx
│ │ │ │ │ │ │ ├── customers/
│ │ │ │ │ │ │ │ ├── (index)/
│ │ │ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ │ │ └── referrals/
│ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ ├── [customerId]/
│ │ │ │ │ │ │ │ │ ├── earnings/
│ │ │ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ │ │ └── sales/
│ │ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ └── customers-dropdown-menu.tsx
│ │ │ │ │ │ │ ├── fraud/
│ │ │ │ │ │ │ │ ├── example-fraud-events.tsx
│ │ │ │ │ │ │ │ ├── fraud-group-table.tsx
│ │ │ │ │ │ │ │ ├── fraud-paid-traffic-settings.tsx
│ │ │ │ │ │ │ │ ├── fraud-referral-source-settings.tsx
│ │ │ │ │ │ │ │ ├── fraud-rule-toggle-settings.tsx
│ │ │ │ │ │ │ │ ├── fraud-upsell.tsx
│ │ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ │ ├── program-fraud-actions-menu.tsx
│ │ │ │ │ │ │ │ ├── program-fraud-settings-button.tsx
│ │ │ │ │ │ │ │ ├── program-fraud-settings-sheet.tsx
│ │ │ │ │ │ │ │ ├── resolved/
│ │ │ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ │ │ └── resolved-fraud-group-table.tsx
│ │ │ │ │ │ │ │ └── use-fraud-group-filters.tsx
│ │ │ │ │ │ │ ├── groups/
│ │ │ │ │ │ │ │ ├── [groupSlug]/
│ │ │ │ │ │ │ │ │ ├── branding/
│ │ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ │ ├── discounts/
│ │ │ │ │ │ │ │ │ │ ├── group-discounts.tsx
│ │ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ │ ├── group-header.tsx
│ │ │ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ │ │ ├── links/
│ │ │ │ │ │ │ │ │ │ ├── add-edit-group-additional-link-modal.tsx
│ │ │ │ │ │ │ │ │ │ ├── add-edit-group-default-link-sheet.tsx
│ │ │ │ │ │ │ │ │ │ ├── change-program-domain-modal.tsx
│ │ │ │ │ │ │ │ │ │ ├── group-additional-links.tsx
│ │ │ │ │ │ │ │ │ │ ├── group-default-links.tsx
│ │ │ │ │ │ │ │ │ │ ├── group-link-settings.tsx
│ │ │ │ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ │ │ │ └── partner-link-preview.tsx
│ │ │ │ │ │ │ │ │ ├── rewards/
│ │ │ │ │ │ │ │ │ │ ├── group-rewards.tsx
│ │ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ │ └── settings/
│ │ │ │ │ │ │ │ │ ├── group-additional-settings.tsx
│ │ │ │ │ │ │ │ │ ├── group-move-rules.tsx
│ │ │ │ │ │ │ │ │ ├── group-settings.tsx
│ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ ├── create-group-button.tsx
│ │ │ │ │ │ │ │ ├── create-group-modal.tsx
│ │ │ │ │ │ │ │ ├── groups-table.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ ├── messages/
│ │ │ │ │ │ │ │ ├── [partnerId]/
│ │ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ │ ├── messages-disabled.tsx
│ │ │ │ │ │ │ │ ├── messages-upsell.tsx
│ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── network/
│ │ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ │ ├── network-empty-state.tsx
│ │ │ │ │ │ │ │ ├── network-upsell.tsx
│ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ │ └── use-partner-network-filters.tsx
│ │ │ │ │ │ │ ├── overview-chart.tsx
│ │ │ │ │ │ │ ├── overview-links.tsx
│ │ │ │ │ │ │ ├── overview-tasks.tsx
│ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ ├── partners/
│ │ │ │ │ │ │ │ ├── [partnerId]/
│ │ │ │ │ │ │ │ │ ├── comments/
│ │ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ │ ├── customers/
│ │ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ │ │ ├── links/
│ │ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ │ ├── partner-nav.tsx
│ │ │ │ │ │ │ │ │ ├── partner-stats.tsx
│ │ │ │ │ │ │ │ │ └── payouts/
│ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ ├── applications/
│ │ │ │ │ │ │ │ │ ├── applications-menu.tsx
│ │ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ │ │ └── rejected/
│ │ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ ├── import-export-buttons.tsx
│ │ │ │ │ │ │ │ ├── invite-partner-button.tsx
│ │ │ │ │ │ │ │ ├── invite-partner-sheet.tsx
│ │ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ │ ├── partners-table.tsx
│ │ │ │ │ │ │ │ └── use-partner-filters.tsx
│ │ │ │ │ │ │ ├── partners-graphic.tsx
│ │ │ │ │ │ │ ├── partners-upgrade-cta.tsx
│ │ │ │ │ │ │ ├── payouts/
│ │ │ │ │ │ │ │ ├── [payoutId]/
│ │ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ │ ├── payout-paid-cell.tsx
│ │ │ │ │ │ │ │ ├── payout-stats.tsx
│ │ │ │ │ │ │ │ ├── payout-table.tsx
│ │ │ │ │ │ │ │ ├── program-payout-methods.tsx
│ │ │ │ │ │ │ │ ├── program-payout-mode-section.tsx
│ │ │ │ │ │ │ │ ├── program-payout-settings-button.tsx
│ │ │ │ │ │ │ │ ├── program-payout-settings-sheet.tsx
│ │ │ │ │ │ │ │ ├── success/
│ │ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ └── use-payout-filters.tsx
│ │ │ │ │ │ │ ├── program-settings-row.tsx
│ │ │ │ │ │ │ └── resources/
│ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ ├── program-brand-assets/
│ │ │ │ │ │ │ │ ├── add-color-modal.tsx
│ │ │ │ │ │ │ │ ├── add-file-modal.tsx
│ │ │ │ │ │ │ │ ├── add-link-modal.tsx
│ │ │ │ │ │ │ │ ├── add-logo-modal.tsx
│ │ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ │ └── use-upload-program-resource.ts
│ │ │ │ │ │ │ └── program-help-and-support.tsx
│ │ │ │ │ │ └── settings/
│ │ │ │ │ │ ├── billing/
│ │ │ │ │ │ │ ├── invoices/
│ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ ├── payment-method-types.ts
│ │ │ │ │ │ │ ├── payment-methods.tsx
│ │ │ │ │ │ │ ├── plan-usage.tsx
│ │ │ │ │ │ │ ├── upgrade/
│ │ │ │ │ │ │ │ ├── adjust-usage-row.tsx
│ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ └── usage-chart.tsx
│ │ │ │ │ │ ├── domains/
│ │ │ │ │ │ │ ├── default/
│ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── email/
│ │ │ │ │ │ │ │ ├── constants.ts
│ │ │ │ │ │ │ │ ├── email-domain-card.tsx
│ │ │ │ │ │ │ │ ├── email-domain-dns-records.tsx
│ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── header.tsx
│ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── integrations/
│ │ │ │ │ │ │ ├── [integrationSlug]/
│ │ │ │ │ │ │ │ ├── loading.tsx
│ │ │ │ │ │ │ │ ├── manage/
│ │ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── enabled/
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── enabled-integrations.tsx
│ │ │ │ │ │ │ ├── featured-integrations.tsx
│ │ │ │ │ │ │ ├── integrations-cards.tsx
│ │ │ │ │ │ │ ├── integrations-list.tsx
│ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ ├── new/
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── members/
│ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── notifications/
│ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── oauth-apps/
│ │ │ │ │ │ │ ├── [appId]/
│ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── create-oauth-app-button.tsx
│ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ ├── new/
│ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ ├── security/
│ │ │ │ │ │ │ ├── audit-logs.tsx
│ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ ├── saml.tsx
│ │ │ │ │ │ │ └── scim.tsx
│ │ │ │ │ │ ├── tokens/
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── tracking/
│ │ │ │ │ │ │ ├── add-hostname-modal.tsx
│ │ │ │ │ │ │ ├── base-script-section.tsx
│ │ │ │ │ │ │ ├── complete-step-button.tsx
│ │ │ │ │ │ │ ├── connection-instructions.tsx
│ │ │ │ │ │ │ ├── conversion-tracking-section.tsx
│ │ │ │ │ │ │ ├── conversion-tracking-toggle.tsx
│ │ │ │ │ │ │ ├── guide.tsx
│ │ │ │ │ │ │ ├── hostname-menu.tsx
│ │ │ │ │ │ │ ├── hostname-section.tsx
│ │ │ │ │ │ │ ├── outbound-domain-tracking-section.tsx
│ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ ├── publishable-key-form.tsx
│ │ │ │ │ │ │ ├── publishable-key-menu.tsx
│ │ │ │ │ │ │ ├── site-visit-tracking-section.tsx
│ │ │ │ │ │ │ ├── step.tsx
│ │ │ │ │ │ │ ├── track-lead-guides-section.tsx
│ │ │ │ │ │ │ ├── track-sales-guides-section.tsx
│ │ │ │ │ │ │ ├── use-dynamic-guide.ts
│ │ │ │ │ │ │ ├── use-selected-guide.ts
│ │ │ │ │ │ │ └── verify-install.tsx
│ │ │ │ │ │ └── webhooks/
│ │ │ │ │ │ ├── [webhookId]/
│ │ │ │ │ │ │ ├── edit/
│ │ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── create-webhook-button.tsx
│ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ ├── new/
│ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── analytics/
│ │ │ │ │ │ ├── client.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── auth.tsx
│ │ │ │ │ ├── layout.tsx
│ │ │ │ │ └── links/
│ │ │ │ │ ├── [...link]/
│ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── domains/
│ │ │ │ │ │ ├── default/
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── email/
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── folders/
│ │ │ │ │ │ ├── [folderId]/
│ │ │ │ │ │ │ └── members/
│ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ ├── page.tsx
│ │ │ │ │ ├── tags/
│ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ ├── tag-card-placeholder.tsx
│ │ │ │ │ │ └── tag-card.tsx
│ │ │ │ │ └── utm/
│ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ ├── page.tsx
│ │ │ │ │ ├── template-card-placeholder.tsx
│ │ │ │ │ └── template-card.tsx
│ │ │ │ ├── account/
│ │ │ │ │ └── settings/
│ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ ├── page.tsx
│ │ │ │ │ ├── referrals/
│ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── security/
│ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ ├── request-set-password.tsx
│ │ │ │ │ │ └── update-password.tsx
│ │ │ │ │ └── tokens/
│ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ └── loading.tsx
│ │ │ ├── (deeplink)/
│ │ │ │ └── deeplink/
│ │ │ │ └── [domain]/
│ │ │ │ └── [[...key]]/
│ │ │ │ ├── action-buttons.tsx
│ │ │ │ ├── brand-logo-badge.tsx
│ │ │ │ ├── page.tsx
│ │ │ │ └── translations.ts
│ │ │ ├── (invites)/
│ │ │ │ ├── [slug]/
│ │ │ │ │ └── invite/
│ │ │ │ │ ├── accept-invite-button.tsx
│ │ │ │ │ ├── close-invite-button.tsx
│ │ │ │ │ ├── invite-confetti.tsx
│ │ │ │ │ └── page.tsx
│ │ │ │ └── layout.tsx
│ │ │ ├── (onboarding)/
│ │ │ │ ├── [slug]/
│ │ │ │ │ └── wrapped/
│ │ │ │ │ ├── [year]/
│ │ │ │ │ │ ├── client.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ ├── onboarding/
│ │ │ │ │ ├── (steps)/
│ │ │ │ │ │ ├── domain/
│ │ │ │ │ │ │ ├── custom/
│ │ │ │ │ │ │ │ ├── form.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── default-domain-selector.tsx
│ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ └── register/
│ │ │ │ │ │ │ ├── form.tsx
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── layout.tsx
│ │ │ │ │ │ ├── plan/
│ │ │ │ │ │ │ ├── enterprise-link.tsx
│ │ │ │ │ │ │ ├── free-plan-button.tsx
│ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ └── plan-selector.tsx
│ │ │ │ │ │ ├── products/
│ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ └── product-selector.tsx
│ │ │ │ │ │ ├── program/
│ │ │ │ │ │ │ ├── form.tsx
│ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ ├── reward/
│ │ │ │ │ │ │ │ ├── form.tsx
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ └── use-onboarding-program.tsx
│ │ │ │ │ │ ├── step-page.tsx
│ │ │ │ │ │ ├── success/
│ │ │ │ │ │ │ ├── page-client.tsx
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ └── workspace/
│ │ │ │ │ │ ├── form.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── later-button.tsx
│ │ │ │ │ ├── next-button.tsx
│ │ │ │ │ ├── use-onboarding-product.ts
│ │ │ │ │ ├── use-onboarding-progress.ts
│ │ │ │ │ └── welcome/
│ │ │ │ │ ├── page.tsx
│ │ │ │ │ └── track-signup.tsx
│ │ │ │ └── signed-in-hint.tsx
│ │ │ ├── (redirects)/
│ │ │ │ ├── [slug]/
│ │ │ │ │ ├── domains/
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ └── settings/
│ │ │ │ │ ├── referrals/
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ └── tags/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── analytics/
│ │ │ │ │ └── page.tsx
│ │ │ │ └── loading.tsx
│ │ │ ├── (share)/
│ │ │ │ └── share/
│ │ │ │ └── [dashboardId]/
│ │ │ │ ├── action.ts
│ │ │ │ ├── form.tsx
│ │ │ │ └── page.tsx
│ │ │ ├── embed/
│ │ │ │ └── support-chat/
│ │ │ │ ├── dynamic-height-messenger.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ └── page.tsx
│ │ │ └── layout.tsx
│ │ ├── banned/
│ │ │ └── page.tsx
│ │ ├── cloaked/
│ │ │ └── [url]/
│ │ │ └── page.tsx
│ │ ├── custom-uri-scheme/
│ │ │ └── [url]/
│ │ │ └── page.tsx
│ │ ├── expired/
│ │ │ └── [domain]/
│ │ │ └── page.tsx
│ │ ├── inspect/
│ │ │ └── [domain]/
│ │ │ └── [key]/
│ │ │ ├── card.tsx
│ │ │ └── page.tsx
│ │ ├── layout.tsx
│ │ ├── manifest.ts
│ │ ├── not-found-hint.tsx
│ │ ├── not-found.tsx
│ │ ├── password/
│ │ │ └── [linkId]/
│ │ │ ├── action.ts
│ │ │ ├── form.tsx
│ │ │ ├── loading.tsx
│ │ │ └── page.tsx
│ │ ├── providers.tsx
│ │ ├── proxy/
│ │ │ └── [domain]/
│ │ │ └── [key]/
│ │ │ └── page.tsx
│ │ ├── robots.ts
│ │ ├── sitemap.ts
│ │ └── wellknown/
│ │ └── [domain]/
│ │ └── [file]/
│ │ └── route.ts
│ ├── docker-compose.yml
│ ├── global-setup.ts
│ ├── guides/
│ │ ├── appwrite.md
│ │ ├── auth0.md
│ │ ├── better-auth.md
│ │ ├── clerk.md
│ │ ├── framer.md
│ │ ├── gtm-client-sdk.md
│ │ ├── gtm-track-lead.md
│ │ ├── gtm-track-sale.md
│ │ ├── manual-client-sdk.md
│ │ ├── manual-track-lead.md
│ │ ├── manual-track-sale.md
│ │ ├── next-auth.md
│ │ ├── react.md
│ │ ├── rest-api.md
│ │ ├── segment-track-lead.md
│ │ ├── segment-track-sale.md
│ │ ├── shopify.md
│ │ ├── stripe-checkout.md
│ │ ├── stripe-customers.md
│ │ ├── stripe-payment-links.md
│ │ ├── supabase.md
│ │ ├── webflow.md
│ │ └── wordpress.md
│ ├── instrumentation.ts
│ ├── lib/
│ │ ├── actions/
│ │ │ ├── add-edit-integration.ts
│ │ │ ├── auth/
│ │ │ │ └── throw-if-authenticated.ts
│ │ │ ├── check-account-exists.ts
│ │ │ ├── create-oauth-url.ts
│ │ │ ├── create-user-account.ts
│ │ │ ├── enable-disable-webhook.ts
│ │ │ ├── folders/
│ │ │ │ ├── request-folder-edit-access.ts
│ │ │ │ ├── set-default-folder.ts
│ │ │ │ └── update-folder-user-role.ts
│ │ │ ├── fraud/
│ │ │ │ ├── bulk-resolve-fraud-groups.ts
│ │ │ │ └── resolve-fraud-group.ts
│ │ │ ├── generate-client-secret.ts
│ │ │ ├── generate-unsubscribe-url.ts
│ │ │ ├── get-integration-install-url.ts
│ │ │ ├── parse-action-errors.ts
│ │ │ ├── partners/
│ │ │ │ ├── accept-program-invite.ts
│ │ │ │ ├── approve-bounty-submission.ts
│ │ │ │ ├── approve-partner.ts
│ │ │ │ ├── archive-partner.ts
│ │ │ │ ├── ban-partner.ts
│ │ │ │ ├── bulk-approve-partners.ts
│ │ │ │ ├── bulk-archive-partners.ts
│ │ │ │ ├── bulk-ban-partners.ts
│ │ │ │ ├── bulk-deactivate-partners.ts
│ │ │ │ ├── bulk-invite-partners.ts
│ │ │ │ ├── bulk-reject-partner-applications.ts
│ │ │ │ ├── confirm-payouts.ts
│ │ │ │ ├── create-bounty-submission.ts
│ │ │ │ ├── create-clawback.ts
│ │ │ │ ├── create-discount.ts
│ │ │ │ ├── create-manual-commission.ts
│ │ │ │ ├── create-partner-comment.ts
│ │ │ │ ├── create-program-application.ts
│ │ │ │ ├── create-program.ts
│ │ │ │ ├── create-reward.ts
│ │ │ │ ├── deactivate-partner.ts
│ │ │ │ ├── delete-discount.ts
│ │ │ │ ├── delete-partner-comment.ts
│ │ │ │ ├── delete-program-invite.ts
│ │ │ │ ├── delete-reward.ts
│ │ │ │ ├── force-withdrawal.ts
│ │ │ │ ├── generate-lander.ts
│ │ │ │ ├── generate-paypal-oauth-url.ts
│ │ │ │ ├── generate-stripe-account-link.ts
│ │ │ │ ├── generate-stripe-recipient-account-link.ts
│ │ │ │ ├── get-conversion-score.ts
│ │ │ │ ├── invite-partner-from-network.ts
│ │ │ │ ├── invite-partner.ts
│ │ │ │ ├── mark-commission-duplicate.ts
│ │ │ │ ├── mark-commission-fraud-or-canceled.ts
│ │ │ │ ├── mark-partner-messages-read.ts
│ │ │ │ ├── mark-program-messages-read.ts
│ │ │ │ ├── merge-partner-accounts.ts
│ │ │ │ ├── message-partner.ts
│ │ │ │ ├── message-program.ts
│ │ │ │ ├── onboard-partner.ts
│ │ │ │ ├── onboard-program.ts
│ │ │ │ ├── program-resources/
│ │ │ │ │ ├── add-program-resource.ts
│ │ │ │ │ ├── constants.ts
│ │ │ │ │ ├── delete-program-resource.ts
│ │ │ │ │ ├── get-program-resource-upload-url.ts
│ │ │ │ │ └── update-program-resource.ts
│ │ │ │ ├── reactivate-partner.ts
│ │ │ │ ├── reject-bounty-submission.ts
│ │ │ │ ├── reject-partner-application.ts
│ │ │ │ ├── reopen-bounty-submission.ts
│ │ │ │ ├── resend-program-invite.ts
│ │ │ │ ├── retry-failed-paypal-payouts.ts
│ │ │ │ ├── revoke-program-invite.ts
│ │ │ │ ├── save-invite-email-data.ts
│ │ │ │ ├── set-rewardful-token.ts
│ │ │ │ ├── set-tolt-token.ts
│ │ │ │ ├── start-firstpromoter-import.ts
│ │ │ │ ├── start-partner-platform-verification.ts
│ │ │ │ ├── start-partnerstack-import.ts
│ │ │ │ ├── start-rewardful-import.ts
│ │ │ │ ├── start-tolt-import.ts
│ │ │ │ ├── trigger-aggregate-due-commissions.ts
│ │ │ │ ├── unban-partner.ts
│ │ │ │ ├── update-application-settings.ts
│ │ │ │ ├── update-discount.ts
│ │ │ │ ├── update-discovered-partner.ts
│ │ │ │ ├── update-group-branding.ts
│ │ │ │ ├── update-partner-comment.ts
│ │ │ │ ├── update-partner-enrollment.ts
│ │ │ │ ├── update-partner-notification-preference.ts
│ │ │ │ ├── update-partner-payout-settings.ts
│ │ │ │ ├── update-partner-platforms.ts
│ │ │ │ ├── update-partner-profile.ts
│ │ │ │ ├── update-program.ts
│ │ │ │ ├── update-reward.ts
│ │ │ │ ├── upload-bounty-submission-file.ts
│ │ │ │ ├── upload-campaign-image.ts
│ │ │ │ ├── upload-lander-image.ts
│ │ │ │ ├── upload-program-application-image.ts
│ │ │ │ ├── verify-partner-website.ts
│ │ │ │ ├── verify-social-account-by-code.ts
│ │ │ │ └── withdraw-partner-application.ts
│ │ │ ├── referrals/
│ │ │ │ ├── submit-referral.ts
│ │ │ │ ├── update-referral-status.ts
│ │ │ │ └── update-referral.ts
│ │ │ ├── request-password-reset.ts
│ │ │ ├── safe-action.ts
│ │ │ ├── send-invite-referral-email.ts
│ │ │ ├── send-otp.ts
│ │ │ ├── send-test-webhook.ts
│ │ │ ├── set-onboarding-progress.ts
│ │ │ ├── submit-oauth-app-for-review.ts
│ │ │ ├── throw-if-no-permission.ts
│ │ │ ├── update-workspace-notification-preference.ts
│ │ │ ├── update-workspace-preferences.ts
│ │ │ ├── update-workspace-store.ts
│ │ │ └── verify-workspace-setup.ts
│ │ ├── ai/
│ │ │ ├── build-system-prompt.ts
│ │ │ ├── create-support-ticket.ts
│ │ │ ├── find-relevant-docs.ts
│ │ │ ├── generate-csv-mapping.ts
│ │ │ ├── generate-filters.ts
│ │ │ ├── get-program-performance.ts
│ │ │ ├── get-workspace-details.ts
│ │ │ ├── request-support-ticket.ts
│ │ │ └── upsert-docs-embedding.ts
│ │ ├── analytics/
│ │ │ ├── allowed-hostnames-cache.ts
│ │ │ ├── constants.ts
│ │ │ ├── convert-currency.ts
│ │ │ ├── events-export-helpers.ts
│ │ │ ├── filter-helpers.ts
│ │ │ ├── format-date-tooltip.ts
│ │ │ ├── get-analytics.ts
│ │ │ ├── get-customer-events.ts
│ │ │ ├── get-events.ts
│ │ │ ├── get-folder-ids-to-filter.ts
│ │ │ ├── is-first-conversion.ts
│ │ │ ├── metadata-query-parser.ts
│ │ │ ├── types.ts
│ │ │ ├── utils/
│ │ │ │ ├── convert-to-csv.ts
│ │ │ │ ├── edit-query-string.ts
│ │ │ │ ├── format-utc-datetime-clickhouse.ts
│ │ │ │ ├── get-interval-data.ts
│ │ │ │ ├── get-start-end-dates.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── valid-date-range-for-plan.ts
│ │ │ └── verify-analytics-allowed-hostnames.ts
│ │ ├── api/
│ │ │ ├── activity-log/
│ │ │ │ ├── build-program-enrollment-change-set.ts
│ │ │ │ ├── get-resource-diff.ts
│ │ │ │ ├── track-activity-log.ts
│ │ │ │ └── track-reward-activity-log.ts
│ │ │ ├── audit-logs/
│ │ │ │ ├── get-audit-logs.ts
│ │ │ │ ├── record-audit-log.ts
│ │ │ │ └── schemas.ts
│ │ │ ├── campaigns/
│ │ │ │ ├── constants.ts
│ │ │ │ ├── get-campaign-events.ts
│ │ │ │ ├── get-campaign-or-throw.ts
│ │ │ │ ├── get-campaign-summary.ts
│ │ │ │ ├── schedule-campaigns.ts
│ │ │ │ └── validate-campaign.ts
│ │ │ ├── commissions/
│ │ │ │ ├── format-commissions-for-export.ts
│ │ │ │ ├── get-commissions-count.ts
│ │ │ │ └── get-commissions.ts
│ │ │ ├── conversions/
│ │ │ │ ├── track-lead.ts
│ │ │ │ └── track-sale.ts
│ │ │ ├── cors.ts
│ │ │ ├── create-downloadable-export.ts
│ │ │ ├── create-id.ts
│ │ │ ├── customers/
│ │ │ │ ├── get-customer-or-throw.ts
│ │ │ │ ├── get-customer-stripe-invoices.ts
│ │ │ │ └── transform-customer.ts
│ │ │ ├── discounts/
│ │ │ │ ├── construct-discount-code.ts
│ │ │ │ ├── create-discount-code.ts
│ │ │ │ ├── delete-discount-code.ts
│ │ │ │ └── is-discount-equivalent.ts
│ │ │ ├── domains/
│ │ │ │ ├── add-domain-vercel.ts
│ │ │ │ ├── claim-dot-link-domain.ts
│ │ │ │ ├── configure-vercel-nameservers.ts
│ │ │ │ ├── get-config-response.ts
│ │ │ │ ├── get-domain-or-throw.ts
│ │ │ │ ├── get-domain-response.ts
│ │ │ │ ├── get-email-domain-or-throw.ts
│ │ │ │ ├── is-valid-domain.ts
│ │ │ │ ├── mark-domain-deleted.ts
│ │ │ │ ├── queue-domain-update.ts
│ │ │ │ ├── remove-domain-vercel.ts
│ │ │ │ ├── transform-domain.ts
│ │ │ │ ├── utils.ts
│ │ │ │ └── verify-domain.ts
│ │ │ ├── environment.ts
│ │ │ ├── error-codes.ts
│ │ │ ├── errors.ts
│ │ │ ├── folders/
│ │ │ │ ├── delete-workspace-folders.ts
│ │ │ │ └── queue-folder-deletion.ts
│ │ │ ├── fraud/
│ │ │ │ ├── constants.ts
│ │ │ │ ├── create-fraud-events.ts
│ │ │ │ ├── define-fraud-rule.ts
│ │ │ │ ├── detect-duplicate-payout-method-fraud.ts
│ │ │ │ ├── detect-record-fraud-application.ts
│ │ │ │ ├── detect-record-fraud-event.ts
│ │ │ │ ├── execute-fraud-rule.ts
│ │ │ │ ├── get-merged-fraud-rules.ts
│ │ │ │ ├── get-partner-application-risks.ts
│ │ │ │ ├── report-cross-program-ban-to-network.ts
│ │ │ │ ├── report-fraud-to-network.ts
│ │ │ │ ├── resolve-fraud-groups.ts
│ │ │ │ ├── rules/
│ │ │ │ │ ├── check-customer-email-match.ts
│ │ │ │ │ ├── check-customer-email-suspicious.ts
│ │ │ │ │ ├── check-paid-traffic-detected.ts
│ │ │ │ │ ├── check-partner-email-domain-mismatch.ts
│ │ │ │ │ ├── check-partner-email-masked.ts
│ │ │ │ │ ├── check-partner-no-social-links.ts
│ │ │ │ │ ├── check-partner-no-verified-social-links.ts
│ │ │ │ │ └── check-referral-source-banned.ts
│ │ │ │ └── utils.ts
│ │ │ ├── get-ratelimit-for-plan.ts
│ │ │ ├── get-workspace-users.ts
│ │ │ ├── groups/
│ │ │ │ ├── find-groups-with-matching-rules.ts
│ │ │ │ ├── get-group-move-rules.ts
│ │ │ │ ├── get-group-or-throw.ts
│ │ │ │ ├── get-groups.ts
│ │ │ │ ├── move-partners-to-group.ts
│ │ │ │ ├── throw-if-invalid-group-ids.ts
│ │ │ │ ├── upsert-group-move-rules.ts
│ │ │ │ └── validate-group-move-rules.ts
│ │ │ ├── links/
│ │ │ │ ├── ab-test-scheduler.ts
│ │ │ │ ├── archive-link.ts
│ │ │ │ ├── bulk-create-links.ts
│ │ │ │ ├── bulk-delete-links.ts
│ │ │ │ ├── bulk-update-links.ts
│ │ │ │ ├── cache.ts
│ │ │ │ ├── case-sensitivity.ts
│ │ │ │ ├── complete-ab-tests.ts
│ │ │ │ ├── create-link.ts
│ │ │ │ ├── delete-link.ts
│ │ │ │ ├── format-links-for-export.ts
│ │ │ │ ├── get-link-or-throw.ts
│ │ │ │ ├── get-links-count.ts
│ │ │ │ ├── get-links-for-workspace.ts
│ │ │ │ ├── include-program-enrollment.ts
│ │ │ │ ├── include-tags.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── plan-features-check.ts
│ │ │ │ ├── process-link.ts
│ │ │ │ ├── propagate-bulk-link-changes.ts
│ │ │ │ ├── record-click-cache.ts
│ │ │ │ ├── update-link-stats-for-importer.ts
│ │ │ │ ├── update-link.ts
│ │ │ │ ├── update-links-usage.ts
│ │ │ │ ├── usage-checks.ts
│ │ │ │ ├── utils/
│ │ │ │ │ ├── check-if-links-have-folders.ts
│ │ │ │ │ ├── check-if-links-have-tags.ts
│ │ │ │ │ ├── check-if-links-have-webhooks.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── key-checks.ts
│ │ │ │ │ ├── process-key.ts
│ │ │ │ │ └── transform-link.ts
│ │ │ │ ├── validate-links-query-filters.ts
│ │ │ │ └── validate-partner-link-url.ts
│ │ │ ├── network/
│ │ │ │ └── calculate-partner-ranking.ts
│ │ │ ├── oauth/
│ │ │ │ ├── actions.ts
│ │ │ │ ├── constants.ts
│ │ │ │ └── utils.ts
│ │ │ ├── pagination.ts
│ │ │ ├── partner-profile/
│ │ │ │ ├── client.ts
│ │ │ │ ├── get-partner-earnings-timeseries.ts
│ │ │ │ ├── get-partner-for-program.ts
│ │ │ │ ├── obfuscate-customer-email.ts
│ │ │ │ ├── partner-platforms-providers.ts
│ │ │ │ └── upsert-partner-platform.ts
│ │ │ ├── partners/
│ │ │ │ ├── bulk-deactivate-partners.ts
│ │ │ │ ├── bulk-delete-partners.ts
│ │ │ │ ├── create-and-enroll-partner.ts
│ │ │ │ ├── create-partner-default-links.ts
│ │ │ │ ├── deactivate-partner.ts
│ │ │ │ ├── format-partners-for-export.ts
│ │ │ │ ├── generate-partner-link.ts
│ │ │ │ ├── get-discount-or-throw.ts
│ │ │ │ ├── get-group-rewards-and-bounties.ts
│ │ │ │ ├── get-network-invites-usage.ts
│ │ │ │ ├── get-partner-rewind.ts
│ │ │ │ ├── get-partner-users.ts
│ │ │ │ ├── get-partners-count.ts
│ │ │ │ ├── get-partners.ts
│ │ │ │ ├── get-reward-or-throw.ts
│ │ │ │ ├── invite-partner-user.ts
│ │ │ │ ├── notify-partner-application.ts
│ │ │ │ ├── notify-partner-commission.ts
│ │ │ │ ├── notify-partner-group-change.ts
│ │ │ │ ├── process-partner-deactivation.ts
│ │ │ │ ├── serialize-reward.ts
│ │ │ │ ├── sync-partner-links-stats.ts
│ │ │ │ ├── sync-total-commissions.ts
│ │ │ │ └── throw-if-existing-tenant-id-exists.ts
│ │ │ ├── payouts/
│ │ │ │ ├── get-effective-payout-mode.ts
│ │ │ │ ├── get-eligible-payouts.ts
│ │ │ │ ├── get-payout-or-throw.ts
│ │ │ │ └── payout-eligibility-filter.ts
│ │ │ ├── postbacks/
│ │ │ │ └── get-postback-or-throw.ts
│ │ │ ├── programs/
│ │ │ │ ├── deactivate-program.ts
│ │ │ │ ├── get-default-program-id-or-throw.ts
│ │ │ │ ├── get-program-enrollment-or-throw.ts
│ │ │ │ └── get-program-or-throw.ts
│ │ │ ├── rbac/
│ │ │ │ ├── permissions.ts
│ │ │ │ └── resources.ts
│ │ │ ├── referrals/
│ │ │ │ ├── get-referral-or-throw.ts
│ │ │ │ ├── mark-referral-closed-won.ts
│ │ │ │ ├── mark-referral-qualified.ts
│ │ │ │ ├── notify-partner-referral-submitted.ts
│ │ │ │ └── notify-referral-status-update.ts
│ │ │ ├── rewards/
│ │ │ │ └── validate-reward.ts
│ │ │ ├── sales/
│ │ │ │ ├── calculate-sale-earnings.ts
│ │ │ │ ├── construct-discount-amount.ts
│ │ │ │ └── construct-reward-amount.ts
│ │ │ ├── scrape-creators/
│ │ │ │ ├── client.ts
│ │ │ │ ├── get-linkedin-post.ts
│ │ │ │ ├── get-social-content.ts
│ │ │ │ ├── get-social-profile.ts
│ │ │ │ └── schema.ts
│ │ │ ├── tags/
│ │ │ │ └── combine-tag-ids.ts
│ │ │ ├── tokens/
│ │ │ │ ├── scopes.ts
│ │ │ │ └── throw-if-no-access.ts
│ │ │ ├── users.ts
│ │ │ ├── utils/
│ │ │ │ ├── assert-valid-date-range-for-plan.ts
│ │ │ │ ├── generate-export-filename.ts
│ │ │ │ ├── generate-random-string.ts
│ │ │ │ ├── get-ip.ts
│ │ │ │ ├── is-non-empty-json.ts
│ │ │ │ └── with-prisma-retry.ts
│ │ │ ├── utils.ts
│ │ │ ├── utm/
│ │ │ │ └── extract-utm-params.ts
│ │ │ ├── validate-allowed-hostnames.ts
│ │ │ ├── workflows/
│ │ │ │ ├── evaluate-workflow-conditions.ts
│ │ │ │ ├── execute-complete-bounty-workflow.ts
│ │ │ │ ├── execute-move-group-workflow.ts
│ │ │ │ ├── execute-send-campaign-workflow.ts
│ │ │ │ ├── execute-workflows.ts
│ │ │ │ ├── interpolate-email-template.ts
│ │ │ │ ├── parse-workflow-config.ts
│ │ │ │ ├── render-campaign-email-html.ts
│ │ │ │ ├── render-campaign-email-markdown.ts
│ │ │ │ └── utils.ts
│ │ │ └── workspaces/
│ │ │ ├── assert-role-plan.ts
│ │ │ ├── create-workspace-id.ts
│ │ │ ├── delete-workspace.ts
│ │ │ ├── is-saml-enforced-for-email-domain.ts
│ │ │ ├── onboarding-step-cache.ts
│ │ │ └── workspace-id.ts
│ │ ├── auth/
│ │ │ ├── admin.ts
│ │ │ ├── confirm-email-change.ts
│ │ │ ├── constants.ts
│ │ │ ├── hash-token.ts
│ │ │ ├── index.ts
│ │ │ ├── lock-account.ts
│ │ │ ├── options.ts
│ │ │ ├── partner-users/
│ │ │ │ ├── partner-user-permissions.ts
│ │ │ │ └── throw-if-no-permission.ts
│ │ │ ├── partner.ts
│ │ │ ├── password.ts
│ │ │ ├── publishable-key.ts
│ │ │ ├── rate-limit-request.ts
│ │ │ ├── session.ts
│ │ │ ├── token-cache.ts
│ │ │ ├── track-dub-lead.ts
│ │ │ ├── utils.ts
│ │ │ └── workspace.ts
│ │ ├── axiom/
│ │ │ ├── axiom.ts
│ │ │ └── server.ts
│ │ ├── bounty/
│ │ │ ├── api/
│ │ │ │ ├── approve-bounty-submission.ts
│ │ │ │ ├── create-bounty-submission.ts
│ │ │ │ ├── generate-performance-bounty-name.ts
│ │ │ │ ├── get-bounties-by-groups.ts
│ │ │ │ ├── get-bounty-or-throw.ts
│ │ │ │ ├── get-bounty-with-details.ts
│ │ │ │ ├── get-group-bounty-summaries.ts
│ │ │ │ ├── get-social-metrics-updates.ts
│ │ │ │ ├── performance-bounty-scope-attributes.ts
│ │ │ │ ├── reject-bounty-submission.ts
│ │ │ │ ├── trigger-draft-bounty-submissions.ts
│ │ │ │ └── validate-bounty.ts
│ │ │ ├── constants.ts
│ │ │ ├── periods.ts
│ │ │ ├── rewards.ts
│ │ │ ├── social-content.ts
│ │ │ ├── submission-status.ts
│ │ │ └── utils.ts
│ │ ├── client-access-check.ts
│ │ ├── constants/
│ │ │ ├── misc.ts
│ │ │ ├── notification-preferences.ts
│ │ │ ├── partner-profile.ts
│ │ │ ├── payouts-supported-countries.ts
│ │ │ ├── payouts.ts
│ │ │ └── program.ts
│ │ ├── cron/
│ │ │ ├── enqueue-batch-jobs.ts
│ │ │ ├── index.ts
│ │ │ ├── limiter.ts
│ │ │ ├── qstash-workflow-logger.ts
│ │ │ ├── qstash-workflow.ts
│ │ │ ├── send-limit-email.ts
│ │ │ ├── verify-qstash.ts
│ │ │ ├── verify-vercel.ts
│ │ │ └── with-cron.ts
│ │ ├── customers/
│ │ │ └── api/
│ │ │ ├── customer-count-where.ts
│ │ │ ├── fetch-customers-batch.ts
│ │ │ ├── format-customers-export.ts
│ │ │ └── get-customers.ts
│ │ ├── dub.ts
│ │ ├── dynadot/
│ │ │ ├── constants.ts
│ │ │ ├── register-domain.ts
│ │ │ ├── search-domains.ts
│ │ │ └── set-renew-option.ts
│ │ ├── edge-config/
│ │ │ ├── get-feature-flags.ts
│ │ │ ├── get-partner-feature-flags.ts
│ │ │ ├── index.ts
│ │ │ ├── is-blacklisted-domain.ts
│ │ │ ├── is-blacklisted-email.ts
│ │ │ ├── is-blacklisted-key.ts
│ │ │ ├── is-blacklisted-referrer.ts
│ │ │ ├── is-reserved-username.ts
│ │ │ └── update.ts
│ │ ├── email/
│ │ │ ├── email-templates-map.ts
│ │ │ ├── extract-email-domain.ts
│ │ │ ├── queue-batch-email.ts
│ │ │ └── unsubscribe-token.ts
│ │ ├── embed/
│ │ │ ├── constants.ts
│ │ │ └── referrals/
│ │ │ ├── auth.ts
│ │ │ └── token-class.ts
│ │ ├── exceeded-limit-error.ts
│ │ ├── fetchers/
│ │ │ ├── get-content-api.ts
│ │ │ ├── get-dashboard.ts
│ │ │ ├── get-network-program.ts
│ │ │ ├── get-program-slugs.ts
│ │ │ ├── get-program.ts
│ │ │ └── index.ts
│ │ ├── firstpromoter/
│ │ │ ├── api.ts
│ │ │ ├── import-campaigns.ts
│ │ │ ├── import-commissions.ts
│ │ │ ├── import-customers.ts
│ │ │ ├── import-partners.ts
│ │ │ ├── importer.ts
│ │ │ ├── schemas.ts
│ │ │ ├── types.ts
│ │ │ └── update-stripe-customers.ts
│ │ ├── folder/
│ │ │ ├── constants.ts
│ │ │ ├── get-folder-or-throw.ts
│ │ │ ├── get-folders.ts
│ │ │ └── permissions.ts
│ │ ├── form-utils.ts
│ │ ├── get-highest-severity.ts
│ │ ├── get-integration-guide-markdown.ts
│ │ ├── hooks/
│ │ │ └── use-synced-local-storage.ts
│ │ ├── integrations/
│ │ │ ├── bitly/
│ │ │ │ └── oauth.ts
│ │ │ ├── common/
│ │ │ │ └── ui/
│ │ │ │ └── configure-webhook.tsx
│ │ │ ├── hubspot/
│ │ │ │ ├── api.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── oauth.ts
│ │ │ │ ├── schema.ts
│ │ │ │ ├── track-lead.ts
│ │ │ │ ├── track-sale.ts
│ │ │ │ ├── ui/
│ │ │ │ │ └── settings.tsx
│ │ │ │ └── update-hubspot-settings.ts
│ │ │ ├── install.ts
│ │ │ ├── oauth-provider.ts
│ │ │ ├── segment/
│ │ │ │ ├── install.ts
│ │ │ │ ├── transform.ts
│ │ │ │ ├── ui/
│ │ │ │ │ ├── set-write-key.tsx
│ │ │ │ │ └── settings.tsx
│ │ │ │ └── utils.ts
│ │ │ ├── shopify/
│ │ │ │ ├── create-lead.ts
│ │ │ │ ├── create-sale.ts
│ │ │ │ ├── process-order.ts
│ │ │ │ └── schema.ts
│ │ │ ├── singular/
│ │ │ │ ├── track-lead.ts
│ │ │ │ └── track-sale.ts
│ │ │ ├── slack/
│ │ │ │ ├── commands.ts
│ │ │ │ ├── oauth.ts
│ │ │ │ ├── schema.ts
│ │ │ │ ├── transform.ts
│ │ │ │ ├── ui/
│ │ │ │ │ └── settings.tsx
│ │ │ │ └── verify-request.ts
│ │ │ ├── stripe/
│ │ │ │ ├── schema.ts
│ │ │ │ ├── ui/
│ │ │ │ │ └── settings.tsx
│ │ │ │ └── update-stripe-settings.ts
│ │ │ ├── types.ts
│ │ │ ├── utils.ts
│ │ │ └── zapier/
│ │ │ └── ui/
│ │ │ └── settings.tsx
│ │ ├── is-generic-email.ts
│ │ ├── jackson.ts
│ │ ├── links/
│ │ │ └── links-display.ts
│ │ ├── middleware/
│ │ │ ├── admin.ts
│ │ │ ├── api.ts
│ │ │ ├── app.ts
│ │ │ ├── create-link.ts
│ │ │ ├── embed.ts
│ │ │ ├── link.ts
│ │ │ ├── new-link.ts
│ │ │ ├── partners.ts
│ │ │ ├── utils/
│ │ │ │ ├── app-redirect.ts
│ │ │ │ ├── bots-list.ts
│ │ │ │ ├── cache-deeplink-click-data.ts
│ │ │ │ ├── crawl-bitly.ts
│ │ │ │ ├── create-response-with-cookies.ts
│ │ │ │ ├── detect-bot.ts
│ │ │ │ ├── detect-qr.ts
│ │ │ │ ├── get-default-partner.ts
│ │ │ │ ├── get-default-workspace.ts
│ │ │ │ ├── get-final-url.ts
│ │ │ │ ├── get-identity-hash.ts
│ │ │ │ ├── get-user-via-token.ts
│ │ │ │ ├── get-workspace-product.ts
│ │ │ │ ├── handle-not-found-link.ts
│ │ │ │ ├── has-pending-invites.ts
│ │ │ │ ├── is-google-play-store-url.ts
│ │ │ │ ├── is-ios-app-store-url.ts
│ │ │ │ ├── is-ip-in-range.ts
│ │ │ │ ├── is-singular-tracking-url.ts
│ │ │ │ ├── is-supported-custom-uri-scheme.ts
│ │ │ │ ├── is-top-level-settings-redirect.ts
│ │ │ │ ├── is-valid-internal-redirect.ts
│ │ │ │ ├── parse.ts
│ │ │ │ ├── partners-redirect.ts
│ │ │ │ └── resolve-ab-test-url.ts
│ │ │ └── workspaces.ts
│ │ ├── names.ts
│ │ ├── network/
│ │ │ ├── get-discoverability-requirements.ts
│ │ │ ├── get-partner-profile-checklist-progress.ts
│ │ │ └── program-categories.ts
│ │ ├── next-auth.d.ts
│ │ ├── onboarding/
│ │ │ └── types.ts
│ │ ├── openapi/
│ │ │ ├── analytics/
│ │ │ │ └── index.ts
│ │ │ ├── bounties/
│ │ │ │ ├── approve-bounty-submission.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── list-bounty-submissions.ts
│ │ │ │ └── reject-bounty-submission.ts
│ │ │ ├── commissions/
│ │ │ │ ├── index.ts
│ │ │ │ ├── list-commissions.ts
│ │ │ │ └── update-commission.ts
│ │ │ ├── customers/
│ │ │ │ ├── delete-customer.ts
│ │ │ │ ├── get-customer.ts
│ │ │ │ ├── get-customers.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── update-customer.ts
│ │ │ ├── domains/
│ │ │ │ ├── check-domain-status.ts
│ │ │ │ ├── create-domain.ts
│ │ │ │ ├── delete-domain.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── list-domains.ts
│ │ │ │ ├── register-domain.ts
│ │ │ │ └── update-domain.ts
│ │ │ ├── embed-tokens/
│ │ │ │ ├── create-referrals-embed-token.ts
│ │ │ │ └── index.ts
│ │ │ ├── events/
│ │ │ │ └── index.ts
│ │ │ ├── folders/
│ │ │ │ ├── create-folder.ts
│ │ │ │ ├── delete-folder.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── list-folders.ts
│ │ │ │ └── update-folder.ts
│ │ │ ├── index.ts
│ │ │ ├── links/
│ │ │ │ ├── bulk-create-links.ts
│ │ │ │ ├── bulk-delete-links.ts
│ │ │ │ ├── bulk-update-links.ts
│ │ │ │ ├── create-link.ts
│ │ │ │ ├── delete-link.ts
│ │ │ │ ├── get-link-info.ts
│ │ │ │ ├── get-links-count.ts
│ │ │ │ ├── get-links.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── update-link.ts
│ │ │ │ └── upsert-link.ts
│ │ │ ├── partners/
│ │ │ │ ├── ban-partner.ts
│ │ │ │ ├── create-partner-link.ts
│ │ │ │ ├── create-partner.ts
│ │ │ │ ├── deactivate-partner.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── list-partners.ts
│ │ │ │ ├── retrieve-analytics.ts
│ │ │ │ ├── retrieve-partner-links.ts
│ │ │ │ └── upsert-partner-link.ts
│ │ │ ├── payouts/
│ │ │ │ ├── index.ts
│ │ │ │ └── list-payouts.ts
│ │ │ ├── qr/
│ │ │ │ └── index.ts
│ │ │ ├── responses.ts
│ │ │ ├── tags/
│ │ │ │ ├── create-tag.ts
│ │ │ │ ├── delete-tag.ts
│ │ │ │ ├── get-tags.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── update-tag.ts
│ │ │ └── track/
│ │ │ ├── index.ts
│ │ │ ├── lead.ts
│ │ │ ├── open.ts
│ │ │ └── sale.ts
│ │ ├── partners/
│ │ │ ├── aggregate-partner-links-stats.ts
│ │ │ ├── approve-partner-enrollment.ts
│ │ │ ├── calculate-payout-fee-with-waiver.ts
│ │ │ ├── complete-program-applications.ts
│ │ │ ├── construct-partner-link.ts
│ │ │ ├── create-partner-commission.ts
│ │ │ ├── create-stablecoin-payout.ts
│ │ │ ├── create-stripe-transfer.ts
│ │ │ ├── cutoff-period.ts
│ │ │ ├── determine-partner-reward.ts
│ │ │ ├── evaluate-application-requirements.ts
│ │ │ ├── evaluate-reward-conditions.ts
│ │ │ ├── format-application-form-data.ts
│ │ │ ├── get-group-rewards-and-discount.ts
│ │ │ ├── get-link-structure-options.ts
│ │ │ ├── get-partner-bank-account.ts
│ │ │ ├── get-payout-methods-for-country.ts
│ │ │ ├── get-reward-amount.ts
│ │ │ ├── partner-platforms.ts
│ │ │ ├── partner-profile.ts
│ │ │ ├── query-link-structure-help-text.tsx
│ │ │ ├── sanitize-markdown.ts
│ │ │ ├── sort-rewards-by-event-order.ts
│ │ │ └── throw-if-no-partnerid-tenantid.ts
│ │ ├── partnerstack/
│ │ │ ├── api.ts
│ │ │ ├── import-commissions.ts
│ │ │ ├── import-customers.ts
│ │ │ ├── import-groups.ts
│ │ │ ├── import-links.ts
│ │ │ ├── import-partners.ts
│ │ │ ├── importer.ts
│ │ │ ├── schemas.ts
│ │ │ ├── types.ts
│ │ │ └── update-stripe-customers.ts
│ │ ├── payouts/
│ │ │ ├── create-payouts-idempotency-key.ts
│ │ │ ├── get-partner-payout-methods.ts
│ │ │ ├── mark-payouts-as-processed.ts
│ │ │ └── recompute-partner-payout-state.ts
│ │ ├── paypal/
│ │ │ ├── create-batch-payout.ts
│ │ │ ├── create-paypal-token.ts
│ │ │ ├── env.ts
│ │ │ ├── get-pending-payouts.ts
│ │ │ ├── oauth.ts
│ │ │ └── schema.ts
│ │ ├── plain/
│ │ │ ├── client.ts
│ │ │ ├── create-plain-thread.ts
│ │ │ ├── sync-user-plan.ts
│ │ │ └── upsert-plain-customer.ts
│ │ ├── plan-capabilities.ts
│ │ ├── planetscale/
│ │ │ ├── check-if-key-exists.ts
│ │ │ ├── check-if-user-exists.ts
│ │ │ ├── connection.ts
│ │ │ ├── get-domain-via-edge.ts
│ │ │ ├── get-link-via-edge.ts
│ │ │ ├── get-link-with-partner.ts
│ │ │ ├── get-partner-enrollment-info.ts
│ │ │ ├── get-random-key.ts
│ │ │ ├── get-shortlink-via-edge.ts
│ │ │ ├── get-workspace-via-edge.ts
│ │ │ ├── granularity.ts
│ │ │ ├── index.ts
│ │ │ └── types.ts
│ │ ├── plans/
│ │ │ └── has-partner-access.ts
│ │ ├── postback/
│ │ │ ├── api/
│ │ │ │ ├── get-postback-events.ts
│ │ │ │ ├── postback-adapter-custom.ts
│ │ │ │ ├── postback-adapter-slack.ts
│ │ │ │ ├── postback-adapters.ts
│ │ │ │ ├── postback-event-enrichers.ts
│ │ │ │ ├── postback-event-transformers.ts
│ │ │ │ ├── record-postback-event.ts
│ │ │ │ ├── send-partner-postback.ts
│ │ │ │ └── utils.ts
│ │ │ ├── constants.ts
│ │ │ ├── sample-events/
│ │ │ │ ├── commission-created.json
│ │ │ │ ├── lead-created.json
│ │ │ │ └── sale-created.json
│ │ │ └── schemas.ts
│ │ ├── qr/
│ │ │ ├── api.tsx
│ │ │ ├── codegen.ts
│ │ │ ├── constants.ts
│ │ │ ├── index.tsx
│ │ │ ├── types.ts
│ │ │ └── utils.tsx
│ │ ├── referrals/
│ │ │ └── constants.ts
│ │ ├── rewardful/
│ │ │ ├── api.ts
│ │ │ ├── import-affiliate-coupons.ts
│ │ │ ├── import-campaigns.ts
│ │ │ ├── import-commissions.ts
│ │ │ ├── import-customers.ts
│ │ │ ├── import-partners.ts
│ │ │ ├── importer.ts
│ │ │ ├── schemas.ts
│ │ │ └── types.ts
│ │ ├── social-utils.ts
│ │ ├── storage.ts
│ │ ├── stripe/
│ │ │ ├── cancel-subscription.ts
│ │ │ ├── check-payment-method-mandate.ts
│ │ │ ├── client.ts
│ │ │ ├── coupon-discount-converter.ts
│ │ │ ├── create-connected-account.ts
│ │ │ ├── create-fx-quote.ts
│ │ │ ├── create-payment-intent.ts
│ │ │ ├── create-stripe-discount-code.ts
│ │ │ ├── create-stripe-outbound-payment.ts
│ │ │ ├── create-stripe-recipient-account-link.ts
│ │ │ ├── create-stripe-recipient-account.ts
│ │ │ ├── disable-stripe-discount-code.ts
│ │ │ ├── fund-financial-account.ts
│ │ │ ├── get-stripe-outbound-payment.ts
│ │ │ ├── get-stripe-recipient-account.ts
│ │ │ ├── get-stripe-recipient-payout-method.ts
│ │ │ ├── index.ts
│ │ │ ├── payment-methods.ts
│ │ │ ├── stripe-v2-client.ts
│ │ │ └── stripe-v2-schemas.ts
│ │ ├── swr/
│ │ │ ├── mutate.ts
│ │ │ ├── use-activity-logs.ts
│ │ │ ├── use-api-mutation.ts
│ │ │ ├── use-bounty-submissions-count.ts
│ │ │ ├── use-bounty.ts
│ │ │ ├── use-commission.ts
│ │ │ ├── use-commissions-count.ts
│ │ │ ├── use-commissions-timeseries.ts
│ │ │ ├── use-current-folder-id.ts
│ │ │ ├── use-customer-activity.ts
│ │ │ ├── use-customer.ts
│ │ │ ├── use-customers-count.ts
│ │ │ ├── use-customers.ts
│ │ │ ├── use-default-domains.ts
│ │ │ ├── use-discount-codes.ts
│ │ │ ├── use-discounts.ts
│ │ │ ├── use-domain.ts
│ │ │ ├── use-domains-count.ts
│ │ │ ├── use-domains.ts
│ │ │ ├── use-email-domains.ts
│ │ │ ├── use-folder-access-requests.ts
│ │ │ ├── use-folder-link-count.ts
│ │ │ ├── use-folder-permissions.ts
│ │ │ ├── use-folder-users.ts
│ │ │ ├── use-folder.ts
│ │ │ ├── use-folders-count.ts
│ │ │ ├── use-folders.ts
│ │ │ ├── use-fraud-events-count.ts
│ │ │ ├── use-fraud-events-paginated.ts
│ │ │ ├── use-fraud-events.ts
│ │ │ ├── use-fraud-groups-count.ts
│ │ │ ├── use-fraud-groups.ts
│ │ │ ├── use-group-move-rules.ts
│ │ │ ├── use-group.ts
│ │ │ ├── use-groups-count.ts
│ │ │ ├── use-groups.ts
│ │ │ ├── use-guide.ts
│ │ │ ├── use-integrations.ts
│ │ │ ├── use-link.ts
│ │ │ ├── use-links-count.ts
│ │ │ ├── use-links.ts
│ │ │ ├── use-network-partners-count.ts
│ │ │ ├── use-network-programs-count.ts
│ │ │ ├── use-partner-activity-logs.ts
│ │ │ ├── use-partner-analytics.ts
│ │ │ ├── use-partner-application-risks.ts
│ │ │ ├── use-partner-bounty.ts
│ │ │ ├── use-partner-comments-count.ts
│ │ │ ├── use-partner-comments.ts
│ │ │ ├── use-partner-cross-program-summary.ts
│ │ │ ├── use-partner-customer.ts
│ │ │ ├── use-partner-customers-count.ts
│ │ │ ├── use-partner-customers.ts
│ │ │ ├── use-partner-earnings-count.ts
│ │ │ ├── use-partner-earnings-timeseries.ts
│ │ │ ├── use-partner-group-default-links.ts
│ │ │ ├── use-partner-links.ts
│ │ │ ├── use-partner-messages-count.ts
│ │ │ ├── use-partner-messages.ts
│ │ │ ├── use-partner-network-invites-usage.ts
│ │ │ ├── use-partner-payout-settings.ts
│ │ │ ├── use-partner-payouts-count.ts
│ │ │ ├── use-partner-payouts.ts
│ │ │ ├── use-partner-profile.ts
│ │ │ ├── use-partner-program-bounties.ts
│ │ │ ├── use-partner-referrals-count.ts
│ │ │ ├── use-partner-referrals.ts
│ │ │ ├── use-partner-rewind.ts
│ │ │ ├── use-partner.ts
│ │ │ ├── use-partners-count-by-groupids.ts
│ │ │ ├── use-partners-count.ts
│ │ │ ├── use-partners.ts
│ │ │ ├── use-payment-methods.ts
│ │ │ ├── use-payout.ts
│ │ │ ├── use-payouts-count.ts
│ │ │ ├── use-payouts.ts
│ │ │ ├── use-program-enrollment.ts
│ │ │ ├── use-program-enrollments-count.ts
│ │ │ ├── use-program-enrollments.ts
│ │ │ ├── use-program-messages-count.ts
│ │ │ ├── use-program-messages.ts
│ │ │ ├── use-program-referrals-count.ts
│ │ │ ├── use-program-resources.ts
│ │ │ ├── use-program.ts
│ │ │ ├── use-refresh-session.ts
│ │ │ ├── use-rewardful-campaigns.ts
│ │ │ ├── use-rewards.ts
│ │ │ ├── use-saml.ts
│ │ │ ├── use-scim.ts
│ │ │ ├── use-tags-count.ts
│ │ │ ├── use-tags.ts
│ │ │ ├── use-usage-timeseries.ts
│ │ │ ├── use-user.ts
│ │ │ ├── use-webhook.ts
│ │ │ ├── use-webhooks.ts
│ │ │ ├── use-workspace-preferences.ts
│ │ │ ├── use-workspace-store.ts
│ │ │ ├── use-workspace-users.ts
│ │ │ ├── use-workspace.ts
│ │ │ └── use-workspaces.ts
│ │ ├── tinybird/
│ │ │ ├── client.ts
│ │ │ ├── get-click-event.ts
│ │ │ ├── get-customer-events-tb.ts
│ │ │ ├── get-import-error-logs.ts
│ │ │ ├── get-lead-event.ts
│ │ │ ├── get-lead-events.ts
│ │ │ ├── get-top-links-by-countries.ts
│ │ │ ├── get-webhook-events.ts
│ │ │ ├── index.ts
│ │ │ ├── log-conversion-events.ts
│ │ │ ├── log-import-error.ts
│ │ │ ├── record-click-zod.ts
│ │ │ ├── record-click.ts
│ │ │ ├── record-fake-click.ts
│ │ │ ├── record-lead.ts
│ │ │ ├── record-link.ts
│ │ │ ├── record-sale.ts
│ │ │ └── record-webhook-event.ts
│ │ ├── tolt/
│ │ │ ├── api.ts
│ │ │ ├── cleanup-partners.ts
│ │ │ ├── import-commissions.ts
│ │ │ ├── import-customers.ts
│ │ │ ├── import-links.ts
│ │ │ ├── import-partners.ts
│ │ │ ├── importer.ts
│ │ │ ├── schemas.ts
│ │ │ ├── types.ts
│ │ │ └── update-stripe-customers.ts
│ │ ├── types.ts
│ │ ├── upstash/
│ │ │ ├── format-redis-link.ts
│ │ │ ├── index.ts
│ │ │ ├── ratelimit-policy.ts
│ │ │ ├── ratelimit.ts
│ │ │ ├── record-metatags.ts
│ │ │ ├── redis-streams.ts
│ │ │ ├── redis.ts
│ │ │ └── vector.ts
│ │ ├── webhook/
│ │ │ ├── cache.ts
│ │ │ ├── constants.ts
│ │ │ ├── create-webhook.ts
│ │ │ ├── failure.ts
│ │ │ ├── get-webhooks.ts
│ │ │ ├── handle-external-payout-event.ts
│ │ │ ├── publish.ts
│ │ │ ├── qstash.ts
│ │ │ ├── sample-events/
│ │ │ │ ├── bounty-created.json
│ │ │ │ ├── bounty-updated.json
│ │ │ │ ├── commission-created.json
│ │ │ │ ├── lead-created.json
│ │ │ │ ├── link-clicked.json
│ │ │ │ ├── link-created.json
│ │ │ │ ├── link-deleted.json
│ │ │ │ ├── link-updated.json
│ │ │ │ ├── partner-application-submitted.json
│ │ │ │ ├── partner-enrolled.json
│ │ │ │ ├── payload.ts
│ │ │ │ ├── payout-confirmed.json
│ │ │ │ └── sale-created.json
│ │ │ ├── schemas.ts
│ │ │ ├── secret.ts
│ │ │ ├── signature.ts
│ │ │ ├── transform.ts
│ │ │ ├── types.ts
│ │ │ ├── update-webhook.ts
│ │ │ ├── utils.ts
│ │ │ └── validate-webhook.ts
│ │ ├── well-known.ts
│ │ ├── workspace-roles.ts
│ │ └── zod/
│ │ └── schemas/
│ │ ├── activity-log.ts
│ │ ├── analytics-response.ts
│ │ ├── analytics.ts
│ │ ├── auth.ts
│ │ ├── bounties.ts
│ │ ├── campaigns.ts
│ │ ├── clicks.ts
│ │ ├── commissions.ts
│ │ ├── customer-activity.ts
│ │ ├── customers.ts
│ │ ├── dashboard.ts
│ │ ├── deep-links.ts
│ │ ├── deprecated.ts
│ │ ├── discount.ts
│ │ ├── domains.ts
│ │ ├── email-domains.ts
│ │ ├── folders.ts
│ │ ├── fraud.ts
│ │ ├── group-bounties.ts
│ │ ├── group-with-program.ts
│ │ ├── groups.ts
│ │ ├── import-csv.ts
│ │ ├── import-error-log.ts
│ │ ├── integration.ts
│ │ ├── invites.ts
│ │ ├── invoices.ts
│ │ ├── leads.ts
│ │ ├── links.ts
│ │ ├── messages.ts
│ │ ├── misc.ts
│ │ ├── oauth.ts
│ │ ├── opens.ts
│ │ ├── partner-network.ts
│ │ ├── partner-profile.ts
│ │ ├── partners.ts
│ │ ├── payouts.ts
│ │ ├── program-application-form.ts
│ │ ├── program-application.ts
│ │ ├── program-embed.ts
│ │ ├── program-invite-email.ts
│ │ ├── program-lander.ts
│ │ ├── program-network.ts
│ │ ├── program-onboarding.ts
│ │ ├── program-resources.ts
│ │ ├── programs.ts
│ │ ├── qr.ts
│ │ ├── referral-form.ts
│ │ ├── referrals-embed.ts
│ │ ├── referrals.ts
│ │ ├── rewards.ts
│ │ ├── sales.ts
│ │ ├── schemas.ts
│ │ ├── tags.ts
│ │ ├── token.ts
│ │ ├── usage.ts
│ │ ├── users.ts
│ │ ├── utils.ts
│ │ ├── utm.ts
│ │ ├── webhooks.ts
│ │ ├── workflows.ts
│ │ ├── workspace-preferences.ts
│ │ └── workspaces.ts
│ ├── middleware.ts
│ ├── next.config.js
│ ├── package.json
│ ├── playwright/
│ │ ├── README.md
│ │ ├── auth.setup.ts
│ │ ├── env.ts
│ │ ├── partner-login.spec.ts
│ │ ├── partner-onboarding.spec.ts
│ │ └── seed.ts
│ ├── playwright.config.ts
│ ├── postcss.config.js
│ ├── public/
│ │ └── .well-known/
│ │ └── security.txt
│ ├── scripts/
│ │ ├── analyze-bundle.ts
│ │ ├── analyze-domains.ts
│ │ ├── analyze-link-webhooks.ts
│ │ ├── analyze-top-utms.ts
│ │ ├── analyze-utm-usage.ts
│ │ ├── annature/
│ │ │ └── import-domains.ts
│ │ ├── buffer/
│ │ │ ├── delete-old-links.ts
│ │ │ └── migrate-to-case-sensitive.ts
│ │ ├── bulk-archive-links.ts
│ │ ├── bulk-create-domains.ts
│ │ ├── bulk-create-links.ts
│ │ ├── bulk-delete-links.ts
│ │ ├── bulk-update-links.ts
│ │ ├── cache-popular-urls.ts
│ │ ├── cal/
│ │ │ └── backfill-referral-links.ts
│ │ ├── check-customers.ts
│ │ ├── conversion-customers.ts
│ │ ├── convert-case-sensitive.ts
│ │ ├── convert-manual-commissions.ts
│ │ ├── create-integration.ts
│ │ ├── create-key.ts
│ │ ├── deactivate-programs.ts
│ │ ├── delete-link-cache.ts
│ │ ├── dev/
│ │ │ ├── data.json
│ │ │ └── seed.ts
│ │ ├── download-links.ts
│ │ ├── download-top-links.ts
│ │ ├── dub-domain-users.ts
│ │ ├── dub-partner-rewind.ts
│ │ ├── dub-sdk.ts
│ │ ├── dub-wrapped.ts
│ │ ├── find-link.ts
│ │ ├── find-workspaces-without-users.ts
│ │ ├── fix-broken-applications.ts
│ │ ├── fix-broken-link-tags.ts
│ │ ├── fix-broken-partner-users.ts
│ │ ├── fix-broken-root-domains.ts
│ │ ├── fix-broken-workspace-users.ts
│ │ ├── fix-usage-count.ts
│ │ ├── format-clicks.ts
│ │ ├── format-links.ts
│ │ ├── framer/
│ │ │ ├── 1-process-framer-combined.ts
│ │ │ ├── 2-sort-lead-events-by-date.ts
│ │ │ ├── 3-backfill-tb-events.ts
│ │ │ ├── backfill-commissions.ts
│ │ │ ├── check-pending-payout-totals.ts
│ │ │ ├── get-links-to-backfill.ts
│ │ │ ├── get-remaining-links-to-backfill.ts
│ │ │ ├── mark-commissions-paid.ts
│ │ │ ├── mark-commissions-pending.ts
│ │ │ ├── process-lead-events.ts
│ │ │ └── tally-commissions.ts
│ │ ├── generate-openapi.ts
│ │ ├── get-api-users.ts
│ │ ├── get-customers.ts
│ │ ├── get-inactive-users.ts
│ │ ├── get-premium-workspaces.ts
│ │ ├── get-top-domains-for-links.ts
│ │ ├── get-top-links-for-workspace.ts
│ │ ├── get-users-by-links.ts
│ │ ├── get-users-with-multiple-free-workspaces.ts
│ │ ├── get-users.ts
│ │ ├── get-workspaces-by-clicks.ts
│ │ ├── get-workspaces-by-links.ts
│ │ ├── hash-speed.ts
│ │ ├── lua-convert.ts
│ │ ├── migrate-commission-attributes.ts
│ │ ├── migrations/
│ │ │ ├── backfill-application-groupId.ts
│ │ │ ├── backfill-attribution.ts
│ │ │ ├── backfill-banned-partner-links.ts
│ │ │ ├── backfill-click-commissions.ts
│ │ │ ├── backfill-commissions-rewardId.ts
│ │ │ ├── backfill-cross-program-ban-fraud-events.ts
│ │ │ ├── backfill-customer-first-sale.ts
│ │ │ ├── backfill-customer-partner-ids.ts
│ │ │ ├── backfill-customer-sales.ts
│ │ │ ├── backfill-customer-subscription-cancellation.ts
│ │ │ ├── backfill-customers.ts
│ │ │ ├── backfill-dashboards.ts
│ │ │ ├── backfill-deepview.ts
│ │ │ ├── backfill-default-payout-method.ts
│ │ │ ├── backfill-default-program-ids.ts
│ │ │ ├── backfill-discoverableat.ts
│ │ │ ├── backfill-domain-logo.ts
│ │ │ ├── backfill-folders-limit.ts
│ │ │ ├── backfill-folders-usage.ts
│ │ │ ├── backfill-group-links-pgdl-acme.ts
│ │ │ ├── backfill-group-links-pgdl.ts
│ │ │ ├── backfill-group-links-settings.ts
│ │ │ ├── backfill-group-settings.ts
│ │ │ ├── backfill-invoice-paid-at.ts
│ │ │ ├── backfill-invoice-payment-method.ts
│ │ │ ├── backfill-invoice-prefixes.ts
│ │ │ ├── backfill-link-commissions.ts
│ │ │ ├── backfill-link-partner-group-ids.ts
│ │ │ ├── backfill-link-stats.ts
│ │ │ ├── backfill-link-webhooks.ts
│ │ │ ├── backfill-missing-lead-commissions.ts
│ │ │ ├── backfill-missing-sales.ts
│ │ │ ├── backfill-notification-email-columns.ts
│ │ │ ├── backfill-notification-email-deliveredat.ts
│ │ │ ├── backfill-notification-preferences.ts
│ │ │ ├── backfill-partner-groupid-logs.ts
│ │ │ ├── backfill-partner-groups-verify.ts
│ │ │ ├── backfill-partner-groups.ts
│ │ │ ├── backfill-partner-platforms.ts
│ │ │ ├── backfill-payout-initiated-at.ts
│ │ │ ├── backfill-payout-method-hash.ts
│ │ │ ├── backfill-payout-method.ts
│ │ │ ├── backfill-payout-mode.ts
│ │ │ ├── backfill-performance-bounty-submissions.ts
│ │ │ ├── backfill-plain-customers.ts
│ │ │ ├── backfill-program-categories.ts
│ │ │ ├── backfill-program-marketplace-descriptions.ts
│ │ │ ├── backfill-program-marketplace.ts
│ │ │ ├── backfill-referral-links.ts
│ │ │ ├── backfill-reward-activity-log.ts
│ │ │ ├── backfill-reward-modifier-ids.ts
│ │ │ ├── backfill-saml-sso.ts
│ │ │ ├── backfill-short-links.ts
│ │ │ ├── backfill-stripe-connect.ts
│ │ │ ├── backfill-submission-completedat.ts
│ │ │ ├── backfill-total-commissions.ts
│ │ │ ├── migrate-application-formdata.ts
│ │ │ ├── migrate-application-submissions.ts
│ │ │ ├── migrate-bounties-submission-requirements.ts
│ │ │ ├── migrate-campaign-message-to-markdown.ts
│ │ │ ├── migrate-discounts.ts
│ │ │ ├── migrate-domains.ts
│ │ │ ├── migrate-images.ts
│ │ │ ├── migrate-integrations.ts
│ │ │ ├── migrate-lander-data.ts
│ │ │ ├── migrate-links-to-workspaces.ts
│ │ │ ├── migrate-partner-links.ts
│ │ │ ├── migrate-partners-with-tenantids.ts
│ │ │ ├── migrate-reward-amounts.ts
│ │ │ ├── migrate-rewards-remainder.ts
│ │ │ ├── migrate-rewards.ts
│ │ │ ├── migrate-sales.ts
│ │ │ ├── migrate-workflow-triggers.ts
│ │ │ ├── remove-duplicate-notification-emails.ts
│ │ │ ├── restore-group-ids.ts
│ │ │ ├── sanitize-partner-platform.ts
│ │ │ ├── update-discoverable-partners.ts
│ │ │ └── update-payout-mode-to-internal.ts
│ │ ├── misc/
│ │ │ ├── cleanup-fraud-events.ts
│ │ │ ├── cleanup-generic-email-fraud-events.ts
│ │ │ ├── fraud-campaign-ids.ts
│ │ │ ├── remove-fraud-events.ts
│ │ │ ├── restore-link-analytics.ts
│ │ │ ├── restore-links.ts
│ │ │ ├── restore-program-enrollments.ts
│ │ │ └── restore-program-folders.ts
│ │ ├── move-links-to-folder.ts
│ │ ├── partners/
│ │ │ ├── aggregate-stats-seeding.ts
│ │ │ ├── check-pending-paypal-payouts.ts
│ │ │ ├── combine-payouts.ts
│ │ │ ├── delete-partner-profile.ts
│ │ │ ├── delete-partners-for-program.ts
│ │ │ ├── delete-program-application.ts
│ │ │ ├── delete-program-enrollment.ts
│ │ │ ├── delete-program.ts
│ │ │ ├── export-partners.ts
│ │ │ ├── fix-partner-groups.ts
│ │ │ ├── fix-partner-payouts.ts
│ │ │ ├── get-largest-programs.ts
│ │ │ ├── invalidate-partner-links.ts
│ │ │ ├── merge-partner-profile.ts
│ │ │ ├── update-links.ts
│ │ │ ├── update-partner-country.ts
│ │ │ └── update-payout-dates.ts
│ │ ├── perplexity/
│ │ │ ├── backfill-leads.ts
│ │ │ ├── backfill-tenantids.ts
│ │ │ ├── ban-partners.ts
│ │ │ ├── deactivate-partners.ts
│ │ │ ├── move-partners.ts
│ │ │ ├── partners-updated-countries.ts
│ │ │ ├── review-bounties.ts
│ │ │ ├── update-commissions.ts
│ │ │ └── update-notifications.ts
│ │ ├── persist-customer-avatars.ts
│ │ ├── processed-payouts.ts
│ │ ├── programs/
│ │ │ ├── 1-import-partners.ts
│ │ │ ├── 2-import-partner-links.ts
│ │ │ ├── 3-import-customer-leads.ts
│ │ │ ├── 4-export-stripe-invoices.ts
│ │ │ ├── 5-import-customer-sales.ts
│ │ │ ├── add-to-marketplace.ts
│ │ │ ├── backfill-custom-commissions.ts
│ │ │ ├── backfill-discount-codes.ts
│ │ │ ├── backfill-reuse-commission.ts
│ │ │ ├── delete-program-enrollments.ts
│ │ │ ├── update-commissions-canceled.ts
│ │ │ └── update-commissions-paid.ts
│ │ ├── referral-form-sample.json
│ │ ├── remove-workspace-scopes.ts
│ │ ├── restore-backup.ts
│ │ ├── revert-partner-payout-demo.ts
│ │ ├── reward-conditions.ts
│ │ ├── run.ts
│ │ ├── seed-invite-codes.ts
│ │ ├── seed-support-embeddings.ts
│ │ ├── send-batch-emails.ts
│ │ ├── sent-mail-reset.ts
│ │ ├── ship30/
│ │ │ └── backfill-leads.ts
│ │ ├── sitemap-importer.ts
│ │ ├── stripe/
│ │ │ ├── backfill-stripe-webhook-events.ts
│ │ │ ├── backfill-trace-id.ts
│ │ │ ├── connect-client.ts
│ │ │ ├── delete-connected-account.ts
│ │ │ ├── fix-processed-payouts.ts
│ │ │ ├── get-connected-customer.ts
│ │ │ ├── manual-payouts.ts
│ │ │ ├── retrieve-balance.ts
│ │ │ ├── search-customers.ts
│ │ │ ├── update-payouts-schedule.ts
│ │ │ └── update-stripe-customers.ts
│ │ ├── sync-conversions.ts
│ │ ├── sync-domain-clicks.ts
│ │ ├── sync-expired-links.ts
│ │ ├── sync-limits.ts
│ │ ├── sync-link-clicks.ts
│ │ ├── sync-link-tags.ts
│ │ ├── sync-links-metadata.ts
│ │ ├── sync-tag-analytics.ts
│ │ ├── tella/
│ │ │ ├── remind-applications.ts
│ │ │ ├── update-commission-flat.ts
│ │ │ ├── update-commission-percentage.ts
│ │ │ ├── update-commissions.ts
│ │ │ └── update-reward-tier.ts
│ │ ├── test-paypal-payouts.ts
│ │ ├── testimonial/
│ │ │ ├── final-sync-commissions.ts
│ │ │ ├── sync-commissions.ts
│ │ │ └── update-commissions.ts
│ │ ├── tinybird/
│ │ │ ├── delete-lead-event.ts
│ │ │ ├── delete-links.ts
│ │ │ ├── delete-sale-event.ts
│ │ │ ├── update-click-event.ts
│ │ │ ├── update-lead-event.ts
│ │ │ └── update-sale-event.ts
│ │ ├── trigger-update-partner-stats.ts
│ │ ├── unban-links.ts
│ │ ├── update-integrations.ts
│ │ ├── update-link-owner.ts
│ │ ├── update-not-found.ts
│ │ ├── update-payment-failed.ts
│ │ ├── update-payouts-limits.ts
│ │ ├── update-referral-form-data.ts
│ │ ├── update-spam-links.ts
│ │ ├── update-subscribers.ts
│ │ ├── update-user-notifications.ts
│ │ ├── update-webhook-cache.ts
│ │ ├── update-workspace-dates.ts
│ │ ├── update-workspace-tags.ts
│ │ ├── upload-users.ts
│ │ └── wispr-flow/
│ │ └── update-links.ts
│ ├── styles/
│ │ ├── fonts.ts
│ │ └── globals.css
│ ├── tailwind.config.ts
│ ├── tests/
│ │ ├── analytics/
│ │ │ ├── advanced-filter-helpers.test.ts
│ │ │ ├── get-analytics-advanced.test.ts
│ │ │ ├── get-analytics.test.ts
│ │ │ ├── get-events.test.ts
│ │ │ ├── metadata-query-parser.test.ts
│ │ │ ├── partner-analytics.test.ts
│ │ │ └── public-analytics-dashboard.test.ts
│ │ ├── bounties/
│ │ │ └── index.test.ts
│ │ ├── campaigns/
│ │ │ └── index.test.ts
│ │ ├── commissions/
│ │ │ ├── index.test.ts
│ │ │ └── pagination.test.ts
│ │ ├── customers/
│ │ │ ├── index.test.ts
│ │ │ └── pagination.test.ts
│ │ ├── discounts/
│ │ │ └── index.test.ts
│ │ ├── domains/
│ │ │ └── index.test.ts
│ │ ├── embed-tokens/
│ │ │ └── referrals.test.ts
│ │ ├── folders/
│ │ │ └── index.test.ts
│ │ ├── fraud/
│ │ │ ├── fraud-groups.test.ts
│ │ │ └── index.test.ts
│ │ ├── links/
│ │ │ ├── bulk-create-link.test.ts
│ │ │ ├── bulk-delete-link.test.ts
│ │ │ ├── bulk-update-link.test.ts
│ │ │ ├── count-links.test.ts
│ │ │ ├── create-link-error.test.ts
│ │ │ ├── create-link.test.ts
│ │ │ ├── delete-link.test.ts
│ │ │ ├── folder-link-access.test.ts
│ │ │ ├── list-links.test.ts
│ │ │ ├── retrieve-link.test.ts
│ │ │ ├── retrieve-metatags.test.ts
│ │ │ ├── update-link.test.ts
│ │ │ └── upsert-link.test.ts
│ │ ├── misc/
│ │ │ ├── allowed-hostnames.test.ts
│ │ │ ├── base64.test.ts
│ │ │ ├── calculate-payout-fee-with-waiver.test.ts
│ │ │ ├── case-sensitive-keys.test.ts
│ │ │ ├── check-eligibility-requirements.test.ts
│ │ │ ├── create-id.test.ts
│ │ │ ├── eligibility-condition-schema.test.ts
│ │ │ ├── email-domain-validation.test.ts
│ │ │ ├── filter-active-group-bounties.test.ts
│ │ │ ├── interpolate-email-template.test.ts
│ │ │ └── ip-cidr.test.ts
│ │ ├── partner-groups/
│ │ │ └── index.test.ts
│ │ ├── partners/
│ │ │ ├── analytics.test.ts
│ │ │ ├── ban-partner.test.ts
│ │ │ ├── create-partner-link.test.ts
│ │ │ ├── create-partner.test.ts
│ │ │ ├── deactivate-partner.test.ts
│ │ │ ├── list-partners.test.ts
│ │ │ ├── resource.ts
│ │ │ └── upsert-partner-link.test.ts
│ │ ├── payouts/
│ │ │ └── index.test.ts
│ │ ├── redirects/
│ │ │ └── index.test.ts
│ │ ├── rewards/
│ │ │ ├── click-reward.test.ts
│ │ │ ├── lead-reward.test.ts
│ │ │ ├── reward-conditions.test.ts
│ │ │ └── sale-reward.test.ts
│ │ ├── setupTests.ts
│ │ ├── tags/
│ │ │ ├── create-tag-error.test.ts
│ │ │ ├── create-tag.test.ts
│ │ │ └── list-tags.test.ts
│ │ ├── tracks/
│ │ │ ├── track-click.test.ts
│ │ │ ├── track-lead-client.test.ts
│ │ │ ├── track-lead.test.ts
│ │ │ ├── track-open.test.ts
│ │ │ ├── track-sale-client.test.ts
│ │ │ └── track-sale.test.ts
│ │ ├── utils/
│ │ │ ├── env.ts
│ │ │ ├── fetch-partner.ts
│ │ │ ├── helpers.ts
│ │ │ ├── http.ts
│ │ │ ├── integration-member.ts
│ │ │ ├── integration-old.ts
│ │ │ ├── integration.ts
│ │ │ ├── resource.ts
│ │ │ ├── schema.ts
│ │ │ └── verify-commission.ts
│ │ ├── webhooks/
│ │ │ └── index.test.ts
│ │ ├── workflows/
│ │ │ ├── award-bounty-workflow.test.ts
│ │ │ ├── e2e-endpoints-guard.test.ts
│ │ │ ├── move-group-workflow.test.ts
│ │ │ ├── send-campaign-workflow.test.ts
│ │ │ └── utils/
│ │ │ ├── delete-bounty-and-submissions.ts
│ │ │ ├── track-e2e-lead.ts
│ │ │ ├── verify-bounty-submission.ts
│ │ │ ├── verify-campaign-sent.ts
│ │ │ └── verify-partner-group-move.ts
│ │ └── workspaces/
│ │ ├── retrieve-workspace.error.test.ts
│ │ └── retrieve-workspace.test.ts
│ ├── tsconfig.json
│ ├── ui/
│ │ ├── account/
│ │ │ ├── delete-account.tsx
│ │ │ ├── update-default-workspace.tsx
│ │ │ ├── update-subscription.tsx
│ │ │ ├── upload-avatar.tsx
│ │ │ └── user-id.tsx
│ │ ├── activity-logs/
│ │ │ ├── action-renderers/
│ │ │ │ ├── partner-group-changed-renderer.tsx
│ │ │ │ ├── referral-created-renderer.tsx
│ │ │ │ ├── referral-status-changed-renderer.tsx
│ │ │ │ └── reward-activity-renderer.tsx
│ │ │ ├── activity-entry-chips.tsx
│ │ │ ├── activity-feed.tsx
│ │ │ ├── activity-log-context.tsx
│ │ │ ├── activity-log-description.tsx
│ │ │ ├── activity-log-registry.tsx
│ │ │ ├── partner-group-activity-item.tsx
│ │ │ ├── partner-group-activity-section.tsx
│ │ │ ├── partner-group-history-sheet.tsx
│ │ │ ├── partner-referral-activity-section.tsx
│ │ │ ├── referral-activity-item.tsx
│ │ │ ├── referral-activity-section.tsx
│ │ │ ├── reward-activity-item.tsx
│ │ │ ├── reward-activity-section.tsx
│ │ │ └── reward-history-sheet.tsx
│ │ ├── analytics/
│ │ │ ├── analytics-area-chart.tsx
│ │ │ ├── analytics-card.tsx
│ │ │ ├── analytics-export-button.tsx
│ │ │ ├── analytics-funnel-chart.tsx
│ │ │ ├── analytics-loading-spinner.tsx
│ │ │ ├── analytics-options.tsx
│ │ │ ├── analytics-provider.tsx
│ │ │ ├── analytics-tabs.tsx
│ │ │ ├── bar-list.tsx
│ │ │ ├── chart-section.tsx
│ │ │ ├── chart-view-switcher.tsx
│ │ │ ├── continent-icon.tsx
│ │ │ ├── device-icon.tsx
│ │ │ ├── device-section.tsx
│ │ │ ├── events/
│ │ │ │ ├── events-export-button.tsx
│ │ │ │ ├── events-provider.tsx
│ │ │ │ ├── events-table.tsx
│ │ │ │ ├── events-tabs.tsx
│ │ │ │ ├── example-data.ts
│ │ │ │ ├── index.tsx
│ │ │ │ ├── metadata-viewer.tsx
│ │ │ │ └── row-menu-button.tsx
│ │ │ ├── index.tsx
│ │ │ ├── link-preview.tsx
│ │ │ ├── location-section.tsx
│ │ │ ├── partner-section.tsx
│ │ │ ├── referrer-icon.tsx
│ │ │ ├── referrers-utms.tsx
│ │ │ ├── share-button.tsx
│ │ │ ├── toggle.tsx
│ │ │ ├── top-links.tsx
│ │ │ ├── trigger-display.tsx
│ │ │ ├── use-analytics-connected-status.ts
│ │ │ ├── use-analytics-filters.tsx
│ │ │ ├── use-analytics-query.tsx
│ │ │ └── utils.ts
│ │ ├── auth/
│ │ │ ├── auth-alternative-banner.tsx
│ │ │ ├── auth-methods-separator.tsx
│ │ │ ├── forgot-password-form.tsx
│ │ │ ├── login/
│ │ │ │ ├── email-sign-in.tsx
│ │ │ │ ├── framer-button.tsx
│ │ │ │ ├── github-button.tsx
│ │ │ │ ├── google-button.tsx
│ │ │ │ ├── login-form.tsx
│ │ │ │ └── sso-sign-in.tsx
│ │ │ ├── register/
│ │ │ │ ├── context.tsx
│ │ │ │ ├── resend-otp.tsx
│ │ │ │ ├── signup-email.tsx
│ │ │ │ ├── signup-form.tsx
│ │ │ │ ├── signup-oauth.tsx
│ │ │ │ └── verify-email-form.tsx
│ │ │ └── reset-password-form.tsx
│ │ ├── colors.ts
│ │ ├── customers/
│ │ │ ├── customer-activity-list.tsx
│ │ │ ├── customer-avatar.tsx
│ │ │ ├── customer-details-column.tsx
│ │ │ ├── customer-partner-earnings-table.tsx
│ │ │ ├── customer-row-item.tsx
│ │ │ ├── customer-sales-table.tsx
│ │ │ ├── customer-selector.tsx
│ │ │ ├── customer-stats.tsx
│ │ │ ├── customer-tabs.tsx
│ │ │ ├── customers-table/
│ │ │ │ ├── customers-table.tsx
│ │ │ │ ├── example-data.ts
│ │ │ │ └── use-customer-filters.tsx
│ │ │ └── export-customers-button.tsx
│ │ ├── domains/
│ │ │ ├── add-edit-domain-form.tsx
│ │ │ ├── domain-card-placeholder.tsx
│ │ │ ├── domain-card-title-column.tsx
│ │ │ ├── domain-card.tsx
│ │ │ ├── domain-configuration.tsx
│ │ │ ├── domain-selector.tsx
│ │ │ ├── free-dot-link-banner.tsx
│ │ │ └── register-domain-form.tsx
│ │ ├── dub-partners-logo.tsx
│ │ ├── folders/
│ │ │ ├── add-folder-form.tsx
│ │ │ ├── edit-folder-form.tsx
│ │ │ ├── edit-folder-sheet.tsx
│ │ │ ├── folder-actions.tsx
│ │ │ ├── folder-card-placeholder.tsx
│ │ │ ├── folder-card.tsx
│ │ │ ├── folder-dropdown.tsx
│ │ │ ├── folder-icon.tsx
│ │ │ ├── folder-info-panel.tsx
│ │ │ ├── move-link-form.tsx
│ │ │ ├── rename-folder-form.tsx
│ │ │ ├── request-edit-button.tsx
│ │ │ ├── simple-folder-card.tsx
│ │ │ └── utils.ts
│ │ ├── guides/
│ │ │ ├── guide-action-button.tsx
│ │ │ ├── guide-list.tsx
│ │ │ ├── guide-selector.tsx
│ │ │ ├── guide.tsx
│ │ │ ├── icons/
│ │ │ │ ├── appwrite.tsx
│ │ │ │ ├── auth-js.tsx
│ │ │ │ ├── auth0.tsx
│ │ │ │ ├── better-auth.tsx
│ │ │ │ ├── clerk.tsx
│ │ │ │ ├── code-editor.tsx
│ │ │ │ ├── custom.tsx
│ │ │ │ ├── framer.tsx
│ │ │ │ ├── gtm.tsx
│ │ │ │ ├── next-auth.tsx
│ │ │ │ ├── react.tsx
│ │ │ │ ├── segment.tsx
│ │ │ │ ├── shopify.tsx
│ │ │ │ ├── supabase.tsx
│ │ │ │ ├── webflow.tsx
│ │ │ │ └── wordpress.tsx
│ │ │ ├── install-stripe-integration-button.tsx
│ │ │ ├── integrations.ts
│ │ │ └── markdown.tsx
│ │ ├── integrations/
│ │ │ ├── integration-card.tsx
│ │ │ └── integration-logo.tsx
│ │ ├── layout/
│ │ │ ├── auth-layout.tsx
│ │ │ ├── changelog-popup.tsx
│ │ │ ├── layout-loader.tsx
│ │ │ ├── main-nav.tsx
│ │ │ ├── page-content/
│ │ │ │ ├── index.tsx
│ │ │ │ ├── nav-button.tsx
│ │ │ │ ├── page-content-header.tsx
│ │ │ │ ├── page-content-old.tsx
│ │ │ │ ├── page-content-with-side-panel.tsx
│ │ │ │ └── toggle-side-panel-button.tsx
│ │ │ ├── page-nav-tabs.tsx
│ │ │ ├── page-width-wrapper.tsx
│ │ │ ├── settings-layout.tsx
│ │ │ ├── sidebar/
│ │ │ │ ├── affiliate-program-popup.tsx
│ │ │ │ ├── app-sidebar-nav.tsx
│ │ │ │ ├── dub-partners-popup.tsx
│ │ │ │ ├── help-button.tsx
│ │ │ │ ├── icons/
│ │ │ │ │ ├── compass.tsx
│ │ │ │ │ ├── connected-dots4.tsx
│ │ │ │ │ ├── cursor-rays.tsx
│ │ │ │ │ ├── gear.tsx
│ │ │ │ │ ├── hyperlink.tsx
│ │ │ │ │ ├── lines-y.tsx
│ │ │ │ │ └── user.tsx
│ │ │ │ ├── news-rsc.tsx
│ │ │ │ ├── news.tsx
│ │ │ │ ├── partner-program-dropdown.tsx
│ │ │ │ ├── partners-sidebar-nav.tsx
│ │ │ │ ├── payout-stats.tsx
│ │ │ │ ├── program-help-support.tsx
│ │ │ │ ├── refer-button.tsx
│ │ │ │ ├── sidebar-nav.tsx
│ │ │ │ ├── sidebar-usage.tsx
│ │ │ │ ├── use-program-applications-count.tsx
│ │ │ │ ├── user-dropdown.tsx
│ │ │ │ ├── workspace-dropdown.tsx
│ │ │ │ └── year-in-review-card.tsx
│ │ │ ├── toolbar/
│ │ │ │ ├── onboarding/
│ │ │ │ │ └── onboarding-button.tsx
│ │ │ │ └── toolbar.tsx
│ │ │ ├── upgrade-banner.tsx
│ │ │ └── user-survey/
│ │ │ ├── index.tsx
│ │ │ └── survey-form.tsx
│ │ ├── links/
│ │ │ ├── archived-links-hint.tsx
│ │ │ ├── comments-badge.tsx
│ │ │ ├── destination-url-input.tsx
│ │ │ ├── disabled-link-tooltip.tsx
│ │ │ ├── link-analytics-badge.tsx
│ │ │ ├── link-builder/
│ │ │ │ ├── constants.ts
│ │ │ │ ├── controls/
│ │ │ │ │ ├── link-builder-destination-url-input.tsx
│ │ │ │ │ ├── link-builder-folder-selector.tsx
│ │ │ │ │ ├── link-builder-short-link-input.tsx
│ │ │ │ │ └── link-comments-input.tsx
│ │ │ │ ├── conversion-tracking-toggle.tsx
│ │ │ │ ├── draft-controls.tsx
│ │ │ │ ├── link-action-bar.tsx
│ │ │ │ ├── link-builder-header.tsx
│ │ │ │ ├── link-builder-provider.tsx
│ │ │ │ ├── link-creator-info.tsx
│ │ │ │ ├── link-feature-buttons.tsx
│ │ │ │ ├── link-partner-details.tsx
│ │ │ │ ├── link-preview.tsx
│ │ │ │ ├── more-dropdown.tsx
│ │ │ │ ├── multi-tags-icon.tsx
│ │ │ │ ├── options-list.tsx
│ │ │ │ ├── qr-code-preview.tsx
│ │ │ │ ├── tag-select.tsx
│ │ │ │ ├── use-link-builder-keyboard-shortcut.ts
│ │ │ │ ├── use-link-builder-submit.tsx
│ │ │ │ ├── use-metatags.ts
│ │ │ │ └── utm-templates-button.tsx
│ │ │ ├── link-card-placeholder.tsx
│ │ │ ├── link-card.tsx
│ │ │ ├── link-controls.tsx
│ │ │ ├── link-details-column.tsx
│ │ │ ├── link-display.tsx
│ │ │ ├── link-icon.tsx
│ │ │ ├── link-not-found.tsx
│ │ │ ├── link-selection-provider.tsx
│ │ │ ├── link-sort.tsx
│ │ │ ├── link-tests.tsx
│ │ │ ├── link-title-column.tsx
│ │ │ ├── links-container.tsx
│ │ │ ├── links-display-provider.tsx
│ │ │ ├── links-toolbar.tsx
│ │ │ ├── short-link-input.tsx
│ │ │ ├── simple-link-card.tsx
│ │ │ ├── tag-badge.tsx
│ │ │ ├── tests-badge.tsx
│ │ │ ├── use-available-domains.ts
│ │ │ ├── use-folder-filter-options.ts
│ │ │ └── use-link-filters.tsx
│ │ ├── messages/
│ │ │ ├── message-markdown.tsx
│ │ │ ├── messages-context.tsx
│ │ │ ├── messages-list.tsx
│ │ │ ├── messages-panel.tsx
│ │ │ └── toggle-side-panel-button.tsx
│ │ ├── modals/
│ │ │ ├── add-customer-modal.tsx
│ │ │ ├── add-discount-code-modal.tsx
│ │ │ ├── add-edit-domain-modal.tsx
│ │ │ ├── add-edit-email-domain-modal.tsx
│ │ │ ├── add-edit-tag-modal.tsx
│ │ │ ├── add-edit-token-modal.tsx
│ │ │ ├── add-edit-utm-template.modal.tsx
│ │ │ ├── add-folder-modal.tsx
│ │ │ ├── add-partner-link-modal.tsx
│ │ │ ├── add-payment-method-modal.tsx
│ │ │ ├── add-workspace-modal.tsx
│ │ │ ├── application-settings-modal.tsx
│ │ │ ├── archive-domain-modal.tsx
│ │ │ ├── archive-link-modal.tsx
│ │ │ ├── archive-partner-modal.tsx
│ │ │ ├── ban-partner-modal.tsx
│ │ │ ├── bulk-approve-partners-modal.tsx
│ │ │ ├── bulk-archive-partners-modal.tsx
│ │ │ ├── bulk-ban-partners-modal.tsx
│ │ │ ├── bulk-deactivate-partners-modal.tsx
│ │ │ ├── bulk-reject-partners-modal.tsx
│ │ │ ├── bulk-resolve-fraud-groups-modal.tsx
│ │ │ ├── change-group-modal.tsx
│ │ │ ├── confirm-approve-bounty-submission-modal.tsx
│ │ │ ├── confirm-modal.tsx
│ │ │ ├── confirm-referral-status-change-modal.tsx
│ │ │ ├── confirm-set-default-group-modal.tsx
│ │ │ ├── deactivate-partner-modal.tsx
│ │ │ ├── delete-account-modal.tsx
│ │ │ ├── delete-discount-code-modal.tsx
│ │ │ ├── delete-domain-modal.tsx
│ │ │ ├── delete-email-domain-modal.tsx
│ │ │ ├── delete-folder-modal.tsx
│ │ │ ├── delete-group-modal.tsx
│ │ │ ├── delete-link-modal.tsx
│ │ │ ├── delete-partner-link-modal.tsx
│ │ │ ├── delete-token-modal.tsx
│ │ │ ├── delete-webhook-modal.tsx
│ │ │ ├── delete-workspace-modal.tsx
│ │ │ ├── disable-fraud-rules-modal.tsx
│ │ │ ├── domain-auto-renewal-modal.tsx
│ │ │ ├── domain-verification-modal.tsx
│ │ │ ├── dot-link-offer-modal.tsx
│ │ │ ├── edit-customer-modal.tsx
│ │ │ ├── edit-referral-modal.tsx
│ │ │ ├── export-applications-modal.tsx
│ │ │ ├── export-commissions-modal.tsx
│ │ │ ├── export-customers-modal.tsx
│ │ │ ├── export-links-modal.tsx
│ │ │ ├── export-partners-modal.tsx
│ │ │ ├── google-oauth-modal.tsx
│ │ │ ├── import-bitly-modal.tsx
│ │ │ ├── import-csv-modal/
│ │ │ │ ├── field-mapping.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── select-file.tsx
│ │ │ ├── import-firstpromoter-modal.tsx
│ │ │ ├── import-partnerstack-modal.tsx
│ │ │ ├── import-rebrandly-modal.tsx
│ │ │ ├── import-rewardful-modal.tsx
│ │ │ ├── import-short-modal.tsx
│ │ │ ├── import-tolt-modal.tsx
│ │ │ ├── invite-code-modal.tsx
│ │ │ ├── invite-partner-user-modal.tsx
│ │ │ ├── invite-referral-modal.tsx
│ │ │ ├── invite-workspace-user-modal.tsx
│ │ │ ├── link-builder/
│ │ │ │ ├── ab-testing/
│ │ │ │ │ ├── ab-testing-modal.tsx
│ │ │ │ │ ├── end-ab-testing-modal.tsx
│ │ │ │ │ └── traffic-split-slider.tsx
│ │ │ │ ├── ab-testing-modal.tsx
│ │ │ │ ├── advanced-modal.tsx
│ │ │ │ ├── expiration-modal.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── og-modal.tsx
│ │ │ │ ├── partners-modal.tsx
│ │ │ │ ├── password-modal.tsx
│ │ │ │ ├── targeting-modal.tsx
│ │ │ │ ├── unsplash-search.tsx
│ │ │ │ ├── use-link-drafts.ts
│ │ │ │ ├── utm-modal.tsx
│ │ │ │ ├── utm-templates-combo.tsx
│ │ │ │ └── webhooks-modal.tsx
│ │ │ ├── link-conversion-tracking-modal.tsx
│ │ │ ├── link-qr-modal.tsx
│ │ │ ├── manage-usage-modal.tsx
│ │ │ ├── modal-provider.tsx
│ │ │ ├── move-link-to-folder-modal.tsx
│ │ │ ├── oauth-app-created-modal.tsx
│ │ │ ├── partner-link-modal.tsx
│ │ │ ├── partner-link-qr-modal.tsx
│ │ │ ├── plan-change-confirmation-modal.tsx
│ │ │ ├── primary-domain-modal.tsx
│ │ │ ├── program-welcome-modal.tsx
│ │ │ ├── prompt-modal.tsx
│ │ │ ├── reactivate-partner-modal.tsx
│ │ │ ├── register-domain-modal.tsx
│ │ │ ├── register-domain-success-modal.tsx
│ │ │ ├── reject-partner-application-modal.tsx
│ │ │ ├── remove-oauth-app-modal.tsx
│ │ │ ├── remove-partner-user-modal.tsx
│ │ │ ├── remove-saml-modal.tsx
│ │ │ ├── remove-scim-modal.tsx
│ │ │ ├── remove-workspace-user-modal.tsx
│ │ │ ├── rename-folder-modal.tsx
│ │ │ ├── saml-modal.tsx
│ │ │ ├── scim-modal.tsx
│ │ │ ├── send-test-webhook-modal.tsx
│ │ │ ├── set-default-folder-modal.tsx
│ │ │ ├── share-dashboard-modal.tsx
│ │ │ ├── social-verification-by-code-modal.tsx
│ │ │ ├── submit-oauth-app-modal.tsx
│ │ │ ├── tag-link-modal.tsx
│ │ │ ├── token-created-modal.tsx
│ │ │ ├── transfer-domain-modal.tsx
│ │ │ ├── transfer-link-modal.tsx
│ │ │ ├── unban-partner-modal.tsx
│ │ │ ├── uninstall-integration-modal.tsx
│ │ │ ├── update-partner-user-modal.tsx
│ │ │ ├── update-workspace-user-role.tsx
│ │ │ └── upgraded-modal.tsx
│ │ ├── oauth-apps/
│ │ │ ├── add-edit-app-form.tsx
│ │ │ ├── add-edit-integration-form.tsx
│ │ │ ├── oauth-app-card.tsx
│ │ │ ├── oauth-app-credentials.tsx
│ │ │ └── oauth-app-placeholder.tsx
│ │ ├── partners/
│ │ │ ├── activity-event.tsx
│ │ │ ├── bounties/
│ │ │ │ ├── bounty-description.tsx
│ │ │ │ ├── bounty-incremental-bonus-tooltip.tsx
│ │ │ │ ├── bounty-performance.tsx
│ │ │ │ ├── bounty-platform-icons.ts
│ │ │ │ ├── bounty-progress-bar-row.tsx
│ │ │ │ ├── bounty-reward-criteria.tsx
│ │ │ │ ├── bounty-reward-description.tsx
│ │ │ │ ├── bounty-social-content-preview.tsx
│ │ │ │ ├── bounty-social-content.tsx
│ │ │ │ ├── bounty-social-metrics-rewards-table.tsx
│ │ │ │ ├── bounty-status-badge.tsx
│ │ │ │ ├── bounty-submission-details-sheet.tsx
│ │ │ │ ├── bounty-submission-requirements.tsx
│ │ │ │ ├── bounty-thumbnail-image.tsx
│ │ │ │ ├── claim-bounty-context.tsx
│ │ │ │ ├── claim-bounty-sheet.tsx
│ │ │ │ ├── reject-bounty-submission-modal.tsx
│ │ │ │ ├── use-claim-bounty-form.ts
│ │ │ │ └── use-social-content.ts
│ │ │ ├── comission-type-icon.tsx
│ │ │ ├── commission-row-menu.tsx
│ │ │ ├── commission-status-badges.tsx
│ │ │ ├── commission-type-badge.tsx
│ │ │ ├── confirm-payouts-sheet.tsx
│ │ │ ├── constants.ts
│ │ │ ├── conversion-score-icon.tsx
│ │ │ ├── country-combobox.tsx
│ │ │ ├── discounts/
│ │ │ │ ├── add-edit-discount-sheet.tsx
│ │ │ │ └── discount-code-badge.tsx
│ │ │ ├── eligibility-requirements.tsx
│ │ │ ├── external-payouts-indicator.tsx
│ │ │ ├── format-discount-description.ts
│ │ │ ├── format-reward-description.ts
│ │ │ ├── fraud-risks/
│ │ │ │ ├── commissions-on-hold-table.tsx
│ │ │ │ ├── fraud-disclaimer-banner.tsx
│ │ │ │ ├── fraud-events-tables/
│ │ │ │ │ ├── fraud-cross-program-ban-table.tsx
│ │ │ │ │ ├── fraud-matching-customer-email-table.tsx
│ │ │ │ │ ├── fraud-paid-traffic-detected-table.tsx
│ │ │ │ │ ├── fraud-partner-info-table.tsx
│ │ │ │ │ ├── fraud-referral-source-banned-table.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── fraud-review-sheet.tsx
│ │ │ │ ├── partner-application-fraud-severity-indicator.tsx
│ │ │ │ ├── partner-application-risk-summary-modal.tsx
│ │ │ │ ├── partner-application-risk-summary.tsx
│ │ │ │ ├── partner-cross-program-summary.tsx
│ │ │ │ ├── partner-fraud-banner.tsx
│ │ │ │ ├── partner-fraud-indicator.tsx
│ │ │ │ ├── resolve-fraud-group-modal.tsx
│ │ │ │ └── resolved-fraud-group-table.tsx
│ │ │ ├── groups/
│ │ │ │ ├── design/
│ │ │ │ │ ├── application-form/
│ │ │ │ │ │ ├── application-hero-preview.tsx
│ │ │ │ │ │ ├── fields/
│ │ │ │ │ │ │ ├── form-control.tsx
│ │ │ │ │ │ │ ├── image-upload-field.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── long-text-field.tsx
│ │ │ │ │ │ │ ├── max-character-count.tsx
│ │ │ │ │ │ │ ├── multiple-choice-field.tsx
│ │ │ │ │ │ │ ├── select-field.tsx
│ │ │ │ │ │ │ ├── short-text-field.tsx
│ │ │ │ │ │ │ └── website-and-socials-field.tsx
│ │ │ │ │ │ ├── form-data-for-application-form-data.ts
│ │ │ │ │ │ ├── modals/
│ │ │ │ │ │ │ ├── add-field-modal.tsx
│ │ │ │ │ │ │ ├── edit-application-hero-modal.tsx
│ │ │ │ │ │ │ ├── generate-lander-modal.tsx
│ │ │ │ │ │ │ ├── image-upload-field-modal.tsx
│ │ │ │ │ │ │ ├── long-text-field-modal.tsx
│ │ │ │ │ │ │ ├── multiple-choice-field-modal.tsx
│ │ │ │ │ │ │ ├── select-field-modal.tsx
│ │ │ │ │ │ │ ├── short-text-field-modal.tsx
│ │ │ │ │ │ │ └── website-and-socials-field-modal.tsx
│ │ │ │ │ │ ├── program-application-form.tsx
│ │ │ │ │ │ ├── program-terms-preview.tsx
│ │ │ │ │ │ └── required-fields-preview.tsx
│ │ │ │ │ ├── branding-context-provider.tsx
│ │ │ │ │ ├── branding-form.tsx
│ │ │ │ │ ├── branding-settings-form.tsx
│ │ │ │ │ ├── edit-list.tsx
│ │ │ │ │ ├── lander/
│ │ │ │ │ │ ├── lander-ai-banner.tsx
│ │ │ │ │ │ ├── lander-preview-controls.tsx
│ │ │ │ │ │ └── modals/
│ │ │ │ │ │ ├── accordion-block-modal.tsx
│ │ │ │ │ │ ├── add-block-modal.tsx
│ │ │ │ │ │ ├── earnings-calculator-block-modal.tsx
│ │ │ │ │ │ ├── edit-hero-modal.tsx
│ │ │ │ │ │ ├── files-block-modal.tsx
│ │ │ │ │ │ ├── generate-lander-modal.tsx
│ │ │ │ │ │ ├── image-block-modal.tsx
│ │ │ │ │ │ └── text-block-modal.tsx
│ │ │ │ │ ├── preview-window.tsx
│ │ │ │ │ ├── previews/
│ │ │ │ │ │ ├── application-preview.tsx
│ │ │ │ │ │ ├── embed-preview.tsx
│ │ │ │ │ │ ├── lander-preview.tsx
│ │ │ │ │ │ └── portal-preview.tsx
│ │ │ │ │ └── studs-pattern.tsx
│ │ │ │ ├── group-color-circle.tsx
│ │ │ │ ├── group-color-picker.tsx
│ │ │ │ ├── group-selector.tsx
│ │ │ │ ├── group-settings-row.tsx
│ │ │ │ ├── groups-multi-select.tsx
│ │ │ │ └── reward-discount-partners-card.tsx
│ │ │ ├── hero-background.tsx
│ │ │ ├── lander/
│ │ │ │ ├── blocks/
│ │ │ │ │ ├── accordion-block.tsx
│ │ │ │ │ ├── block-description.tsx
│ │ │ │ │ ├── block-markdown.tsx
│ │ │ │ │ ├── block-title.tsx
│ │ │ │ │ ├── earnings-calculator-block.tsx
│ │ │ │ │ ├── files-block.tsx
│ │ │ │ │ ├── image-block.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── text-block.tsx
│ │ │ │ │ └── wave-pattern.tsx
│ │ │ │ ├── lander-hero.tsx
│ │ │ │ └── lander-rewards.tsx
│ │ │ ├── mark-commission-duplicate-modal.tsx
│ │ │ ├── mark-commission-fraud-or-canceled-modal.tsx
│ │ │ ├── merge-accounts/
│ │ │ │ ├── account-input-group.tsx
│ │ │ │ ├── form-context.tsx
│ │ │ │ ├── merge-account-form.tsx
│ │ │ │ ├── merge-partner-accounts-modal.tsx
│ │ │ │ ├── otp-input-field.tsx
│ │ │ │ ├── send-verification-code-form.tsx
│ │ │ │ ├── step-progress-bar.tsx
│ │ │ │ └── verify-code-form.tsx
│ │ │ ├── overview/
│ │ │ │ ├── blocks/
│ │ │ │ │ ├── commissions-block.tsx
│ │ │ │ │ ├── conversion-block.tsx
│ │ │ │ │ ├── countries-block.tsx
│ │ │ │ │ ├── links-block.tsx
│ │ │ │ │ ├── partners-block.tsx
│ │ │ │ │ ├── sale-type-block.tsx
│ │ │ │ │ └── traffic-sources-block.tsx
│ │ │ │ ├── exceeded-events-limit.tsx
│ │ │ │ ├── program-overview-block.tsx
│ │ │ │ └── program-overview-card.tsx
│ │ │ ├── partner-about.tsx
│ │ │ ├── partner-advanced-settings-modal.tsx
│ │ │ ├── partner-application-details.tsx
│ │ │ ├── partner-application-sheet.tsx
│ │ │ ├── partner-avatar.tsx
│ │ │ ├── partner-comments.tsx
│ │ │ ├── partner-info-cards.tsx
│ │ │ ├── partner-info-group.tsx
│ │ │ ├── partner-info-section.tsx
│ │ │ ├── partner-info-stats.tsx
│ │ │ ├── partner-link-selector.tsx
│ │ │ ├── partner-network/
│ │ │ │ ├── conversion-score-tooltip.tsx
│ │ │ │ ├── invites-usage.tsx
│ │ │ │ └── network-partner-sheet.tsx
│ │ │ ├── partner-platform-card.tsx
│ │ │ ├── partner-platform-summary.tsx
│ │ │ ├── partner-platforms-form.tsx
│ │ │ ├── partner-profile-sheet.tsx
│ │ │ ├── partner-row-item.tsx
│ │ │ ├── partner-selector.tsx
│ │ │ ├── partner-sheet-tabs.tsx
│ │ │ ├── partner-social-column.tsx
│ │ │ ├── partner-star-button.tsx
│ │ │ ├── partner-status-badge-with-tooltip.tsx
│ │ │ ├── partner-status-badges.ts
│ │ │ ├── partners-upgrade-modal.tsx
│ │ │ ├── payout-row-menu.tsx
│ │ │ ├── payout-status-badge-partner.tsx
│ │ │ ├── payout-status-badges.tsx
│ │ │ ├── payout-status-descriptions.ts
│ │ │ ├── payouts/
│ │ │ │ ├── bank-account-requirements-modal.tsx
│ │ │ │ ├── connect-payout-button.tsx
│ │ │ │ ├── connect-payout-modal.tsx
│ │ │ │ ├── payout-method-cards.tsx
│ │ │ │ ├── payout-method-config.ts
│ │ │ │ ├── payout-method-dropdown.tsx
│ │ │ │ ├── stablecoin-payout-banner.tsx
│ │ │ │ ├── stablecoin-payout-card.tsx
│ │ │ │ ├── stablecoin-payout-icon.tsx
│ │ │ │ ├── stablecoin-payout-modal.tsx
│ │ │ │ ├── use-payout-connect-flow.tsx
│ │ │ │ └── use-stablecoin-payout-promo.tsx
│ │ │ ├── program-application-sheet.tsx
│ │ │ ├── program-card.tsx
│ │ │ ├── program-category-select.tsx
│ │ │ ├── program-color-picker.tsx
│ │ │ ├── program-eligibility-card.tsx
│ │ │ ├── program-help-links.tsx
│ │ │ ├── program-invite-card.tsx
│ │ │ ├── program-link-configuration.tsx
│ │ │ ├── program-marketplace/
│ │ │ │ ├── program-category.tsx
│ │ │ │ ├── program-marketplace-banner.tsx
│ │ │ │ ├── program-marketplace-card.tsx
│ │ │ │ ├── program-marketplace-logos.tsx
│ │ │ │ ├── program-reward-icon.tsx
│ │ │ │ ├── program-rewards-display.tsx
│ │ │ │ ├── programs-promo-banner.tsx
│ │ │ │ ├── programs-promo-card.tsx
│ │ │ │ └── use-program-marketplace-promo.tsx
│ │ │ ├── program-onboarding-form-wrapper.tsx
│ │ │ ├── program-reward-description.tsx
│ │ │ ├── program-reward-list.tsx
│ │ │ ├── program-reward-modifiers-tooltip.tsx
│ │ │ ├── program-reward-terms.tsx
│ │ │ ├── program-rewards-panel.tsx
│ │ │ ├── program-selector.tsx
│ │ │ ├── program-sheet-accordion.tsx
│ │ │ ├── program-stats-filter.tsx
│ │ │ ├── resources/
│ │ │ │ ├── resource-card.tsx
│ │ │ │ └── resource-section.tsx
│ │ │ ├── rewards/
│ │ │ │ ├── add-edit-reward-sheet.tsx
│ │ │ │ ├── reward-icon-square.tsx
│ │ │ │ ├── reward-preview-card.tsx
│ │ │ │ └── rewards-logic.tsx
│ │ │ ├── rewind/
│ │ │ │ ├── constants.ts
│ │ │ │ ├── partner-rewind-banner.tsx
│ │ │ │ ├── partner-rewind-card.tsx
│ │ │ │ └── use-partner-rewind-status.tsx
│ │ │ ├── trusted-partner-badge.tsx
│ │ │ └── use-country-change-warning-modal.tsx
│ │ ├── placeholders/
│ │ │ ├── bubble-icon.tsx
│ │ │ ├── button-link.tsx
│ │ │ ├── cta.tsx
│ │ │ ├── feature-graphics/
│ │ │ │ ├── analytics.tsx
│ │ │ │ ├── collaboration.tsx
│ │ │ │ ├── domains.tsx
│ │ │ │ ├── personalization.tsx
│ │ │ │ └── qr.tsx
│ │ │ ├── features-section.tsx
│ │ │ ├── hero.tsx
│ │ │ └── logos.tsx
│ │ ├── postbacks/
│ │ │ ├── add-edit-postback-modal.tsx
│ │ │ ├── partner-postback-actions.tsx
│ │ │ ├── postback-card.tsx
│ │ │ ├── postback-detail-skeleton.tsx
│ │ │ ├── postback-event-details-sheet.tsx
│ │ │ ├── postback-event-list-skeleton.tsx
│ │ │ ├── postback-event-list.tsx
│ │ │ ├── postback-placeholder.tsx
│ │ │ ├── postback-secret-modal.tsx
│ │ │ ├── postback-status.tsx
│ │ │ └── send-test-postback-modal.tsx
│ │ ├── referrals/
│ │ │ ├── form-fields/
│ │ │ │ ├── country-field.tsx
│ │ │ │ ├── date-field.tsx
│ │ │ │ ├── form-control.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── max-character-count.tsx
│ │ │ │ ├── multi-select-field.tsx
│ │ │ │ ├── number-field.tsx
│ │ │ │ ├── phone-field.tsx
│ │ │ │ ├── select-field.tsx
│ │ │ │ ├── text-field.tsx
│ │ │ │ └── textarea-field.tsx
│ │ │ ├── partner-profile-referral-sheet.tsx
│ │ │ ├── partner-profile-referrals-empty-state.tsx
│ │ │ ├── partner-referral-sheet.tsx
│ │ │ ├── partner-referral-table.tsx
│ │ │ ├── referral-details.tsx
│ │ │ ├── referral-form.tsx
│ │ │ ├── referral-lead-details.tsx
│ │ │ ├── referral-partner-details.tsx
│ │ │ ├── referral-status-badge.tsx
│ │ │ ├── referral-status-badges.ts
│ │ │ ├── referral-status-dropdown.tsx
│ │ │ ├── referral-utils.ts
│ │ │ ├── submit-referral-sheet.tsx
│ │ │ └── use-program-referral-filters.tsx
│ │ ├── shared/
│ │ │ ├── amount-input.tsx
│ │ │ ├── animated-empty-state.tsx
│ │ │ ├── back-link.tsx
│ │ │ ├── business-badge-tooltip.tsx
│ │ │ ├── conditional-link.tsx
│ │ │ ├── custom-toast.tsx
│ │ │ ├── emoji-picker.tsx
│ │ │ ├── empty-state.tsx
│ │ │ ├── filter-button-table-row.tsx
│ │ │ ├── icons/
│ │ │ │ ├── airplay.tsx
│ │ │ │ ├── alert-circle-fill.tsx
│ │ │ │ ├── chart.tsx
│ │ │ │ ├── check-circle-fill.tsx
│ │ │ │ ├── clipboard.tsx
│ │ │ │ ├── delete.tsx
│ │ │ │ ├── devices.tsx
│ │ │ │ ├── divider.tsx
│ │ │ │ ├── download.tsx
│ │ │ │ ├── drag.tsx
│ │ │ │ ├── edit.tsx
│ │ │ │ ├── external-link.tsx
│ │ │ │ ├── eye-off.tsx
│ │ │ │ ├── eye.tsx
│ │ │ │ ├── filter.tsx
│ │ │ │ ├── heart.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── infinity.tsx
│ │ │ │ ├── link.tsx
│ │ │ │ ├── lock.tsx
│ │ │ │ ├── logout.tsx
│ │ │ │ ├── message.tsx
│ │ │ │ ├── qr.tsx
│ │ │ │ ├── random.tsx
│ │ │ │ ├── repeat.tsx
│ │ │ │ ├── save.tsx
│ │ │ │ ├── search.tsx
│ │ │ │ ├── sort.tsx
│ │ │ │ ├── three-dots.tsx
│ │ │ │ ├── upload-cloud.tsx
│ │ │ │ ├── users.tsx
│ │ │ │ ├── x-circle-fill.tsx
│ │ │ │ └── x.tsx
│ │ │ ├── inline-badge-popover.tsx
│ │ │ ├── markdown-description.tsx
│ │ │ ├── markdown.tsx
│ │ │ ├── max-characters-counter.tsx
│ │ │ ├── message-input.tsx
│ │ │ ├── modal-hero.tsx
│ │ │ ├── new-background.tsx
│ │ │ ├── password-requirements.tsx
│ │ │ ├── pro-badge-tooltip.tsx
│ │ │ ├── qr-code.tsx
│ │ │ ├── search-box.tsx
│ │ │ ├── simple-date-range-picker.tsx
│ │ │ ├── simple-empty-state.tsx
│ │ │ ├── upgrade-required-toast.tsx
│ │ │ └── zoom-image.tsx
│ │ ├── support/
│ │ │ ├── chat-bubble.tsx
│ │ │ ├── chat-interface.tsx
│ │ │ ├── clear-chat-button.tsx
│ │ │ ├── code-block.tsx
│ │ │ ├── embedded-chat.tsx
│ │ │ ├── message.tsx
│ │ │ ├── program-combobox.tsx
│ │ │ ├── source-citations.tsx
│ │ │ ├── starter-questions.tsx
│ │ │ ├── status-indicator.tsx
│ │ │ ├── ticket-upload.tsx
│ │ │ ├── types.ts
│ │ │ └── workspace-combobox.tsx
│ │ ├── token-avatar.tsx
│ │ ├── users/
│ │ │ ├── user-avatar.tsx
│ │ │ └── user-row-item.tsx
│ │ ├── webhooks/
│ │ │ ├── add-edit-webhook-form.tsx
│ │ │ ├── link-selector.tsx
│ │ │ ├── loading-events-skelton.tsx
│ │ │ ├── no-events-placeholder.tsx
│ │ │ ├── webhook-card.tsx
│ │ │ ├── webhook-event-details-sheet.tsx
│ │ │ ├── webhook-event-list.tsx
│ │ │ ├── webhook-header.tsx
│ │ │ ├── webhook-placeholder.tsx
│ │ │ └── webhook-status.tsx
│ │ └── workspaces/
│ │ ├── create-workspace-button.tsx
│ │ ├── create-workspace-form.tsx
│ │ ├── delete-workspace.tsx
│ │ ├── invite-teammates-form.tsx
│ │ ├── manage-subscription-button.tsx
│ │ ├── plan-badge.tsx
│ │ ├── plan-features.tsx
│ │ ├── subscription-menu.tsx
│ │ ├── upgrade-plan-button.tsx
│ │ ├── upload-logo.tsx
│ │ ├── workspace-arrow.tsx
│ │ ├── workspace-exceeded-events.tsx
│ │ └── workspace-selector.tsx
│ ├── vercel.json
│ └── vitest.config.ts
├── package.json
├── packages/
│ ├── cli/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── api/
│ │ │ │ ├── callback.ts
│ │ │ │ ├── domains.ts
│ │ │ │ └── links.ts
│ │ │ ├── commands/
│ │ │ │ ├── config.ts
│ │ │ │ ├── domains.ts
│ │ │ │ ├── links.ts
│ │ │ │ ├── login.ts
│ │ │ │ └── shorten.ts
│ │ │ ├── index.ts
│ │ │ ├── types/
│ │ │ │ └── index.ts
│ │ │ └── utils/
│ │ │ ├── config.ts
│ │ │ ├── get-nanoid.ts
│ │ │ ├── get-package-info.ts
│ │ │ ├── handle-error.ts
│ │ │ ├── logger.ts
│ │ │ ├── oauth.ts
│ │ │ └── parser.ts
│ │ ├── tsconfig.json
│ │ └── tsup.config.ts
│ ├── email/
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── components/
│ │ │ │ ├── bounty-thumbnail.tsx
│ │ │ │ └── footer.tsx
│ │ │ ├── index.ts
│ │ │ ├── react-email.d.ts
│ │ │ ├── resend/
│ │ │ │ ├── client.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── types.ts
│ │ │ ├── send-via-nodemailer.ts
│ │ │ ├── send-via-resend.ts
│ │ │ ├── templates/
│ │ │ │ ├── api-key-created.tsx
│ │ │ │ ├── bounty-approved.tsx
│ │ │ │ ├── bounty-completed.tsx
│ │ │ │ ├── bounty-new-submission.tsx
│ │ │ │ ├── bounty-rejected.tsx
│ │ │ │ ├── bounty-submitted.tsx
│ │ │ │ ├── broadcasts/
│ │ │ │ │ ├── dub-product-update-mar26.tsx
│ │ │ │ │ ├── dub-wrapped.tsx
│ │ │ │ │ ├── payout-auto-withdrawals.tsx
│ │ │ │ │ ├── program-marketplace-announcement.tsx
│ │ │ │ │ └── stablecoin-payouts-announcement.tsx
│ │ │ │ ├── campaign-email.tsx
│ │ │ │ ├── clicks-exceeded.tsx
│ │ │ │ ├── clicks-summary.tsx
│ │ │ │ ├── confirm-email-change.tsx
│ │ │ │ ├── connect-payout-reminder.tsx
│ │ │ │ ├── connect-platforms-reminder.tsx
│ │ │ │ ├── connected-payout-method.tsx
│ │ │ │ ├── connected-paypal-account.tsx
│ │ │ │ ├── discount-deleted.tsx
│ │ │ │ ├── domain-claimed.tsx
│ │ │ │ ├── domain-deleted.tsx
│ │ │ │ ├── domain-expired.tsx
│ │ │ │ ├── domain-renewal-failed.tsx
│ │ │ │ ├── domain-renewal-reminder.tsx
│ │ │ │ ├── domain-renewed.tsx
│ │ │ │ ├── domain-transferred.tsx
│ │ │ │ ├── dub-partner-rewind.tsx
│ │ │ │ ├── duplicate-payout-method.tsx
│ │ │ │ ├── email-domain-status-changed.tsx
│ │ │ │ ├── email-updated.tsx
│ │ │ │ ├── export-ready.tsx
│ │ │ │ ├── failed-payment.tsx
│ │ │ │ ├── feedback-email.tsx
│ │ │ │ ├── folder-edit-access-requested.tsx
│ │ │ │ ├── integration-installed.tsx
│ │ │ │ ├── invalid-domain.tsx
│ │ │ │ ├── links-import-errors.tsx
│ │ │ │ ├── links-imported.tsx
│ │ │ │ ├── links-limit.tsx
│ │ │ │ ├── login-link.tsx
│ │ │ │ ├── new-bounty-available.tsx
│ │ │ │ ├── new-commission-alert-partner.tsx
│ │ │ │ ├── new-message-from-partner.tsx
│ │ │ │ ├── new-message-from-program.tsx
│ │ │ │ ├── new-referral-signup.tsx
│ │ │ │ ├── new-sale-alert-program-owner.tsx
│ │ │ │ ├── notify-partner-reapply.tsx
│ │ │ │ ├── partner-account-merged.tsx
│ │ │ │ ├── partner-application-approved.tsx
│ │ │ │ ├── partner-application-received.tsx
│ │ │ │ ├── partner-application-rejected.tsx
│ │ │ │ ├── partner-banned.tsx
│ │ │ │ ├── partner-deactivated.tsx
│ │ │ │ ├── partner-group-changed.tsx
│ │ │ │ ├── partner-payout-confirmed.tsx
│ │ │ │ ├── partner-payout-failed.tsx
│ │ │ │ ├── partner-payout-force-withdrawal.tsx
│ │ │ │ ├── partner-payout-processed.tsx
│ │ │ │ ├── partner-payout-withdrawal-completed.tsx
│ │ │ │ ├── partner-payout-withdrawal-failed.tsx
│ │ │ │ ├── partner-payout-withdrawal-initiated.tsx
│ │ │ │ ├── partner-paypal-payout-failed.tsx
│ │ │ │ ├── partner-program-summary.tsx
│ │ │ │ ├── partner-referral-submitted.tsx
│ │ │ │ ├── partner-user-invited.tsx
│ │ │ │ ├── password-updated.tsx
│ │ │ │ ├── pending-applications-summary.tsx
│ │ │ │ ├── program-application-reminder.tsx
│ │ │ │ ├── program-imported.tsx
│ │ │ │ ├── program-invite.tsx
│ │ │ │ ├── program-network-invite.tsx
│ │ │ │ ├── program-payout-reminder.tsx
│ │ │ │ ├── program-payout-thank-you.tsx
│ │ │ │ ├── program-welcome.tsx
│ │ │ │ ├── referral-invite.tsx
│ │ │ │ ├── referral-status-update.tsx
│ │ │ │ ├── reset-password-link.tsx
│ │ │ │ ├── unresolved-fraud-events-summary.tsx
│ │ │ │ ├── upgrade-email.tsx
│ │ │ │ ├── verify-email-for-account-merge.tsx
│ │ │ │ ├── verify-email.tsx
│ │ │ │ ├── webhook-added.tsx
│ │ │ │ ├── webhook-disabled.tsx
│ │ │ │ ├── webhook-failed.tsx
│ │ │ │ ├── welcome-email-partner.tsx
│ │ │ │ ├── welcome-email.tsx
│ │ │ │ └── workspace-invite.tsx
│ │ │ └── types.ts
│ │ └── tsconfig.json
│ ├── embeds/
│ │ ├── core/
│ │ │ ├── README.md
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── constants.ts
│ │ │ │ ├── core.ts
│ │ │ │ ├── embed.ts
│ │ │ │ ├── error.ts
│ │ │ │ ├── example/
│ │ │ │ │ └── index.html
│ │ │ │ ├── index.ts
│ │ │ │ └── types.ts
│ │ │ ├── tsconfig.json
│ │ │ └── tsup.config.ts
│ │ └── react/
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── postcss.config.js
│ │ ├── prepublish.js
│ │ ├── src/
│ │ │ ├── embed.tsx
│ │ │ ├── example/
│ │ │ │ └── app.tsx
│ │ │ └── index.ts
│ │ ├── tailwind.config.ts
│ │ ├── tsconfig.json
│ │ └── tsup.config.ts
│ ├── hubspot-app/
│ │ ├── CLAUDE.md
│ │ ├── README.md
│ │ ├── hsproject.json
│ │ ├── package.json
│ │ └── src/
│ │ └── app/
│ │ ├── app-hsmeta.json
│ │ └── webhooks/
│ │ └── webhooks-hsmeta.json
│ ├── prisma/
│ │ ├── client.ts
│ │ ├── edge.ts
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── schema/
│ │ │ ├── activity.prisma
│ │ │ ├── bounty.prisma
│ │ │ ├── campaign.prisma
│ │ │ ├── comment.prisma
│ │ │ ├── commission.prisma
│ │ │ ├── customer.prisma
│ │ │ ├── dashboard.prisma
│ │ │ ├── discount.prisma
│ │ │ ├── domain.prisma
│ │ │ ├── folder.prisma
│ │ │ ├── fraud.prisma
│ │ │ ├── group.prisma
│ │ │ ├── integration.prisma
│ │ │ ├── invoice.prisma
│ │ │ ├── jackson.prisma
│ │ │ ├── link.prisma
│ │ │ ├── message.prisma
│ │ │ ├── misc.prisma
│ │ │ ├── network.prisma
│ │ │ ├── notification.prisma
│ │ │ ├── oauth.prisma
│ │ │ ├── partner.prisma
│ │ │ ├── payout.prisma
│ │ │ ├── platform.prisma
│ │ │ ├── postback.prisma
│ │ │ ├── program.prisma
│ │ │ ├── referral.prisma
│ │ │ ├── reward.prisma
│ │ │ ├── schema.prisma
│ │ │ ├── tag.prisma
│ │ │ ├── token.prisma
│ │ │ ├── utm.prisma
│ │ │ ├── webhook.prisma
│ │ │ ├── workflow.prisma
│ │ │ └── workspace.prisma
│ │ └── tsconfig.json
│ ├── stripe-app/
│ │ ├── README.md
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── hooks/
│ │ │ │ └── use-workspace.ts
│ │ │ ├── utils/
│ │ │ │ ├── constants.ts
│ │ │ │ ├── dub.ts
│ │ │ │ ├── oauth.ts
│ │ │ │ ├── secrets.ts
│ │ │ │ ├── stripe.ts
│ │ │ │ └── types.ts
│ │ │ └── views/
│ │ │ └── AppSettings.tsx
│ │ ├── stripe-app.dev.json
│ │ ├── stripe-app.json
│ │ ├── tsconfig.json
│ │ └── ui-extensions.d.ts
│ ├── tailwind-config/
│ │ ├── package.json
│ │ ├── tailwind.config.ts
│ │ └── themes.css
│ ├── tinybird/
│ │ ├── README.md
│ │ ├── datasources/
│ │ │ ├── dub_audit_logs.datasource
│ │ │ ├── dub_click_events.datasource
│ │ │ ├── dub_click_events_id.datasource
│ │ │ ├── dub_click_events_mv.datasource
│ │ │ ├── dub_conversion_events_log.datasource
│ │ │ ├── dub_first_sale_mv.datasource
│ │ │ ├── dub_import_error_logs.datasource
│ │ │ ├── dub_lead_events.datasource
│ │ │ ├── dub_lead_events_mv.datasource
│ │ │ ├── dub_links_metadata.datasource
│ │ │ ├── dub_links_metadata_latest.datasource
│ │ │ ├── dub_postback_events.datasource
│ │ │ ├── dub_sale_events.datasource
│ │ │ ├── dub_sale_events_mv.datasource
│ │ │ └── dub_webhook_events.datasource
│ │ └── pipes/
│ │ ├── all_stats.pipe
│ │ ├── coordinates_all.pipe
│ │ ├── coordinates_sales.pipe
│ │ ├── dub_click_events_id_pipe.pipe
│ │ ├── dub_click_events_pipe.pipe
│ │ ├── dub_first_sale_pipe.pipe
│ │ ├── dub_lead_events_pipe.pipe
│ │ ├── dub_links_metadata_pipe.pipe
│ │ ├── dub_sale_events_pipe.pipe
│ │ ├── get_audit_logs.pipe
│ │ ├── get_click_event.pipe
│ │ ├── get_framer_lead_events.pipe
│ │ ├── get_import_error_logs.pipe
│ │ ├── get_lead_event.pipe
│ │ ├── get_lead_events.pipe
│ │ ├── get_postback_events.pipe
│ │ ├── get_webhook_events.pipe
│ │ ├── v2_customer_events.pipe
│ │ ├── v2_top_programs.pipe
│ │ ├── v3_count.pipe
│ │ ├── v3_events.pipe
│ │ ├── v3_group_by.pipe
│ │ ├── v3_group_by_link_country.pipe
│ │ ├── v3_group_by_link_metadata.pipe
│ │ ├── v3_timeseries.pipe
│ │ ├── v3_usage.pipe
│ │ ├── v3_usage_latest.pipe
│ │ ├── v4_count.pipe
│ │ ├── v4_events.pipe
│ │ ├── v4_group_by.pipe
│ │ ├── v4_group_by_link_metadata.pipe
│ │ └── v4_timeseries.pipe
│ ├── tsconfig/
│ │ ├── base.json
│ │ ├── nextjs.json
│ │ ├── package.json
│ │ └── react-library.json
│ ├── ui/
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── postcss.config.js
│ │ ├── src/
│ │ │ ├── accordion.tsx
│ │ │ ├── activity-ring.tsx
│ │ │ ├── alert.tsx
│ │ │ ├── animated-size-container.tsx
│ │ │ ├── avatar.tsx
│ │ │ ├── background.tsx
│ │ │ ├── badge.tsx
│ │ │ ├── blur-image.tsx
│ │ │ ├── button.tsx
│ │ │ ├── card-list/
│ │ │ │ ├── card-list-card.tsx
│ │ │ │ ├── card-list.tsx
│ │ │ │ └── index.ts
│ │ │ ├── card-selector.tsx
│ │ │ ├── carousel/
│ │ │ │ ├── carousel.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── nav-bar.tsx
│ │ │ │ └── thumbnails.tsx
│ │ │ ├── charts/
│ │ │ │ ├── areas.tsx
│ │ │ │ ├── bars.tsx
│ │ │ │ ├── chart-context.ts
│ │ │ │ ├── funnel-chart.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── time-series-chart.tsx
│ │ │ │ ├── tooltip-sync.tsx
│ │ │ │ ├── types.ts
│ │ │ │ ├── use-tooltip.ts
│ │ │ │ ├── utils.ts
│ │ │ │ ├── x-axis.tsx
│ │ │ │ └── y-axis.tsx
│ │ │ ├── checkbox.tsx
│ │ │ ├── client-only.tsx
│ │ │ ├── combobox/
│ │ │ │ └── index.tsx
│ │ │ ├── composite-logo.tsx
│ │ │ ├── content.ts
│ │ │ ├── copy-button.tsx
│ │ │ ├── copy-text.tsx
│ │ │ ├── date-picker/
│ │ │ │ ├── calendar.tsx
│ │ │ │ ├── date-picker.tsx
│ │ │ │ ├── date-range-picker.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── presets.tsx
│ │ │ │ ├── shared.ts
│ │ │ │ ├── trigger.tsx
│ │ │ │ └── types.ts
│ │ │ ├── dots-pattern.tsx
│ │ │ ├── dub-status-badge.tsx
│ │ │ ├── empty-state.tsx
│ │ │ ├── file-upload.tsx
│ │ │ ├── filter/
│ │ │ │ ├── filter-list.tsx
│ │ │ │ ├── filter-select.tsx
│ │ │ │ ├── index.ts
│ │ │ │ └── types.ts
│ │ │ ├── footer.tsx
│ │ │ ├── form.tsx
│ │ │ ├── grid.tsx
│ │ │ ├── hooks/
│ │ │ │ ├── index.ts
│ │ │ │ ├── use-click-handlers.ts
│ │ │ │ ├── use-column-visibility.ts
│ │ │ │ ├── use-cookies.ts
│ │ │ │ ├── use-copy-to-clipboard.tsx
│ │ │ │ ├── use-current-anchor.ts
│ │ │ │ ├── use-current-subdomain.ts
│ │ │ │ ├── use-enter-submit.ts
│ │ │ │ ├── use-in-viewport.tsx
│ │ │ │ ├── use-input-focused.ts
│ │ │ │ ├── use-intersection-observer.ts
│ │ │ │ ├── use-keyboard-shortcut.tsx
│ │ │ │ ├── use-local-storage.ts
│ │ │ │ ├── use-media-query.ts
│ │ │ │ ├── use-optimistic-update.ts
│ │ │ │ ├── use-pagination.ts
│ │ │ │ ├── use-remove-ga-params.ts
│ │ │ │ ├── use-resize-observer.ts
│ │ │ │ ├── use-router-stuff.ts
│ │ │ │ ├── use-scroll-progress.ts
│ │ │ │ ├── use-scroll.ts
│ │ │ │ └── use-toast-with-undo.tsx
│ │ │ ├── icon-menu.tsx
│ │ │ ├── icons/
│ │ │ │ ├── anthropic.tsx
│ │ │ │ ├── arrow-up-right-2.tsx
│ │ │ │ ├── bing.tsx
│ │ │ │ ├── continents/
│ │ │ │ │ ├── af.tsx
│ │ │ │ │ ├── as.tsx
│ │ │ │ │ ├── eu.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── na.tsx
│ │ │ │ │ ├── oc.tsx
│ │ │ │ │ └── sa.tsx
│ │ │ │ ├── copy.tsx
│ │ │ │ ├── crown-small.tsx
│ │ │ │ ├── default-domains/
│ │ │ │ │ ├── amazon.tsx
│ │ │ │ │ ├── chatgpt.tsx
│ │ │ │ │ ├── figma.tsx
│ │ │ │ │ ├── github-enhanced.tsx
│ │ │ │ │ ├── google-enhanced.tsx
│ │ │ │ │ └── spotify.tsx
│ │ │ │ ├── dub-analytics.tsx
│ │ │ │ ├── dub-api.tsx
│ │ │ │ ├── dub-crafted-shield.tsx
│ │ │ │ ├── dub-links.tsx
│ │ │ │ ├── dub-partners.tsx
│ │ │ │ ├── dub-product-icon.tsx
│ │ │ │ ├── expanding-arrow.tsx
│ │ │ │ ├── facebook.tsx
│ │ │ │ ├── file-pen.tsx
│ │ │ │ ├── file-send.tsx
│ │ │ │ ├── github.tsx
│ │ │ │ ├── go.tsx
│ │ │ │ ├── google.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── instagram.tsx
│ │ │ │ ├── ios-app-store.tsx
│ │ │ │ ├── linkedin.tsx
│ │ │ │ ├── loading-circle.tsx
│ │ │ │ ├── loading-dots.tsx
│ │ │ │ ├── loading-spinner.tsx
│ │ │ │ ├── lock-small.tsx
│ │ │ │ ├── magic.tsx
│ │ │ │ ├── markdown-icon.tsx
│ │ │ │ ├── matrix-lines.tsx
│ │ │ │ ├── nucleo/
│ │ │ │ │ ├── README.md
│ │ │ │ │ ├── android-logo.tsx
│ │ │ │ │ ├── apple-logo.tsx
│ │ │ │ │ ├── apple.tsx
│ │ │ │ │ ├── arrow-bold-up.tsx
│ │ │ │ │ ├── arrow-right.tsx
│ │ │ │ │ ├── arrow-trend-up.tsx
│ │ │ │ │ ├── arrow-turn-left.tsx
│ │ │ │ │ ├── arrow-turn-right2.tsx
│ │ │ │ │ ├── arrow-up-right.tsx
│ │ │ │ │ ├── arrows-opposite-direction-x.tsx
│ │ │ │ │ ├── arrows-opposite-direction-y.tsx
│ │ │ │ │ ├── at-sign.tsx
│ │ │ │ │ ├── badge-check.tsx
│ │ │ │ │ ├── badge-check2-fill.tsx
│ │ │ │ │ ├── bell.tsx
│ │ │ │ │ ├── blog.tsx
│ │ │ │ │ ├── bolt-fill.tsx
│ │ │ │ │ ├── bolt.tsx
│ │ │ │ │ ├── book-open.tsx
│ │ │ │ │ ├── book2-fill.tsx
│ │ │ │ │ ├── book2-small.tsx
│ │ │ │ │ ├── book2.tsx
│ │ │ │ │ ├── books2.tsx
│ │ │ │ │ ├── box-archive.tsx
│ │ │ │ │ ├── brackets-curly.tsx
│ │ │ │ │ ├── briefcase-fill.tsx
│ │ │ │ │ ├── brush.tsx
│ │ │ │ │ ├── bullet-list-fill.tsx
│ │ │ │ │ ├── bullet-list.tsx
│ │ │ │ │ ├── calculator.tsx
│ │ │ │ │ ├── calendar-days.tsx
│ │ │ │ │ ├── calendar-refresh.tsx
│ │ │ │ │ ├── calendar.tsx
│ │ │ │ │ ├── calendar6.tsx
│ │ │ │ │ ├── cards.tsx
│ │ │ │ │ ├── caret-up-fill.tsx
│ │ │ │ │ ├── chart-activity2.tsx
│ │ │ │ │ ├── chart-area2.tsx
│ │ │ │ │ ├── chart-line.tsx
│ │ │ │ │ ├── check.tsx
│ │ │ │ │ ├── check2.tsx
│ │ │ │ │ ├── checkbox-checked-fill.tsx
│ │ │ │ │ ├── checkbox-unchecked.tsx
│ │ │ │ │ ├── chevron-left.tsx
│ │ │ │ │ ├── chevron-right.tsx
│ │ │ │ │ ├── chevron-up.tsx
│ │ │ │ │ ├── circle-arrow-right.tsx
│ │ │ │ │ ├── circle-check-fill.tsx
│ │ │ │ │ ├── circle-check.tsx
│ │ │ │ │ ├── circle-dollar-out.tsx
│ │ │ │ │ ├── circle-dollar.tsx
│ │ │ │ │ ├── circle-dollar3.tsx
│ │ │ │ │ ├── circle-dotted.tsx
│ │ │ │ │ ├── circle-half-dotted-check.tsx
│ │ │ │ │ ├── circle-half-dotted-clock.tsx
│ │ │ │ │ ├── circle-info.tsx
│ │ │ │ │ ├── circle-percentage.tsx
│ │ │ │ │ ├── circle-play-fill.tsx
│ │ │ │ │ ├── circle-play.tsx
│ │ │ │ │ ├── circle-question.tsx
│ │ │ │ │ ├── circle-user.tsx
│ │ │ │ │ ├── circle-warning.tsx
│ │ │ │ │ ├── circle-xmark.tsx
│ │ │ │ │ ├── cir
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/apply-issue-labels-to-pr.yml
================================================
name: "Apply issue labels to PR"
on:
pull_request_target:
types:
- opened
jobs:
label_on_pr:
runs-on: ubuntu-latest
permissions:
contents: none
issues: read
pull-requests: write
steps:
- name: Apply labels from linked issue to PR
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
async function getLinkedIssues(owner, repo, prNumber) {
const query = `query GetLinkedIssues($owner: String!, $repo: String!, $prNumber: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $prNumber) {
closingIssuesReferences(first: 10) {
nodes {
number
labels(first: 10) {
nodes {
name
}
}
}
}
}
}
}`;
const variables = {
owner: owner,
repo: repo,
prNumber: prNumber,
};
const result = await github.graphql(query, variables);
return result.repository.pullRequest.closingIssuesReferences.nodes;
}
const pr = context.payload.pull_request;
const linkedIssues = await getLinkedIssues(
context.repo.owner,
context.repo.repo,
pr.number
);
const labelsToAdd = new Set();
for (const issue of linkedIssues) {
if (issue.labels && issue.labels.nodes) {
for (const label of issue.labels.nodes) {
labelsToAdd.add(label.name);
}
}
}
if (labelsToAdd.size) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
labels: Array.from(labelsToAdd),
});
}
================================================
FILE: .github/workflows/deploy-embed-script.yml
================================================
name: "Deploy embed script"
on:
push:
branches:
- main
paths:
- "packages/embeds/core/**"
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 8
- name: Install dependencies & build
run: pnpm --filter @dub/embed-core build
# - name: Deploy to Cloudflare Pages (https://www.dubcdn.com/embed/script.js)
# uses: cloudflare/wrangler-action@v3
# with:
# apiToken: ${{ secrets.CLOUDFLARE_PAGES_API_KEY }}
# accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
# command: pages deploy dist/embed/script.js --project-name=dub-cdn --commit-dirty=true
# workingDirectory: packages/embeds/core
# packageManager: pnpm
================================================
FILE: .github/workflows/e2e.yaml
================================================
name: Public API Tests
on:
deployment_status:
jobs:
api-tests:
timeout-minutes: 30
if: github.event_name == 'deployment_status' && github.event.deployment_status.state == 'success'
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Setup pnpm
uses: pnpm/action-setup@v3
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: 20
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Build utils
working-directory: packages/utils
run: pnpm build
- name: Run tests
working-directory: apps/web
env:
E2E_BASE_URL: ${{ github.event.deployment_status.environment_url }}
E2E_TOKEN: ${{ secrets.E2E_TOKEN }}
E2E_TOKEN_MEMBER: ${{ secrets.E2E_TOKEN_MEMBER }}
E2E_TOKEN_OLD: ${{ secrets.E2E_TOKEN_OLD }}
E2E_PUBLISHABLE_KEY: ${{ secrets.E2E_PUBLISHABLE_KEY }}
QSTASH_TOKEN: ${{ secrets.QSTASH_TOKEN }}
QSTASH_CURRENT_SIGNING_KEY: ${{ secrets.QSTASH_CURRENT_SIGNING_KEY }}
NEXT_PUBLIC_NGROK_URL: ${{ github.event.deployment_status.environment_url }}
run: pnpm test
================================================
FILE: .github/workflows/playwright.yaml
================================================
name: Playwright E2E Tests
on:
pull_request:
branches: [main]
paths:
- "apps/web/**"
- "packages/**"
- ".github/workflows/playwright.yaml"
concurrency:
group: e2e-${{ github.head_ref }}
cancel-in-progress: true
jobs:
e2e:
permissions:
contents: read
timeout-minutes: 20
runs-on: ubuntu-latest
env:
CI: "true"
NODE_OPTIONS: "--max-old-space-size=8192"
DATABASE_URL: "mysql://root:@localhost:3306/planetscale"
PLANETSCALE_DATABASE_URL: "http://root:unused@localhost:3900/planetscale"
NEXTAUTH_SECRET: "e2e-test-secret-at-least-32-chars-long"
NEXTAUTH_URL: "http://partners.localhost:8888"
NEXT_PUBLIC_APP_NAME: "Dub"
NEXT_PUBLIC_APP_DOMAIN: "dub.co"
NEXT_PUBLIC_APP_SHORT_DOMAIN: "dub.sh"
E2E_PARTNER_EMAIL: "partner1@dub-internal-test.com"
E2E_PARTNER_PASSWORD: "password"
TINYBIRD_API_KEY: "xx"
TINYBIRD_API_URL: "xx"
UPSTASH_REDIS_REST_URL: "https://sensible-camel-xxxx.upstash.io"
UPSTASH_REDIS_REST_TOKEN: "xx"
UPSTASH_VECTOR_REST_URL: "https://sensible-camel-xxxx.upstash.io"
UPSTASH_VECTOR_REST_TOKEN: "xx"
QSTASH_TOKEN: "xx"
QSTASH_CURRENT_SIGNING_KEY: "xx"
QSTASH_NEXT_SIGNING_KEY: "xx"
AXIOM_TOKEN: ""
AXIOM_DATASET: ""
RESEND_API_KEY: "xx"
EMBEDDING_SYNC_SECRET: "xx"
ANTHROPIC_API_KEY: "xx"
STRIPE_SECRET_KEY: "xx"
STRIPE_WEBHOOK_SECRET: "xx"
STRIPE_CONNECT_WEBHOOK_SECRET: "xx"
STRIPE_APP_WEBHOOK_SECRET_TEST: "xx"
STRIPE_APP_SECRET_KEY_TEST: "xx"
STRIPE_CONNECT_V2_WEBHOOK_SECRET: "xx"
STRIPE_APP_SECRET_KEY_SANDBOX: "xx"
services:
mysql:
image: mysql:8.0
env:
MYSQL_DATABASE: planetscale
MYSQL_ROOT_HOST: "%"
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
options: >-
--health-cmd="mysqladmin ping -h 127.0.0.1"
--health-interval=10s
--health-timeout=5s
--health-retries=5
ports:
- 3306:3306
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Start PlanetScale simulator
run: |
docker run -d --name ps-http-sim \
--network host \
ghcr.io/mattrobenolt/ps-http-sim:latest \
-listen-addr=0.0.0.0 \
-listen-port=3900 \
-mysql-dbname=planetscale \
-mysql-no-pass \
-mysql-addr=127.0.0.1
- name: Setup pnpm
uses: pnpm/action-setup@v3
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('apps/web/package.json') }}
- name: Install Playwright Chromium
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: pnpm --filter web exec playwright install chromium
- name: Generate Prisma client
working-directory: apps/web
run: pnpm prisma:generate
- name: Push database schema
working-directory: apps/web
run: pnpm prisma:push
- name: Seed test data
working-directory: apps/web
run: pnpm tsx playwright/seed.ts
# - name: Cache Next.js build
# uses: actions/cache@v4
# with:
# path: apps/web/.next/cache
# key: nextjs-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ hashFiles('apps/web/**/*.ts', 'apps/web/**/*.tsx') }}
# restore-keys: |
# nextjs-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}-
# nextjs-${{ runner.os }}-
# - name: Cache Turbo
# uses: actions/cache@v4
# with:
# path: .turbo
# key: turbo-${{ runner.os }}-${{ github.sha }}
# restore-keys: |
# turbo-${{ runner.os }}-
- name: Build application
run: pnpm turbo build --filter=web
- name: Run Playwright tests
working-directory: apps/web
run: pnpm test:e2e
================================================
FILE: .github/workflows/prettier.yaml
================================================
name: Prettier Check
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v3
- name: Install dependencies
run: pnpm install
- name: Fix prettier issues
run: pnpm run format
- name: Check prettier format
run: pnpm run prettier-check
================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
node_modules
dist/
# next.js
.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
.pnpm-debug.log*
# local env files
.env*.local
.env
# vercel
.vercel
# tinybird
.venv
.tinyb
# turbo
.turbo
# typescript
*.tsbuildinfo
next-env.d.ts
# miscellaneous
/pages/api/scripts*
packages/stripe-app/.build/*
.react-email
.contentlayer
.vscode
*.csv
*.ndjson
.vitest
# playwright
playwright-report/
**/playwright/.auth/
test-results/
blob-report/
================================================
FILE: .prettierignore
================================================
node_modules
pnpm-lock.yaml
.next
.turbo
dist
================================================
FILE: LICENSE.md
================================================
Copyright (c) 2024-present Dub Technologies, Inc.
Portions of this software – namely all files that reside under the following directories of this repository – are licensed under the license defined in "[ee/LICENSE.md](<https://github.com/dubinc/dub/tree/main/apps/web/app/(ee)/LICENSE.md>)".
- [apps/web/app/(ee)](<https://github.com/dubinc/dub/tree/main/apps/web/app/(ee)>)
- [apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)](<https://github.com/dubinc/dub/tree/main/apps/web/app/app.dub.co/(dashboard)/%5Bslug%5D/(ee)>)
All third-party components incorporated into the Dub Software are licensed under the original license provided by the owner of the applicable component.
Content outside of the above mentioned directories or restrictions above is available under the "AGPLv3" license as defined below.
---
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.
================================================
FILE: README.md
================================================
<a href="https://dub.co">
<img alt="Dub is the modern, open-source link attribution platform for short links, conversion tracking, and affiliate programs." src="https://github.com/user-attachments/assets/42cf0705-f5a2-4200-bc4a-c5acf0ba9e15">
</a>
<h3 align="center">Dub</h3>
<p align="center">
The open-source link attribution platform.
<br />
<a href="https://dub.co"><strong>Learn more »</strong></a>
<br />
<br />
<a href="#introduction"><strong>Introduction</strong></a> ·
<a href="#tech-stack"><strong>Tech Stack</strong></a> ·
<a href="#self-hosting"><strong>Self-hosting</strong></a> ·
<a href="#contributing"><strong>Contributing</strong></a>
</p>
<p align="center">
<a href="https://twitter.com/dubdotco">
<img src="https://img.shields.io/twitter/follow/dubdotco?style=flat&label=%40dubdotco&logo=twitter&color=0bf&logoColor=fff" alt="Twitter" />
</a>
<a href="https://news.ycombinator.com/item?id=32939407"><img src="https://img.shields.io/badge/Hacker%20News-255-%23FF6600" alt="Hacker News"></a>
<a href="https://github.com/dubinc/dub/blob/main/LICENSE.md">
<img src="https://img.shields.io/github/license/dubinc/dub?label=license&logo=github&color=f80&logoColor=fff" alt="License" />
</a>
</p>
<br/>
## Introduction
Dub is the modern, open-source link attribution platform for [short links](https://dub.co/home), [conversion tracking](https://dub.co/analytics), and [affiliate programs](https://dub.co/partners).
Our platform powers 100M+ clicks and 2M+ links monthly, and is used by world-class marketing teams from companies like Twilio, Buffer, Framer, Perplexity, Vercel, Laravel, and [more](https://dub.co/customers).
## Tech Stack
- [Next.js](https://nextjs.org/) – framework
- [TypeScript](https://www.typescriptlang.org/) – language
- [Tailwind](https://tailwindcss.com/) – CSS
- [Prisma](https://www.prisma.io/) – ORM
- [Upstash](https://upstash.com/) – redis
- [Tinybird](https://tinybird.com/) – analytics
- [PlanetScale](https://planetscale.com/) – database
- [NextAuth.js](https://next-auth.js.org/) – auth
- [BoxyHQ](https://boxyhq.com/enterprise-sso) – SSO/SAML
- [Turborepo](https://turbo.build/repo) – monorepo
- [Stripe](https://stripe.com/) – payments
- [Resend](https://resend.com/) – emails
- [Vercel](https://vercel.com/) – deployments
## Self-Hosting
You can self-host Dub for greater control over your data and design. [Read this guide](https://dub.co/docs/self-hosting/guide) to learn more.
## Contributing
We love our contributors! Here's how you can contribute:
- [Open an issue](https://github.com/dubinc/dub/issues) if you believe you've encountered a bug.
- Follow the [local development guide](https://dub.co/docs/local-development) to get your local dev environment set up.
- Make a [pull request](https://github.com/dubinc/dub/pull) to add new features/make quality-of-life improvements/fix bugs.
### Recommended Versions
| Package | Version |
| ------- | -------- |
| node | v23.11.0 |
| pnpm | 9.15.9 |
### Common Local Development Issues
- `The table <table-name> does not exist in the current database.` - Run `pnpm prisma:push` push the state of the Prisma schema file to the database without using migrations files.
- The project is not building correctly locally - verify your versions of `node` and `pnpm` match the recommended versions above. Delete all `node_modules`, `.next`, and `.turbo` directories in the `apps` and `packages` directory. You may now reinstall `node_modules` by running `pnpm install` and attempt to rebuild the project with `pnpm build`.
### Dev Seed Script
This script seeds the database with development data for testing and development purposes.
**Basic seeding (adds data without deleting existing data):**
```bash
cd apps/web
pnpm run script dev/seed
```
**Truncate database before seeding (deletes all existing data first):**
```bash
cd apps/web
pnpm run script dev/seed --truncate
```
When using `--truncate`, the script will ask for confirmation before deleting any data.
## Repo Activity

## License
Dub Technologies, Inc. is a commercial open-source company, which means some parts of this open-source repository require a commercial license. The concept is called "Open Core" where the core technology (99%) is fully open source, licensed under [AGPLv3](https://opensource.org/license/agpl-v3) and the last 1% is covered under a commercial license (["/ee" Enterprise Edition](<https://github.com/dubinc/dub/tree/ee/apps/web/app/(ee)>)) which we believe is entirely relevant for larger organisations that require enterprise features. Enterprise features are built by the core engineering team of Dub Technologies, Inc., which is hired full-time.
================================================
FILE: SECURITY.md
================================================
# Security Policy
## Supported Versions
All versions of Dub are currently being supported with security updates.
## Reporting a Vulnerability
To report a vulnerability, send an email to security@dub.co.
We will respond within 48 hours acknowledging your report with details about next steps and potential rewards/compensation for responsible disclosure.
================================================
FILE: apps/web/app/(ee)/LICENSE.md
================================================
The Dub.co Commercial License (the “Commercial License”)
Copyright (c) 2024-present Dub Technologies, Inc
With regard to the Dub.co Software:
This software and associated documentation files (the "Software") may only be
used in production, if you (and any entity that you represent) have agreed to,
and are in compliance with, the Dub.co Subscription Terms available
at https://dub.co/legal/terms, or other agreements governing
the use of the Software, as mutually agreed by you and Dub.co, Inc ("Dub.co"),
and otherwise have a valid Dub.co Enterprise Edition subscription ("Commercial Subscription")
for the correct number of hosts as defined in the "Commercial Terms ("Hosts"). Subject to the foregoing sentence,
you are free to modify this Software and publish patches to the Software. You agree
that Dub.co and/or its licensors (as applicable) retain all right, title and interest in
and to all such modifications and/or patches, and all such modifications and/or
patches may only be used, copied, modified, displayed, distributed, or otherwise
exploited with a valid Commercial Subscription for the correct number of hosts.
Notwithstanding the foregoing, you may copy and modify the Software for development
and testing purposes, without requiring a subscription. You agree that Dub.co and/or
its licensors (as applicable) retain all right, title and interest in and to all such
modifications. You are not granted any other rights beyond what is expressly stated herein.
Subject to the foregoing, it is forbidden to copy, merge, publish, distribute, sublicense,
and/or sell the Software.
This Commercial License applies only to the part of this Software that is not distributed under
the AGPLv3 license. Any part of this Software distributed under the MIT license or which
is served client-side as an image, font, cascading stylesheet (CSS), file which produces
or is compiled, arranged, augmented, or combined into client-side JavaScript, in whole or
in part, is copyrighted under the AGPLv3 license. The full text of this Commercial License shall
be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
For all third party components incorporated into the Dub.co Software, those
components are licensed under the original license provided by the owner of the
applicable component.
================================================
FILE: apps/web/app/(ee)/README.md
================================================
<!-- PROJECT LOGO -->
<div align="center">
<a href="https://dub.co/enterprise">
<img src="https://github.com/user-attachments/assets/42cf0705-f5a2-4200-bc4a-c5acf0ba9e15" alt="Logo">
</a>
<a href="https://dub.co/enterprise">Get an Enterprise License</a>
</div>
# Enterprise Edition
Welcome to the Enterprise Edition of Dub.co.
The [/(ee)](<https://github.com/dubinc/dub/tree/main/apps/web/app/(ee)>) subfolder is the place for all the **Enterprise Edition** features from our [hosted](https://dub.co/pricing) plan and enterprise-grade features for [Enterprise](https://dub.co/enterprise), included but not limited to the following:
- [Dub Conversions](https://dub.co/help/article/dub-conversions)
- [Dub Partners](https://dub.co/help/article/dub-partners)
- [SAML/SSO + SCIM Directory sync ](https://dub.co/help/category/saml-sso)
> _❗ WARNING: This repository is copyrighted (unlike our [main repo](https://github.com/dubinc/dub)). You are not allowed to use this code to host your own version of app.dub.co without obtaining a proper [license](https://dub.co/enterprise) first❗_
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(auth)/layout.tsx
================================================
import { Background } from "@dub/ui";
export default function AdminAuthLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<>
<Background />
<div className="relative z-10 flex flex-col items-center justify-center">
{children}
</div>
</>
);
}
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(auth)/login/page.tsx
================================================
export { default } from "../../../../app.dub.co/(auth)/login/page";
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/analytics/page.tsx
================================================
import Analytics from "@/ui/analytics";
import LayoutLoader from "@/ui/layout/layout-loader";
import { Suspense } from "react";
export default function AdminAnalytics() {
return (
<Suspense fallback={<LayoutLoader />}>
<div className="w-full">
<Analytics adminPage />
</div>
</Suspense>
);
}
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/commissions/client.tsx
================================================
"use client";
import { formatDateTooltip } from "@/lib/analytics/format-date-tooltip";
import { AnalyticsLoadingSpinner } from "@/ui/analytics/analytics-loading-spinner";
import { FilterButtonTableRow } from "@/ui/shared/filter-button-table-row";
import SimpleDateRangePicker from "@/ui/shared/simple-date-range-picker";
import {
CrownSmall,
Filter,
Table,
usePagination,
useRouterStuff,
useTable,
} from "@dub/ui";
import { Areas, TimeSeriesChart, XAxis, YAxis } from "@dub/ui/charts";
import { GridIcon } from "@dub/ui/icons";
import {
cn,
currencyFormatter,
DUB_FOUNDING_DATE,
fetcher,
OG_AVATAR_URL,
} from "@dub/utils";
import NumberFlow from "@number-flow/react";
import { Fragment, useCallback, useMemo, useState } from "react";
import useSWR from "swr";
export default function CommissionsPageClient() {
const { queryParams, getQueryString, searchParamsObj } = useRouterStuff();
const { interval, start, end, programId } = searchParamsObj;
const { data: { programs, timeseries } = {}, isLoading } = useSWR<{
programs: {
id: string;
name: string;
logo: string;
commissions: number;
fees: number;
}[];
timeseries: {
start: Date;
commissions: number;
}[];
}>(
`/api/admin/commissions${getQueryString({
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
})}`,
fetcher,
{
keepPreviousData: true,
},
);
// Filter configuration
const filters = useMemo(
() => [
{
key: "programId",
icon: GridIcon,
label: "Program",
options:
programs?.map((program) => ({
value: program.id,
label: program.name,
icon: (
<img
src={program.logo || `${OG_AVATAR_URL}${program.name}`}
alt={`${program.name} image`}
className="size-4 rounded-full"
/>
),
})) ?? null,
},
],
[programs],
);
const activeFilters = useMemo(() => {
return [...(programId ? [{ key: "programId", value: programId }] : [])];
}, [programId]);
const onSelect = useCallback(
(key: string, value: any) =>
queryParams({
set: {
[key]: value,
},
del: "page",
}),
[queryParams],
);
const onRemove = useCallback(
(key: string) =>
queryParams({
del: [key, "page"],
}),
[queryParams],
);
const onRemoveAll = useCallback(
() =>
queryParams({
del: ["programId"],
}),
[queryParams],
);
const [selectedFilter, setSelectedFilter] = useState<string | null>(null);
const [search, setSearch] = useState("");
const tabs: {
id: string;
label: string;
colorClassName: string;
disabled?: boolean;
}[] = [
{
id: "commissions",
label: "Commissions",
colorClassName: "text-teal-500 bg-teal-500/50 border-teal-500",
},
{
id: "fees",
label: "Fees",
colorClassName: "text-red-500 bg-red-500/50 border-red-500",
disabled: true,
},
];
const tab = tabs[0];
const selectedTab = tab.id;
const chartData =
timeseries?.map(({ start, commissions }) => ({
date: start ? new Date(start) : new Date(),
values: {
commissions: commissions || 0,
},
})) ?? null;
const totals = useMemo(() => {
return {
commissions:
timeseries?.reduce(
(acc, { commissions }) => acc + (commissions || 0),
0,
) ?? 0,
fees: programs?.reduce((acc, { fees }) => acc + (fees || 0), 0) ?? 0,
};
}, [timeseries, programs]);
const { pagination, setPagination } = usePagination();
const { table, ...tableProps } = useTable({
data: programs ?? [],
columns: [
{
id: "position",
header: "Position",
size: 12,
minSize: 12,
maxSize: 12,
cell: ({ row }) => {
return (
<div className="flex w-28 items-center justify-start gap-2 tabular-nums">
{row.index + 1}
{row.index <= 2 && (
<CrownSmall
className={cn("size-4", {
"text-amber-400": row.index === 0,
"text-neutral-400": row.index === 1,
"text-yellow-900": row.index === 2,
})}
/>
)}
</div>
);
},
},
{
id: "program",
header: "Program",
cell: ({ row }) => (
<div className="flex items-center gap-1.5">
<img
src={row.original.logo}
alt={row.original.name}
width={20}
height={20}
className="size-4 rounded-full"
/>
<span className="text-sm font-medium">{row.original.name}</span>
</div>
),
meta: {
filterParams: ({ row }) => ({
programId: row.original.id,
}),
},
},
{
id: "commissions",
header: "Commissions",
accessorKey: "commissions",
cell: ({ row }) => currencyFormatter(row.original.commissions),
},
{
id: "fees",
header: "Fees",
accessorKey: "fees",
cell: ({ row }) => currencyFormatter(row.original.fees),
},
],
pagination,
onPaginationChange: setPagination,
resourceName: (plural) => `program${plural ? "s" : ""}`,
rowCount: programs?.length ?? 0,
loading: isLoading,
cellRight: (cell) => {
const meta = cell.column.columnDef.meta as
| {
filterParams?: any;
}
| undefined;
return (
meta?.filterParams && (
<FilterButtonTableRow set={meta.filterParams(cell)} />
)
);
},
});
return (
<div className="mx-auto flex w-full max-w-screen-xl flex-col gap-3 p-6">
<div className="flex flex-col gap-3 md:flex-row md:items-center">
<Filter.Select
className="w-full md:w-fit"
filters={filters}
activeFilters={activeFilters}
onSelect={onSelect}
onRemove={onRemove}
onSearchChange={setSearch}
onSelectedFilterChange={setSelectedFilter}
/>
<SimpleDateRangePicker
defaultInterval="mtd"
className="w-full sm:min-w-[200px] md:w-fit"
/>
</div>
{activeFilters.length > 0 && (
<div>
<Filter.List
filters={filters}
activeFilters={activeFilters}
onSelect={onSelect}
onRemove={onRemove}
onRemoveAll={onRemoveAll}
/>
</div>
)}
<div className="flex flex-col divide-y divide-neutral-200 rounded-lg border border-neutral-200 bg-white">
<div className="scrollbar-hide grid w-full grid-cols-2 divide-x overflow-y-hidden sm:grid-cols-3">
{tabs.map(({ id, label, colorClassName, disabled }) => {
return (
<button
key={id}
disabled={disabled}
onClick={() => {
queryParams({
set: { tab: id },
});
}}
className={cn(
"border-box relative block h-full w-full flex-none px-4 py-3 sm:px-8 sm:py-6",
"ring-inset ring-neutral-500 focus-visible:ring-1 sm:first:rounded-tl-xl",
disabled
? "cursor-not-allowed"
: "transition-colors hover:bg-neutral-50 focus:outline-none active:bg-neutral-100",
)}
>
{/* Active tab indicator */}
<div
className={cn(
"absolute bottom-0 left-0 h-0.5 w-full bg-black transition-transform duration-100",
selectedTab !== id && "translate-y-[3px]",
)}
/>
<div className="flex items-center gap-2.5 text-sm text-neutral-600">
<div
className={cn(
"h-2 w-2 rounded-sm bg-current shadow-[inset_0_0_0_1px_#00000019]",
colorClassName,
)}
/>
<span>{label}</span>
</div>
<div className="mt-1 flex h-12 items-center">
{(totals[id] || totals[id] === 0) && !isLoading ? (
<NumberFlow
value={(totals[id] ?? 0) / 100}
className="text-xl font-medium sm:text-3xl"
format={{
style: "currency",
currency: "USD",
// @ts-ignore – trailingZeroDisplay is a valid option but TS is outdated
trailingZeroDisplay: "stripIfInteger",
}}
/>
) : (
<div className="h-10 w-24 animate-pulse rounded-md bg-neutral-200" />
)}
</div>
</button>
);
})}
</div>
<div className="p-5 sm:p-10">
<div className="flex h-96 w-full items-center justify-center">
{chartData ? (
chartData.length > 0 ? (
<TimeSeriesChart
data={chartData}
series={[
{
id: "commissions",
valueAccessor: (d) => d.values.commissions,
isActive: selectedTab === "commissions",
colorClassName: tab.colorClassName,
},
]}
tooltipClassName="p-0"
tooltipContent={(d) => (
<>
<p className="border-b border-neutral-200 px-4 py-3 text-sm text-neutral-900">
{formatDateTooltip(d.date, {
interval,
start,
end,
})}
</p>
<div className="grid grid-cols-2 gap-x-6 gap-y-2 px-4 py-3 text-sm">
<Fragment>
<div className="flex items-center gap-2">
<div
className={cn(
"h-2 w-2 rounded-sm shadow-[inset_0_0_0_1px_#0003]",
tab.colorClassName,
)}
/>
<p className="capitalize text-neutral-600">
{tab.label}
</p>
</div>
<p className="text-right font-medium text-neutral-900">
{currencyFormatter(d.values[tab.id])}
</p>
</Fragment>
</div>
</>
)}
>
<Areas />
<XAxis
maxTicks={5}
tickFormat={(d) =>
formatDateTooltip(d, {
interval,
start,
end,
dataAvailableFrom: DUB_FOUNDING_DATE,
})
}
/>
<YAxis
showGridLines
tickFormat={(value) => currencyFormatter(value)}
/>
</TimeSeriesChart>
) : (
<div className="text-center text-sm text-neutral-600">
No data available.
</div>
)
) : (
<AnalyticsLoadingSpinner />
)}
</div>
</div>
</div>
<div className="w-full">
<Table {...tableProps} table={table} />
</div>
</div>
);
}
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/commissions/page.tsx
================================================
import { Suspense } from "react";
import CommissionsPageClient from "./client";
export default async function CommissionsPage() {
return (
<Suspense>
<CommissionsPageClient />
</Suspense>
);
}
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/components/ban-link.tsx
================================================
"use client";
import { LoadingSpinner } from "@dub/ui";
import { cn } from "@dub/utils";
import { useState } from "react";
import { toast } from "sonner";
export function BanLink() {
const [pending, setPending] = useState(false);
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const form = e.currentTarget;
const key = new FormData(form).get("key");
if (!key || typeof key !== "string") return;
if (!window.confirm("Are you sure you want to ban this link?")) return;
setPending(true);
try {
const res = await fetch(
`/api/admin/links/ban?domain=dub.sh&key=${encodeURIComponent(key)}`,
{ method: "DELETE" },
).then((r) => r.json());
if (res.error) {
toast.error(res.error);
} else {
toast.success("Link has been banned");
}
} finally {
setPending(false);
}
};
return (
<div className="flex flex-col space-y-5">
<form onSubmit={handleSubmit}>
<Form pending={pending} />
</form>
</div>
);
}
const Form = ({ pending }: { pending: boolean }) => {
return (
<div className="relative flex w-full rounded-md shadow-sm">
<span className="inline-flex items-center rounded-l-md border border-r-0 border-neutral-300 bg-neutral-50 px-5 text-neutral-500 sm:text-sm">
dub.sh
</span>
<input
name="key"
id="key"
type="text"
required
disabled={pending}
autoComplete="off"
className={cn(
"block w-full rounded-r-md border-neutral-300 text-neutral-900 placeholder-neutral-400 focus:border-neutral-500 focus:outline-none focus:ring-neutral-500 sm:text-sm",
pending && "bg-neutral-100",
)}
placeholder="IG47WZs"
aria-invalid="true"
onPaste={(e: React.ClipboardEvent<HTMLInputElement>) => {
e.preventDefault();
// if pasting in https://dub.sh/xxx or dub.sh/xxx, extract xxx
const text = e.clipboardData.getData("text/plain");
if (
text.startsWith("https://dub.sh/") ||
text.startsWith("dub.sh/")
) {
e.currentTarget.value = text
.replace("https://dub.sh/", "")
.replace("dub.sh/", "");
} else {
e.currentTarget.value = text;
}
}}
/>
{pending && (
<LoadingSpinner className="absolute inset-y-0 right-2 my-auto h-full w-5 text-neutral-400" />
)}
</div>
);
};
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/components/delete-partner-account.tsx
================================================
"use client";
import { LoadingSpinner } from "@dub/ui";
import { cn } from "@dub/utils";
import { useFormStatus } from "react-dom";
import { toast } from "sonner";
export function DeletePartnerAccount() {
return (
<div className="flex flex-col space-y-5">
<form
action={async (formData) => {
const deletePartnerAccount =
formData.get("deletePartnerAccount") === "on";
const message = deletePartnerAccount
? "Are you sure you want to delete this partner account completely? This will also delete the partner account along with their Stripe express account. This action cannot be undone."
: "Are you sure you want to delete this partner's Stripe express account? This action cannot be undone.";
const confirmed = window.confirm(message);
if (!confirmed) {
return;
}
await fetch("/api/admin/delete-partner-account", {
method: "POST",
body: JSON.stringify({
email: formData.get("email"),
deletePartnerAccount:
formData.get("deletePartnerAccount") === "on",
}),
}).then(async (res) => {
if (res.ok) {
toast.success(
deletePartnerAccount
? "Partner account deleted!"
: "Stripe express account deleted!",
);
} else {
const error = await res.text();
toast.error(error);
}
});
}}
>
<Form />
</form>
</div>
);
}
const Form = () => {
const { pending } = useFormStatus();
return (
<div className="flex flex-col space-y-4">
<div className="relative flex w-full rounded-md shadow-sm">
<input
name="email"
id="email"
type="email"
required
disabled={pending}
autoComplete="off"
className={cn(
"block w-full rounded-md border-neutral-300 text-neutral-900 placeholder-neutral-400 focus:border-neutral-500 focus:outline-none focus:ring-neutral-500 sm:text-sm",
pending && "bg-neutral-100",
)}
onPaste={(e: React.ClipboardEvent<HTMLInputElement>) => {
// remove mailto: on paste
e.preventDefault();
const text = e.clipboardData.getData("text/plain");
if (text.startsWith("mailto:")) {
e.currentTarget.value = text.replace("mailto:", "");
} else {
e.currentTarget.value = text;
}
}}
placeholder="panic@thedis.co"
aria-invalid="true"
/>
{pending && (
<LoadingSpinner className="absolute inset-y-0 right-2 my-auto h-full w-5 text-neutral-400" />
)}
</div>
<div className="flex items-center space-x-2">
<input
name="deletePartnerAccount"
id="deletePartnerAccount"
type="checkbox"
disabled={pending}
className="h-4 w-4 rounded border-neutral-300 text-neutral-600 focus:ring-neutral-500"
/>
<label
htmlFor="deletePartnerAccount"
className="text-sm text-neutral-700"
>
Delete partner account as well
</label>
</div>
</div>
);
};
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/components/impersonate-user.tsx
================================================
"use client";
import { Button, LoadingSpinner } from "@dub/ui";
import { cn } from "@dub/utils";
import { useState } from "react";
import { useFormStatus } from "react-dom";
import { toast } from "sonner";
import UserInfo, { UserInfoProps } from "./user-info";
export function ImpersonateUser() {
const [data, setData] = useState<UserInfoProps | null>(null);
return (
<div className="flex flex-col space-y-5">
<form
action={async (formData) => {
await fetch("/api/admin/impersonate", {
method: "POST",
body: JSON.stringify({
email: formData.get("email"),
}),
}).then(async (res) => {
if (res.ok) {
setData(await res.json());
} else {
const error = await res.text();
toast.error(error);
}
});
}}
>
<Form />
</form>
{data && (
<form
action={async () => {
if (
!confirm(
`This will ban the user ${data.email} and delete all their workspaces and links. Are you sure?`,
)
) {
return;
}
await fetch("/api/admin/ban", {
method: "POST",
body: JSON.stringify({
email: data.email,
}),
}).then(async (res) => {
if (res.ok) {
toast.success("User has been banned");
} else {
const error = await res.text();
toast.error(error);
}
});
}}
>
<UserInfo data={data} />
<div className="mt-4">
<BanButton />
</div>
</form>
)}
</div>
);
}
const Form = () => {
const { pending } = useFormStatus();
return (
<div className="relative flex w-full rounded-md shadow-sm">
<input
name="email"
id="email"
type="email"
required
disabled={pending}
autoComplete="off"
className={cn(
"block w-full rounded-md border-neutral-300 text-neutral-900 placeholder-neutral-400 focus:border-neutral-500 focus:outline-none focus:ring-neutral-500 sm:text-sm",
pending && "bg-neutral-100",
)}
onPaste={(e: React.ClipboardEvent<HTMLInputElement>) => {
// remove mailto: on paste
e.preventDefault();
const text = e.clipboardData.getData("text/plain");
if (text.startsWith("mailto:")) {
e.currentTarget.value = text.replace("mailto:", "");
} else {
e.currentTarget.value = text;
}
}}
placeholder="panic@thedis.co"
aria-invalid="true"
/>
{pending && (
<LoadingSpinner className="absolute inset-y-0 right-2 my-auto h-full w-5 text-neutral-400" />
)}
</div>
);
};
const BanButton = () => {
const { pending } = useFormStatus();
return <Button text="Confirm Ban" loading={pending} variant="danger" />;
};
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/components/impersonate-workspace.tsx
================================================
"use client";
import { LoadingSpinner } from "@dub/ui";
import { cn } from "@dub/utils";
import { useState } from "react";
import { useFormStatus } from "react-dom";
import { toast } from "sonner";
import UserInfo, { UserInfoProps } from "./user-info";
export function ImpersonateWorkspace() {
const [data, setData] = useState<UserInfoProps | null>(null);
return (
<div className="flex flex-col space-y-5">
<form
action={async (formData) => {
await fetch("/api/admin/impersonate", {
method: "POST",
body: JSON.stringify({
slug: formData.get("slug"),
}),
}).then(async (res) => {
if (res.ok) {
setData(await res.json());
} else {
const error = await res.text();
toast.error(error);
}
});
}}
>
<Form />
</form>
{data && <UserInfo data={data} />}
</div>
);
}
const Form = () => {
const { pending } = useFormStatus();
return (
<div className="relative flex w-full rounded-md shadow-sm">
<span className="inline-flex items-center rounded-l-md border border-r-0 border-neutral-300 bg-neutral-50 px-5 text-neutral-500 sm:text-sm">
app.dub.co
</span>
<input
name="slug"
id="slug"
type="text"
required
disabled={pending}
autoComplete="off"
className={cn(
"block w-full rounded-r-md border-neutral-300 text-neutral-900 placeholder-neutral-400 focus:border-neutral-500 focus:outline-none focus:ring-neutral-500 sm:text-sm",
pending && "bg-neutral-100",
)}
placeholder="owd"
aria-invalid="true"
/>
{pending && (
<LoadingSpinner className="absolute inset-y-0 right-2 my-auto h-full w-5 text-neutral-400" />
)}
</div>
);
};
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/components/refresh-domain.tsx
================================================
"use client";
import { LoadingSpinner } from "@dub/ui";
import { cn } from "@dub/utils";
import { useFormStatus } from "react-dom";
import { toast } from "sonner";
export function RefreshDomain() {
return (
<div className="flex flex-col space-y-5">
<form
action={async (data) =>
await fetch("/api/admin/refresh-domain", {
method: "POST",
body: JSON.stringify({
domain: data.get("domain"),
}),
})
.then((res) => res.json())
.then((res) => {
if (res.error) {
toast.error(res.error);
} else {
toast.success("Domain has been refreshed");
}
})
}
>
<Form />
</form>
</div>
);
}
const Form = () => {
const { pending } = useFormStatus();
return (
<div className="relative flex w-full rounded-md shadow-sm">
<input
name="domain"
id="domain"
type="text"
required
disabled={pending}
autoComplete="off"
className={cn(
"block w-full rounded-md border-neutral-300 text-neutral-900 placeholder-neutral-400 focus:border-neutral-500 focus:outline-none focus:ring-neutral-500 sm:text-sm",
pending && "bg-neutral-100",
)}
placeholder="acme.com"
aria-invalid="true"
/>
{pending && (
<LoadingSpinner className="absolute inset-y-0 right-2 my-auto h-full w-5 text-neutral-400" />
)}
</div>
);
};
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/components/reset-login-attempts.tsx
================================================
"use client";
import { LoadingSpinner } from "@dub/ui";
import { cn } from "@dub/utils";
import { useFormStatus } from "react-dom";
import { toast } from "sonner";
export function ResetLoginAttempts() {
return (
<div className="flex flex-col space-y-5">
<form
action={async (data) =>
await fetch("/api/admin/reset-login-attempts", {
method: "POST",
body: JSON.stringify({
email: data.get("email"),
}),
})
.then((res) => res.json())
.then((res) => {
if (res.error) {
toast.error(res.error);
} else {
toast.success("Login attempts have been reset");
}
})
}
>
<Form />
</form>
</div>
);
}
const Form = () => {
const { pending } = useFormStatus();
return (
<div className="relative flex w-full rounded-md shadow-sm">
<input
name="email"
id="email"
type="email"
required
disabled={pending}
autoComplete="off"
className={cn(
"block w-full rounded-md border-neutral-300 text-neutral-900 placeholder-neutral-400 focus:border-neutral-500 focus:outline-none focus:ring-neutral-500 sm:text-sm",
pending && "bg-neutral-100",
)}
placeholder="user@example.com"
aria-invalid="true"
/>
{pending && (
<LoadingSpinner className="absolute inset-y-0 right-2 my-auto h-full w-5 text-neutral-400" />
)}
</div>
);
};
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/components/user-info.tsx
================================================
"use client";
import { PartnerStatusBadges } from "@/ui/partners/partner-status-badges";
import { Badge, Copy, StatusBadge, Tick, useCopyToClipboard } from "@dub/ui";
import { capitalize, currencyFormatter, nFormatter } from "@dub/utils";
import { toast } from "sonner";
export interface UserInfoProps {
email: string;
workspaces: {
id: string;
name: string;
slug: string;
plan: string;
clicks: number;
links: number;
totalClicks: number;
totalLinks: number;
}[];
programs: {
id: string;
name: string;
slug: string;
status: string;
totalClicks: number;
totalLeads: number;
totalConversions: number;
totalSaleAmount: number;
totalCommissions: number;
}[];
impersonateUrl: {
app: string;
partners: string;
};
}
const workspaceItems = [
{ id: "clicks", label: "Clicks" },
{ id: "links", label: "Links" },
{ id: "totalClicks", label: "Total Clicks" },
{ id: "totalLinks", label: "Total Links" },
];
const programItems = [
{ id: "totalClicks", label: "Total Clicks" },
{ id: "totalLeads", label: "Total Leads" },
{ id: "totalConversions", label: "Total Conversions" },
{ id: "totalSaleAmount", label: "Total Sales", isCurrency: true },
{ id: "totalCommissions", label: "Total Commissions", isCurrency: true },
];
export default function UserInfo({ data }: { data: UserInfoProps }) {
return (
<div className="grid gap-4">
<LoginLinkCopyButton text={data.email} url={data.email} />
<LoginLinkCopyButton
text="app.dub.co login link"
url={data.impersonateUrl.app}
/>
<LoginLinkCopyButton
text="partners.dub.co login link"
url={data.impersonateUrl.partners}
/>
{data.workspaces.length > 0 && (
<div>
<h3 className="mb-2 text-sm font-semibold text-neutral-900">
Workspaces
</h3>
<div className="grid grid-cols-2 gap-4">
{data.workspaces.map((workspace) => (
<div
key={workspace.slug}
className="flex flex-col space-y-2 rounded-lg border border-neutral-200 p-2"
>
<div className="flex items-center space-x-2">
<p className="font-semibold">{workspace.name}</p>
<Badge className="lowercase">{workspace.slug}</Badge>
</div>
<div className="flex justify-between text-sm">
<span className="font-medium text-neutral-700">ID</span>
<span className="text-neutral-500">{workspace.id}</span>
</div>
<div className="flex justify-between text-sm">
<span className="font-medium text-neutral-700">Plan</span>
<span className="text-neutral-500">
{capitalize(workspace.plan)}
</span>
</div>
{workspaceItems.map((item) => (
<div key={item.id} className="flex justify-between text-sm">
<span className="font-medium text-neutral-700">
{item.label}
</span>
<span className="text-neutral-500">
{nFormatter(workspace[item.id], { full: true })}
</span>
</div>
))}
</div>
))}
</div>
</div>
)}
{data.workspaces.length > 0 && data.programs.length > 0 && (
<div className="my-2 border-b border-neutral-200" />
)}
{data.programs.length > 0 && (
<div>
<h3 className="mb-2 text-sm font-semibold text-neutral-900">
Programs
</h3>
<div className="grid grid-cols-2 gap-4">
{data.programs.map((program) => (
<div
key={program.id}
className="flex flex-col space-y-2 rounded-lg border border-neutral-200 p-2"
>
<div className="flex items-center space-x-2">
<p className="font-semibold">{program.name}</p>
<Badge className="lowercase">{program.slug}</Badge>
</div>
<div className="flex justify-between text-sm">
<span className="font-medium text-neutral-700">ID</span>
<span className="text-neutral-500">{program.id}</span>
</div>
<div className="flex justify-between text-sm">
<span className="font-medium text-neutral-700">Status</span>
<StatusBadge
variant={PartnerStatusBadges[program.status].variant}
>
{PartnerStatusBadges[program.status].label}
</StatusBadge>
</div>
{programItems.map((item) => (
<div key={item.id} className="flex justify-between text-sm">
<span className="font-medium text-neutral-700">
{item.label}
</span>
<span className="text-neutral-500">
{item.isCurrency
? currencyFormatter(program[item.id])
: nFormatter(program[item.id], { full: true })}
</span>
</div>
))}
</div>
))}
</div>
</div>
)}
</div>
);
}
const LoginLinkCopyButton = ({ text, url }: { text: string; url: string }) => {
const [copied, copyToClipboard] = useCopyToClipboard();
return (
<div className="flex w-full items-center space-x-3">
<div className="w-full rounded-md border border-neutral-300 px-4 py-2 text-sm text-neutral-900">
{text}
</div>
<button
type="button"
onClick={() =>
toast.promise(copyToClipboard(url), {
success: "Copied to clipboard",
})
}
className="rounded-md border border-neutral-300 p-2"
>
{copied ? (
<Tick className="h-5 w-5 text-neutral-500" />
) : (
<Copy className="h-5 w-5 text-neutral-500" />
)}
</button>
</div>
);
};
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/events/page.tsx
================================================
import Events from "@/ui/analytics/events";
import { EventsProvider } from "@/ui/analytics/events/events-provider";
import LayoutLoader from "@/ui/layout/layout-loader";
import AnalyticsClient from "app/app.dub.co/(dashboard)/[slug]/analytics/client";
import { Suspense } from "react";
export default function AdminEvents() {
return (
<Suspense fallback={<LayoutLoader />}>
<AnalyticsClient eventsPage>
<EventsProvider>
<Events adminPage />
</EventsProvider>
</AnalyticsClient>
</Suspense>
);
}
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/layout-nav-client.tsx
================================================
"use client";
import {
ClientOnly,
MaxWidthWrapper,
NavWordmark,
Popover,
useMediaQuery,
} from "@dub/ui";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useState } from "react";
const tabs = [
{
href: "/links",
label: "Links",
},
{
href: "/analytics",
label: "Analytics",
},
{
href: "/commissions",
label: "Commissions",
},
{
href: "/payouts",
label: "Payouts",
},
{
href: "/revenue",
label: "Revenue",
},
];
export function AdminNav() {
const [openPopover, setOpenPopover] = useState(false);
const { isMobile } = useMediaQuery();
const pathname = usePathname();
const NavContent = () => (
<div className="flex w-full flex-col gap-1 p-2">
{tabs.map((tab) => {
const isActive =
pathname === tab.href || pathname?.startsWith(`${tab.href}/`);
return (
<Link
href={tab.href}
key={tab.href}
className={`block w-full rounded-md px-4 py-2 text-left text-sm text-neutral-700 transition-colors hover:bg-neutral-100 active:bg-neutral-200 ${
isActive ? "bg-neutral-100" : ""
}`}
onClick={() => setOpenPopover(false)}
>
{tab.label}
</Link>
);
})}
</div>
);
return (
<div className="sticky left-0 right-0 top-0 z-20 border-b border-neutral-200 bg-white">
<MaxWidthWrapper>
<div className="flex h-16 w-full items-center justify-between sm:justify-start sm:gap-12">
<Link href="/">
<NavWordmark className="h-6" />
</Link>
<ClientOnly>
{isMobile ? (
<div className="ml-auto">
<Popover
content={<NavContent />}
openPopover={openPopover}
setOpenPopover={setOpenPopover}
mobileOnly
>
<button className="text-neutral-500">
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<line x1="3" y1="12" x2="21" y2="12" />
<line x1="3" y1="6" x2="21" y2="6" />
<line x1="3" y1="18" x2="21" y2="18" />
</svg>
</button>
</Popover>
</div>
) : (
<div className="flex items-center gap-4">
{tabs.map((tab) => {
const isActive =
pathname === tab.href ||
pathname?.startsWith(`${tab.href}/`);
return (
<Link
href={tab.href}
key={tab.href}
className={`rounded-md px-3 py-1.5 text-sm transition-colors ${
isActive
? "bg-neutral-100 text-neutral-900"
: "text-neutral-500 hover:text-neutral-700"
}`}
>
{tab.label}
</Link>
);
})}
</div>
)}
</ClientOnly>
</div>
</MaxWidthWrapper>
</div>
);
}
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/layout.tsx
================================================
import { constructMetadata } from "@dub/utils";
import { ReactNode } from "react";
import { AdminNav } from "./layout-nav-client";
export const metadata = constructMetadata({ noIndex: true });
export default function AdminLayout({ children }: { children: ReactNode }) {
return (
<>
<div className="min-h-screen w-full bg-neutral-50">
<AdminNav />
{children}
</div>
</>
);
}
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/links/page.tsx
================================================
import AdminLinksClient from "app/app.dub.co/(dashboard)/[slug]/links/page-client";
import { Suspense } from "react";
export default function AdminLinks() {
return (
<Suspense>
<AdminLinksClient />
</Suspense>
);
}
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/page.tsx
================================================
import { constructMetadata } from "@dub/utils";
import { BanLink } from "./components/ban-link";
import { DeletePartnerAccount } from "./components/delete-partner-account";
import { ImpersonateUser } from "./components/impersonate-user";
import { ImpersonateWorkspace } from "./components/impersonate-workspace";
import { RefreshDomain } from "./components/refresh-domain";
import { ResetLoginAttempts } from "./components/reset-login-attempts";
export const metadata = constructMetadata({
title: "Dub Admin",
noIndex: true,
});
export default function AdminPage() {
return (
<div className="mx-auto flex w-full max-w-screen-sm flex-col divide-y divide-neutral-200 overflow-auto bg-white">
<div className="flex flex-col space-y-4 px-5 py-10">
<h2 className="text-xl font-semibold">Impersonate User</h2>
<p className="text-sm text-neutral-500">Get a login link for a user</p>
<ImpersonateUser />
</div>
<div className="flex flex-col space-y-4 px-5 py-10">
<h2 className="text-xl font-semibold">Impersonate Workspace</h2>
<p className="text-sm text-neutral-500">
Get a login link for the owner of a workspace
</p>
<ImpersonateWorkspace />
</div>
<div className="flex flex-col space-y-4 px-5 py-10">
<h2 className="text-xl font-semibold">Ban Link</h2>
<p className="text-sm text-neutral-500">Ban a dub.sh link</p>
<BanLink />
</div>
<div className="flex flex-col space-y-4 px-5 py-10">
<h2 className="text-xl font-semibold">Delete Stripe Express Account</h2>
<p className="text-sm text-neutral-500">
Delete a partner's Stripe express account (and potentially their
partner account as well). <br />
<br />
Caveats:
<br />- If the partner has already received payouts via Stripe, their
Stripe Express account won't be deleted.
<br />- If the partner has already received commissions or leads on
Dub, their partner account won't be deleted.
</p>
<DeletePartnerAccount />
</div>
<div className="flex flex-col space-y-4 px-5 py-10">
<h2 className="text-xl font-semibold">Refresh Domain</h2>
<p className="text-sm text-neutral-500">
Remove and re-add domain from Vercel
</p>
<RefreshDomain />
</div>
<div className="flex flex-col space-y-4 px-5 py-10">
<h2 className="text-xl font-semibold">Reset Login Attempts</h2>
<p className="text-sm text-neutral-500">
Reset a user's invalidLoginAttempts and lockedAt fields
</p>
<ResetLoginAttempts />
</div>
</div>
);
}
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/payouts/client.tsx
================================================
"use client";
import { formatDateTooltip } from "@/lib/analytics/format-date-tooltip";
import { AnalyticsLoadingSpinner } from "@/ui/analytics/analytics-loading-spinner";
import { PayoutStatusBadges } from "@/ui/partners/payout-status-badges";
import { FilterButtonTableRow } from "@/ui/shared/filter-button-table-row";
import SimpleDateRangePicker from "@/ui/shared/simple-date-range-picker";
import { InvoiceStatus } from "@dub/prisma/client";
import {
Button,
Filter,
StatusBadge,
Table,
usePagination,
useRouterStuff,
useTable,
} from "@dub/ui";
import { Areas, TimeSeriesChart, XAxis, YAxis } from "@dub/ui/charts";
import { CircleDotted, GridIcon, Paypal } from "@dub/ui/icons";
import {
cn,
currencyFormatter,
fetcher,
formatDateTime,
OG_AVATAR_URL,
} from "@dub/utils";
import NumberFlow from "@number-flow/react";
import Link from "next/link";
import { Fragment, useCallback, useMemo, useState } from "react";
import useSWR from "swr";
interface TimeseriesData {
date: Date;
payouts: number;
fees: number;
total: number;
}
interface InvoiceData {
date: Date;
programId: string;
programName: string;
programLogo: string;
status: InvoiceStatus;
amount: number;
fee: number;
total: number;
}
type Tab = {
id: "payouts" | "fees" | "total";
label: string;
colorClassName: string;
};
export default function PayoutsPageClient() {
const { queryParams, getQueryString, searchParamsObj } = useRouterStuff();
const { interval, start, end, status, programId } = searchParamsObj;
const { data: { invoices, timeseriesData } = {}, isLoading } = useSWR<{
invoices: InvoiceData[];
timeseriesData: TimeseriesData[];
}>(`/api/admin/payouts${getQueryString()}`, fetcher, {
keepPreviousData: true,
});
// Extract unique programs from invoices
const programs = useMemo(() => {
if (!invoices) return [];
const programMap = new Map<
string,
{ id: string; name: string; logo: string }
>();
invoices.forEach((invoice) => {
if (!programMap.has(invoice.programId)) {
programMap.set(invoice.programId, {
id: invoice.programId,
name: invoice.programName,
logo: invoice.programLogo,
});
}
});
return Array.from(programMap.values()).sort((a, b) =>
a.name.localeCompare(b.name),
);
}, [invoices]);
// Filter configuration
const filters = useMemo(
() => [
{
key: "programId",
icon: GridIcon,
label: "Program",
options:
programs.map((program) => ({
value: program.id,
label: program.name,
icon: (
<img
src={program.logo || `${OG_AVATAR_URL}${program.name}`}
alt={`${program.name} image`}
className="size-4 rounded-full"
/>
),
})) ?? null,
},
{
key: "status",
icon: CircleDotted,
label: "Status",
options: Object.entries(PayoutStatusBadges)
.filter(([key]) =>
["processing", "completed", "failed"].includes(key),
)
.map(([value, { label }]) => {
const Icon =
PayoutStatusBadges[value as keyof typeof PayoutStatusBadges].icon;
return {
value,
label,
icon: (
<Icon
className={cn(
PayoutStatusBadges[value as keyof typeof PayoutStatusBadges]
.className,
"size-4 bg-transparent",
)}
/>
),
};
}),
},
],
[programs],
);
const activeFilters = useMemo(() => {
return [
...(programId ? [{ key: "programId", value: programId }] : []),
...(status ? [{ key: "status", value: status }] : []),
];
}, [programId, status]);
const onSelect = useCallback(
(key: string, value: any) =>
queryParams({
set: {
[key]: value,
},
del: "page",
}),
[queryParams],
);
const onRemove = useCallback(
(key: string) =>
queryParams({
del: [key, "page"],
}),
[queryParams],
);
const onRemoveAll = useCallback(
() =>
queryParams({
del: ["status", "programId"],
}),
[queryParams],
);
const tabs: Tab[] = [
{
id: "payouts",
label: "Payouts",
colorClassName: "text-blue-500/50 bg-blue-500/50 border-blue-500",
},
{
id: "fees",
label: "Fees",
colorClassName: "text-red-500/50 bg-red-500/50 border-red-500",
},
{
id: "total",
label: "Total",
colorClassName: "text-green-500/50 bg-green-500/50 border-green-500",
},
];
const [selectedTab, setSelectedTab] = useState<"payouts" | "fees" | "total">(
"payouts",
);
const tab = tabs.find(({ id }) => id === selectedTab) ?? tabs[0];
// take the last 12 months
const chartData =
timeseriesData?.map(({ date, ...rest }) => ({
date: new Date(date),
values: {
value: rest[selectedTab],
},
})) ?? null;
const dateFormatter = (date: Date) =>
date.toLocaleDateString("en-US", {
month: "short",
year: "numeric",
timeZone: "UTC",
});
const totals = useMemo(() => {
return {
payouts:
timeseriesData?.reduce((acc, { payouts }) => acc + payouts, 0) ?? 0,
fees: timeseriesData?.reduce((acc, { fees }) => acc + fees, 0) ?? 0,
total: timeseriesData?.reduce((acc, { total }) => acc + total, 0) ?? 0,
};
}, [timeseriesData]);
const { pagination, setPagination } = usePagination();
const { table, ...tableProps } = useTable({
data: invoices ?? [],
columns: [
{
id: "date",
header: "Payment Date (UTC)",
accessorKey: "date",
cell: ({ row }) =>
formatDateTime(row.original.date, {
timeZone: "UTC",
}),
},
{
id: "program",
header: "Program",
cell: ({ row }) => (
<div className="flex items-center gap-1.5">
<img
src={row.original.programLogo}
alt={row.original.programName}
width={20}
height={20}
className="size-4 rounded-full"
/>
<span className="text-sm font-medium">
{row.original.programName}
</span>
</div>
),
meta: {
filterParams: ({ row }) => ({
programId: row.original.programId,
}),
},
},
{
id: "status",
header: "Status",
cell: ({ row }) => {
const badge = PayoutStatusBadges[row.original.status];
return badge ? (
<StatusBadge icon={badge.icon} variant={badge.variant}>
{badge.label}
</StatusBadge>
) : (
"-"
);
},
meta: {
filterParams: ({ row }) => ({
status: row.original.status,
}),
},
},
{
id: "amount",
header: "Amount",
accessorKey: "amount",
cell: ({ row }) => currencyFormatter(row.original.amount),
},
{
id: "fee",
header: "Fee",
accessorKey: "fee",
cell: ({ row }) => currencyFormatter(row.original.fee),
},
{
id: "total",
header: "Total",
accessorKey: "total",
cell: ({ row }) => currencyFormatter(row.original.total),
},
],
pagination,
onPaginationChange: setPagination,
resourceName: (plural) => `invoice${plural ? "s" : ""}`,
rowCount: invoices?.length ?? 0,
loading: isLoading,
cellRight: (cell) => {
const meta = cell.column.columnDef.meta as
| {
filterParams?: any;
}
| undefined;
return (
meta?.filterParams && (
<FilterButtonTableRow set={meta.filterParams(cell)} />
)
);
},
});
return (
<div className="mx-auto flex w-full max-w-screen-xl flex-col gap-3 p-6">
<div className="flex flex-col gap-3 md:flex-row md:items-center">
<Filter.Select
className="w-full md:w-fit"
filters={filters}
activeFilters={activeFilters}
onSelect={onSelect}
onRemove={onRemove}
/>
<SimpleDateRangePicker
defaultInterval="mtd"
className="w-full sm:min-w-[200px] md:w-fit"
/>
<Link href="/payouts/paypal">
<Button
variant="secondary"
text="Paypal payouts"
icon={<Paypal className="size-4" />}
/>
</Link>
</div>
{activeFilters.length > 0 && (
<div>
<Filter.List
filters={filters}
activeFilters={activeFilters}
onSelect={onSelect}
onRemove={onRemove}
onRemoveAll={onRemoveAll}
/>
</div>
)}
<div className="flex flex-col divide-y divide-neutral-200 rounded-lg border border-neutral-200 bg-white">
<div className="scrollbar-hide grid w-full grid-cols-1 divide-y overflow-y-hidden sm:grid-cols-3 sm:divide-x sm:divide-y-0">
{tabs.map(({ id, label, colorClassName }) => {
return (
<button
key={id}
onClick={() => {
setSelectedTab(id);
queryParams({
set: { tab: id },
});
}}
className={cn(
"border-box relative block h-full w-full flex-none px-4 py-3 sm:px-8 sm:py-6",
"transition-colors hover:bg-neutral-50 focus:outline-none active:bg-neutral-100",
"ring-inset ring-neutral-500 focus-visible:ring-1 sm:first:rounded-tl-xl",
)}
>
{/* Active tab indicator */}
{selectedTab === id && (
<div className="absolute bottom-0 left-0 h-0.5 w-full bg-black" />
)}
<div className="flex items-center gap-2.5 text-sm text-neutral-600">
<div
className={cn(
"h-2 w-2 rounded-sm bg-current shadow-[inset_0_0_0_1px_#00000019]",
colorClassName,
)}
/>
<span>{label}</span>
</div>
<div className="mt-1 flex h-12 items-center">
{(totals[id] || totals[id] === 0) && !isLoading ? (
<NumberFlow
value={(totals[id] ?? 0) / 100}
className="text-xl font-medium sm:text-3xl"
format={{
style: "currency",
currency: "USD",
// @ts-ignore – trailingZeroDisplay is a valid option but TS is outdated
trailingZeroDisplay: "stripIfInteger",
}}
/>
) : (
<div className="h-10 w-24 animate-pulse rounded-md bg-neutral-200" />
)}
</div>
</button>
);
})}
</div>
<div className="p-5 sm:p-10">
<div className="flex h-96 w-full items-center justify-center">
{chartData ? (
chartData.length > 0 ? (
<TimeSeriesChart
data={chartData}
series={[
{
id: "value",
valueAccessor: (d) => d.values.value,
isActive: true,
colorClassName: tab.colorClassName,
},
]}
tooltipClassName="p-0"
tooltipContent={(d) => (
<>
<p className="border-b border-neutral-200 px-4 py-3 text-sm text-neutral-900">
{formatDateTooltip(d.date, {
interval,
start,
end,
timezone: "UTC",
})}
</p>
<div className="grid grid-cols-2 gap-x-6 gap-y-2 px-4 py-3 text-sm">
<Fragment>
<div className="flex items-center gap-2">
<div
className={cn(
"h-2 w-2 rounded-sm shadow-[inset_0_0_0_1px_#0003]",
tab.colorClassName,
)}
/>
<p className="capitalize text-neutral-600">
{tab.label}
</p>
</div>
<p className="text-right font-medium text-neutral-900">
{currencyFormatter(d.values.value)}
</p>
</Fragment>
</div>
</>
)}
>
<Areas />
<XAxis maxTicks={5} tickFormat={dateFormatter} />
<YAxis
showGridLines
tickFormat={(value) => currencyFormatter(value)}
/>
</TimeSeriesChart>
) : (
<div className="text-center text-sm text-neutral-600">
No data available.
</div>
)
) : (
<AnalyticsLoadingSpinner />
)}
</div>
</div>
</div>
<div className="w-full">
<Table {...tableProps} table={table} />
</div>
</div>
);
}
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/payouts/page.tsx
================================================
import { Suspense } from "react";
import PayoutsPageClient from "./client";
export default async function PayoutsPage() {
return (
<Suspense>
<PayoutsPageClient />
</Suspense>
);
}
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/payouts/paypal/client.tsx
================================================
"use client";
import type { PaypalPayoutResponse } from "@/lib/paypal/get-pending-payouts";
import { PartnerAvatar } from "@/ui/partners/partner-avatar";
import { PayoutStatusBadges } from "@/ui/partners/payout-status-badges";
import { FilterButtonTableRow } from "@/ui/shared/filter-button-table-row";
import {
Button,
StatusBadge,
Table,
usePagination,
useRouterStuff,
useTable,
} from "@dub/ui";
import { Globe } from "@dub/ui/icons";
import {
cn,
COUNTRIES,
currencyFormatter,
fetcher,
nFormatter,
OG_AVATAR_URL,
} from "@dub/utils";
import NumberFlow from "@number-flow/react";
import { ChevronLeft } from "lucide-react";
import Link from "next/link";
import { useMemo } from "react";
import useSWR from "swr";
export default function PaypalPayoutsPageClient() {
const { getQueryString } = useRouterStuff();
const { data: payouts = [], isLoading } = useSWR<PaypalPayoutResponse[]>(
`/api/admin/payouts/paypal${getQueryString()}`,
fetcher,
{
keepPreviousData: true,
},
);
const { pagination, setPagination } = usePagination(100);
// Client-side pagination
const paginatedPayouts = useMemo(() => {
const start = (pagination.pageIndex - 1) * pagination.pageSize;
const end = start + pagination.pageSize;
return payouts.slice(start, end);
}, [payouts, pagination.pageIndex, pagination.pageSize]);
const { table, ...tableProps } = useTable({
data: paginatedPayouts,
columns: [
{
id: "partner",
header: "Partner",
cell: ({ row }) => (
<div className="flex items-center gap-1.5">
<PartnerAvatar partner={row.original.partner} className="size-4" />
<span className="text-sm text-neutral-900">
{row.original.partner.email || "-"}
</span>
</div>
),
},
{
id: "country",
header: "Country",
accessorKey: "partner.country",
meta: {
filterParams: ({ getValue }) => ({ country: getValue() }),
},
cell: ({ row }) => {
const country = row.original.partner.country;
if (!country || country === "Unknown") {
return (
<div className="flex items-center gap-3">
<Globe className="size-4 shrink-0" />
<span className="text-sm text-neutral-900">Unknown</span>
</div>
);
}
return (
<div
className="flex items-center gap-3"
title={COUNTRIES[country] ?? country}
>
<img
alt={country}
src={`https://hatscripts.github.io/circle-flags/flags/${country.toLowerCase()}.svg`}
className="size-4 shrink-0"
/>
<span className="truncate text-sm text-neutral-900">
{COUNTRIES[country] ?? country}
</span>
</div>
);
},
},
{
id: "program",
header: "Program",
accessorKey: "program.id",
meta: {
filterParams: ({ getValue }) => ({ programId: getValue() }),
},
cell: ({ row }) => (
<div className="flex items-center gap-1.5">
<img
src={
row.original.program.logo ||
`${OG_AVATAR_URL}${row.original.program.name}`
}
alt={row.original.program.name}
width={20}
height={20}
className="size-4 rounded-full"
/>
<span className="text-sm font-medium">
{row.original.program.name}
</span>
</div>
),
},
{
id: "status",
header: "Status",
cell: ({ row }) => {
const badge = PayoutStatusBadges[row.original.status];
return badge ? (
<StatusBadge icon={badge.icon} variant={badge.variant}>
{badge.label}
</StatusBadge>
) : (
"-"
);
},
},
{
id: "amount",
header: "Amount",
accessorKey: "amount",
cell: ({ row }) => currencyFormatter(row.original.amount),
},
],
pagination,
onPaginationChange: setPagination,
resourceName: (plural) => `payout${plural ? "s" : ""}`,
rowCount: payouts.length,
loading: isLoading,
cellRight: (cell) => {
const meta = cell.column.columnDef.meta as
| {
filterParams?: any;
}
| undefined;
return (
meta?.filterParams && (
<FilterButtonTableRow set={meta.filterParams(cell)} />
)
);
},
});
const stats = useMemo(() => {
const allPayouts = payouts;
const processingPayouts = payouts.filter((p) => p.status === "processing");
const pendingPayouts = payouts.filter((p) => p.status === "pending");
return [
{
id: "all",
label: "Total payouts",
amount: allPayouts.reduce((acc, p) => acc + p.amount, 0),
count: allPayouts.length,
colorClassName: "bg-blue-500",
},
{
id: "processing",
label: "Processing payouts",
amount: processingPayouts.reduce((acc, p) => acc + p.amount, 0),
count: processingPayouts.length,
colorClassName: "bg-purple-500",
},
{
id: "pending",
label: "Pending payouts",
amount: pendingPayouts.reduce((acc, p) => acc + p.amount, 0),
count: pendingPayouts.length,
colorClassName: "bg-orange-500",
},
];
}, [payouts]);
return (
<div className="mx-auto flex w-full max-w-screen-xl flex-col gap-3 p-6">
<div className="flex items-center justify-start">
<Link href="/payouts">
<Button
variant="secondary"
text="Back to all payouts"
icon={<ChevronLeft className="size-4" />}
/>
</Link>
</div>
<div className="grid grid-cols-1 divide-y divide-neutral-200 rounded-lg border border-neutral-200 bg-white sm:grid-cols-3 sm:flex-row sm:divide-x sm:divide-y-0">
{stats.map(({ id, label, amount, count, colorClassName }) => (
<div key={id} className="flex-none px-4 py-3 sm:px-8 sm:py-6">
<div className="flex items-center gap-2.5 text-sm text-neutral-600">
<div
className={cn(
"h-2 w-2 rounded-sm shadow-[inset_0_0_0_1px_#00000019]",
colorClassName,
)}
/>
<span>{label}</span>
</div>
<div className="mt-1 flex h-12 items-center">
{!isLoading ? (
<div className="flex items-baseline gap-2">
<NumberFlow
value={amount / 100}
className="text-xl font-medium sm:text-3xl"
format={{
style: "currency",
currency: "USD",
}}
/>
<span className="text-sm text-neutral-500">
({nFormatter(count, { full: true })})
</span>
</div>
) : (
<div className="h-10 w-24 animate-pulse rounded-md bg-neutral-200" />
)}
</div>
</div>
))}
</div>
<div className="w-full">
<Table {...tableProps} table={table} />
</div>
</div>
);
}
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/payouts/paypal/page.tsx
================================================
import { Suspense } from "react";
import PaypalPayoutsPageClient from "./client";
export default async function PaypalPayoutsPage() {
return (
<Suspense>
<PaypalPayoutsPageClient />
</Suspense>
);
}
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/revenue/client.tsx
================================================
"use client";
import SimpleDateRangePicker from "@/ui/shared/simple-date-range-picker";
import {
CrownSmall,
Table,
usePagination,
useRouterStuff,
useTable,
} from "@dub/ui";
import { cn, currencyFormatter, fetcher, nFormatter } from "@dub/utils";
import NumberFlow from "@number-flow/react";
import { useMemo } from "react";
import useSWR from "swr";
export default function RevenuePageClient() {
const { getQueryString } = useRouterStuff();
const { data: { programs } = {}, isLoading } = useSWR<{
programs: {
id: string;
name: string;
logo: string;
partners: number;
sales: number;
saleAmount: number;
}[];
}>(`/api/admin/revenue${getQueryString()}`, fetcher, {
keepPreviousData: true,
});
const { pagination, setPagination } = usePagination();
const { table, ...tableProps } = useTable({
data: programs ?? [],
columns: [
{
id: "position",
header: "Position",
size: 12,
minSize: 12,
maxSize: 12,
cell: ({ row }) => {
return (
<div className="flex w-28 items-center justify-start gap-2 tabular-nums">
{row.index + 1}
{row.index <= 2 && (
<CrownSmall
className={cn("size-4", {
"text-amber-400": row.index === 0,
"text-neutral-400": row.index === 1,
"text-yellow-900": row.index === 2,
})}
/>
)}
</div>
);
},
},
{
id: "program",
header: "Program",
cell: ({ row }) => (
<div className="flex items-center gap-1.5">
<img
src={row.original.logo}
alt={row.original.name}
width={20}
height={20}
className="size-4 rounded-full"
/>
<span className="text-sm font-medium">{row.original.name}</span>
</div>
),
},
{
id: "partners",
header: "Active Partners",
accessorKey: "partners",
cell: ({ row }) => nFormatter(row.original.partners, { full: true }),
},
{
id: "sales",
header: "Total Sales",
accessorKey: "sales",
cell: ({ row }) => nFormatter(row.original.sales, { full: true }),
},
{
id: "revenue",
header: "Affiliate Revenue",
accessorKey: "revenue",
cell: ({ row }) => currencyFormatter(row.original.saleAmount),
},
],
pagination,
onPaginationChange: setPagination,
resourceName: (plural) => `program${plural ? "s" : ""}`,
rowCount: programs?.length ?? 0,
loading: isLoading,
});
const stats = useMemo(
() => [
{
id: "partners",
label: "Active Partners",
value: programs?.reduce(
(acc, { partners }) => acc + (partners || 0),
0,
),
colorClassName: "bg-blue-500",
},
{
id: "sales",
label: "Total Sales",
value: programs?.reduce((acc, { sales }) => acc + (sales || 0), 0),
colorClassName: "bg-green-500",
},
{
id: "revenue",
label: "Affiliate Revenue",
value: programs?.reduce(
(acc, { saleAmount }) => acc + (saleAmount || 0),
0,
),
colorClassName: "bg-purple-500",
},
],
[programs],
);
return (
<div className="mx-auto flex w-full max-w-screen-xl flex-col space-y-6 p-6">
<SimpleDateRangePicker defaultInterval="mtd" className="w-fit" />
<div className="flex flex-col divide-y divide-neutral-200 rounded-lg border border-neutral-200 bg-white">
<div className="grid w-full grid-cols-1 divide-x sm:grid-cols-3">
{stats.map(({ id, label, value, colorClassName }) => (
<div key={id} className="flex-none px-4 py-3 sm:px-8 sm:py-6">
<div className="flex items-center gap-2.5 text-sm text-neutral-600">
<div
className={cn(
"h-2 w-2 rounded-sm shadow-[inset_0_0_0_1px_#00000019]",
colorClassName,
)}
/>
<span>{label}</span>
</div>
<div className="mt-1 flex h-12 items-center">
{value !== undefined ? (
id === "revenue" ? (
<NumberFlow
value={value / 100}
className="text-xl font-medium sm:text-3xl"
format={{
style: "currency",
currency: "USD",
// @ts-ignore – trailingZeroDisplay is a valid option but TS is outdated
trailingZeroDisplay: "stripIfInteger",
}}
/>
) : (
<NumberFlow
value={value}
className="text-xl font-medium sm:text-3xl"
/>
)
) : (
<div className="h-10 w-24 animate-pulse rounded-md bg-neutral-200" />
)}
</div>
</div>
))}
</div>
</div>
<div className="w-full">
<Table {...tableProps} table={table} />
</div>
</div>
);
}
================================================
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/revenue/page.tsx
================================================
import { Suspense } from "react";
import RevenuePageClient from "./client";
export default async function RevenuePage() {
return (
<Suspense>
<RevenuePageClient />
</Suspense>
);
}
================================================
FILE: apps/web/app/(ee)/admin.dub.co/layout.tsx
================================================
"use client";
import { SessionProvider } from "next-auth/react";
import { ReactNode } from "react";
export default function AdminLayout({ children }: { children: ReactNode }) {
return <SessionProvider>{children}</SessionProvider>;
}
================================================
FILE: apps/web/app/(ee)/api/admin/analytics/route.ts
================================================
import { getAnalytics } from "@/lib/analytics/get-analytics";
import { withAdmin } from "@/lib/auth";
import { parseAnalyticsQuery } from "@/lib/zod/schemas/analytics";
import { NextResponse } from "next/server";
// GET /api/admin/analytics – get analytics for admin
export const GET = withAdmin(async ({ searchParams }) => {
const parsedParams = parseAnalyticsQuery(searchParams);
const response = await getAnalytics(parsedParams);
return NextResponse.json(response);
});
================================================
FILE: apps/web/app/(ee)/api/admin/ban/route.ts
================================================
import { deleteWorkspaceAdmin } from "@/lib/api/workspaces/delete-workspace";
import { withAdmin } from "@/lib/auth";
import { updateConfig } from "@/lib/edge-config";
import { isStored, storage } from "@/lib/storage";
import { prisma } from "@dub/prisma";
import { R2_URL } from "@dub/utils";
import { waitUntil } from "@vercel/functions";
import { NextResponse } from "next/server";
// POST /api/admin/ban
export const POST = withAdmin(async ({ req }) => {
const { email } = await req.json();
const user = await prisma.user.findUniqueOrThrow({
where: {
email,
},
select: {
id: true,
email: true,
image: true,
projects: {
where: {
role: "owner",
},
select: {
project: {
select: {
id: true,
slug: true,
logo: true,
stripeId: true,
},
},
},
},
},
});
console.log(
`Found user ${user.email} with ${user.projects.length} workspaces`,
);
waitUntil(
Promise.all(
user.projects.map(({ project }) => deleteWorkspaceAdmin(project)),
).then(async () => {
await Promise.all([
user.image &&
isStored(user.image) &&
storage.delete({ key: user.image.replace(`${R2_URL}/`, "") }),
updateConfig({
key: "emails",
value: email,
}),
]);
// delete user
await prisma.user.delete({
where: {
id: user.id,
},
});
}),
);
return NextResponse.json({ success: true });
});
================================================
FILE: apps/web/app/(ee)/api/admin/commissions/get-commissions-timeseries.ts
================================================
import { sqlGranularityMap } from "@/lib/planetscale/granularity";
import { TZDate } from "@date-fns/tz";
import { prisma } from "@dub/prisma";
import { Prisma } from "@dub/prisma/client";
import { ACME_PROGRAM_ID } from "@dub/utils";
import { format } from "date-fns";
interface Commission {
start: string;
commissions: number;
}
export async function getCommissionsTimeseries({
programId,
startDate,
endDate,
granularity,
timezone,
}: {
programId?: string;
startDate: Date;
endDate: Date;
granularity: string;
timezone: string;
}) {
const { dateFormat, dateIncrement, startFunction, formatString } =
sqlGranularityMap[granularity];
const commissions = await prisma.$queryRaw<Commission[]>`
SELECT
DATE_FORMAT(CONVERT_TZ(createdAt, "UTC", ${timezone || "UTC"}), ${dateFormat}) AS start,
SUM(earnings) AS commissions
FROM Commission
WHERE
createdAt >= ${startDate}
AND createdAt < ${endDate}
AND status IN ("pending", "processed", "paid")
AND ${programId ? Prisma.sql`programId = ${programId}` : Prisma.sql`programId != ${ACME_PROGRAM_ID}`}
GROUP BY start
ORDER BY start ASC;`;
// Convert dates to TZDate with the specified timezone
const tzStartDate = new TZDate(startDate, timezone || "UTC");
const tzEndDate = new TZDate(endDate, timezone || "UTC");
let currentDate = startFunction(tzStartDate);
const commissionsLookup = Object.fromEntries(
commissions.map((item) => [
item.start,
{
commissions: Number(item.commissions),
},
]),
);
const timeseries: Commission[] = [];
while (currentDate < tzEndDate) {
const periodKey = format(currentDate, formatString);
timeseries.push({
start: currentDate.toISOString(),
...(commissionsLookup[periodKey] || {
commissions: 0,
}),
});
currentDate = dateIncrement(currentDate);
}
return timeseries;
}
================================================
FILE: apps/web/app/(ee)/api/admin/commissions/get-top-program-by-commissions.ts
================================================
import { prisma } from "@dub/prisma";
import { ACME_PROGRAM_ID } from "@dub/utils";
export async function getTopProgramsByCommissions({
programId,
startDate,
endDate,
}: {
programId?: string;
startDate: Date;
endDate: Date;
}) {
const programCommissions = await prisma.commission.groupBy({
by: ["programId"],
_sum: {
earnings: true,
},
where: {
createdAt: {
gte: startDate,
lte: endDate,
},
status: {
in: ["pending", "processed", "paid"],
},
programId: programId || {
not: ACME_PROGRAM_ID,
},
},
orderBy: {
_sum: {
earnings: "desc",
},
},
take: 50,
});
const topPrograms = await prisma.program.findMany({
where: {
id: {
in: programCommissions.map(({ programId }) => programId),
},
},
include: {
workspace: {
select: {
payoutFee: true,
},
},
},
});
const programIdMap = Object.fromEntries(
topPrograms.map((program) => [program.id, program]),
);
const topProgramsWithCommissions = programCommissions
.map(({ programId, _sum }) => {
const program = programIdMap[programId];
if (!program) return null;
const commissions = _sum.earnings || 0;
const payoutFee = program.workspace?.payoutFee || 0;
return {
...program,
commissions,
fees: commissions * payoutFee,
};
})
.filter(Boolean);
return topProgramsWithCommissions;
}
================================================
FILE: apps/web/app/(ee)/api/admin/commissions/route.ts
================================================
import { getStartEndDates } from "@/lib/analytics/utils/get-start-end-dates";
import { withAdmin } from "@/lib/auth";
import { analyticsQuerySchema } from "@/lib/zod/schemas/analytics";
import { DUB_FOUNDING_DATE } from "@dub/utils";
import { endOfDay, startOfDay } from "date-fns";
import { NextResponse } from "next/server";
import * as z from "zod/v4";
import { getCommissionsTimeseries } from "./get-commissions-timeseries";
import { getTopProgramsByCommissions } from "./get-top-program-by-commissions";
const adminCommissionsQuerySchema = z
.object({
programId: z.string().optional(),
timezone: z.string().optional().default("UTC"),
})
.extend(
analyticsQuerySchema.pick({ interval: true, start: true, end: true }).shape,
);
export const GET = withAdmin(async ({ searchParams }) => {
const {
programId,
interval = "mtd",
start,
end,
timezone = "UTC",
} = adminCommissionsQuerySchema.parse(searchParams);
const { startDate, endDate, granularity } = getStartEndDates({
interval,
start: start ? startOfDay(new Date(start)) : undefined,
end: end ? endOfDay(new Date(end)) : undefined,
dataAvailableFrom: DUB_FOUNDING_DATE,
timezone,
});
const [programs, timeseries] = await Promise.all([
getTopProgramsByCommissions({ programId, startDate, endDate }),
getCommissionsTimeseries({
programId,
startDate,
endDate,
granularity,
timezone,
}),
]);
return NextResponse.json({
programs,
timeseries,
});
});
================================================
FILE: apps/web/app/(ee)/api/admin/delete-partner-account/route.ts
================================================
import { withAdmin } from "@/lib/auth";
import { conn } from "@/lib/planetscale";
import { stripe } from "@/lib/stripe";
import { recordLink } from "@/lib/tinybird";
import { prisma } from "@dub/prisma";
import { prettyPrint } from "@dub/utils";
import { NextResponse } from "next/server";
// POST /api/admin/delete-partner-account
export const POST = withAdmin(async ({ req }) => {
const { email, deletePartnerAccount } = await req.json();
const partner = await prisma.partner.findUnique({
where: {
email,
},
include: {
commissions: true,
programs: {
select: {
program: true,
links: true,
groupId: true,
},
},
},
});
if (!partner) {
return new Response("Partner not found", { status: 404 });
}
if (partner.stripeConnectId) {
try {
// check if stripe express account has received payouts before
const transfers = await stripe.transfers.list({
destination: partner.stripeConnectId,
limit: 1,
});
if (transfers.data.length > 0) {
return new Response(
"Stripe express account has received payouts before and cannot be deleted.",
{
status: 400,
},
);
}
const res = await stripe.accounts.del(partner.stripeConnectId);
console.log(
`Deleted Stripe express account for partner ${partner.email}: `,
prettyPrint(res),
);
} catch (error) {
console.log(
"Error deleting Stripe express account (probably already deleted): ",
error,
);
}
await prisma.partner.update({
where: {
id: partner.id,
},
data: {
stripeConnectId: null,
payoutsEnabledAt: null,
payoutMethodHash: null,
},
});
console.log(`Updated partner ${partner.email} with stripeConnectId null`);
}
if (deletePartnerAccount) {
if (partner.commissions.length > 0) {
return new Response(
"Partner has already received commissions and cannot be deleted.",
{
status: 400,
},
);
}
if (
partner.programs.some(({ links }) => links.some((link) => link.leads > 0))
) {
return new Response(
"Partner has already received leads and cannot be deleted.",
{
status: 400,
},
);
}
if (partner.programs.length > 0) {
for (const { program, links, groupId } of partner.programs) {
if (links.length > 0) {
await Promise.allSettled([
prisma.link.deleteMany({
where: {
id: {
in: links.map((link) => link.id),
},
},
}),
recordLink(
links.map((link) => ({
...link,
programEnrollment: { groupId },
})),
{ deleted: true },
),
]);
console.log(
`Deleted ${links.length} links for program ${program.name} (${program.slug})`,
);
}
}
await prisma.programEnrollment.deleteMany({
where: {
partnerId: partner.id,
programId: {
in: partner.programs.map(({ program }) => program.id),
},
},
});
console.log(
`Deleted ${partner.programs.length} program enrollments for partner ${partner.email} (${partner.id})`,
);
}
await conn.execute(`DELETE FROM Partner WHERE id = ?`, [partner.id]);
console.log(`Deleted partner ${partner.email} (${partner.id})`);
}
return NextResponse.json({ success: true });
});
================================================
FILE: apps/web/app/(ee)/api/admin/events/route.ts
================================================
import { getEvents } from "@/lib/analytics/get-events";
import { withAdmin } from "@/lib/auth";
import { eventsQuerySchema } from "@/lib/zod/schemas/analytics";
import { NextResponse } from "next/server";
// GET /api/admin/events – get events for admin
export const GET = withAdmin(async ({ searchParams }) => {
const parsedParams = eventsQuerySchema.parse(searchParams);
const response = await getEvents(parsedParams);
return NextResponse.json(response);
});
================================================
FILE: apps/web/app/(ee)/api/admin/impersonate/route.ts
================================================
import { hashToken, withAdmin } from "@/lib/auth";
import { prisma } from "@dub/prisma";
import { APP_DOMAIN, PARTNERS_DOMAIN } from "@dub/utils";
import { randomBytes } from "crypto";
import { NextResponse } from "next/server";
// POST /api/admin/impersonate
export const POST = withAdmin(async ({ req }) => {
const { email, slug } = await req.json();
const response = await prisma.user.findFirst({
where: email
? { email }
: {
projects: {
some: {
project: {
slug,
},
role: "owner",
},
},
},
select: {
email: true,
projects: {
select: {
project: {
select: {
id: true,
name: true,
slug: true,
plan: true,
usage: true,
linksUsage: true,
totalClicks: true,
totalLinks: true,
},
},
},
orderBy: {
project: {
totalClicks: "desc",
},
},
},
partners: {
select: {
partner: {
select: {
programs: {
select: {
program: {
select: {
id: true,
name: true,
slug: true,
},
},
status: true,
totalClicks: true,
totalLeads: true,
totalConversions: true,
totalSaleAmount: true,
totalCommissions: true,
},
orderBy: {
totalCommissions: "desc",
},
},
},
},
},
},
},
});
if (!response?.email) {
return new Response("User not found", { status: 404 });
}
const data = {
email: response.email,
workspaces: response.projects.map(({ project }) => ({
...project,
clicks: project.usage,
links: project.linksUsage,
totalClicks: project.totalClicks,
totalLinks: project.totalLinks,
})),
programs:
response.partners.length > 0
? response.partners[0].partner.programs.map(({ program, ...rest }) => ({
...program,
...rest,
}))
: [],
impersonateUrl: await getImpersonateUrl(response.email),
};
return NextResponse.json(data);
});
async function getImpersonateUrl(email: string) {
const token = randomBytes(32).toString("hex");
await prisma.verificationToken.create({
data: {
identifier: email,
token: await hashToken(token, { secret: true }),
expires: new Date(Date.now() + 60000),
},
});
return {
app: `${APP_DOMAIN}/api/auth/callback/email?${new URLSearchParams({
callbackUrl: APP_DOMAIN,
email,
token,
})}`,
partners: `${PARTNERS_DOMAIN}/api/auth/callback/email?${new URLSearchParams(
{
callbackUrl: PARTNERS_DOMAIN,
email,
token,
},
)}`,
};
}
================================================
FILE: apps/web/app/(ee)/api/admin/links/[linkId]/route.ts
================================================
import { transformLink } from "@/lib/api/links";
import { withAdmin } from "@/lib/auth";
import { prisma } from "@dub/prisma";
import { NextResponse } from "next/server";
// GET /api/admin/links/[linkId] – get a link as an admin
export const GET = withAdmin(async ({ params }) => {
const { linkId } = params;
const link = await prisma.link.findUnique({
where: {
id: linkId,
},
});
if (!link) {
return NextResponse.json({ error: "Link not found" }, { status: 404 });
}
return NextResponse.json(transformLink(link));
});
================================================
FILE: apps/web/app/(ee)/api/admin/links/ban/route.ts
================================================
import { linkCache } from "@/lib/api/links/cache";
import { withAdmin } from "@/lib/auth";
import { updateConfig } from "@/lib/edge-config";
import { domainKeySchema } from "@/lib/zod/schemas/links";
import { prisma } from "@dub/prisma";
import {
LEGAL_USER_ID,
LEGAL_WORKSPACE_ID,
getDomainWithoutWWW,
} from "@dub/utils";
import { NextResponse } from "next/server";
// DELETE /api/admin/links/ban – ban a dub.sh link by key
export const DELETE = withAdmin(async ({ searchParams }) => {
const { domain, key } = domainKeySchema.parse(searchParams);
const link = await prisma.link.findUnique({
where: { domain_key: { domain, key } },
});
if (!link) {
return NextResponse.json({ error: "Link not found" }, { status: 404 });
}
const urlDomain = getDomainWithoutWWW(link.url);
const response = await Promise.all([
prisma.link.update({
where: {
id: link.id,
},
data: {
userId: LEGAL_USER_ID,
projectId: LEGAL_WORKSPACE_ID,
},
}),
linkCache.set({ ...link, projectId: LEGAL_WORKSPACE_ID }),
urlDomain &&
updateConfig({
key: "domains",
value: urlDomain,
}),
]);
return NextResponse.json(response);
});
================================================
FILE: apps/web/app/(ee)/api/admin/links/count/route.ts
================================================
import { withAdmin } from "@/lib/auth";
import { prisma } from "@dub/prisma";
import { DUB_DOMAINS_ARRAY, LEGAL_USER_ID } from "@dub/utils";
import { NextResponse } from "next/server";
// GET /api/admin/links/count
export const GET = withAdmin(async ({ searchParams }) => {
let { groupBy, search, domain, tagId } = searchParams as {
groupBy?: "domain" | "tagId" | "userId";
search?: string;
domain?: string;
tagId?: string;
};
let response;
const tagIds = tagId ? tagId.split(",") : [];
const linksWhere = {
// when filtering by domain, only filter by domain if the filter group is not "Domains"
...(domain && groupBy !== "domain"
? {
domain,
}
: {
domain: {
in: DUB_DOMAINS_ARRAY,
},
}),
userId: {
not: LEGAL_USER_ID,
},
...(search && {
OR: [
{
shortLink: { contains: search },
},
{
url: { contains: search },
},
],
}),
};
if (groupBy === "tagId") {
response = await prisma.linkTag.groupBy({
by: ["tagId"],
where: {
link: linksWhere,
},
_count: true,
orderBy: {
_count: {
tagId: "desc",
},
},
});
} else {
const where = {
...linksWhere,
...(tagIds.length > 0 && {
tags: {
some: {
tagId: {
in: tagIds,
},
},
},
}),
};
if (groupBy) {
response = await prisma.link.groupBy({
by: [groupBy],
where,
_count: true,
orderBy: {
_count: {
[groupBy]: "desc",
},
},
take: 500,
});
} else {
response = await prisma.link.count({
where,
});
}
}
return NextResponse.json(response);
});
================================================
FILE: apps/web/app/(ee)/api/admin/links/route.ts
================================================
import { transformLink } from "@/lib/api/links";
import { withAdmin } from "@/lib/auth";
import { prisma } from "@dub/prisma";
import { DUB_DOMAINS_ARRAY, LEGAL_USER_ID } from "@dub/utils";
import { NextResponse } from "next/server";
// GET /api/admin/links
export const GET = withAdmin(async ({ searchParams }) => {
const {
domain,
search,
sort = "createdAt",
page,
} = searchParams as {
domain?: string;
search?: string;
sort?: "createdAt" | "clicks" | "lastClicked";
page?: string;
};
const response = await prisma.link.findMany({
where: {
...(domain
? { domain }
: {
domain: {
in: DUB_DOMAINS_ARRAY,
},
}),
...(!search && {
createdAt: {
gte: new Date(Date.now() - 1000 * 60 * 60 * 24 * 30), // 30 days ago
},
}),
OR: [
{
userId: {
not: LEGAL_USER_ID,
},
},
{
userId: null,
},
],
...(search &&
(search.startsWith("https://")
? {
shortLink: search,
}
: {
OR: [
{
shortLink: { contains: search },
},
{
url: { contains: search },
},
],
})),
},
include: {
user: true,
tags: {
include: {
tag: {
select: {
id: true,
name: true,
color: true,
},
},
},
},
},
orderBy: {
[sort]: "desc",
},
take: 100,
...(page && {
skip: (parseInt(page) - 1) * 100,
}),
});
return NextResponse.json(response.map((link) => transformLink(link)));
});
================================================
FILE: apps/web/app/(ee)/api/admin/payouts/paypal/route.ts
================================================
import { withAdmin } from "@/lib/auth/admin";
import { getPendingPaypalPayouts } from "@/lib/paypal/get-pending-payouts";
import { NextResponse } from "next/server";
export const GET = withAdmin(async ({ searchParams }) => {
const { country, programId } = searchParams;
const pendingPaypalPayouts = await getPendingPaypalPayouts({
country,
programId,
});
return NextResponse.json(pendingPaypalPayouts);
});
================================================
FILE: apps/web/app/(ee)/api/admin/payouts/route.ts
================================================
import { getStartEndDates } from "@/lib/analytics/utils/get-start-end-dates";
import { withAdmin } from "@/lib/auth";
import { sqlGranularityMap } from "@/lib/planetscale/granularity";
import { analyticsQuerySchema } from "@/lib/zod/schemas/analytics";
import { prisma } from "@dub/prisma";
import { InvoiceStatus, Prisma } from "@dub/prisma/client";
import { ACME_PROGRAM_ID } from "@dub/utils";
import { format } from "date-fns";
import { NextResponse } from "next/server";
import * as z from "zod/v4";
interface TimeseriesPoint {
payouts: number;
fees: number;
total: number;
}
interface FormattedTimeseriesPoint extends TimeseriesPoint {
date: Date;
}
const adminPayoutsQuerySchema = z
.object({
programId: z.string().optional(),
status: z.enum(InvoiceStatus).optional(),
})
.extend(
analyticsQuerySchema.pick({ interval: true, start: true, end: true }).shape,
);
export const GET = withAdmin(async ({ searchParams }) => {
const {
programId,
status,
interval = "mtd",
start,
end,
} = adminPayoutsQuerySchema.parse(searchParams);
const timezone = "UTC";
const { startDate, endDate, granularity } = getStartEndDates({
interval,
start,
end,
timezone,
});
// Fetch invoices
const invoices = await prisma.invoice.findMany({
where: {
...(programId
? { programId }
: {
AND: [
{
programId: {
not: ACME_PROGRAM_ID,
},
},
{
program: {
isNot: null,
},
},
],
}),
status: status || {
not: "failed",
},
createdAt: {
gte: startDate,
lte: endDate,
},
},
include: {
program: {
select: {
name: true,
logo: true,
},
},
},
orderBy: {
createdAt: "desc",
},
});
const { dateFormat, dateIncrement, startFunction, formatString } =
sqlGranularityMap[granularity];
// Calculate timeseries data for payouts and fees
const timeseriesData = await prisma.$queryRaw<
{ date: Date; payouts: number; fees: number; total: number }[]
>`
SELECT
DATE_FORMAT(CONVERT_TZ(createdAt, "UTC", ${timezone}), ${dateFormat}) as date,
SUM(amount) as payouts,
SUM(fee) as fees,
SUM(total) as total
FROM Invoice
WHERE
${programId ? Prisma.sql`programId = ${programId}` : Prisma.sql`programId != ${ACME_PROGRAM_ID}`}
AND ${status ? Prisma.sql`status = ${status}` : Prisma.sql`status != 'failed'`}
AND createdAt >= ${startDate}
AND createdAt <= ${endDate}
GROUP BY DATE_FORMAT(CONVERT_TZ(createdAt, "UTC", ${timezone}), ${dateFormat})
ORDER BY date ASC;
`;
const formattedInvoices = invoices.map((invoice) => ({
date: invoice.createdAt,
// we're coercing this cause we've filtered out invoices without a programId above
programId: invoice.programId!,
programName: invoice.program!.name,
programLogo: invoice.program!.logo,
status: invoice.status,
amount: invoice.amount,
fee: invoice.fee,
total: invoice.total,
}));
// Create a lookup object for the timeseries data
const timeseriesLookup: Record<string, TimeseriesPoint> = Object.fromEntries(
timeseriesData.map((item) => [
item.date,
{
payouts: Number(item.payouts),
fees: Number(item.fees),
total: Number(item.total),
},
]),
);
// Backfill missing dates with 0 values
let currentDate = startFunction(startDate);
const formattedTimeseriesData: FormattedTimeseriesPoint[] = [];
while (currentDate < endDate) {
const periodKey = format(currentDate, formatString);
formattedTimeseriesData.push({
date: currentDate,
...(timeseriesLookup[periodKey] || {
payouts: 0,
fees: 0,
total: 0,
}),
});
currentDate = dateIncrement(currentDate);
}
return NextResponse.json({
invoices: formattedInvoices,
timeseriesData: formattedTimeseriesData,
});
});
================================================
FILE: apps/web/app/(ee)/api/admin/refresh-domain/route.ts
================================================
import { addDomainToVercel } from "@/lib/api/domains/add-domain-vercel";
import { withAdmin } from "@/lib/auth";
import { NextResponse } from "next/server";
// POST /api/admin/refresh-domain
export const POST = withAdmin(async ({ req }) => {
const { domain } = await req.json();
const remove = await fetch(
`https://api.vercel.com/v9/projects/${process.env.PROJECT_ID_VERCEL}/domains/${domain}?teamId=${process.env.TEAM_ID_VERCEL}`,
{
headers: {
Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`,
},
method: "DELETE",
},
).then((res) => res.json());
const add = await addDomainToVercel(domain);
console.log({ remove, add });
return NextResponse.json({ success: true });
});
================================================
FILE: apps/web/app/(ee)/api/admin/reset-login-attempts/route.ts
================================================
import { withAdmin } from "@/lib/auth";
import { prisma } from "@dub/prisma";
import { NextResponse } from "next/server";
// POST /api/admin/reset-login-attempts
export const POST = withAdmin(async ({ req }) => {
const { email } = await req.json();
if (!email) {
return NextResponse.json({ error: "Email is required" }, { status: 400 });
}
const user = await prisma.user.findUnique({
where: { email },
select: {
id: true,
email: true,
invalidLoginAttempts: true,
lockedAt: true,
},
});
if (!user) {
return NextResponse.json({ error: "User not found" }, { status: 404 });
}
const updatedUser = await prisma.user.update({
where: { email },
data: {
invalidLoginAttempts: 0,
lockedAt: null,
},
select: {
id: true,
email: true,
invalidLoginAttempts: true,
lockedAt: true,
},
});
return NextResponse.json({
success: true,
user: updatedUser,
});
});
================================================
FILE: apps/web/app/(ee)/api/admin/revenue/get-top-programs-by-sales.ts
================================================
import { formatUTCDateTimeClickhouse } from "@/lib/analytics/utils/format-utc-datetime-clickhouse";
import { tb } from "@/lib/tinybird";
import { prisma } from "@dub/prisma";
import { ACME_PROGRAM_ID } from "@dub/utils";
import * as z from "zod/v4";
export async function getTopProgramsBySales({
startDate,
endDate,
}: {
startDate: Date;
endDate: Date;
}) {
const pipe = tb.buildPipe({
pipe: "v2_top_programs",
parameters: z.any(),
data: z.any(),
});
const response = await pipe({
eventType: "sales",
start: formatUTCDateTimeClickhouse(startDate),
end: formatUTCDateTimeClickhouse(endDate),
});
const topProgramsData = response.data as {
programId: string;
}[];
const programIds = topProgramsData
.map((item) => item.programId)
.filter((id) => id !== ACME_PROGRAM_ID);
const programs = await prisma.program.findMany({
where: {
id: {
in: programIds,
},
},
select: {
id: true,
name: true,
logo: true,
_count: {
select: {
partners: {
where: {
totalCommissions: {
gt: 0,
},
},
},
},
},
},
});
return topProgramsData
.map((item) => {
const program = programs.find((program) => program.id === item.programId);
if (!program) return null;
const { _count, ...rest } = program;
return {
...rest,
...item,
partners: _count.partners,
};
})
.filter(Boolean);
}
================================================
FILE: apps/web/app/(ee)/api/admin/revenue/route.ts
================================================
import { getStartEndDates } from "@/lib/analytics/utils/get-start-end-dates";
import { withAdmin } from "@/lib/auth";
import { DUB_FOUNDING_DATE } from "@dub/utils";
import { endOfDay, startOfDay } from "date-fns";
import { NextResponse } from "next/server";
import { getTopProgramsBySales } from "./get-top-programs-by-sales";
export const GET = withAdmin(async ({ searchParams }) => {
const { interval = "mtd", start, end } = searchParams;
const { startDate, endDate } = getStartEndDates({
interval,
start: start ? startOfDay(new Date(start)) : undefined,
end: end ? endOfDay(new Date(end)) : undefined,
dataAvailableFrom: DUB_FOUNDING_DATE,
});
const programs = await getTopProgramsBySales({
startDate,
endDate,
});
return NextResponse.json({
programs,
});
});
================================================
FILE: apps/web/app/(ee)/api/audit-logs/export/route.ts
================================================
import { convertToCSV } from "@/lib/analytics/utils";
import { getAuditLogs } from "@/lib/api/audit-logs/get-audit-logs";
import { DubApiError } from "@/lib/api/errors";
import { getDefaultProgramIdOrThrow } from "@/lib/api/programs/get-default-program-id-or-throw";
import { parseRequestBody } from "@/lib/api/utils";
import { withWorkspace } from "@/lib/auth";
import { getPlanCapabilities } from "@/lib/plan-capabilities";
import * as z from "zod/v4";
const auditLogExportQuerySchema = z.object({
start: z.string(),
end: z.string(),
});
// POST /api/audit-logs/export – export audit logs to CSV
export const POST = withWorkspace(
async ({ req, workspace }) => {
const { start, end } = auditLogExportQuerySchema.parse(
await parseRequestBody(req),
);
if (!start || !end) {
throw new DubApiError({
code: "bad_request",
message: "Must provide start and end dates.",
});
}
const { canExportAuditLogs } = getPlanCapabilities(workspace.plan);
if (!canExportAuditLogs) {
throw new DubApiError({
code: "forbidden",
message: "You are not authorized to export audit logs.",
});
}
const programId = getDefaultProgramIdOrThrow(workspace);
const auditLogs = await getAuditLogs({
workspaceId: workspace.id,
programId,
start: new Date(start),
end: new Date(end),
});
const csvData = convertToCSV(auditLogs);
return new Response(csvData, {
headers: {
"Content-Type": "application/csv",
"Content-Disposition": `attachment;`,
},
});
},
{
requiredRoles: ["owner", "member"],
requiredPlan: ["enterprise"],
},
);
================================================
FILE: apps/web/app/(ee)/api/auth/saml/authorize/route.ts
================================================
import { jackson } from "@/lib/jackson";
import { getSearchParams } from "@dub/utils";
import { NextResponse } from "next/server";
const handler = async (req: Request) => {
const { oauthController } = await jackson();
const requestParams =
req.method === "GET" ? getSearchParams(req.url) : await req.json();
const { redirect_url, authorize_form } =
await oauthController.authorize(requestParams);
if (redirect_url) {
return NextResponse.redirect(redirect_url, {
status: 302,
});
} else {
return new Response(authorize_form, {
headers: {
"Content-Type": "text/html; charset=utf-8",
},
});
}
};
export { handler as GET, handler as POST };
================================================
FILE: apps/web/app/(ee)/api/auth/saml/callback/route.ts
================================================
import { jackson } from "@/lib/jackson";
import { NextResponse } from "next/server";
export async function POST(req: Request) {
const { oauthController } = await jackson();
const formData = await req.formData();
const RelayState = formData.get("RelayState") || "";
const SAMLResponse = formData.get("SAMLResponse") || "";
const { redirect_url } = await oauthController.samlResponse({
RelayState: RelayState as string,
SAMLResponse: SAMLResponse as string,
});
if (!redirect_url) {
return new Response("No redirect URL found.", {
status: 400,
});
}
return NextResponse.redirect(redirect_url, {
status: 302,
});
}
================================================
FILE: apps/web/app/(ee)/api/auth/saml/token/route.ts
================================================
import { jackson } from "@/lib/jackson";
import * as jose from "jose";
import { NextResponse } from "next/server";
import * as dummy from "openid-client";
export async function POST(req: Request) {
console.log("token route");
// Need these imports to fix import errors with jackson
// https://github.com/ory/polis/blob/main/pages/api/import-hack.ts
const unused = dummy; // eslint-disable-line @typescript-eslint/no-unused-vars
const unused2 = jose; // eslint-disable-line @typescript-eslint/no-unused-vars
const { oauthController } = await jackson();
const formData = await req.formData();
const body = Object.fromEntries(formData.entries());
const token = await oauthController.token(body as any);
return NextResponse.json(token);
}
================================================
FILE: apps/web/app/(ee)/api/auth/saml/userinfo/route.ts
================================================
import { jackson } from "@/lib/jackson";
import { NextResponse } from "next/server";
export async function GET(req: Request) {
const { oauthController } = await jackson();
const authHeader = req.headers.get("Authorization");
if (!authHeader) {
return new Response("Unauthorized", {
status: 401,
});
}
const token = authHeader.split(" ")[1];
const user = await oauthController.userInfo(token);
return NextResponse.json(user);
}
================================================
FILE: apps/web/app/(ee)/api/auth/saml/verify/route.tsx
================================================
import { jackson } from "@/lib/jackson";
import { prisma } from "@dub/prisma";
import { NextResponse } from "next/server";
export async function POST(req: Request) {
const { apiController } = await jackson();
const { slug } = await req.json();
if (!slug) {
return NextResponse.json(
{ error: "No workspace slug provided." },
{ status: 400 },
);
}
const workspace = await prisma.project.findUnique({
where: { slug },
select: { id: true },
});
if (!workspace) {
return NextResponse.json(
{ error: "Workspace not found." },
{ status: 404 },
);
}
const connections = await apiController.getConnections({
tenant: workspace.id,
product: "Dub",
});
if (!connections || connections.length === 0) {
return NextResponse.json(
{ error: "No SSO connections found for this workspace." },
{ status: 404 },
);
}
const data = {
workspaceId: workspace.id,
};
return NextResponse.json({ data });
}
================================================
FILE: apps/web/app/(ee)/api/bounties/[bountyId]/route.ts
================================================
import { recordAuditLog } from "@/lib/api/audit-logs/record-audit-log";
import { DubApiError } from "@/lib/api/errors";
import { throwIfInvalidGroupIds } from "@/lib/api/groups/throw-if-invalid-group-ids";
import { getDefaultProgramIdOrThrow } from "@/lib/api/programs/get-default-program-id-or-throw";
import { parseRequestBody } from "@/lib/api/utils";
import { withWorkspace } from "@/lib/auth";
import { generatePerformanceBountyName } from "@/lib/bounty/api/generate-performance-bounty-name";
import { getBountyWithDetails } from "@/lib/bounty/api/get-bounty-with-details";
import { PERFORMANCE_BOUNTY_SCOPE_ATTRIBUTES } from "@/lib/bounty/api/performance-bounty-scope-attributes";
import { validateBounty } from "@/lib/bounty/api/validate-bounty";
import { getPlanCapabilities } from "@/lib/plan-capabilities";
import { WorkflowCondition } from "@/lib/types";
import { sendWorkspaceWebhook } from "@/lib/webhook/publish";
import {
BountySchema,
submissionRequirementsSchema,
updateBountySchema,
} from "@/lib/zod/schemas/bounties";
import { prisma } from "@dub/prisma";
import { PartnerGroup, Prisma } from "@dub/prisma/client";
import { arrayEqual, deepEqual } from "@dub/utils";
import { waitUntil } from "@vercel/functions";
import { NextResponse } from "next/server";
// GET /api/bounties/[bountyId] - get a bounty
export const GET = withWorkspace(
async ({ workspace, params }) => {
const { bountyId } = params;
const programId = getDefaultProgramIdOrThrow(workspace);
console.time("getBountyWithDetails");
const bounty = await getBountyWithDetails({
bountyId,
programId,
});
console.timeEnd("getBountyWithDetails");
return NextResponse.json(BountySchema.parse(bounty));
},
{
requiredPlan: [
"business",
"business plus",
"business extra",
"business max",
"advanced",
"enterprise",
],
},
);
// PATCH /api/bounties/[bountyId] - update a bounty
export const PATCH = withWorkspace(
async ({ workspace, params, req, session }) => {
const { bountyId } = params;
const programId = getDefaultProgramIdOrThrow(workspace);
const {
name,
description,
startsAt,
endsAt,
submissionsOpenAt,
submissionFrequency,
maxSubmissions,
rewardAmount,
rewardDescription,
submissionRequirements,
performanceCondition,
groupIds,
} = updateBountySchema.parse(await parseRequestBody(req));
const bounty = await prisma.bounty.findUniqueOrThrow({
where: {
id: bountyId,
programId,
},
include: {
groups: true,
workflow: true,
_count: {
select: {
submissions: true,
},
},
},
});
validateBounty({
type: bounty.type,
startsAt,
endsAt: endsAt !== undefined ? endsAt : bounty.endsAt,
submissionsOpenAt,
submissionFrequency:
submissionFrequency !== undefined
? submissionFrequency
: bounty.submissionFrequency,
maxSubmissions:
maxSubmissions !== undefined ? maxSubmissions : bounty.maxSubmissions,
submissionRequirements,
rewardAmount,
rewardDescription,
performanceScope: bounty.performanceScope,
});
if (
submissionRequirements !== undefined &&
submissionRequirements?.socialMetrics &&
!getPlanCapabilities(workspace.plan).canUseBountySocialMetrics
) {
throw new DubApiError({
code: "forbidden",
message: "Social metrics criteria require Advanced plan or above.",
});
}
// TODO:
// When we do archive, make sure it disables the workflow
// if groupIds is provided and is different from the current groupIds, update the groups
let updatedPartnerGroups: PartnerGroup[] | undefined = undefined;
if (
groupIds &&
!arrayEqual(
bounty.groups.map((group) => group.groupId),
groupIds,
)
) {
updatedPartnerGroups = await throwIfInvalidGroupIds({
programId,
groupIds,
});
}
// Prevent updates if `performanceCondition.attribute` differs from the current value if there are existing submissions
if (performanceCondition && bounty.workflow) {
const submissionCount = bounty._count.submissions;
const currentCondition = bounty.workflow
.triggerConditions?.[0] as WorkflowCondition;
if (
currentCondition &&
currentCondition.attribute !== performanceCondition.attribute &&
submissionCount > 0
) {
throw new DubApiError({
code: "bad_request",
message: `You cannot change the performance condition from "${PERFORMANCE_BOUNTY_SCOPE_ATTRIBUTES[currentCondition.attribute].toLowerCase()}" to "${PERFORMANCE_BOUNTY_SCOPE_ATTRIBUTES[performanceCondition.attribute].toLowerCase()}" because the bounty has submissions.`,
});
}
}
// Prevent update if `submissionRequirements.socialMetrics` differs from the current value if there are existing submissions
if (submissionRequirements) {
const submissionCount = bounty._count.submissions;
const currentSocialMetrics = bounty.submissionRequirements
? submissionRequirementsSchema.parse(bounty.submissionRequirements)
.socialMetrics ?? {}
: {};
const incomingSocialMetrics =
submissionRequirementsSchema.parse(submissionRequirements)
.socialMetrics ?? {};
if (
!deepEqual(currentSocialMetrics, incomingSocialMetrics) &&
submissionCount > 0
) {
throw new DubApiError({
code: "bad_request",
message:
"You cannot change the social metrics criteria because the bounty has submissions.",
});
}
}
// Bounty name
let bountyName = name;
if (bounty.type === "performance" && performanceCondition) {
bountyName = generatePerformanceBountyName({
rewardAmount: rewardAmount ?? 0, // this shouldn't happen since we return early if rewardAmount is null
condition: performanceCondition,
});
}
const data = await prisma.$transaction(async (tx) => {
const updatedBounty = await tx.bounty.update({
where: {
id: bounty.id,
},
data: {
name: bountyName ?? undefined,
description,
startsAt: startsAt!, // Can remove the ! when we're on a newer TS version (currently 5.4.4)
endsAt,
submissionsOpenAt:
bounty.type === "submission" ? submissionsOpenAt : null,
...(bounty.type === "submission" &&
submissionFrequency !== undefined && { submissionFrequency }),
...(bounty.type === "submission" &&
maxSubmissions !== undefined && {
maxSubmissions: maxSubmissions ?? 1,
}),
rewardAmount:
rewardAmount !== undefined ? rewardAmount : bounty.rewardAmount,
rewardDescription,
...(bounty.type === "submission" &&
submissionRequirements !== undefined && {
submissionRequirements: submissionRequirements ?? Prisma.DbNull,
}),
...(updatedPartnerGroups && {
groups: {
deleteMany: {},
create: updatedPartnerGroups.map((group) => ({
groupId: group.id,
})),
},
}),
},
include: {
workflow: true,
groups: true,
},
});
if (updatedBounty.workflowId && performanceCondition) {
await tx.workflow.update({
where: {
id: updatedBounty.workflowId,
},
data: {
triggerConditions: [performanceCondition],
},
});
}
return {
...updatedBounty,
performanceCondition,
};
});
const updatedBounty = BountySchema.parse({
...data,
groups: data.groups.map(({ groupId }) => ({ id: groupId })),
performanceCondition: data.workflow?.triggerConditions?.[0],
});
waitUntil(
Promise.allSettled([
recordAuditLog({
workspaceId: workspace.id,
programId,
action: "bounty.updated",
description: `Bounty ${bounty.id} updated`,
actor: session?.user,
targets: [
{
type: "bounty",
id: bounty.id,
metadata: updatedBounty,
},
],
}),
sendWorkspaceWebhook({
workspace,
trigger: "bounty.updated",
data: updatedBounty,
}),
]),
);
return NextResponse.json(updatedBounty);
},
{
requiredPlan: [
"business",
"business plus",
"business extra",
"business max",
"advanced",
"enterprise",
],
requiredRoles: ["owner", "member"],
},
);
// DELETE /api/bounties/[bountyId] - delete a bounty
export const DELETE = withWorkspace(
async ({ workspace, params, session }) => {
const { bountyId } = params;
const programId = getDefaultProgramIdOrThrow(workspace);
const bounty = await prisma.bounty.findUniqueOrThrow({
where: {
id: bountyId,
programId,
},
include: {
groups: true,
workflow: true,
_count: {
select: {
submissions: true,
},
},
},
});
if (bounty._count.submissions > 0) {
throw new DubApiError({
message:
"Bounties with submissions cannot be deleted. You can archive them instead.",
code: "bad_request",
});
}
await prisma.$transaction(async (tx) => {
const bounty = await tx.bounty.delete({
where: {
id: bountyId,
},
});
if (bounty.workflowId) {
await tx.workflow.delete({
where: {
id: bounty.workflowId,
},
});
}
});
const deletedBounty = BountySchema.parse({
...bounty,
groups: bounty.groups.map(({ groupId }) => ({ id: groupId })),
performanceCondition: bounty.workflow?.triggerConditions?.[0],
});
waitUntil(
recordAuditLog({
workspaceId: workspace.id,
programId,
action: "bounty.deleted",
description: `Bounty ${bountyId} deleted`,
actor: session?.user,
targets: [
{
type: "bounty",
id: bountyId,
metadata: deletedBounty,
},
],
}),
);
return NextResponse.json({ id: bountyId });
},
{
requiredPlan: [
"business",
"business plus",
"business extra",
"business max",
"advanced",
"enterprise",
],
requiredRoles: ["owner", "member"],
},
);
================================================
FILE: apps/web/app/(ee)/api/bounties/[bountyId]/submissions/[submissionId]/approve/route.ts
================================================
import { getDefaultProgramIdOrThrow } from "@/lib/api/programs/get-default-program-id-or-throw";
import { parseRequestBody } from "@/lib/api/utils";
import { withWorkspace } from "@/lib/auth";
import { approveBountySubmission } from "@/lib/bounty/api/approve-bounty-submission";
import { getBountyOrThrow } from "@/lib/bounty/api/get-bounty-or-throw";
import { approveBountySubmissionBodySchema } from "@/lib/zod/schemas/bounties";
import { NextResponse } from "next/server";
// POST /api/bounties/[bountyId]/submissions/[submissionId]/approve - approve a submission
export const POST = withWorkspace(
async ({ workspace, params, req, session }) => {
const { bountyId, submissionId } = params;
const programId = getDefaultProgramIdOrThrow(workspace);
let body;
try {
body = await parseRequestBody(req);
} catch (e) {
// If body is empty or invalid, use empty object since body is optional
body = {};
}
const { rewardAmount } = approveBountySubmissionBodySchema.parse(body);
await getBountyOrThrow({
bountyId,
programId,
});
const approvedSubmission = await approveBountySubmission({
programId,
bountyId,
submissionId,
rewardAmount,
user: session.user,
});
return NextResponse.json(approvedSubmission);
},
{
requiredPlan: ["advanced", "enterprise"],
requiredRoles: ["owner", "member"],
},
);
================================================
FILE: apps/web/app/(ee)/api/bounties/[bountyId]/submissions/[submissionId]/reject/route.ts
================================================
import { getDefaultProgramIdOrThrow } from "@/lib/api/programs/get-default-program-id-or-throw";
import { parseRequestBody } from "@/lib/api/utils";
import { withWorkspace } from "@/lib/auth";
import { getBountyOrThrow } from "@/lib/bounty/api/get-bounty-or-throw";
import { rejectBountySubmission } from "@/lib/bounty/api/reject-bounty-submission";
import { rejectBountySubmissionBodySchema } from "@/lib/zod/schemas/bounties";
import { NextResponse } from "next/server";
// POST /api/bounties/[bountyId]/submissions/[submissionId]/reject - reject a submission
export const POST = withWorkspace(
async ({ workspace, params, req, session }) => {
const { bountyId, submissionId } = params;
const programId = getDefaultProgramIdOrThrow(workspace);
let body;
try {
body = await parseRequestBody(req);
} catch (e) {
// If body is empty or invalid, use empty object since body is optional
body = {};
}
const { rejectionReason, rejectionNote } =
rejectBountySubmissionBodySchema.parse(body);
await getBountyOrThrow({
bountyId,
programId,
});
const rejectedSubmission = await rejectBountySubmission({
programId,
bountyId,
submissionId,
rejectionReason,
rejectionNote,
user: session.user,
});
return NextResponse.json(rejectedSubmission);
},
{
requiredPlan: ["advanced", "enterprise"],
requiredRoles: ["owner", "member"],
},
);
================================================
FILE: apps/web/app/(ee)/api/bounties/[bountyId]/submissions/route.ts
================================================
import { getDefaultProgramIdOrThrow } from "@/lib/api/programs/get-default-program-id-or-throw";
import { withWorkspace } from "@/lib/auth";
import { getBountyOrThrow } from "@/lib/bounty/api/get-bounty-or-throw";
import {
BountySubmissionExtendedSchema,
getBountySubmissionsQuerySchema,
} from "@/lib/zod/schemas/bounties";
import { prisma } from "@dub/prisma";
import { NextResponse } from "next/server";
// GET /api/bounties/[bountyId]/submissions - get all submissions for a bounty
export const GET = withWorkspace(
async ({ workspace, params, searchParams }) => {
const { bountyId } = params;
const programId = getDefaultProgramIdOrThrow(workspace);
await getBountyOrThrow({
bountyId,
programId,
include: {
groups: true,
},
});
const {
status,
groupId,
partnerId,
sortOrder,
sortBy,
page = 1,
pageSize,
} = getBountySubmissionsQuerySchema.parse(searchParams);
const submissions = await prisma.bountySubmission.findMany({
where: {
bountyId,
status: status ?? {
in: ["draft", "submitted", "approved"],
},
...(groupId && {
programEnrollment: {
groupId,
},
}),
...(partnerId && {
partnerId,
}),
},
include: {
user: true,
commission: true,
partner: true,
programEnrollment: true,
},
orderBy: {
[sortBy]: sortOrder,
},
skip: (page - 1) * pageSize,
take: pageSize,
});
const bountySubmissions = submissions.map(
({ partner, programEnrollment, commission, user, ...submissionData }) =>
BountySubmissionExtendedSchema.parse({
...submissionData,
partner: {
...partner,
...(programEnrollment || {}),
id: partner.id,
status: programEnrollment?.status ?? null,
},
commission,
user,
}),
);
return NextResponse.json(bountySubmissions);
},
{
requiredPlan: [
"business",
"business plus",
"business extra",
"business max",
"advanced",
"enterprise",
],
},
);
================================================
FILE: apps/web/app/(ee)/api/bounties/[bountyId]/sync-social-metrics/route.ts
================================================
import { DubApiError } from "@/lib/api/errors";
import { getDefaultProgramIdOrThrow } from "@/lib/api/programs/get-default-program-id-or-throw";
import { parseRequestBody } from "@/lib/api/utils";
import { withWorkspace } from "@/lib/auth";
import { getBountyOrThrow } from "@/lib/bounty/api/get-bounty-or-throw";
import { getSocialMetricsUpdates } from "@/lib/bounty/api/get-social-metrics-updates";
import { resolveBountyDetails } from "@/lib/bounty/utils";
import { qstash } from "@/lib/cron";
import { sendEmail } from "@dub/email";
import BountyCompleted from "@dub/email/templates/bounty-completed";
import { prisma } from "@dub/prisma";
import { Prisma } from "@dub/prisma/client";
import { APP_DOMAIN_WITH_NGROK } from "@dub/utils";
import { NextResponse } from "next/server";
import * as z from "zod/v4";
const inputSchema = z.object({
submissionId: z
.string()
.optional()
.describe(
"The ID of the submission to sync social metrics for. If not provided, all submissions will be synced.",
),
});
// POST /api/bounties/[bountyId]/sync-social-metrics - sync social metrics for a bounty
export const POST = withWorkspace(
async ({ workspace, params, req }) => {
const { bountyId } = params;
const programId = getDefaultProgramIdOrThrow(workspace);
const { submissionId } = inputSchema.parse(await parseRequestBody(req));
const bounty = await getBountyOrThrow({
bountyId,
programId,
include: submissionId
? {
program: {
select: {
name: true,
slug: true,
supportEmail: true,
},
},
submissions: {
where: {
id: submissionId,
},
select: {
id: true,
urls: true,
status: true,
partner: true,
},
},
}
: undefined,
});
const bountyInfo = resolveBountyDetails(bounty);
if (!bountyInfo?.socialMetrics) {
throw new DubApiError({
code: "bad_request",
message: "This bounty does not have social metrics requirements.",
});
}
const submission = submissionId ? bounty.submissions?.[0] : undefined;
if (submissionId) {
if (!submission) {
throw new DubApiError({
code: "not_found",
message: `Submission ${submissionId} not found.`,
});
}
if (submission.status === "approved") {
throw new DubApiError({
code: "bad_request",
message: "Social metrics can't be synced for an approved submission.",
});
}
}
const now = new Date();
if (bounty.startsAt && bounty.startsAt > now) {
throw new DubApiError({
code: "bad_request",
message: "Social metrics can only be synced after the bounty starts.",
});
}
if (bounty.endsAt && bounty.endsAt < now) {
throw new DubApiError({
code: "bad_request",
message: "Social metrics can't be synced after the bounty ends.",
});
}
// Do the sync in a background job if no submissionId is provided
if (!submissionId) {
const response = await qstash.publishJSON({
url: `${APP_DOMAIN_WITH_NGROK}/api/cron/bounties/sync-social-metrics`,
method: "POST",
body: {
bountyId,
},
});
if (!response.messageId) {
throw new DubApiError({
code: "bad_request",
message: "Could not sync social metrics for this bounty now.",
});
}
return NextResponse.json({});
}
// Otherwise, do the sync for the specific submission
const toUpdate = await getSocialMetricsUpdates({
bounty,
submissions: bounty.submissions![0],
});
if (toUpdate.length > 0) {
const update = toUpdate.find((s) => s.id === submissionId);
if (!update) {
return NextResponse.json({});
}
const { socialMetricCount, socialMetricsLastSyncedAt } = update;
const submission = bounty.submissions![0];
const updateData: Prisma.BountySubmissionUpdateInput = {
socialMetricCount,
socialMetricsLastSyncedAt,
};
const hasMetCriteria =
socialMetricCount != null &&
bountyInfo.socialMetrics?.minCount != null &&
socialMetricCount >= bountyInfo.socialMetrics.minCount;
const shouldTransitionToSubmitted =
submission.status === "draft" && hasMetCriteria;
if (shouldTransitionToSubmitted) {
updateData.status = "submitted";
updateData.completedAt = new Date();
}
await prisma.bountySubmission.update({
where: {
id: submissionId,
},
data: {
...updateData,
},
});
const { partner } = submission;
if (shouldTransitionToSubmitted && partner.email) {
await sendEmail({
subject: "Bounty completed!",
to: partner.email,
variant: "notifications",
replyTo: bounty.program.supportEmail || "noreply",
react: BountyCompleted({
email: partner.email,
bounty: {
name: bounty.name,
type: bounty.type,
},
program: {
name: bounty.program.name,
slug: bounty.program.slug,
},
}),
headers: {
"Idempotency-Key": `bounty-completed-${submissionId}`,
},
});
}
}
return NextResponse.json({});
},
{
requiredPlan: [
"business",
"business plus",
"business extra",
"business max",
"advanced",
"enterprise",
],
},
);
================================================
FILE: apps/web/app/(ee)/api/bounties/count/submissions/route.ts
================================================
import { getDefaultProgramIdOrThrow } from "@/lib/api/programs/get-default-program-id-or-throw";
import { withWorkspace } from "@/lib/auth";
import { prisma } from "@dub/prisma";
import { BountySubmissionStatus } from "@dub/prisma/client";
import { NextResponse } from "next/server";
import * as z from "zod/v4";
const bountiesSubmissionsCountQuerySchema = z.object({
bountyId: z.string().optional(),
groupId: z.string().optional(),
partnerId: z.string().optional(),
});
const statuses = Object.values(BountySubmissionStatus);
// GET /api/bounties/count/submissions – get the total bounty submissions count by status (potentially filtered by bountyId)
export const GET = withWorkspace(
async ({ workspace, searchParams }) => {
const programId = getDefaultProgramIdOrThrow(workspace);
const { bountyId, groupId, partnerId } =
bountiesSubmissionsCountQuerySchema.parse(searchParams);
const count = await prisma.bountySubmission.groupBy({
by: ["status"],
where: {
programId,
bountyId,
...(groupId && {
programEnrollment: {
groupId,
},
}),
...(partnerId && {
partnerId,
}),
},
_count: true,
});
const counts = count.map((c) => ({
status: c.status,
count: c._count,
}));
statuses.forEach((status) => {
if (!counts.some((c) => c.status === status)) {
counts.push({
status,
count: 0,
});
}
});
return NextResponse.json(counts);
},
{
requiredPlan: [
"business",
"business plus",
"business extra",
"business max",
"advanced",
"enterprise",
],
},
);
================================================
FILE: apps/web/app/(ee)/api/bounties/route.ts
================================================
import { recordAuditLog } from "@/lib/api/audit-logs/record-audit-log";
import { createId } from "@/lib/api/create-id";
import { DubApiError } from "@/lib/api/errors";
import { throwIfInvalidGroupIds } from "@/lib/api/groups/throw-if-invalid-group-ids";
import { getDefaultProgramIdOrThrow } from "@/lib/api/programs/get-default-program-id-or-throw";
import { getProgramEnrollmentOrThrow } from "@/lib/api/programs/get-program-enrollment-or-throw";
import { parseRequestBody } from "@/lib/api/utils";
import { withWorkspace } from "@/lib/auth";
import { generatePerformanceBountyName } from "@/lib/bounty/api/generate-performance-bounty-name";
import { validateBounty } from "@/lib/bounty/api/validate-bounty";
import { qstash } from "@/lib/cron";
import { getPlanCapabilities } from "@/lib/plan-capabilities";
import { WorkflowAction } from "@/lib/types";
import { sendWorkspaceWebhook } from "@/lib/webhook/publish";
import {
BountyListSchema,
BountySchema,
createBountySchema,
getBountiesQuerySchema,
} from "@/lib/zod/schemas/bounties";
import {
WORKFLOW_ACTION_TYPES,
WORKFLOW_ATTRIBUTE_TRIGGER,
} from "@/lib/zod/schemas/workflows";
import { prisma } from "@dub/prisma";
import { Workflow } from "@dub/prisma/client";
import { APP_DOMAIN_WITH_NGROK } from "@dub/utils";
import { waitUntil } from "@vercel/functions";
import { NextResponse } from "next/server";
// GET /api/bounties - get all bounties for a program
export const GET = withWorkspace(
async ({ workspace, searchParams }) => {
const programId = getDefaultProgramIdOrThrow(workspace);
const { partnerId, includeSubmissionsCount } =
getBountiesQuerySchema.parse(searchParams);
const programEnrollment = partnerId
? await getProgramEnrollmentOrThrow({
partnerId,
programId,
include: {
program: true,
},
})
: null;
const [bounties, allBountiesSubmissionsCount] = await Promise.all([
prisma.bounty.findMany({
where: {
programId,
// Filter only bounties the specified partner is eligible for
...(programEnrollment && {
AND: [
// Filter out expired bounties
{
OR: [{ endsAt: null }, { endsAt: { gt: new Date() } }],
},
// Filter by partner's group eligibility
{
OR: [
{
groups: {
none: {},
},
},
{
groups: {
some: {
groupId:
programEnrollment.groupId ||
programEnrollment.program.defaultGroupId,
},
},
},
],
},
],
}),
},
include: {
groups: {
select: {
groupId: true,
},
},
},
}),
includeSubmissionsCount
? prisma.bountySubmission.groupBy({
by: ["bountyId", "status"],
where: {
programId,
status: {
in: ["submitted", "approved"],
},
},
_count: {
status: true,
},
})
: null,
]);
const aggregateSubmissionsCountForBounty = (bountyId: string) => {
if (!allBountiesSubmissionsCount) {
return null;
}
const bountySubmissions = allBountiesSubmissionsCount.filter(
(s) => s.bountyId === bountyId,
);
const total = bountySubmissions.reduce(
(sum, s) => sum + s._count.status,
0,
);
const submitted =
bountySubmissions.find((s) => s.status === "submitted")?._count
.status ?? 0;
const approved =
bountySubmissions.find((s) => s.status === "approved")?._count.status ??
0;
return {
total,
submitted,
approved,
};
};
const data = bounties.map((bounty) => {
return BountyListSchema.parse({
...bounty,
groups: bounty.groups.map(({ groupId }) => ({ id: groupId })),
...(allBountiesSubmissionsCount && {
submissionsCountData: aggregateSubmissionsCountForBounty(bounty.id),
}),
});
});
return NextResponse.json(data);
},
{
requiredPlan: [
"business",
"business plus",
"business extra",
"business max",
"advanced",
"enterprise",
],
},
);
// POST /api/bounties - create a bounty
export const POST = withWorkspace(
async ({ workspace, req, session }) => {
const programId = getDefaultProgramIdOrThrow(workspace);
const parsedBody = createBountySchema.parse(await parseRequestBody(req));
let {
name,
description,
type,
rewardAmount,
rewardDescription,
startsAt,
endsAt,
submissionsOpenAt,
submissionFrequency,
maxSubmissions,
submissionRequirements,
groupIds,
performanceCondition,
performanceScope,
sendNotificationEmails,
} = parsedBody;
// Use current date as default if startsAt is not provided
startsAt = startsAt || new Date();
validateBounty(parsedBody);
const { canUseBountySocialMetrics, canSendEmailCampaigns } =
getPlanCapabilities(workspace.plan);
if (submissionRequirements?.socialMetrics && !canUseBountySocialMetrics) {
throw new DubApiError({
code: "forbidden",
message: "Social metrics criteria require Advanced plan or above.",
});
}
const partnerGroups = await throwIfInvalidGroupIds({
programId,
groupIds,
});
// Bounty name
let bountyName = name;
if (type === "performance" && performanceCondition) {
bountyName = generatePerformanceBountyName({
rewardAmount: rewardAmount ?? 0, // this shouldn't happen since we return early if rewardAmount is null
condition: performanceCondition,
});
}
if (!bountyName) {
throw new DubApiError({
code: "bad_request",
message: "Bounty name is required.",
});
}
const bounty = await prisma.$transaction(async (tx) => {
let workflow: Workflow | null = null;
const bountyId = createId({ prefix: "bnty_" });
// Create a workflow if there is a performance condition
if (performanceCondition && type === "performance") {
const action: WorkflowAction = {
type: WORKFLOW_ACTION_TYPES.AwardBounty,
data: {
bountyId,
},
};
workflow = await tx.workflow.create({
data: {
id: createId({ prefix: "wf_" }),
programId,
trigger: WORKFLOW_ATTRIBUTE_TRIGGER[performanceCondition.attribute],
triggerConditions: [performanceCondition],
actions: [action],
},
});
}
// Create a bounty
return await tx.bounty.create({
data: {
id: bountyId,
programId,
workflowId: workflow?.id,
name: bountyName,
description,
type,
startsAt,
endsAt,
submissionsOpenAt: type === "submission" ? submissionsOpenAt : null,
submissionFrequency:
type === "submission" ? submissionFrequency : null,
maxSubmissions: type === "submission" ? maxSubmissions ?? 1 : 1,
rewardAmount,
rewardDescription,
performanceScope: type === "performance" ? performanceScope : null,
...(submissionRequirements &&
type === "submission" && {
submissionRequirements,
}),
...(partnerGroups.length && {
groups: {
createMany: {
data: partnerGroups.map(({ id }) => ({
groupId: id,
})),
},
},
}),
},
include: {
workflow: true,
groups: true,
},
});
});
const createdBounty = BountySchema.parse({
...bounty,
groups: bounty.groups.map(({ groupId }) => ({ id: groupId })),
performanceCondition: bounty.workflow?.triggerConditions?.[0],
});
const shouldScheduleDraftSubmissions =
bounty.type === "performance" && bounty.performanceScope === "lifetime";
waitUntil(
Promise.allSettled([
recordAuditLog({
workspaceId: workspace.id,
programId,
action: "bounty.created",
description: `Bounty ${bounty.id} created`,
actor: session?.user,
targets: [
{
type: "bounty",
id: bounty.id,
metadata: createdBounty,
},
],
}),
sendWorkspaceWebhook({
workspace,
trigger: "bounty.created",
data: createdBounty,
}),
sendNotificationEmails &&
canSendEmailCampaigns &&
qstash.publishJSON({
url: `${APP_DOMAIN_WITH_NGROK}/api/cron/bounties/notify-partners`,
body: {
bountyId: bounty.id,
},
notBef
Showing preview only (214K chars total). Download the full file or copy to clipboard to get everything.
gitextract_j4v7jeo4/ ├── .github/ │ └── workflows/ │ ├── apply-issue-labels-to-pr.yml │ ├── deploy-embed-script.yml │ ├── e2e.yaml │ ├── playwright.yaml │ └── prettier.yaml ├── .gitignore ├── .prettierignore ├── LICENSE.md ├── README.md ├── SECURITY.md ├── apps/ │ └── web/ │ ├── app/ │ │ ├── (ee)/ │ │ │ ├── LICENSE.md │ │ │ ├── README.md │ │ │ ├── admin.dub.co/ │ │ │ │ ├── (auth)/ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ └── login/ │ │ │ │ │ └── page.tsx │ │ │ │ ├── (dashboard)/ │ │ │ │ │ ├── analytics/ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── commissions/ │ │ │ │ │ │ ├── client.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── ban-link.tsx │ │ │ │ │ │ ├── delete-partner-account.tsx │ │ │ │ │ │ ├── impersonate-user.tsx │ │ │ │ │ │ ├── impersonate-workspace.tsx │ │ │ │ │ │ ├── refresh-domain.tsx │ │ │ │ │ │ ├── reset-login-attempts.tsx │ │ │ │ │ │ └── user-info.tsx │ │ │ │ │ ├── events/ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── layout-nav-client.tsx │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── links/ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── page.tsx │ │ │ │ │ ├── payouts/ │ │ │ │ │ │ ├── client.tsx │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ └── paypal/ │ │ │ │ │ │ ├── client.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── revenue/ │ │ │ │ │ ├── client.tsx │ │ │ │ │ └── page.tsx │ │ │ │ └── layout.tsx │ │ │ ├── api/ │ │ │ │ ├── admin/ │ │ │ │ │ ├── analytics/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── ban/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── commissions/ │ │ │ │ │ │ ├── get-commissions-timeseries.ts │ │ │ │ │ │ ├── get-top-program-by-commissions.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── delete-partner-account/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── events/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── impersonate/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── links/ │ │ │ │ │ │ ├── [linkId]/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── ban/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── count/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── payouts/ │ │ │ │ │ │ ├── paypal/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── refresh-domain/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── reset-login-attempts/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── revenue/ │ │ │ │ │ ├── get-top-programs-by-sales.ts │ │ │ │ │ └── route.ts │ │ │ │ ├── audit-logs/ │ │ │ │ │ └── export/ │ │ │ │ │ └── route.ts │ │ │ │ ├── auth/ │ │ │ │ │ └── saml/ │ │ │ │ │ ├── authorize/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── callback/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── token/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── userinfo/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── verify/ │ │ │ │ │ └── route.tsx │ │ │ │ ├── bounties/ │ │ │ │ │ ├── [bountyId]/ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ ├── submissions/ │ │ │ │ │ │ │ ├── [submissionId]/ │ │ │ │ │ │ │ │ ├── approve/ │ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ │ └── reject/ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── sync-social-metrics/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── count/ │ │ │ │ │ │ └── submissions/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ ├── campaigns/ │ │ │ │ │ ├── [campaignId]/ │ │ │ │ │ │ ├── duplicate/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── events/ │ │ │ │ │ │ │ ├── count/ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── preview/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ └── summary/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── count/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ ├── commissions/ │ │ │ │ │ ├── [commissionId]/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── count/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── export/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── route.ts │ │ │ │ │ └── timeseries/ │ │ │ │ │ └── route.ts │ │ │ │ ├── cron/ │ │ │ │ │ ├── aggregate-clicks/ │ │ │ │ │ │ ├── resolve-click-reward-amount.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── bounties/ │ │ │ │ │ │ ├── create-draft-submissions/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── notify-partners/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── queue-sync-social-metrics/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── sync-social-metrics/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── campaigns/ │ │ │ │ │ │ └── broadcast/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── cleanup/ │ │ │ │ │ │ ├── demo-embed-partners/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── e2e-tests/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── expired-tokens/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── link-retention/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── rejected-applications/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── unenrolled-partners/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── discount-codes/ │ │ │ │ │ │ ├── create/ │ │ │ │ │ │ │ ├── queue-batches/ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── delete/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── disposable-emails/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── domains/ │ │ │ │ │ │ ├── delete/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── renewal-payments/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── renewal-reminders/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── transfer/ │ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ ├── update/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── verify/ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── email-domains/ │ │ │ │ │ │ ├── update/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── verify/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── export/ │ │ │ │ │ │ ├── commissions/ │ │ │ │ │ │ │ ├── fetch-commissions-batch.ts │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── customers/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── events/ │ │ │ │ │ │ │ ├── fetch-events-batch.ts │ │ │ │ │ │ │ ├── partner/ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ └── workspace/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── links/ │ │ │ │ │ │ │ ├── fetch-links-batch.ts │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── partners/ │ │ │ │ │ │ ├── fetch-partners-batch.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── folders/ │ │ │ │ │ │ └── delete/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── framer/ │ │ │ │ │ │ └── backfill-leads-batch/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── fraud/ │ │ │ │ │ │ └── summary/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── fx-rates/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── groups/ │ │ │ │ │ │ ├── create-default-links/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── remap-default-links/ │ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ ├── remap-discount-codes/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── sync-utm/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── update-default-links/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── import/ │ │ │ │ │ │ ├── bitly/ │ │ │ │ │ │ │ ├── fetch-utils.ts │ │ │ │ │ │ │ ├── queue-import.ts │ │ │ │ │ │ │ ├── rate-limit.ts │ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ │ ├── sanitize-json.ts │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ ├── csv/ │ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ ├── firstpromoter/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── partnerstack/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── rebrandly/ │ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ ├── rewardful/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── short/ │ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ └── tolt/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── invoices/ │ │ │ │ │ │ └── retry-failed/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── links/ │ │ │ │ │ │ ├── [linkId]/ │ │ │ │ │ │ │ └── complete-tests/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── delete/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── invalidate-for-discounts/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── invalidate-for-partners/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── messages/ │ │ │ │ │ │ ├── notify-partner/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── notify-program/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── network/ │ │ │ │ │ │ ├── calculate-program-similarities/ │ │ │ │ │ │ │ ├── calculate-category-similarity.ts │ │ │ │ │ │ │ ├── calculate-partner-similarity.ts │ │ │ │ │ │ │ ├── calculate-performance-similarity.ts │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── update-partner-discoverability/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── partner-platforms/ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ └── youtube/ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ └── youtube-channel-schema.ts │ │ │ │ │ ├── partner-program-summary/ │ │ │ │ │ │ ├── process/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── partners/ │ │ │ │ │ │ ├── auto-approve/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── auto-reject/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── ban/ │ │ │ │ │ │ │ ├── cancel-commissions.ts │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── deactivate/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── merge-accounts/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── payouts/ │ │ │ │ │ │ ├── aggregate-due-commissions/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── balance-available/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── charge-succeeded/ │ │ │ │ │ │ │ ├── queue-external-payouts.ts │ │ │ │ │ │ │ ├── queue-stripe-payouts.ts │ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ │ ├── send-paypal-payouts.ts │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ ├── force-withdrawals/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── payout-failed/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── payout-paid/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── process/ │ │ │ │ │ │ │ ├── process-payouts.ts │ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ │ ├── split-payouts.ts │ │ │ │ │ │ │ └── updates/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── reminders/ │ │ │ │ │ │ │ ├── partners/ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ └── program-owners/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── send-stripe-payout/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── pending-applications-summary/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── program-application-reminder/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── programs/ │ │ │ │ │ │ └── deactivate/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── send-batch-email/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── shopify/ │ │ │ │ │ │ └── order-paid/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── streams/ │ │ │ │ │ │ ├── update-partner-stats/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── update-workspace-clicks/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── trigger-withdrawal/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── usage/ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── utils.ts │ │ │ │ │ ├── welcome-user/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── workflows/ │ │ │ │ │ │ └── [workflowId]/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── workspaces/ │ │ │ │ │ └── delete/ │ │ │ │ │ ├── delete-workspace-customers.ts │ │ │ │ │ ├── delete-workspace-domains.ts │ │ │ │ │ ├── delete-workspace-folders.ts │ │ │ │ │ ├── delete-workspace-links.ts │ │ │ │ │ ├── delete-workspace.ts │ │ │ │ │ ├── route.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── customers/ │ │ │ │ │ ├── [id]/ │ │ │ │ │ │ ├── activity/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ └── stripe-invoices/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── count/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── export/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── route.ts │ │ │ │ │ └── search-stripe/ │ │ │ │ │ └── route.ts │ │ │ │ ├── discount-codes/ │ │ │ │ │ ├── [discountCodeId]/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ ├── domains/ │ │ │ │ │ ├── register/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── status/ │ │ │ │ │ └── route.ts │ │ │ │ ├── e2e/ │ │ │ │ │ ├── bounties/ │ │ │ │ │ │ └── [bountyId]/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── enrollments/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── guard.ts │ │ │ │ │ ├── notification-emails/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── trigger-workflow/ │ │ │ │ │ │ └── [workflowId]/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── workflows/ │ │ │ │ │ ├── [workflowId]/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ ├── email-domains/ │ │ │ │ │ ├── [domain]/ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ └── verify/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ ├── embed/ │ │ │ │ │ └── referrals/ │ │ │ │ │ ├── analytics/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── earnings/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── leaderboard/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── links/ │ │ │ │ │ │ ├── [linkId]/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── token/ │ │ │ │ │ └── route.ts │ │ │ │ ├── events/ │ │ │ │ │ ├── export/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ ├── fraud/ │ │ │ │ │ ├── events/ │ │ │ │ │ │ ├── count/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── groups/ │ │ │ │ │ │ ├── count/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── rules/ │ │ │ │ │ └── route.ts │ │ │ │ ├── groups/ │ │ │ │ │ ├── [groupIdOrSlug]/ │ │ │ │ │ │ ├── default/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── default-links/ │ │ │ │ │ │ │ ├── [defaultLinkId]/ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── partners/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── count/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── route.ts │ │ │ │ │ └── rules/ │ │ │ │ │ └── route.ts │ │ │ │ ├── hubspot/ │ │ │ │ │ ├── callback/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── webhook/ │ │ │ │ │ └── route.ts │ │ │ │ ├── messages/ │ │ │ │ │ ├── count/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ ├── mock/ │ │ │ │ │ └── rewardful/ │ │ │ │ │ ├── affiliates/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── campaigns/ │ │ │ │ │ │ ├── [campaignId]/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── campaigns.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── commissions/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── referrals/ │ │ │ │ │ └── route.ts │ │ │ │ ├── network/ │ │ │ │ │ ├── partners/ │ │ │ │ │ │ ├── count/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── invites-usage/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── programs/ │ │ │ │ │ ├── count/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ ├── partner-profile/ │ │ │ │ │ ├── invites/ │ │ │ │ │ │ ├── accept/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── messages/ │ │ │ │ │ │ ├── count/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── notification-preferences/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── payouts/ │ │ │ │ │ │ ├── count/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ └── settings/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── postbacks/ │ │ │ │ │ │ ├── [postbackId]/ │ │ │ │ │ │ │ ├── events/ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ ├── rotate-secret/ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ │ └── send-test/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── programs/ │ │ │ │ │ │ ├── [programId]/ │ │ │ │ │ │ │ ├── activity-logs/ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ ├── analytics/ │ │ │ │ │ │ │ │ ├── export/ │ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ ├── bounties/ │ │ │ │ │ │ │ │ ├── [bountyId]/ │ │ │ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ │ │ │ └── social-content-stats/ │ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ ├── customers/ │ │ │ │ │ │ │ │ ├── [customerId]/ │ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ │ ├── count/ │ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ ├── earnings/ │ │ │ │ │ │ │ │ ├── count/ │ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ │ │ └── timeseries/ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ ├── events/ │ │ │ │ │ │ │ │ ├── export/ │ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ ├── groups/ │ │ │ │ │ │ │ │ └── [groupIdOrSlug]/ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ ├── links/ │ │ │ │ │ │ │ │ ├── [linkId]/ │ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ ├── referrals/ │ │ │ │ │ │ │ │ ├── count/ │ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ ├── resources/ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── count/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── rewind/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── route.ts │ │ │ │ │ └── users/ │ │ │ │ │ └── route.ts │ │ │ │ ├── partners/ │ │ │ │ │ ├── [partnerId]/ │ │ │ │ │ │ ├── application-risks/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── comments/ │ │ │ │ │ │ │ ├── count/ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── cross-program-summary/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── analytics/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── ban/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── count/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── deactivate/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── export/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── links/ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ └── upsert/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── platforms/ │ │ │ │ │ │ └── callback/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ ├── payouts/ │ │ │ │ │ ├── [payoutId]/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── count/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ ├── paypal/ │ │ │ │ │ ├── callback/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── webhook/ │ │ │ │ │ ├── payouts-item-failed.ts │ │ │ │ │ ├── payouts-item-succeeded.ts │ │ │ │ │ ├── route.ts │ │ │ │ │ ├── utils.ts │ │ │ │ │ └── verify-signature.ts │ │ │ │ ├── programs/ │ │ │ │ │ ├── [programId]/ │ │ │ │ │ │ ├── applications/ │ │ │ │ │ │ │ ├── [applicationId]/ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ └── export/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── discounts/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── payouts/ │ │ │ │ │ │ │ └── eligible/ │ │ │ │ │ │ │ ├── count/ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── referrals/ │ │ │ │ │ │ │ ├── count/ │ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── resources/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── rewardful/ │ │ │ │ │ └── campaigns/ │ │ │ │ │ └── route.ts │ │ │ │ ├── rewards/ │ │ │ │ │ ├── [rewardId]/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ ├── scim/ │ │ │ │ │ └── v2.0/ │ │ │ │ │ └── [...directory]/ │ │ │ │ │ └── route.ts │ │ │ │ ├── shopify/ │ │ │ │ │ ├── integration/ │ │ │ │ │ │ ├── callback/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── webhook/ │ │ │ │ │ │ ├── app-uninstalled.ts │ │ │ │ │ │ ├── customers-data-request.ts │ │ │ │ │ │ ├── customers-redact.ts │ │ │ │ │ │ ├── orders-paid.ts │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ └── shop-redact.ts │ │ │ │ │ └── pixel/ │ │ │ │ │ └── route.ts │ │ │ │ ├── singular/ │ │ │ │ │ └── webhook/ │ │ │ │ │ └── route.ts │ │ │ │ ├── stripe/ │ │ │ │ │ ├── connect/ │ │ │ │ │ │ ├── v2/ │ │ │ │ │ │ │ └── webhook/ │ │ │ │ │ │ │ ├── outbound-payment-failed.ts │ │ │ │ │ │ │ ├── outbound-payment-posted.ts │ │ │ │ │ │ │ ├── outbound-payment-returned.ts │ │ │ │ │ │ │ ├── recipient-account-closed.ts │ │ │ │ │ │ │ ├── recipient-configuration-updated.ts │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── webhook/ │ │ │ │ │ │ ├── account-application-deauthorized.ts │ │ │ │ │ │ ├── account-updated.ts │ │ │ │ │ │ ├── balance-available.ts │ │ │ │ │ │ ├── payout-failed.ts │ │ │ │ │ │ ├── payout-paid.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── integration/ │ │ │ │ │ │ ├── callback/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ └── webhook/ │ │ │ │ │ │ ├── account-application-deauthorized.ts │ │ │ │ │ │ ├── charge-refunded.ts │ │ │ │ │ │ ├── checkout-session-completed.ts │ │ │ │ │ │ ├── coupon-deleted.ts │ │ │ │ │ │ ├── customer-created.ts │ │ │ │ │ │ ├── customer-subscription-created.ts │ │ │ │ │ │ ├── customer-subscription-deleted.ts │ │ │ │ │ │ ├── customer-updated.ts │ │ │ │ │ │ ├── invoice-paid.ts │ │ │ │ │ │ ├── promotion-code-updated.ts │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ ├── sandbox/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── test/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── utils/ │ │ │ │ │ │ ├── create-new-customer.ts │ │ │ │ │ │ ├── get-connected-customer.ts │ │ │ │ │ │ ├── get-promotion-code.ts │ │ │ │ │ │ ├── get-subscription-product-id.ts │ │ │ │ │ │ └── update-customer-with-stripe-customer-id.ts │ │ │ │ │ └── webhook/ │ │ │ │ │ ├── charge-failed.ts │ │ │ │ │ ├── charge-refunded.ts │ │ │ │ │ ├── charge-succeeded.ts │ │ │ │ │ ├── checkout-session-completed.ts │ │ │ │ │ ├── customer-subscription-deleted.ts │ │ │ │ │ ├── customer-subscription-updated.ts │ │ │ │ │ ├── invoice-payment-failed.tsx │ │ │ │ │ ├── payment-intent-requires-action.ts │ │ │ │ │ ├── route.ts │ │ │ │ │ ├── transfer-reversed.ts │ │ │ │ │ └── utils/ │ │ │ │ │ ├── process-domain-renewal-failure.ts │ │ │ │ │ ├── process-payout-invoice-failure.ts │ │ │ │ │ ├── send-cancellation-feedback.ts │ │ │ │ │ └── update-workspace-plan.ts │ │ │ │ ├── track/ │ │ │ │ │ ├── click/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── lead/ │ │ │ │ │ │ ├── client/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── open/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── sale/ │ │ │ │ │ │ ├── client/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── visit/ │ │ │ │ │ └── route.ts │ │ │ │ └── workflows/ │ │ │ │ └── partner-approved/ │ │ │ │ └── route.ts │ │ │ ├── app.dub.co/ │ │ │ │ ├── (new-program)/ │ │ │ │ │ ├── [slug]/ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ └── program/ │ │ │ │ │ │ └── new/ │ │ │ │ │ │ ├── form.tsx │ │ │ │ │ │ ├── overview/ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ ├── partners/ │ │ │ │ │ │ │ ├── form.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── rewards/ │ │ │ │ │ │ │ ├── form.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── step-page.tsx │ │ │ │ │ │ └── support/ │ │ │ │ │ │ ├── form.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── header.tsx │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── sidebar-context.tsx │ │ │ │ │ └── steps.tsx │ │ │ │ ├── embed/ │ │ │ │ │ ├── referrals/ │ │ │ │ │ │ ├── activity.tsx │ │ │ │ │ │ ├── add-edit-link.tsx │ │ │ │ │ │ ├── dynamic-height-messenger.tsx │ │ │ │ │ │ ├── earnings-summary.tsx │ │ │ │ │ │ ├── earnings.tsx │ │ │ │ │ │ ├── faq.tsx │ │ │ │ │ │ ├── leaderboard.tsx │ │ │ │ │ │ ├── links-list.tsx │ │ │ │ │ │ ├── links.tsx │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ ├── quickstart.tsx │ │ │ │ │ │ ├── resources.tsx │ │ │ │ │ │ ├── theme-options.ts │ │ │ │ │ │ ├── token.tsx │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ └── use-embed-token.ts │ │ │ │ ├── invoices/ │ │ │ │ │ └── [invoiceId]/ │ │ │ │ │ ├── domain-renewal-invoice.tsx │ │ │ │ │ ├── partner-payout-invoice.tsx │ │ │ │ │ └── route.tsx │ │ │ │ └── layout.tsx │ │ │ └── partners.dub.co/ │ │ │ ├── (apply)/ │ │ │ │ └── [programSlug]/ │ │ │ │ ├── (default)/ │ │ │ │ │ ├── apply/ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ └── success/ │ │ │ │ │ │ ├── cta-buttons.tsx │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ ├── pixel-conversion.tsx │ │ │ │ │ │ └── screenshot.tsx │ │ │ │ │ ├── apply-button.tsx │ │ │ │ │ ├── header.tsx │ │ │ │ │ ├── layout.tsx │ │ │ │ │ └── page.tsx │ │ │ │ └── (group-level)/ │ │ │ │ └── [groupSlug]/ │ │ │ │ ├── apply/ │ │ │ │ │ ├── page.tsx │ │ │ │ │ └── success/ │ │ │ │ │ └── page.tsx │ │ │ │ ├── layout.tsx │ │ │ │ └── page.tsx │ │ │ ├── (auth-login-register)/ │ │ │ │ ├── (generic)/ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── login/ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── register/ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ └── page.tsx │ │ │ │ ├── (program)/ │ │ │ │ │ └── [programSlug]/ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── login/ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── register/ │ │ │ │ │ └── page.tsx │ │ │ │ ├── partner-banner.tsx │ │ │ │ ├── program-logos.tsx │ │ │ │ └── side-panel.tsx │ │ │ ├── (auth-other)/ │ │ │ │ ├── auth/ │ │ │ │ │ ├── confirm-email-change/ │ │ │ │ │ │ └── [token]/ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── reset-password/ │ │ │ │ │ └── [token]/ │ │ │ │ │ └── page.tsx │ │ │ │ ├── forgot-password/ │ │ │ │ │ └── page.tsx │ │ │ │ ├── invite/ │ │ │ │ │ └── page.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── logo.tsx │ │ │ │ └── unsubscribe/ │ │ │ │ └── [token]/ │ │ │ │ └── page.tsx │ │ │ ├── (dashboard)/ │ │ │ │ ├── account/ │ │ │ │ │ └── settings/ │ │ │ │ │ ├── page.tsx │ │ │ │ │ └── security/ │ │ │ │ │ └── page.tsx │ │ │ │ ├── auth.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── messages/ │ │ │ │ │ ├── [programSlug]/ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ └── page.tsx │ │ │ │ ├── payouts/ │ │ │ │ │ ├── page.tsx │ │ │ │ │ ├── partner-payout-details-sheet.tsx │ │ │ │ │ ├── partner-payout-settings-button.tsx │ │ │ │ │ ├── partner-payout-settings-sheet.tsx │ │ │ │ │ ├── payout-stats.tsx │ │ │ │ │ ├── payout-table.tsx │ │ │ │ │ └── use-payout-filters.tsx │ │ │ │ ├── profile/ │ │ │ │ │ ├── about-you-form.tsx │ │ │ │ │ ├── how-you-work-form.tsx │ │ │ │ │ ├── industry-interests-modal.tsx │ │ │ │ │ ├── members/ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── notifications/ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ ├── page.tsx │ │ │ │ │ ├── postbacks/ │ │ │ │ │ │ ├── [id]/ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── add-postback-button.tsx │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── profile-details-form.tsx │ │ │ │ │ ├── profile-discovery-guide.tsx │ │ │ │ │ ├── settings-row.tsx │ │ │ │ │ └── use-partner-discovery-requirements.ts │ │ │ │ ├── programs/ │ │ │ │ │ ├── [programSlug]/ │ │ │ │ │ │ ├── (enrolled)/ │ │ │ │ │ │ │ ├── analytics/ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── auth.tsx │ │ │ │ │ │ │ ├── bounties/ │ │ │ │ │ │ │ │ ├── [bountyId]/ │ │ │ │ │ │ │ │ │ ├── bounty-performance-section.tsx │ │ │ │ │ │ │ │ │ ├── bounty-submissions-table.tsx │ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ ├── bounty-card.tsx │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── customers/ │ │ │ │ │ │ │ │ ├── (index)/ │ │ │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ │ │ ├── referrals/ │ │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ │ └── use-partner-customer-filters.tsx │ │ │ │ │ │ │ │ └── [customerId]/ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── earnings/ │ │ │ │ │ │ │ │ ├── earnings-composite-chart.tsx │ │ │ │ │ │ │ │ ├── earnings-table.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── events/ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── hide-program-details-button.tsx │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ ├── links/ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ │ ├── partner-link-card.tsx │ │ │ │ │ │ │ │ └── partner-link-controls.tsx │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ ├── payouts-card.tsx │ │ │ │ │ │ │ ├── resources/ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── share-earnings-modal.tsx │ │ │ │ │ │ │ └── unapproved-program-page.tsx │ │ │ │ │ │ ├── apply/ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ └── program-sidebar.tsx │ │ │ │ │ │ └── invite/ │ │ │ │ │ │ ├── accept-program-invite-button.tsx │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ └── program-invite-confetti.tsx │ │ │ │ │ ├── invitations/ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── marketplace/ │ │ │ │ │ │ ├── [programSlug]/ │ │ │ │ │ │ │ ├── header-controls.tsx │ │ │ │ │ │ │ ├── loading.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── featured-program-card.tsx │ │ │ │ │ │ ├── featured-programs.tsx │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ ├── marketplace-empty-state.tsx │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ ├── program-card.tsx │ │ │ │ │ │ ├── program-sort.tsx │ │ │ │ │ │ ├── program-status-badge.tsx │ │ │ │ │ │ └── use-program-network-filters.tsx │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ └── page.tsx │ │ │ │ └── rewind/ │ │ │ │ └── 2025/ │ │ │ │ ├── conclusion.tsx │ │ │ │ ├── intro.tsx │ │ │ │ ├── page-client.tsx │ │ │ │ ├── page.tsx │ │ │ │ ├── rewind.tsx │ │ │ │ └── share-rewind-modal.tsx │ │ │ ├── (onboarding)/ │ │ │ │ ├── layout.tsx │ │ │ │ └── onboarding/ │ │ │ │ ├── onboarding-form.tsx │ │ │ │ ├── page.tsx │ │ │ │ ├── payouts/ │ │ │ │ │ ├── page.tsx │ │ │ │ │ └── payout-provider.tsx │ │ │ │ └── platforms/ │ │ │ │ ├── page-client.tsx │ │ │ │ └── page.tsx │ │ │ ├── (redirects)/ │ │ │ │ └── apply/ │ │ │ │ └── [programSlug]/ │ │ │ │ └── [[...slug]]/ │ │ │ │ └── page.tsx │ │ │ ├── invoices/ │ │ │ │ └── [payoutId]/ │ │ │ │ └── route.tsx │ │ │ └── layout.tsx │ │ ├── [domain]/ │ │ │ ├── browser-graphic.tsx │ │ │ ├── layout.tsx │ │ │ ├── not-found/ │ │ │ │ └── page.tsx │ │ │ ├── page.tsx │ │ │ ├── placeholder.tsx │ │ │ └── stats/ │ │ │ └── [key]/ │ │ │ └── page.tsx │ │ ├── api/ │ │ │ ├── (old)/ │ │ │ │ └── projects/ │ │ │ │ ├── [slug]/ │ │ │ │ │ ├── domains/ │ │ │ │ │ │ ├── [domain]/ │ │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ │ └── verify/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── default/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── links/ │ │ │ │ │ │ ├── [linkId]/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── bulk/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── count/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── info/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── random/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── route.ts │ │ │ │ │ └── tags/ │ │ │ │ │ ├── [id]/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ ├── activity-logs/ │ │ │ │ └── route.ts │ │ │ ├── ai/ │ │ │ │ ├── completion/ │ │ │ │ │ └── route.ts │ │ │ │ ├── support-chat/ │ │ │ │ │ ├── route.ts │ │ │ │ │ └── upload/ │ │ │ │ │ └── route.ts │ │ │ │ └── sync-embeddings/ │ │ │ │ ├── fetch-plausible-pageviews.ts │ │ │ │ └── route.ts │ │ │ ├── analytics/ │ │ │ │ ├── [eventType]/ │ │ │ │ │ ├── [endpoint]/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ ├── dashboard/ │ │ │ │ │ └── route.ts │ │ │ │ ├── export/ │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ ├── auth/ │ │ │ │ ├── [...nextauth]/ │ │ │ │ │ └── route.tsx │ │ │ │ └── reset-password/ │ │ │ │ └── route.ts │ │ │ ├── callback/ │ │ │ │ ├── bitly/ │ │ │ │ │ └── route.ts │ │ │ │ ├── plain/ │ │ │ │ │ ├── partner/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── utils.ts │ │ │ │ │ └── workspace/ │ │ │ │ │ └── route.ts │ │ │ │ └── stripe/ │ │ │ │ └── route.ts │ │ │ ├── dashboards/ │ │ │ │ ├── [id]/ │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ ├── docs/ │ │ │ │ └── guides/ │ │ │ │ └── [guide]/ │ │ │ │ └── route.ts │ │ │ ├── domains/ │ │ │ │ ├── [domain]/ │ │ │ │ │ ├── primary/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── route.ts │ │ │ │ │ ├── transfer/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── validate/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── verify/ │ │ │ │ │ └── route.ts │ │ │ │ ├── client/ │ │ │ │ │ ├── register/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── saved/ │ │ │ │ │ └── route.ts │ │ │ │ ├── count/ │ │ │ │ │ └── route.ts │ │ │ │ ├── default/ │ │ │ │ │ └── route.ts │ │ │ │ ├── route.ts │ │ │ │ └── search-availability/ │ │ │ │ └── route.ts │ │ │ ├── dub/ │ │ │ │ └── webhook/ │ │ │ │ ├── lead-created.ts │ │ │ │ ├── route.ts │ │ │ │ └── sale-created.ts │ │ │ ├── folders/ │ │ │ │ ├── [folderId]/ │ │ │ │ │ ├── dashboard/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── route.ts │ │ │ │ │ └── users/ │ │ │ │ │ └── route.ts │ │ │ │ ├── access-requests/ │ │ │ │ │ └── route.ts │ │ │ │ ├── count/ │ │ │ │ │ └── route.ts │ │ │ │ ├── permissions/ │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ ├── integrations/ │ │ │ │ ├── route.ts │ │ │ │ └── uninstall/ │ │ │ │ └── route.ts │ │ │ ├── links/ │ │ │ │ ├── [linkId]/ │ │ │ │ │ ├── dashboard/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── route.ts │ │ │ │ │ └── transfer/ │ │ │ │ │ └── route.ts │ │ │ │ ├── bulk/ │ │ │ │ │ └── route.ts │ │ │ │ ├── count/ │ │ │ │ │ └── route.ts │ │ │ │ ├── exists/ │ │ │ │ │ └── route.ts │ │ │ │ ├── export/ │ │ │ │ │ └── route.ts │ │ │ │ ├── iframeable/ │ │ │ │ │ └── route.ts │ │ │ │ ├── info/ │ │ │ │ │ └── route.ts │ │ │ │ ├── metatags/ │ │ │ │ │ ├── route.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── random/ │ │ │ │ │ └── route.ts │ │ │ │ ├── route.ts │ │ │ │ ├── sync/ │ │ │ │ │ └── route.ts │ │ │ │ └── upsert/ │ │ │ │ └── route.ts │ │ │ ├── me/ │ │ │ │ └── route.ts │ │ │ ├── misc/ │ │ │ │ ├── check-favicon/ │ │ │ │ │ └── route.ts │ │ │ │ └── check-workspace-slug/ │ │ │ │ └── route.ts │ │ │ ├── oauth/ │ │ │ │ ├── apps/ │ │ │ │ │ ├── [appId]/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ ├── authorize/ │ │ │ │ │ └── route.ts │ │ │ │ ├── token/ │ │ │ │ │ ├── exchange-code-for-token.ts │ │ │ │ │ ├── refresh-access-token.ts │ │ │ │ │ └── route.ts │ │ │ │ └── userinfo/ │ │ │ │ └── route.ts │ │ │ ├── og/ │ │ │ │ ├── analytics/ │ │ │ │ │ └── route.tsx │ │ │ │ ├── avatar/ │ │ │ │ │ └── [[...seed]]/ │ │ │ │ │ └── route.tsx │ │ │ │ ├── load-google-font.ts │ │ │ │ ├── partner-earnings/ │ │ │ │ │ └── route.tsx │ │ │ │ ├── partner-rewind/ │ │ │ │ │ └── route.tsx │ │ │ │ └── program/ │ │ │ │ └── route.tsx │ │ │ ├── postbacks/ │ │ │ │ └── callback/ │ │ │ │ └── route.ts │ │ │ ├── providers/ │ │ │ │ └── route.ts │ │ │ ├── qr/ │ │ │ │ └── route.tsx │ │ │ ├── resend/ │ │ │ │ └── webhook/ │ │ │ │ ├── email-bounced.ts │ │ │ │ ├── email-delivered.ts │ │ │ │ ├── email-opened.ts │ │ │ │ └── route.ts │ │ │ ├── resumes/ │ │ │ │ └── upload-url/ │ │ │ │ └── route.ts │ │ │ ├── route.ts │ │ │ ├── slack/ │ │ │ │ ├── callback/ │ │ │ │ │ └── route.ts │ │ │ │ └── slash-commands/ │ │ │ │ └── route.ts │ │ │ ├── supported-countries/ │ │ │ │ └── route.ts │ │ │ ├── tags/ │ │ │ │ ├── [id]/ │ │ │ │ │ └── route.ts │ │ │ │ ├── count/ │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ ├── tokens/ │ │ │ │ ├── [id]/ │ │ │ │ │ └── route.ts │ │ │ │ ├── embed/ │ │ │ │ │ └── referrals/ │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ ├── unsplash/ │ │ │ │ ├── download/ │ │ │ │ │ └── route.ts │ │ │ │ ├── search/ │ │ │ │ │ └── route.ts │ │ │ │ └── utils.ts │ │ │ ├── user/ │ │ │ │ ├── notification-preferences/ │ │ │ │ │ └── route.ts │ │ │ │ ├── password/ │ │ │ │ │ └── route.ts │ │ │ │ ├── referrals-token/ │ │ │ │ │ └── route.ts │ │ │ │ ├── route.ts │ │ │ │ ├── set-password/ │ │ │ │ │ └── route.ts │ │ │ │ └── tokens/ │ │ │ │ └── route.ts │ │ │ ├── utm/ │ │ │ │ ├── [id]/ │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ ├── webhooks/ │ │ │ │ ├── [webhookId]/ │ │ │ │ │ ├── events/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ ├── callback/ │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ └── workspaces/ │ │ │ ├── [idOrSlug]/ │ │ │ │ ├── billing/ │ │ │ │ │ ├── cancel/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── invoices/ │ │ │ │ │ │ ├── [invoiceId]/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── manage/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── payment-methods/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── upgrade/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── usage/ │ │ │ │ │ └── route.ts │ │ │ │ ├── import/ │ │ │ │ │ ├── [importId]/ │ │ │ │ │ │ └── download/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── bitly/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── csv/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── rebrandly/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── short/ │ │ │ │ │ └── route.ts │ │ │ │ ├── invites/ │ │ │ │ │ ├── accept/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── decline/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── reset/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ ├── notification-preferences/ │ │ │ │ │ └── route.ts │ │ │ │ ├── route.ts │ │ │ │ ├── saml/ │ │ │ │ │ └── route.ts │ │ │ │ ├── scim/ │ │ │ │ │ └── route.ts │ │ │ │ ├── stats/ │ │ │ │ │ └── [endpoint]/ │ │ │ │ │ └── route.ts │ │ │ │ ├── upload-url/ │ │ │ │ │ └── route.ts │ │ │ │ └── users/ │ │ │ │ └── route.ts │ │ │ └── route.ts │ │ ├── app.dub.co/ │ │ │ ├── (auth)/ │ │ │ │ ├── auth/ │ │ │ │ │ ├── confirm-email-change/ │ │ │ │ │ │ └── [token]/ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── reset-password/ │ │ │ │ │ │ └── [token]/ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── saml/ │ │ │ │ │ ├── form.tsx │ │ │ │ │ └── page.tsx │ │ │ │ ├── customer-logos.tsx │ │ │ │ ├── forgot-password/ │ │ │ │ │ └── page.tsx │ │ │ │ ├── invites/ │ │ │ │ │ └── [code]/ │ │ │ │ │ └── page.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── login/ │ │ │ │ │ └── page.tsx │ │ │ │ ├── oauth/ │ │ │ │ │ └── authorize/ │ │ │ │ │ ├── authorize-form.tsx │ │ │ │ │ ├── loading.tsx │ │ │ │ │ ├── page.tsx │ │ │ │ │ └── scopes-requested.tsx │ │ │ │ ├── register/ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ └── page.tsx │ │ │ │ ├── side-panel.tsx │ │ │ │ └── unsubscribe/ │ │ │ │ └── [token]/ │ │ │ │ ├── page.tsx │ │ │ │ └── unsubscribe-form.tsx │ │ │ ├── (dashboard)/ │ │ │ │ ├── [slug]/ │ │ │ │ │ ├── (ee)/ │ │ │ │ │ │ ├── customers/ │ │ │ │ │ │ │ ├── [customerId]/ │ │ │ │ │ │ │ │ ├── earnings/ │ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ │ └── sales/ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── events/ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── program/ │ │ │ │ │ │ │ ├── analytics/ │ │ │ │ │ │ │ │ ├── analytics-chart.tsx │ │ │ │ │ │ │ │ ├── analytics-partners-table.tsx │ │ │ │ │ │ │ │ ├── analytics-timeseries-chart.tsx │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ │ └── partner-analytics-filter-cell.tsx │ │ │ │ │ │ │ ├── auth.tsx │ │ │ │ │ │ │ ├── bounties/ │ │ │ │ │ │ │ │ ├── [bountyId]/ │ │ │ │ │ │ │ │ │ ├── bounty-header.tsx │ │ │ │ │ │ │ │ │ ├── bounty-info.tsx │ │ │ │ │ │ │ │ │ ├── bounty-submission-details-sheet.tsx │ │ │ │ │ │ │ │ │ ├── bounty-submission-row-menu.tsx │ │ │ │ │ │ │ │ │ ├── bounty-submissions-table.tsx │ │ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ │ │ └── use-bounty-submission-filters.tsx │ │ │ │ │ │ │ │ ├── add-edit-bounty/ │ │ │ │ │ │ │ │ │ ├── add-edit-bounty-sheet.tsx │ │ │ │ │ │ │ │ │ ├── bounty-amount-input.tsx │ │ │ │ │ │ │ │ │ ├── bounty-criteria-manual-submission.tsx │ │ │ │ │ │ │ │ │ ├── bounty-criteria-social-metrics.tsx │ │ │ │ │ │ │ │ │ ├── bounty-criteria.tsx │ │ │ │ │ │ │ │ │ ├── bounty-form-context.tsx │ │ │ │ │ │ │ │ │ ├── bounty-logic.tsx │ │ │ │ │ │ │ │ │ ├── confirm-create-bounty-modal.tsx │ │ │ │ │ │ │ │ │ └── use-add-edit-bounty-form.ts │ │ │ │ │ │ │ │ ├── bounty-action-button.tsx │ │ │ │ │ │ │ │ ├── bounty-card.tsx │ │ │ │ │ │ │ │ ├── bounty-list.tsx │ │ │ │ │ │ │ │ ├── create-bounty-button.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── campaigns/ │ │ │ │ │ │ │ │ ├── [campaignId]/ │ │ │ │ │ │ │ │ │ ├── campaign-action-bar.tsx │ │ │ │ │ │ │ │ │ ├── campaign-controls.tsx │ │ │ │ │ │ │ │ │ ├── campaign-editor-skeleton.tsx │ │ │ │ │ │ │ │ │ ├── campaign-editor.tsx │ │ │ │ │ │ │ │ │ ├── campaign-events-columns.tsx │ │ │ │ │ │ │ │ │ ├── campaign-events-modal.tsx │ │ │ │ │ │ │ │ │ ├── campaign-events.tsx │ │ │ │ │ │ │ │ │ ├── campaign-form-context.tsx │ │ │ │ │ │ │ │ │ ├── campaign-groups-selector.tsx │ │ │ │ │ │ │ │ │ ├── campaign-metrics.tsx │ │ │ │ │ │ │ │ │ ├── duplicate-logic-warning.tsx │ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ │ │ ├── send-email-preview-modal.tsx │ │ │ │ │ │ │ │ │ ├── transactional-campaign-logic.tsx │ │ │ │ │ │ │ │ │ ├── use-campaign-confirmation-modals.tsx │ │ │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ │ │ ├── campaign-stats.tsx │ │ │ │ │ │ │ │ ├── campaign-status-badges.tsx │ │ │ │ │ │ │ │ ├── campaign-type-badges.tsx │ │ │ │ │ │ │ │ ├── campaign-type-icon.tsx │ │ │ │ │ │ │ │ ├── campaigns-page-content.tsx │ │ │ │ │ │ │ │ ├── campaigns-table.tsx │ │ │ │ │ │ │ │ ├── campaigns-upsell.tsx │ │ │ │ │ │ │ │ ├── create-campaign-button.tsx │ │ │ │ │ │ │ │ ├── delete-campaign-modal.tsx │ │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ │ ├── use-campaign.tsx │ │ │ │ │ │ │ │ ├── use-campaigns-count.tsx │ │ │ │ │ │ │ │ └── use-campaigns-filters.tsx │ │ │ │ │ │ │ ├── coming-soon-page.tsx │ │ │ │ │ │ │ ├── commissions/ │ │ │ │ │ │ │ │ ├── [commissionId]/ │ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ ├── commission-popover-buttons.tsx │ │ │ │ │ │ │ │ ├── commissions-stats.tsx │ │ │ │ │ │ │ │ ├── commissions-table.tsx │ │ │ │ │ │ │ │ ├── create-clawback-sheet.tsx │ │ │ │ │ │ │ │ ├── create-commission-button.tsx │ │ │ │ │ │ │ │ ├── create-commission-sheet.tsx │ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ │ └── use-commission-filters.tsx │ │ │ │ │ │ │ ├── customers/ │ │ │ │ │ │ │ │ ├── (index)/ │ │ │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ │ │ └── referrals/ │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ ├── [customerId]/ │ │ │ │ │ │ │ │ │ ├── earnings/ │ │ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ │ │ └── sales/ │ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ └── customers-dropdown-menu.tsx │ │ │ │ │ │ │ ├── fraud/ │ │ │ │ │ │ │ │ ├── example-fraud-events.tsx │ │ │ │ │ │ │ │ ├── fraud-group-table.tsx │ │ │ │ │ │ │ │ ├── fraud-paid-traffic-settings.tsx │ │ │ │ │ │ │ │ ├── fraud-referral-source-settings.tsx │ │ │ │ │ │ │ │ ├── fraud-rule-toggle-settings.tsx │ │ │ │ │ │ │ │ ├── fraud-upsell.tsx │ │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ │ ├── program-fraud-actions-menu.tsx │ │ │ │ │ │ │ │ ├── program-fraud-settings-button.tsx │ │ │ │ │ │ │ │ ├── program-fraud-settings-sheet.tsx │ │ │ │ │ │ │ │ ├── resolved/ │ │ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ │ │ └── resolved-fraud-group-table.tsx │ │ │ │ │ │ │ │ └── use-fraud-group-filters.tsx │ │ │ │ │ │ │ ├── groups/ │ │ │ │ │ │ │ │ ├── [groupSlug]/ │ │ │ │ │ │ │ │ │ ├── branding/ │ │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ │ ├── discounts/ │ │ │ │ │ │ │ │ │ │ ├── group-discounts.tsx │ │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ │ ├── group-header.tsx │ │ │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ │ │ ├── links/ │ │ │ │ │ │ │ │ │ │ ├── add-edit-group-additional-link-modal.tsx │ │ │ │ │ │ │ │ │ │ ├── add-edit-group-default-link-sheet.tsx │ │ │ │ │ │ │ │ │ │ ├── change-program-domain-modal.tsx │ │ │ │ │ │ │ │ │ │ ├── group-additional-links.tsx │ │ │ │ │ │ │ │ │ │ ├── group-default-links.tsx │ │ │ │ │ │ │ │ │ │ ├── group-link-settings.tsx │ │ │ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ │ │ │ └── partner-link-preview.tsx │ │ │ │ │ │ │ │ │ ├── rewards/ │ │ │ │ │ │ │ │ │ │ ├── group-rewards.tsx │ │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ │ └── settings/ │ │ │ │ │ │ │ │ │ ├── group-additional-settings.tsx │ │ │ │ │ │ │ │ │ ├── group-move-rules.tsx │ │ │ │ │ │ │ │ │ ├── group-settings.tsx │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ ├── create-group-button.tsx │ │ │ │ │ │ │ │ ├── create-group-modal.tsx │ │ │ │ │ │ │ │ ├── groups-table.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ ├── messages/ │ │ │ │ │ │ │ │ ├── [partnerId]/ │ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ │ ├── messages-disabled.tsx │ │ │ │ │ │ │ │ ├── messages-upsell.tsx │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── network/ │ │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ │ ├── network-empty-state.tsx │ │ │ │ │ │ │ │ ├── network-upsell.tsx │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ │ └── use-partner-network-filters.tsx │ │ │ │ │ │ │ ├── overview-chart.tsx │ │ │ │ │ │ │ ├── overview-links.tsx │ │ │ │ │ │ │ ├── overview-tasks.tsx │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ ├── partners/ │ │ │ │ │ │ │ │ ├── [partnerId]/ │ │ │ │ │ │ │ │ │ ├── comments/ │ │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ │ ├── customers/ │ │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ │ │ ├── links/ │ │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ │ ├── partner-nav.tsx │ │ │ │ │ │ │ │ │ ├── partner-stats.tsx │ │ │ │ │ │ │ │ │ └── payouts/ │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ ├── applications/ │ │ │ │ │ │ │ │ │ ├── applications-menu.tsx │ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ │ │ └── rejected/ │ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ ├── import-export-buttons.tsx │ │ │ │ │ │ │ │ ├── invite-partner-button.tsx │ │ │ │ │ │ │ │ ├── invite-partner-sheet.tsx │ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ │ ├── partners-table.tsx │ │ │ │ │ │ │ │ └── use-partner-filters.tsx │ │ │ │ │ │ │ ├── partners-graphic.tsx │ │ │ │ │ │ │ ├── partners-upgrade-cta.tsx │ │ │ │ │ │ │ ├── payouts/ │ │ │ │ │ │ │ │ ├── [payoutId]/ │ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ │ ├── payout-paid-cell.tsx │ │ │ │ │ │ │ │ ├── payout-stats.tsx │ │ │ │ │ │ │ │ ├── payout-table.tsx │ │ │ │ │ │ │ │ ├── program-payout-methods.tsx │ │ │ │ │ │ │ │ ├── program-payout-mode-section.tsx │ │ │ │ │ │ │ │ ├── program-payout-settings-button.tsx │ │ │ │ │ │ │ │ ├── program-payout-settings-sheet.tsx │ │ │ │ │ │ │ │ ├── success/ │ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ └── use-payout-filters.tsx │ │ │ │ │ │ │ ├── program-settings-row.tsx │ │ │ │ │ │ │ └── resources/ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ ├── program-brand-assets/ │ │ │ │ │ │ │ │ ├── add-color-modal.tsx │ │ │ │ │ │ │ │ ├── add-file-modal.tsx │ │ │ │ │ │ │ │ ├── add-link-modal.tsx │ │ │ │ │ │ │ │ ├── add-logo-modal.tsx │ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ │ └── use-upload-program-resource.ts │ │ │ │ │ │ │ └── program-help-and-support.tsx │ │ │ │ │ │ └── settings/ │ │ │ │ │ │ ├── billing/ │ │ │ │ │ │ │ ├── invoices/ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ ├── payment-method-types.ts │ │ │ │ │ │ │ ├── payment-methods.tsx │ │ │ │ │ │ │ ├── plan-usage.tsx │ │ │ │ │ │ │ ├── upgrade/ │ │ │ │ │ │ │ │ ├── adjust-usage-row.tsx │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ └── usage-chart.tsx │ │ │ │ │ │ ├── domains/ │ │ │ │ │ │ │ ├── default/ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── email/ │ │ │ │ │ │ │ │ ├── constants.ts │ │ │ │ │ │ │ │ ├── email-domain-card.tsx │ │ │ │ │ │ │ │ ├── email-domain-dns-records.tsx │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── header.tsx │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── integrations/ │ │ │ │ │ │ │ ├── [integrationSlug]/ │ │ │ │ │ │ │ │ ├── loading.tsx │ │ │ │ │ │ │ │ ├── manage/ │ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── enabled/ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── enabled-integrations.tsx │ │ │ │ │ │ │ ├── featured-integrations.tsx │ │ │ │ │ │ │ ├── integrations-cards.tsx │ │ │ │ │ │ │ ├── integrations-list.tsx │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ ├── new/ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── members/ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── notifications/ │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── oauth-apps/ │ │ │ │ │ │ │ ├── [appId]/ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── create-oauth-app-button.tsx │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ ├── new/ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ ├── security/ │ │ │ │ │ │ │ ├── audit-logs.tsx │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ ├── saml.tsx │ │ │ │ │ │ │ └── scim.tsx │ │ │ │ │ │ ├── tokens/ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── tracking/ │ │ │ │ │ │ │ ├── add-hostname-modal.tsx │ │ │ │ │ │ │ ├── base-script-section.tsx │ │ │ │ │ │ │ ├── complete-step-button.tsx │ │ │ │ │ │ │ ├── connection-instructions.tsx │ │ │ │ │ │ │ ├── conversion-tracking-section.tsx │ │ │ │ │ │ │ ├── conversion-tracking-toggle.tsx │ │ │ │ │ │ │ ├── guide.tsx │ │ │ │ │ │ │ ├── hostname-menu.tsx │ │ │ │ │ │ │ ├── hostname-section.tsx │ │ │ │ │ │ │ ├── outbound-domain-tracking-section.tsx │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ ├── publishable-key-form.tsx │ │ │ │ │ │ │ ├── publishable-key-menu.tsx │ │ │ │ │ │ │ ├── site-visit-tracking-section.tsx │ │ │ │ │ │ │ ├── step.tsx │ │ │ │ │ │ │ ├── track-lead-guides-section.tsx │ │ │ │ │ │ │ ├── track-sales-guides-section.tsx │ │ │ │ │ │ │ ├── use-dynamic-guide.ts │ │ │ │ │ │ │ ├── use-selected-guide.ts │ │ │ │ │ │ │ └── verify-install.tsx │ │ │ │ │ │ └── webhooks/ │ │ │ │ │ │ ├── [webhookId]/ │ │ │ │ │ │ │ ├── edit/ │ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── create-webhook-button.tsx │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ ├── new/ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── analytics/ │ │ │ │ │ │ ├── client.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── auth.tsx │ │ │ │ │ ├── layout.tsx │ │ │ │ │ └── links/ │ │ │ │ │ ├── [...link]/ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── domains/ │ │ │ │ │ │ ├── default/ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── email/ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── folders/ │ │ │ │ │ │ ├── [folderId]/ │ │ │ │ │ │ │ └── members/ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ ├── page.tsx │ │ │ │ │ ├── tags/ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ ├── tag-card-placeholder.tsx │ │ │ │ │ │ └── tag-card.tsx │ │ │ │ │ └── utm/ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ ├── page.tsx │ │ │ │ │ ├── template-card-placeholder.tsx │ │ │ │ │ └── template-card.tsx │ │ │ │ ├── account/ │ │ │ │ │ └── settings/ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ ├── page.tsx │ │ │ │ │ ├── referrals/ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── security/ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ ├── request-set-password.tsx │ │ │ │ │ │ └── update-password.tsx │ │ │ │ │ └── tokens/ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ └── page.tsx │ │ │ │ ├── layout.tsx │ │ │ │ └── loading.tsx │ │ │ ├── (deeplink)/ │ │ │ │ └── deeplink/ │ │ │ │ └── [domain]/ │ │ │ │ └── [[...key]]/ │ │ │ │ ├── action-buttons.tsx │ │ │ │ ├── brand-logo-badge.tsx │ │ │ │ ├── page.tsx │ │ │ │ └── translations.ts │ │ │ ├── (invites)/ │ │ │ │ ├── [slug]/ │ │ │ │ │ └── invite/ │ │ │ │ │ ├── accept-invite-button.tsx │ │ │ │ │ ├── close-invite-button.tsx │ │ │ │ │ ├── invite-confetti.tsx │ │ │ │ │ └── page.tsx │ │ │ │ └── layout.tsx │ │ │ ├── (onboarding)/ │ │ │ │ ├── [slug]/ │ │ │ │ │ └── wrapped/ │ │ │ │ │ ├── [year]/ │ │ │ │ │ │ ├── client.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── page.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── onboarding/ │ │ │ │ │ ├── (steps)/ │ │ │ │ │ │ ├── domain/ │ │ │ │ │ │ │ ├── custom/ │ │ │ │ │ │ │ │ ├── form.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── default-domain-selector.tsx │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ └── register/ │ │ │ │ │ │ │ ├── form.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ ├── plan/ │ │ │ │ │ │ │ ├── enterprise-link.tsx │ │ │ │ │ │ │ ├── free-plan-button.tsx │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ └── plan-selector.tsx │ │ │ │ │ │ ├── products/ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ └── product-selector.tsx │ │ │ │ │ │ ├── program/ │ │ │ │ │ │ │ ├── form.tsx │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ ├── reward/ │ │ │ │ │ │ │ │ ├── form.tsx │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ └── use-onboarding-program.tsx │ │ │ │ │ │ ├── step-page.tsx │ │ │ │ │ │ ├── success/ │ │ │ │ │ │ │ ├── page-client.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ └── workspace/ │ │ │ │ │ │ ├── form.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── later-button.tsx │ │ │ │ │ ├── next-button.tsx │ │ │ │ │ ├── use-onboarding-product.ts │ │ │ │ │ ├── use-onboarding-progress.ts │ │ │ │ │ └── welcome/ │ │ │ │ │ ├── page.tsx │ │ │ │ │ └── track-signup.tsx │ │ │ │ └── signed-in-hint.tsx │ │ │ ├── (redirects)/ │ │ │ │ ├── [slug]/ │ │ │ │ │ ├── domains/ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── settings/ │ │ │ │ │ ├── referrals/ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── tags/ │ │ │ │ │ └── page.tsx │ │ │ │ ├── analytics/ │ │ │ │ │ └── page.tsx │ │ │ │ └── loading.tsx │ │ │ ├── (share)/ │ │ │ │ └── share/ │ │ │ │ └── [dashboardId]/ │ │ │ │ ├── action.ts │ │ │ │ ├── form.tsx │ │ │ │ └── page.tsx │ │ │ ├── embed/ │ │ │ │ └── support-chat/ │ │ │ │ ├── dynamic-height-messenger.tsx │ │ │ │ ├── layout.tsx │ │ │ │ └── page.tsx │ │ │ └── layout.tsx │ │ ├── banned/ │ │ │ └── page.tsx │ │ ├── cloaked/ │ │ │ └── [url]/ │ │ │ └── page.tsx │ │ ├── custom-uri-scheme/ │ │ │ └── [url]/ │ │ │ └── page.tsx │ │ ├── expired/ │ │ │ └── [domain]/ │ │ │ └── page.tsx │ │ ├── inspect/ │ │ │ └── [domain]/ │ │ │ └── [key]/ │ │ │ ├── card.tsx │ │ │ └── page.tsx │ │ ├── layout.tsx │ │ ├── manifest.ts │ │ ├── not-found-hint.tsx │ │ ├── not-found.tsx │ │ ├── password/ │ │ │ └── [linkId]/ │ │ │ ├── action.ts │ │ │ ├── form.tsx │ │ │ ├── loading.tsx │ │ │ └── page.tsx │ │ ├── providers.tsx │ │ ├── proxy/ │ │ │ └── [domain]/ │ │ │ └── [key]/ │ │ │ └── page.tsx │ │ ├── robots.ts │ │ ├── sitemap.ts │ │ └── wellknown/ │ │ └── [domain]/ │ │ └── [file]/ │ │ └── route.ts │ ├── docker-compose.yml │ ├── global-setup.ts │ ├── guides/ │ │ ├── appwrite.md │ │ ├── auth0.md │ │ ├── better-auth.md │ │ ├── clerk.md │ │ ├── framer.md │ │ ├── gtm-client-sdk.md │ │ ├── gtm-track-lead.md │ │ ├── gtm-track-sale.md │ │ ├── manual-client-sdk.md │ │ ├── manual-track-lead.md │ │ ├── manual-track-sale.md │ │ ├── next-auth.md │ │ ├── react.md │ │ ├── rest-api.md │ │ ├── segment-track-lead.md │ │ ├── segment-track-sale.md │ │ ├── shopify.md │ │ ├── stripe-checkout.md │ │ ├── stripe-customers.md │ │ ├── stripe-payment-links.md │ │ ├── supabase.md │ │ ├── webflow.md │ │ └── wordpress.md │ ├── instrumentation.ts │ ├── lib/ │ │ ├── actions/ │ │ │ ├── add-edit-integration.ts │ │ │ ├── auth/ │ │ │ │ └── throw-if-authenticated.ts │ │ │ ├── check-account-exists.ts │ │ │ ├── create-oauth-url.ts │ │ │ ├── create-user-account.ts │ │ │ ├── enable-disable-webhook.ts │ │ │ ├── folders/ │ │ │ │ ├── request-folder-edit-access.ts │ │ │ │ ├── set-default-folder.ts │ │ │ │ └── update-folder-user-role.ts │ │ │ ├── fraud/ │ │ │ │ ├── bulk-resolve-fraud-groups.ts │ │ │ │ └── resolve-fraud-group.ts │ │ │ ├── generate-client-secret.ts │ │ │ ├── generate-unsubscribe-url.ts │ │ │ ├── get-integration-install-url.ts │ │ │ ├── parse-action-errors.ts │ │ │ ├── partners/ │ │ │ │ ├── accept-program-invite.ts │ │ │ │ ├── approve-bounty-submission.ts │ │ │ │ ├── approve-partner.ts │ │ │ │ ├── archive-partner.ts │ │ │ │ ├── ban-partner.ts │ │ │ │ ├── bulk-approve-partners.ts │ │ │ │ ├── bulk-archive-partners.ts │ │ │ │ ├── bulk-ban-partners.ts │ │ │ │ ├── bulk-deactivate-partners.ts │ │ │ │ ├── bulk-invite-partners.ts │ │ │ │ ├── bulk-reject-partner-applications.ts │ │ │ │ ├── confirm-payouts.ts │ │ │ │ ├── create-bounty-submission.ts │ │ │ │ ├── create-clawback.ts │ │ │ │ ├── create-discount.ts │ │ │ │ ├── create-manual-commission.ts │ │ │ │ ├── create-partner-comment.ts │ │ │ │ ├── create-program-application.ts │ │ │ │ ├── create-program.ts │ │ │ │ ├── create-reward.ts │ │ │ │ ├── deactivate-partner.ts │ │ │ │ ├── delete-discount.ts │ │ │ │ ├── delete-partner-comment.ts │ │ │ │ ├── delete-program-invite.ts │ │ │ │ ├── delete-reward.ts │ │ │ │ ├── force-withdrawal.ts │ │ │ │ ├── generate-lander.ts │ │ │ │ ├── generate-paypal-oauth-url.ts │ │ │ │ ├── generate-stripe-account-link.ts │ │ │ │ ├── generate-stripe-recipient-account-link.ts │ │ │ │ ├── get-conversion-score.ts │ │ │ │ ├── invite-partner-from-network.ts │ │ │ │ ├── invite-partner.ts │ │ │ │ ├── mark-commission-duplicate.ts │ │ │ │ ├── mark-commission-fraud-or-canceled.ts │ │ │ │ ├── mark-partner-messages-read.ts │ │ │ │ ├── mark-program-messages-read.ts │ │ │ │ ├── merge-partner-accounts.ts │ │ │ │ ├── message-partner.ts │ │ │ │ ├── message-program.ts │ │ │ │ ├── onboard-partner.ts │ │ │ │ ├── onboard-program.ts │ │ │ │ ├── program-resources/ │ │ │ │ │ ├── add-program-resource.ts │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── delete-program-resource.ts │ │ │ │ │ ├── get-program-resource-upload-url.ts │ │ │ │ │ └── update-program-resource.ts │ │ │ │ ├── reactivate-partner.ts │ │ │ │ ├── reject-bounty-submission.ts │ │ │ │ ├── reject-partner-application.ts │ │ │ │ ├── reopen-bounty-submission.ts │ │ │ │ ├── resend-program-invite.ts │ │ │ │ ├── retry-failed-paypal-payouts.ts │ │ │ │ ├── revoke-program-invite.ts │ │ │ │ ├── save-invite-email-data.ts │ │ │ │ ├── set-rewardful-token.ts │ │ │ │ ├── set-tolt-token.ts │ │ │ │ ├── start-firstpromoter-import.ts │ │ │ │ ├── start-partner-platform-verification.ts │ │ │ │ ├── start-partnerstack-import.ts │ │ │ │ ├── start-rewardful-import.ts │ │ │ │ ├── start-tolt-import.ts │ │ │ │ ├── trigger-aggregate-due-commissions.ts │ │ │ │ ├── unban-partner.ts │ │ │ │ ├── update-application-settings.ts │ │ │ │ ├── update-discount.ts │ │ │ │ ├── update-discovered-partner.ts │ │ │ │ ├── update-group-branding.ts │ │ │ │ ├── update-partner-comment.ts │ │ │ │ ├── update-partner-enrollment.ts │ │ │ │ ├── update-partner-notification-preference.ts │ │ │ │ ├── update-partner-payout-settings.ts │ │ │ │ ├── update-partner-platforms.ts │ │ │ │ ├── update-partner-profile.ts │ │ │ │ ├── update-program.ts │ │ │ │ ├── update-reward.ts │ │ │ │ ├── upload-bounty-submission-file.ts │ │ │ │ ├── upload-campaign-image.ts │ │ │ │ ├── upload-lander-image.ts │ │ │ │ ├── upload-program-application-image.ts │ │ │ │ ├── verify-partner-website.ts │ │ │ │ ├── verify-social-account-by-code.ts │ │ │ │ └── withdraw-partner-application.ts │ │ │ ├── referrals/ │ │ │ │ ├── submit-referral.ts │ │ │ │ ├── update-referral-status.ts │ │ │ │ └── update-referral.ts │ │ │ ├── request-password-reset.ts │ │ │ ├── safe-action.ts │ │ │ ├── send-invite-referral-email.ts │ │ │ ├── send-otp.ts │ │ │ ├── send-test-webhook.ts │ │ │ ├── set-onboarding-progress.ts │ │ │ ├── submit-oauth-app-for-review.ts │ │ │ ├── throw-if-no-permission.ts │ │ │ ├── update-workspace-notification-preference.ts │ │ │ ├── update-workspace-preferences.ts │ │ │ ├── update-workspace-store.ts │ │ │ └── verify-workspace-setup.ts │ │ ├── ai/ │ │ │ ├── build-system-prompt.ts │ │ │ ├── create-support-ticket.ts │ │ │ ├── find-relevant-docs.ts │ │ │ ├── generate-csv-mapping.ts │ │ │ ├── generate-filters.ts │ │ │ ├── get-program-performance.ts │ │ │ ├── get-workspace-details.ts │ │ │ ├── request-support-ticket.ts │ │ │ └── upsert-docs-embedding.ts │ │ ├── analytics/ │ │ │ ├── allowed-hostnames-cache.ts │ │ │ ├── constants.ts │ │ │ ├── convert-currency.ts │ │ │ ├── events-export-helpers.ts │ │ │ ├── filter-helpers.ts │ │ │ ├── format-date-tooltip.ts │ │ │ ├── get-analytics.ts │ │ │ ├── get-customer-events.ts │ │ │ ├── get-events.ts │ │ │ ├── get-folder-ids-to-filter.ts │ │ │ ├── is-first-conversion.ts │ │ │ ├── metadata-query-parser.ts │ │ │ ├── types.ts │ │ │ ├── utils/ │ │ │ │ ├── convert-to-csv.ts │ │ │ │ ├── edit-query-string.ts │ │ │ │ ├── format-utc-datetime-clickhouse.ts │ │ │ │ ├── get-interval-data.ts │ │ │ │ ├── get-start-end-dates.ts │ │ │ │ ├── index.ts │ │ │ │ └── valid-date-range-for-plan.ts │ │ │ └── verify-analytics-allowed-hostnames.ts │ │ ├── api/ │ │ │ ├── activity-log/ │ │ │ │ ├── build-program-enrollment-change-set.ts │ │ │ │ ├── get-resource-diff.ts │ │ │ │ ├── track-activity-log.ts │ │ │ │ └── track-reward-activity-log.ts │ │ │ ├── audit-logs/ │ │ │ │ ├── get-audit-logs.ts │ │ │ │ ├── record-audit-log.ts │ │ │ │ └── schemas.ts │ │ │ ├── campaigns/ │ │ │ │ ├── constants.ts │ │ │ │ ├── get-campaign-events.ts │ │ │ │ ├── get-campaign-or-throw.ts │ │ │ │ ├── get-campaign-summary.ts │ │ │ │ ├── schedule-campaigns.ts │ │ │ │ └── validate-campaign.ts │ │ │ ├── commissions/ │ │ │ │ ├── format-commissions-for-export.ts │ │ │ │ ├── get-commissions-count.ts │ │ │ │ └── get-commissions.ts │ │ │ ├── conversions/ │ │ │ │ ├── track-lead.ts │ │ │ │ └── track-sale.ts │ │ │ ├── cors.ts │ │ │ ├── create-downloadable-export.ts │ │ │ ├── create-id.ts │ │ │ ├── customers/ │ │ │ │ ├── get-customer-or-throw.ts │ │ │ │ ├── get-customer-stripe-invoices.ts │ │ │ │ └── transform-customer.ts │ │ │ ├── discounts/ │ │ │ │ ├── construct-discount-code.ts │ │ │ │ ├── create-discount-code.ts │ │ │ │ ├── delete-discount-code.ts │ │ │ │ └── is-discount-equivalent.ts │ │ │ ├── domains/ │ │ │ │ ├── add-domain-vercel.ts │ │ │ │ ├── claim-dot-link-domain.ts │ │ │ │ ├── configure-vercel-nameservers.ts │ │ │ │ ├── get-config-response.ts │ │ │ │ ├── get-domain-or-throw.ts │ │ │ │ ├── get-domain-response.ts │ │ │ │ ├── get-email-domain-or-throw.ts │ │ │ │ ├── is-valid-domain.ts │ │ │ │ ├── mark-domain-deleted.ts │ │ │ │ ├── queue-domain-update.ts │ │ │ │ ├── remove-domain-vercel.ts │ │ │ │ ├── transform-domain.ts │ │ │ │ ├── utils.ts │ │ │ │ └── verify-domain.ts │ │ │ ├── environment.ts │ │ │ ├── error-codes.ts │ │ │ ├── errors.ts │ │ │ ├── folders/ │ │ │ │ ├── delete-workspace-folders.ts │ │ │ │ └── queue-folder-deletion.ts │ │ │ ├── fraud/ │ │ │ │ ├── constants.ts │ │ │ │ ├── create-fraud-events.ts │ │ │ │ ├── define-fraud-rule.ts │ │ │ │ ├── detect-duplicate-payout-method-fraud.ts │ │ │ │ ├── detect-record-fraud-application.ts │ │ │ │ ├── detect-record-fraud-event.ts │ │ │ │ ├── execute-fraud-rule.ts │ │ │ │ ├── get-merged-fraud-rules.ts │ │ │ │ ├── get-partner-application-risks.ts │ │ │ │ ├── report-cross-program-ban-to-network.ts │ │ │ │ ├── report-fraud-to-network.ts │ │ │ │ ├── resolve-fraud-groups.ts │ │ │ │ ├── rules/ │ │ │ │ │ ├── check-customer-email-match.ts │ │ │ │ │ ├── check-customer-email-suspicious.ts │ │ │ │ │ ├── check-paid-traffic-detected.ts │ │ │ │ │ ├── check-partner-email-domain-mismatch.ts │ │ │ │ │ ├── check-partner-email-masked.ts │ │ │ │ │ ├── check-partner-no-social-links.ts │ │ │ │ │ ├── check-partner-no-verified-social-links.ts │ │ │ │ │ └── check-referral-source-banned.ts │ │ │ │ └── utils.ts │ │ │ ├── get-ratelimit-for-plan.ts │ │ │ ├── get-workspace-users.ts │ │ │ ├── groups/ │ │ │ │ ├── find-groups-with-matching-rules.ts │ │ │ │ ├── get-group-move-rules.ts │ │ │ │ ├── get-group-or-throw.ts │ │ │ │ ├── get-groups.ts │ │ │ │ ├── move-partners-to-group.ts │ │ │ │ ├── throw-if-invalid-group-ids.ts │ │ │ │ ├── upsert-group-move-rules.ts │ │ │ │ └── validate-group-move-rules.ts │ │ │ ├── links/ │ │ │ │ ├── ab-test-scheduler.ts │ │ │ │ ├── archive-link.ts │ │ │ │ ├── bulk-create-links.ts │ │ │ │ ├── bulk-delete-links.ts │ │ │ │ ├── bulk-update-links.ts │ │ │ │ ├── cache.ts │ │ │ │ ├── case-sensitivity.ts │ │ │ │ ├── complete-ab-tests.ts │ │ │ │ ├── create-link.ts │ │ │ │ ├── delete-link.ts │ │ │ │ ├── format-links-for-export.ts │ │ │ │ ├── get-link-or-throw.ts │ │ │ │ ├── get-links-count.ts │ │ │ │ ├── get-links-for-workspace.ts │ │ │ │ ├── include-program-enrollment.ts │ │ │ │ ├── include-tags.ts │ │ │ │ ├── index.ts │ │ │ │ ├── plan-features-check.ts │ │ │ │ ├── process-link.ts │ │ │ │ ├── propagate-bulk-link-changes.ts │ │ │ │ ├── record-click-cache.ts │ │ │ │ ├── update-link-stats-for-importer.ts │ │ │ │ ├── update-link.ts │ │ │ │ ├── update-links-usage.ts │ │ │ │ ├── usage-checks.ts │ │ │ │ ├── utils/ │ │ │ │ │ ├── check-if-links-have-folders.ts │ │ │ │ │ ├── check-if-links-have-tags.ts │ │ │ │ │ ├── check-if-links-have-webhooks.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── key-checks.ts │ │ │ │ │ ├── process-key.ts │ │ │ │ │ └── transform-link.ts │ │ │ │ ├── validate-links-query-filters.ts │ │ │ │ └── validate-partner-link-url.ts │ │ │ ├── network/ │ │ │ │ └── calculate-partner-ranking.ts │ │ │ ├── oauth/ │ │ │ │ ├── actions.ts │ │ │ │ ├── constants.ts │ │ │ │ └── utils.ts │ │ │ ├── pagination.ts │ │ │ ├── partner-profile/ │ │ │ │ ├── client.ts │ │ │ │ ├── get-partner-earnings-timeseries.ts │ │ │ │ ├── get-partner-for-program.ts │ │ │ │ ├── obfuscate-customer-email.ts │ │ │ │ ├── partner-platforms-providers.ts │ │ │ │ └── upsert-partner-platform.ts │ │ │ ├── partners/ │ │ │ │ ├── bulk-deactivate-partners.ts │ │ │ │ ├── bulk-delete-partners.ts │ │ │ │ ├── create-and-enroll-partner.ts │ │ │ │ ├── create-partner-default-links.ts │ │ │ │ ├── deactivate-partner.ts │ │ │ │ ├── format-partners-for-export.ts │ │ │ │ ├── generate-partner-link.ts │ │ │ │ ├── get-discount-or-throw.ts │ │ │ │ ├── get-group-rewards-and-bounties.ts │ │ │ │ ├── get-network-invites-usage.ts │ │ │ │ ├── get-partner-rewind.ts │ │ │ │ ├── get-partner-users.ts │ │ │ │ ├── get-partners-count.ts │ │ │ │ ├── get-partners.ts │ │ │ │ ├── get-reward-or-throw.ts │ │ │ │ ├── invite-partner-user.ts │ │ │ │ ├── notify-partner-application.ts │ │ │ │ ├── notify-partner-commission.ts │ │ │ │ ├── notify-partner-group-change.ts │ │ │ │ ├── process-partner-deactivation.ts │ │ │ │ ├── serialize-reward.ts │ │ │ │ ├── sync-partner-links-stats.ts │ │ │ │ ├── sync-total-commissions.ts │ │ │ │ └── throw-if-existing-tenant-id-exists.ts │ │ │ ├── payouts/ │ │ │ │ ├── get-effective-payout-mode.ts │ │ │ │ ├── get-eligible-payouts.ts │ │ │ │ ├── get-payout-or-throw.ts │ │ │ │ └── payout-eligibility-filter.ts │ │ │ ├── postbacks/ │ │ │ │ └── get-postback-or-throw.ts │ │ │ ├── programs/ │ │ │ │ ├── deactivate-program.ts │ │ │ │ ├── get-default-program-id-or-throw.ts │ │ │ │ ├── get-program-enrollment-or-throw.ts │ │ │ │ └── get-program-or-throw.ts │ │ │ ├── rbac/ │ │ │ │ ├── permissions.ts │ │ │ │ └── resources.ts │ │ │ ├── referrals/ │ │ │ │ ├── get-referral-or-throw.ts │ │ │ │ ├── mark-referral-closed-won.ts │ │ │ │ ├── mark-referral-qualified.ts │ │ │ │ ├── notify-partner-referral-submitted.ts │ │ │ │ └── notify-referral-status-update.ts │ │ │ ├── rewards/ │ │ │ │ └── validate-reward.ts │ │ │ ├── sales/ │ │ │ │ ├── calculate-sale-earnings.ts │ │ │ │ ├── construct-discount-amount.ts │ │ │ │ └── construct-reward-amount.ts │ │ │ ├── scrape-creators/ │ │ │ │ ├── client.ts │ │ │ │ ├── get-linkedin-post.ts │ │ │ │ ├── get-social-content.ts │ │ │ │ ├── get-social-profile.ts │ │ │ │ └── schema.ts │ │ │ ├── tags/ │ │ │ │ └── combine-tag-ids.ts │ │ │ ├── tokens/ │ │ │ │ ├── scopes.ts │ │ │ │ └── throw-if-no-access.ts │ │ │ ├── users.ts │ │ │ ├── utils/ │ │ │ │ ├── assert-valid-date-range-for-plan.ts │ │ │ │ ├── generate-export-filename.ts │ │ │ │ ├── generate-random-string.ts │ │ │ │ ├── get-ip.ts │ │ │ │ ├── is-non-empty-json.ts │ │ │ │ └── with-prisma-retry.ts │ │ │ ├── utils.ts │ │ │ ├── utm/ │ │ │ │ └── extract-utm-params.ts │ │ │ ├── validate-allowed-hostnames.ts │ │ │ ├── workflows/ │ │ │ │ ├── evaluate-workflow-conditions.ts │ │ │ │ ├── execute-complete-bounty-workflow.ts │ │ │ │ ├── execute-move-group-workflow.ts │ │ │ │ ├── execute-send-campaign-workflow.ts │ │ │ │ ├── execute-workflows.ts │ │ │ │ ├── interpolate-email-template.ts │ │ │ │ ├── parse-workflow-config.ts │ │ │ │ ├── render-campaign-email-html.ts │ │ │ │ ├── render-campaign-email-markdown.ts │ │ │ │ └── utils.ts │ │ │ └── workspaces/ │ │ │ ├── assert-role-plan.ts │ │ │ ├── create-workspace-id.ts │ │ │ ├── delete-workspace.ts │ │ │ ├── is-saml-enforced-for-email-domain.ts │ │ │ ├── onboarding-step-cache.ts │ │ │ └── workspace-id.ts │ │ ├── auth/ │ │ │ ├── admin.ts │ │ │ ├── confirm-email-change.ts │ │ │ ├── constants.ts │ │ │ ├── hash-token.ts │ │ │ ├── index.ts │ │ │ ├── lock-account.ts │ │ │ ├── options.ts │ │ │ ├── partner-users/ │ │ │ │ ├── partner-user-permissions.ts │ │ │ │ └── throw-if-no-permission.ts │ │ │ ├── partner.ts │ │ │ ├── password.ts │ │ │ ├── publishable-key.ts │ │ │ ├── rate-limit-request.ts │ │ │ ├── session.ts │ │ │ ├── token-cache.ts │ │ │ ├── track-dub-lead.ts │ │ │ ├── utils.ts │ │ │ └── workspace.ts │ │ ├── axiom/ │ │ │ ├── axiom.ts │ │ │ └── server.ts │ │ ├── bounty/ │ │ │ ├── api/ │ │ │ │ ├── approve-bounty-submission.ts │ │ │ │ ├── create-bounty-submission.ts │ │ │ │ ├── generate-performance-bounty-name.ts │ │ │ │ ├── get-bounties-by-groups.ts │ │ │ │ ├── get-bounty-or-throw.ts │ │ │ │ ├── get-bounty-with-details.ts │ │ │ │ ├── get-group-bounty-summaries.ts │ │ │ │ ├── get-social-metrics-updates.ts │ │ │ │ ├── performance-bounty-scope-attributes.ts │ │ │ │ ├── reject-bounty-submission.ts │ │ │ │ ├── trigger-draft-bounty-submissions.ts │ │ │ │ └── validate-bounty.ts │ │ │ ├── constants.ts │ │ │ ├── periods.ts │ │ │ ├── rewards.ts │ │ │ ├── social-content.ts │ │ │ ├── submission-status.ts │ │ │ └── utils.ts │ │ ├── client-access-check.ts │ │ ├── constants/ │ │ │ ├── misc.ts │ │ │ ├── notification-preferences.ts │ │ │ ├── partner-profile.ts │ │ │ ├── payouts-supported-countries.ts │ │ │ ├── payouts.ts │ │ │ └── program.ts │ │ ├── cron/ │ │ │ ├── enqueue-batch-jobs.ts │ │ │ ├── index.ts │ │ │ ├── limiter.ts │ │ │ ├── qstash-workflow-logger.ts │ │ │ ├── qstash-workflow.ts │ │ │ ├── send-limit-email.ts │ │ │ ├── verify-qstash.ts │ │ │ ├── verify-vercel.ts │ │ │ └── with-cron.ts │ │ ├── customers/ │ │ │ └── api/ │ │ │ ├── customer-count-where.ts │ │ │ ├── fetch-customers-batch.ts │ │ │ ├── format-customers-export.ts │ │ │ └── get-customers.ts │ │ ├── dub.ts │ │ ├── dynadot/ │ │ │ ├── constants.ts │ │ │ ├── register-domain.ts │ │ │ ├── search-domains.ts │ │ │ └── set-renew-option.ts │ │ ├── edge-config/ │ │ │ ├── get-feature-flags.ts │ │ │ ├── get-partner-feature-flags.ts │ │ │ ├── index.ts │ │ │ ├── is-blacklisted-domain.ts │ │ │ ├── is-blacklisted-email.ts │ │ │ ├── is-blacklisted-key.ts │ │ │ ├── is-blacklisted-referrer.ts │ │ │ ├── is-reserved-username.ts │ │ │ └── update.ts │ │ ├── email/ │ │ │ ├── email-templates-map.ts │ │ │ ├── extract-email-domain.ts │ │ │ ├── queue-batch-email.ts │ │ │ └── unsubscribe-token.ts │ │ ├── embed/ │ │ │ ├── constants.ts │ │ │ └── referrals/ │ │ │ ├── auth.ts │ │ │ └── token-class.ts │ │ ├── exceeded-limit-error.ts │ │ ├── fetchers/ │ │ │ ├── get-content-api.ts │ │ │ ├── get-dashboard.ts │ │ │ ├── get-network-program.ts │ │ │ ├── get-program-slugs.ts │ │ │ ├── get-program.ts │ │ │ └── index.ts │ │ ├── firstpromoter/ │ │ │ ├── api.ts │ │ │ ├── import-campaigns.ts │ │ │ ├── import-commissions.ts │ │ │ ├── import-customers.ts │ │ │ ├── import-partners.ts │ │ │ ├── importer.ts │ │ │ ├── schemas.ts │ │ │ ├── types.ts │ │ │ └── update-stripe-customers.ts │ │ ├── folder/ │ │ │ ├── constants.ts │ │ │ ├── get-folder-or-throw.ts │ │ │ ├── get-folders.ts │ │ │ └── permissions.ts │ │ ├── form-utils.ts │ │ ├── get-highest-severity.ts │ │ ├── get-integration-guide-markdown.ts │ │ ├── hooks/ │ │ │ └── use-synced-local-storage.ts │ │ ├── integrations/ │ │ │ ├── bitly/ │ │ │ │ └── oauth.ts │ │ │ ├── common/ │ │ │ │ └── ui/ │ │ │ │ └── configure-webhook.tsx │ │ │ ├── hubspot/ │ │ │ │ ├── api.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── oauth.ts │ │ │ │ ├── schema.ts │ │ │ │ ├── track-lead.ts │ │ │ │ ├── track-sale.ts │ │ │ │ ├── ui/ │ │ │ │ │ └── settings.tsx │ │ │ │ └── update-hubspot-settings.ts │ │ │ ├── install.ts │ │ │ ├── oauth-provider.ts │ │ │ ├── segment/ │ │ │ │ ├── install.ts │ │ │ │ ├── transform.ts │ │ │ │ ├── ui/ │ │ │ │ │ ├── set-write-key.tsx │ │ │ │ │ └── settings.tsx │ │ │ │ └── utils.ts │ │ │ ├── shopify/ │ │ │ │ ├── create-lead.ts │ │ │ │ ├── create-sale.ts │ │ │ │ ├── process-order.ts │ │ │ │ └── schema.ts │ │ │ ├── singular/ │ │ │ │ ├── track-lead.ts │ │ │ │ └── track-sale.ts │ │ │ ├── slack/ │ │ │ │ ├── commands.ts │ │ │ │ ├── oauth.ts │ │ │ │ ├── schema.ts │ │ │ │ ├── transform.ts │ │ │ │ ├── ui/ │ │ │ │ │ └── settings.tsx │ │ │ │ └── verify-request.ts │ │ │ ├── stripe/ │ │ │ │ ├── schema.ts │ │ │ │ ├── ui/ │ │ │ │ │ └── settings.tsx │ │ │ │ └── update-stripe-settings.ts │ │ │ ├── types.ts │ │ │ ├── utils.ts │ │ │ └── zapier/ │ │ │ └── ui/ │ │ │ └── settings.tsx │ │ ├── is-generic-email.ts │ │ ├── jackson.ts │ │ ├── links/ │ │ │ └── links-display.ts │ │ ├── middleware/ │ │ │ ├── admin.ts │ │ │ ├── api.ts │ │ │ ├── app.ts │ │ │ ├── create-link.ts │ │ │ ├── embed.ts │ │ │ ├── link.ts │ │ │ ├── new-link.ts │ │ │ ├── partners.ts │ │ │ ├── utils/ │ │ │ │ ├── app-redirect.ts │ │ │ │ ├── bots-list.ts │ │ │ │ ├── cache-deeplink-click-data.ts │ │ │ │ ├── crawl-bitly.ts │ │ │ │ ├── create-response-with-cookies.ts │ │ │ │ ├── detect-bot.ts │ │ │ │ ├── detect-qr.ts │ │ │ │ ├── get-default-partner.ts │ │ │ │ ├── get-default-workspace.ts │ │ │ │ ├── get-final-url.ts │ │ │ │ ├── get-identity-hash.ts │ │ │ │ ├── get-user-via-token.ts │ │ │ │ ├── get-workspace-product.ts │ │ │ │ ├── handle-not-found-link.ts │ │ │ │ ├── has-pending-invites.ts │ │ │ │ ├── is-google-play-store-url.ts │ │ │ │ ├── is-ios-app-store-url.ts │ │ │ │ ├── is-ip-in-range.ts │ │ │ │ ├── is-singular-tracking-url.ts │ │ │ │ ├── is-supported-custom-uri-scheme.ts │ │ │ │ ├── is-top-level-settings-redirect.ts │ │ │ │ ├── is-valid-internal-redirect.ts │ │ │ │ ├── parse.ts │ │ │ │ ├── partners-redirect.ts │ │ │ │ └── resolve-ab-test-url.ts │ │ │ └── workspaces.ts │ │ ├── names.ts │ │ ├── network/ │ │ │ ├── get-discoverability-requirements.ts │ │ │ ├── get-partner-profile-checklist-progress.ts │ │ │ └── program-categories.ts │ │ ├── next-auth.d.ts │ │ ├── onboarding/ │ │ │ └── types.ts │ │ ├── openapi/ │ │ │ ├── analytics/ │ │ │ │ └── index.ts │ │ │ ├── bounties/ │ │ │ │ ├── approve-bounty-submission.ts │ │ │ │ ├── index.ts │ │ │ │ ├── list-bounty-submissions.ts │ │ │ │ └── reject-bounty-submission.ts │ │ │ ├── commissions/ │ │ │ │ ├── index.ts │ │ │ │ ├── list-commissions.ts │ │ │ │ └── update-commission.ts │ │ │ ├── customers/ │ │ │ │ ├── delete-customer.ts │ │ │ │ ├── get-customer.ts │ │ │ │ ├── get-customers.ts │ │ │ │ ├── index.ts │ │ │ │ └── update-customer.ts │ │ │ ├── domains/ │ │ │ │ ├── check-domain-status.ts │ │ │ │ ├── create-domain.ts │ │ │ │ ├── delete-domain.ts │ │ │ │ ├── index.ts │ │ │ │ ├── list-domains.ts │ │ │ │ ├── register-domain.ts │ │ │ │ └── update-domain.ts │ │ │ ├── embed-tokens/ │ │ │ │ ├── create-referrals-embed-token.ts │ │ │ │ └── index.ts │ │ │ ├── events/ │ │ │ │ └── index.ts │ │ │ ├── folders/ │ │ │ │ ├── create-folder.ts │ │ │ │ ├── delete-folder.ts │ │ │ │ ├── index.ts │ │ │ │ ├── list-folders.ts │ │ │ │ └── update-folder.ts │ │ │ ├── index.ts │ │ │ ├── links/ │ │ │ │ ├── bulk-create-links.ts │ │ │ │ ├── bulk-delete-links.ts │ │ │ │ ├── bulk-update-links.ts │ │ │ │ ├── create-link.ts │ │ │ │ ├── delete-link.ts │ │ │ │ ├── get-link-info.ts │ │ │ │ ├── get-links-count.ts │ │ │ │ ├── get-links.ts │ │ │ │ ├── index.ts │ │ │ │ ├── update-link.ts │ │ │ │ └── upsert-link.ts │ │ │ ├── partners/ │ │ │ │ ├── ban-partner.ts │ │ │ │ ├── create-partner-link.ts │ │ │ │ ├── create-partner.ts │ │ │ │ ├── deactivate-partner.ts │ │ │ │ ├── index.ts │ │ │ │ ├── list-partners.ts │ │ │ │ ├── retrieve-analytics.ts │ │ │ │ ├── retrieve-partner-links.ts │ │ │ │ └── upsert-partner-link.ts │ │ │ ├── payouts/ │ │ │ │ ├── index.ts │ │ │ │ └── list-payouts.ts │ │ │ ├── qr/ │ │ │ │ └── index.ts │ │ │ ├── responses.ts │ │ │ ├── tags/ │ │ │ │ ├── create-tag.ts │ │ │ │ ├── delete-tag.ts │ │ │ │ ├── get-tags.ts │ │ │ │ ├── index.ts │ │ │ │ └── update-tag.ts │ │ │ └── track/ │ │ │ ├── index.ts │ │ │ ├── lead.ts │ │ │ ├── open.ts │ │ │ └── sale.ts │ │ ├── partners/ │ │ │ ├── aggregate-partner-links-stats.ts │ │ │ ├── approve-partner-enrollment.ts │ │ │ ├── calculate-payout-fee-with-waiver.ts │ │ │ ├── complete-program-applications.ts │ │ │ ├── construct-partner-link.ts │ │ │ ├── create-partner-commission.ts │ │ │ ├── create-stablecoin-payout.ts │ │ │ ├── create-stripe-transfer.ts │ │ │ ├── cutoff-period.ts │ │ │ ├── determine-partner-reward.ts │ │ │ ├── evaluate-application-requirements.ts │ │ │ ├── evaluate-reward-conditions.ts │ │ │ ├── format-application-form-data.ts │ │ │ ├── get-group-rewards-and-discount.ts │ │ │ ├── get-link-structure-options.ts │ │ │ ├── get-partner-bank-account.ts │ │ │ ├── get-payout-methods-for-country.ts │ │ │ ├── get-reward-amount.ts │ │ │ ├── partner-platforms.ts │ │ │ ├── partner-profile.ts │ │ │ ├── query-link-structure-help-text.tsx │ │ │ ├── sanitize-markdown.ts │ │ │ ├── sort-rewards-by-event-order.ts │ │ │ └── throw-if-no-partnerid-tenantid.ts │ │ ├── partnerstack/ │ │ │ ├── api.ts │ │ │ ├── import-commissions.ts │ │ │ ├── import-customers.ts │ │ │ ├── import-groups.ts │ │ │ ├── import-links.ts │ │ │ ├── import-partners.ts │ │ │ ├── importer.ts │ │ │ ├── schemas.ts │ │ │ ├── types.ts │ │ │ └── update-stripe-customers.ts │ │ ├── payouts/ │ │ │ ├── create-payouts-idempotency-key.ts │ │ │ ├── get-partner-payout-methods.ts │ │ │ ├── mark-payouts-as-processed.ts │ │ │ └── recompute-partner-payout-state.ts │ │ ├── paypal/ │ │ │ ├── create-batch-payout.ts │ │ │ ├── create-paypal-token.ts │ │ │ ├── env.ts │ │ │ ├── get-pending-payouts.ts │ │ │ ├── oauth.ts │ │ │ └── schema.ts │ │ ├── plain/ │ │ │ ├── client.ts │ │ │ ├── create-plain-thread.ts │ │ │ ├── sync-user-plan.ts │ │ │ └── upsert-plain-customer.ts │ │ ├── plan-capabilities.ts │ │ ├── planetscale/ │ │ │ ├── check-if-key-exists.ts │ │ │ ├── check-if-user-exists.ts │ │ │ ├── connection.ts │ │ │ ├── get-domain-via-edge.ts │ │ │ ├── get-link-via-edge.ts │ │ │ ├── get-link-with-partner.ts │ │ │ ├── get-partner-enrollment-info.ts │ │ │ ├── get-random-key.ts │ │ │ ├── get-shortlink-via-edge.ts │ │ │ ├── get-workspace-via-edge.ts │ │ │ ├── granularity.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── plans/ │ │ │ └── has-partner-access.ts │ │ ├── postback/ │ │ │ ├── api/ │ │ │ │ ├── get-postback-events.ts │ │ │ │ ├── postback-adapter-custom.ts │ │ │ │ ├── postback-adapter-slack.ts │ │ │ │ ├── postback-adapters.ts │ │ │ │ ├── postback-event-enrichers.ts │ │ │ │ ├── postback-event-transformers.ts │ │ │ │ ├── record-postback-event.ts │ │ │ │ ├── send-partner-postback.ts │ │ │ │ └── utils.ts │ │ │ ├── constants.ts │ │ │ ├── sample-events/ │ │ │ │ ├── commission-created.json │ │ │ │ ├── lead-created.json │ │ │ │ └── sale-created.json │ │ │ └── schemas.ts │ │ ├── qr/ │ │ │ ├── api.tsx │ │ │ ├── codegen.ts │ │ │ ├── constants.ts │ │ │ ├── index.tsx │ │ │ ├── types.ts │ │ │ └── utils.tsx │ │ ├── referrals/ │ │ │ └── constants.ts │ │ ├── rewardful/ │ │ │ ├── api.ts │ │ │ ├── import-affiliate-coupons.ts │ │ │ ├── import-campaigns.ts │ │ │ ├── import-commissions.ts │ │ │ ├── import-customers.ts │ │ │ ├── import-partners.ts │ │ │ ├── importer.ts │ │ │ ├── schemas.ts │ │ │ └── types.ts │ │ ├── social-utils.ts │ │ ├── storage.ts │ │ ├── stripe/ │ │ │ ├── cancel-subscription.ts │ │ │ ├── check-payment-method-mandate.ts │ │ │ ├── client.ts │ │ │ ├── coupon-discount-converter.ts │ │ │ ├── create-connected-account.ts │ │ │ ├── create-fx-quote.ts │ │ │ ├── create-payment-intent.ts │ │ │ ├── create-stripe-discount-code.ts │ │ │ ├── create-stripe-outbound-payment.ts │ │ │ ├── create-stripe-recipient-account-link.ts │ │ │ ├── create-stripe-recipient-account.ts │ │ │ ├── disable-stripe-discount-code.ts │ │ │ ├── fund-financial-account.ts │ │ │ ├── get-stripe-outbound-payment.ts │ │ │ ├── get-stripe-recipient-account.ts │ │ │ ├── get-stripe-recipient-payout-method.ts │ │ │ ├── index.ts │ │ │ ├── payment-methods.ts │ │ │ ├── stripe-v2-client.ts │ │ │ └── stripe-v2-schemas.ts │ │ ├── swr/ │ │ │ ├── mutate.ts │ │ │ ├── use-activity-logs.ts │ │ │ ├── use-api-mutation.ts │ │ │ ├── use-bounty-submissions-count.ts │ │ │ ├── use-bounty.ts │ │ │ ├── use-commission.ts │ │ │ ├── use-commissions-count.ts │ │ │ ├── use-commissions-timeseries.ts │ │ │ ├── use-current-folder-id.ts │ │ │ ├── use-customer-activity.ts │ │ │ ├── use-customer.ts │ │ │ ├── use-customers-count.ts │ │ │ ├── use-customers.ts │ │ │ ├── use-default-domains.ts │ │ │ ├── use-discount-codes.ts │ │ │ ├── use-discounts.ts │ │ │ ├── use-domain.ts │ │ │ ├── use-domains-count.ts │ │ │ ├── use-domains.ts │ │ │ ├── use-email-domains.ts │ │ │ ├── use-folder-access-requests.ts │ │ │ ├── use-folder-link-count.ts │ │ │ ├── use-folder-permissions.ts │ │ │ ├── use-folder-users.ts │ │ │ ├── use-folder.ts │ │ │ ├── use-folders-count.ts │ │ │ ├── use-folders.ts │ │ │ ├── use-fraud-events-count.ts │ │ │ ├── use-fraud-events-paginated.ts │ │ │ ├── use-fraud-events.ts │ │ │ ├── use-fraud-groups-count.ts │ │ │ ├── use-fraud-groups.ts │ │ │ ├── use-group-move-rules.ts │ │ │ ├── use-group.ts │ │ │ ├── use-groups-count.ts │ │ │ ├── use-groups.ts │ │ │ ├── use-guide.ts │ │ │ ├── use-integrations.ts │ │ │ ├── use-link.ts │ │ │ ├── use-links-count.ts │ │ │ ├── use-links.ts │ │ │ ├── use-network-partners-count.ts │ │ │ ├── use-network-programs-count.ts │ │ │ ├── use-partner-activity-logs.ts │ │ │ ├── use-partner-analytics.ts │ │ │ ├── use-partner-application-risks.ts │ │ │ ├── use-partner-bounty.ts │ │ │ ├── use-partner-comments-count.ts │ │ │ ├── use-partner-comments.ts │ │ │ ├── use-partner-cross-program-summary.ts │ │ │ ├── use-partner-customer.ts │ │ │ ├── use-partner-customers-count.ts │ │ │ ├── use-partner-customers.ts │ │ │ ├── use-partner-earnings-count.ts │ │ │ ├── use-partner-earnings-timeseries.ts │ │ │ ├── use-partner-group-default-links.ts │ │ │ ├── use-partner-links.ts │ │ │ ├── use-partner-messages-count.ts │ │ │ ├── use-partner-messages.ts │ │ │ ├── use-partner-network-invites-usage.ts │ │ │ ├── use-partner-payout-settings.ts │ │ │ ├── use-partner-payouts-count.ts │ │ │ ├── use-partner-payouts.ts │ │ │ ├── use-partner-profile.ts │ │ │ ├── use-partner-program-bounties.ts │ │ │ ├── use-partner-referrals-count.ts │ │ │ ├── use-partner-referrals.ts │ │ │ ├── use-partner-rewind.ts │ │ │ ├── use-partner.ts │ │ │ ├── use-partners-count-by-groupids.ts │ │ │ ├── use-partners-count.ts │ │ │ ├── use-partners.ts │ │ │ ├── use-payment-methods.ts │ │ │ ├── use-payout.ts │ │ │ ├── use-payouts-count.ts │ │ │ ├── use-payouts.ts │ │ │ ├── use-program-enrollment.ts │ │ │ ├── use-program-enrollments-count.ts │ │ │ ├── use-program-enrollments.ts │ │ │ ├── use-program-messages-count.ts │ │ │ ├── use-program-messages.ts │ │ │ ├── use-program-referrals-count.ts │ │ │ ├── use-program-resources.ts │ │ │ ├── use-program.ts │ │ │ ├── use-refresh-session.ts │ │ │ ├── use-rewardful-campaigns.ts │ │ │ ├── use-rewards.ts │ │ │ ├── use-saml.ts │ │ │ ├── use-scim.ts │ │ │ ├── use-tags-count.ts │ │ │ ├── use-tags.ts │ │ │ ├── use-usage-timeseries.ts │ │ │ ├── use-user.ts │ │ │ ├── use-webhook.ts │ │ │ ├── use-webhooks.ts │ │ │ ├── use-workspace-preferences.ts │ │ │ ├── use-workspace-store.ts │ │ │ ├── use-workspace-users.ts │ │ │ ├── use-workspace.ts │ │ │ └── use-workspaces.ts │ │ ├── tinybird/ │ │ │ ├── client.ts │ │ │ ├── get-click-event.ts │ │ │ ├── get-customer-events-tb.ts │ │ │ ├── get-import-error-logs.ts │ │ │ ├── get-lead-event.ts │ │ │ ├── get-lead-events.ts │ │ │ ├── get-top-links-by-countries.ts │ │ │ ├── get-webhook-events.ts │ │ │ ├── index.ts │ │ │ ├── log-conversion-events.ts │ │ │ ├── log-import-error.ts │ │ │ ├── record-click-zod.ts │ │ │ ├── record-click.ts │ │ │ ├── record-fake-click.ts │ │ │ ├── record-lead.ts │ │ │ ├── record-link.ts │ │ │ ├── record-sale.ts │ │ │ └── record-webhook-event.ts │ │ ├── tolt/ │ │ │ ├── api.ts │ │ │ ├── cleanup-partners.ts │ │ │ ├── import-commissions.ts │ │ │ ├── import-customers.ts │ │ │ ├── import-links.ts │ │ │ ├── import-partners.ts │ │ │ ├── importer.ts │ │ │ ├── schemas.ts │ │ │ ├── types.ts │ │ │ └── update-stripe-customers.ts │ │ ├── types.ts │ │ ├── upstash/ │ │ │ ├── format-redis-link.ts │ │ │ ├── index.ts │ │ │ ├── ratelimit-policy.ts │ │ │ ├── ratelimit.ts │ │ │ ├── record-metatags.ts │ │ │ ├── redis-streams.ts │ │ │ ├── redis.ts │ │ │ └── vector.ts │ │ ├── webhook/ │ │ │ ├── cache.ts │ │ │ ├── constants.ts │ │ │ ├── create-webhook.ts │ │ │ ├── failure.ts │ │ │ ├── get-webhooks.ts │ │ │ ├── handle-external-payout-event.ts │ │ │ ├── publish.ts │ │ │ ├── qstash.ts │ │ │ ├── sample-events/ │ │ │ │ ├── bounty-created.json │ │ │ │ ├── bounty-updated.json │ │ │ │ ├── commission-created.json │ │ │ │ ├── lead-created.json │ │ │ │ ├── link-clicked.json │ │ │ │ ├── link-created.json │ │ │ │ ├── link-deleted.json │ │ │ │ ├── link-updated.json │ │ │ │ ├── partner-application-submitted.json │ │ │ │ ├── partner-enrolled.json │ │ │ │ ├── payload.ts │ │ │ │ ├── payout-confirmed.json │ │ │ │ └── sale-created.json │ │ │ ├── schemas.ts │ │ │ ├── secret.ts │ │ │ ├── signature.ts │ │ │ ├── transform.ts │ │ │ ├── types.ts │ │ │ ├── update-webhook.ts │ │ │ ├── utils.ts │ │ │ └── validate-webhook.ts │ │ ├── well-known.ts │ │ ├── workspace-roles.ts │ │ └── zod/ │ │ └── schemas/ │ │ ├── activity-log.ts │ │ ├── analytics-response.ts │ │ ├── analytics.ts │ │ ├── auth.ts │ │ ├── bounties.ts │ │ ├── campaigns.ts │ │ ├── clicks.ts │ │ ├── commissions.ts │ │ ├── customer-activity.ts │ │ ├── customers.ts │ │ ├── dashboard.ts │ │ ├── deep-links.ts │ │ ├── deprecated.ts │ │ ├── discount.ts │ │ ├── domains.ts │ │ ├── email-domains.ts │ │ ├── folders.ts │ │ ├── fraud.ts │ │ ├── group-bounties.ts │ │ ├── group-with-program.ts │ │ ├── groups.ts │ │ ├── import-csv.ts │ │ ├── import-error-log.ts │ │ ├── integration.ts │ │ ├── invites.ts │ │ ├── invoices.ts │ │ ├── leads.ts │ │ ├── links.ts │ │ ├── messages.ts │ │ ├── misc.ts │ │ ├── oauth.ts │ │ ├── opens.ts │ │ ├── partner-network.ts │ │ ├── partner-profile.ts │ │ ├── partners.ts │ │ ├── payouts.ts │ │ ├── program-application-form.ts │ │ ├── program-application.ts │ │ ├── program-embed.ts │ │ ├── program-invite-email.ts │ │ ├── program-lander.ts │ │ ├── program-network.ts │ │ ├── program-onboarding.ts │ │ ├── program-resources.ts │ │ ├── programs.ts │ │ ├── qr.ts │ │ ├── referral-form.ts │ │ ├── referrals-embed.ts │ │ ├── referrals.ts │ │ ├── rewards.ts │ │ ├── sales.ts │ │ ├── schemas.ts │ │ ├── tags.ts │ │ ├── token.ts │ │ ├── usage.ts │ │ ├── users.ts │ │ ├── utils.ts │ │ ├── utm.ts │ │ ├── webhooks.ts │ │ ├── workflows.ts │ │ ├── workspace-preferences.ts │ │ └── workspaces.ts │ ├── middleware.ts │ ├── next.config.js │ ├── package.json │ ├── playwright/ │ │ ├── README.md │ │ ├── auth.setup.ts │ │ ├── env.ts │ │ ├── partner-login.spec.ts │ │ ├── partner-onboarding.spec.ts │ │ └── seed.ts │ ├── playwright.config.ts │ ├── postcss.config.js │ ├── public/ │ │ └── .well-known/ │ │ └── security.txt │ ├── scripts/ │ │ ├── analyze-bundle.ts │ │ ├── analyze-domains.ts │ │ ├── analyze-link-webhooks.ts │ │ ├── analyze-top-utms.ts │ │ ├── analyze-utm-usage.ts │ │ ├── annature/ │ │ │ └── import-domains.ts │ │ ├── buffer/ │ │ │ ├── delete-old-links.ts │ │ │ └── migrate-to-case-sensitive.ts │ │ ├── bulk-archive-links.ts │ │ ├── bulk-create-domains.ts │ │ ├── bulk-create-links.ts │ │ ├── bulk-delete-links.ts │ │ ├── bulk-update-links.ts │ │ ├── cache-popular-urls.ts │ │ ├── cal/ │ │ │ └── backfill-referral-links.ts │ │ ├── check-customers.ts │ │ ├── conversion-customers.ts │ │ ├── convert-case-sensitive.ts │ │ ├── convert-manual-commissions.ts │ │ ├── create-integration.ts │ │ ├── create-key.ts │ │ ├── deactivate-programs.ts │ │ ├── delete-link-cache.ts │ │ ├── dev/ │ │ │ ├── data.json │ │ │ └── seed.ts │ │ ├── download-links.ts │ │ ├── download-top-links.ts │ │ ├── dub-domain-users.ts │ │ ├── dub-partner-rewind.ts │ │ ├── dub-sdk.ts │ │ ├── dub-wrapped.ts │ │ ├── find-link.ts │ │ ├── find-workspaces-without-users.ts │ │ ├── fix-broken-applications.ts │ │ ├── fix-broken-link-tags.ts │ │ ├── fix-broken-partner-users.ts │ │ ├── fix-broken-root-domains.ts │ │ ├── fix-broken-workspace-users.ts │ │ ├── fix-usage-count.ts │ │ ├── format-clicks.ts │ │ ├── format-links.ts │ │ ├── framer/ │ │ │ ├── 1-process-framer-combined.ts │ │ │ ├── 2-sort-lead-events-by-date.ts │ │ │ ├── 3-backfill-tb-events.ts │ │ │ ├── backfill-commissions.ts │ │ │ ├── check-pending-payout-totals.ts │ │ │ ├── get-links-to-backfill.ts │ │ │ ├── get-remaining-links-to-backfill.ts │ │ │ ├── mark-commissions-paid.ts │ │ │ ├── mark-commissions-pending.ts │ │ │ ├── process-lead-events.ts │ │ │ └── tally-commissions.ts │ │ ├── generate-openapi.ts │ │ ├── get-api-users.ts │ │ ├── get-customers.ts │ │ ├── get-inactive-users.ts │ │ ├── get-premium-workspaces.ts │ │ ├── get-top-domains-for-links.ts │ │ ├── get-top-links-for-workspace.ts │ │ ├── get-users-by-links.ts │ │ ├── get-users-with-multiple-free-workspaces.ts │ │ ├── get-users.ts │ │ ├── get-workspaces-by-clicks.ts │ │ ├── get-workspaces-by-links.ts │ │ ├── hash-speed.ts │ │ ├── lua-convert.ts │ │ ├── migrate-commission-attributes.ts │ │ ├── migrations/ │ │ │ ├── backfill-application-groupId.ts │ │ │ ├── backfill-attribution.ts │ │ │ ├── backfill-banned-partner-links.ts │ │ │ ├── backfill-click-commissions.ts │ │ │ ├── backfill-commissions-rewardId.ts │ │ │ ├── backfill-cross-program-ban-fraud-events.ts │ │ │ ├── backfill-customer-first-sale.ts │ │ │ ├── backfill-customer-partner-ids.ts │ │ │ ├── backfill-customer-sales.ts │ │ │ ├── backfill-customer-subscription-cancellation.ts │ │ │ ├── backfill-customers.ts │ │ │ ├── backfill-dashboards.ts │ │ │ ├── backfill-deepview.ts │ │ │ ├── backfill-default-payout-method.ts │ │ │ ├── backfill-default-program-ids.ts │ │ │ ├── backfill-discoverableat.ts │ │ │ ├── backfill-domain-logo.ts │ │ │ ├── backfill-folders-limit.ts │ │ │ ├── backfill-folders-usage.ts │ │ │ ├── backfill-group-links-pgdl-acme.ts │ │ │ ├── backfill-group-links-pgdl.ts │ │ │ ├── backfill-group-links-settings.ts │ │ │ ├── backfill-group-settings.ts │ │ │ ├── backfill-invoice-paid-at.ts │ │ │ ├── backfill-invoice-payment-method.ts │ │ │ ├── backfill-invoice-prefixes.ts │ │ │ ├── backfill-link-commissions.ts │ │ │ ├── backfill-link-partner-group-ids.ts │ │ │ ├── backfill-link-stats.ts │ │ │ ├── backfill-link-webhooks.ts │ │ │ ├── backfill-missing-lead-commissions.ts │ │ │ ├── backfill-missing-sales.ts │ │ │ ├── backfill-notification-email-columns.ts │ │ │ ├── backfill-notification-email-deliveredat.ts │ │ │ ├── backfill-notification-preferences.ts │ │ │ ├── backfill-partner-groupid-logs.ts │ │ │ ├── backfill-partner-groups-verify.ts │ │ │ ├── backfill-partner-groups.ts │ │ │ ├── backfill-partner-platforms.ts │ │ │ ├── backfill-payout-initiated-at.ts │ │ │ ├── backfill-payout-method-hash.ts │ │ │ ├── backfill-payout-method.ts │ │ │ ├── backfill-payout-mode.ts │ │ │ ├── backfill-performance-bounty-submissions.ts │ │ │ ├── backfill-plain-customers.ts │ │ │ ├── backfill-program-categories.ts │ │ │ ├── backfill-program-marketplace-descriptions.ts │ │ │ ├── backfill-program-marketplace.ts │ │ │ ├── backfill-referral-links.ts │ │ │ ├── backfill-reward-activity-log.ts │ │ │ ├── backfill-reward-modifier-ids.ts │ │ │ ├── backfill-saml-sso.ts │ │ │ ├── backfill-short-links.ts │ │ │ ├── backfill-stripe-connect.ts │ │ │ ├── backfill-submission-completedat.ts │ │ │ ├── backfill-total-commissions.ts │ │ │ ├── migrate-application-formdata.ts │ │ │ ├── migrate-application-submissions.ts │ │ │ ├── migrate-bounties-submission-requirements.ts │ │ │ ├── migrate-campaign-message-to-markdown.ts │ │ │ ├── migrate-discounts.ts │ │ │ ├── migrate-domains.ts │ │ │ ├── migrate-images.ts │ │ │ ├── migrate-integrations.ts │ │ │ ├── migrate-lander-data.ts │ │ │ ├── migrate-links-to-workspaces.ts │ │ │ ├── migrate-partner-links.ts │ │ │ ├── migrate-partners-with-tenantids.ts │ │ │ ├── migrate-reward-amounts.ts │ │ │ ├── migrate-rewards-remainder.ts │ │ │ ├── migrate-rewards.ts │ │ │ ├── migrate-sales.ts │ │ │ ├── migrate-workflow-triggers.ts │ │ │ ├── remove-duplicate-notification-emails.ts │ │ │ ├── restore-group-ids.ts │ │ │ ├── sanitize-partner-platform.ts │ │ │ ├── update-discoverable-partners.ts │ │ │ └── update-payout-mode-to-internal.ts │ │ ├── misc/ │ │ │ ├── cleanup-fraud-events.ts │ │ │ ├── cleanup-generic-email-fraud-events.ts │ │ │ ├── fraud-campaign-ids.ts │ │ │ ├── remove-fraud-events.ts │ │ │ ├── restore-link-analytics.ts │ │ │ ├── restore-links.ts │ │ │ ├── restore-program-enrollments.ts │ │ │ └── restore-program-folders.ts │ │ ├── move-links-to-folder.ts │ │ ├── partners/ │ │ │ ├── aggregate-stats-seeding.ts │ │ │ ├── check-pending-paypal-payouts.ts │ │ │ ├── combine-payouts.ts │ │ │ ├── delete-partner-profile.ts │ │ │ ├── delete-partners-for-program.ts │ │ │ ├── delete-program-application.ts │ │ │ ├── delete-program-enrollment.ts │ │ │ ├── delete-program.ts │ │ │ ├── export-partners.ts │ │ │ ├── fix-partner-groups.ts │ │ │ ├── fix-partner-payouts.ts │ │ │ ├── get-largest-programs.ts │ │ │ ├── invalidate-partner-links.ts │ │ │ ├── merge-partner-profile.ts │ │ │ ├── update-links.ts │ │ │ ├── update-partner-country.ts │ │ │ └── update-payout-dates.ts │ │ ├── perplexity/ │ │ │ ├── backfill-leads.ts │ │ │ ├── backfill-tenantids.ts │ │ │ ├── ban-partners.ts │ │ │ ├── deactivate-partners.ts │ │ │ ├── move-partners.ts │ │ │ ├── partners-updated-countries.ts │ │ │ ├── review-bounties.ts │ │ │ ├── update-commissions.ts │ │ │ └── update-notifications.ts │ │ ├── persist-customer-avatars.ts │ │ ├── processed-payouts.ts │ │ ├── programs/ │ │ │ ├── 1-import-partners.ts │ │ │ ├── 2-import-partner-links.ts │ │ │ ├── 3-import-customer-leads.ts │ │ │ ├── 4-export-stripe-invoices.ts │ │ │ ├── 5-import-customer-sales.ts │ │ │ ├── add-to-marketplace.ts │ │ │ ├── backfill-custom-commissions.ts │ │ │ ├── backfill-discount-codes.ts │ │ │ ├── backfill-reuse-commission.ts │ │ │ ├── delete-program-enrollments.ts │ │ │ ├── update-commissions-canceled.ts │ │ │ └── update-commissions-paid.ts │ │ ├── referral-form-sample.json │ │ ├── remove-workspace-scopes.ts │ │ ├── restore-backup.ts │ │ ├── revert-partner-payout-demo.ts │ │ ├── reward-conditions.ts │ │ ├── run.ts │ │ ├── seed-invite-codes.ts │ │ ├── seed-support-embeddings.ts │ │ ├── send-batch-emails.ts │ │ ├── sent-mail-reset.ts │ │ ├── ship30/ │ │ │ └── backfill-leads.ts │ │ ├── sitemap-importer.ts │ │ ├── stripe/ │ │ │ ├── backfill-stripe-webhook-events.ts │ │ │ ├── backfill-trace-id.ts │ │ │ ├── connect-client.ts │ │ │ ├── delete-connected-account.ts │ │ │ ├── fix-processed-payouts.ts │ │ │ ├── get-connected-customer.ts │ │ │ ├── manual-payouts.ts │ │ │ ├── retrieve-balance.ts │ │ │ ├── search-customers.ts │ │ │ ├── update-payouts-schedule.ts │ │ │ └── update-stripe-customers.ts │ │ ├── sync-conversions.ts │ │ ├── sync-domain-clicks.ts │ │ ├── sync-expired-links.ts │ │ ├── sync-limits.ts │ │ ├── sync-link-clicks.ts │ │ ├── sync-link-tags.ts │ │ ├── sync-links-metadata.ts │ │ ├── sync-tag-analytics.ts │ │ ├── tella/ │ │ │ ├── remind-applications.ts │ │ │ ├── update-commission-flat.ts │ │ │ ├── update-commission-percentage.ts │ │ │ ├── update-commissions.ts │ │ │ └── update-reward-tier.ts │ │ ├── test-paypal-payouts.ts │ │ ├── testimonial/ │ │ │ ├── final-sync-commissions.ts │ │ │ ├── sync-commissions.ts │ │ │ └── update-commissions.ts │ │ ├── tinybird/ │ │ │ ├── delete-lead-event.ts │ │ │ ├── delete-links.ts │ │ │ ├── delete-sale-event.ts │ │ │ ├── update-click-event.ts │ │ │ ├── update-lead-event.ts │ │ │ └── update-sale-event.ts │ │ ├── trigger-update-partner-stats.ts │ │ ├── unban-links.ts │ │ ├── update-integrations.ts │ │ ├── update-link-owner.ts │ │ ├── update-not-found.ts │ │ ├── update-payment-failed.ts │ │ ├── update-payouts-limits.ts │ │ ├── update-referral-form-data.ts │ │ ├── update-spam-links.ts │ │ ├── update-subscribers.ts │ │ ├── update-user-notifications.ts │ │ ├── update-webhook-cache.ts │ │ ├── update-workspace-dates.ts │ │ ├── update-workspace-tags.ts │ │ ├── upload-users.ts │ │ └── wispr-flow/ │ │ └── update-links.ts │ ├── styles/ │ │ ├── fonts.ts │ │ └── globals.css │ ├── tailwind.config.ts │ ├── tests/ │ │ ├── analytics/ │ │ │ ├── advanced-filter-helpers.test.ts │ │ │ ├── get-analytics-advanced.test.ts │ │ │ ├── get-analytics.test.ts │ │ │ ├── get-events.test.ts │ │ │ ├── metadata-query-parser.test.ts │ │ │ ├── partner-analytics.test.ts │ │ │ └── public-analytics-dashboard.test.ts │ │ ├── bounties/ │ │ │ └── index.test.ts │ │ ├── campaigns/ │ │ │ └── index.test.ts │ │ ├── commissions/ │ │ │ ├── index.test.ts │ │ │ └── pagination.test.ts │ │ ├── customers/ │ │ │ ├── index.test.ts │ │ │ └── pagination.test.ts │ │ ├── discounts/ │ │ │ └── index.test.ts │ │ ├── domains/ │ │ │ └── index.test.ts │ │ ├── embed-tokens/ │ │ │ └── referrals.test.ts │ │ ├── folders/ │ │ │ └── index.test.ts │ │ ├── fraud/ │ │ │ ├── fraud-groups.test.ts │ │ │ └── index.test.ts │ │ ├── links/ │ │ │ ├── bulk-create-link.test.ts │ │ │ ├── bulk-delete-link.test.ts │ │ │ ├── bulk-update-link.test.ts │ │ │ ├── count-links.test.ts │ │ │ ├── create-link-error.test.ts │ │ │ ├── create-link.test.ts │ │ │ ├── delete-link.test.ts │ │ │ ├── folder-link-access.test.ts │ │ │ ├── list-links.test.ts │ │ │ ├── retrieve-link.test.ts │ │ │ ├── retrieve-metatags.test.ts │ │ │ ├── update-link.test.ts │ │ │ └── upsert-link.test.ts │ │ ├── misc/ │ │ │ ├── allowed-hostnames.test.ts │ │ │ ├── base64.test.ts │ │ │ ├── calculate-payout-fee-with-waiver.test.ts │ │ │ ├── case-sensitive-keys.test.ts │ │ │ ├── check-eligibility-requirements.test.ts │ │ │ ├── create-id.test.ts │ │ │ ├── eligibility-condition-schema.test.ts │ │ │ ├── email-domain-validation.test.ts │ │ │ ├── filter-active-group-bounties.test.ts │ │ │ ├── interpolate-email-template.test.ts │ │ │ └── ip-cidr.test.ts │ │ ├── partner-groups/ │ │ │ └── index.test.ts │ │ ├── partners/ │ │ │ ├── analytics.test.ts │ │ │ ├── ban-partner.test.ts │ │ │ ├── create-partner-link.test.ts │ │ │ ├── create-partner.test.ts │ │ │ ├── deactivate-partner.test.ts │ │ │ ├── list-partners.test.ts │ │ │ ├── resource.ts │ │ │ └── upsert-partner-link.test.ts │ │ ├── payouts/ │ │ │ └── index.test.ts │ │ ├── redirects/ │ │ │ └── index.test.ts │ │ ├── rewards/ │ │ │ ├── click-reward.test.ts │ │ │ ├── lead-reward.test.ts │ │ │ ├── reward-conditions.test.ts │ │ │ └── sale-reward.test.ts │ │ ├── setupTests.ts │ │ ├── tags/ │ │ │ ├── create-tag-error.test.ts │ │ │ ├── create-tag.test.ts │ │ │ └── list-tags.test.ts │ │ ├── tracks/ │ │ │ ├── track-click.test.ts │ │ │ ├── track-lead-client.test.ts │ │ │ ├── track-lead.test.ts │ │ │ ├── track-open.test.ts │ │ │ ├── track-sale-client.test.ts │ │ │ └── track-sale.test.ts │ │ ├── utils/ │ │ │ ├── env.ts │ │ │ ├── fetch-partner.ts │ │ │ ├── helpers.ts │ │ │ ├── http.ts │ │ │ ├── integration-member.ts │ │ │ ├── integration-old.ts │ │ │ ├── integration.ts │ │ │ ├── resource.ts │ │ │ ├── schema.ts │ │ │ └── verify-commission.ts │ │ ├── webhooks/ │ │ │ └── index.test.ts │ │ ├── workflows/ │ │ │ ├── award-bounty-workflow.test.ts │ │ │ ├── e2e-endpoints-guard.test.ts │ │ │ ├── move-group-workflow.test.ts │ │ │ ├── send-campaign-workflow.test.ts │ │ │ └── utils/ │ │ │ ├── delete-bounty-and-submissions.ts │ │ │ ├── track-e2e-lead.ts │ │ │ ├── verify-bounty-submission.ts │ │ │ ├── verify-campaign-sent.ts │ │ │ └── verify-partner-group-move.ts │ │ └── workspaces/ │ │ ├── retrieve-workspace.error.test.ts │ │ └── retrieve-workspace.test.ts │ ├── tsconfig.json │ ├── ui/ │ │ ├── account/ │ │ │ ├── delete-account.tsx │ │ │ ├── update-default-workspace.tsx │ │ │ ├── update-subscription.tsx │ │ │ ├── upload-avatar.tsx │ │ │ └── user-id.tsx │ │ ├── activity-logs/ │ │ │ ├── action-renderers/ │ │ │ │ ├── partner-group-changed-renderer.tsx │ │ │ │ ├── referral-created-renderer.tsx │ │ │ │ ├── referral-status-changed-renderer.tsx │ │ │ │ └── reward-activity-renderer.tsx │ │ │ ├── activity-entry-chips.tsx │ │ │ ├── activity-feed.tsx │ │ │ ├── activity-log-context.tsx │ │ │ ├── activity-log-description.tsx │ │ │ ├── activity-log-registry.tsx │ │ │ ├── partner-group-activity-item.tsx │ │ │ ├── partner-group-activity-section.tsx │ │ │ ├── partner-group-history-sheet.tsx │ │ │ ├── partner-referral-activity-section.tsx │ │ │ ├── referral-activity-item.tsx │ │ │ ├── referral-activity-section.tsx │ │ │ ├── reward-activity-item.tsx │ │ │ ├── reward-activity-section.tsx │ │ │ └── reward-history-sheet.tsx │ │ ├── analytics/ │ │ │ ├── analytics-area-chart.tsx │ │ │ ├── analytics-card.tsx │ │ │ ├── analytics-export-button.tsx │ │ │ ├── analytics-funnel-chart.tsx │ │ │ ├── analytics-loading-spinner.tsx │ │ │ ├── analytics-options.tsx │ │ │ ├── analytics-provider.tsx │ │ │ ├── analytics-tabs.tsx │ │ │ ├── bar-list.tsx │ │ │ ├── chart-section.tsx │ │ │ ├── chart-view-switcher.tsx │ │ │ ├── continent-icon.tsx │ │ │ ├── device-icon.tsx │ │ │ ├── device-section.tsx │ │ │ ├── events/ │ │ │ │ ├── events-export-button.tsx │ │ │ │ ├── events-provider.tsx │ │ │ │ ├── events-table.tsx │ │ │ │ ├── events-tabs.tsx │ │ │ │ ├── example-data.ts │ │ │ │ ├── index.tsx │ │ │ │ ├── metadata-viewer.tsx │ │ │ │ └── row-menu-button.tsx │ │ │ ├── index.tsx │ │ │ ├── link-preview.tsx │ │ │ ├── location-section.tsx │ │ │ ├── partner-section.tsx │ │ │ ├── referrer-icon.tsx │ │ │ ├── referrers-utms.tsx │ │ │ ├── share-button.tsx │ │ │ ├── toggle.tsx │ │ │ ├── top-links.tsx │ │ │ ├── trigger-display.tsx │ │ │ ├── use-analytics-connected-status.ts │ │ │ ├── use-analytics-filters.tsx │ │ │ ├── use-analytics-query.tsx │ │ │ └── utils.ts │ │ ├── auth/ │ │ │ ├── auth-alternative-banner.tsx │ │ │ ├── auth-methods-separator.tsx │ │ │ ├── forgot-password-form.tsx │ │ │ ├── login/ │ │ │ │ ├── email-sign-in.tsx │ │ │ │ ├── framer-button.tsx │ │ │ │ ├── github-button.tsx │ │ │ │ ├── google-button.tsx │ │ │ │ ├── login-form.tsx │ │ │ │ └── sso-sign-in.tsx │ │ │ ├── register/ │ │ │ │ ├── context.tsx │ │ │ │ ├── resend-otp.tsx │ │ │ │ ├── signup-email.tsx │ │ │ │ ├── signup-form.tsx │ │ │ │ ├── signup-oauth.tsx │ │ │ │ └── verify-email-form.tsx │ │ │ └── reset-password-form.tsx │ │ ├── colors.ts │ │ ├── customers/ │ │ │ ├── customer-activity-list.tsx │ │ │ ├── customer-avatar.tsx │ │ │ ├── customer-details-column.tsx │ │ │ ├── customer-partner-earnings-table.tsx │ │ │ ├── customer-row-item.tsx │ │ │ ├── customer-sales-table.tsx │ │ │ ├── customer-selector.tsx │ │ │ ├── customer-stats.tsx │ │ │ ├── customer-tabs.tsx │ │ │ ├── customers-table/ │ │ │ │ ├── customers-table.tsx │ │ │ │ ├── example-data.ts │ │ │ │ └── use-customer-filters.tsx │ │ │ └── export-customers-button.tsx │ │ ├── domains/ │ │ │ ├── add-edit-domain-form.tsx │ │ │ ├── domain-card-placeholder.tsx │ │ │ ├── domain-card-title-column.tsx │ │ │ ├── domain-card.tsx │ │ │ ├── domain-configuration.tsx │ │ │ ├── domain-selector.tsx │ │ │ ├── free-dot-link-banner.tsx │ │ │ └── register-domain-form.tsx │ │ ├── dub-partners-logo.tsx │ │ ├── folders/ │ │ │ ├── add-folder-form.tsx │ │ │ ├── edit-folder-form.tsx │ │ │ ├── edit-folder-sheet.tsx │ │ │ ├── folder-actions.tsx │ │ │ ├── folder-card-placeholder.tsx │ │ │ ├── folder-card.tsx │ │ │ ├── folder-dropdown.tsx │ │ │ ├── folder-icon.tsx │ │ │ ├── folder-info-panel.tsx │ │ │ ├── move-link-form.tsx │ │ │ ├── rename-folder-form.tsx │ │ │ ├── request-edit-button.tsx │ │ │ ├── simple-folder-card.tsx │ │ │ └── utils.ts │ │ ├── guides/ │ │ │ ├── guide-action-button.tsx │ │ │ ├── guide-list.tsx │ │ │ ├── guide-selector.tsx │ │ │ ├── guide.tsx │ │ │ ├── icons/ │ │ │ │ ├── appwrite.tsx │ │ │ │ ├── auth-js.tsx │ │ │ │ ├── auth0.tsx │ │ │ │ ├── better-auth.tsx │ │ │ │ ├── clerk.tsx │ │ │ │ ├── code-editor.tsx │ │ │ │ ├── custom.tsx │ │ │ │ ├── framer.tsx │ │ │ │ ├── gtm.tsx │ │ │ │ ├── next-auth.tsx │ │ │ │ ├── react.tsx │ │ │ │ ├── segment.tsx │ │ │ │ ├── shopify.tsx │ │ │ │ ├── supabase.tsx │ │ │ │ ├── webflow.tsx │ │ │ │ └── wordpress.tsx │ │ │ ├── install-stripe-integration-button.tsx │ │ │ ├── integrations.ts │ │ │ └── markdown.tsx │ │ ├── integrations/ │ │ │ ├── integration-card.tsx │ │ │ └── integration-logo.tsx │ │ ├── layout/ │ │ │ ├── auth-layout.tsx │ │ │ ├── changelog-popup.tsx │ │ │ ├── layout-loader.tsx │ │ │ ├── main-nav.tsx │ │ │ ├── page-content/ │ │ │ │ ├── index.tsx │ │ │ │ ├── nav-button.tsx │ │ │ │ ├── page-content-header.tsx │ │ │ │ ├── page-content-old.tsx │ │ │ │ ├── page-content-with-side-panel.tsx │ │ │ │ └── toggle-side-panel-button.tsx │ │ │ ├── page-nav-tabs.tsx │ │ │ ├── page-width-wrapper.tsx │ │ │ ├── settings-layout.tsx │ │ │ ├── sidebar/ │ │ │ │ ├── affiliate-program-popup.tsx │ │ │ │ ├── app-sidebar-nav.tsx │ │ │ │ ├── dub-partners-popup.tsx │ │ │ │ ├── help-button.tsx │ │ │ │ ├── icons/ │ │ │ │ │ ├── compass.tsx │ │ │ │ │ ├── connected-dots4.tsx │ │ │ │ │ ├── cursor-rays.tsx │ │ │ │ │ ├── gear.tsx │ │ │ │ │ ├── hyperlink.tsx │ │ │ │ │ ├── lines-y.tsx │ │ │ │ │ └── user.tsx │ │ │ │ ├── news-rsc.tsx │ │ │ │ ├── news.tsx │ │ │ │ ├── partner-program-dropdown.tsx │ │ │ │ ├── partners-sidebar-nav.tsx │ │ │ │ ├── payout-stats.tsx │ │ │ │ ├── program-help-support.tsx │ │ │ │ ├── refer-button.tsx │ │ │ │ ├── sidebar-nav.tsx │ │ │ │ ├── sidebar-usage.tsx │ │ │ │ ├── use-program-applications-count.tsx │ │ │ │ ├── user-dropdown.tsx │ │ │ │ ├── workspace-dropdown.tsx │ │ │ │ └── year-in-review-card.tsx │ │ │ ├── toolbar/ │ │ │ │ ├── onboarding/ │ │ │ │ │ └── onboarding-button.tsx │ │ │ │ └── toolbar.tsx │ │ │ ├── upgrade-banner.tsx │ │ │ └── user-survey/ │ │ │ ├── index.tsx │ │ │ └── survey-form.tsx │ │ ├── links/ │ │ │ ├── archived-links-hint.tsx │ │ │ ├── comments-badge.tsx │ │ │ ├── destination-url-input.tsx │ │ │ ├── disabled-link-tooltip.tsx │ │ │ ├── link-analytics-badge.tsx │ │ │ ├── link-builder/ │ │ │ │ ├── constants.ts │ │ │ │ ├── controls/ │ │ │ │ │ ├── link-builder-destination-url-input.tsx │ │ │ │ │ ├── link-builder-folder-selector.tsx │ │ │ │ │ ├── link-builder-short-link-input.tsx │ │ │ │ │ └── link-comments-input.tsx │ │ │ │ ├── conversion-tracking-toggle.tsx │ │ │ │ ├── draft-controls.tsx │ │ │ │ ├── link-action-bar.tsx │ │ │ │ ├── link-builder-header.tsx │ │ │ │ ├── link-builder-provider.tsx │ │ │ │ ├── link-creator-info.tsx │ │ │ │ ├── link-feature-buttons.tsx │ │ │ │ ├── link-partner-details.tsx │ │ │ │ ├── link-preview.tsx │ │ │ │ ├── more-dropdown.tsx │ │ │ │ ├── multi-tags-icon.tsx │ │ │ │ ├── options-list.tsx │ │ │ │ ├── qr-code-preview.tsx │ │ │ │ ├── tag-select.tsx │ │ │ │ ├── use-link-builder-keyboard-shortcut.ts │ │ │ │ ├── use-link-builder-submit.tsx │ │ │ │ ├── use-metatags.ts │ │ │ │ └── utm-templates-button.tsx │ │ │ ├── link-card-placeholder.tsx │ │ │ ├── link-card.tsx │ │ │ ├── link-controls.tsx │ │ │ ├── link-details-column.tsx │ │ │ ├── link-display.tsx │ │ │ ├── link-icon.tsx │ │ │ ├── link-not-found.tsx │ │ │ ├── link-selection-provider.tsx │ │ │ ├── link-sort.tsx │ │ │ ├── link-tests.tsx │ │ │ ├── link-title-column.tsx │ │ │ ├── links-container.tsx │ │ │ ├── links-display-provider.tsx │ │ │ ├── links-toolbar.tsx │ │ │ ├── short-link-input.tsx │ │ │ ├── simple-link-card.tsx │ │ │ ├── tag-badge.tsx │ │ │ ├── tests-badge.tsx │ │ │ ├── use-available-domains.ts │ │ │ ├── use-folder-filter-options.ts │ │ │ └── use-link-filters.tsx │ │ ├── messages/ │ │ │ ├── message-markdown.tsx │ │ │ ├── messages-context.tsx │ │ │ ├── messages-list.tsx │ │ │ ├── messages-panel.tsx │ │ │ └── toggle-side-panel-button.tsx │ │ ├── modals/ │ │ │ ├── add-customer-modal.tsx │ │ │ ├── add-discount-code-modal.tsx │ │ │ ├── add-edit-domain-modal.tsx │ │ │ ├── add-edit-email-domain-modal.tsx │ │ │ ├── add-edit-tag-modal.tsx │ │ │ ├── add-edit-token-modal.tsx │ │ │ ├── add-edit-utm-template.modal.tsx │ │ │ ├── add-folder-modal.tsx │ │ │ ├── add-partner-link-modal.tsx │ │ │ ├── add-payment-method-modal.tsx │ │ │ ├── add-workspace-modal.tsx │ │ │ ├── application-settings-modal.tsx │ │ │ ├── archive-domain-modal.tsx │ │ │ ├── archive-link-modal.tsx │ │ │ ├── archive-partner-modal.tsx │ │ │ ├── ban-partner-modal.tsx │ │ │ ├── bulk-approve-partners-modal.tsx │ │ │ ├── bulk-archive-partners-modal.tsx │ │ │ ├── bulk-ban-partners-modal.tsx │ │ │ ├── bulk-deactivate-partners-modal.tsx │ │ │ ├── bulk-reject-partners-modal.tsx │ │ │ ├── bulk-resolve-fraud-groups-modal.tsx │ │ │ ├── change-group-modal.tsx │ │ │ ├── confirm-approve-bounty-submission-modal.tsx │ │ │ ├── confirm-modal.tsx │ │ │ ├── confirm-referral-status-change-modal.tsx │ │ │ ├── confirm-set-default-group-modal.tsx │ │ │ ├── deactivate-partner-modal.tsx │ │ │ ├── delete-account-modal.tsx │ │ │ ├── delete-discount-code-modal.tsx │ │ │ ├── delete-domain-modal.tsx │ │ │ ├── delete-email-domain-modal.tsx │ │ │ ├── delete-folder-modal.tsx │ │ │ ├── delete-group-modal.tsx │ │ │ ├── delete-link-modal.tsx │ │ │ ├── delete-partner-link-modal.tsx │ │ │ ├── delete-token-modal.tsx │ │ │ ├── delete-webhook-modal.tsx │ │ │ ├── delete-workspace-modal.tsx │ │ │ ├── disable-fraud-rules-modal.tsx │ │ │ ├── domain-auto-renewal-modal.tsx │ │ │ ├── domain-verification-modal.tsx │ │ │ ├── dot-link-offer-modal.tsx │ │ │ ├── edit-customer-modal.tsx │ │ │ ├── edit-referral-modal.tsx │ │ │ ├── export-applications-modal.tsx │ │ │ ├── export-commissions-modal.tsx │ │ │ ├── export-customers-modal.tsx │ │ │ ├── export-links-modal.tsx │ │ │ ├── export-partners-modal.tsx │ │ │ ├── google-oauth-modal.tsx │ │ │ ├── import-bitly-modal.tsx │ │ │ ├── import-csv-modal/ │ │ │ │ ├── field-mapping.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── select-file.tsx │ │ │ ├── import-firstpromoter-modal.tsx │ │ │ ├── import-partnerstack-modal.tsx │ │ │ ├── import-rebrandly-modal.tsx │ │ │ ├── import-rewardful-modal.tsx │ │ │ ├── import-short-modal.tsx │ │ │ ├── import-tolt-modal.tsx │ │ │ ├── invite-code-modal.tsx │ │ │ ├── invite-partner-user-modal.tsx │ │ │ ├── invite-referral-modal.tsx │ │ │ ├── invite-workspace-user-modal.tsx │ │ │ ├── link-builder/ │ │ │ │ ├── ab-testing/ │ │ │ │ │ ├── ab-testing-modal.tsx │ │ │ │ │ ├── end-ab-testing-modal.tsx │ │ │ │ │ └── traffic-split-slider.tsx │ │ │ │ ├── ab-testing-modal.tsx │ │ │ │ ├── advanced-modal.tsx │ │ │ │ ├── expiration-modal.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── og-modal.tsx │ │ │ │ ├── partners-modal.tsx │ │ │ │ ├── password-modal.tsx │ │ │ │ ├── targeting-modal.tsx │ │ │ │ ├── unsplash-search.tsx │ │ │ │ ├── use-link-drafts.ts │ │ │ │ ├── utm-modal.tsx │ │ │ │ ├── utm-templates-combo.tsx │ │ │ │ └── webhooks-modal.tsx │ │ │ ├── link-conversion-tracking-modal.tsx │ │ │ ├── link-qr-modal.tsx │ │ │ ├── manage-usage-modal.tsx │ │ │ ├── modal-provider.tsx │ │ │ ├── move-link-to-folder-modal.tsx │ │ │ ├── oauth-app-created-modal.tsx │ │ │ ├── partner-link-modal.tsx │ │ │ ├── partner-link-qr-modal.tsx │ │ │ ├── plan-change-confirmation-modal.tsx │ │ │ ├── primary-domain-modal.tsx │ │ │ ├── program-welcome-modal.tsx │ │ │ ├── prompt-modal.tsx │ │ │ ├── reactivate-partner-modal.tsx │ │ │ ├── register-domain-modal.tsx │ │ │ ├── register-domain-success-modal.tsx │ │ │ ├── reject-partner-application-modal.tsx │ │ │ ├── remove-oauth-app-modal.tsx │ │ │ ├── remove-partner-user-modal.tsx │ │ │ ├── remove-saml-modal.tsx │ │ │ ├── remove-scim-modal.tsx │ │ │ ├── remove-workspace-user-modal.tsx │ │ │ ├── rename-folder-modal.tsx │ │ │ ├── saml-modal.tsx │ │ │ ├── scim-modal.tsx │ │ │ ├── send-test-webhook-modal.tsx │ │ │ ├── set-default-folder-modal.tsx │ │ │ ├── share-dashboard-modal.tsx │ │ │ ├── social-verification-by-code-modal.tsx │ │ │ ├── submit-oauth-app-modal.tsx │ │ │ ├── tag-link-modal.tsx │ │ │ ├── token-created-modal.tsx │ │ │ ├── transfer-domain-modal.tsx │ │ │ ├── transfer-link-modal.tsx │ │ │ ├── unban-partner-modal.tsx │ │ │ ├── uninstall-integration-modal.tsx │ │ │ ├── update-partner-user-modal.tsx │ │ │ ├── update-workspace-user-role.tsx │ │ │ └── upgraded-modal.tsx │ │ ├── oauth-apps/ │ │ │ ├── add-edit-app-form.tsx │ │ │ ├── add-edit-integration-form.tsx │ │ │ ├── oauth-app-card.tsx │ │ │ ├── oauth-app-credentials.tsx │ │ │ └── oauth-app-placeholder.tsx │ │ ├── partners/ │ │ │ ├── activity-event.tsx │ │ │ ├── bounties/ │ │ │ │ ├── bounty-description.tsx │ │ │ │ ├── bounty-incremental-bonus-tooltip.tsx │ │ │ │ ├── bounty-performance.tsx │ │ │ │ ├── bounty-platform-icons.ts │ │ │ │ ├── bounty-progress-bar-row.tsx │ │ │ │ ├── bounty-reward-criteria.tsx │ │ │ │ ├── bounty-reward-description.tsx │ │ │ │ ├── bounty-social-content-preview.tsx │ │ │ │ ├── bounty-social-content.tsx │ │ │ │ ├── bounty-social-metrics-rewards-table.tsx │ │ │ │ ├── bounty-status-badge.tsx │ │ │ │ ├── bounty-submission-details-sheet.tsx │ │ │ │ ├── bounty-submission-requirements.tsx │ │ │ │ ├── bounty-thumbnail-image.tsx │ │ │ │ ├── claim-bounty-context.tsx │ │ │ │ ├── claim-bounty-sheet.tsx │ │ │ │ ├── reject-bounty-submission-modal.tsx │ │ │ │ ├── use-claim-bounty-form.ts │ │ │ │ └── use-social-content.ts │ │ │ ├── comission-type-icon.tsx │ │ │ ├── commission-row-menu.tsx │ │ │ ├── commission-status-badges.tsx │ │ │ ├── commission-type-badge.tsx │ │ │ ├── confirm-payouts-sheet.tsx │ │ │ ├── constants.ts │ │ │ ├── conversion-score-icon.tsx │ │ │ ├── country-combobox.tsx │ │ │ ├── discounts/ │ │ │ │ ├── add-edit-discount-sheet.tsx │ │ │ │ └── discount-code-badge.tsx │ │ │ ├── eligibility-requirements.tsx │ │ │ ├── external-payouts-indicator.tsx │ │ │ ├── format-discount-description.ts │ │ │ ├── format-reward-description.ts │ │ │ ├── fraud-risks/ │ │ │ │ ├── commissions-on-hold-table.tsx │ │ │ │ ├── fraud-disclaimer-banner.tsx │ │ │ │ ├── fraud-events-tables/ │ │ │ │ │ ├── fraud-cross-program-ban-table.tsx │ │ │ │ │ ├── fraud-matching-customer-email-table.tsx │ │ │ │ │ ├── fraud-paid-traffic-detected-table.tsx │ │ │ │ │ ├── fraud-partner-info-table.tsx │ │ │ │ │ ├── fraud-referral-source-banned-table.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── fraud-review-sheet.tsx │ │ │ │ ├── partner-application-fraud-severity-indicator.tsx │ │ │ │ ├── partner-application-risk-summary-modal.tsx │ │ │ │ ├── partner-application-risk-summary.tsx │ │ │ │ ├── partner-cross-program-summary.tsx │ │ │ │ ├── partner-fraud-banner.tsx │ │ │ │ ├── partner-fraud-indicator.tsx │ │ │ │ ├── resolve-fraud-group-modal.tsx │ │ │ │ └── resolved-fraud-group-table.tsx │ │ │ ├── groups/ │ │ │ │ ├── design/ │ │ │ │ │ ├── application-form/ │ │ │ │ │ │ ├── application-hero-preview.tsx │ │ │ │ │ │ ├── fields/ │ │ │ │ │ │ │ ├── form-control.tsx │ │ │ │ │ │ │ ├── image-upload-field.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── long-text-field.tsx │ │ │ │ │ │ │ ├── max-character-count.tsx │ │ │ │ │ │ │ ├── multiple-choice-field.tsx │ │ │ │ │ │ │ ├── select-field.tsx │ │ │ │ │ │ │ ├── short-text-field.tsx │ │ │ │ │ │ │ └── website-and-socials-field.tsx │ │ │ │ │ │ ├── form-data-for-application-form-data.ts │ │ │ │ │ │ ├── modals/ │ │ │ │ │ │ │ ├── add-field-modal.tsx │ │ │ │ │ │ │ ├── edit-application-hero-modal.tsx │ │ │ │ │ │ │ ├── generate-lander-modal.tsx │ │ │ │ │ │ │ ├── image-upload-field-modal.tsx │ │ │ │ │ │ │ ├── long-text-field-modal.tsx │ │ │ │ │ │ │ ├── multiple-choice-field-modal.tsx │ │ │ │ │ │ │ ├── select-field-modal.tsx │ │ │ │ │ │ │ ├── short-text-field-modal.tsx │ │ │ │ │ │ │ └── website-and-socials-field-modal.tsx │ │ │ │ │ │ ├── program-application-form.tsx │ │ │ │ │ │ ├── program-terms-preview.tsx │ │ │ │ │ │ └── required-fields-preview.tsx │ │ │ │ │ ├── branding-context-provider.tsx │ │ │ │ │ ├── branding-form.tsx │ │ │ │ │ ├── branding-settings-form.tsx │ │ │ │ │ ├── edit-list.tsx │ │ │ │ │ ├── lander/ │ │ │ │ │ │ ├── lander-ai-banner.tsx │ │ │ │ │ │ ├── lander-preview-controls.tsx │ │ │ │ │ │ └── modals/ │ │ │ │ │ │ ├── accordion-block-modal.tsx │ │ │ │ │ │ ├── add-block-modal.tsx │ │ │ │ │ │ ├── earnings-calculator-block-modal.tsx │ │ │ │ │ │ ├── edit-hero-modal.tsx │ │ │ │ │ │ ├── files-block-modal.tsx │ │ │ │ │ │ ├── generate-lander-modal.tsx │ │ │ │ │ │ ├── image-block-modal.tsx │ │ │ │ │ │ └── text-block-modal.tsx │ │ │ │ │ ├── preview-window.tsx │ │ │ │ │ ├── previews/ │ │ │ │ │ │ ├── application-preview.tsx │ │ │ │ │ │ ├── embed-preview.tsx │ │ │ │ │ │ ├── lander-preview.tsx │ │ │ │ │ │ └── portal-preview.tsx │ │ │ │ │ └── studs-pattern.tsx │ │ │ │ ├── group-color-circle.tsx │ │ │ │ ├── group-color-picker.tsx │ │ │ │ ├── group-selector.tsx │ │ │ │ ├── group-settings-row.tsx │ │ │ │ ├── groups-multi-select.tsx │ │ │ │ └── reward-discount-partners-card.tsx │ │ │ ├── hero-background.tsx │ │ │ ├── lander/ │ │ │ │ ├── blocks/ │ │ │ │ │ ├── accordion-block.tsx │ │ │ │ │ ├── block-description.tsx │ │ │ │ │ ├── block-markdown.tsx │ │ │ │ │ ├── block-title.tsx │ │ │ │ │ ├── earnings-calculator-block.tsx │ │ │ │ │ ├── files-block.tsx │ │ │ │ │ ├── image-block.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── text-block.tsx │ │ │ │ │ └── wave-pattern.tsx │ │ │ │ ├── lander-hero.tsx │ │ │ │ └── lander-rewards.tsx │ │ │ ├── mark-commission-duplicate-modal.tsx │ │ │ ├── mark-commission-fraud-or-canceled-modal.tsx │ │ │ ├── merge-accounts/ │ │ │ │ ├── account-input-group.tsx │ │ │ │ ├── form-context.tsx │ │ │ │ ├── merge-account-form.tsx │ │ │ │ ├── merge-partner-accounts-modal.tsx │ │ │ │ ├── otp-input-field.tsx │ │ │ │ ├── send-verification-code-form.tsx │ │ │ │ ├── step-progress-bar.tsx │ │ │ │ └── verify-code-form.tsx │ │ │ ├── overview/ │ │ │ │ ├── blocks/ │ │ │ │ │ ├── commissions-block.tsx │ │ │ │ │ ├── conversion-block.tsx │ │ │ │ │ ├── countries-block.tsx │ │ │ │ │ ├── links-block.tsx │ │ │ │ │ ├── partners-block.tsx │ │ │ │ │ ├── sale-type-block.tsx │ │ │ │ │ └── traffic-sources-block.tsx │ │ │ │ ├── exceeded-events-limit.tsx │ │ │ │ ├── program-overview-block.tsx │ │ │ │ └── program-overview-card.tsx │ │ │ ├── partner-about.tsx │ │ │ ├── partner-advanced-settings-modal.tsx │ │ │ ├── partner-application-details.tsx │ │ │ ├── partner-application-sheet.tsx │ │ │ ├── partner-avatar.tsx │ │ │ ├── partner-comments.tsx │ │ │ ├── partner-info-cards.tsx │ │ │ ├── partner-info-group.tsx │ │ │ ├── partner-info-section.tsx │ │ │ ├── partner-info-stats.tsx │ │ │ ├── partner-link-selector.tsx │ │ │ ├── partner-network/ │ │ │ │ ├── conversion-score-tooltip.tsx │ │ │ │ ├── invites-usage.tsx │ │ │ │ └── network-partner-sheet.tsx │ │ │ ├── partner-platform-card.tsx │ │ │ ├── partner-platform-summary.tsx │ │ │ ├── partner-platforms-form.tsx │ │ │ ├── partner-profile-sheet.tsx │ │ │ ├── partner-row-item.tsx │ │ │ ├── partner-selector.tsx │ │ │ ├── partner-sheet-tabs.tsx │ │ │ ├── partner-social-column.tsx │ │ │ ├── partner-star-button.tsx │ │ │ ├── partner-status-badge-with-tooltip.tsx │ │ │ ├── partner-status-badges.ts │ │ │ ├── partners-upgrade-modal.tsx │ │ │ ├── payout-row-menu.tsx │ │ │ ├── payout-status-badge-partner.tsx │ │ │ ├── payout-status-badges.tsx │ │ │ ├── payout-status-descriptions.ts │ │ │ ├── payouts/ │ │ │ │ ├── bank-account-requirements-modal.tsx │ │ │ │ ├── connect-payout-button.tsx │ │ │ │ ├── connect-payout-modal.tsx │ │ │ │ ├── payout-method-cards.tsx │ │ │ │ ├── payout-method-config.ts │ │ │ │ ├── payout-method-dropdown.tsx │ │ │ │ ├── stablecoin-payout-banner.tsx │ │ │ │ ├── stablecoin-payout-card.tsx │ │ │ │ ├── stablecoin-payout-icon.tsx │ │ │ │ ├── stablecoin-payout-modal.tsx │ │ │ │ ├── use-payout-connect-flow.tsx │ │ │ │ └── use-stablecoin-payout-promo.tsx │ │ │ ├── program-application-sheet.tsx │ │ │ ├── program-card.tsx │ │ │ ├── program-category-select.tsx │ │ │ ├── program-color-picker.tsx │ │ │ ├── program-eligibility-card.tsx │ │ │ ├── program-help-links.tsx │ │ │ ├── program-invite-card.tsx │ │ │ ├── program-link-configuration.tsx │ │ │ ├── program-marketplace/ │ │ │ │ ├── program-category.tsx │ │ │ │ ├── program-marketplace-banner.tsx │ │ │ │ ├── program-marketplace-card.tsx │ │ │ │ ├── program-marketplace-logos.tsx │ │ │ │ ├── program-reward-icon.tsx │ │ │ │ ├── program-rewards-display.tsx │ │ │ │ ├── programs-promo-banner.tsx │ │ │ │ ├── programs-promo-card.tsx │ │ │ │ └── use-program-marketplace-promo.tsx │ │ │ ├── program-onboarding-form-wrapper.tsx │ │ │ ├── program-reward-description.tsx │ │ │ ├── program-reward-list.tsx │ │ │ ├── program-reward-modifiers-tooltip.tsx │ │ │ ├── program-reward-terms.tsx │ │ │ ├── program-rewards-panel.tsx │ │ │ ├── program-selector.tsx │ │ │ ├── program-sheet-accordion.tsx │ │ │ ├── program-stats-filter.tsx │ │ │ ├── resources/ │ │ │ │ ├── resource-card.tsx │ │ │ │ └── resource-section.tsx │ │ │ ├── rewards/ │ │ │ │ ├── add-edit-reward-sheet.tsx │ │ │ │ ├── reward-icon-square.tsx │ │ │ │ ├── reward-preview-card.tsx │ │ │ │ └── rewards-logic.tsx │ │ │ ├── rewind/ │ │ │ │ ├── constants.ts │ │ │ │ ├── partner-rewind-banner.tsx │ │ │ │ ├── partner-rewind-card.tsx │ │ │ │ └── use-partner-rewind-status.tsx │ │ │ ├── trusted-partner-badge.tsx │ │ │ └── use-country-change-warning-modal.tsx │ │ ├── placeholders/ │ │ │ ├── bubble-icon.tsx │ │ │ ├── button-link.tsx │ │ │ ├── cta.tsx │ │ │ ├── feature-graphics/ │ │ │ │ ├── analytics.tsx │ │ │ │ ├── collaboration.tsx │ │ │ │ ├── domains.tsx │ │ │ │ ├── personalization.tsx │ │ │ │ └── qr.tsx │ │ │ ├── features-section.tsx │ │ │ ├── hero.tsx │ │ │ └── logos.tsx │ │ ├── postbacks/ │ │ │ ├── add-edit-postback-modal.tsx │ │ │ ├── partner-postback-actions.tsx │ │ │ ├── postback-card.tsx │ │ │ ├── postback-detail-skeleton.tsx │ │ │ ├── postback-event-details-sheet.tsx │ │ │ ├── postback-event-list-skeleton.tsx │ │ │ ├── postback-event-list.tsx │ │ │ ├── postback-placeholder.tsx │ │ │ ├── postback-secret-modal.tsx │ │ │ ├── postback-status.tsx │ │ │ └── send-test-postback-modal.tsx │ │ ├── referrals/ │ │ │ ├── form-fields/ │ │ │ │ ├── country-field.tsx │ │ │ │ ├── date-field.tsx │ │ │ │ ├── form-control.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── max-character-count.tsx │ │ │ │ ├── multi-select-field.tsx │ │ │ │ ├── number-field.tsx │ │ │ │ ├── phone-field.tsx │ │ │ │ ├── select-field.tsx │ │ │ │ ├── text-field.tsx │ │ │ │ └── textarea-field.tsx │ │ │ ├── partner-profile-referral-sheet.tsx │ │ │ ├── partner-profile-referrals-empty-state.tsx │ │ │ ├── partner-referral-sheet.tsx │ │ │ ├── partner-referral-table.tsx │ │ │ ├── referral-details.tsx │ │ │ ├── referral-form.tsx │ │ │ ├── referral-lead-details.tsx │ │ │ ├── referral-partner-details.tsx │ │ │ ├── referral-status-badge.tsx │ │ │ ├── referral-status-badges.ts │ │ │ ├── referral-status-dropdown.tsx │ │ │ ├── referral-utils.ts │ │ │ ├── submit-referral-sheet.tsx │ │ │ └── use-program-referral-filters.tsx │ │ ├── shared/ │ │ │ ├── amount-input.tsx │ │ │ ├── animated-empty-state.tsx │ │ │ ├── back-link.tsx │ │ │ ├── business-badge-tooltip.tsx │ │ │ ├── conditional-link.tsx │ │ │ ├── custom-toast.tsx │ │ │ ├── emoji-picker.tsx │ │ │ ├── empty-state.tsx │ │ │ ├── filter-button-table-row.tsx │ │ │ ├── icons/ │ │ │ │ ├── airplay.tsx │ │ │ │ ├── alert-circle-fill.tsx │ │ │ │ ├── chart.tsx │ │ │ │ ├── check-circle-fill.tsx │ │ │ │ ├── clipboard.tsx │ │ │ │ ├── delete.tsx │ │ │ │ ├── devices.tsx │ │ │ │ ├── divider.tsx │ │ │ │ ├── download.tsx │ │ │ │ ├── drag.tsx │ │ │ │ ├── edit.tsx │ │ │ │ ├── external-link.tsx │ │ │ │ ├── eye-off.tsx │ │ │ │ ├── eye.tsx │ │ │ │ ├── filter.tsx │ │ │ │ ├── heart.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── infinity.tsx │ │ │ │ ├── link.tsx │ │ │ │ ├── lock.tsx │ │ │ │ ├── logout.tsx │ │ │ │ ├── message.tsx │ │ │ │ ├── qr.tsx │ │ │ │ ├── random.tsx │ │ │ │ ├── repeat.tsx │ │ │ │ ├── save.tsx │ │ │ │ ├── search.tsx │ │ │ │ ├── sort.tsx │ │ │ │ ├── three-dots.tsx │ │ │ │ ├── upload-cloud.tsx │ │ │ │ ├── users.tsx │ │ │ │ ├── x-circle-fill.tsx │ │ │ │ └── x.tsx │ │ │ ├── inline-badge-popover.tsx │ │ │ ├── markdown-description.tsx │ │ │ ├── markdown.tsx │ │ │ ├── max-characters-counter.tsx │ │ │ ├── message-input.tsx │ │ │ ├── modal-hero.tsx │ │ │ ├── new-background.tsx │ │ │ ├── password-requirements.tsx │ │ │ ├── pro-badge-tooltip.tsx │ │ │ ├── qr-code.tsx │ │ │ ├── search-box.tsx │ │ │ ├── simple-date-range-picker.tsx │ │ │ ├── simple-empty-state.tsx │ │ │ ├── upgrade-required-toast.tsx │ │ │ └── zoom-image.tsx │ │ ├── support/ │ │ │ ├── chat-bubble.tsx │ │ │ ├── chat-interface.tsx │ │ │ ├── clear-chat-button.tsx │ │ │ ├── code-block.tsx │ │ │ ├── embedded-chat.tsx │ │ │ ├── message.tsx │ │ │ ├── program-combobox.tsx │ │ │ ├── source-citations.tsx │ │ │ ├── starter-questions.tsx │ │ │ ├── status-indicator.tsx │ │ │ ├── ticket-upload.tsx │ │ │ ├── types.ts │ │ │ └── workspace-combobox.tsx │ │ ├── token-avatar.tsx │ │ ├── users/ │ │ │ ├── user-avatar.tsx │ │ │ └── user-row-item.tsx │ │ ├── webhooks/ │ │ │ ├── add-edit-webhook-form.tsx │ │ │ ├── link-selector.tsx │ │ │ ├── loading-events-skelton.tsx │ │ │ ├── no-events-placeholder.tsx │ │ │ ├── webhook-card.tsx │ │ │ ├── webhook-event-details-sheet.tsx │ │ │ ├── webhook-event-list.tsx │ │ │ ├── webhook-header.tsx │ │ │ ├── webhook-placeholder.tsx │ │ │ └── webhook-status.tsx │ │ └── workspaces/ │ │ ├── create-workspace-button.tsx │ │ ├── create-workspace-form.tsx │ │ ├── delete-workspace.tsx │ │ ├── invite-teammates-form.tsx │ │ ├── manage-subscription-button.tsx │ │ ├── plan-badge.tsx │ │ ├── plan-features.tsx │ │ ├── subscription-menu.tsx │ │ ├── upgrade-plan-button.tsx │ │ ├── upload-logo.tsx │ │ ├── workspace-arrow.tsx │ │ ├── workspace-exceeded-events.tsx │ │ └── workspace-selector.tsx │ ├── vercel.json │ └── vitest.config.ts ├── package.json ├── packages/ │ ├── cli/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── api/ │ │ │ │ ├── callback.ts │ │ │ │ ├── domains.ts │ │ │ │ └── links.ts │ │ │ ├── commands/ │ │ │ │ ├── config.ts │ │ │ │ ├── domains.ts │ │ │ │ ├── links.ts │ │ │ │ ├── login.ts │ │ │ │ └── shorten.ts │ │ │ ├── index.ts │ │ │ ├── types/ │ │ │ │ └── index.ts │ │ │ └── utils/ │ │ │ ├── config.ts │ │ │ ├── get-nanoid.ts │ │ │ ├── get-package-info.ts │ │ │ ├── handle-error.ts │ │ │ ├── logger.ts │ │ │ ├── oauth.ts │ │ │ └── parser.ts │ │ ├── tsconfig.json │ │ └── tsup.config.ts │ ├── email/ │ │ ├── package.json │ │ ├── src/ │ │ │ ├── components/ │ │ │ │ ├── bounty-thumbnail.tsx │ │ │ │ └── footer.tsx │ │ │ ├── index.ts │ │ │ ├── react-email.d.ts │ │ │ ├── resend/ │ │ │ │ ├── client.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ ├── send-via-nodemailer.ts │ │ │ ├── send-via-resend.ts │ │ │ ├── templates/ │ │ │ │ ├── api-key-created.tsx │ │ │ │ ├── bounty-approved.tsx │ │ │ │ ├── bounty-completed.tsx │ │ │ │ ├── bounty-new-submission.tsx │ │ │ │ ├── bounty-rejected.tsx │ │ │ │ ├── bounty-submitted.tsx │ │ │ │ ├── broadcasts/ │ │ │ │ │ ├── dub-product-update-mar26.tsx │ │ │ │ │ ├── dub-wrapped.tsx │ │ │ │ │ ├── payout-auto-withdrawals.tsx │ │ │ │ │ ├── program-marketplace-announcement.tsx │ │ │ │ │ └── stablecoin-payouts-announcement.tsx │ │ │ │ ├── campaign-email.tsx │ │ │ │ ├── clicks-exceeded.tsx │ │ │ │ ├── clicks-summary.tsx │ │ │ │ ├── confirm-email-change.tsx │ │ │ │ ├── connect-payout-reminder.tsx │ │ │ │ ├── connect-platforms-reminder.tsx │ │ │ │ ├── connected-payout-method.tsx │ │ │ │ ├── connected-paypal-account.tsx │ │ │ │ ├── discount-deleted.tsx │ │ │ │ ├── domain-claimed.tsx │ │ │ │ ├── domain-deleted.tsx │ │ │ │ ├── domain-expired.tsx │ │ │ │ ├── domain-renewal-failed.tsx │ │ │ │ ├── domain-renewal-reminder.tsx │ │ │ │ ├── domain-renewed.tsx │ │ │ │ ├── domain-transferred.tsx │ │ │ │ ├── dub-partner-rewind.tsx │ │ │ │ ├── duplicate-payout-method.tsx │ │ │ │ ├── email-domain-status-changed.tsx │ │ │ │ ├── email-updated.tsx │ │ │ │ ├── export-ready.tsx │ │ │ │ ├── failed-payment.tsx │ │ │ │ ├── feedback-email.tsx │ │ │ │ ├── folder-edit-access-requested.tsx │ │ │ │ ├── integration-installed.tsx │ │ │ │ ├── invalid-domain.tsx │ │ │ │ ├── links-import-errors.tsx │ │ │ │ ├── links-imported.tsx │ │ │ │ ├── links-limit.tsx │ │ │ │ ├── login-link.tsx │ │ │ │ ├── new-bounty-available.tsx │ │ │ │ ├── new-commission-alert-partner.tsx │ │ │ │ ├── new-message-from-partner.tsx │ │ │ │ ├── new-message-from-program.tsx │ │ │ │ ├── new-referral-signup.tsx │ │ │ │ ├── new-sale-alert-program-owner.tsx │ │ │ │ ├── notify-partner-reapply.tsx │ │ │ │ ├── partner-account-merged.tsx │ │ │ │ ├── partner-application-approved.tsx │ │ │ │ ├── partner-application-received.tsx │ │ │ │ ├── partner-application-rejected.tsx │ │ │ │ ├── partner-banned.tsx │ │ │ │ ├── partner-deactivated.tsx │ │ │ │ ├── partner-group-changed.tsx │ │ │ │ ├── partner-payout-confirmed.tsx │ │ │ │ ├── partner-payout-failed.tsx │ │ │ │ ├── partner-payout-force-withdrawal.tsx │ │ │ │ ├── partner-payout-processed.tsx │ │ │ │ ├── partner-payout-withdrawal-completed.tsx │ │ │ │ ├── partner-payout-withdrawal-failed.tsx │ │ │ │ ├── partner-payout-withdrawal-initiated.tsx │ │ │ │ ├── partner-paypal-payout-failed.tsx │ │ │ │ ├── partner-program-summary.tsx │ │ │ │ ├── partner-referral-submitted.tsx │ │ │ │ ├── partner-user-invited.tsx │ │ │ │ ├── password-updated.tsx │ │ │ │ ├── pending-applications-summary.tsx │ │ │ │ ├── program-application-reminder.tsx │ │ │ │ ├── program-imported.tsx │ │ │ │ ├── program-invite.tsx │ │ │ │ ├── program-network-invite.tsx │ │ │ │ ├── program-payout-reminder.tsx │ │ │ │ ├── program-payout-thank-you.tsx │ │ │ │ ├── program-welcome.tsx │ │ │ │ ├── referral-invite.tsx │ │ │ │ ├── referral-status-update.tsx │ │ │ │ ├── reset-password-link.tsx │ │ │ │ ├── unresolved-fraud-events-summary.tsx │ │ │ │ ├── upgrade-email.tsx │ │ │ │ ├── verify-email-for-account-merge.tsx │ │ │ │ ├── verify-email.tsx │ │ │ │ ├── webhook-added.tsx │ │ │ │ ├── webhook-disabled.tsx │ │ │ │ ├── webhook-failed.tsx │ │ │ │ ├── welcome-email-partner.tsx │ │ │ │ ├── welcome-email.tsx │ │ │ │ └── workspace-invite.tsx │ │ │ └── types.ts │ │ └── tsconfig.json │ ├── embeds/ │ │ ├── core/ │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── constants.ts │ │ │ │ ├── core.ts │ │ │ │ ├── embed.ts │ │ │ │ ├── error.ts │ │ │ │ ├── example/ │ │ │ │ │ └── index.html │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ ├── tsconfig.json │ │ │ └── tsup.config.ts │ │ └── react/ │ │ ├── README.md │ │ ├── package.json │ │ ├── postcss.config.js │ │ ├── prepublish.js │ │ ├── src/ │ │ │ ├── embed.tsx │ │ │ ├── example/ │ │ │ │ └── app.tsx │ │ │ └── index.ts │ │ ├── tailwind.config.ts │ │ ├── tsconfig.json │ │ └── tsup.config.ts │ ├── hubspot-app/ │ │ ├── CLAUDE.md │ │ ├── README.md │ │ ├── hsproject.json │ │ ├── package.json │ │ └── src/ │ │ └── app/ │ │ ├── app-hsmeta.json │ │ └── webhooks/ │ │ └── webhooks-hsmeta.json │ ├── prisma/ │ │ ├── client.ts │ │ ├── edge.ts │ │ ├── index.ts │ │ ├── package.json │ │ ├── schema/ │ │ │ ├── activity.prisma │ │ │ ├── bounty.prisma │ │ │ ├── campaign.prisma │ │ │ ├── comment.prisma │ │ │ ├── commission.prisma │ │ │ ├── customer.prisma │ │ │ ├── dashboard.prisma │ │ │ ├── discount.prisma │ │ │ ├── domain.prisma │ │ │ ├── folder.prisma │ │ │ ├── fraud.prisma │ │ │ ├── group.prisma │ │ │ ├── integration.prisma │ │ │ ├── invoice.prisma │ │ │ ├── jackson.prisma │ │ │ ├── link.prisma │ │ │ ├── message.prisma │ │ │ ├── misc.prisma │ │ │ ├── network.prisma │ │ │ ├── notification.prisma │ │ │ ├── oauth.prisma │ │ │ ├── partner.prisma │ │ │ ├── payout.prisma │ │ │ ├── platform.prisma │ │ │ ├── postback.prisma │ │ │ ├── program.prisma │ │ │ ├── referral.prisma │ │ │ ├── reward.prisma │ │ │ ├── schema.prisma │ │ │ ├── tag.prisma │ │ │ ├── token.prisma │ │ │ ├── utm.prisma │ │ │ ├── webhook.prisma │ │ │ ├── workflow.prisma │ │ │ └── workspace.prisma │ │ └── tsconfig.json │ ├── stripe-app/ │ │ ├── README.md │ │ ├── jest.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── hooks/ │ │ │ │ └── use-workspace.ts │ │ │ ├── utils/ │ │ │ │ ├── constants.ts │ │ │ │ ├── dub.ts │ │ │ │ ├── oauth.ts │ │ │ │ ├── secrets.ts │ │ │ │ ├── stripe.ts │ │ │ │ └── types.ts │ │ │ └── views/ │ │ │ └── AppSettings.tsx │ │ ├── stripe-app.dev.json │ │ ├── stripe-app.json │ │ ├── tsconfig.json │ │ └── ui-extensions.d.ts │ ├── tailwind-config/ │ │ ├── package.json │ │ ├── tailwind.config.ts │ │ └── themes.css │ ├── tinybird/ │ │ ├── README.md │ │ ├── datasources/ │ │ │ ├── dub_audit_logs.datasource │ │ │ ├── dub_click_events.datasource │ │ │ ├── dub_click_events_id.datasource │ │ │ ├── dub_click_events_mv.datasource │ │ │ ├── dub_conversion_events_log.datasource │ │ │ ├── dub_first_sale_mv.datasource │ │ │ ├── dub_import_error_logs.datasource │ │ │ ├── dub_lead_events.datasource │ │ │ ├── dub_lead_events_mv.datasource │ │ │ ├── dub_links_metadata.datasource │ │ │ ├── dub_links_metadata_latest.datasource │ │ │ ├── dub_postback_events.datasource │ │ │ ├── dub_sale_events.datasource │ │ │ ├── dub_sale_events_mv.datasource │ │ │ └── dub_webhook_events.datasource │ │ └── pipes/ │ │ ├── all_stats.pipe │ │ ├── coordinates_all.pipe │ │ ├── coordinates_sales.pipe │ │ ├── dub_click_events_id_pipe.pipe │ │ ├── dub_click_events_pipe.pipe │ │ ├── dub_first_sale_pipe.pipe │ │ ├── dub_lead_events_pipe.pipe │ │ ├── dub_links_metadata_pipe.pipe │ │ ├── dub_sale_events_pipe.pipe │ │ ├── get_audit_logs.pipe │ │ ├── get_click_event.pipe │ │ ├── get_framer_lead_events.pipe │ │ ├── get_import_error_logs.pipe │ │ ├── get_lead_event.pipe │ │ ├── get_lead_events.pipe │ │ ├── get_postback_events.pipe │ │ ├── get_webhook_events.pipe │ │ ├── v2_customer_events.pipe │ │ ├── v2_top_programs.pipe │ │ ├── v3_count.pipe │ │ ├── v3_events.pipe │ │ ├── v3_group_by.pipe │ │ ├── v3_group_by_link_country.pipe │ │ ├── v3_group_by_link_metadata.pipe │ │ ├── v3_timeseries.pipe │ │ ├── v3_usage.pipe │ │ ├── v3_usage_latest.pipe │ │ ├── v4_count.pipe │ │ ├── v4_events.pipe │ │ ├── v4_group_by.pipe │ │ ├── v4_group_by_link_metadata.pipe │ │ └── v4_timeseries.pipe │ ├── tsconfig/ │ │ ├── base.json │ │ ├── nextjs.json │ │ ├── package.json │ │ └── react-library.json │ ├── ui/ │ │ ├── README.md │ │ ├── package.json │ │ ├── postcss.config.js │ │ ├── src/ │ │ │ ├── accordion.tsx │ │ │ ├── activity-ring.tsx │ │ │ ├── alert.tsx │ │ │ ├── animated-size-container.tsx │ │ │ ├── avatar.tsx │ │ │ ├── background.tsx │ │ │ ├── badge.tsx │ │ │ ├── blur-image.tsx │ │ │ ├── button.tsx │ │ │ ├── card-list/ │ │ │ │ ├── card-list-card.tsx │ │ │ │ ├── card-list.tsx │ │ │ │ └── index.ts │ │ │ ├── card-selector.tsx │ │ │ ├── carousel/ │ │ │ │ ├── carousel.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── nav-bar.tsx │ │ │ │ └── thumbnails.tsx │ │ │ ├── charts/ │ │ │ │ ├── areas.tsx │ │ │ │ ├── bars.tsx │ │ │ │ ├── chart-context.ts │ │ │ │ ├── funnel-chart.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── time-series-chart.tsx │ │ │ │ ├── tooltip-sync.tsx │ │ │ │ ├── types.ts │ │ │ │ ├── use-tooltip.ts │ │ │ │ ├── utils.ts │ │ │ │ ├── x-axis.tsx │ │ │ │ └── y-axis.tsx │ │ │ ├── checkbox.tsx │ │ │ ├── client-only.tsx │ │ │ ├── combobox/ │ │ │ │ └── index.tsx │ │ │ ├── composite-logo.tsx │ │ │ ├── content.ts │ │ │ ├── copy-button.tsx │ │ │ ├── copy-text.tsx │ │ │ ├── date-picker/ │ │ │ │ ├── calendar.tsx │ │ │ │ ├── date-picker.tsx │ │ │ │ ├── date-range-picker.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── presets.tsx │ │ │ │ ├── shared.ts │ │ │ │ ├── trigger.tsx │ │ │ │ └── types.ts │ │ │ ├── dots-pattern.tsx │ │ │ ├── dub-status-badge.tsx │ │ │ ├── empty-state.tsx │ │ │ ├── file-upload.tsx │ │ │ ├── filter/ │ │ │ │ ├── filter-list.tsx │ │ │ │ ├── filter-select.tsx │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ ├── footer.tsx │ │ │ ├── form.tsx │ │ │ ├── grid.tsx │ │ │ ├── hooks/ │ │ │ │ ├── index.ts │ │ │ │ ├── use-click-handlers.ts │ │ │ │ ├── use-column-visibility.ts │ │ │ │ ├── use-cookies.ts │ │ │ │ ├── use-copy-to-clipboard.tsx │ │ │ │ ├── use-current-anchor.ts │ │ │ │ ├── use-current-subdomain.ts │ │ │ │ ├── use-enter-submit.ts │ │ │ │ ├── use-in-viewport.tsx │ │ │ │ ├── use-input-focused.ts │ │ │ │ ├── use-intersection-observer.ts │ │ │ │ ├── use-keyboard-shortcut.tsx │ │ │ │ ├── use-local-storage.ts │ │ │ │ ├── use-media-query.ts │ │ │ │ ├── use-optimistic-update.ts │ │ │ │ ├── use-pagination.ts │ │ │ │ ├── use-remove-ga-params.ts │ │ │ │ ├── use-resize-observer.ts │ │ │ │ ├── use-router-stuff.ts │ │ │ │ ├── use-scroll-progress.ts │ │ │ │ ├── use-scroll.ts │ │ │ │ └── use-toast-with-undo.tsx │ │ │ ├── icon-menu.tsx │ │ │ ├── icons/ │ │ │ │ ├── anthropic.tsx │ │ │ │ ├── arrow-up-right-2.tsx │ │ │ │ ├── bing.tsx │ │ │ │ ├── continents/ │ │ │ │ │ ├── af.tsx │ │ │ │ │ ├── as.tsx │ │ │ │ │ ├── eu.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── na.tsx │ │ │ │ │ ├── oc.tsx │ │ │ │ │ └── sa.tsx │ │ │ │ ├── copy.tsx │ │ │ │ ├── crown-small.tsx │ │ │ │ ├── default-domains/ │ │ │ │ │ ├── amazon.tsx │ │ │ │ │ ├── chatgpt.tsx │ │ │ │ │ ├── figma.tsx │ │ │ │ │ ├── github-enhanced.tsx │ │ │ │ │ ├── google-enhanced.tsx │ │ │ │ │ └── spotify.tsx │ │ │ │ ├── dub-analytics.tsx │ │ │ │ ├── dub-api.tsx │ │ │ │ ├── dub-crafted-shield.tsx │ │ │ │ ├── dub-links.tsx │ │ │ │ ├── dub-partners.tsx │ │ │ │ ├── dub-product-icon.tsx │ │ │ │ ├── expanding-arrow.tsx │ │ │ │ ├── facebook.tsx │ │ │ │ ├── file-pen.tsx │ │ │ │ ├── file-send.tsx │ │ │ │ ├── github.tsx │ │ │ │ ├── go.tsx │ │ │ │ ├── google.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── instagram.tsx │ │ │ │ ├── ios-app-store.tsx │ │ │ │ ├── linkedin.tsx │ │ │ │ ├── loading-circle.tsx │ │ │ │ ├── loading-dots.tsx │ │ │ │ ├── loading-spinner.tsx │ │ │ │ ├── lock-small.tsx │ │ │ │ ├── magic.tsx │ │ │ │ ├── markdown-icon.tsx │ │ │ │ ├── matrix-lines.tsx │ │ │ │ ├── nucleo/ │ │ │ │ │ ├── README.md │ │ │ │ │ ├── android-logo.tsx │ │ │ │ │ ├── apple-logo.tsx │ │ │ │ │ ├── apple.tsx │ │ │ │ │ ├── arrow-bold-up.tsx │ │ │ │ │ ├── arrow-right.tsx │ │ │ │ │ ├── arrow-trend-up.tsx │ │ │ │ │ ├── arrow-turn-left.tsx │ │ │ │ │ ├── arrow-turn-right2.tsx │ │ │ │ │ ├── arrow-up-right.tsx │ │ │ │ │ ├── arrows-opposite-direction-x.tsx │ │ │ │ │ ├── arrows-opposite-direction-y.tsx │ │ │ │ │ ├── at-sign.tsx │ │ │ │ │ ├── badge-check.tsx │ │ │ │ │ ├── badge-check2-fill.tsx │ │ │ │ │ ├── bell.tsx │ │ │ │ │ ├── blog.tsx │ │ │ │ │ ├── bolt-fill.tsx │ │ │ │ │ ├── bolt.tsx │ │ │ │ │ ├── book-open.tsx │ │ │ │ │ ├── book2-fill.tsx │ │ │ │ │ ├── book2-small.tsx │ │ │ │ │ ├── book2.tsx │ │ │ │ │ ├── books2.tsx │ │ │ │ │ ├── box-archive.tsx │ │ │ │ │ ├── brackets-curly.tsx │ │ │ │ │ ├── briefcase-fill.tsx │ │ │ │ │ ├── brush.tsx │ │ │ │ │ ├── bullet-list-fill.tsx │ │ │ │ │ ├── bullet-list.tsx │ │ │ │ │ ├── calculator.tsx │ │ │ │ │ ├── calendar-days.tsx │ │ │ │ │ ├── calendar-refresh.tsx │ │ │ │ │ ├── calendar.tsx │ │ │ │ │ ├── calendar6.tsx │ │ │ │ │ ├── cards.tsx │ │ │ │ │ ├── caret-up-fill.tsx │ │ │ │ │ ├── chart-activity2.tsx │ │ │ │ │ ├── chart-area2.tsx │ │ │ │ │ ├── chart-line.tsx │ │ │ │ │ ├── check.tsx │ │ │ │ │ ├── check2.tsx │ │ │ │ │ ├── checkbox-checked-fill.tsx │ │ │ │ │ ├── checkbox-unchecked.tsx │ │ │ │ │ ├── chevron-left.tsx │ │ │ │ │ ├── chevron-right.tsx │ │ │ │ │ ├── chevron-up.tsx │ │ │ │ │ ├── circle-arrow-right.tsx │ │ │ │ │ ├── circle-check-fill.tsx │ │ │ │ │ ├── circle-check.tsx │ │ │ │ │ ├── circle-dollar-out.tsx │ │ │ │ │ ├── circle-dollar.tsx │ │ │ │ │ ├── circle-dollar3.tsx │ │ │ │ │ ├── circle-dotted.tsx │ │ │ │ │ ├── circle-half-dotted-check.tsx │ │ │ │ │ ├── circle-half-dotted-clock.tsx │ │ │ │ │ ├── circle-info.tsx │ │ │ │ │ ├── circle-percentage.tsx │ │ │ │ │ ├── circle-play-fill.tsx │ │ │ │ │ ├── circle-play.tsx │ │ │ │ │ ├── circle-question.tsx │ │ │ │ │ ├── circle-user.tsx │ │ │ │ │ ├── circle-warning.tsx │ │ │ │ │ ├── circle-xmark.tsx │ │ │ │ │ ├── circles.tsx │ │ │ │ │ ├── circles3.tsx │ │ │ │ │ ├── cloud-upload.tsx │ │ │ │ │ ├──
Showing preview only (650K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (5941 symbols across 3089 files)
FILE: apps/web/app/(ee)/admin.dub.co/(auth)/layout.tsx
function AdminAuthLayout (line 3) | function AdminAuthLayout({
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/analytics/page.tsx
function AdminAnalytics (line 5) | function AdminAnalytics() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/commissions/client.tsx
function CommissionsPageClient (line 28) | function CommissionsPageClient() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/commissions/page.tsx
function CommissionsPage (line 4) | async function CommissionsPage() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/components/ban-link.tsx
function BanLink (line 8) | function BanLink() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/components/delete-partner-account.tsx
function DeletePartnerAccount (line 8) | function DeletePartnerAccount() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/components/impersonate-user.tsx
function ImpersonateUser (line 10) | function ImpersonateUser() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/components/impersonate-workspace.tsx
function ImpersonateWorkspace (line 10) | function ImpersonateWorkspace() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/components/refresh-domain.tsx
function RefreshDomain (line 8) | function RefreshDomain() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/components/reset-login-attempts.tsx
function ResetLoginAttempts (line 8) | function ResetLoginAttempts() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/components/user-info.tsx
type UserInfoProps (line 7) | interface UserInfoProps {
function UserInfo (line 51) | function UserInfo({ data }: { data: UserInfoProps }) {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/events/page.tsx
function AdminEvents (line 7) | function AdminEvents() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/layout-nav-client.tsx
function AdminNav (line 37) | function AdminNav() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/layout.tsx
function AdminLayout (line 7) | function AdminLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/links/page.tsx
function AdminLinks (line 4) | function AdminLinks() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/page.tsx
function AdminPage (line 14) | function AdminPage() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/payouts/client.tsx
type TimeseriesData (line 32) | interface TimeseriesData {
type InvoiceData (line 39) | interface InvoiceData {
type Tab (line 50) | type Tab = {
function PayoutsPageClient (line 56) | function PayoutsPageClient() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/payouts/page.tsx
function PayoutsPage (line 4) | async function PayoutsPage() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/payouts/paypal/client.tsx
function PaypalPayoutsPageClient (line 30) | function PaypalPayoutsPageClient() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/payouts/paypal/page.tsx
function PaypalPayoutsPage (line 4) | async function PaypalPayoutsPage() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/revenue/client.tsx
function RevenuePageClient (line 16) | function RevenuePageClient() {
FILE: apps/web/app/(ee)/admin.dub.co/(dashboard)/revenue/page.tsx
function RevenuePage (line 4) | async function RevenuePage() {
FILE: apps/web/app/(ee)/admin.dub.co/layout.tsx
function AdminLayout (line 6) | function AdminLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/(ee)/api/admin/analytics/route.ts
constant GET (line 7) | const GET = withAdmin(async ({ searchParams }) => {
FILE: apps/web/app/(ee)/api/admin/ban/route.ts
constant POST (line 11) | const POST = withAdmin(async ({ req }) => {
FILE: apps/web/app/(ee)/api/admin/commissions/get-commissions-timeseries.ts
type Commission (line 8) | interface Commission {
function getCommissionsTimeseries (line 13) | async function getCommissionsTimeseries({
FILE: apps/web/app/(ee)/api/admin/commissions/get-top-program-by-commissions.ts
function getTopProgramsByCommissions (line 4) | async function getTopProgramsByCommissions({
FILE: apps/web/app/(ee)/api/admin/commissions/route.ts
constant GET (line 20) | const GET = withAdmin(async ({ searchParams }) => {
FILE: apps/web/app/(ee)/api/admin/delete-partner-account/route.ts
constant POST (line 10) | const POST = withAdmin(async ({ req }) => {
FILE: apps/web/app/(ee)/api/admin/events/route.ts
constant GET (line 7) | const GET = withAdmin(async ({ searchParams }) => {
FILE: apps/web/app/(ee)/api/admin/impersonate/route.ts
constant POST (line 8) | const POST = withAdmin(async ({ req }) => {
function getImpersonateUrl (line 104) | async function getImpersonateUrl(email: string) {
FILE: apps/web/app/(ee)/api/admin/links/[linkId]/route.ts
constant GET (line 7) | const GET = withAdmin(async ({ params }) => {
FILE: apps/web/app/(ee)/api/admin/links/ban/route.ts
constant DELETE (line 14) | const DELETE = withAdmin(async ({ searchParams }) => {
FILE: apps/web/app/(ee)/api/admin/links/count/route.ts
constant GET (line 7) | const GET = withAdmin(async ({ searchParams }) => {
FILE: apps/web/app/(ee)/api/admin/links/route.ts
constant GET (line 8) | const GET = withAdmin(async ({ searchParams }) => {
FILE: apps/web/app/(ee)/api/admin/payouts/paypal/route.ts
constant GET (line 5) | const GET = withAdmin(async ({ searchParams }) => {
FILE: apps/web/app/(ee)/api/admin/payouts/route.ts
type TimeseriesPoint (line 12) | interface TimeseriesPoint {
type FormattedTimeseriesPoint (line 18) | interface FormattedTimeseriesPoint extends TimeseriesPoint {
constant GET (line 31) | const GET = withAdmin(async ({ searchParams }) => {
FILE: apps/web/app/(ee)/api/admin/refresh-domain/route.ts
constant POST (line 6) | const POST = withAdmin(async ({ req }) => {
FILE: apps/web/app/(ee)/api/admin/reset-login-attempts/route.ts
constant POST (line 6) | const POST = withAdmin(async ({ req }) => {
FILE: apps/web/app/(ee)/api/admin/revenue/get-top-programs-by-sales.ts
function getTopProgramsBySales (line 7) | async function getTopProgramsBySales({
FILE: apps/web/app/(ee)/api/admin/revenue/route.ts
constant GET (line 8) | const GET = withAdmin(async ({ searchParams }) => {
FILE: apps/web/app/(ee)/api/audit-logs/export/route.ts
constant POST (line 16) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/auth/saml/callback/route.ts
function POST (line 4) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/auth/saml/token/route.ts
function POST (line 6) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/auth/saml/userinfo/route.ts
function GET (line 4) | async function GET(req: Request) {
FILE: apps/web/app/(ee)/api/auth/saml/verify/route.tsx
function POST (line 5) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/bounties/[bountyId]/route.ts
constant GET (line 26) | const GET = withWorkspace(
constant PATCH (line 54) | const PATCH = withWorkspace(
constant DELETE (line 293) | const DELETE = withWorkspace(
FILE: apps/web/app/(ee)/api/bounties/[bountyId]/submissions/[submissionId]/approve/route.ts
constant POST (line 10) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/bounties/[bountyId]/submissions/[submissionId]/reject/route.ts
constant POST (line 10) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/bounties/[bountyId]/submissions/route.ts
constant GET (line 12) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/bounties/[bountyId]/sync-social-metrics/route.ts
constant POST (line 27) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/bounties/count/submissions/route.ts
constant GET (line 17) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/bounties/route.ts
constant GET (line 32) | const GET = withWorkspace(
constant POST (line 155) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/campaigns/[campaignId]/duplicate/route.ts
constant POST (line 12) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/campaigns/[campaignId]/events/count/route.ts
constant GET (line 9) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/campaigns/[campaignId]/events/route.ts
constant GET (line 9) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/campaigns/[campaignId]/preview/route.ts
constant POST (line 28) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/campaigns/[campaignId]/route.ts
constant GET (line 25) | const GET = withWorkspace(
constant PATCH (line 52) | const PATCH = withWorkspace(
constant DELETE (line 180) | const DELETE = withWorkspace(
FILE: apps/web/app/(ee)/api/campaigns/[campaignId]/summary/route.ts
constant GET (line 8) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/campaigns/count/route.ts
constant GET (line 9) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/campaigns/route.ts
constant GET (line 21) | const GET = withWorkspace(
constant POST (line 80) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/commissions/[commissionId]/route.ts
constant GET (line 22) | const GET = withWorkspace(async ({ workspace, params }) => {
constant PATCH (line 100) | const PATCH = withWorkspace(
FILE: apps/web/app/(ee)/api/commissions/count/route.ts
constant GET (line 8) | const GET = withWorkspace(async ({ workspace, searchParams }) => {
FILE: apps/web/app/(ee)/api/commissions/export/route.ts
constant MAX_COMMISSIONS_TO_EXPORT (line 12) | const MAX_COMMISSIONS_TO_EXPORT = 1000;
constant GET (line 15) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/commissions/route.ts
constant GET (line 15) | const GET = withWorkspace(async ({ workspace, searchParams }) => {
FILE: apps/web/app/(ee)/api/commissions/timeseries/route.ts
type Commission (line 18) | interface Commission {
constant GET (line 24) | const GET = withWorkspace(async ({ workspace, searchParams }) => {
FILE: apps/web/app/(ee)/api/cron/aggregate-clicks/resolve-click-reward-amount.ts
function resolveClickRewardAmount (line 8) | function resolveClickRewardAmount({
FILE: apps/web/app/(ee)/api/cron/aggregate-clicks/route.ts
constant BATCH_SIZE (line 22) | const BATCH_SIZE = 200;
function handler (line 32) | async function handler(req: Request) {
FILE: apps/web/app/(ee)/api/cron/bounties/create-draft-submissions/route.ts
constant MAX_PAGE_SIZE (line 23) | const MAX_PAGE_SIZE = 100;
function POST (line 27) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/bounties/notify-partners/route.ts
constant EMAIL_BATCH_SIZE (line 27) | const EMAIL_BATCH_SIZE = 100;
constant BATCH_DELAY_SECONDS (line 28) | const BATCH_DELAY_SECONDS = 2;
constant EXTENDED_DELAY_SECONDS (line 29) | const EXTENDED_DELAY_SECONDS = 30;
constant EXTENDED_DELAY_INTERVAL (line 30) | const EXTENDED_DELAY_INTERVAL = 25;
function POST (line 34) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/bounties/queue-sync-social-metrics/route.ts
constant GET (line 11) | const GET = withCron(async () => {
FILE: apps/web/app/(ee)/api/cron/bounties/sync-social-metrics/route.ts
constant SUBMISSION_BATCH_SIZE (line 23) | const SUBMISSION_BATCH_SIZE = 50;
constant POST (line 26) | const POST = withCron(async ({ rawBody }) => {
FILE: apps/web/app/(ee)/api/cron/campaigns/broadcast/route.ts
constant EMAIL_BATCH_SIZE (line 31) | const EMAIL_BATCH_SIZE = 100;
constant BATCH_DELAY_SECONDS (line 32) | const BATCH_DELAY_SECONDS = 2;
constant EXTENDED_DELAY_SECONDS (line 33) | const EXTENDED_DELAY_SECONDS = 30;
constant EXTENDED_DELAY_INTERVAL (line 34) | const EXTENDED_DELAY_INTERVAL = 25;
function POST (line 38) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/cleanup/demo-embed-partners/route.ts
function POST (line 13) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/cleanup/e2e-tests/route.ts
constant E2E_USER_ID (line 14) | const E2E_USER_ID = "clxz1q7c7000hbqx5ckv4r82h";
constant E2E_WORKSPACE_ID (line 15) | const E2E_WORKSPACE_ID = "clrei1gld0002vs9mzn93p8ik";
function POST (line 19) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/cleanup/expired-tokens/route.ts
function POST (line 15) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/cleanup/link-retention/route.ts
function POST (line 16) | async function POST(req: Request) {
constant LINKS_PER_BATCH (line 56) | const LINKS_PER_BATCH = 100;
constant MAX_LINK_BATCHES (line 57) | const MAX_LINK_BATCHES = 10;
function deleteOldLinks (line 59) | async function deleteOldLinks(
FILE: apps/web/app/(ee)/api/cron/cleanup/rejected-applications/route.ts
function POST (line 13) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/cleanup/unenrolled-partners/route.ts
function POST (line 13) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/discount-codes/create/queue-batches/route.ts
constant POST (line 18) | const POST = withCron(async ({ rawBody }) => {
FILE: apps/web/app/(ee)/api/cron/discount-codes/create/route.ts
constant POST (line 16) | const POST = withCron(async ({ rawBody }) => {
FILE: apps/web/app/(ee)/api/cron/discount-codes/delete/route.ts
constant POST (line 15) | const POST = withCron(async ({ rawBody }) => {
FILE: apps/web/app/(ee)/api/cron/disposable-emails/route.ts
function POST (line 11) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/domains/delete/route.ts
function POST (line 21) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/domains/renewal-payments/route.ts
type GroupedWorkspace (line 20) | interface GroupedWorkspace {
function GET (line 26) | async function GET(req: Request) {
FILE: apps/web/app/(ee)/api/cron/domains/renewal-reminders/route.ts
constant REMINDER_WINDOWS (line 27) | const REMINDER_WINDOWS = [30, 23, 16];
function GET (line 30) | async function GET(req: Request) {
FILE: apps/web/app/(ee)/api/cron/domains/transfer/route.ts
function POST (line 20) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/domains/update/route.ts
constant LINK_BATCH_SIZE (line 18) | const LINK_BATCH_SIZE = 100;
function POST (line 21) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/domains/verify/route.ts
function GET (line 21) | async function GET(req: Request) {
FILE: apps/web/app/(ee)/api/cron/email-domains/update/route.ts
constant POST (line 15) | const POST = withCron(async ({ rawBody }) => {
FILE: apps/web/app/(ee)/api/cron/email-domains/verify/route.ts
constant GET (line 14) | const GET = withCron(async () => {
function verifyEmailDomain (line 47) | async function verifyEmailDomain(domain: EmailDomain) {
FILE: apps/web/app/(ee)/api/cron/export/commissions/fetch-commissions-batch.ts
type CommissionFilters (line 5) | type CommissionFilters = Omit<
FILE: apps/web/app/(ee)/api/cron/export/commissions/route.ts
function POST (line 23) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/export/customers/route.ts
constant MAX_CUSTOMERS_EXPORT_LIMIT (line 14) | const MAX_CUSTOMERS_EXPORT_LIMIT = 100_000;
constant POST (line 19) | const POST = withCron(async ({ rawBody }) => {
FILE: apps/web/app/(ee)/api/cron/export/events/partner/route.ts
function POST (line 39) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/export/events/workspace/route.ts
function POST (line 30) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/export/links/route.ts
function POST (line 28) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/export/partners/fetch-partners-batch.ts
type PartnerFilters (line 5) | type PartnerFilters = Omit<
FILE: apps/web/app/(ee)/api/cron/export/partners/route.ts
function POST (line 23) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/folders/delete/route.ts
constant MAX_LINKS_PER_BATCH (line 12) | const MAX_LINKS_PER_BATCH = 500;
function POST (line 20) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/framer/backfill-leads-batch/route.ts
type PayloadItem (line 31) | type PayloadItem = {
constant FRAMER_WORKSPACE_ID (line 38) | const FRAMER_WORKSPACE_ID = "clsvopiw0000ejy0grp821me0";
constant CACHE_KEY (line 39) | const CACHE_KEY = "framerMigratedExternalIdEventNames";
constant DOMAIN (line 40) | const DOMAIN = "framer.link";
constant POST (line 56) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/cron/fraud/summary/route.ts
constant PROGRAMS_BATCH_SIZE (line 17) | const PROGRAMS_BATCH_SIZE = 10;
function handler (line 26) | async function handler(req: Request) {
FILE: apps/web/app/(ee)/api/cron/fx-rates/route.ts
function POST (line 11) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/groups/create-default-links/route.ts
constant PAGE_SIZE (line 19) | const PAGE_SIZE = 100;
constant MAX_BATCH (line 20) | const MAX_BATCH = 10;
function POST (line 39) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/groups/remap-default-links/route.ts
function POST (line 43) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/groups/remap-default-links/utils.ts
function remapPartnerGroupDefaultLinks (line 5) | function remapPartnerGroupDefaultLinks({
FILE: apps/web/app/(ee)/api/cron/groups/remap-discount-codes/route.ts
constant POST (line 20) | const POST = withCron(async ({ rawBody }) => {
FILE: apps/web/app/(ee)/api/cron/groups/sync-utm/route.ts
constant PAGE_SIZE (line 16) | const PAGE_SIZE = 50;
function POST (line 34) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/groups/update-default-links/route.ts
constant PAGE_SIZE (line 16) | const PAGE_SIZE = 100;
constant MAX_BATCH (line 17) | const MAX_BATCH = 10;
function POST (line 35) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/import/bitly/fetch-utils.ts
type FetchBitlyLinksResult (line 7) | interface FetchBitlyLinksResult {
FILE: apps/web/app/(ee)/api/cron/import/bitly/route.ts
function POST (line 14) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/import/bitly/sanitize-json.ts
function sanitizeBitlyJson (line 1) | function sanitizeBitlyJson(body: string): string {
FILE: apps/web/app/(ee)/api/cron/import/csv/route.ts
type MapperResult (line 37) | interface MapperResult {
type ErrorLink (line 51) | interface ErrorLink {
function POST (line 58) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/import/csv/utils.ts
function sendCsvImportEmails (line 6) | async function sendCsvImportEmails({
FILE: apps/web/app/(ee)/api/cron/import/firstpromoter/route.ts
function POST (line 13) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/import/partnerstack/route.ts
function POST (line 14) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/import/rebrandly/route.ts
function POST (line 11) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/import/rewardful/route.ts
function POST (line 13) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/import/short/route.ts
function POST (line 11) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/import/tolt/route.ts
function POST (line 14) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/invoices/retry-failed/route.ts
function POST (line 14) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/links/[linkId]/complete-tests/route.ts
function POST (line 8) | async function POST(
FILE: apps/web/app/(ee)/api/cron/links/delete/route.ts
function POST (line 12) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/links/invalidate-for-discounts/route.ts
function POST (line 23) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/links/invalidate-for-partners/route.ts
function POST (line 15) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/messages/notify-partner/route.ts
function POST (line 23) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/messages/notify-program/route.ts
function POST (line 23) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/network/calculate-program-similarities/calculate-category-similarity.ts
function calculateCategorySimilarity (line 4) | async function calculateCategorySimilarity(
FILE: apps/web/app/(ee)/api/cron/network/calculate-program-similarities/calculate-partner-similarity.ts
type PartnerSimilarityResult (line 3) | interface PartnerSimilarityResult {
function calculatePartnerSimilarity (line 10) | async function calculatePartnerSimilarity(
FILE: apps/web/app/(ee)/api/cron/network/calculate-program-similarities/calculate-performance-similarity.ts
constant METRIC_KEYS (line 3) | const METRIC_KEYS = [
function calculatePerformanceSimilarity (line 12) | async function calculatePerformanceSimilarity(
FILE: apps/web/app/(ee)/api/cron/network/calculate-program-similarities/route.ts
constant PROGRAMS_PER_BATCH (line 25) | const PROGRAMS_PER_BATCH = 10;
function POST (line 30) | async function POST(req: Request) {
function calculateProgramSimilarity (line 52) | async function calculateProgramSimilarity({
function findNextProgram (line 215) | async function findNextProgram({
FILE: apps/web/app/(ee)/api/cron/network/update-partner-discoverability/route.ts
function POST (line 13) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/partner-platforms/route.ts
constant BATCH_SIZE (line 15) | const BATCH_SIZE = 50;
constant POST (line 26) | const POST = withCron(async ({ rawBody }) => {
FILE: apps/web/app/(ee)/api/cron/partner-platforms/youtube/route.ts
constant POST (line 16) | const POST = withCron(async () => {
FILE: apps/web/app/(ee)/api/cron/partner-program-summary/process/route.ts
constant PARTNER_BATCH_SIZE (line 15) | const PARTNER_BATCH_SIZE = 100;
type AnalyticsResponse (line 27) | interface AnalyticsResponse {
constant POST (line 38) | const POST = withCron(async ({ rawBody }) => {
FILE: apps/web/app/(ee)/api/cron/partner-program-summary/route.ts
constant PROGRAM_BATCH_SIZE (line 10) | const PROGRAM_BATCH_SIZE = 50;
constant GET (line 15) | const GET = withCron(async () => {
FILE: apps/web/app/(ee)/api/cron/partners/auto-approve/route.ts
constant POST (line 19) | const POST = withCron(async ({ rawBody }) => {
FILE: apps/web/app/(ee)/api/cron/partners/auto-reject/route.ts
constant POST (line 20) | const POST = withCron(async ({ rawBody }) => {
FILE: apps/web/app/(ee)/api/cron/partners/ban/cancel-commissions.ts
function cancelCommissions (line 4) | async function cancelCommissions({
FILE: apps/web/app/(ee)/api/cron/partners/ban/route.ts
constant POST (line 23) | const POST = withCron(async ({ rawBody }) => {
FILE: apps/web/app/(ee)/api/cron/partners/deactivate/route.ts
constant POST (line 17) | const POST = withCron(async ({ rawBody }) => {
FILE: apps/web/app/(ee)/api/cron/partners/merge-accounts/route.ts
constant CACHE_KEY_PREFIX (line 26) | const CACHE_KEY_PREFIX = "merge-partner-accounts";
function POST (line 30) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/payouts/aggregate-due-commissions/route.ts
constant BATCH_SIZE (line 13) | const BATCH_SIZE = 1000;
function handler (line 21) | async function handler(req: Request) {
FILE: apps/web/app/(ee)/api/cron/payouts/balance-available/route.ts
function POST (line 27) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/payouts/charge-succeeded/queue-external-payouts.ts
function queueExternalPayouts (line 9) | async function queueExternalPayouts(
FILE: apps/web/app/(ee)/api/cron/payouts/charge-succeeded/queue-stripe-payouts.ts
function queueStripePayouts (line 15) | async function queueStripePayouts(
FILE: apps/web/app/(ee)/api/cron/payouts/charge-succeeded/route.ts
function POST (line 24) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/payouts/charge-succeeded/send-paypal-payouts.ts
function sendPaypalPayouts (line 8) | async function sendPaypalPayouts(invoice: Pick<Invoice, "id">) {
FILE: apps/web/app/(ee)/api/cron/payouts/charge-succeeded/utils.ts
type StablecoinScheduleResult (line 10) | interface StablecoinScheduleResult {
function scheduleDelayedStablecoinPayouts (line 17) | async function scheduleDelayedStablecoinPayouts(invoice: {
FILE: apps/web/app/(ee)/api/cron/payouts/force-withdrawals/route.ts
constant BATCH_SIZE (line 14) | const BATCH_SIZE = 20;
function handler (line 22) | async function handler(req: Request) {
FILE: apps/web/app/(ee)/api/cron/payouts/payout-failed/route.ts
function POST (line 22) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/payouts/payout-paid/route.ts
function POST (line 22) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/payouts/process/process-payouts.ts
type ProcessPayoutsProps (line 34) | interface ProcessPayoutsProps {
function processPayouts (line 63) | async function processPayouts({
FILE: apps/web/app/(ee)/api/cron/payouts/process/route.ts
function POST (line 27) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/payouts/process/split-payouts.ts
function splitPayouts (line 11) | async function splitPayouts({
FILE: apps/web/app/(ee)/api/cron/payouts/process/updates/route.ts
constant BATCH_SIZE (line 19) | const BATCH_SIZE = 100;
function POST (line 23) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/payouts/reminders/partners/route.ts
constant BATCH_SIZE (line 14) | const BATCH_SIZE = 1000;
function handler (line 20) | async function handler(req: Request) {
FILE: apps/web/app/(ee)/api/cron/payouts/reminders/program-owners/route.ts
function GET (line 16) | async function GET(req: Request) {
FILE: apps/web/app/(ee)/api/cron/payouts/send-stripe-payout/route.ts
function POST (line 19) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/pending-applications-summary/route.ts
constant PROGRAMS_BATCH_SIZE (line 19) | const PROGRAMS_BATCH_SIZE = 50;
constant GET (line 28) | const GET = withCron(async ({ rawBody }) => {
constant POST (line 281) | const POST = GET;
FILE: apps/web/app/(ee)/api/cron/program-application-reminder/route.ts
function POST (line 11) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/programs/deactivate/route.ts
constant POST (line 17) | const POST = withCron(async ({ rawBody }) => {
FILE: apps/web/app/(ee)/api/cron/send-batch-email/route.ts
type BatchError (line 31) | interface BatchError {
function POST (line 38) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/shopify/order-paid/route.ts
function POST (line 15) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/streams/update-partner-stats/route.ts
constant BATCH_SIZE (line 16) | const BATCH_SIZE = 6000;
type ProgramEnrollmentStats (line 18) | type ProgramEnrollmentStats = Partial<
function GET (line 349) | async function GET(req: Request) {
FILE: apps/web/app/(ee)/api/cron/streams/update-workspace-clicks/route.ts
constant BATCH_SIZE (line 13) | const BATCH_SIZE = 10000;
type WorkspaceAggregateUsage (line 15) | type WorkspaceAggregateUsage = {
function GET (line 182) | async function GET(req: Request) {
FILE: apps/web/app/(ee)/api/cron/trigger-withdrawal/route.ts
function GET (line 12) | async function GET(req: Request) {
FILE: apps/web/app/(ee)/api/cron/usage/route.ts
function handler (line 14) | async function handler(req: Request) {
FILE: apps/web/app/(ee)/api/cron/utils.ts
function logAndRespond (line 1) | function logAndRespond(
FILE: apps/web/app/(ee)/api/cron/welcome-user/route.ts
function POST (line 17) | async function POST(req: Request) {
FILE: apps/web/app/(ee)/api/cron/workflows/[workflowId]/route.ts
function POST (line 13) | async function POST(
FILE: apps/web/app/(ee)/api/cron/workspaces/delete/delete-workspace-customers.ts
constant MAX_CUSTOMERS_PER_BATCH (line 9) | const MAX_CUSTOMERS_PER_BATCH = 100;
function deleteWorkspaceCustomers (line 11) | async function deleteWorkspaceCustomers(
FILE: apps/web/app/(ee)/api/cron/workspaces/delete/delete-workspace-domains.ts
constant MAX_DOMAINS_PER_BATCH (line 8) | const MAX_DOMAINS_PER_BATCH = 10;
function deleteWorkspaceDomains (line 10) | async function deleteWorkspaceDomains(payload: DeleteWorkspacePayload) {
FILE: apps/web/app/(ee)/api/cron/workspaces/delete/delete-workspace-folders.ts
constant MAX_FOLDERS_PER_BATCH (line 7) | const MAX_FOLDERS_PER_BATCH = 100;
function deleteWorkspaceFolders (line 9) | async function deleteWorkspaceFolders(payload: DeleteWorkspacePayload) {
FILE: apps/web/app/(ee)/api/cron/workspaces/delete/delete-workspace-links.ts
constant MAX_LINKS_PER_BATCH (line 8) | const MAX_LINKS_PER_BATCH = 100;
function deleteWorkspaceLinks (line 10) | async function deleteWorkspaceLinks(payload: DeleteWorkspacePayload) {
FILE: apps/web/app/(ee)/api/cron/workspaces/delete/delete-workspace.ts
function deleteWorkspace (line 5) | async function deleteWorkspace(payload: DeleteWorkspacePayload) {
FILE: apps/web/app/(ee)/api/cron/workspaces/delete/route.ts
constant POST (line 13) | const POST = withCron(async ({ rawBody }) => {
FILE: apps/web/app/(ee)/api/cron/workspaces/delete/utils.ts
type DeleteWorkspacePayload (line 21) | type DeleteWorkspacePayload = z.infer<typeof deleteWorkspaceSchema>;
function enqueueNextWorkspaceDeleteStep (line 23) | async function enqueueNextWorkspaceDeleteStep({
FILE: apps/web/app/(ee)/api/customers/[id]/activity/route.ts
constant GET (line 10) | const GET = withWorkspace(async ({ workspace, params }) => {
FILE: apps/web/app/(ee)/api/customers/[id]/route.ts
constant GET (line 19) | const GET = withWorkspace(
constant PATCH (line 54) | const PATCH = withWorkspace(
constant DELETE (line 166) | const DELETE = withWorkspace(
FILE: apps/web/app/(ee)/api/customers/[id]/stripe-invoices/route.ts
constant GET (line 8) | const GET = withWorkspace(async ({ workspace, params }) => {
FILE: apps/web/app/(ee)/api/customers/count/route.ts
constant GET (line 9) | const GET = withWorkspace(async ({ workspace, searchParams }) => {
FILE: apps/web/app/(ee)/api/customers/export/route.ts
constant MAX_CUSTOMERS_TO_EXPORT (line 13) | const MAX_CUSTOMERS_TO_EXPORT = 1000;
constant GET (line 16) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/customers/route.ts
constant GET (line 23) | const GET = withWorkspace(
constant POST (line 64) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/customers/search-stripe/route.ts
constant GET (line 13) | const GET = withWorkspace(async ({ workspace, searchParams }) => {
FILE: apps/web/app/(ee)/api/discount-codes/[discountCodeId]/route.ts
constant DELETE (line 11) | const DELETE = withWorkspace(
FILE: apps/web/app/(ee)/api/discount-codes/route.ts
constant GET (line 18) | const GET = withWorkspace(
constant POST (line 51) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/domains/register/route.ts
constant POST (line 10) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/domains/status/route.ts
constant GET (line 14) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/e2e/bounties/[bountyId]/route.ts
constant DELETE (line 8) | const DELETE = withWorkspace(async ({ params, workspace }) => {
FILE: apps/web/app/(ee)/api/e2e/enrollments/route.ts
constant PATCH (line 8) | const PATCH = withWorkspace(
FILE: apps/web/app/(ee)/api/e2e/guard.ts
function assertE2EWorkspace (line 5) | function assertE2EWorkspace(
FILE: apps/web/app/(ee)/api/e2e/notification-emails/route.ts
constant GET (line 9) | const GET = withWorkspace(async ({ workspace, searchParams }) => {
constant POST (line 26) | const POST = withWorkspace(
constant DELETE (line 53) | const DELETE = withWorkspace(
FILE: apps/web/app/(ee)/api/e2e/trigger-workflow/[workflowId]/route.ts
constant POST (line 13) | const POST = withWorkspace(async ({ workspace, params }) => {
FILE: apps/web/app/(ee)/api/e2e/workflows/[workflowId]/route.ts
constant PATCH (line 8) | const PATCH = withWorkspace(
FILE: apps/web/app/(ee)/api/e2e/workflows/route.ts
constant GET (line 8) | const GET = withWorkspace(async ({ workspace, searchParams }) => {
FILE: apps/web/app/(ee)/api/email-domains/[domain]/route.ts
constant PATCH (line 20) | const PATCH = withWorkspace(
constant DELETE (line 153) | const DELETE = withWorkspace(
FILE: apps/web/app/(ee)/api/email-domains/[domain]/verify/route.ts
constant GET (line 10) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/email-domains/route.ts
constant GET (line 20) | const GET = withWorkspace(
constant POST (line 39) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/embed/referrals/analytics/route.ts
constant GET (line 7) | const GET = withReferralsEmbedToken(async ({ links, program }) => {
FILE: apps/web/app/(ee)/api/embed/referrals/earnings/route.ts
constant GET (line 11) | const GET = withReferralsEmbedToken(
FILE: apps/web/app/(ee)/api/embed/referrals/leaderboard/route.ts
constant GET (line 10) | const GET = withReferralsEmbedToken(async ({ program }) => {
FILE: apps/web/app/(ee)/api/embed/referrals/links/[linkId]/route.ts
constant PATCH (line 19) | const PATCH = withReferralsEmbedToken(
FILE: apps/web/app/(ee)/api/embed/referrals/links/route.ts
constant GET (line 17) | const GET = withReferralsEmbedToken(async ({ links }) => {
constant POST (line 24) | const POST = withReferralsEmbedToken(
FILE: apps/web/app/(ee)/api/embed/referrals/token/route.ts
constant GET (line 5) | const GET = withReferralsEmbedToken(async ({ embedToken }) => {
FILE: apps/web/app/(ee)/api/events/export/route.ts
constant MAX_EVENTS_TO_EXPORT (line 20) | const MAX_EVENTS_TO_EXPORT = 1000;
constant GET (line 32) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/events/route.ts
constant GET (line 12) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/fraud/events/count/route.ts
constant GET (line 9) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/fraud/events/route.ts
constant GET (line 14) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/fraud/groups/count/route.ts
constant GET (line 13) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/fraud/groups/route.ts
constant GET (line 12) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/fraud/rules/route.ts
constant GET (line 32) | const GET = withWorkspace(
constant PATCH (line 76) | const PATCH = withWorkspace(
FILE: apps/web/app/(ee)/api/groups/[groupIdOrSlug]/default-links/[defaultLinkId]/route.ts
constant PATCH (line 18) | const PATCH = withWorkspace(
constant DELETE (line 159) | const DELETE = withWorkspace(
FILE: apps/web/app/(ee)/api/groups/[groupIdOrSlug]/default-links/route.ts
constant GET (line 21) | const GET = withWorkspace(
constant POST (line 57) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/groups/[groupIdOrSlug]/default/route.ts
constant POST (line 14) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/groups/[groupIdOrSlug]/partners/route.ts
constant POST (line 16) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/groups/[groupIdOrSlug]/route.ts
constant GET (line 23) | const GET = withWorkspace(
constant PATCH (line 50) | const PATCH = withWorkspace(
constant DELETE (line 272) | const DELETE = withWorkspace(
FILE: apps/web/app/(ee)/api/groups/count/route.ts
constant GET (line 8) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/groups/route.ts
constant GET (line 22) | const GET = withWorkspace(
constant POST (line 50) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/groups/rules/route.ts
constant GET (line 8) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/hubspot/webhook/route.ts
constant HUBSPOT_CLIENT_SECRET (line 14) | const HUBSPOT_CLIENT_SECRET = process.env.HUBSPOT_CLIENT_SECRET || "";
constant POST (line 17) | const POST = withAxiom(async (req) => {
function processWebhookEvent (line 65) | async function processWebhookEvent(event: any) {
FILE: apps/web/app/(ee)/api/messages/count/route.ts
constant GET (line 8) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/messages/route.ts
constant GET (line 11) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/mock/rewardful/affiliates/route.ts
function GET (line 3) | async function GET(request: NextRequest) {
FILE: apps/web/app/(ee)/api/mock/rewardful/campaigns/[campaignId]/route.ts
function GET (line 4) | async function GET(
FILE: apps/web/app/(ee)/api/mock/rewardful/campaigns/route.ts
function GET (line 4) | async function GET() {
FILE: apps/web/app/(ee)/api/mock/rewardful/commissions/route.ts
function GET (line 3) | async function GET(request: NextRequest) {
FILE: apps/web/app/(ee)/api/mock/rewardful/referrals/route.ts
function GET (line 3) | async function GET(request: NextRequest) {
FILE: apps/web/app/(ee)/api/network/partners/count/route.ts
constant GET (line 10) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/network/partners/invites-usage/route.ts
constant GET (line 6) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/network/partners/route.ts
constant GET (line 17) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/network/programs/count/route.ts
constant GET (line 16) | const GET = withPartnerProfile(async ({ partner, searchParams }) => {
FILE: apps/web/app/(ee)/api/network/programs/route.ts
constant GET (line 12) | const GET = withPartnerProfile(async ({ partner, searchParams }) => {
FILE: apps/web/app/(ee)/api/partner-profile/invites/accept/route.ts
constant POST (line 7) | const POST = withSession(async ({ session }) => {
FILE: apps/web/app/(ee)/api/partner-profile/invites/route.ts
constant GET (line 21) | const GET = withPartnerProfile(async ({ partner, searchParams }) => {
constant POST (line 46) | const POST = withPartnerProfile(
constant PATCH (line 169) | const PATCH = withPartnerProfile(
constant DELETE (line 215) | const DELETE = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/messages/count/route.ts
constant GET (line 7) | const GET = withPartnerProfile(async ({ partner, searchParams }) => {
FILE: apps/web/app/(ee)/api/partner-profile/messages/route.ts
constant GET (line 10) | const GET = withPartnerProfile(async ({ partner, searchParams }) => {
FILE: apps/web/app/(ee)/api/partner-profile/notification-preferences/route.ts
constant GET (line 6) | const GET = withPartnerProfile(async ({ partner, session }) => {
FILE: apps/web/app/(ee)/api/partner-profile/payouts/count/route.ts
constant GET (line 8) | const GET = withPartnerProfile(async ({ partner, searchParams }) => {
FILE: apps/web/app/(ee)/api/partner-profile/payouts/route.ts
constant GET (line 10) | const GET = withPartnerProfile(async ({ partner, searchParams }) => {
FILE: apps/web/app/(ee)/api/partner-profile/payouts/settings/route.ts
constant GET (line 6) | const GET = withPartnerProfile(async ({ partner }) => {
FILE: apps/web/app/(ee)/api/partner-profile/postbacks/[postbackId]/events/route.ts
constant GET (line 7) | const GET = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/postbacks/[postbackId]/rotate-secret/route.ts
constant POST (line 12) | const POST = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/postbacks/[postbackId]/route.ts
constant GET (line 12) | const GET = withPartnerProfile(
constant PATCH (line 30) | const PATCH = withPartnerProfile(
constant DELETE (line 66) | const DELETE = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/postbacks/[postbackId]/send-test/route.ts
constant POST (line 20) | const POST = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/postbacks/route.ts
constant GET (line 22) | const GET = withPartnerProfile(
constant POST (line 42) | const POST = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/activity-logs/route.ts
constant GET (line 12) | const GET = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/analytics/export/route.ts
constant GET (line 18) | const GET = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/analytics/route.ts
constant GET (line 16) | const GET = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/bounties/[bountyId]/route.ts
constant GET (line 10) | const GET = withPartnerProfile(async ({ partner, params }) => {
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/bounties/[bountyId]/social-content-stats/route.ts
constant GET (line 16) | const GET = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/bounties/route.ts
constant GET (line 10) | const GET = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/customers/[customerId]/route.ts
constant GET (line 20) | const GET = withPartnerProfile(async ({ partner, params }) => {
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/customers/count/route.ts
constant GET (line 15) | const GET = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/customers/route.ts
constant GET (line 22) | const GET = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/earnings/count/route.ts
constant GET (line 12) | const GET = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/earnings/route.ts
constant GET (line 15) | const GET = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/earnings/timeseries/route.ts
constant GET (line 7) | const GET = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/events/export/route.ts
constant MAX_EVENTS_TO_EXPORT (line 33) | const MAX_EVENTS_TO_EXPORT = 1000;
constant GET (line 36) | const GET = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/events/route.ts
constant GET (line 22) | const GET = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/groups/[groupIdOrSlug]/route.ts
constant GET (line 7) | const GET = withPartnerProfile(async ({ params }) => {
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/links/[linkId]/route.ts
constant PATCH (line 16) | const PATCH = withPartnerProfile(
constant DELETE (line 159) | const DELETE = withPartnerProfile(async ({ partner, params }) => {
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/links/route.ts
constant GET (line 19) | const GET = withPartnerProfile(async ({ partner, params }) => {
constant POST (line 47) | const POST = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/referrals/count/route.ts
constant GET (line 12) | const GET = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/referrals/route.ts
constant GET (line 12) | const GET = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/resources/route.ts
constant GET (line 7) | const GET = withPartnerProfile(async ({ partner, params }) => {
FILE: apps/web/app/(ee)/api/partner-profile/programs/[programId]/route.ts
constant GET (line 8) | const GET = withPartnerProfile(async ({ partner, params }) => {
FILE: apps/web/app/(ee)/api/partner-profile/programs/count/route.ts
constant GET (line 7) | const GET = withPartnerProfile(async ({ partner, searchParams }) => {
FILE: apps/web/app/(ee)/api/partner-profile/programs/route.ts
constant GET (line 10) | const GET = withPartnerProfile(async ({ partner, searchParams }) => {
FILE: apps/web/app/(ee)/api/partner-profile/rewind/route.ts
constant GET (line 7) | const GET = withPartnerProfile(async ({ partner }) => {
FILE: apps/web/app/(ee)/api/partner-profile/route.ts
constant GET (line 6) | const GET = withPartnerProfile(async ({ partner, partnerUser }) => {
FILE: apps/web/app/(ee)/api/partner-profile/users/route.ts
constant GET (line 15) | const GET = withPartnerProfile(async ({ partner, searchParams }) => {
constant PATCH (line 63) | const PATCH = withPartnerProfile(
constant DELETE (line 140) | const DELETE = withPartnerProfile(
FILE: apps/web/app/(ee)/api/partners/[partnerId]/application-risks/route.ts
constant GET (line 8) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/partners/[partnerId]/comments/count/route.ts
constant GET (line 7) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/partners/[partnerId]/comments/route.ts
constant GET (line 9) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/partners/[partnerId]/cross-program-summary/route.ts
constant GET (line 12) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/partners/[partnerId]/route.ts
constant GET (line 9) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/partners/analytics/route.ts
constant GET (line 18) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/partners/ban/route.ts
constant POST (line 12) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/partners/count/route.ts
constant GET (line 8) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/partners/deactivate/route.ts
constant POST (line 13) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/partners/export/route.ts
constant MAX_PARTNERS_TO_EXPORT (line 12) | const MAX_PARTNERS_TO_EXPORT = 1000;
constant GET (line 15) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/partners/links/route.ts
constant GET (line 24) | const GET = withWorkspace(
constant POST (line 70) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/partners/links/upsert/route.ts
constant PUT (line 26) | const PUT = withWorkspace(
FILE: apps/web/app/(ee)/api/partners/platforms/callback/route.ts
type State (line 21) | interface State {
function GET (line 28) | async function GET(req: Request) {
FILE: apps/web/app/(ee)/api/partners/route.ts
constant GET (line 19) | const GET = withWorkspace(
constant POST (line 103) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/payouts/[payoutId]/route.ts
constant GET (line 11) | const GET = withWorkspace(async ({ workspace, params }) => {
FILE: apps/web/app/(ee)/api/payouts/count/route.ts
constant GET (line 11) | const GET = withWorkspace(async ({ workspace, searchParams }) => {
FILE: apps/web/app/(ee)/api/payouts/route.ts
constant GET (line 16) | const GET = withWorkspace(async ({ workspace, searchParams }) => {
FILE: apps/web/app/(ee)/api/paypal/webhook/payouts-item-failed.ts
constant PAYPAL_TO_DUB_STATUS (line 6) | const PAYPAL_TO_DUB_STATUS = {
function payoutsItemFailed (line 14) | async function payoutsItemFailed(event: any) {
FILE: apps/web/app/(ee)/api/paypal/webhook/payouts-item-succeeded.ts
function payoutsItemSucceeded (line 4) | async function payoutsItemSucceeded(event: any) {
FILE: apps/web/app/(ee)/api/paypal/webhook/verify-signature.ts
constant CERT_CACHE_KEY_PREFIX (line 7) | const CERT_CACHE_KEY_PREFIX = "paypal:cert:";
constant CERT_CACHE_TTL_SECONDS (line 8) | const CERT_CACHE_TTL_SECONDS = 60 * 60 * 24 * 7;
function downloadAndCache (line 10) | async function downloadAndCache(url: string) {
function verifySignature (line 42) | async function verifySignature({
FILE: apps/web/app/(ee)/api/programs/[programId]/applications/[applicationId]/route.ts
constant GET (line 7) | const GET = withWorkspace(async ({ workspace, params }) => {
FILE: apps/web/app/(ee)/api/programs/[programId]/applications/export/route.ts
constant GET (line 24) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/programs/[programId]/discounts/route.ts
constant GET (line 10) | const GET = withWorkspace(async ({ workspace }) => {
FILE: apps/web/app/(ee)/api/programs/[programId]/payouts/eligible/count/route.ts
constant GET (line 14) | const GET = withWorkspace(async ({ workspace, searchParams }) => {
FILE: apps/web/app/(ee)/api/programs/[programId]/payouts/eligible/route.ts
constant GET (line 19) | const GET = withWorkspace(async ({ workspace, searchParams }) => {
FILE: apps/web/app/(ee)/api/programs/[programId]/referrals/count/route.ts
constant GET (line 12) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/programs/[programId]/referrals/route.ts
constant GET (line 13) | const GET = withWorkspace(
FILE: apps/web/app/(ee)/api/programs/[programId]/resources/route.ts
constant GET (line 8) | const GET = withWorkspace(async ({ workspace }) => {
FILE: apps/web/app/(ee)/api/programs/[programId]/route.ts
constant GET (line 7) | const GET = withWorkspace(async ({ workspace, params }) => {
FILE: apps/web/app/(ee)/api/programs/rewardful/campaigns/route.ts
constant GET (line 7) | const GET = withWorkspace(async ({ workspace }) => {
FILE: apps/web/app/(ee)/api/rewards/[rewardId]/route.ts
constant GET (line 8) | const GET = withWorkspace(async ({ workspace, params }) => {
FILE: apps/web/app/(ee)/api/rewards/route.ts
constant GET (line 9) | const GET = withWorkspace(async ({ workspace }) => {
FILE: apps/web/app/(ee)/api/shopify/integration/callback/route.ts
constant PATCH (line 12) | const PATCH = withWorkspace(
FILE: apps/web/app/(ee)/api/shopify/integration/webhook/app-uninstalled.ts
function appUninstalled (line 3) | async function appUninstalled({ shopDomain }: { shopDomain: string }) {
FILE: apps/web/app/(ee)/api/shopify/integration/webhook/customers-data-request.ts
function customersDataRequest (line 14) | async function customersDataRequest({
FILE: apps/web/app/(ee)/api/shopify/integration/webhook/customers-redact.ts
function customersRedact (line 15) | async function customersRedact({
FILE: apps/web/app/(ee)/api/shopify/integration/webhook/orders-paid.ts
function ordersPaid (line 8) | async function ordersPaid({
FILE: apps/web/app/(ee)/api/shopify/integration/webhook/shop-redact.ts
function shopRedact (line 10) | async function shopRedact({
FILE: apps/web/app/(ee)/api/singular/webhook/route.ts
constant GET (line 40) | const GET = withAxiom(async (req) => {
FILE: apps/web/app/(ee)/api/stripe/connect/v2/webhook/outbound-payment-failed.ts
function outboundPaymentFailed (line 7) | async function outboundPaymentFailed(event: Stripe.ThinEvent) {
FILE: apps/web/app/(ee)/api/stripe/connect/v2/webhook/outbound-payment-posted.ts
function outboundPaymentPosted (line 6) | async function outboundPaymentPosted(event: Stripe.ThinEvent) {
FILE: apps/web/app/(ee)/api/stripe/connect/v2/webhook/outbound-payment-returned.ts
function outboundPaymentReturned (line 7) | async function outboundPaymentReturned(event: Stripe.ThinEvent) {
FILE: apps/web/app/(ee)/api/stripe/connect/v2/webhook/recipient-account-closed.ts
function recipientAccountClosed (line 6) | async function recipientAccountClosed(event: Stripe.ThinEvent) {
FILE: apps/web/app/(ee)/api/stripe/connect/v2/webhook/recipient-configuration-updated.ts
function recipientConfigurationUpdated (line 8) | async function recipientConfigurationUpdated(event: Stripe.ThinEvent) {
FILE: apps/web/app/(ee)/api/stripe/connect/webhook/account-application-deauthorized.ts
function accountApplicationDeauthorized (line 5) | async function accountApplicationDeauthorized(event: Stripe.Event) {
FILE: apps/web/app/(ee)/api/stripe/connect/webhook/account-updated.ts
function accountUpdated (line 20) | async function accountUpdated(event: Stripe.Event) {
FILE: apps/web/app/(ee)/api/stripe/connect/webhook/balance-available.ts
function balanceAvailable (line 9) | async function balanceAvailable(event: Stripe.Event) {
FILE: apps/web/app/(ee)/api/stripe/connect/webhook/payout-failed.ts
function payoutFailed (line 9) | async function payoutFailed(event: Stripe.Event) {
FILE: apps/web/app/(ee)/api/stripe/connect/webhook/payout-paid.ts
function payoutPaid (line 9) | async function payoutPaid(event: Stripe.Event) {
FILE: apps/web/app/(ee)/api/stripe/integration/route.ts
constant CORS_HEADERS (line 11) | const CORS_HEADERS = new Headers({
constant PATCH (line 18) | const PATCH = withWorkspace(
FILE: apps/web/app/(ee)/api/stripe/integration/webhook/account-application-deauthorized.ts
function accountApplicationDeauthorized (line 7) | async function accountApplicationDeauthorized(
FILE: apps/web/app/(ee)/api/stripe/integration/webhook/charge-refunded.ts
function chargeRefunded (line 8) | async function chargeRefunded(event: Stripe.Event, mode: StripeMode) {
FILE: apps/web/app/(ee)/api/stripe/integration/webhook/checkout-session-completed.ts
function checkoutSessionCompleted (line 36) | async function checkoutSessionCompleted(
function attributeViaPromoCode (line 555) | async function attributeViaPromoCode({
function incrementLinkLeads (line 749) | async function incrementLinkLeads(linkId: string) {
FILE: apps/web/app/(ee)/api/stripe/integration/webhook/coupon-deleted.ts
function couponDeleted (line 12) | async function couponDeleted(event: Stripe.Event) {
FILE: apps/web/app/(ee)/api/stripe/integration/webhook/customer-created.ts
function customerCreated (line 6) | async function customerCreated(event: Stripe.Event) {
FILE: apps/web/app/(ee)/api/stripe/integration/webhook/customer-subscription-created.ts
function customerSubscriptionCreated (line 13) | async function customerSubscriptionCreated(
FILE: apps/web/app/(ee)/api/stripe/integration/webhook/customer-subscription-deleted.ts
function customerSubscriptionDeleted (line 5) | async function customerSubscriptionDeleted(event: Stripe.Event) {
FILE: apps/web/app/(ee)/api/stripe/integration/webhook/customer-updated.ts
function customerUpdated (line 6) | async function customerUpdated(event: Stripe.Event) {
FILE: apps/web/app/(ee)/api/stripe/integration/webhook/invoice-paid.ts
function invoicePaid (line 21) | async function invoicePaid(event: Stripe.Event, mode: StripeMode) {
FILE: apps/web/app/(ee)/api/stripe/integration/webhook/promotion-code-updated.ts
function promotionCodeUpdated (line 5) | async function promotionCodeUpdated(event: Stripe.Event) {
FILE: apps/web/app/(ee)/api/stripe/integration/webhook/route.ts
constant POST (line 31) | const POST = withAxiom(async (req: Request) => {
FILE: apps/web/app/(ee)/api/stripe/integration/webhook/utils/create-new-customer.ts
function createNewCustomer (line 16) | async function createNewCustomer(event: Stripe.Event) {
FILE: apps/web/app/(ee)/api/stripe/integration/webhook/utils/get-connected-customer.ts
function getConnectedCustomer (line 4) | async function getConnectedCustomer({
FILE: apps/web/app/(ee)/api/stripe/integration/webhook/utils/get-promotion-code.ts
function getPromotionCode (line 4) | async function getPromotionCode({
FILE: apps/web/app/(ee)/api/stripe/integration/webhook/utils/get-subscription-product-id.ts
function getSubscriptionProductId (line 4) | async function getSubscriptionProductId({
FILE: apps/web/app/(ee)/api/stripe/integration/webhook/utils/update-customer-with-stripe-customer-id.ts
function updateCustomerWithStripeCustomerId (line 3) | async function updateCustomerWithStripeCustomerId({
FILE: apps/web/app/(ee)/api/stripe/webhook/charge-failed.ts
function chargeFailed (line 6) | async function chargeFailed(event: Stripe.Event) {
FILE: apps/web/app/(ee)/api/stripe/webhook/charge-refunded.ts
function chargeRefunded (line 6) | async function chargeRefunded(event: Stripe.Event) {
function processDomainRenewalInvoice (line 33) | async function processDomainRenewalInvoice({ invoice }: { invoice: Invoi...
FILE: apps/web/app/(ee)/api/stripe/webhook/charge-succeeded.ts
function chargeSucceeded (line 11) | async function chargeSucceeded(event: Stripe.Event) {
function processPayoutInvoice (line 75) | async function processPayoutInvoice({ invoice }: { invoice: Invoice }) {
function processDomainRenewalInvoice (line 107) | async function processDomainRenewalInvoice({ invoice }: { invoice: Invoi...
FILE: apps/web/app/(ee)/api/stripe/webhook/checkout-session-completed.ts
function checkoutSessionCompleted (line 15) | async function checkoutSessionCompleted(event: Stripe.Event) {
function completeOnboarding (line 143) | async function completeOnboarding({
FILE: apps/web/app/(ee)/api/stripe/webhook/customer-subscription-deleted.ts
function customerSubscriptionDeleted (line 17) | async function customerSubscriptionDeleted(event: Stripe.Event) {
FILE: apps/web/app/(ee)/api/stripe/webhook/customer-subscription-updated.ts
function customerSubscriptionUpdated (line 7) | async function customerSubscriptionUpdated(event: Stripe.Event) {
FILE: apps/web/app/(ee)/api/stripe/webhook/invoice-payment-failed.tsx
function invoicePaymentFailed (line 6) | async function invoicePaymentFailed(event: Stripe.Event) {
FILE: apps/web/app/(ee)/api/stripe/webhook/payment-intent-requires-action.ts
function paymentIntentRequiresAction (line 6) | async function paymentIntentRequiresAction(event: Stripe.Event) {
FILE: apps/web/app/(ee)/api/stripe/webhook/transfer-reversed.ts
function transferReversed (line 5) | async function transferReversed(event: Stripe.Event) {
FILE: apps/web/app/(ee)/api/stripe/webhook/utils/process-domain-renewal-failure.ts
function processDomainRenewalFailure (line 10) | async function processDomainRenewalFailure({
FILE: apps/web/app/(ee)/api/stripe/webhook/utils/process-payout-invoice-failure.ts
function processPayoutInvoiceFailure (line 14) | async function processPayoutInvoiceFailure({
FILE: apps/web/app/(ee)/api/stripe/webhook/utils/send-cancellation-feedback.ts
function sendCancellationFeedback (line 14) | async function sendCancellationFeedback({
FILE: apps/web/app/(ee)/api/stripe/webhook/utils/update-workspace-plan.ts
function updateWorkspacePlan (line 14) | async function updateWorkspacePlan({
FILE: apps/web/app/(ee)/api/track/click/route.ts
constant POST (line 58) | const POST = withAxiom(async (req) => {
FILE: apps/web/app/(ee)/api/track/lead/client/route.ts
constant POST (line 14) | const POST = withPublishableKey(
FILE: apps/web/app/(ee)/api/track/lead/route.ts
constant POST (line 10) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/track/open/route.ts
constant POST (line 22) | const POST = withAxiom(async (req) => {
FILE: apps/web/app/(ee)/api/track/sale/client/route.ts
constant POST (line 14) | const POST = withPublishableKey(
FILE: apps/web/app/(ee)/api/track/sale/route.ts
constant POST (line 10) | const POST = withWorkspace(
FILE: apps/web/app/(ee)/api/track/visit/route.ts
constant POST (line 18) | const POST = withAxiom(async (req) => {
FILE: apps/web/app/(ee)/api/workflows/partner-approved/route.ts
type Payload (line 24) | type Payload = z.infer<typeof payloadSchema>;
FILE: apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/layout.tsx
function NewProgramWorkspaceLayout (line 4) | function NewProgramWorkspaceLayout({
FILE: apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/form.tsx
function Form (line 15) | function Form() {
FILE: apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/overview/page-client.tsx
function PageClient (line 17) | function PageClient() {
FILE: apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/overview/page.tsx
function Page (line 4) | async function Page() {
FILE: apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/page.tsx
function Page (line 4) | async function Page() {
FILE: apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/partners/form.tsx
function Form (line 16) | function Form() {
FILE: apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/partners/page.tsx
function Page (line 4) | async function Page() {
FILE: apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/rewards/form.tsx
constant DEFAULT_REWARD_TYPES (line 17) | const DEFAULT_REWARD_TYPES = [
constant COMMISSION_STRUCTURE_DESCRIPTIONS (line 32) | const COMMISSION_STRUCTURE_DESCRIPTIONS: Record<string, string> = {
constant PAYOUT_MODELS (line 37) | const PAYOUT_MODELS = [
function Form (line 52) | function Form() {
FILE: apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/rewards/page.tsx
function ProgramOnboardingRewardsPage (line 4) | async function ProgramOnboardingRewardsPage() {
FILE: apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/step-page.tsx
function StepPage (line 4) | function StepPage({
FILE: apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/support/form.tsx
function Form (line 13) | function Form() {
FILE: apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/support/page.tsx
function Page (line 4) | function Page() {
FILE: apps/web/app/(ee)/app.dub.co/(new-program)/header.tsx
function ProgramOnboardingHeader (line 16) | function ProgramOnboardingHeader() {
FILE: apps/web/app/(ee)/app.dub.co/(new-program)/layout.tsx
function Layout (line 8) | function Layout({ children }: { children: React.ReactNode }) {
FILE: apps/web/app/(ee)/app.dub.co/(new-program)/sidebar-context.tsx
type SidebarContextType (line 8) | interface SidebarContextType {
function SidebarProvider (line 15) | function SidebarProvider({ children }: { children: ReactNode }) {
function useSidebar (line 42) | function useSidebar() {
FILE: apps/web/app/(ee)/app.dub.co/(new-program)/steps.tsx
function ProgramOnboardingSteps (line 14) | function ProgramOnboardingSteps() {
FILE: apps/web/app/(ee)/app.dub.co/embed/referrals/activity.tsx
function ReferralsEmbedActivity (line 9) | function ReferralsEmbedActivity({
function EmptyState (line 102) | function EmptyState() {
function EmptyStateBackground (line 126) | function EmptyStateBackground({ className, ...rest }: SVGProps<SVGSVGEle...
FILE: apps/web/app/(ee)/app.dub.co/embed/referrals/add-edit-link.tsx
type Props (line 27) | interface Props {
type FormData (line 34) | interface FormData {
function ReferralsEmbedCreateUpdateLink (line 39) | function ReferralsEmbedCreateUpdateLink({
function DestinationDomainCombobox (line 302) | function DestinationDomainCombobox({
FILE: apps/web/app/(ee)/app.dub.co/embed/referrals/dynamic-height-messenger.tsx
function DynamicHeightMessenger (line 5) | function DynamicHeightMessenger() {
FILE: apps/web/app/(ee)/app.dub.co/embed/referrals/earnings-summary.tsx
function ReferralsEmbedEarningsSummary (line 4) | function ReferralsEmbedEarningsSummary({
FILE: apps/web/app/(ee)/app.dub.co/embed/referrals/earnings.tsx
function ReferralsEmbedEarnings (line 22) | function ReferralsEmbedEarnings({ salesCount }: { salesCount: number }) {
FILE: apps/web/app/(ee)/app.dub.co/embed/referrals/faq.tsx
function ReferralsEmbedFAQ (line 15) | function ReferralsEmbedFAQ({
FILE: apps/web/app/(ee)/app.dub.co/embed/referrals/leaderboard.tsx
function ReferralsEmbedLeaderboard (line 18) | function ReferralsEmbedLeaderboard() {
FILE: apps/web/app/(ee)/app.dub.co/embed/referrals/links-list.tsx
type Props (line 27) | interface Props {
function ReferralsEmbedLinksList (line 38) | function ReferralsEmbedLinksList({
FILE: apps/web/app/(ee)/app.dub.co/embed/referrals/links.tsx
type Props (line 8) | interface Props {
function ReferralsEmbedLinks (line 17) | function ReferralsEmbedLinks({ links, program, group }: Props) {
FILE: apps/web/app/(ee)/app.dub.co/embed/referrals/page-client.tsx
function ReferralsEmbedPageClient (line 42) | function ReferralsEmbedPageClient({
function ReferralLinkDisplay (line 241) | function ReferralLinkDisplay({
function Menu (line 415) | function Menu({
FILE: apps/web/app/(ee)/app.dub.co/embed/referrals/page.tsx
function ReferralsEmbedPage (line 9) | async function ReferralsEmbedPage(props: {
function ReferralsEmbedRSC (line 40) | async function ReferralsEmbedRSC({
function EmbedInlineLoading (line 60) | function EmbedInlineLoading({ themeOptions }: { themeOptions: ThemeOptio...
FILE: apps/web/app/(ee)/app.dub.co/embed/referrals/quickstart.tsx
constant BUTTON_CLASSNAME (line 20) | const BUTTON_CLASSNAME = "h-9 rounded-lg bg-bg-inverted hover:bg-neutral...
function ReferralsEmbedQuickstart (line 22) | function ReferralsEmbedQuickstart({
constant BG_MUTED (line 184) | const BG_MUTED = "rgb(var(--bg-muted))";
constant BG_DEFAULT (line 185) | const BG_DEFAULT = "rgb(var(--bg-default))";
constant BORDER_SUBTLE (line 186) | const BORDER_SUBTLE = "rgb(var(--border-subtle))";
constant CONTENT_SUBTLE (line 187) | const CONTENT_SUBTLE = "rgb(var(--content-subtle))";
FILE: apps/web/app/(ee)/app.dub.co/embed/referrals/resources.tsx
function ReferralsEmbedResources (line 14) | function ReferralsEmbedResources({
FILE: apps/web/app/(ee)/app.dub.co/embed/referrals/theme-options.ts
type ThemeOptions (line 3) | type ThemeOptions = {
function parseThemeOptions (line 7) | function parseThemeOptions(themeOptions?: string): ThemeOptions {
FILE: apps/web/app/(ee)/app.dub.co/embed/referrals/types.ts
type ReferralsEmbedLink (line 4) | type ReferralsEmbedLink = z.infer<typeof ReferralsEmbedLinkSchema>;
FILE: apps/web/app/(ee)/app.dub.co/invoices/[invoiceId]/domain-renewal-invoice.tsx
function DomainRenewalInvoice (line 25) | async function DomainRenewalInvoice({
FILE: apps/web/app/(ee)/app.dub.co/invoices/[invoiceId]/partner-payout-invoice.tsx
function PartnerPayoutInvoice (line 35) | async function PartnerPayoutInvoice({
FILE: apps/web/app/(ee)/app.dub.co/invoices/[invoiceId]/route.tsx
constant GET (line 9) | const GET = withSession(async ({ session, params }) => {
FILE: apps/web/app/(ee)/partners.dub.co/(apply)/[programSlug]/(default)/apply-button.tsx
function ApplyButton (line 7) | function ApplyButton({
FILE: apps/web/app/(ee)/partners.dub.co/(apply)/[programSlug]/(default)/apply/page.tsx
function ApplicationPage (line 11) | async function ApplicationPage(props: {
FILE: apps/web/app/(ee)/partners.dub.co/(apply)/[programSlug]/(default)/apply/success/cta-buttons.tsx
function CTAButtons (line 8) | function CTAButtons() {
FILE: apps/web/app/(ee)/partners.dub.co/(apply)/[programSlug]/(default)/apply/success/page.tsx
constant FEATURES (line 17) | const FEATURES = [
function SuccessPage (line 44) | async function SuccessPage(props: {
FILE: apps/web/app/(ee)/partners.dub.co/(apply)/[programSlug]/(default)/apply/success/pixel-conversion.tsx
type Window (line 8) | interface Window {
function PixelConversion (line 18) | function PixelConversion() {
function PixelConversionHelper (line 28) | function PixelConversionHelper() {
FILE: apps/web/app/(ee)/partners.dub.co/(apply)/[programSlug]/(default)/apply/success/screenshot.tsx
function Screenshot (line 5) | function Screenshot({
FILE: apps/web/app/(ee)/partners.dub.co/(apply)/[programSlug]/(default)/header.tsx
function ApplyHeader (line 10) | function ApplyHeader({
FILE: apps/web/app/(ee)/partners.dub.co/(apply)/[programSlug]/(default)/layout.tsx
function generateMetadata (line 13) | async function generateMetadata(props: {
function generateStaticParams (line 41) | async function generateStaticParams() {
function ApplyLayout (line 50) | async function ApplyLayout(
FILE: apps/web/app/(ee)/partners.dub.co/(apply)/[programSlug]/(default)/page.tsx
function ApplyPage (line 12) | async function ApplyPage(props: {
FILE: apps/web/app/(ee)/partners.dub.co/(auth-login-register)/(generic)/layout.tsx
function generateMetadata (line 12) | async function generateMetadata(props: {
function generateStaticParams (line 45) | async function generateStaticParams() {
function PartnerAuthLayout (line 53) | async function PartnerAuthLayout(props: {
FILE: apps/web/app/(ee)/partners.dub.co/(auth-login-register)/(generic)/login/page.tsx
function LoginPage (line 10) | async function LoginPage(props: {
FILE: apps/web/app/(ee)/partners.dub.co/(auth-login-register)/(generic)/register/page-client.tsx
type PartialProgram (line 17) | type PartialProgram = Pick<Program, "name" | "logo" | "slug">;
function RegisterPageClient (line 19) | function RegisterPageClient({
function SignUp (line 44) | function SignUp({ program }: { program?: PartialProgram }) {
function Verify (line 80) | function Verify() {
FILE: apps/web/app/(ee)/partners.dub.co/(auth-login-register)/(generic)/register/page.tsx
function RegisterPage (line 7) | async function RegisterPage(props: {
FILE: apps/web/app/(ee)/partners.dub.co/(auth-login-register)/partner-banner.tsx
function PartnerBanner (line 5) | function PartnerBanner({
FILE: apps/web/app/(ee)/partners.dub.co/(auth-login-register)/program-logos.tsx
constant LOGO_COUNT (line 4) | const LOGO_COUNT = 13;
constant ROW_COUNT (line 5) | const ROW_COUNT = 4;
constant ROWS (line 8) | const ROWS = [...Array(ROW_COUNT)].map(() => {
constant BLUR_STEPS (line 27) | const BLUR_STEPS = 5;
constant BLUR_STEP_SIZE (line 28) | const BLUR_STEP_SIZE = 5;
constant BLACK (line 30) | const BLACK = "rgba(0,0,0,1)";
constant TRANSPARENT (line 31) | const TRANSPARENT = "rgba(0,0,0,0)";
function ProgramLogos (line 33) | function ProgramLogos() {
FILE: apps/web/app/(ee)/partners.dub.co/(auth-login-register)/side-panel.tsx
function SidePanel (line 6) | function SidePanel({
FILE: apps/web/app/(ee)/partners.dub.co/(auth-other)/forgot-password/page.tsx
function ForgotPasswordPage (line 4) | function ForgotPasswordPage() {
FILE: apps/web/app/(ee)/partners.dub.co/(auth-other)/invite/page.tsx
function AcceptPartnerInvitePage (line 12) | function AcceptPartnerInvitePage() {
FILE: apps/web/app/(ee)/partners.dub.co/(auth-other)/layout.tsx
function PartnerAuthLayout (line 5) | function PartnerAuthLayout({
FILE: apps/web/app/(ee)/partners.dub.co/(auth-other)/logo.tsx
function Logo (line 7) | function Logo({ className }: { className?: string }) {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/auth.tsx
constant ERROR_CODES (line 10) | const ERROR_CODES = {
function PartnerProfileAuth (line 22) | function PartnerProfileAuth({ children }: { children: ReactNode }) {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/layout.tsx
function PartnerDashboardLayout (line 6) | function PartnerDashboardLayout({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/messages/[programSlug]/page-client.tsx
function PartnerMessagesProgramPageClient (line 44) | function PartnerMessagesProgramPageClient() {
function ProgramInfoPanel (line 311) | function ProgramInfoPanel({
function ProgramInfoPanelSkeleton (line 477) | function ProgramInfoPanelSkeleton() {
function ViewProgramButton (line 547) | function ViewProgramButton({ programSlug }: { programSlug: string }) {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/messages/[programSlug]/page.tsx
function PartnerMessagesProgramPage (line 3) | function PartnerMessagesProgramPage() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/messages/layout.tsx
function MessagesLayout (line 13) | function MessagesLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/messages/page-client.tsx
function PartnerMessagesPageClient (line 6) | function PartnerMessagesPageClient() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/messages/page.tsx
function PartnerMessages (line 3) | function PartnerMessages() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/payouts/page.tsx
function PartnersPayoutsSettings (line 7) | function PartnersPayoutsSettings() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/payouts/partner-payout-details-sheet.tsx
type PayoutDetailsSheetProps (line 47) | type PayoutDetailsSheetProps = {
function PayoutDetailsSheetContent (line 61) | function PayoutDetailsSheetContent({ payout }: PayoutDetailsSheetProps) {
function PayoutDetailsSheet (line 399) | function PayoutDetailsSheet({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/payouts/partner-payout-settings-button.tsx
function PartnerPayoutSettingsButton (line 10) | function PartnerPayoutSettingsButton() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/payouts/partner-payout-settings-sheet.tsx
type PartnerPayoutSettingsFormData (line 32) | type PartnerPayoutSettingsFormData = z.infer<
function useExternalPayoutEnrollments (line 36) | function useExternalPayoutEnrollments() {
function PartnerPayoutSettingsSheet (line 58) | function PartnerPayoutSettingsSheet() {
function PartnerPayoutSettingsSheetInner (line 87) | function PartnerPayoutSettingsSheetInner() {
function PayoutMethodsSectionSkeleton (line 180) | function PayoutMethodsSectionSkeleton() {
function PayoutMethodsSection (line 198) | function PayoutMethodsSection() {
function InvoiceDetailsSection (line 284) | function InvoiceDetailsSection({
function ConnectedExternalAccounts (line 347) | function ConnectedExternalAccounts() {
function usePartnerPayoutSettingsSheet (line 413) | function usePartnerPayoutSettingsSheet() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/payouts/payout-stats.tsx
function PayoutStatsCard (line 24) | function PayoutStatsCard({
function PayoutStats (line 115) | function PayoutStats() {
function ForceWithdrawalModalDescription (line 270) | function ForceWithdrawalModalDescription({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/payouts/payout-table.tsx
function PayoutTable (line 40) | function PayoutTable() {
function AmountRowItem (line 276) | function AmountRowItem({ payout }: { payout: PartnerPayoutResponse }) {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/payouts/use-payout-filters.tsx
function usePayoutFilters (line 10) | function usePayoutFilters() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/about-you-form.tsx
type AboutYouFormData (line 22) | type AboutYouFormData = {
function AboutYouForm (line 28) | function AboutYouForm({ partner }: { partner?: PartnerProps }) {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/how-you-work-form.tsx
type HowYouWorkFormData (line 19) | type HowYouWorkFormData = {
function HowYouWorkForm (line 24) | function HowYouWorkForm({ partner }: { partner?: PartnerProps }) {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/industry-interests-modal.tsx
type IndustryInterestsModalProps (line 8) | type IndustryInterestsModalProps = {
function IndustryInterestsModal (line 15) | function IndustryInterestsModal({
function IndustryInterestsModalInner (line 27) | function IndustryInterestsModalInner({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/members/page-client.tsx
function ProfileMembersPageClient (line 41) | function ProfileMembersPageClient() {
function RoleCell (line 294) | function RoleCell({
function RowMenuButton (line 352) | function RowMenuButton({
function MenuItem (line 420) | function MenuItem({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/members/page.tsx
function ProfileMembersPage (line 3) | function ProfileMembersPage() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/notifications/page-client.tsx
type PreferenceType (line 17) | type PreferenceType = z.infer<typeof partnerNotificationTypes>;
type Preferences (line 18) | type Preferences = Record<PreferenceType, boolean>;
function PartnerSettingsNotificationsPageClient (line 54) | function PartnerSettingsNotificationsPageClient() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/notifications/page.tsx
function PartnerSettingsNotificationsPage (line 5) | function PartnerSettingsNotificationsPage() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/page-client.tsx
function ProfileSettingsPageClient (line 18) | function ProfileSettingsPageClient() {
function Controls (line 47) | function Controls() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/page.tsx
function ProfileSettingsPage (line 3) | function ProfileSettingsPage() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/postbacks/[id]/page-client.tsx
type PostbackDetailPageClientProps (line 22) | interface PostbackDetailPageClientProps {
function PostbackDetailPageClient (line 26) | function PostbackDetailPageClient({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/postbacks/[id]/page.tsx
function PostbackDetailPage (line 3) | async function PostbackDetailPage(props: {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/postbacks/add-postback-button.tsx
function AddPostbackButton (line 5) | function AddPostbackButton({ onClick }: { onClick: () => void }) {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/postbacks/page-client.tsx
function PostbacksPageClient (line 17) | function PostbacksPageClient() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/postbacks/page.tsx
function PostbacksPage (line 3) | function PostbacksPage() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/profile-details-form.tsx
type BasicInfoFormData (line 36) | type BasicInfoFormData = {
function ProfileDetailsForm (line 45) | function ProfileDetailsForm({ partner }: { partner?: PartnerProps }) {
function BasicInfoForm (line 147) | function BasicInfoForm({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/profile-discovery-guide.tsx
function ProfileDiscoveryGuide (line 15) | function ProfileDiscoveryGuide() {
function ConditionalLink (line 119) | function ConditionalLink({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/settings-row.tsx
function SettingsRow (line 3) | function SettingsRow({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/use-partner-discovery-requirements.ts
function usePartnerDiscoveryRequirements (line 6) | function usePartnerDiscoveryRequirements() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/analytics/page.tsx
function PartnerAnalytics (line 4) | function PartnerAnalytics() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/auth.tsx
function ProgramEnrollmentAuth (line 8) | function ProgramEnrollmentAuth({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/bounties/[bountyId]/bounty-performance-section.tsx
type PerformanceAttribute (line 45) | type PerformanceAttribute = keyof typeof PERFORMANCE_BOUNTY_SCOPE_ATTRIB...
type PerformanceRow (line 47) | interface PerformanceRow {
constant ATTRIBUTE_TO_ANALYTICS_FIELD (line 64) | const ATTRIBUTE_TO_ANALYTICS_FIELD: Partial<
constant ATTRIBUTE_TO_CHART_FIELD (line 72) | const ATTRIBUTE_TO_CHART_FIELD: Partial<
constant ATTRIBUTE_TO_EVENT_PARAMS (line 80) | const ATTRIBUTE_TO_EVENT_PARAMS: Partial<
constant ATTRIBUTE_TO_TABLE_TITLE (line 91) | const ATTRIBUTE_TO_TABLE_TITLE: Record<PerformanceAttribute, string> = {
function BountyPerformanceSection (line 98) | function BountyPerformanceSection({
function BountyPerformanceChart (line 118) | function BountyPerformanceChart({ bounty }: { bounty: PartnerBountyProps...
constant PAGE_SIZE (line 259) | const PAGE_SIZE = 10;
function PerformanceTableShell (line 261) | function PerformanceTableShell({
function BountyPerformanceTable (line 291) | function BountyPerformanceTable({ bounty }: { bounty: PartnerBountyProps...
function BountyPerformanceEventsTable (line 303) | function BountyPerformanceEventsTable({
function BountyPerformanceCommissionsTable (line 544) | function BountyPerformanceCommissionsTable({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/bounties/[bountyId]/bounty-submissions-table.tsx
type PartnerBountySubmission (line 16) | type PartnerBountySubmission = PartnerBountyProps["submissions"][number];
function BountySubmissionsTable (line 18) | function BountySubmissionsTable({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/bounties/[bountyId]/page-client.tsx
function PartnerBountyPageClient (line 24) | function PartnerBountyPageClient() {
function BountyDetailsProgressSkeleton (line 99) | function BountyDetailsProgressSkeleton() {
function PartnerBountyPageHeader (line 115) | function PartnerBountyPageHeader() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/bounties/[bountyId]/page.tsx
function PartnerBountyPage (line 7) | function PartnerBountyPage() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/bounties/bounty-card.tsx
function PartnerBountyCard (line 21) | function PartnerBountyCard({
function BountyRewardsTable (line 100) | function BountyRewardsTable({
function BountyEndDate (line 176) | function BountyEndDate({ bounty }: { bounty: PartnerBountyProps }) {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/bounties/page-client.tsx
function BountiesPageClient (line 22) | function BountiesPageClient() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/bounties/page.tsx
function BountiesPage (line 4) | function BountiesPage() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/customers/(index)/layout.tsx
function PartnerCustomersLayout (line 18) | function PartnerCustomersLayout({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/customers/(index)/page-client.tsx
function ProgramCustomersPageClient (line 34) | function ProgramCustomersPageClient() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/customers/(index)/page.tsx
function ProgramCustomers (line 3) | function ProgramCustomers() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/customers/(index)/referrals/page.tsx
function PartnerCustomersReferralsPage (line 29) | function PartnerCustomersReferralsPage() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/customers/(index)/use-partner-customer-filters.tsx
function usePartnerCustomerFilters (line 7) | function usePartnerCustomerFilters() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/customers/[customerId]/page-client.tsx
function ProgramCustomerPageClient (line 22) | function ProgramCustomerPageClient() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/customers/[customerId]/page.tsx
function ProgramCustomer (line 3) | function ProgramCustomer() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/earnings/earnings-composite-chart.tsx
constant LINE_COLORS (line 29) | const LINE_COLORS = [
constant EVENT_TYPE_LINE_COLORS (line 38) | const EVENT_TYPE_LINE_COLORS = {
constant MAX_LINES (line 44) | const MAX_LINES = LINE_COLORS.length;
function EarningsCompositeChart (line 46) | function EarningsCompositeChart() {
function EarningsTableControls (line 240) | function EarningsTableControls() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/earnings/earnings-table.tsx
type ColumnMeta (line 37) | type ColumnMeta = {
function EarningsTablePartner (line 43) | function EarningsTablePartner({ limit }: { limit?: number }) {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/earnings/page.tsx
function ProgramEarning (line 6) | function ProgramEarning() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/events/page.tsx
function ProgramEvents (line 5) | function ProgramEvents() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/hide-program-details-button.tsx
function HideProgramDetailsButton (line 8) | function HideProgramDetailsButton() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/layout.tsx
function Layout (line 3) | function Layout({ children }: { children: React.ReactNode }) {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/links/page-client.tsx
function usePartnerLinksContext (line 34) | function usePartnerLinksContext() {
function ProgramLinksPageClient (line 44) | function ProgramLinksPageClient() {
function LinkCardSkeleton (line 199) | function LinkCardSkeleton() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/links/page.tsx
function ProgramLinks (line 6) | function ProgramLinks() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/links/partner-link-card.tsx
constant CHARTS (line 45) | const CHARTS = [
function PartnerLinkCard (line 67) | function PartnerLinkCard({ link }: { link: PartnerProfileLinkProps }) {
function LinkEventsChart (line 398) | function LinkEventsChart({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/links/partner-link-controls.tsx
function PartnerLinkControls (line 10) | function PartnerLinkControls({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/page-client.tsx
function ProgramPageClient (line 70) | function ProgramPageClient() {
function EarningsChart (line 287) | function EarningsChart() {
function StatCard (line 425) | function StatCard({
function StatCardSimple (line 505) | function StatCardSimple({
function BrandedChart (line 554) | function BrandedChart({
function ViewMoreButton (line 642) | function ViewMoreButton({ href }: { href: string }) {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/page.tsx
function ProgramPage (line 5) | function ProgramPage() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/payouts-card.tsx
function PayoutsCard (line 14) | function PayoutsCard({ programId }: { programId?: string }) {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/resources/page-client.tsx
function ResourcesPageClient (line 19) | function ResourcesPageClient() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/resources/page.tsx
function ResourcesPage (line 4) | function ResourcesPage() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/share-earnings-modal.tsx
constant BACKGROUND_OPTIONS (line 10) | const BACKGROUND_OPTIONS = [
type BackgroundType (line 21) | type BackgroundType = (typeof BACKGROUND_OPTIONS)[number]["id"];
type ShareEarningsModalProps (line 23) | type ShareEarningsModalProps = {
function ShareEarningsModal (line 33) | function ShareEarningsModal({
function ShareEarningsModalInner (line 60) | function ShareEarningsModalInner({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/unapproved-program-page.tsx
function UnapprovedProgramPage (line 42) | function UnapprovedProgramPage({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/apply/page.tsx
function ProgramDetailsPage (line 14) | async function ProgramDetailsPage(props: {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/apply/program-sidebar.tsx
function ProgramSidebar (line 22) | function ProgramSidebar({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/invite/accept-program-invite-button.tsx
function AcceptProgramInviteButton (line 11) | function AcceptProgramInviteButton({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/invite/page.tsx
function ProgramInvitePage (line 18) | async function ProgramInvitePage(props: {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/invitations/page-client.tsx
function ProgramInvitationsPageClient (line 10) | function ProgramInvitationsPageClient() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/invitations/page.tsx
function ProgramInvitationsPage (line 4) | function ProgramInvitationsPage() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/marketplace/[programSlug]/header-controls.tsx
function MarketplaceProgramHeaderControls (line 19) | function MarketplaceProgramHeaderControls({
function ApplyButton (line 46) | function ApplyButton({ program }: { program: NetworkProgramProps }) {
function AcceptInviteButton (line 130) | function AcceptInviteButton({ program }: { program: NetworkProgramProps ...
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/marketplace/[programSlug]/loading.tsx
function MarketplaceProgramPageLoading (line 4) | function MarketplaceProgramPageLoading() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/marketplace/[programSlug]/page.tsx
function generateStaticParams (line 21) | async function generateStaticParams() {
function MarketplaceProgramPage (line 38) | async function MarketplaceProgramPage(props: {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/marketplace/featured-program-card.tsx
function FeaturedProgramCard (line 9) | function FeaturedProgramCard({
function FeaturedProgramCardSkeleton (line 180) | function FeaturedProgramCardSkeleton() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/marketplace/featured-programs.tsx
function FeaturedPrograms (line 18) | function FeaturedPrograms() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/marketplace/layout.tsx
function MarketplaceLayout (line 5) | function MarketplaceLayout({ children }: PropsWithChildren) {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/marketplace/marketplace-empty-state.tsx
function MarketplaceEmptyState (line 4) | function MarketplaceEmptyState({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/marketplace/page-client.tsx
function ProgramMarketplacePageClient (line 22) | function ProgramMarketplacePageClient() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/marketplace/page.tsx
function PartnersDashboard (line 5) | function PartnersDashboard() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/marketplace/program-card.tsx
function ProgramCard (line 9) | function ProgramCard({ program }: { program: NetworkProgramProps }) {
function ProgramCardSkeleton (line 121) | function ProgramCardSkeleton() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/marketplace/program-sort.tsx
function ProgramSort (line 42) | function ProgramSort() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/marketplace/program-status-badge.tsx
function ProgramStatusBadge (line 30) | function ProgramStatusBadge({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/marketplace/use-program-network-filters.tsx
constant REWARD_TYPES (line 10) | const REWARD_TYPES = {
function useProgramNetworkFilters (line 29) | function useProgramNetworkFilters() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/page-client.tsx
function PartnersDashboardPageClient (line 11) | function PartnersDashboardPageClient() {
function EmptyStateChart (line 61) | function EmptyStateChart() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/page.tsx
function PartnersDashboard (line 4) | function PartnersDashboard() {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/rewind/2025/conclusion.tsx
function Conclusion (line 7) | function Conclusion({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/rewind/2025/intro.tsx
function Intro (line 4) | function Intro({ onStart }: { onStart: () => void }) {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/rewind/2025/page-client.tsx
function PartnerRewind2025PageClient (line 11) | function PartnerRewind2025PageClient({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/rewind/2025/page.tsx
function PartnerRewind2025Page (line 15) | async function PartnerRewind2025Page() {
function Gradient (line 68) | function Gradient({ className }: { className?: string }) {
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/rewind/2025/rewind.tsx
constant STEP_DELAY_MS (line 19) | const STEP_DELAY_MS = 8_000;
function Rewind (line 24) | function Rewind({
function StepSlide (line 165) | function StepSlide({
FILE: apps/web/app/(ee)/partners.dub.co/(dashboard)/rewind/2025/share-rewind-modal.tsx
type ShareRewindModalInnerProps (line 7) | type ShareRewindModalInnerProps = {
type ShareRewindModalProps (line 11) | type ShareRewindModalProps = {
function ShareRewindModal (line 16) | function ShareRewindModal(props: ShareRewindModalProps) {
function ShareRewindModalInner (line 24) | function ShareRewindModalInner({ step }: ShareRewindModalInnerProps) {
function useShareRewindModal (line 114) | function useShareRewindModal(props: ShareRewindModalInnerProps) {
FILE: apps/web/app/(ee)/partners.dub.co/(onboarding)/layout.tsx
function PartnerOnboardingLayout (line 7) | function PartnerOnboardingLayout({
FILE: apps/web/app/(ee)/partners.dub.co/(onboarding)/onboarding/onboarding-form.tsx
type FormData (line 29) | type FormData = z.infer<typeof onboardPartnerSchema>;
function OnboardingForm (line 31) | function OnboardingForm({
FILE: apps/web/app/(ee)/partners.dub.co/(onboarding)/onboarding/page.tsx
function PartnerOnboarding (line 6) | function PartnerOnboarding() {
function OnboardingFormRSC (line 21) | async function OnboardingFormRSC() {
FILE: apps/web/app/(ee)/partners.dub.co/(onboarding)/onboarding/payouts/page.tsx
function OnboardingVerificationPage (line 9) | function OnboardingVerificationPage() {
function PayoutSkeleton (line 27) | function PayoutSkeleton() {
function PayoutRSC (line 54) | async function PayoutRSC() {
FILE: apps/web/app/(ee)/partners.dub.co/(onboarding)/onboarding/payouts/payout-provider.tsx
function PayoutProvider (line 8) | function PayoutProvider({
FILE: apps/web/app/(ee)/partners.dub.co/(onboarding)/onboarding/platforms/page-client.tsx
function OnboardingPlatformsPageClient (line 9) | function OnboardingPlatformsPageClient({
FILE: apps/web/app/(ee)/partners.dub.co/(onboarding)/onboarding/platforms/page.tsx
function OnboardingPlatformsPage (line 12) | function OnboardingPlatformsPage() {
function OnboardingPlatformsFormRSC (line 33) | async function OnboardingPlatformsFormRSC() {
FILE: apps/web/app/(ee)/partners.dub.co/(redirects)/apply/[programSlug]/[[...slug]]/page.tsx
function OldApplyPage (line 3) | async function OldApplyPage(props: {
FILE: apps/web/app/(ee)/partners.dub.co/invoices/[payoutId]/route.tsx
constant GET (line 36) | const GET = withPartnerProfile(async ({ partner, params }) => {
FILE: apps/web/app/(ee)/partners.dub.co/layout.tsx
function PartnersLayout (line 6) | function PartnersLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/[domain]/browser-graphic.tsx
function BrowserGraphic (line 5) | function BrowserGraphic({ domain }: { domain: string }) {
FILE: apps/web/app/[domain]/layout.tsx
function CustomDomainLayout (line 3) | function CustomDomainLayout({
FILE: apps/web/app/[domain]/not-found/page.tsx
constant UTM_PARAMS (line 19) | const UTM_PARAMS = {
function NotFoundLinkPage (line 24) | async function NotFoundLinkPage(props: {
FILE: apps/web/app/[domain]/page.tsx
function generateMetadata (line 6) | async function generateMetadata(props: {
function CustomDomainPage (line 23) | function CustomDomainPage() {
FILE: apps/web/app/[domain]/placeholder.tsx
constant UTM_PARAMS (line 13) | const UTM_PARAMS = {
function PlaceholderContent (line 18) | function PlaceholderContent() {
FILE: apps/web/app/[domain]/stats/[key]/page.tsx
function OldStatsPage (line 5) | async function OldStatsPage(props: {
FILE: apps/web/app/api/activity-logs/route.ts
constant GET (line 13) | const GET = withWorkspace(async ({ workspace, searchParams }) => {
FILE: apps/web/app/api/ai/completion/route.ts
constant POST (line 20) | const POST = withWorkspace(async ({ req, workspace }) => {
FILE: apps/web/app/api/ai/support-chat/route.ts
constant POST (line 15) | const POST = withSession(async ({ req, session }) => {
FILE: apps/web/app/api/ai/support-chat/upload/route.ts
constant MAX_UPLOAD_SIZE_BYTES (line 6) | const MAX_UPLOAD_SIZE_BYTES = 10 * 1024 * 1024;
constant MAX_FILE_NAME_LENGTH (line 7) | const MAX_FILE_NAME_LENGTH = 255;
constant ACCEPTED_EXTENSIONS (line 9) | const ACCEPTED_EXTENSIONS = new Set([
constant POST (line 24) | const POST = withSession(async ({ req, session }) => {
FILE: apps/web/app/api/ai/sync-embeddings/fetch-plausible-pageviews.ts
function fetchPlausiblePageviews (line 5) | async function fetchPlausiblePageviews(): Promise<Map<string, number>> {
FILE: apps/web/app/api/analytics/export/route.ts
constant GET (line 19) | const GET = withWorkspace(
FILE: apps/web/app/api/analytics/route.ts
constant GET (line 20) | const GET = withWorkspace(
FILE: apps/web/app/api/auth/reset-password/route.ts
function POST (line 12) | async function POST(req: NextRequest) {
FILE: apps/web/app/api/callback/bitly/route.ts
function GET (line 10) | async function GET(req: Request) {
FILE: apps/web/app/api/callback/plain/partner/route.ts
function POST (line 21) | async function POST(req: NextRequest) {
FILE: apps/web/app/api/callback/plain/workspace/route.ts
function POST (line 18) | async function POST(req: NextRequest) {
FILE: apps/web/app/api/dashboards/[id]/route.ts
constant PATCH (line 33) | const PATCH = withWorkspace(
constant DELETE (line 56) | const DELETE = withWorkspace(
FILE: apps/web/app/api/dashboards/route.ts
constant GET (line 16) | const GET = withWorkspace(
constant POST (line 30) | const POST = withWorkspace(
FILE: apps/web/app/api/docs/guides/[guide]/route.ts
constant GET (line 5) | const GET = withSession(async ({ params }) => {
FILE: apps/web/app/api/domains/[domain]/primary/route.ts
constant POST (line 8) | const POST = withWorkspace(
FILE: apps/web/app/api/domains/[domain]/route.ts
constant GET (line 28) | const GET = withWorkspace(
constant PATCH (line 44) | const PATCH = withWorkspace(
constant DELETE (line 248) | const DELETE = withWorkspace(
FILE: apps/web/app/api/domains/[domain]/transfer/route.ts
constant POST (line 13) | const POST = withWorkspace(
FILE: apps/web/app/api/domains/[domain]/validate/route.ts
constant GET (line 8) | const GET = withSession(async ({ params }) => {
function hasSiteConfigured (line 34) | async function hasSiteConfigured(domain: string): Promise<boolean> {
FILE: apps/web/app/api/domains/[domain]/verify/route.ts
constant GET (line 13) | const GET = withWorkspace(
FILE: apps/web/app/api/domains/client/register/route.ts
constant POST (line 16) | const POST = withWorkspace(
FILE: apps/web/app/api/domains/client/saved/route.ts
constant POST (line 16) | const POST = withWorkspace(
FILE: apps/web/app/api/domains/count/route.ts
constant GET (line 7) | const GET = withWorkspace(
FILE: apps/web/app/api/domains/default/route.ts
constant GET (line 10) | const GET = withWorkspace(
constant PATCH (line 57) | const PATCH = withWorkspace(
FILE: apps/web/app/api/domains/route.ts
constant GET (line 22) | const GET = withWorkspace(
constant POST (line 96) | const POST = withWorkspace(
FILE: apps/web/app/api/domains/search-availability/route.ts
constant GET (line 18) | const GET = withWorkspace(
FILE: apps/web/app/api/dub/webhook/lead-created.ts
constant REFERRAL_SIGNUPS_MAX (line 6) | const REFERRAL_SIGNUPS_MAX = 32;
function leadCreated (line 7) | async function leadCreated(data: LeadCreatedEvent["data"]) {
FILE: apps/web/app/api/dub/webhook/sale-created.ts
function saleCreated (line 3) | async function saleCreated(data: SaleCreatedEvent["data"]) {
FILE: apps/web/app/api/folders/[folderId]/dashboard/route.ts
constant GET (line 8) | const GET = withWorkspace(
FILE: apps/web/app/api/folders/[folderId]/route.ts
constant GET (line 13) | const GET = withWorkspace(
constant PATCH (line 41) | const PATCH = withWorkspace(
constant DELETE (line 111) | const DELETE = withWorkspace(
FILE: apps/web/app/api/folders/[folderId]/users/route.ts
constant GET (line 10) | const GET = withWorkspace(
FILE: apps/web/app/api/folders/access-requests/route.ts
constant GET (line 6) | const GET = withWorkspace(
FILE: apps/web/app/api/folders/count/route.ts
constant GET (line 8) | const GET = withWorkspace(
FILE: apps/web/app/api/folders/permissions/route.ts
constant GET (line 11) | const GET = withWorkspace(
FILE: apps/web/app/api/folders/route.ts
constant GET (line 18) | const GET = withWorkspace(
constant POST (line 41) | const POST = withWorkspace(
FILE: apps/web/app/api/integrations/route.ts
constant GET (line 6) | const GET = withWorkspace(
FILE: apps/web/app/api/integrations/uninstall/route.ts
constant DELETE (line 12) | const DELETE = withWorkspace(
FILE: apps/web/app/api/links/[linkId]/dashboard/route.ts
constant GET (line 8) | const GET = withWorkspace(
FILE: apps/web/app/api/links/[linkId]/route.ts
constant GET (line 24) | const GET = withWorkspace(
constant PATCH (line 73) | const PATCH = withWorkspace(
constant PUT (line 205) | const PUT = PATCH;
constant DELETE (line 208) | const DELETE = withWorkspace(
FILE: apps/web/app/api/links/[linkId]/transfer/route.ts
constant POST (line 22) | const POST = withWorkspace(
FILE: apps/web/app/api/links/bulk/route.ts
constant POST (line 34) | const POST = withWorkspace(
constant PATCH (line 264) | const PATCH = withWorkspace(
constant DELETE (line 467) | const DELETE = withWorkspace(
FILE: apps/web/app/api/links/count/route.ts
constant GET (line 8) | const GET = withWorkspace(
FILE: apps/web/app/api/links/export/route.ts
constant MAX_LINKS_TO_EXPORT (line 16) | const MAX_LINKS_TO_EXPORT = 1000;
constant GET (line 19) | const GET = withWorkspace(
FILE: apps/web/app/api/links/iframeable/route.ts
function GET (line 12) | async function GET(req: NextRequest) {
FILE: apps/web/app/api/links/info/route.ts
constant GET (line 11) | const GET = withWorkspace(
FILE: apps/web/app/api/links/metatags/route.ts
function GET (line 9) | async function GET(req: NextRequest) {
FILE: apps/web/app/api/links/route.ts
constant GET (line 20) | const GET = withWorkspace(
constant POST (line 48) | const POST = withWorkspace(
FILE: apps/web/app/api/links/sync/route.ts
constant POST (line 10) | const POST = withWorkspace(
FILE: apps/web/app/api/links/upsert/route.ts
constant PUT (line 23) | const PUT = withWorkspace(
FILE: apps/web/app/api/me/route.ts
constant GET (line 6) | const GET = withSession(async ({ session }) => {
FILE: apps/web/app/api/misc/check-favicon/route.ts
constant GET (line 5) | const GET = withSession(async ({ searchParams }) => {
FILE: apps/web/app/api/misc/check-workspace-slug/route.ts
constant GET (line 7) | const GET = withSession(async ({ searchParams }) => {
FILE: apps/web/app/api/oauth/apps/[appId]/route.ts
constant GET (line 13) | const GET = withWorkspace(
constant PATCH (line 53) | const PATCH = withWorkspace(
constant DELETE (line 173) | const DELETE = withWorkspace(
FILE: apps/web/app/api/oauth/apps/route.ts
constant GET (line 15) | const GET = withWorkspace(
constant POST (line 45) | const POST = withWorkspace(
FILE: apps/web/app/api/oauth/authorize/route.ts
constant POST (line 13) | const POST = withWorkspace(async ({ session, req, workspace }) => {
FILE: apps/web/app/api/oauth/token/route.ts
function POST (line 11) | async function POST(req: NextRequest) {
FILE: apps/web/app/api/oauth/userinfo/route.ts
constant CORS_HEADERS (line 9) | const CORS_HEADERS = new Headers({
function GET (line 16) | async function GET(req: NextRequest) {
FILE: apps/web/app/api/og/analytics/route.tsx
function GET (line 15) | async function GET(req: NextRequest) {
FILE: apps/web/app/api/og/avatar/[[...seed]]/route.tsx
function GET (line 7) | async function GET(
FILE: apps/web/app/api/og/load-google-font.ts
function loadGoogleFont (line 1) | async function loadGoogleFont(font: string) {
FILE: apps/web/app/api/og/partner-earnings/route.tsx
constant WIDTH (line 9) | const WIDTH = 1368;
constant HEIGHT (line 10) | const HEIGHT = 994;
constant BACKGROUND_IMAGES (line 12) | const BACKGROUND_IMAGES = {
constant GET (line 17) | const GET = withPartnerProfile(async ({ partner, searchParams }) => {
function Chart (line 160) | function Chart({
FILE: apps/web/app/api/og/partner-rewind/route.tsx
constant WIDTH (line 14) | const WIDTH = 1084;
constant HEIGHT (line 15) | const HEIGHT = 994;
constant GET (line 17) | const GET = withPartnerProfile(async ({ partner, searchParams }) => {
FILE: apps/web/app/api/og/program/route.tsx
constant DARK_CELLS (line 11) | const DARK_CELLS = [
function GET (line 18) | async function GET(req: NextRequest) {
function InvoiceDollar (line 188) | function InvoiceDollar({
FILE: apps/web/app/api/providers/route.ts
function GET (line 9) | async function GET(req: NextRequest) {
FILE: apps/web/app/api/qr/route.tsx
constant CORS_HEADERS (line 13) | const CORS_HEADERS = new Headers({
function GET (line 18) | async function GET(req: NextRequest) {
function OPTIONS (line 106) | function OPTIONS() {
FILE: apps/web/app/api/resend/webhook/email-bounced.ts
function emailBounced (line 3) | async function emailBounced({
FILE: apps/web/app/api/resend/webhook/email-delivered.ts
function emailDelivered (line 3) | async function emailDelivered({
FILE: apps/web/app/api/resend/webhook/email-opened.ts
function emailOpened (line 3) | async function emailOpened({
FILE: apps/web/app/api/resumes/upload-url/route.ts
constant CORS_HEADERS (line 7) | const CORS_HEADERS = new Headers({
FILE: apps/web/app/api/route.ts
function GET (line 6) | function GET() {
FILE: apps/web/app/api/supported-countries/route.ts
function GET (line 6) | async function GET() {
FILE: apps/web/app/api/tags/[id]/route.ts
constant PATCH (line 12) | const PATCH = withWorkspace(
constant PUT (line 59) | const PUT = PATCH;
constant DELETE (line 62) | const DELETE = withWorkspace(
FILE: apps/web/app/api/tags/count/route.ts
constant GET (line 7) | const GET = withWorkspace(
FILE: apps/web/app/api/tags/route.ts
constant GET (line 15) | const GET = withWorkspace(
constant POST (line 68) | const POST = withWorkspace(
FILE: apps/web/app/api/tokens/[id]/route.ts
constant GET (line 12) | const GET = withWorkspace(
constant PATCH (line 53) | const PATCH = withWorkspace(
constant DELETE (line 108) | const DELETE = withWorkspace(
FILE: apps/web/app/api/tokens/embed/referrals/route.ts
constant POST (line 16) | const POST = withWorkspace(
FILE: apps/web/app/api/tokens/route.ts
constant MAX_WORKSPACE_TOKENS (line 18) | const MAX_WORKSPACE_TOKENS = 100;
constant GET (line 25) | const GET = withWorkspace(
constant POST (line 66) | const POST = withWorkspace(
FILE: apps/web/app/api/unsplash/download/route.ts
function POST (line 4) | async function POST(req: Request) {
FILE: apps/web/app/api/unsplash/search/route.ts
function GET (line 8) | async function GET(req: Request) {
FILE: apps/web/app/api/user/notification-preferences/route.ts
function GET (line 18) | async function GET(request: NextRequest) {
function POST (line 78) | async function POST(request: NextRequest) {
FILE: apps/web/app/api/user/password/route.ts
constant PATCH (line 13) | const PATCH = withSession(async ({ req, session }) => {
FILE: apps/web/app/api/user/referrals-token/route.ts
constant GET (line 11) | const GET = withSession(async ({ session }) => {
FILE: apps/web/app/api/user/route.ts
constant GET (line 28) | const GET = withSession(async ({ session }) => {
constant PATCH (line 66) | const PATCH = withSession(async ({ req, session }) => {
constant PUT (line 151) | const PUT = PATCH;
constant DELETE (line 154) | const DELETE = withSession(async ({ session }) => {
FILE: apps/web/app/api/user/set-password/route.ts
constant POST (line 11) | const POST = withSession(async ({ session }) => {
FILE: apps/web/app/api/user/tokens/route.ts
constant GET (line 6) | const GET = withSession(async ({ session }) => {
constant DELETE (line 31) | const DELETE = withSession(async ({ searchParams, session }) => {
FILE: apps/web/app/api/utm/[id]/route.ts
constant PATCH (line 16) | const PATCH = withWorkspace(
constant DELETE (line 130) | const DELETE = withWorkspace(
FILE: apps/web/app/api/utm/route.ts
constant GET (line 9) | const GET = withWorkspace(
constant POST (line 32) | const POST = withWorkspace(
FILE: apps/web/app/api/webhooks/[webhookId]/events/route.ts
constant GET (line 7) | const GET = withWorkspace(
FILE: apps/web/app/api/webhooks/[webhookId]/route.ts
constant GET (line 16) | const GET = withWorkspace(
constant PATCH (line 53) | const PATCH = withWorkspace(
constant DELETE (line 210) | const DELETE = withWorkspace(
FILE: apps/web/app/api/webhooks/route.ts
constant GET (line 25) | const GET = withWorkspace(
constant POST (line 47) | const POST = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/billing/cancel/route.ts
constant POST (line 8) | const POST = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/billing/invoices/[invoiceId]/route.ts
constant GET (line 6) | const GET = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/billing/invoices/route.ts
constant GET (line 17) | const GET = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/billing/manage/route.ts
constant POST (line 8) | const POST = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/billing/payment-methods/route.ts
constant GET (line 20) | const GET = withWorkspace(
constant POST (line 53) | const POST = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/billing/upgrade/route.ts
constant POST (line 21) | const POST = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/billing/usage/route.ts
constant GET (line 11) | const GET = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/import/[importId]/download/route.ts
constant GET (line 6) | const GET = withWorkspace(async ({ workspace, params }) => {
FILE: apps/web/app/api/workspaces/[idOrSlug]/import/bitly/route.ts
constant GET (line 14) | const GET = withWorkspace(async ({ workspace }) => {
constant POST (line 61) | const POST = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/import/csv/route.ts
constant POST (line 13) | const POST = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/import/rebrandly/route.ts
constant GET (line 14) | const GET = withWorkspace(async ({ workspace }) => {
constant PUT (line 80) | const PUT = withWorkspace(
constant POST (line 95) | const POST = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/import/short/route.ts
constant GET (line 14) | const GET = withWorkspace(async ({ workspace }) => {
constant PUT (line 67) | const PUT = withWorkspace(
constant POST (line 79) | const POST = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/invites/accept/route.ts
constant POST (line 11) | const POST = withSession(async ({ session, params }) => {
FILE: apps/web/app/api/workspaces/[idOrSlug]/invites/decline/route.ts
constant POST (line 7) | const POST = withSession(async ({ session, params }) => {
FILE: apps/web/app/api/workspaces/[idOrSlug]/invites/reset/route.ts
constant POST (line 6) | const POST = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/invites/route.ts
constant GET (line 19) | const GET = withWorkspace(
constant POST (line 49) | const POST = withWorkspace(
constant PATCH (line 180) | const PATCH = withWorkspace(
constant DELETE (line 225) | const DELETE = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/notification-preferences/route.ts
constant GET (line 6) | const GET = withWorkspace(async ({ workspace, session }) => {
FILE: apps/web/app/api/workspaces/[idOrSlug]/route.ts
constant GET (line 42) | const GET = withWorkspace(
constant PATCH (line 80) | const PATCH = withWorkspace(
constant PUT (line 241) | const PUT = PATCH;
constant DELETE (line 244) | const DELETE = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/saml/route.ts
constant GET (line 30) | const GET = withWorkspace(
constant POST (line 56) | const POST = withWorkspace(
constant DELETE (line 100) | const DELETE = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/scim/route.ts
constant GET (line 17) | const GET = withWorkspace(
constant POST (line 43) | const POST = withWorkspace(
constant DELETE (line 70) | const DELETE = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/upload-url/route.ts
constant POST (line 12) | const POST = withWorkspace(
FILE: apps/web/app/api/workspaces/[idOrSlug]/users/route.ts
constant GET (line 16) | const GET = withWorkspace(
constant PATCH (line 60) | const PATCH = withWorkspace(
constant DELETE (line 95) | const DELETE = withWorkspace(
FILE: apps/web/app/api/workspaces/route.ts
constant GET (line 19) | const GET = withSession(async ({ session }) => {
constant POST (line 61) | const POST = withSession(async ({ req, session }) => {
FILE: apps/web/app/app.dub.co/(auth)/auth/confirm-email-change/[token]/page-client.tsx
function ConfirmEmailChangePageClient (line 9) | async function ConfirmEmailChangePageClient({
FILE: apps/web/app/app.dub.co/(auth)/auth/confirm-email-change/[token]/page.tsx
type PageProps (line 14) | interface PageProps {
function ConfirmEmailChangePage (line 19) | async function ConfirmEmailChangePage(props: PageProps) {
FILE: apps/web/app/app.dub.co/(auth)/auth/reset-password/[token]/page.tsx
type Props (line 7) | interface Props {
function ResetPasswordPage (line 13) | async function ResetPasswordPage(props: Props) {
FILE: apps/web/app/app.dub.co/(auth)/auth/saml/form.tsx
function SAMLForm (line 8) | function SAMLForm() {
FILE: apps/web/app/app.dub.co/(auth)/auth/saml/page.tsx
function SAMLPage (line 7) | function SAMLPage() {
FILE: apps/web/app/app.dub.co/(auth)/customer-logos.tsx
constant CUSTOMER_LOGOS (line 5) | const CUSTOMER_LOGOS: { name: string; src: string; className?: string }[...
function CustomerLogos (line 30) | function CustomerLogos() {
FILE: apps/web/app/app.dub.co/(auth)/forgot-password/page.tsx
function ForgotPasswordPage (line 9) | function ForgotPasswordPage() {
FILE: apps/web/app/app.dub.co/(auth)/invites/[code]/page.tsx
function InvitesPage (line 11) | async function InvitesPage(props: {
function VerifyInvite (line 34) | async function VerifyInvite({ code }: { code: string }) {
FILE: apps/web/app/app.dub.co/(auth)/layout.tsx
function AuthLayout (line 7) | function AuthLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/app.dub.co/(auth)/login/page.tsx
function LoginPage (line 12) | function LoginPage() {
FILE: apps/web/app/app.dub.co/(auth)/oauth/authorize/loading.tsx
function AuthorizeLoading (line 4) | function AuthorizeLoading() {
FILE: apps/web/app/app.dub.co/(auth)/oauth/authorize/page.tsx
function Authorize (line 21) | async function Authorize(props: {
FILE: apps/web/app/app.dub.co/(auth)/oauth/authorize/scopes-requested.tsx
type ScopesProps (line 7) | interface ScopesProps {
FILE: apps/web/app/app.dub.co/(auth)/register/page-client.tsx
function RegisterPageClient (line 13) | function RegisterPageClient() {
function SignUp (line 21) | function SignUp() {
function Verify (line 53) | function Verify() {
FILE: apps/web/app/app.dub.co/(auth)/register/page.tsx
function RegisterPage (line 10) | function RegisterPage() {
FILE: apps/web/app/app.dub.co/(auth)/side-panel.tsx
function SidePanel (line 5) | function SidePanel() {
FILE: apps/web/app/app.dub.co/(auth)/unsubscribe/[token]/page.tsx
function UnsubscribePage (line 13) | async function UnsubscribePage(props: {
FILE: apps/web/app/app.dub.co/(auth)/unsubscribe/[token]/unsubscribe-form.tsx
type PreferenceState (line 15) | type PreferenceState = Record<NotificationPreferenceType, boolean>;
constant NOTIFICATION_ICONS (line 17) | const NOTIFICATION_ICONS: Record<
function UnsubscribeForm (line 26) | function UnsubscribeForm({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/customers/[customerId]/earnings/page-client.tsx
function CustomerEarningsPageClient (line 16) | function CustomerEarningsPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/customers/[customerId]/earnings/page.tsx
function CustomerEarningsPage (line 3) | function CustomerEarningsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/customers/[customerId]/layout.tsx
function CustomerLayout (line 27) | function CustomerLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/customers/[customerId]/sales/page-client.tsx
function CustomerSalesPageClient (line 13) | function CustomerSalesPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/customers/[customerId]/sales/page.tsx
function CustomerSalesPage (line 3) | function CustomerSalesPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/customers/page-client.tsx
function CustomersPageClient (line 3) | function CustomersPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/customers/page.tsx
function CustomersPage (line 6) | function CustomersPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/events/page.tsx
function WorkspaceAnalyticsEvents (line 8) | function WorkspaceAnalyticsEvents() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/analytics/analytics-chart.tsx
function AnalyticsChart (line 13) | function AnalyticsChart() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/analytics/analytics-partners-table.tsx
function AnalyticsPartnersTable (line 27) | function AnalyticsPartnersTable() {
function PartnerTableSkeleton (line 231) | function PartnerTableSkeleton() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/analytics/analytics-timeseries-chart.tsx
function AnalyticsTimeseriesChart (line 14) | function AnalyticsTimeseriesChart({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/analytics/page-client.tsx
function ProgramAnalyticsPageClient (line 30) | function ProgramAnalyticsPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/analytics/page.tsx
function ProgramAnalytics (line 9) | function ProgramAnalytics() {
function ProgramAnalyticsPageWrapper (line 26) | function ProgramAnalyticsPageWrapper() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/analytics/partner-analytics-filter-cell.tsx
type PartnerAnalyticsFilterCellProps (line 9) | interface PartnerAnalyticsFilterCellProps {
function PartnerAnalyticsFilterCell (line 21) | function PartnerAnalyticsFilterCell({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/auth.tsx
function ProgramAuth (line 12) | function ProgramAuth({ children }: { children: ReactNode }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/[bountyId]/bounty-header.tsx
function BountyHeaderTitle (line 9) | function BountyHeaderTitle() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/[bountyId]/bounty-info.tsx
function BountyInfo (line 20) | function BountyInfo() {
function BountyInfoSkeleton (line 184) | function BountyInfoSkeleton() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/[bountyId]/bounty-submission-details-sheet.tsx
type BountySubmissionDetailsSheetProps (line 54) | type BountySubmissionDetailsSheetProps = {
function BountySubmissionDetailsSheetContent (line 61) | function BountySubmissionDetailsSheetContent({
function BountySubmissionDetailsSheet (line 614) | function BountySubmissionDetailsSheet({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/[bountyId]/bounty-submission-row-menu.tsx
function BountySubmissionRowMenu (line 15) | function BountySubmissionRowMenu({
function MenuItem (line 110) | function MenuItem({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/[bountyId]/bounty-submissions-table.tsx
function BountySubmissionsTable (line 51) | function BountySubmissionsTable() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/[bountyId]/page.tsx
function Page (line 7) | function Page() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/[bountyId]/use-bounty-submission-filters.tsx
function useBountySubmissionFilters (line 17) | function useBountySubmissionFilters({
function usePartnerFilterOptions (line 168) | function usePartnerFilterOptions(search: string) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/add-edit-bounty/add-edit-bounty-sheet.tsx
type BountySheetProps (line 50) | interface BountySheetProps {
constant BOUNTY_TYPES (line 55) | const BOUNTY_TYPES: CardSelectorOption[] = [
function BountySheetContent (line 68) | function BountySheetContent({ setIsOpen, bounty }: BountySheetProps) {
function SubmissionWindowBadge (line 567) | function SubmissionWindowBadge({
function BountySheet (line 603) | function BountySheet({
function useBountySheet (line 625) | function useBountySheet(
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/add-edit-bounty/bounty-amount-input.tsx
type BountyAmountInputProps (line 10) | interface BountyAmountInputProps {
function BountyAmountInput (line 15) | function BountyAmountInput({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/add-edit-bounty/bounty-criteria-manual-submission.tsx
constant REWARD_TYPES (line 22) | const REWARD_TYPES = [
type RewardType (line 33) | type RewardType = (typeof REWARD_TYPES)[number]["value"];
constant REWARD_TYPE_COPY (line 35) | const REWARD_TYPE_COPY: Record<
constant REWARD_VALID_BUTTON_CLASS (line 43) | const REWARD_VALID_BUTTON_CLASS =
constant REWARD_INVALID_BUTTON_CLASS (line 45) | const REWARD_INVALID_BUTTON_CLASS =
function BountyCriteriaManualSubmission (line 48) | function BountyCriteriaManualSubmission() {
function RewardTypeBadge (line 352) | function RewardTypeBadge({
function RewardValueBadge (line 376) | function RewardValueBadge({ rewardType }: { rewardType: RewardType }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/add-edit-bounty/bounty-criteria-social-metrics.tsx
type SocialMetricsVariableBonusProps (line 34) | interface SocialMetricsVariableBonusProps {
function BountyCriteriaSocialMetrics (line 41) | function BountyCriteriaSocialMetrics() {
function SocialMetricsIncrementalBonus (line 293) | function SocialMetricsIncrementalBonus({
function VariableBonusAmountInput (line 472) | function VariableBonusAmountInput({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/add-edit-bounty/bounty-criteria.tsx
constant BOUNTY_SUBMISSION_TYPES (line 22) | const BOUNTY_SUBMISSION_TYPES = [
type BountySubmissionType (line 33) | type BountySubmissionType = (typeof BOUNTY_SUBMISSION_TYPES)[number]["va...
function BountyCriteria (line 35) | function BountyCriteria() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/add-edit-bounty/bounty-form-context.tsx
type CreateBountyInputExtended (line 6) | type CreateBountyInputExtended = CreateBountyInput & {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/add-edit-bounty/bounty-logic.tsx
function BountyLogic (line 16) | function BountyLogic({ className }: { className?: string }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/add-edit-bounty/confirm-create-bounty-modal.tsx
type ConfirmCreateBountyModalProps (line 25) | type ConfirmCreateBountyModalProps = {
function ConfirmCreateBountyModal (line 40) | function ConfirmCreateBountyModal({
function useConfirmCreateBountyModal (line 242) | function useConfirmCreateBountyModal(
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/add-edit-bounty/use-add-edit-bounty-form.ts
constant ACCORDION_ITEMS (line 23) | const ACCORDION_ITEMS = [
function useAddEditBountyForm (line 33) | function useAddEditBountyForm({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/bounty-action-button.tsx
type BountyActionButtonProps (line 19) | interface BountyActionButtonProps {
function BountyActionButton (line 25) | function BountyActionButton({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/bounty-card.tsx
function BountyCard (line 14) | function BountyCard({ bounty }: { bounty: BountyListProps }) {
function SubmissionsCountBadge (line 166) | function SubmissionsCountBadge({ count }: { count: number }) {
function BountyEndedBadge (line 174) | function BountyEndedBadge({ endsAt }: { endsAt: Date }) {
function BountyCardSkeleton (line 182) | function BountyCardSkeleton() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/bounty-list.tsx
function BountyList (line 13) | function BountyList() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/create-bounty-button.tsx
function CreateBountyButton (line 6) | function CreateBountyButton() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/page.tsx
function Page (line 6) | function Page() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/campaign-action-bar.tsx
type CampaignActionBarProps (line 9) | interface CampaignActionBarProps extends PropsWithChildren {
function CampaignActionBar (line 16) | function CampaignActionBar({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/campaign-controls.tsx
type CampaignControlsProps (line 31) | interface CampaignControlsProps {
function CampaignControls (line 35) | function CampaignControls({ campaign }: CampaignControlsProps) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/campaign-editor-skeleton.tsx
function CampaignEditorSkeleton (line 7) | function CampaignEditorSkeleton() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/campaign-editor.tsx
function CampaignEditor (line 88) | function CampaignEditor({ campaign }: { campaign: Campaign }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/campaign-events-modal.tsx
function CampaignEventsModal (line 14) | function CampaignEventsModal({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/campaign-events.tsx
type EventStatus (line 14) | type EventStatus = "delivered" | "opened" | "bounced";
type CampaignEvent (line 16) | type CampaignEvent = z.infer<typeof campaignEventSchema>;
constant MAX_EVENTS (line 18) | const MAX_EVENTS = 10;
function CampaignEvents (line 20) | function CampaignEvents() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/campaign-groups-selector.tsx
constant MAX_DISPLAYED_GROUPS (line 10) | const MAX_DISPLAYED_GROUPS = 1;
type CampaignGroupsSelectorProps (line 12) | interface CampaignGroupsSelectorProps {
function CampaignGroupsSelector (line 17) | function CampaignGroupsSelector({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/campaign-metrics.tsx
function CampaignMetrics (line 13) | function CampaignMetrics() {
function CampaignMetricsLoadingSkeleton (line 93) | function CampaignMetricsLoadingSkeleton() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/duplicate-logic-warning.tsx
function DuplicateLogicWarning (line 14) | function DuplicateLogicWarning() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/page-client.tsx
function ProgramCampaignPageClient (line 8) | function ProgramCampaignPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/page.tsx
function ProgramCampaignPage (line 3) | function ProgramCampaignPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/send-email-preview-modal.tsx
type SendEmailPreviewModalProps (line 11) | interface SendEmailPreviewModalProps {
function SendEmailPreviewModal (line 17) | function SendEmailPreviewModal({
function useSendEmailPreviewModal (line 130) | function useSendEmailPreviewModal({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/transactional-campaign-logic.tsx
function TransactionalCampaignLogic (line 14) | function TransactionalCampaignLogic() {
function DropdownValueInput (line 90) | function DropdownValueInput({
function ValueInput (line 131) | function ValueInput({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/use-campaign-confirmation-modals.tsx
type UseCampaignConfirmationModalsProps (line 15) | interface UseCampaignConfirmationModalsProps {
function useCampaignConfirmationModals (line 19) | function useCampaignConfirmationModals({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/utils.ts
function isValidTriggerCondition (line 4) | function isValidTriggerCondition(
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/campaign-stats.tsx
type StatsFilterProps (line 14) | interface StatsFilterProps {
type CampaignsCountByType (line 24) | interface CampaignsCountByType {
function CampaignStats (line 29) | function CampaignStats() {
function StatsFilter (line 100) | function StatsFilter({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/campaign-status-badges.tsx
constant CAMPAIGN_STATUS_BADGES (line 9) | const CAMPAIGN_STATUS_BADGES = {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/campaign-type-badges.tsx
constant CAMPAIGN_TYPE_BADGES (line 3) | const CAMPAIGN_TYPE_BADGES = {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/campaign-type-icon.tsx
function CampaignTypeIcon (line 4) | function CampaignTypeIcon({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/campaigns-page-content.tsx
function CampaignsPageContent (line 4) | function CampaignsPageContent({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/campaigns-table.tsx
type PartnersCountByGroup (line 38) | interface PartnersCountByGroup {
function CampaignsTable (line 43) | function CampaignsTable() {
function RowMenuButton (line 210) | function RowMenuButton({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/campaigns-upsell.tsx
function CampaignsUpsell (line 10) | function CampaignsUpsell() {
constant EXAMPLE_CAMPAIGNS (line 55) | const EXAMPLE_CAMPAIGNS: {
function ExampleCampaignCell (line 77) | function ExampleCampaignCell({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/create-campaign-button.tsx
function CreateCampaignButton (line 23) | function CreateCampaignButton() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/delete-campaign-modal.tsx
type DeleteCampaignModalProps (line 13) | interface DeleteCampaignModalProps {
function useDeleteCampaignModal (line 129) | function useDeleteCampaignModal(
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/layout.tsx
function CampaignsLayout (line 9) | function CampaignsLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/page.tsx
function ProgramCampaignsPage (line 7) | function ProgramCampaignsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/use-campaign.tsx
function useCampaign (line 7) | function useCampaign() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/use-campaigns-count.tsx
type UseCampaignsCountProps (line 8) | interface UseCampaignsCountProps
function useCampaignsCount (line 13) | function useCampaignsCount<T>({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/use-campaigns-filters.tsx
type CampaignsCountByType (line 12) | interface CampaignsCountByType {
type CampaignsCountByStatus (line 17) | interface CampaignsCountByStatus {
function useCampaignsFilters (line 22) | function useCampaignsFilters() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/coming-soon-page.tsx
function ComingSoonPage (line 6) | function ComingSoonPage({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/commissions/[commissionId]/page-client.tsx
function CommissionDetailsPageClient (line 38) | function CommissionDetailsPageClient() {
function CommissionDetailsContent (line 101) | function CommissionDetailsContent({
function CommissionActivity (line 311) | function CommissionActivity({
function CommissionDetailSkeleton (line 510) | function CommissionDetailSkeleton() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/commissions/[commissionId]/page.tsx
function CommissionDetailsPage (line 3) | function CommissionDetailsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/commissions/commission-popover-buttons.tsx
function CommissionPopoverButtons (line 9) | function CommissionPopoverButtons() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/commissions/commissions-stats.tsx
function CommissionsStats (line 10) | function CommissionsStats() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/commissions/commissions-table.tsx
function CommissionsTable (line 68) | function CommissionsTable() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/commissions/create-clawback-sheet.tsx
type CreateClawbackSheetProps (line 18) | interface CreateClawbackSheetProps {
type FormData (line 24) | type FormData = z.infer<typeof createClawbackSchema>;
function CreateClawbackSheetContent (line 26) | function CreateClawbackSheetContent(
function CreateClawbackSheet (line 235) | function CreateClawbackSheet({
function useCreateClawbackSheet (line 247) | function useCreateClawbackSheet(
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/commissions/create-commission-button.tsx
function CreateCommissionButton (line 6) | function CreateCommissionButton() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/commissions/create-commission-sheet.tsx
type CreateCommissionSheetProps (line 37) | interface CreateCommissionSheetProps {
type FormData (line 41) | type FormData = z.infer<typeof createCommissionSchema>;
type StripeInvoiceFromApi (line 43) | type StripeInvoiceFromApi = z.infer<typeof StripeCustomerInvoiceSchema>;
function fetcherStripeInvoices (line 45) | async function fetcherStripeInvoices(url: string): Promise<{
function CreateCommissionSheetContent (line 65) | function CreateCommissionSheetContent({
function CreateCommissionSheet (line 1020) | function CreateCommissionSheet({
function useCreateCommissionSheet (line 1035) | function useCreateCommissionSheet(
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/commissions/page.tsx
function ProgramCommissions (line 10) | function ProgramCommissions() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/commissions/use-commission-filters.tsx
function useCommissionFilters (line 19) | function useCommissionFilters() {
function usePartnerFilterOptions (line 188) | function usePartnerFilterOptions(search: string) {
function useCustomerFilterOptions (line 223) | function useCustomerFilterOptions(search: string) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/customers/(index)/layout.tsx
function PartnerCustomersLayout (line 16) | function PartnerCustomersLayout({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/customers/(index)/page.tsx
function ProgramCustomersPage (line 6) | function ProgramCustomersPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/customers/(index)/referrals/page.tsx
function PartnerCustomersReferralsPage (line 5) | function PartnerCustomersReferralsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/customers/[customerId]/earnings/page-client.tsx
function CustomerEarningsPageClient (line 16) | function CustomerEarningsPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/customers/[customerId]/earnings/page.tsx
function CustomerEarningsPage (line 3) | function CustomerEarningsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/customers/[customerId]/layout.tsx
function ProgramCustomerLayout (line 26) | function ProgramCustomerLayout({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/customers/[customerId]/page.tsx
function ProgramCustomerPage (line 4) | async function ProgramCustomerPage({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/customers/[customerId]/sales/page-client.tsx
function CustomerSalesPageClient (line 13) | function CustomerSalesPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/customers/[customerId]/sales/page.tsx
function CustomerSalesPage (line 3) | function CustomerSalesPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/customers/customers-dropdown-menu.tsx
function CustomersDropdownMenu (line 10) | function CustomersDropdownMenu() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/example-fraud-events.tsx
constant EXAMPLE_FRAUD_EVENTS (line 7) | const EXAMPLE_FRAUD_EVENTS: {
type ExampleFraudEventProps (line 24) | interface ExampleFraudEventProps {
function ExampleFraudEvents (line 30) | function ExampleFraudEvents() {
function ExampleFraudEvent (line 43) | function ExampleFraudEvent({ event }: { event: ExampleFraudEventProps }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/fraud-group-table.tsx
function FraudGroupTable (line 38) | function FraudGroupTable() {
function RowMenuButton (line 410) | function RowMenuButton({ row }: { row: Row<FraudGroupProps> }) {
function MenuItem (line 486) | function MenuItem({
function useCurrentFraudGroup (line 526) | function useCurrentFraudGroup({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/fraud-paid-traffic-settings.tsx
type FormData (line 24) | type FormData = z.infer<
constant PAID_TRAFFIC_PLATFORM_ICONS (line 28) | const PAID_TRAFFIC_PLATFORM_ICONS: Record<
type FraudPaidTrafficSettingsProps (line 41) | interface FraudPaidTrafficSettingsProps {
function FraudPaidTrafficSettings (line 45) | function FraudPaidTrafficSettings({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/fraud-referral-source-settings.tsx
type FormData (line 10) | type FormData = z.infer<
type FraudReferralSourceSettingsProps (line 14) | interface FraudReferralSourceSettingsProps {
function FraudReferralSourceSettings (line 18) | function FraudReferralSourceSettings({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/fraud-rule-toggle-settings.tsx
type FraudRuleToggleSettingsProps (line 7) | interface FraudRuleToggleSettingsProps {
function FraudRuleToggleSettings (line 14) | function FraudRuleToggleSettings({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/fraud-upsell.tsx
function FraudUpsell (line 9) | function FraudUpsell() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/layout.tsx
function FraudRiskLayout (line 9) | function FraudRiskLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/page.tsx
function ProgramFraudRiskPage (line 7) | function ProgramFraudRiskPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/program-fraud-actions-menu.tsx
function ProgramFraudActionsMenu (line 9) | function ProgramFraudActionsMenu() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/program-fraud-settings-button.tsx
function ProgramFraudSettingsButton (line 6) | function ProgramFraudSettingsButton() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/program-fraud-settings-sheet.tsx
constant RULES_WITH_CUSTOM_UI (line 32) | const RULES_WITH_CUSTOM_UI = new Set([
constant TOGGLE_ONLY_RULES (line 38) | const TOGGLE_ONLY_RULES = CONFIGURABLE_FRAUD_RULES.filter(
type ProgramFraudSettingsSheetProps (line 43) | interface ProgramFraudSettingsSheetProps {
function ProgramFraudSettingsSheetContent (line 47) | function ProgramFraudSettingsSheetContent({
function ProgramFraudSettingsSheet (line 226) | function ProgramFraudSettingsSheet({
function useProgramFraudSettingsSheet (line 239) | function useProgramFraudSettingsSheet() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolved/page.tsx
function ResolvedFraudGroupsPage (line 5) | async function ResolvedFraudGroupsPage(props: {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolved/resolved-fraud-group-table.tsx
function ResolvedFraudGroupTable (line 27) | function ResolvedFraudGroupTable() {
function useCurrentFraudGroup (line 313) | function useCurrentFraudGroup({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/use-fraud-group-filters.tsx
function useFraudGroupFilters (line 13) | function useFraudGroupFilters({
function usePartnerFilterOptions (line 123) | function usePartnerFilterOptions(search: string) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/branding/page.tsx
function GroupBrandingPage (line 3) | function GroupBrandingPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/discounts/page.tsx
function GroupDiscountsPage (line 3) | function GroupDiscountsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/group-header.tsx
function GroupHeaderTitle (line 29) | function GroupHeaderTitle() {
function GroupHeaderTabs (line 79) | function GroupHeaderTabs() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/layout.tsx
function GroupLayout (line 5) | function GroupLayout({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/links/add-edit-group-additional-link-modal.tsx
type AdditionalLinkFormData (line 21) | type AdditionalLinkFormData = {
constant URL_VALIDATION_MODES (line 27) | const URL_VALIDATION_MODES = [
function partnerLinkToFormData (line 45) | function partnerLinkToFormData(
function formDataToPartnerLink (line 64) | function formDataToPartnerLink(
type AddDestinationUrlModalProps (line 92) | interface AddDestinationUrlModalProps {
function AddDestinationUrlModalContent (line 99) | function AddDestinationUrlModalContent({
function AddDestinationUrlModal (line 399) | function AddDestinationUrlModal({
function useAddDestinationUrlModal (line 420) | function useAddDestinationUrlModal(
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/links/add-edit-group-default-link-sheet.tsx
type DefaultPartnerLinkSheetProps (line 30) | interface DefaultPartnerLinkSheetProps {
type FormData (line 35) | type FormData = z.infer<typeof createOrUpdateDefaultLinkSchema>;
function DefaultPartnerLinkSheetContent (line 37) | function DefaultPartnerLinkSheetContent({
function LinkSettingsCard (line 241) | function LinkSettingsCard({
function DefaultPartnerLinkSheet (line 259) | function DefaultPartnerLinkSheet({
function useDefaultPartnerLinkSheet (line 272) | function useDefaultPartnerLinkSheet(props: {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/links/change-program-domain-modal.tsx
type ChangeProgramDomainModalProps (line 12) | type ChangeProgramDomainModalProps = {
function ChangeProgramDomainModal (line 19) | function ChangeProgramDomainModal(props: ChangeProgramDomainModalProps) {
function ChangeProgramDomainModalInner (line 30) | function ChangeProgramDomainModalInner({
function useChangeProgramDomainModal (line 150) | function useChangeProgramDomainModal({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/links/group-additional-links.tsx
type FormData (line 29) | type FormData = Pick<
function GroupAdditionalLinks (line 34) | function GroupAdditionalLinks() {
function GroupAdditionalLinksForm (line 68) | function GroupAdditionalLinksForm({ group }: { group: GroupProps }) {
function SettingsRow (line 230) | function SettingsRow({
function LinkFormat (line 252) | function LinkFormat({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/links/group-default-links.tsx
function GroupDefaultLinks (line 20) | function GroupDefaultLinks() {
function CreateDefaultLinkButton (line 71) | function CreateDefaultLinkButton({
function DefaultLinkPreview (line 99) | function DefaultLinkPreview({ link }: { link: PartnerGroupDefaultLink }) {
function DefaultLinkPreviewSkeleton (line 211) | function DefaultLinkPreviewSkeleton() {
function NoDefaultLinks (line 234) | function NoDefaultLinks() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/links/group-link-settings.tsx
type FormData (line 19) | type FormData = {
function GroupLinkSettings (line 30) | function GroupLinkSettings() {
function GroupLinkSettingsForm (line 57) | function GroupLinkSettingsForm({ group }: { group: GroupProps }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/links/page.tsx
function GroupDefaultLinksPage (line 5) | function GroupDefaultLinksPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/links/partner-link-preview.tsx
function PartnerLinkPreview (line 8) | function PartnerLinkPreview({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/rewards/group-rewards.tsx
constant REWARD_EVENT_DESCRIPTIONS (line 20) | const REWARD_EVENT_DESCRIPTIONS: Record<
function GroupRewards (line 38) | function GroupRewards() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/rewards/page.tsx
function GroupRewardsPage (line 3) | function GroupRewardsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/settings/group-additional-settings.tsx
type FormData (line 22) | type FormData = z.infer<typeof updateGroupSchema>;
function GroupAdditionalSettings (line 24) | function GroupAdditionalSettings() {
function GroupAdditionalSettingsForm (line 31) | function GroupAdditionalSettingsForm({
function ConfirmAutoApproveModal (line 281) | function ConfirmAutoApproveModal({
function ConfirmHoldingPeriodModal (line 348) | function ConfirmHoldingPeriodModal({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/settings/group-move-rules.tsx
constant ATTRIBUTES (line 20) | const ATTRIBUTES = [
type Attribute (line 27) | type Attribute = (typeof ATTRIBUTES)[number];
type AttributeType (line 28) | type AttributeType = (typeof ATTRIBUTES)[number]["type"];
type RangeValue (line 29) | type RangeValue = { min: number; max?: number };
type ValueType (line 30) | type ValueType = number | RangeValue | undefined;
constant ATTRIBUTE_BY_KEY (line 32) | const ATTRIBUTE_BY_KEY = Object.fromEntries(
constant RANGE_SELECTOR_OPTIONS (line 36) | const RANGE_SELECTOR_OPTIONS = [
function GroupMoveRules (line 41) | function GroupMoveRules() {
function GroupRule (line 143) | function GroupRule({
function GroupMoveTarget (line 297) | function GroupMoveTarget() {
function NoGroupRule (line 327) | function NoGroupRule() {
function GroupMoveRuleUpsell (line 338) | function GroupMoveRuleUpsell() {
function ValueInput (line 360) | function ValueInput({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/settings/group-settings.tsx
type FormData (line 23) | type FormData = z.input<typeof updateGroupSchema>;
constant GROUP_NAME_DESCRIPTION (line 25) | const GROUP_NAME_DESCRIPTION =
constant GROUP_SLUG_DESCRIPTION (line 27) | const GROUP_SLUG_DESCRIPTION =
constant GROUP_ID_DESCRIPTION (line 29) | const GROUP_ID_DESCRIPTION =
function GroupSettings (line 32) | function GroupSettings() {
function GroupSettingsForm (line 37) | function GroupSettingsForm({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/settings/page.tsx
function GroupSettingsPage (line 4) | function GroupSettingsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/create-group-button.tsx
function CreateGroupButton (line 10) | function CreateGroupButton() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/create-group-modal.tsx
type CreateGroupModalProps (line 16) | interface CreateGroupModalProps {
type FormData (line 20) | type FormData = z.input<typeof createGroupSchema>;
function CreateGroupModalContent (line 22) | function CreateGroupModalContent({ setIsOpen }: CreateGroupModalProps) {
function CreateGroupModal (line 163) | function CreateGroupModal({
function useCreateGroupModal (line 176) | function useCreateGroupModal(
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/groups-table.tsx
function GroupsTable (line 53) | function GroupsTable() {
function RowMenuButton (line 244) | function RowMenuButton({
function MenuItem (line 369) | function MenuItem({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/page.tsx
function ProgramPartnersGroups (line 6) | function ProgramPartnersGroups() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/layout.tsx
function ProgramLayout (line 4) | function ProgramLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/messages/[partnerId]/page-client.tsx
function ProgramMessagesPartnerPageClient (line 30) | function ProgramMessagesPartnerPageClient() {
function PartnerInfoSectionSkeleton (line 265) | function PartnerInfoSectionSkeleton() {
function PartnerInfoGroupSkeleton (line 282) | function PartnerInfoGroupSkeleton() {
function PartnerInfoStatsSkeleton (line 294) | function PartnerInfoStatsSkeleton({ className }: { className?: string }) {
function ViewPartnerButton (line 312) | function ViewPartnerButton({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/messages/[partnerId]/page.tsx
function ProgramMessagesPartnerPage (line 3) | function ProgramMessagesPartnerPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/messages/layout.tsx
function MessagesLayout (line 18) | function MessagesLayout({ children }: { children: ReactNode }) {
function CapableLayout (line 30) | function CapableLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/messages/messages-disabled.tsx
function MessagesDisabled (line 8) | function MessagesDisabled() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/messages/messages-upsell.tsx
function MessagesUpsell (line 8) | function MessagesUpsell() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/messages/page-client.tsx
function ProgramMessagesPageClient (line 8) | function ProgramMessagesPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/messages/page.tsx
function ProgramMessages (line 3) | function ProgramMessages() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/network/layout.tsx
function PartnerNetworkLayout (line 10) | function PartnerNetworkLayout({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/network/network-empty-state.tsx
function NetworkEmptyState (line 6) | function NetworkEmptyState({
function DemoAvatar (line 62) | function DemoAvatar(props: SVGProps<SVGSVGElement>) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/network/network-upsell.tsx
function NetworkUpsell (line 8) | function NetworkUpsell({ contactUs }: { contactUs?: boolean }) {
constant EXAMPLE_PARTNERS (line 47) | const EXAMPLE_PARTNERS = [
function ExamplePartnerCell (line 70) | function ExamplePartnerCell({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/network/page-client.tsx
function ProgramPartnerNetworkPageClient (line 62) | function ProgramPartnerNetworkPageClient() {
function PartnerCard (line 319) | function PartnerCard({
function ListRow (line 553) | function ListRow({
function ListPill (line 654) | function ListPill({ icon: Icon, label }: { icon?: Icon; label: string }) {
function useCurrentPartner (line 666) | function useCurrentPartner({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/network/page.tsx
function ProgramPartnerNetwork (line 6) | function ProgramPartnerNetwork() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/network/use-partner-network-filters.tsx
function usePartnerNetworkFilters (line 18) | function usePartnerNetworkFilters({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/overview-chart.tsx
type ViewType (line 17) | type ViewType = "sales" | "leads" | "commissions";
function OverviewChart (line 30) | function OverviewChart() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/overview-links.tsx
function OverviewLinks (line 22) | function OverviewLinks() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/overview-tasks.tsx
function OverviewTasks (line 11) | function OverviewTasks() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/page-client.tsx
constant BLOCKS (line 27) | const BLOCKS = [
function ProgramOverviewPageClient (line 37) | function ProgramOverviewPageClient() {
function FinishSetupWrapper (line 116) | function FinishSetupWrapper({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/page.tsx
function ProgramOverviewPage (line 5) | async function ProgramOverviewPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners-graphic.tsx
function PartnersGraphic (line 3) | function PartnersGraphic() {
constant EXAMPLE_PARTNERS (line 16) | const EXAMPLE_PARTNERS = [
function ExamplePartnerCell (line 47) | function ExamplePartnerCell({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners-upgrade-cta.tsx
function PartnersUpgradeCTA (line 10) | function PartnersUpgradeCTA({
constant EXAMPLE_PARTNERS (line 77) | const EXAMPLE_PARTNERS = [
function ExamplePartnerCell (line 108) | function ExamplePartnerCell({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/comments/page.tsx
function ProgramPartnerCommentsPage (line 6) | function ProgramPartnerCommentsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/customers/page.tsx
function ProgramPartnerCustomersPage (line 19) | function ProgramPartnerCustomersPage() {
function PartnerCustomers (line 38) | function PartnerCustomers({ partner }: { partner: EnrolledPartnerProps }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/layout.tsx
function ProgramPartnerLayout (line 65) | function ProgramPartnerLayout({
function PartnerProfileButton (line 138) | function PartnerProfileButton({
function PageControls (line 170) | function PageControls({ partner }: { partner: EnrolledPartnerProps }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/links/page.tsx
function ProgramPartnerLinksPage (line 28) | function ProgramPartnerLinksPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/partner-nav.tsx
function PartnerNav (line 17) | function PartnerNav() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/partner-stats.tsx
function PartnerStats (line 7) | function PartnerStats({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/payouts/page.tsx
function ProgramPartnerPayoutsPage (line 21) | function ProgramPartnerPayoutsPage() {
function PartnerPayouts (line 40) | function PartnerPayouts({ partner }: { partner: EnrolledPartnerProps }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/applications/applications-menu.tsx
function ApplicationsMenu (line 13) | function ApplicationsMenu() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/applications/page-client.tsx
function ProgramPartnersApplicationsPageClient (line 63) | function ProgramPartnersApplicationsPageClient() {
function RowMenuButton (line 508) | function RowMenuButton({
function useCurrentPartner (line 564) | function useCurrentPartner({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/applications/page.tsx
function ProgramPartnersApplications (line 6) | function ProgramPartnersApplications() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/applications/rejected/page-client.tsx
function ProgramPartnersRejectedApplicationsPageClient (line 64) | function ProgramPartnersRejectedApplicationsPageClient() {
function PartnerRowMenuButton (line 451) | function PartnerRowMenuButton({
function useCurrentPartner (line 528) | function useCurrentPartner({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/applications/rejected/page.tsx
function ProgramPartnersRejectedApplications (line 5) | async function ProgramPartnersRejectedApplications(props: {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/import-export-buttons.tsx
function ImportExportButtons (line 15) | function ImportExportButtons() {
function ImportOption (line 103) | function ImportOption({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/invite-partner-button.tsx
function InvitePartnerButton (line 6) | function InvitePartnerButton() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/invite-partner-sheet.tsx
type InvitePartnerSheetProps (line 42) | interface InvitePartnerSheetProps {
type InvitePartnerFormData (line 46) | type InvitePartnerFormData = {
type EmailContent (line 54) | type EmailContent = {
function InvitePartnerSheetContent (line 60) | function InvitePartnerSheetContent({ setIsOpen }: InvitePartnerSheetProp...
function EmailPreview (line 442) | function EmailPreview({
function InvitePartnerSheet (line 671) | function InvitePartnerSheet({
function useInvitePartnerSheet (line 684) | function useInvitePartnerSheet() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/page.tsx
function ProgramPartners (line 7) | function ProgramPartners() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/partners-table.tsx
function PartnersTable (line 114) | function PartnersTable() {
function BulkActionsMenu (line 622) | function BulkActionsMenu({
function RowMenuButton (line 690) | function RowMenuButton({
function MenuItem (line 924) | function MenuItem({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/use-partner-filters.tsx
function usePartnerFilters (line 12) | function usePartnerFilters(
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/[payoutId]/page-client.tsx
type PayoutActivityItem (line 52) | type PayoutActivityItem = {
function PayoutDetailsPageClient (line 58) | function PayoutDetailsPageClient() {
function PayoutDetailsContent (line 128) | function PayoutDetailsContent({
function PayoutDetailsskeleton (line 479) | function PayoutDetailsskeleton() {
function PayoutConfirmButton (line 493) | function PayoutConfirmButton() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/[payoutId]/page.tsx
function PayoutDetailsPage (line 3) | function PayoutDetailsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/page-client.tsx
function ProgramPayoutsPageClient (line 6) | function ProgramPayoutsPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/page.tsx
function ProgramPayoutsPage (line 6) | function ProgramPayoutsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/payout-paid-cell.tsx
type PayoutPaidCellUser (line 7) | type PayoutPaidCellUser = {
type PayoutPaidCellProps (line 14) | type PayoutPaidCellProps = {
function PayoutPaidCell (line 20) | function PayoutPaidCell({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/payout-stats.tsx
function PayoutStats (line 19) | function PayoutStats() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/payout-table.tsx
function PayoutTable (line 36) | function PayoutTable() {
function AmountRowItem (line 271) | function AmountRowItem({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/program-payout-methods.tsx
type PayoutMethodCardProps (line 15) | interface PayoutMethodCardProps {
function ProgramPayoutMethods (line 26) | function ProgramPayoutMethods() {
function PayoutMethodCard (line 154) | function PayoutMethodCard({
function ExternalPayoutMethods (line 187) | function ExternalPayoutMethods() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/program-payout-mode-section.tsx
function ProgramPayoutModeSection (line 9) | function ProgramPayoutModeSection() {
function WebhookInfo (line 69) | function WebhookInfo() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/program-payout-settings-button.tsx
function ProgramPayoutSettingsButton (line 6) | function ProgramPayoutSettingsButton() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/program-payout-settings-sheet.tsx
type ProgramPayoutSettingsSheetProps (line 22) | type ProgramPayoutSettingsSheetProps = {
type FormData (line 26) | type FormData = Pick<ProgramProps, "minPayoutAmount">;
function ProgramPayoutSettingsSheetContent (line 28) | function ProgramPayoutSettingsSheetContent({
function ProgramPayoutSettingsSheet (line 208) | function ProgramPayoutSettingsSheet({
function useProgramPayoutSettingsSheet (line 221) | function useProgramPayoutSettingsSheet() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/success/page-client.tsx
function PayoutsSuccessPageClient (line 22) | function PayoutsSuccessPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/success/page.tsx
function PayoutsSuccessPage (line 3) | function PayoutsSuccessPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/use-payout-filters.tsx
function usePayoutFilters (line 12) | function usePayoutFilters() {
function usePartnerFilterOptions (line 134) | function usePartnerFilterOptions(search: string) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/program-settings-row.tsx
function SettingsRow (line 3) | function SettingsRow({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/resources/page.tsx
function ProgramResourcesPage (line 6) | function ProgramResourcesPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/resources/program-brand-assets/add-color-modal.tsx
type ColorModalProps (line 24) | type ColorModalProps = {
type ColorFormData (line 35) | type ColorFormData = z.infer<typeof colorFormSchema>;
function ColorModal (line 37) | function ColorModal(props: ColorModalProps) {
constant DEFAULT_COLORS (line 48) | const DEFAULT_COLORS = ["#dc2626", "#84cc16", "#14b8a6", "#0ea5e9", "#d9...
function ColorModalInner (line 50) | function ColorModalInner({
function useColorModal (line 246) | function useColorModal({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/resources/program-brand-assets/add-file-modal.tsx
type FileModalProps (line 24) | type FileModalProps = {
type FileFormData (line 36) | type FileFormData = z.infer<typeof fileFormSchema>;
function FileModal (line 38) | function FileModal(props: FileModalProps) {
function FileModalInner (line 49) | function FileModalInner({
function useFileModal (line 288) | function useFileModal({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/resources/program-brand-assets/add-link-modal.tsx
type LinkModalProps (line 22) | type LinkModalProps = {
type LinkFormData (line 33) | type LinkFormData = z.infer<typeof linkFormSchema>;
function LinkModal (line 35) | function LinkModal(props: LinkModalProps) {
function LinkModalInner (line 46) | function LinkModalInner({
function useLinkModal (line 216) | function useLinkModal({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/resources/program-brand-assets/add-logo-modal.tsx
type LogoModalProps (line 24) | type LogoModalProps = {
type LogoFormData (line 37) | type LogoFormData = z.infer<typeof logoFormSchema>;
function LogoModal (line 39) | function LogoModal(props: LogoModalProps) {
function LogoModalInner (line 50) | function LogoModalInner({
function useLogoModal (line 290) | function useLogoModal({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/resources/program-brand-assets/index.tsx
function ProgramBrandAssets (line 31) | function ProgramBrandAssets() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/resources/program-brand-assets/use-upload-program-resource.ts
function useUploadProgramResource (line 6) | function useUploadProgramResource(workspaceId: string) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/resources/program-help-and-support.tsx
type FormData (line 17) | type FormData = Pick<
function ProgramHelpAndSupport (line 22) | function ProgramHelpAndSupport() {
function ProgramHelpAndSupportContent (line 41) | function ProgramHelpAndSupportContent({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/invoices/page-client.tsx
constant INVOICE_TYPES (line 21) | const INVOICE_TYPES = [
function WorkspaceInvoicesClient (line 27) | function WorkspaceInvoicesClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/invoices/page.tsx
function WorkspaceInvoices (line 4) | function WorkspaceInvoices() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/layout.tsx
function BillingLayout (line 5) | function BillingLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/page.tsx
function WorkspaceBilling (line 4) | function WorkspaceBilling() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/payment-methods.tsx
function PaymentMethods (line 17) | function PaymentMethods() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/plan-usage.tsx
function PlanUsage (line 44) | function PlanUsage() {
function UsageTabCard (line 272) | function UsageTabCard({
function UsageCategory (line 464) | function UsageCategory(data: {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/upgrade/adjust-usage-row.tsx
function AdjustUsageRow (line 14) | function AdjustUsageRow({
function UsageSlider (line 60) | function UsageSlider({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/upgrade/page-client.tsx
constant COMPARE_FEATURE_ICONS (line 36) | const COMPARE_FEATURE_ICONS: Record<
function WorkspaceBillingUpgradePageClient (line 49) | function WorkspaceBillingUpgradePageClient() {
function BillingCompareSection (line 312) | function BillingCompareSection({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/upgrade/page.tsx
function WorkspaceBillingUpgrade (line 4) | function WorkspaceBillingUpgrade() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/usage-chart.tsx
constant BAR_COLORS (line 32) | const BAR_COLORS = [
constant RESOURCES (line 44) | const RESOURCES = ["links", "events"] as const;
function UsageChart (line 61) | function UsageChart() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/domains/default/page-client.tsx
function DubDomainsIcon (line 23) | function DubDomainsIcon(domain: string) {
function DefaultDomains (line 44) | function DefaultDomains() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/domains/default/page.tsx
function DefaultDomainsPage (line 3) | function DefaultDomainsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/domains/email/constants.ts
constant EMAIL_DOMAIN_STATUS_TO_VARIANT (line 3) | const EMAIL_DOMAIN_STATUS_TO_VARIANT: Record<EmailDomainStatus, string> =
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/domains/email/email-domain-card.tsx
type EmailDomainCardProps (line 26) | interface EmailDomainCardProps {
function EmailDomainCard (line 30) | function EmailDomainCard({ domain }: EmailDomainCardProps) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/domains/email/email-domain-dns-records.tsx
type EmailDomainDnsRecordsProps (line 9) | interface EmailDomainDnsRecordsProps {
type DomainRecord (line 13) | interface DomainRecord {
type DnsRecordsTableProps (line 28) | interface DnsRecordsTableProps {
function DnsRecordsTable (line 36) | function DnsRecordsTable({
function EmailDomainDnsRecords (line 171) | function EmailDomainDnsRecords({ domain }: EmailDomainDnsRecordsProps) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/domains/email/page-client.tsx
function EmailDomains (line 15) | function EmailDomains() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/domains/email/page.tsx
function EmailDomainsPage (line 3) | function EmailDomainsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/domains/header.tsx
function DomainsHeader (line 8) | function DomainsHeader({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/domains/layout.tsx
function DomainsLayout (line 6) | function DomainsLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/domains/page-client.tsx
function CustomDomains (line 34) | function CustomDomains() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/domains/page.tsx
function CustomDomainsPage (line 3) | function CustomDomainsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/[integrationSlug]/loading.tsx
function IntegrationPageLoading (line 3) | function IntegrationPageLoading() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/[integrationSlug]/manage/page.tsx
function IntegrationManagePage (line 9) | async function IntegrationManagePage(props: {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/[integrationSlug]/page-client.tsx
function IntegrationPageClient (line 67) | function IntegrationPageClient({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/[integrationSlug]/page.tsx
function IntegrationPage (line 8) | async function IntegrationPage(props: {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/enabled-integrations.tsx
function EnabledIntegrations (line 14) | function EnabledIntegrations({
function IntegrationRow (line 63) | function IntegrationRow({ integration }: { integration: Integration }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/enabled/page.tsx
function EnabledIntegrationsPage (line 16) | async function EnabledIntegrationsPage(props: {
function EnabledIntegrationsPageRSC (line 35) | async function EnabledIntegrationsPageRSC({ slug }: { slug: string }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/featured-integrations.tsx
constant FEATURED_SLUGS (line 20) | const FEATURED_SLUGS = ["make", "zapier", "stripe", "shopify"];
function FeaturedIntegrations (line 22) | function FeaturedIntegrations({
function CarouselNavBar (line 109) | function CarouselNavBar({
function FeaturedIntegrationsLoader (line 170) | function FeaturedIntegrationsLoader() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/integrations-cards.tsx
constant CATEGORY_ORDER (line 11) | const CATEGORY_ORDER = [
constant PRESENCE_ANIMATION (line 23) | const PRESENCE_ANIMATION = {
function IntegrationsCards (line 30) | function IntegrationsCards({
function IntegrationsCardsLoader (line 127) | function IntegrationsCardsLoader() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/integrations-list.tsx
function IntegrationsList (line 15) | async function IntegrationsList() {
type IntegrationsWithInstallations (line 33) | type IntegrationsWithInstallations = (Integration & {
function IntegrationsListRSC (line 37) | async function IntegrationsListRSC() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/layout.tsx
function IntegrationsLayout (line 5) | function IntegrationsLayout({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/new/page.tsx
function NewIntegrationsPage (line 6) | async function NewIntegrationsPage(props: {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/page.tsx
function IntegrationsPage (line 5) | function IntegrationsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/members/page-client.tsx
function WorkspaceMembersClient (line 47) | function WorkspaceMembersClient() {
function RoleCell (line 331) | function RoleCell({
function RowMenuButton (line 413) | function RowMenuButton({
function MenuItem (line 491) | function MenuItem({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/members/page.tsx
function WorkspaceMembers (line 3) | function WorkspaceMembers() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/notifications/layout.tsx
function NotificationsLayout (line 5) | function NotificationsLayout({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/notifications/page-client.tsx
type PreferenceType (line 14) | type PreferenceType = z.infer<typeof notificationTypes>;
type Preferences (line 15) | type Preferences = Record<PreferenceType, boolean>;
function NotificationsSettingsPageClient (line 17) | function NotificationsSettingsPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/notifications/page.tsx
function NotificationsSettingsPage (line 3) | function NotificationsSettingsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/oauth-apps/[appId]/page-client.tsx
function OAuthAppManagePageClient (line 23) | function OAuthAppManagePageClient({ appId }: { appId: string }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/oauth-apps/[appId]/page.tsx
function OAuthAppManagePage (line 3) | async function OAuthAppManagePage(props: {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/oauth-apps/create-oauth-app-button.tsx
function CreateOAuthAppButton (line 9) | function CreateOAuthAppButton() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/oauth-apps/layout.tsx
function OAuthAppsLayout (line 6) | function OAuthAppsLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/oauth-apps/new/page-client.tsx
function NewOAuthAppPageClient (line 10) | function NewOAuthAppPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/oauth-apps/new/page.tsx
function NewOAuthAppPage (line 3) | async function NewOAuthAppPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/oauth-apps/page-client.tsx
function OAuthAppsPageClient (line 12) | function OAuthAppsPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/oauth-apps/page.tsx
function OAuthAppsPage (line 3) | async function OAuthAppsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/page-client.tsx
function WorkspaceSettingsClient (line 13) | function WorkspaceSettingsClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/page.tsx
function WorkspaceSettings (line 5) | function WorkspaceSettings() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/audit-logs.tsx
function AuditLogs (line 12) | function AuditLogs() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/layout.tsx
function SecurityLayout (line 5) | function SecurityLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/page-client.tsx
function WorkspaceSecurityClient (line 7) | function WorkspaceSecurityClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/page.tsx
function WorkspaceSecurity (line 3) | function WorkspaceSecurity() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/saml.tsx
function SAML (line 23) | function SAML() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/scim.tsx
function SCIM (line 14) | function SCIM() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tokens/page.tsx
function TokensPage (line 32) | function TokensPage() {
function RowMenuButton (line 213) | function RowMenuButton({
function MenuItem (line 270) | function MenuItem({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/add-hostname-modal.tsx
type AddHostnameModalProps (line 121) | interface AddHostnameModalProps {
function useAddHostnameModal (line 151) | function useAddHostnameModal() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/base-script-section.tsx
function BaseScriptSection (line 7) | function BaseScriptSection() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/connection-instructions.tsx
function ConnectionInstructions (line 10) | function ConnectionInstructions() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/conversion-tracking-section.tsx
function ConversionTrackingSection (line 11) | function ConversionTrackingSection() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/conversion-tracking-toggle.tsx
function ConversionTrackingToggle (line 18) | function ConversionTrackingToggle() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/guide.tsx
function GuideMarkdown (line 6) | function GuideMarkdown({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/hostname-menu.tsx
function HostnameMenu (line 6) | function HostnameMenu({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/outbound-domain-tracking-section.tsx
function OutboundDomainTrackingSection (line 9) | function OutboundDomainTrackingSection() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/page-client.tsx
function WorkspaceTrackingSettingsPageClient (line 144) | function WorkspaceTrackingSettingsPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/page.tsx
function WorkspaceTrackingSettingsPage (line 7) | function WorkspaceTrackingSettingsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/publishable-key-menu.tsx
function PublishableKeyMenu (line 6) | function PublishableKeyMenu({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/site-visit-tracking-section.tsx
function SiteVisitTrackingSection (line 12) | function SiteVisitTrackingSection() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/step.tsx
type Step (line 10) | type Step = "connect" | "lead" | "sale";
type BaseStepProps (line 12) | type BaseStepProps = {
type StepProps (line 17) | type StepProps = BaseStepProps & {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/track-lead-guides-section.tsx
function TrackLeadsGuidesSection (line 10) | function TrackLeadsGuidesSection() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/track-sales-guides-section.tsx
function TrackSalesGuidesSection (line 11) | function TrackSalesGuidesSection() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/use-dynamic-guide.ts
function useDynamicGuide (line 8) | function useDynamicGuide(
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/use-selected-guide.ts
function useSelectedGuide (line 5) | function useSelectedGuide({ guides }: { guides: IntegrationGuide[] }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/tracking/verify-install.tsx
type VerifyStatus (line 12) | type VerifyStatus = "pending" | "success" | "error";
type VerificationResponse (line 29) | type VerificationResponse = {
method onSuccess (line 47) | async onSuccess(response) {
method onError (line 57) | onError({ error }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/webhooks/[webhookId]/edit/page-client.tsx
function UpdateWebhookPageClient (line 11) | function UpdateWebhookPageClient({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/webhooks/[webhookId]/edit/page.tsx
function UpdateWebhookPage (line 3) | async function UpdateWebhookPage(props: {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/webhooks/[webhookId]/layout.tsx
function WebhookLayout (line 4) | async function WebhookLayout(props: {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/webhooks/[webhookId]/page-client.tsx
function WebhookLogsPageClient (line 15) | function WebhookLogsPageClient({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/webhooks/[webhookId]/page.tsx
function WebhookEventsPage (line 3) | async function WebhookEventsPage(props: {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/webhooks/create-webhook-button.tsx
function CreateWebhookButton (line 10) | function CreateWebhookButton() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/webhooks/layout.tsx
function WebhooksLayout (line 6) | function WebhooksLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/webhooks/new/page-client.tsx
function NewWebhookPageClient (line 7) | function NewWebhookPageClient({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/webhooks/new/page.tsx
function NewWebhookPage (line 4) | async function NewWebhookPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/webhooks/page-client.tsx
function WebhooksPageClient (line 10) | function WebhooksPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/webhooks/page.tsx
function WebhooksPage (line 3) | function WebhooksPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/analytics/client.tsx
function AnalyticsClient (line 8) | function AnalyticsClient({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/analytics/page.tsx
function WorkspaceAnalytics (line 7) | function WorkspaceAnalytics() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/auth.tsx
function WorkspaceAuth (line 9) | function WorkspaceAuth({ children }: { children: ReactNode }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/layout.tsx
function WorkspaceLayout (line 4) | function WorkspaceLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/links/[...link]/page-client.tsx
function LinkPageClient (line 47) | function LinkPageClient() {
function LinkBuilder (line 93) | function LinkBuilder({ link }: { link: ExpandedLinkProps }) {
function LoadingSkeleton (line 309) | function LoadingSkeleton() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/links/[...link]/page.tsx
function LinkPage (line 4) | function LinkPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/links/domains/layout.tsx
function DomainsLayout (line 6) | function DomainsLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/links/folders/[folderId]/members/page.tsx
function FolderMembersPage (line 5) | async function FolderMembersPage(props: {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/links/folders/page-client.tsx
function FoldersPageControls (line 87) | function FoldersPageControls() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/links/folders/page.tsx
function FoldersPage (line 5) | async function FoldersPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/links/page-client.tsx
function WorkspaceLinksClient (line 42) | function WorkspaceLinksClient() {
function WorkspaceLinksPageControls (line 70) | function WorkspaceLinksPageControls() {
function WorkspaceLinks (line 83) | function WorkspaceLinks() {
function ImportOption (line 400) | function ImportOption({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/links/page.tsx
function WorkspaceLinks (line 3) | function WorkspaceLinks() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/links/tags/page-client.tsx
function WorkspaceTagsClient (line 28) | function WorkspaceTagsClient() {
function TagsPageControls (line 105) | function TagsPageControls() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/links/tags/page.tsx
function TagsPage (line 6) | function TagsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/links/tags/tag-card-placeholder.tsx
function TagCardPlaceholder (line 3) | function TagCardPlaceholder() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/links/tags/tag-card.tsx
function TagCard (line 32) | function TagCard({
function TagCardKeyboardShortcuts (line 224) | function TagCardKeyboardShortcuts({
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/links/utm/page-client.tsx
function WorkspaceUtmTemplatesClient (line 22) | function WorkspaceUtmTemplatesClient() {
function UTMPageControls (line 81) | function UTMPageControls() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/links/utm/page.tsx
function WorkspaceUtmTemplates (line 6) | function WorkspaceUtmTemplates() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/links/utm/template-card-placeholder.tsx
function TemplateCardPlaceholder (line 3) | function TemplateCardPlaceholder() {
FILE: apps/web/app/app.dub.co/(dashboard)/[slug]/links/utm/template-card.tsx
function TemplateCard (line 24) | function TemplateCard({
function TemplateCardKeyboardShortcuts (line 195) | function TemplateCardKeyboardShortcuts({
function UserTemplateAvatar (line 209) | function UserTemplateAvatar({
FILE: apps/web/app/app.dub.co/(dashboard)/account/settings/page-client.tsx
function SettingsPageClient (line 14) | function SettingsPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/account/settings/page.tsx
function SettingsPage (line 4) | function SettingsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/account/settings/referrals/page-client.tsx
function ReferralsPageClient (line 11) | function ReferralsPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/account/settings/referrals/page.tsx
function ReferralsPage (line 3) | function ReferralsPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/account/settings/security/page-client.tsx
function SecurityPageClient (line 9) | function SecurityPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/account/settings/security/page.tsx
function SecurityPage (line 5) | async function SecurityPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/account/settings/tokens/page-client.tsx
function TokensPageClient (line 12) | function TokensPageClient() {
FILE: apps/web/app/app.dub.co/(dashboard)/account/settings/tokens/page.tsx
function TokensPage (line 5) | function TokensPage() {
FILE: apps/web/app/app.dub.co/(dashboard)/layout.tsx
function Layout (line 14) | async function Layout({ children }: { children: ReactNode }) {
FILE: apps/web/app/app.dub.co/(deeplink)/deeplink/[domain]/[[...key]]/action-buttons.tsx
function DeepLinkActionButtons (line 8) | function DeepLinkActionButtons({
FILE: apps/web/app/app.dub.co/(deeplink)/deeplink/[domain]/[[...key]]/brand-logo-badge.tsx
function BrandLogoBadge (line 7) | function BrandLogoBadge({
FILE: apps/web/app/app.dub.co/(deeplink)/deeplink/[domain]/[[...key]]/page.tsx
function DeepLinkPreviewPage (line 17) | async function DeepLinkPreviewPage(props: {
FILE: apps/web/app/app.dub.co/(deeplink)/deeplink/[domain]/[[...key]]/translations.ts
type Language (line 37) | type Language = keyof typeof translations;
function getLanguage (line 39) | function getLanguage(acceptLanguage?: string | null): Language {
function getTranslations (line 61) | function getTranslations(language: Language) {
FILE: apps/web/app/app.dub.co/(invites)/[slug]/invite/accept-invite-button.tsx
function AcceptInviteButton (line 10) | function AcceptInviteButton() {
FILE: apps/web/app/app.dub.co/(invites)/[slug]/invite/close-invite-button.tsx
function CloseInviteButton (line 5) | function CloseInviteButton({
FILE: apps/web/app/app.dub.co/(invites)/[slug]/invite/page.tsx
constant MAX_TEAM_DISPLAY (line 23) | const MAX_TEAM_DISPLAY = 4;
function WorkspaceInvitePage (line 25) | async function WorkspaceInvitePage({
function Hero (line 291) | function Hero({
FILE: apps/web/app/app.dub.co/(invites)/layout.tsx
function InvitesLayout (line 3) | function InvitesLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/app.dub.co/(onboarding)/[slug]/wrapped/[year]/client.tsx
function WrappedPageClient (line 13) | function WrappedPageClient() {
FILE: apps/web/app/app.dub.co/(onboarding)/[slug]/wrapped/[year]/page.tsx
function WrappedPage (line 6) | async function WrappedPage(props: {
FILE: apps/web/app/app.dub.co/(onboarding)/[slug]/wrapped/page.tsx
function WrappedParentPage (line 3) | async function WrappedParentPage(props: {
FILE: apps/web/app/app.dub.co/(onboarding)/layout.tsx
function Layout (line 5) | function Layout({ children }: PropsWithChildren) {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/domain/custom/form.tsx
function Form (line 8) | function Form() {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/domain/custom/page.tsx
function Custom (line 4) | function Custom() {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/domain/default-domain-selector.tsx
function DefaultDomainSelector (line 12) | function DefaultDomainSelector() {
function DomainOption (line 64) | function DomainOption({
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/domain/page.tsx
function Domain (line 4) | function Domain() {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/domain/register/form.tsx
function Form (line 8) | function Form() {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/domain/register/page.tsx
function Register (line 8) | function Register() {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/layout.tsx
function Layout (line 6) | function Layout({ children }: PropsWithChildren) {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/plan/enterprise-link.tsx
function EnterpriseLink (line 6) | function EnterpriseLink() {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/plan/free-plan-button.tsx
function FreePlanButton (line 8) | function FreePlanButton({
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/plan/page.tsx
function Plan (line 12) | function Plan() {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/plan/plan-selector.tsx
function PlanSelector (line 29) | function PlanSelector({ product }: { product: OnboardingProduct }) {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/products/page.tsx
function Products (line 4) | function Products() {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/products/product-selector.tsx
function ProductSelector (line 28) | function ProductSelector() {
function ProductOption (line 58) | function ProductOption({
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/program/form.tsx
function Form (line 14) | function Form() {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/program/page-client.tsx
function ProgramPageClient (line 9) | function ProgramPageClient({ domain }: { domain: string }) {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/program/page.tsx
function ProgramPage (line 7) | async function ProgramPage({
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/program/reward/form.tsx
constant DEFAULT_REWARD_TYPES (line 17) | const DEFAULT_REWARD_TYPES = [
constant PAYOUT_MODELS (line 32) | const PAYOUT_MODELS = [
function Form (line 47) | function Form() {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/program/reward/page.tsx
function ProgramReward (line 9) | function ProgramReward() {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/program/use-onboarding-program.tsx
function useOnboardingProgram (line 5) | function useOnboardingProgram({ domain }: { domain?: string } = {}) {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/step-page.tsx
function StepPage (line 6) | function StepPage({
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/success/page-client.tsx
function SuccessPageClient (line 31) | function SuccessPageClient({
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/success/page.tsx
function SuccessPage (line 6) | async function SuccessPage({
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/workspace/form.tsx
function Form (line 6) | function Form() {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/workspace/page.tsx
function Workspace (line 4) | function Workspace() {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/later-button.tsx
function LaterButton (line 9) | function LaterButton({
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/next-button.tsx
function NextButton (line 7) | function NextButton({
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/use-onboarding-product.ts
constant ONBOARDING_PRODUCTS (line 6) | const ONBOARDING_PRODUCTS = ["links", "partners"] as const;
type OnboardingProduct (line 7) | type OnboardingProduct = (typeof ONBOARDING_PRODUCTS)[number];
function useOnboardingProduct (line 9) | function useOnboardingProduct(): OnboardingProduct {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/use-onboarding-progress.ts
constant PRE_WORKSPACE_STEPS (line 10) | const PRE_WORKSPACE_STEPS = ["workspace"];
function useOnboardingProgress (line 12) | function useOnboardingProgress() {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/welcome/page.tsx
function Welcome (line 7) | function Welcome() {
function Gradient (line 35) | function Gradient({ className }: { className?: string }) {
FILE: apps/web/app/app.dub.co/(onboarding)/onboarding/welcome/track-signup.tsx
function TrackSignup (line 7) | function TrackSignup() {
FILE: apps/web/app/app.dub.co/(onboarding)/signed-in-hint.tsx
function SignedInHint (line 7) | function SignedInHint() {
FILE: apps/web/app/app.dub.co/(redirects)/[slug]/domains/page.tsx
function OldWorkspaceDomains (line 3) | async function OldWorkspaceDomains(props: {
FILE: apps/web/app/app.dub.co/(redirects)/[slug]/settings/referrals/page.tsx
function OldWorkspaceReferrals (line 3) | function OldWorkspaceReferrals() {
FILE: apps/web/app/app.dub.co/(redirects)/[slug]/settings/tags/page.tsx
function OldWorkspaceTags (line 3) | async function OldWorkspaceTags(props: {
FILE: apps/web/app/app.dub.co/(redirects)/analytics/page.tsx
function OldLinksAnalytics (line 4) | async function OldLinksAnalytics(props: {
FILE: apps/web/app/app.dub.co/(redirects)/loading.tsx
function Loading (line 3) | function Loading() {
FILE: apps/web/app/app.dub.co/(share)/share/[dashboardId]/action.ts
function verifyPassword (line 6) | async function verifyPassword(_prevState: any, data: FormData) {
FILE: apps/web/app/app.dub.co/(share)/share/[dashboardId]/form.tsx
function DashboardPasswordForm (line 14) | function DashboardPasswordForm() {
FILE: apps/web/app/app.dub.co/(share)/share/[dashboardId]/page.tsx
function generateMetadata (line 13) | async function generateMetadata(props: {
function DashboardPage (line 31) | async function DashboardPage(props: {
FILE: apps/web/app/app.dub.co/embed/support-chat/dynamic-height-messenger.tsx
function SupportChatDynamicHeightMessenger (line 5) | function SupportChatDynamicHeightMessenger() {
FILE: apps/web/app/app.dub.co/embed/support-chat/layout.tsx
function SupportChatEmbedLayout (line 1) | function SupportChatEmbedLayout({
FILE: apps/web/app/app.dub.co/embed/support-chat/page.tsx
function SupportChatEmbedPage (line 6) | async function SupportChatEmbedPage(props: {
FILE: apps/web/app/app.dub.co/layout.tsx
function AppLayout (line 7) | function AppLayout({ children }: { children: ReactNode }) {
FILE: apps/web/app/banned/page.tsx
constant UTM_PARAMS (line 17) | const UTM_PARAMS = {
function BannedPage (line 22) | async function BannedPage(props: {
FILE: apps/web/app/cloaked/[url]/page.tsx
function generateMetadata (line 11) | async function generateMetadata(props: {
function CloakedPage (line 30) | async function CloakedPage(props: {
FILE: apps/web/app/custom-uri-scheme/[url]/page.tsx
function CustomURISchemePage (line 3) | async function CustomURISchemePage(props: {
FILE: apps/web/app/expired/[domain]/page.tsx
constant UTM_PARAMS (line 20) | const UTM_PARAMS = {
function ExpiredLinkPage (line 25) | async function ExpiredLinkPage(props: {
FILE: apps/web/app/inspect/[domain]/[key]/card.tsx
function LinkInspectorCard (line 6) | function LinkInspectorCard({
FILE: apps/web/app/inspect/[domain]/[key]/page.tsx
function generateMetadata (line 22) | async function generateMetadata(props: {
function InspectPage (line 46) | async function InspectPage(props: {
FILE: apps/web/app/layout.tsx
function RootLayout (line 9) | function RootLayout({
FILE: apps/web/app/manifest.ts
function manifest (line 3) | function manifest(): MetadataRoute.Manifest {
FILE: apps/web/app/not-found-hint.tsx
function NotFoundHint (line 8) | function NotFoundHint() {
function NotFoundHintChild (line 16) | function NotFoundHintChild() {
FILE: apps/web/app/not-found.tsx
function NotFound (line 6) | function NotFound() {
FILE: apps/web/app/password/[linkId]/action.ts
function verifyPassword (line 6) | async function verifyPassword(_prevState: any, data: FormData) {
FILE: apps/web/app/password/[linkId]/form.tsx
function Password
Copy disabled (too large)
Download .json
Condensed preview — 3991 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (13,658K chars).
[
{
"path": ".github/workflows/apply-issue-labels-to-pr.yml",
"chars": 2196,
"preview": "name: \"Apply issue labels to PR\"\n\non:\n pull_request_target:\n types:\n - opened\n\njobs:\n label_on_pr:\n runs-on"
},
{
"path": ".github/workflows/deploy-embed-script.yml",
"chars": 891,
"preview": "name: \"Deploy embed script\"\n\non:\n push:\n branches:\n - main\n paths:\n - \"packages/embeds/core/**\"\n workf"
},
{
"path": ".github/workflows/e2e.yaml",
"chars": 1274,
"preview": "name: Public API Tests\n\non:\n deployment_status:\n\njobs:\n api-tests:\n timeout-minutes: 30\n if: github.event_name ="
},
{
"path": ".github/workflows/playwright.yaml",
"chars": 4288,
"preview": "name: Playwright E2E Tests\n\non:\n pull_request:\n branches: [main]\n paths:\n - \"apps/web/**\"\n - \"packages/"
},
{
"path": ".github/workflows/prettier.yaml",
"chars": 503,
"preview": "name: Prettier Check\n\non:\n push:\n branches:\n - main\n pull_request:\n branches:\n - main\n workflow_dispa"
},
{
"path": ".gitignore",
"chars": 557,
"preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\nnode_modules\ndist/"
},
{
"path": ".prettierignore",
"chars": 45,
"preview": "node_modules\npnpm-lock.yaml\n.next\n.turbo\ndist"
},
{
"path": "LICENSE.md",
"chars": 35090,
"preview": "Copyright (c) 2024-present Dub Technologies, Inc.\n\nPortions of this software – namely all files that reside under the fo"
},
{
"path": "README.md",
"chars": 4881,
"preview": "<a href=\"https://dub.co\">\n <img alt=\"Dub is the modern, open-source link attribution platform for short links, conversi"
},
{
"path": "SECURITY.md",
"chars": 359,
"preview": "# Security Policy\n\n## Supported Versions\n\nAll versions of Dub are currently being supported with security updates.\n\n## R"
},
{
"path": "apps/web/app/(ee)/LICENSE.md",
"chars": 2765,
"preview": "The Dub.co Commercial License (the “Commercial License”)\nCopyright (c) 2024-present Dub Technologies, Inc\n\nWith regard t"
},
{
"path": "apps/web/app/(ee)/README.md",
"chars": 1099,
"preview": "<!-- PROJECT LOGO -->\n<div align=\"center\">\n <a href=\"https://dub.co/enterprise\">\n <img src=\"https://github.com/user-"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(auth)/layout.tsx",
"chars": 298,
"preview": "import { Background } from \"@dub/ui\";\n\nexport default function AdminAuthLayout({\n children,\n}: {\n children: React.Reac"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(auth)/login/page.tsx",
"chars": 68,
"preview": "export { default } from \"../../../../app.dub.co/(auth)/login/page\";\n"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/analytics/page.tsx",
"chars": 325,
"preview": "import Analytics from \"@/ui/analytics\";\nimport LayoutLoader from \"@/ui/layout/layout-loader\";\nimport { Suspense } from \""
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/commissions/client.tsx",
"chars": 12165,
"preview": "\"use client\";\n\nimport { formatDateTooltip } from \"@/lib/analytics/format-date-tooltip\";\nimport { AnalyticsLoadingSpinner"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/commissions/page.tsx",
"chars": 212,
"preview": "import { Suspense } from \"react\";\nimport CommissionsPageClient from \"./client\";\n\nexport default async function Commissio"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/components/ban-link.tsx",
"chars": 2551,
"preview": "\"use client\";\n\nimport { LoadingSpinner } from \"@dub/ui\";\nimport { cn } from \"@dub/utils\";\nimport { useState } from \"reac"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/components/delete-partner-account.tsx",
"chars": 3357,
"preview": "\"use client\";\n\nimport { LoadingSpinner } from \"@dub/ui\";\nimport { cn } from \"@dub/utils\";\nimport { useFormStatus } from "
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/components/impersonate-user.tsx",
"chars": 3097,
"preview": "\"use client\";\n\nimport { Button, LoadingSpinner } from \"@dub/ui\";\nimport { cn } from \"@dub/utils\";\nimport { useState } fr"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/components/impersonate-workspace.tsx",
"chars": 1901,
"preview": "\"use client\";\n\nimport { LoadingSpinner } from \"@dub/ui\";\nimport { cn } from \"@dub/utils\";\nimport { useState } from \"reac"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/components/refresh-domain.tsx",
"chars": 1557,
"preview": "\"use client\";\n\nimport { LoadingSpinner } from \"@dub/ui\";\nimport { cn } from \"@dub/utils\";\nimport { useFormStatus } from "
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/components/reset-login-attempts.tsx",
"chars": 1578,
"preview": "\"use client\";\n\nimport { LoadingSpinner } from \"@dub/ui\";\nimport { cn } from \"@dub/utils\";\nimport { useFormStatus } from "
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/components/user-info.tsx",
"chars": 6276,
"preview": "\"use client\";\nimport { PartnerStatusBadges } from \"@/ui/partners/partner-status-badges\";\nimport { Badge, Copy, StatusBad"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/events/page.tsx",
"chars": 546,
"preview": "import Events from \"@/ui/analytics/events\";\nimport { EventsProvider } from \"@/ui/analytics/events/events-provider\";\nimpo"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/layout-nav-client.tsx",
"chars": 3553,
"preview": "\"use client\";\n\nimport {\n ClientOnly,\n MaxWidthWrapper,\n NavWordmark,\n Popover,\n useMediaQuery,\n} from \"@dub/ui\";\nim"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/layout.tsx",
"chars": 416,
"preview": "import { constructMetadata } from \"@dub/utils\";\nimport { ReactNode } from \"react\";\nimport { AdminNav } from \"./layout-na"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/links/page.tsx",
"chars": 234,
"preview": "import AdminLinksClient from \"app/app.dub.co/(dashboard)/[slug]/links/page-client\";\nimport { Suspense } from \"react\";\n\ne"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/page.tsx",
"chars": 2728,
"preview": "import { constructMetadata } from \"@dub/utils\";\nimport { BanLink } from \"./components/ban-link\";\nimport { DeletePartnerA"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/payouts/client.tsx",
"chars": 14036,
"preview": "\"use client\";\n\nimport { formatDateTooltip } from \"@/lib/analytics/format-date-tooltip\";\nimport { AnalyticsLoadingSpinner"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/payouts/page.tsx",
"chars": 200,
"preview": "import { Suspense } from \"react\";\nimport PayoutsPageClient from \"./client\";\n\nexport default async function PayoutsPage()"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/payouts/paypal/client.tsx",
"chars": 7555,
"preview": "\"use client\";\n\nimport type { PaypalPayoutResponse } from \"@/lib/paypal/get-pending-payouts\";\nimport { PartnerAvatar } fr"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/payouts/paypal/page.tsx",
"chars": 218,
"preview": "import { Suspense } from \"react\";\nimport PaypalPayoutsPageClient from \"./client\";\n\nexport default async function PaypalP"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/revenue/client.tsx",
"chars": 5443,
"preview": "\"use client\";\n\nimport SimpleDateRangePicker from \"@/ui/shared/simple-date-range-picker\";\nimport {\n CrownSmall,\n Table,"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/(dashboard)/revenue/page.tsx",
"chars": 200,
"preview": "import { Suspense } from \"react\";\nimport RevenuePageClient from \"./client\";\n\nexport default async function RevenuePage()"
},
{
"path": "apps/web/app/(ee)/admin.dub.co/layout.tsx",
"chars": 237,
"preview": "\"use client\";\n\nimport { SessionProvider } from \"next-auth/react\";\nimport { ReactNode } from \"react\";\n\nexport default fun"
},
{
"path": "apps/web/app/(ee)/api/admin/analytics/route.ts",
"chars": 482,
"preview": "import { getAnalytics } from \"@/lib/analytics/get-analytics\";\nimport { withAdmin } from \"@/lib/auth\";\nimport { parseAnal"
},
{
"path": "apps/web/app/(ee)/api/admin/ban/route.ts",
"chars": 1604,
"preview": "import { deleteWorkspaceAdmin } from \"@/lib/api/workspaces/delete-workspace\";\nimport { withAdmin } from \"@/lib/auth\";\nim"
},
{
"path": "apps/web/app/(ee)/api/admin/commissions/get-commissions-timeseries.ts",
"chars": 1980,
"preview": "import { sqlGranularityMap } from \"@/lib/planetscale/granularity\";\nimport { TZDate } from \"@date-fns/tz\";\nimport { prism"
},
{
"path": "apps/web/app/(ee)/api/admin/commissions/get-top-program-by-commissions.ts",
"chars": 1527,
"preview": "import { prisma } from \"@dub/prisma\";\nimport { ACME_PROGRAM_ID } from \"@dub/utils\";\n\nexport async function getTopProgram"
},
{
"path": "apps/web/app/(ee)/api/admin/commissions/route.ts",
"chars": 1531,
"preview": "import { getStartEndDates } from \"@/lib/analytics/utils/get-start-end-dates\";\nimport { withAdmin } from \"@/lib/auth\";\nim"
},
{
"path": "apps/web/app/(ee)/api/admin/delete-partner-account/route.ts",
"chars": 3683,
"preview": "import { withAdmin } from \"@/lib/auth\";\nimport { conn } from \"@/lib/planetscale\";\nimport { stripe } from \"@/lib/stripe\";"
},
{
"path": "apps/web/app/(ee)/api/admin/events/route.ts",
"chars": 469,
"preview": "import { getEvents } from \"@/lib/analytics/get-events\";\nimport { withAdmin } from \"@/lib/auth\";\nimport { eventsQuerySche"
},
{
"path": "apps/web/app/(ee)/api/admin/impersonate/route.ts",
"chars": 3154,
"preview": "import { hashToken, withAdmin } from \"@/lib/auth\";\nimport { prisma } from \"@dub/prisma\";\nimport { APP_DOMAIN, PARTNERS_D"
},
{
"path": "apps/web/app/(ee)/api/admin/links/[linkId]/route.ts",
"chars": 553,
"preview": "import { transformLink } from \"@/lib/api/links\";\nimport { withAdmin } from \"@/lib/auth\";\nimport { prisma } from \"@dub/pr"
},
{
"path": "apps/web/app/(ee)/api/admin/links/ban/route.ts",
"chars": 1226,
"preview": "import { linkCache } from \"@/lib/api/links/cache\";\nimport { withAdmin } from \"@/lib/auth\";\nimport { updateConfig } from "
},
{
"path": "apps/web/app/(ee)/api/admin/links/count/route.ts",
"chars": 1878,
"preview": "import { withAdmin } from \"@/lib/auth\";\nimport { prisma } from \"@dub/prisma\";\nimport { DUB_DOMAINS_ARRAY, LEGAL_USER_ID "
},
{
"path": "apps/web/app/(ee)/api/admin/links/route.ts",
"chars": 1834,
"preview": "import { transformLink } from \"@/lib/api/links\";\nimport { withAdmin } from \"@/lib/auth\";\nimport { prisma } from \"@dub/pr"
},
{
"path": "apps/web/app/(ee)/api/admin/payouts/paypal/route.ts",
"chars": 424,
"preview": "import { withAdmin } from \"@/lib/auth/admin\";\nimport { getPendingPaypalPayouts } from \"@/lib/paypal/get-pending-payouts\""
},
{
"path": "apps/web/app/(ee)/api/admin/payouts/route.ts",
"chars": 4140,
"preview": "import { getStartEndDates } from \"@/lib/analytics/utils/get-start-end-dates\";\nimport { withAdmin } from \"@/lib/auth\";\nim"
},
{
"path": "apps/web/app/(ee)/api/admin/refresh-domain/route.ts",
"chars": 735,
"preview": "import { addDomainToVercel } from \"@/lib/api/domains/add-domain-vercel\";\nimport { withAdmin } from \"@/lib/auth\";\nimport "
},
{
"path": "apps/web/app/(ee)/api/admin/reset-login-attempts/route.ts",
"chars": 979,
"preview": "import { withAdmin } from \"@/lib/auth\";\nimport { prisma } from \"@dub/prisma\";\nimport { NextResponse } from \"next/server\""
},
{
"path": "apps/web/app/(ee)/api/admin/revenue/get-top-programs-by-sales.ts",
"chars": 1554,
"preview": "import { formatUTCDateTimeClickhouse } from \"@/lib/analytics/utils/format-utc-datetime-clickhouse\";\nimport { tb } from \""
},
{
"path": "apps/web/app/(ee)/api/admin/revenue/route.ts",
"chars": 810,
"preview": "import { getStartEndDates } from \"@/lib/analytics/utils/get-start-end-dates\";\nimport { withAdmin } from \"@/lib/auth\";\nim"
},
{
"path": "apps/web/app/(ee)/api/audit-logs/export/route.ts",
"chars": 1690,
"preview": "import { convertToCSV } from \"@/lib/analytics/utils\";\nimport { getAuditLogs } from \"@/lib/api/audit-logs/get-audit-logs\""
},
{
"path": "apps/web/app/(ee)/api/auth/saml/authorize/route.ts",
"chars": 704,
"preview": "import { jackson } from \"@/lib/jackson\";\nimport { getSearchParams } from \"@dub/utils\";\nimport { NextResponse } from \"nex"
},
{
"path": "apps/web/app/(ee)/api/auth/saml/callback/route.ts",
"chars": 664,
"preview": "import { jackson } from \"@/lib/jackson\";\nimport { NextResponse } from \"next/server\";\n\nexport async function POST(req: Re"
},
{
"path": "apps/web/app/(ee)/api/auth/saml/token/route.ts",
"chars": 761,
"preview": "import { jackson } from \"@/lib/jackson\";\nimport * as jose from \"jose\";\nimport { NextResponse } from \"next/server\";\nimpor"
},
{
"path": "apps/web/app/(ee)/api/auth/saml/userinfo/route.ts",
"chars": 461,
"preview": "import { jackson } from \"@/lib/jackson\";\nimport { NextResponse } from \"next/server\";\n\nexport async function GET(req: Req"
},
{
"path": "apps/web/app/(ee)/api/auth/saml/verify/route.tsx",
"chars": 999,
"preview": "import { jackson } from \"@/lib/jackson\";\nimport { prisma } from \"@dub/prisma\";\nimport { NextResponse } from \"next/server"
},
{
"path": "apps/web/app/(ee)/api/bounties/[bountyId]/route.ts",
"chars": 10870,
"preview": "import { recordAuditLog } from \"@/lib/api/audit-logs/record-audit-log\";\nimport { DubApiError } from \"@/lib/api/errors\";\n"
},
{
"path": "apps/web/app/(ee)/api/bounties/[bountyId]/submissions/[submissionId]/approve/route.ts",
"chars": 1421,
"preview": "import { getDefaultProgramIdOrThrow } from \"@/lib/api/programs/get-default-program-id-or-throw\";\nimport { parseRequestBo"
},
{
"path": "apps/web/app/(ee)/api/bounties/[bountyId]/submissions/[submissionId]/reject/route.ts",
"chars": 1462,
"preview": "import { getDefaultProgramIdOrThrow } from \"@/lib/api/programs/get-default-program-id-or-throw\";\nimport { parseRequestBo"
},
{
"path": "apps/web/app/(ee)/api/bounties/[bountyId]/submissions/route.ts",
"chars": 2241,
"preview": "import { getDefaultProgramIdOrThrow } from \"@/lib/api/programs/get-default-program-id-or-throw\";\nimport { withWorkspace "
},
{
"path": "apps/web/app/(ee)/api/bounties/[bountyId]/sync-social-metrics/route.ts",
"chars": 5782,
"preview": "import { DubApiError } from \"@/lib/api/errors\";\nimport { getDefaultProgramIdOrThrow } from \"@/lib/api/programs/get-defau"
},
{
"path": "apps/web/app/(ee)/api/bounties/count/submissions/route.ts",
"chars": 1721,
"preview": "import { getDefaultProgramIdOrThrow } from \"@/lib/api/programs/get-default-program-id-or-throw\";\nimport { withWorkspace "
},
{
"path": "apps/web/app/(ee)/api/bounties/route.ts",
"chars": 9996,
"preview": "import { recordAuditLog } from \"@/lib/api/audit-logs/record-audit-log\";\nimport { createId } from \"@/lib/api/create-id\";\n"
},
{
"path": "apps/web/app/(ee)/api/campaigns/[campaignId]/duplicate/route.ts",
"chars": 2602,
"preview": "import { DEFAULT_CAMPAIGN_BODY } from \"@/lib/api/campaigns/constants\";\nimport { getCampaignOrThrow } from \"@/lib/api/cam"
},
{
"path": "apps/web/app/(ee)/api/campaigns/[campaignId]/events/count/route.ts",
"chars": 1376,
"preview": "import { getCampaignOrThrow } from \"@/lib/api/campaigns/get-campaign-or-throw\";\nimport { getDefaultProgramIdOrThrow } fr"
},
{
"path": "apps/web/app/(ee)/api/campaigns/[campaignId]/events/route.ts",
"chars": 952,
"preview": "import { getCampaignEvents } from \"@/lib/api/campaigns/get-campaign-events\";\nimport { getCampaignOrThrow } from \"@/lib/a"
},
{
"path": "apps/web/app/(ee)/api/campaigns/[campaignId]/preview/route.ts",
"chars": 3441,
"preview": "import { getCampaignOrThrow } from \"@/lib/api/campaigns/get-campaign-or-throw\";\nimport { DubApiError } from \"@/lib/api/e"
},
{
"path": "apps/web/app/(ee)/api/campaigns/[campaignId]/route.ts",
"chars": 6707,
"preview": "import { getCampaignOrThrow } from \"@/lib/api/campaigns/get-campaign-or-throw\";\nimport {\n scheduleMarketingCampaign,\n "
},
{
"path": "apps/web/app/(ee)/api/campaigns/[campaignId]/summary/route.ts",
"chars": 792,
"preview": "import { getCampaignOrThrow } from \"@/lib/api/campaigns/get-campaign-or-throw\";\nimport { getCampaignSummary } from \"@/li"
},
{
"path": "apps/web/app/(ee)/api/campaigns/count/route.ts",
"chars": 2267,
"preview": "import { getDefaultProgramIdOrThrow } from \"@/lib/api/programs/get-default-program-id-or-throw\";\nimport { withWorkspace "
},
{
"path": "apps/web/app/(ee)/api/campaigns/route.ts",
"chars": 3894,
"preview": "import { DEFAULT_CAMPAIGN_BODY } from \"@/lib/api/campaigns/constants\";\nimport { createId } from \"@/lib/api/create-id\";\ni"
},
{
"path": "apps/web/app/(ee)/api/commissions/[commissionId]/route.ts",
"chars": 8460,
"preview": "import { convertCurrency } from \"@/lib/analytics/convert-currency\";\nimport { recordAuditLog } from \"@/lib/api/audit-logs"
},
{
"path": "apps/web/app/(ee)/api/commissions/count/route.ts",
"chars": 899,
"preview": "import { getCommissionsCount } from \"@/lib/api/commissions/get-commissions-count\";\nimport { getDefaultProgramIdOrThrow }"
},
{
"path": "apps/web/app/(ee)/api/commissions/export/route.ts",
"chars": 2214,
"preview": "import { convertToCSV } from \"@/lib/analytics/utils\";\nimport { formatCommissionsForExport } from \"@/lib/api/commissions/"
},
{
"path": "apps/web/app/(ee)/api/commissions/route.ts",
"chars": 1914,
"preview": "import { getCommissions } from \"@/lib/api/commissions/get-commissions\";\nimport { transformCustomerForCommission } from \""
},
{
"path": "apps/web/app/(ee)/api/commissions/timeseries/route.ts",
"chars": 2696,
"preview": "import { getStartEndDates } from \"@/lib/analytics/utils/get-start-end-dates\";\nimport { getDefaultProgramIdOrThrow } from"
},
{
"path": "apps/web/app/(ee)/api/cron/aggregate-clicks/resolve-click-reward-amount.ts",
"chars": 1236,
"preview": "import { serializeReward } from \"@/lib/api/partners/serialize-reward\";\nimport { evaluateRewardConditions } from \"@/lib/p"
},
{
"path": "apps/web/app/(ee)/api/cron/aggregate-clicks/route.ts",
"chars": 7198,
"preview": "import { createId } from \"@/lib/api/create-id\";\nimport { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport "
},
{
"path": "apps/web/app/(ee)/api/cron/bounties/create-draft-submissions/route.ts",
"chars": 6236,
"preview": "import { createId } from \"@/lib/api/create-id\";\nimport { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport "
},
{
"path": "apps/web/app/(ee)/api/cron/bounties/notify-partners/route.ts",
"chars": 6712,
"preview": "import { createId } from \"@/lib/api/create-id\";\nimport { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport "
},
{
"path": "apps/web/app/(ee)/api/cron/bounties/queue-sync-social-metrics/route.ts",
"chars": 1452,
"preview": "import { enqueueBatchJobs } from \"@/lib/cron/enqueue-batch-jobs\";\nimport { withCron } from \"@/lib/cron/with-cron\";\nimpor"
},
{
"path": "apps/web/app/(ee)/api/cron/bounties/sync-social-metrics/route.ts",
"chars": 5213,
"preview": "import { getSocialMetricsUpdates } from \"@/lib/bounty/api/get-social-metrics-updates\";\nimport { resolveBountyDetails } f"
},
{
"path": "apps/web/app/(ee)/api/cron/campaigns/broadcast/route.ts",
"chars": 10214,
"preview": "import { validateCampaignFromAddress } from \"@/lib/api/campaigns/validate-campaign\";\nimport { createId } from \"@/lib/api"
},
{
"path": "apps/web/app/(ee)/api/cron/cleanup/demo-embed-partners/route.ts",
"chars": 2339,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { bulkDeletePartners } from \"@/lib/api/partners/"
},
{
"path": "apps/web/app/(ee)/api/cron/cleanup/e2e-tests/route.ts",
"chars": 4238,
"preview": "import { markDomainAsDeleted } from \"@/lib/api/domains/mark-domain-deleted\";\nimport { handleAndReturnErrorResponse } fro"
},
{
"path": "apps/web/app/(ee)/api/cron/cleanup/expired-tokens/route.ts",
"chars": 1833,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/cleanup/link-retention/route.ts",
"chars": 4031,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { qstash } from \"@/lib/cron\";\nimport { verifyQst"
},
{
"path": "apps/web/app/(ee)/api/cron/cleanup/rejected-applications/route.ts",
"chars": 2014,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/cleanup/unenrolled-partners/route.ts",
"chars": 1818,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { bulkDeletePartners } from \"@/lib/api/partners/"
},
{
"path": "apps/web/app/(ee)/api/cron/discount-codes/create/queue-batches/route.ts",
"chars": 3341,
"preview": "import { CRON_BATCH_SIZE, qstash } from \"@/lib/cron\";\nimport { enqueueBatchJobs } from \"@/lib/cron/enqueue-batch-jobs\";\n"
},
{
"path": "apps/web/app/(ee)/api/cron/discount-codes/create/route.ts",
"chars": 2317,
"preview": "import { createDiscountCode } from \"@/lib/api/discounts/create-discount-code\";\nimport { withCron } from \"@/lib/cron/with"
},
{
"path": "apps/web/app/(ee)/api/cron/discount-codes/delete/route.ts",
"chars": 1118,
"preview": "import { withCron } from \"@/lib/cron/with-cron\";\nimport { disableStripeDiscountCode } from \"@/lib/stripe/disable-stripe-"
},
{
"path": "apps/web/app/(ee)/api/cron/disposable-emails/route.ts",
"chars": 1440,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/domains/delete/route.ts",
"chars": 3665,
"preview": "import { queueDomainDeletion } from \"@/lib/api/domains/queue-domain-update\";\nimport { handleAndReturnErrorResponse } fro"
},
{
"path": "apps/web/app/(ee)/api/cron/domains/renewal-payments/route.ts",
"chars": 4822,
"preview": "import { createId } from \"@/lib/api/create-id\";\nimport { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport "
},
{
"path": "apps/web/app/(ee)/api/cron/domains/renewal-reminders/route.ts",
"chars": 3648,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyVercelSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/domains/transfer/route.ts",
"chars": 3517,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { linkCache } from \"@/lib/api/links/cache\";\nimpo"
},
{
"path": "apps/web/app/(ee)/api/cron/domains/transfer/utils.ts",
"chars": 1227,
"preview": "import { sendEmail } from \"@dub/email\";\nimport DomainTransferred from \"@dub/email/templates/domain-transferred\";\nimport "
},
{
"path": "apps/web/app/(ee)/api/cron/domains/update/route.ts",
"chars": 3575,
"preview": "import {\n linkDomainUpdateSchema,\n queueDomainUpdate,\n} from \"@/lib/api/domains/queue-domain-update\";\nimport { handleA"
},
{
"path": "apps/web/app/(ee)/api/cron/domains/verify/route.ts",
"chars": 3293,
"preview": "import { getConfigResponse } from \"@/lib/api/domains/get-config-response\";\nimport { getDomainResponse } from \"@/lib/api/"
},
{
"path": "apps/web/app/(ee)/api/cron/domains/verify/utils.ts",
"chars": 5210,
"preview": "import { markDomainAsDeleted } from \"@/lib/api/domains/mark-domain-deleted\";\nimport { sendBatchEmail } from \"@dub/email\""
},
{
"path": "apps/web/app/(ee)/api/cron/email-domains/update/route.ts",
"chars": 1409,
"preview": "import { withCron } from \"@/lib/cron/with-cron\";\nimport { resend } from \"@dub/email/resend/client\";\nimport { prisma } fr"
},
{
"path": "apps/web/app/(ee)/api/cron/email-domains/verify/route.ts",
"chars": 3320,
"preview": "import { getWorkspaceUsers } from \"@/lib/api/get-workspace-users\";\nimport { withCron } from \"@/lib/cron/with-cron\";\nimpo"
},
{
"path": "apps/web/app/(ee)/api/cron/export/commissions/fetch-commissions-batch.ts",
"chars": 748,
"preview": "import { getCommissions } from \"@/lib/api/commissions/get-commissions\";\nimport { getCommissionsQuerySchema } from \"@/lib"
},
{
"path": "apps/web/app/(ee)/api/cron/export/commissions/route.ts",
"chars": 3286,
"preview": "import { convertToCSV } from \"@/lib/analytics/utils/convert-to-csv\";\nimport { formatCommissionsForExport } from \"@/lib/a"
},
{
"path": "apps/web/app/(ee)/api/cron/export/customers/route.ts",
"chars": 2853,
"preview": "import { convertToCSV } from \"@/lib/analytics/utils/convert-to-csv\";\nimport { createDownloadableExport } from \"@/lib/api"
},
{
"path": "apps/web/app/(ee)/api/cron/export/events/fetch-events-batch.ts",
"chars": 551,
"preview": "import { getEvents } from \"@/lib/analytics/get-events\";\nimport { EventsFilters } from \"@/lib/analytics/types\";\n\nexport a"
},
{
"path": "apps/web/app/(ee)/api/cron/export/events/partner/route.ts",
"chars": 6475,
"preview": "import {\n eventsExportColumnAccessors,\n eventsExportColumnNames,\n} from \"@/lib/analytics/events-export-helpers\";\nimpor"
},
{
"path": "apps/web/app/(ee)/api/cron/export/events/workspace/route.ts",
"chars": 3539,
"preview": "import {\n eventsExportColumnAccessors,\n eventsExportColumnNames,\n} from \"@/lib/analytics/events-export-helpers\";\nimpor"
},
{
"path": "apps/web/app/(ee)/api/cron/export/links/fetch-links-batch.ts",
"chars": 566,
"preview": "import {\n getLinksForWorkspace,\n GetLinksForWorkspaceProps,\n} from \"@/lib/api/links/get-links-for-workspace\";\n\nexport "
},
{
"path": "apps/web/app/(ee)/api/cron/export/links/route.ts",
"chars": 4435,
"preview": "import { convertToCSV } from \"@/lib/analytics/utils/convert-to-csv\";\nimport { getStartEndDates } from \"@/lib/analytics/u"
},
{
"path": "apps/web/app/(ee)/api/cron/export/partners/fetch-partners-batch.ts",
"chars": 702,
"preview": "import { getPartners } from \"@/lib/api/partners/get-partners\";\nimport { partnersExportQuerySchema } from \"@/lib/zod/sche"
},
{
"path": "apps/web/app/(ee)/api/cron/export/partners/route.ts",
"chars": 3192,
"preview": "import { convertToCSV } from \"@/lib/analytics/utils/convert-to-csv\";\nimport { createDownloadableExport } from \"@/lib/api"
},
{
"path": "apps/web/app/(ee)/api/cron/folders/delete/route.ts",
"chars": 2391,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { queueFolderDeletion } from \"@/lib/api/folders/"
},
{
"path": "apps/web/app/(ee)/api/cron/framer/backfill-leads-batch/route.ts",
"chars": 11497,
"preview": "import { createId } from \"@/lib/api/create-id\";\nimport { DubApiError, handleAndReturnErrorResponse } from \"@/lib/api/err"
},
{
"path": "apps/web/app/(ee)/api/cron/fraud/summary/route.ts",
"chars": 5059,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { FRAUD_RULES_BY_TYPE } from \"@/lib/api/fraud/co"
},
{
"path": "apps/web/app/(ee)/api/cron/fx-rates/route.ts",
"chars": 1446,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/groups/create-default-links/route.ts",
"chars": 5413,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { bulkCreateLinks } from \"@/lib/api/links\";\nimpo"
},
{
"path": "apps/web/app/(ee)/api/cron/groups/remap-default-links/route.ts",
"chars": 8213,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { bulkCreateLinks } from \"@/lib/api/links\";\nimpo"
},
{
"path": "apps/web/app/(ee)/api/cron/groups/remap-default-links/utils.ts",
"chars": 2217,
"preview": "import { Link, PartnerGroupDefaultLink } from \"@dub/prisma/client\";\nimport { normalizeUrl } from \"@dub/utils\";\n\n// Add a"
},
{
"path": "apps/web/app/(ee)/api/cron/groups/remap-discount-codes/route.ts",
"chars": 4876,
"preview": "import { createDiscountCode } from \"@/lib/api/discounts/create-discount-code\";\nimport { deleteDiscountCodes } from \"@/li"
},
{
"path": "apps/web/app/(ee)/api/cron/groups/sync-utm/route.ts",
"chars": 4192,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { linkCache } from \"@/lib/api/links/cache\";\nimpo"
},
{
"path": "apps/web/app/(ee)/api/cron/groups/update-default-links/route.ts",
"chars": 3983,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { linkCache } from \"@/lib/api/links/cache\";\nimpo"
},
{
"path": "apps/web/app/(ee)/api/cron/import/bitly/fetch-utils.ts",
"chars": 6110,
"preview": "/**\n * Utilities for fetching links from Bitly API\n */\n\nimport { sanitizeBitlyJson } from \"./sanitize-json\";\n\ninterface "
},
{
"path": "apps/web/app/(ee)/api/cron/import/bitly/queue-import.ts",
"chars": 665,
"preview": "import { qstash } from \"@/lib/cron\";\nimport { APP_DOMAIN_WITH_NGROK } from \"@dub/utils\";\n\n// Queue a Bitly import\nexport"
},
{
"path": "apps/web/app/(ee)/api/cron/import/bitly/rate-limit.ts",
"chars": 1173,
"preview": "import { queueBitlyImport } from \"./queue-import\";\n\n/**\n * Check if we're rate limited and handle accordingly\n */\nexport"
},
{
"path": "apps/web/app/(ee)/api/cron/import/bitly/route.ts",
"chars": 3230,
"preview": "import { createId } from \"@/lib/api/create-id\";\nimport { DubApiError, handleAndReturnErrorResponse } from \"@/lib/api/err"
},
{
"path": "apps/web/app/(ee)/api/cron/import/bitly/sanitize-json.ts",
"chars": 1350,
"preview": "export function sanitizeBitlyJson(body: string): string {\n try {\n // if body is already valid JSON, return it\n JS"
},
{
"path": "apps/web/app/(ee)/api/cron/import/bitly/utils.ts",
"chars": 7286,
"preview": "import { bulkCreateLinks } from \"@/lib/api/links\";\nimport { redis } from \"@/lib/upstash\";\nimport { sendEmail } from \"@du"
},
{
"path": "apps/web/app/(ee)/api/cron/import/csv/route.ts",
"chars": 10562,
"preview": "import { createId } from \"@/lib/api/create-id\";\nimport { addDomainToVercel } from \"@/lib/api/domains/add-domain-vercel\";"
},
{
"path": "apps/web/app/(ee)/api/cron/import/csv/utils.ts",
"chars": 2050,
"preview": "import { sendEmail } from \"@dub/email\";\nimport LinksImportErrors from \"@dub/email/templates/links-import-errors\";\nimport"
},
{
"path": "apps/web/app/(ee)/api/cron/import/firstpromoter/route.ts",
"chars": 1582,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/import/partnerstack/route.ts",
"chars": 1703,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/import/rebrandly/route.ts",
"chars": 2520,
"preview": "import { DubApiError, handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/l"
},
{
"path": "apps/web/app/(ee)/api/cron/import/rebrandly/utils.ts",
"chars": 6681,
"preview": "import { createId } from \"@/lib/api/create-id\";\nimport { bulkCreateLinks } from \"@/lib/api/links\";\nimport { qstash } fro"
},
{
"path": "apps/web/app/(ee)/api/cron/import/rewardful/route.ts",
"chars": 1459,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/import/short/route.ts",
"chars": 1664,
"preview": "import { DubApiError, handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/l"
},
{
"path": "apps/web/app/(ee)/api/cron/import/short/utils.ts",
"chars": 5871,
"preview": "import { createId } from \"@/lib/api/create-id\";\nimport { bulkCreateLinks } from \"@/lib/api/links\";\nimport { qstash } fro"
},
{
"path": "apps/web/app/(ee)/api/cron/import/tolt/route.ts",
"chars": 1566,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/invoices/retry-failed/route.ts",
"chars": 2394,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/links/[linkId]/complete-tests/route.ts",
"chars": 1476,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { completeABTests } from \"@/lib/api/links/comple"
},
{
"path": "apps/web/app/(ee)/api/cron/links/delete/route.ts",
"chars": 1049,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { deleteLink } from \"@/lib/api/links\";\nimport { "
},
{
"path": "apps/web/app/(ee)/api/cron/links/invalidate-for-discounts/route.ts",
"chars": 2378,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { linkCache } from \"@/lib/api/links/cache\";\nimpo"
},
{
"path": "apps/web/app/(ee)/api/cron/links/invalidate-for-partners/route.ts",
"chars": 1380,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { linkCache } from \"@/lib/api/links/cache\";\nimpo"
},
{
"path": "apps/web/app/(ee)/api/cron/messages/notify-partner/route.ts",
"chars": 5028,
"preview": "import { createId } from \"@/lib/api/create-id\";\nimport { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport "
},
{
"path": "apps/web/app/(ee)/api/cron/messages/notify-program/route.ts",
"chars": 4879,
"preview": "import { createId } from \"@/lib/api/create-id\";\nimport { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport "
},
{
"path": "apps/web/app/(ee)/api/cron/network/calculate-program-similarities/calculate-category-similarity.ts",
"chars": 1016,
"preview": "import { prisma } from \"@dub/prisma\";\n\n// Calculate category similarity using Jaccard similarity\nexport async function c"
},
{
"path": "apps/web/app/(ee)/api/cron/network/calculate-program-similarities/calculate-partner-similarity.ts",
"chars": 1404,
"preview": "import { prisma } from \"@dub/prisma\";\n\ninterface PartnerSimilarityResult {\n sharedPartnersCount: bigint;\n program1Part"
},
{
"path": "apps/web/app/(ee)/api/cron/network/calculate-program-similarities/calculate-performance-similarity.ts",
"chars": 1532,
"preview": "import { prisma } from \"@dub/prisma\";\n\nconst METRIC_KEYS = [\n \"totalClicks\",\n \"totalLeads\",\n \"totalConversions\",\n \"t"
},
{
"path": "apps/web/app/(ee)/api/cron/network/calculate-program-similarities/route.ts",
"chars": 6563,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { PROGRAM_SIMILARITY_SCORE_THRESHOLD } from \"@/l"
},
{
"path": "apps/web/app/(ee)/api/cron/network/update-partner-discoverability/route.ts",
"chars": 2193,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { EXCLUDED_PROGRAM_IDS } from \"@/lib/constants/p"
},
{
"path": "apps/web/app/(ee)/api/cron/partner-platforms/route.ts",
"chars": 4128,
"preview": "import {\n AccountNotFoundError,\n getSocialProfile,\n} from \"@/lib/api/scrape-creators/get-social-profile\";\nimport { qst"
},
{
"path": "apps/web/app/(ee)/api/cron/partner-platforms/youtube/route.ts",
"chars": 3055,
"preview": "import { withCron } from \"@/lib/cron/with-cron\";\nimport { prisma } from \"@dub/prisma\";\nimport { PlatformType } from \"@du"
},
{
"path": "apps/web/app/(ee)/api/cron/partner-platforms/youtube/youtube-channel-schema.ts",
"chars": 751,
"preview": "import * as z from \"zod/v4\";\n\nexport const youtubeChannelSchema = z.object({\n id: z.string(),\n statistics: z.object({\n"
},
{
"path": "apps/web/app/(ee)/api/cron/partner-program-summary/process/route.ts",
"chars": 9109,
"preview": "import { getAnalytics } from \"@/lib/analytics/get-analytics\";\nimport { qstash } from \"@/lib/cron\";\nimport { withCron } f"
},
{
"path": "apps/web/app/(ee)/api/cron/partner-program-summary/route.ts",
"chars": 1527,
"preview": "import { enqueueBatchJobs } from \"@/lib/cron/enqueue-batch-jobs\";\nimport { withCron } from \"@/lib/cron/with-cron\";\nimpor"
},
{
"path": "apps/web/app/(ee)/api/cron/partners/auto-approve/route.ts",
"chars": 3624,
"preview": "import { getPartnerApplicationRisks } from \"@/lib/api/fraud/get-partner-application-risks\";\nimport { withCron } from \"@/"
},
{
"path": "apps/web/app/(ee)/api/cron/partners/auto-reject/route.ts",
"chars": 3674,
"preview": "import { resolveFraudGroups } from \"@/lib/api/fraud/resolve-fraud-groups\";\nimport { withCron } from \"@/lib/cron/with-cro"
},
{
"path": "apps/web/app/(ee)/api/cron/partners/ban/cancel-commissions.ts",
"chars": 1942,
"preview": "import { prisma } from \"@dub/prisma\";\n\n// Mark the commissions as canceled\nexport async function cancelCommissions({\n p"
},
{
"path": "apps/web/app/(ee)/api/cron/partners/ban/route.ts",
"chars": 4911,
"preview": "import { deleteDiscountCodes } from \"@/lib/api/discounts/delete-discount-code\";\nimport { reportCrossProgramBanToNetwork "
},
{
"path": "apps/web/app/(ee)/api/cron/partners/deactivate/route.ts",
"chars": 2977,
"preview": "import { deleteDiscountCodes } from \"@/lib/api/discounts/delete-discount-code\";\nimport { linkCache } from \"@/lib/api/lin"
},
{
"path": "apps/web/app/(ee)/api/cron/partners/merge-accounts/route.ts",
"chars": 13322,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { resolveFraudGroups } from \"@/lib/api/fraud/res"
},
{
"path": "apps/web/app/(ee)/api/cron/payouts/aggregate-due-commissions/route.ts",
"chars": 9574,
"preview": "import { createId } from \"@/lib/api/create-id\";\nimport { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport "
},
{
"path": "apps/web/app/(ee)/api/cron/payouts/balance-available/route.ts",
"chars": 7522,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { BANK_ACCOUNT_STATUS_DESCRIPTIONS } from \"@/lib"
},
{
"path": "apps/web/app/(ee)/api/cron/payouts/charge-succeeded/queue-external-payouts.ts",
"chars": 3964,
"preview": "import { queueBatchEmail } from \"@/lib/email/queue-batch-email\";\nimport { sendWorkspaceWebhook } from \"@/lib/webhook/pub"
},
{
"path": "apps/web/app/(ee)/api/cron/payouts/charge-succeeded/queue-stripe-payouts.ts",
"chars": 3390,
"preview": "import { qstash } from \"@/lib/cron\";\nimport { prisma } from \"@dub/prisma\";\nimport { Invoice, PartnerPayoutMethod } from "
},
{
"path": "apps/web/app/(ee)/api/cron/payouts/charge-succeeded/route.ts",
"chars": 4211,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { MIN_WITHDRAWAL_AMOUNT_CENTS } from \"@/lib/cons"
},
{
"path": "apps/web/app/(ee)/api/cron/payouts/charge-succeeded/send-paypal-payouts.ts",
"chars": 2008,
"preview": "import { queueBatchEmail } from \"@/lib/email/queue-batch-email\";\nimport { createPayPalBatchPayout } from \"@/lib/paypal/c"
},
{
"path": "apps/web/app/(ee)/api/cron/payouts/charge-succeeded/utils.ts",
"chars": 2581,
"preview": "import { qstash } from \"@/lib/cron\";\nimport { stripe } from \"@/lib/stripe\";\nimport { APP_DOMAIN_WITH_NGROK } from \"@dub/"
},
{
"path": "apps/web/app/(ee)/api/cron/payouts/force-withdrawals/route.ts",
"chars": 4143,
"preview": "import { forceWithdrawal } from \"@/lib/actions/partners/force-withdrawal\";\nimport { handleAndReturnErrorResponse } from "
},
{
"path": "apps/web/app/(ee)/api/cron/payouts/payout-failed/route.ts",
"chars": 2673,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/payouts/payout-paid/route.ts",
"chars": 2657,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/payouts/process/process-payouts.ts",
"chars": 9169,
"preview": "import { getPayoutEligibilityFilter } from \"@/lib/api/payouts/payout-eligibility-filter\";\nimport { FAST_ACH_FEE_CENTS, F"
},
{
"path": "apps/web/app/(ee)/api/cron/payouts/process/route.ts",
"chars": 3079,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/payouts/process/split-payouts.ts",
"chars": 3468,
"preview": "import { createId } from \"@/lib/api/create-id\";\nimport { getPayoutEligibilityFilter } from \"@/lib/api/payouts/payout-eli"
},
{
"path": "apps/web/app/(ee)/api/cron/payouts/process/updates/route.ts",
"chars": 4553,
"preview": "import { recordAuditLog } from \"@/lib/api/audit-logs/record-audit-log\";\nimport { handleAndReturnErrorResponse } from \"@/"
},
{
"path": "apps/web/app/(ee)/api/cron/payouts/reminders/partners/route.ts",
"chars": 6460,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { MIN_PAYOUT_AMOUNT_FOR_REMINDERS } from \"@/lib/"
},
{
"path": "apps/web/app/(ee)/api/cron/payouts/reminders/program-owners/route.ts",
"chars": 6148,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { INVOICE_MIN_PAYOUT_AMOUNT_CENTS } from \"@/lib/"
},
{
"path": "apps/web/app/(ee)/api/cron/payouts/send-stripe-payout/route.ts",
"chars": 2127,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/pending-applications-summary/route.ts",
"chars": 7259,
"preview": "import { qstash } from \"@/lib/cron\";\nimport { withCron } from \"@/lib/cron/with-cron\";\nimport { sendBatchEmail } from \"@d"
},
{
"path": "apps/web/app/(ee)/api/cron/program-application-reminder/route.ts",
"chars": 3196,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { qstash } from \"@/lib/cron\";\nimport { verifyQst"
},
{
"path": "apps/web/app/(ee)/api/cron/programs/deactivate/route.ts",
"chars": 2442,
"preview": "import { bulkDeactivatePartners } from \"@/lib/api/partners/bulk-deactivate-partners\";\nimport { CRON_BATCH_SIZE, qstash }"
},
{
"path": "apps/web/app/(ee)/api/cron/send-batch-email/route.ts",
"chars": 5546,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/shopify/order-paid/route.ts",
"chars": 1943,
"preview": "import { DubApiError, handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/l"
},
{
"path": "apps/web/app/(ee)/api/cron/streams/update-partner-stats/route.ts",
"chars": 12335,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyVercelSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/streams/update-workspace-clicks/route.ts",
"chars": 6528,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyVercelSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/trigger-withdrawal/route.ts",
"chars": 2590,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyVercelSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/usage/route.ts",
"chars": 1052,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/usage/utils.ts",
"chars": 6919,
"preview": "import { getAnalytics } from \"@/lib/analytics/get-analytics\";\nimport { qstash } from \"@/lib/cron\";\nimport { sendLimitEma"
},
{
"path": "apps/web/app/(ee)/api/cron/utils.ts",
"chars": 255,
"preview": "export function logAndRespond(\n message: string,\n {\n status = 200,\n logLevel = \"info\",\n }: {\n status?: numbe"
},
{
"path": "apps/web/app/(ee)/api/cron/welcome-user/route.ts",
"chars": 3188,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { verifyQstashSignature } from \"@/lib/cron/verif"
},
{
"path": "apps/web/app/(ee)/api/cron/workflows/[workflowId]/route.ts",
"chars": 1688,
"preview": "import { handleAndReturnErrorResponse } from \"@/lib/api/errors\";\nimport { executeSendCampaignWorkflow } from \"@/lib/api/"
},
{
"path": "apps/web/app/(ee)/api/cron/workspaces/delete/delete-workspace-customers.ts",
"chars": 1501,
"preview": "import { isStored, storage } from \"@/lib/storage\";\nimport { prisma } from \"@dub/prisma\";\nimport { R2_URL } from \"@dub/ut"
},
{
"path": "apps/web/app/(ee)/api/cron/workspaces/delete/delete-workspace-domains.ts",
"chars": 1613,
"preview": "import { removeDomainFromVercel } from \"@/lib/api/domains/remove-domain-vercel\";\nimport { prisma } from \"@dub/prisma\";\ni"
},
{
"path": "apps/web/app/(ee)/api/cron/workspaces/delete/delete-workspace-folders.ts",
"chars": 1069,
"preview": "import { prisma } from \"@dub/prisma\";\nimport {\n DeleteWorkspacePayload,\n enqueueNextWorkspaceDeleteStep,\n} from \"./uti"
},
{
"path": "apps/web/app/(ee)/api/cron/workspaces/delete/delete-workspace-links.ts",
"chars": 1143,
"preview": "import { bulkDeleteLinks } from \"@/lib/api/links/bulk-delete-links\";\nimport { prisma } from \"@dub/prisma\";\nimport {\n De"
}
]
// ... and 3791 more files (download for full content)
About this extraction
This page contains the full source code of the dubinc/dub GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 3991 files (12.1 MB), approximately 3.4M tokens, and a symbol index with 5941 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.