├── apps ├── webapp │ ├── .gitignore │ ├── postcss.config.mjs │ ├── src │ │ ├── styles │ │ │ └── app.css │ │ ├── app │ │ │ ├── (authenticated) │ │ │ │ ├── (core) │ │ │ │ │ ├── page.tsx │ │ │ │ │ ├── programs │ │ │ │ │ │ └── [id] │ │ │ │ │ │ │ └── layout.tsx │ │ │ │ │ ├── rewards │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── activity │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── participants │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── analytics │ │ │ │ │ │ └── page.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── settings │ │ │ │ │ ├── organization │ │ │ │ │ │ ├── general │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── api-keys │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ └── members │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── product │ │ │ │ │ │ ├── secrets │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ └── general │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── account │ │ │ │ │ │ └── profile │ │ │ │ │ │ └── page.tsx │ │ │ │ └── onboarding │ │ │ │ │ └── layout.tsx │ │ │ ├── api │ │ │ │ ├── auth │ │ │ │ │ └── [...all] │ │ │ │ │ │ └── route.ts │ │ │ │ └── trpc │ │ │ │ │ └── [trpc] │ │ │ │ │ └── route.ts │ │ │ ├── auth │ │ │ │ └── layout.tsx │ │ │ └── accept-invitation │ │ │ │ └── [token] │ │ │ │ └── page.tsx │ │ ├── lib │ │ │ ├── utils.ts │ │ │ ├── logger.ts │ │ │ ├── hooks │ │ │ │ └── use-debounce.ts │ │ │ ├── auth.ts │ │ │ ├── forms │ │ │ │ └── notification-config-schema.ts │ │ │ ├── auth-client.ts │ │ │ └── date-utils.ts │ │ ├── server │ │ │ ├── db.ts │ │ │ └── api │ │ │ │ └── routers │ │ │ │ ├── post.ts │ │ │ │ ├── product-secrets.ts │ │ │ │ └── referral.ts │ │ ├── hooks │ │ │ └── use-mobile.ts │ │ ├── trpc │ │ │ ├── query-client.ts │ │ │ └── server.ts │ │ └── components │ │ │ ├── date-display.tsx │ │ │ ├── providers │ │ │ ├── auth-ui-provider.tsx │ │ │ └── posthog-provider.tsx │ │ │ ├── site-header.tsx │ │ │ ├── program-setup-card.tsx │ │ │ ├── referral-widget-init.tsx │ │ │ ├── nav-secondary.tsx │ │ │ ├── preview-pane.tsx │ │ │ └── referral-widget-preview.tsx │ ├── eslint.config.mjs │ ├── vitest.config.ts │ ├── components.json │ ├── tsconfig.json │ ├── instrumentation-client.ts │ └── next.config.ts ├── refer │ ├── .gitignore │ ├── vitest.config.ts │ ├── tsconfig.json │ ├── .env.example │ ├── src │ │ ├── index.ts │ │ └── routes │ │ │ └── health.ts │ ├── test │ │ ├── utils │ │ │ └── testServer.ts │ │ └── setup.ts │ └── package.json ├── www │ ├── content │ │ └── docs │ │ │ ├── meta.json │ │ │ ├── api │ │ │ ├── index.mdx │ │ │ ├── meta.json │ │ │ ├── get-programs.mdx │ │ │ ├── get-participants.mdx │ │ │ ├── get-program-by-id.mdx │ │ │ └── get-participant-by-id.mdx │ │ │ └── platform │ │ │ ├── contributing.mdx │ │ │ ├── paddle.mdx │ │ │ ├── index.mdx │ │ │ ├── fraud-prevention.mdx │ │ │ ├── projects.mdx │ │ │ ├── newsletter.mdx │ │ │ ├── meta.json │ │ │ ├── sponsoring.mdx │ │ │ ├── participants.mdx │ │ │ └── setup-affiliate-program.mdx │ ├── public │ │ ├── favicon.ico │ │ ├── refref-icon.png │ │ ├── webapp-home-1.png │ │ ├── refref-logo-dark.png │ │ ├── refref-logo-light.png │ │ ├── refref-logo-dark-gs.png │ │ ├── refref-logo-dark@2x.png │ │ ├── refref-logo-dark@3x.png │ │ ├── refref-logo-light-gs.png │ │ ├── refref-logo-light@2x.png │ │ ├── refref-logo-light@3x.png │ │ ├── refref-text-logo-dark.png │ │ ├── refref-logo-dark-gs@2x.png │ │ ├── refref-logo-dark-gs@3x.png │ │ ├── refref-logo-light-gs@2x.png │ │ ├── refref-logo-light-gs@3x.png │ │ ├── refref-text-logo-light.png │ │ ├── github-readme-header-dark.png │ │ ├── github-readme-header-light.png │ │ ├── refref-github-repo-cover.png │ │ ├── refref-text-logo-dark@2x.png │ │ ├── refref-text-logo-dark@3x.png │ │ ├── refref-text-logo-light@2x.png │ │ ├── refref-text-logo-light@3x.png │ │ ├── refref-github-repo-cover-dark-transparent.png │ │ └── refref-github-repo-cover-light-transparent.png │ ├── app │ │ ├── robots.txt │ │ ├── (home) │ │ │ ├── docs │ │ │ │ └── page.tsx │ │ │ ├── contact │ │ │ │ └── page.tsx │ │ │ ├── changelog │ │ │ │ └── page.tsx │ │ │ ├── layout.tsx │ │ │ ├── page.tsx │ │ │ └── blog │ │ │ │ └── [slug] │ │ │ │ └── page.client.tsx │ │ ├── community │ │ │ └── page.tsx │ │ ├── github │ │ │ └── page.tsx │ │ ├── api │ │ │ └── search │ │ │ │ └── route.ts │ │ ├── docs │ │ │ ├── layout.tsx │ │ │ └── [...slug] │ │ │ │ └── page.tsx │ │ └── layout.tsx │ ├── postcss.config.mjs │ ├── lib │ │ ├── cn.ts │ │ ├── utils.ts │ │ ├── source.ts │ │ └── metadata.ts │ ├── .env.example │ ├── next.config.mjs │ ├── scripts │ │ └── generate-docs.mjs │ ├── tsconfig.json │ ├── components.json │ ├── .gitignore │ ├── source.config.ts │ ├── components │ │ └── ui │ │ │ ├── label.tsx │ │ │ ├── textarea.tsx │ │ │ ├── input.tsx │ │ │ ├── animated-gradient-text.tsx │ │ │ └── checkbox.tsx │ └── README.md ├── api │ ├── .gitignore │ ├── api.http │ ├── .env.example │ ├── src │ │ ├── routes │ │ │ ├── v1 │ │ │ │ ├── track.ts │ │ │ │ └── programs.ts │ │ │ ├── openapi.ts │ │ │ └── health.ts │ │ └── index.ts │ ├── vitest.config.ts │ ├── tsconfig.json │ ├── test │ │ ├── utils │ │ │ └── testServer.ts │ │ └── setup.ts │ ├── README.md │ └── package.json ├── acme │ ├── next.config.js │ ├── next-env.d.ts │ ├── package.json │ ├── tsconfig.json │ └── src │ │ ├── app │ │ ├── layout.tsx │ │ └── api │ │ │ ├── logout │ │ │ └── route.ts │ │ │ ├── test │ │ │ └── reset │ │ │ │ └── route.ts │ │ │ └── me │ │ │ └── route.ts │ │ └── lib │ │ ├── refref-events.ts │ │ └── refref-config.ts ├── assets │ ├── .gitignore │ ├── wrangler.toml │ ├── tsconfig.json │ └── package.json └── e2e │ ├── sanity │ └── pages │ │ ├── acme │ │ ├── acme-base-page.ts │ │ ├── acme-signup-page.ts │ │ ├── acme-dashboard-page.ts │ │ └── acme-purchase-page.ts │ │ └── base-page.ts │ ├── scripts │ └── cleanup-ports.sh │ ├── tsconfig.json │ ├── package.json │ └── .env.example ├── packages ├── widget │ ├── src │ │ ├── vite-env.d.ts │ │ ├── lib │ │ │ ├── utils.ts │ │ │ ├── store.ts │ │ │ └── config.ts │ │ ├── main.tsx │ │ ├── index.css │ │ └── widget │ │ │ └── components │ │ │ └── widget-container.tsx │ ├── eslint.config.mjs │ ├── sample.env │ ├── index.html │ ├── tsconfig.json │ └── components.json ├── eslint-config │ ├── README.md │ ├── package.json │ ├── base.js │ ├── react-internal.js │ └── next.js ├── types │ ├── tsconfig.json │ ├── eslint.config.mjs │ ├── tsup.config.ts │ ├── src │ │ ├── event-config.ts │ │ └── program-template-steps.ts │ └── package.json ├── attribution-script │ ├── eslint.config.mjs │ ├── index.html │ ├── vitest.config.ts │ ├── tsconfig.json │ ├── src │ │ ├── constants.ts │ │ └── types.ts │ ├── vite.config.ts │ └── package.json ├── ui │ ├── postcss.config.mjs │ ├── src │ │ ├── lib │ │ │ ├── utils.ts │ │ │ ├── format.ts │ │ │ └── id.ts │ │ ├── components │ │ │ ├── aspect-ratio.tsx │ │ │ ├── skeleton.tsx │ │ │ ├── spinner.tsx │ │ │ ├── label.tsx │ │ │ ├── separator.tsx │ │ │ ├── textarea.tsx │ │ │ ├── progress.tsx │ │ │ ├── collapsible.tsx │ │ │ ├── kbd.tsx │ │ │ ├── input.tsx │ │ │ ├── data-table │ │ │ │ └── data-table-advanced-toolbar.tsx │ │ │ ├── sonner.tsx │ │ │ ├── referral-widget │ │ │ │ └── referral-widget-dialog-trigger.tsx │ │ │ ├── switch.tsx │ │ │ ├── avatar.tsx │ │ │ ├── checkbox.tsx │ │ │ ├── radio-group.tsx │ │ │ └── hover-card.tsx │ │ ├── hooks │ │ │ ├── use-mobile.ts │ │ │ ├── use-callback-ref.ts │ │ │ └── use-debounced-callback.ts │ │ └── types │ │ │ └── data-table.ts │ ├── tsconfig.json │ └── components.json ├── typescript-config │ ├── package.json │ ├── react-library.json │ ├── nextjs.json │ └── base.json ├── auth │ ├── tsconfig.json │ └── package.json ├── refref-better-auth │ ├── tsconfig.json │ ├── vitest.config.ts │ ├── build.config.ts │ ├── src │ │ ├── index.ts │ │ ├── types.test.ts │ │ └── utils │ │ │ └── cookie.test.ts │ └── package.json ├── id │ ├── tsconfig.json │ └── package.json ├── utils │ ├── tsconfig.json │ ├── src │ │ ├── index.ts │ │ └── plugins │ │ │ └── coredb.ts │ ├── package.json │ └── README.md ├── email-templates │ ├── tsconfig.json │ ├── src │ │ ├── utils │ │ │ └── render.ts │ │ └── index.ts │ └── package.json └── coredb │ ├── drizzle.config.ts │ ├── drizzle │ ├── meta │ │ └── _journal.json │ └── 0001_flaky_madelyne_pryor.sql │ ├── tsconfig.json │ ├── src │ └── index.ts │ └── package.json ├── .github ├── FUNDING.yml └── workflows │ └── ci.yml ├── .npmrc ├── pnpm-workspace.yaml ├── .gitignore ├── package.json ├── turbo.json ├── docker-compose.yml └── .dockerignore /apps/webapp/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | -------------------------------------------------------------------------------- /apps/refer/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .env 4 | .env.local 5 | -------------------------------------------------------------------------------- /apps/www/content/docs/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": ["platform", "api"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/widget/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/api/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .env 4 | .env.local 5 | *.log 6 | -------------------------------------------------------------------------------- /apps/webapp/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from "@refref/ui/postcss.config"; -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: refrefhq -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | public-hoist-pattern[]=*better-auth* 2 | public-hoist-pattern[]=*@better-auth* 3 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "apps/*" 3 | - "!apps/www" 4 | - "packages/*" 5 | -------------------------------------------------------------------------------- /apps/www/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/favicon.ico -------------------------------------------------------------------------------- /apps/www/public/refref-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-icon.png -------------------------------------------------------------------------------- /apps/www/public/webapp-home-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/webapp-home-1.png -------------------------------------------------------------------------------- /packages/eslint-config/README.md: -------------------------------------------------------------------------------- 1 | # `@turbo/eslint-config` 2 | 3 | Collection of internal eslint configurations. 4 | -------------------------------------------------------------------------------- /apps/www/public/refref-logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-logo-dark.png -------------------------------------------------------------------------------- /apps/www/app/robots.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | Allow: / 3 | Disallow: /private/ 4 | 5 | Sitemap: https://refref.ai/sitemap.xml 6 | -------------------------------------------------------------------------------- /apps/www/public/refref-logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-logo-light.png -------------------------------------------------------------------------------- /apps/www/content/docs/api/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: RefRef API 3 | description: RefRef API documentation 4 | index: true 5 | --- 6 | -------------------------------------------------------------------------------- /apps/www/public/refref-logo-dark-gs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-logo-dark-gs.png -------------------------------------------------------------------------------- /apps/www/public/refref-logo-dark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-logo-dark@2x.png -------------------------------------------------------------------------------- /apps/www/public/refref-logo-dark@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-logo-dark@3x.png -------------------------------------------------------------------------------- /apps/www/public/refref-logo-light-gs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-logo-light-gs.png -------------------------------------------------------------------------------- /apps/www/public/refref-logo-light@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-logo-light@2x.png -------------------------------------------------------------------------------- /apps/www/public/refref-logo-light@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-logo-light@3x.png -------------------------------------------------------------------------------- /apps/www/public/refref-text-logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-text-logo-dark.png -------------------------------------------------------------------------------- /apps/www/public/refref-logo-dark-gs@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-logo-dark-gs@2x.png -------------------------------------------------------------------------------- /apps/www/public/refref-logo-dark-gs@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-logo-dark-gs@3x.png -------------------------------------------------------------------------------- /apps/www/public/refref-logo-light-gs@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-logo-light-gs@2x.png -------------------------------------------------------------------------------- /apps/www/public/refref-logo-light-gs@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-logo-light-gs@3x.png -------------------------------------------------------------------------------- /apps/www/public/refref-text-logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-text-logo-light.png -------------------------------------------------------------------------------- /apps/www/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | '@tailwindcss/postcss': {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /apps/www/public/github-readme-header-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/github-readme-header-dark.png -------------------------------------------------------------------------------- /apps/www/public/github-readme-header-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/github-readme-header-light.png -------------------------------------------------------------------------------- /apps/www/public/refref-github-repo-cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-github-repo-cover.png -------------------------------------------------------------------------------- /apps/www/public/refref-text-logo-dark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-text-logo-dark@2x.png -------------------------------------------------------------------------------- /apps/www/public/refref-text-logo-dark@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-text-logo-dark@3x.png -------------------------------------------------------------------------------- /apps/www/public/refref-text-logo-light@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-text-logo-light@2x.png -------------------------------------------------------------------------------- /apps/www/public/refref-text-logo-light@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-text-logo-light@3x.png -------------------------------------------------------------------------------- /apps/www/content/docs/platform/contributing.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Contributing 3 | description: Guide to contributing to the RefRef open source project 4 | --- 5 | TBD -------------------------------------------------------------------------------- /apps/acme/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | }; 5 | 6 | module.exports = nextConfig; 7 | -------------------------------------------------------------------------------- /packages/types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@refref/typescript-config/base.json", 3 | "include": ["src"], 4 | "exclude": ["node_modules", "dist"] 5 | } 6 | -------------------------------------------------------------------------------- /apps/api/api.http: -------------------------------------------------------------------------------- 1 | @host = http://localhost:3001 2 | 3 | ### Health Check - Root 4 | GET {{host}}/ 5 | 6 | ### Health Check - Health Endpoint 7 | GET {{host}}/health 8 | -------------------------------------------------------------------------------- /apps/webapp/src/styles/app.css: -------------------------------------------------------------------------------- 1 | @import "@daveyplate/better-auth-ui/css"; 2 | @import "@refref/ui/globals.css"; 3 | 4 | :root { 5 | --content-max-width: 128rem; 6 | } 7 | -------------------------------------------------------------------------------- /apps/www/app/(home)/docs/page.tsx: -------------------------------------------------------------------------------- 1 | import { redirect } from "next/navigation"; 2 | 3 | export default async function DocsPage() { 4 | redirect("/docs/platform"); 5 | } 6 | -------------------------------------------------------------------------------- /apps/www/public/refref-github-repo-cover-dark-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-github-repo-cover-dark-transparent.png -------------------------------------------------------------------------------- /packages/types/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { config } from "@refref/eslint-config/base"; 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default config; 5 | -------------------------------------------------------------------------------- /apps/webapp/src/app/(authenticated)/(core)/page.tsx: -------------------------------------------------------------------------------- 1 | import { redirect } from "next/navigation"; 2 | 3 | export default function Home() { 4 | redirect("/programs"); 5 | } 6 | -------------------------------------------------------------------------------- /apps/www/public/refref-github-repo-cover-light-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refrefhq/refref/HEAD/apps/www/public/refref-github-repo-cover-light-transparent.png -------------------------------------------------------------------------------- /apps/webapp/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { nextJsConfig } from "@refref/eslint-config/next-js"; 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default nextJsConfig; 5 | -------------------------------------------------------------------------------- /apps/www/content/docs/api/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "RefRef API", 3 | "description": "RefRef API documentation", 4 | "root": "true", 5 | "icon": "SquareCode" 6 | } 7 | 8 | -------------------------------------------------------------------------------- /apps/www/content/docs/platform/paddle.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Paddle Integration 3 | description: Integrating Paddle with RefRef for payment processing and referral tracking 4 | --- 5 | TBD -------------------------------------------------------------------------------- /packages/widget/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { config } from "@refref/eslint-config/react-internal"; 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default config; 5 | -------------------------------------------------------------------------------- /apps/www/content/docs/platform/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Overview 3 | description: Introduction to RefRef 4 | --- 5 | Welcome to RefRef - Open Source Referral Management Platform 6 | 7 | -------------------------------------------------------------------------------- /packages/attribution-script/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { config } from "@refref/eslint-config/base"; 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default config; 5 | -------------------------------------------------------------------------------- /apps/www/app/community/page.tsx: -------------------------------------------------------------------------------- 1 | import { redirect } from "next/navigation"; 2 | 3 | export default async function CommunityPage() { 4 | redirect("https://discord.gg/fx99JWdfS7"); 5 | } 6 | -------------------------------------------------------------------------------- /apps/www/app/github/page.tsx: -------------------------------------------------------------------------------- 1 | import { redirect } from "next/navigation"; 2 | 3 | export default async function CommunityPage() { 4 | redirect("https://github.com/refrefhq/refref"); 5 | } 6 | -------------------------------------------------------------------------------- /packages/ui/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { "@tailwindcss/postcss": {} }, 4 | }; 5 | 6 | export default config; 7 | -------------------------------------------------------------------------------- /apps/www/content/docs/platform/fraud-prevention.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Fraud Prevention 3 | description: Protecting your referral and affiliate programs from fraud and abuse with RefRef 4 | --- 5 | TBD -------------------------------------------------------------------------------- /packages/typescript-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@refref/typescript-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "publishConfig": { 6 | "access": "public" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/widget/sample.env: -------------------------------------------------------------------------------- 1 | # RefRef Widget Environment Variables 2 | # Copy this file to .env and update with your values 3 | 4 | # API Endpoint 5 | VITE_REFREF_API_ENDPOINT=http://localhost:3001 6 | -------------------------------------------------------------------------------- /apps/www/lib/cn.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /packages/typescript-config/react-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "./base.json", 4 | "compilerOptions": { 5 | "jsx": "react-jsx" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /apps/www/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /apps/webapp/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /packages/ui/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /packages/widget/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /apps/acme/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. 6 | -------------------------------------------------------------------------------- /apps/webapp/src/server/db.ts: -------------------------------------------------------------------------------- 1 | import { createDb } from "@refref/coredb"; 2 | import { env } from "@/env"; 3 | 4 | export const db = createDb(env.DATABASE_URL); 5 | export { schema } from "@refref/coredb"; 6 | export type { DBType } from "@refref/coredb"; 7 | -------------------------------------------------------------------------------- /packages/auth/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@refref/typescript-config/base.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src" 6 | }, 7 | "include": ["src"], 8 | "exclude": ["node_modules", "dist"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/refref-better-auth/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@refref/typescript-config/base.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src" 6 | }, 7 | "include": ["src"], 8 | "exclude": ["node_modules", "dist"] 9 | } -------------------------------------------------------------------------------- /packages/types/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "tsup"; 2 | 3 | export default defineConfig({ 4 | entry: ["src/index.ts"], 5 | format: ["cjs", "esm"], 6 | dts: true, 7 | splitting: false, 8 | sourcemap: true, 9 | clean: true, 10 | }); 11 | -------------------------------------------------------------------------------- /packages/id/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@refref/typescript-config/base.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src" 6 | }, 7 | "include": ["src/**/*"], 8 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@refref/typescript-config/base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "rootDir": "./src" 6 | }, 7 | "include": ["src/**/*"], 8 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /apps/www/app/api/search/route.ts: -------------------------------------------------------------------------------- 1 | import { source } from "@/lib/source"; 2 | import { createFromSource } from "fumadocs-core/search/server"; 3 | 4 | // it should be cached forever 5 | export const revalidate = false; 6 | 7 | export const { staticGET: GET } = createFromSource(source); 8 | -------------------------------------------------------------------------------- /apps/www/content/docs/platform/projects.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Projects 3 | description: Understanding projects in RefRef and how to manage them 4 | --- 5 | Projects are the core organizational unit in RefRef that allow you to create and manage distinct referral or affiliate programs. 6 | 7 | -------------------------------------------------------------------------------- /packages/email-templates/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@refref/typescript-config/base.json", 3 | "compilerOptions": { 4 | "jsx": "react", 5 | "outDir": "dist", 6 | "rootDir": "src" 7 | }, 8 | "include": ["src"], 9 | "exclude": ["node_modules", "dist"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/utils/src/index.ts: -------------------------------------------------------------------------------- 1 | // Export plugins 2 | export { default as coredbPlugin } from "./plugins/coredb.js"; 3 | 4 | // Export refcode utilities 5 | export { 6 | generateGlobalCode, 7 | validateVanityCode, 8 | normalizeCode, 9 | isGlobalCodeFormat, 10 | } from "./refcode.js"; 11 | -------------------------------------------------------------------------------- /packages/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@refref/typescript-config/react-library.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "@refref/ui/*": ["./src/*"] 7 | } 8 | }, 9 | "include": ["."], 10 | "exclude": ["node_modules", "dist"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/widget/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from "react"; 2 | import { createRoot } from "react-dom/client"; 3 | import "./index.css"; 4 | import App from "@/App"; 5 | 6 | createRoot(document.getElementById("root")!).render( 7 | 8 | 9 | , 10 | ); 11 | -------------------------------------------------------------------------------- /apps/api/.env.example: -------------------------------------------------------------------------------- 1 | # Server Configuration 2 | PORT=3001 3 | HOST=0.0.0.0 4 | NODE_ENV=development 5 | LOG_LEVEL=info 6 | 7 | # Database Configuration 8 | DATABASE_URL="postgresql://postgres:postgres@localhost:5432/refref" 9 | 10 | # Referral Configuration 11 | REFERRAL_HOST_URL="http://localhost:3002" 12 | -------------------------------------------------------------------------------- /apps/www/content/docs/platform/newsletter.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Newsletter Referral Programs 3 | description: Growing your newsletter audience through referral programs with RefRef 4 | --- 5 | This guide provides strategies for implementing successful referral programs to grow your newsletter audience using RefRef. 6 | 7 | TBD -------------------------------------------------------------------------------- /apps/webapp/src/app/(authenticated)/(core)/programs/[id]/layout.tsx: -------------------------------------------------------------------------------- 1 | export default function ProgramLayout({ 2 | children, 3 | }: { 4 | children: React.ReactNode; 5 | }) { 6 | return ( 7 |
8 | {children} 9 |
10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /apps/webapp/src/app/api/auth/[...all]/route.ts: -------------------------------------------------------------------------------- 1 | import { auth } from "@/lib/auth"; 2 | import { toNextJsHandler } from "better-auth/next-js"; 3 | 4 | /** 5 | * BetterAuth handler for Next.js API routes 6 | * This route handles all authentication-related requests 7 | */ 8 | export const { GET, POST } = toNextJsHandler(auth); 9 | -------------------------------------------------------------------------------- /apps/webapp/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | import path from "path"; 3 | 4 | export default defineConfig({ 5 | test: { 6 | globals: true, 7 | environment: "node", 8 | }, 9 | resolve: { 10 | alias: { 11 | "@": path.resolve(__dirname, "./src"), 12 | }, 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /apps/www/app/(home)/contact/page.tsx: -------------------------------------------------------------------------------- 1 | import Contact from "@/components/ui/contact"; 2 | 3 | export const metadata = { 4 | title: "Contact", 5 | description: 6 | "Get in touch with the authors of RefRef for any questions or support.", 7 | }; 8 | 9 | export default function ContactPage() { 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /apps/www/.env.example: -------------------------------------------------------------------------------- 1 | # S3 Configuration for fetch-content script 2 | AWS_ACCESS_KEY_ID=your_access_key 3 | AWS_SECRET_ACCESS_KEY=your_secret_key 4 | AWS_REGION=us-east-1 5 | 6 | # Optional: Override default S3 settings 7 | # S3_BUCKET_NAME=refref-www 8 | # S3_ENDPOINT=https://s3.wasabisys.com 9 | # BLOG_PREFIX=blog/ 10 | # BLOG_IMAGES_PREFIX=blog-images/ -------------------------------------------------------------------------------- /packages/typescript-config/nextjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "./base.json", 4 | "compilerOptions": { 5 | "plugins": [{ "name": "next" }], 6 | "module": "ESNext", 7 | "moduleResolution": "Bundler", 8 | "allowJs": true, 9 | "jsx": "preserve", 10 | "noEmit": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /apps/www/next.config.mjs: -------------------------------------------------------------------------------- 1 | import { createMDX } from 'fumadocs-mdx/next'; 2 | 3 | const withMDX = createMDX(); 4 | 5 | /** @type {import('next').NextConfig} */ 6 | const config = { 7 | output: 'export', 8 | reactStrictMode: true, 9 | images: { 10 | domains: ['refref.ai'], 11 | unoptimized: true 12 | } 13 | }; 14 | 15 | export default withMDX(config); 16 | -------------------------------------------------------------------------------- /packages/ui/src/components/aspect-ratio.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"; 4 | 5 | function AspectRatio({ 6 | ...props 7 | }: React.ComponentProps) { 8 | return ; 9 | } 10 | 11 | export { AspectRatio }; 12 | -------------------------------------------------------------------------------- /apps/assets/.gitignore: -------------------------------------------------------------------------------- 1 | # Build outputs 2 | dist/ 3 | 4 | # Generated assets (built from packages) 5 | public/*.js 6 | public/*.js.map 7 | 8 | # Keep configuration files 9 | !public/_headers 10 | !public/_redirects 11 | 12 | # Dependencies 13 | node_modules/ 14 | 15 | # TypeScript 16 | *.tsbuildinfo 17 | 18 | # Environment 19 | .env 20 | .env.local 21 | .env.*.local 22 | -------------------------------------------------------------------------------- /packages/ui/src/components/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@refref/ui/lib/utils"; 2 | 3 | function Skeleton({ className, ...props }: React.ComponentProps<"div">) { 4 | return ( 5 |
10 | ); 11 | } 12 | 13 | export { Skeleton }; 14 | -------------------------------------------------------------------------------- /apps/assets/wrangler.toml: -------------------------------------------------------------------------------- 1 | # Wrangler configuration for RefRef Assets 2 | # https://developers.cloudflare.com/workers/wrangler/configuration/ 3 | 4 | name = "refref-assets" 5 | main = "src/index.ts" 6 | compatibility_date = "2024-01-01" 7 | 8 | [assets] 9 | directory = "./public" 10 | binding = "ASSETS" 11 | 12 | # Dev/Preview environment 13 | [env.dev] 14 | name = "refref-assets-dev" 15 | -------------------------------------------------------------------------------- /packages/attribution-script/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | RefRef Attribution Script Demo 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/attribution-script/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | import path from "path"; 3 | 4 | export default defineConfig({ 5 | test: { 6 | globals: true, 7 | environment: "jsdom", 8 | testTimeout: 30000, 9 | hookTimeout: 30000, 10 | }, 11 | resolve: { 12 | alias: { 13 | "@": path.resolve(__dirname, "./src"), 14 | }, 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /packages/refref-better-auth/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | import path from "path"; 3 | 4 | export default defineConfig({ 5 | test: { 6 | globals: true, 7 | environment: "node", 8 | testTimeout: 30000, 9 | hookTimeout: 30000, 10 | }, 11 | resolve: { 12 | alias: { 13 | "@": path.resolve(__dirname, "./src"), 14 | }, 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /apps/webapp/src/server/api/routers/post.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | import { createTRPCRouter, publicProcedure } from "@/server/api/trpc"; 4 | 5 | export const postRouter = createTRPCRouter({ 6 | hello: publicProcedure 7 | .input(z.object({ text: z.string() })) 8 | .query(({ input }) => { 9 | return { 10 | greeting: `Hello ${input.text}`, 11 | }; 12 | }), 13 | }); 14 | -------------------------------------------------------------------------------- /packages/coredb/drizzle.config.ts: -------------------------------------------------------------------------------- 1 | import { type Config } from "drizzle-kit"; 2 | 3 | if (!process.env.DATABASE_URL) { 4 | throw new Error( 5 | "DATABASE_URL environment variable is required for migrations", 6 | ); 7 | } 8 | 9 | export default { 10 | schema: "./src/schema.ts", 11 | dialect: "postgresql", 12 | dbCredentials: { 13 | url: process.env.DATABASE_URL, 14 | }, 15 | } satisfies Config; 16 | -------------------------------------------------------------------------------- /apps/assets/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@refref/typescript-config/base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "target": "ES2022", 8 | "lib": ["ES2022"], 9 | "types": ["node", "@cloudflare/workers-types"] 10 | }, 11 | "include": ["src/**/*", "scripts/**/*"], 12 | "exclude": ["node_modules", "dist", "public"] 13 | } 14 | -------------------------------------------------------------------------------- /apps/www/app/(home)/changelog/page.tsx: -------------------------------------------------------------------------------- 1 | import Changelog from "@/components/ui/changelog"; 2 | import { SubscriptionForm } from "@/components/ui/subscription-form"; 3 | 4 | export const metadata = { 5 | title: "Changelog", 6 | description: "Get the latest product updates and changes to RefRef.", 7 | }; 8 | 9 | export default function ChangelogPage() { 10 | return ( 11 | <> 12 | 13 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /packages/widget/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/widget/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | -------------------------------------------------------------------------------- /packages/ui/src/components/spinner.tsx: -------------------------------------------------------------------------------- 1 | import { Loader2Icon } from "lucide-react"; 2 | 3 | import { cn } from "@refref/ui/lib/utils"; 4 | 5 | function Spinner({ className, ...props }: React.ComponentProps<"svg">) { 6 | return ( 7 | 13 | ); 14 | } 15 | 16 | export { Spinner }; 17 | -------------------------------------------------------------------------------- /apps/webapp/src/lib/logger.ts: -------------------------------------------------------------------------------- 1 | import winston from "winston"; 2 | const { combine, timestamp, colorize, simple, errors } = winston.format; 3 | 4 | const logger = winston.createLogger({ 5 | level: "info", 6 | format: combine( 7 | errors({ stack: true }), 8 | timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), 9 | colorize(), 10 | simple(), 11 | ), 12 | transports: [new winston.transports.Console()], 13 | }); 14 | 15 | export { logger }; 16 | -------------------------------------------------------------------------------- /apps/www/scripts/generate-docs.mjs: -------------------------------------------------------------------------------- 1 | import * as OpenAPI from 'fumadocs-openapi'; 2 | import { rimrafSync } from 'rimraf'; 3 | 4 | const openapiOut = './content/docs/api'; 5 | 6 | // clean generated files 7 | rimrafSync(openapiOut, { 8 | filter(v) { 9 | return !v.endsWith('index.mdx') && !v.endsWith('meta.json'); 10 | }, 11 | }); 12 | 13 | void OpenAPI.generateFiles({ 14 | // input files 15 | input: ['./openapi.yaml'], 16 | output: openapiOut, 17 | groupBy: 'tag', 18 | }); -------------------------------------------------------------------------------- /packages/coredb/drizzle/meta/_journal.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "7", 3 | "dialect": "postgresql", 4 | "entries": [ 5 | { 6 | "idx": 0, 7 | "version": "7", 8 | "when": 1763471717017, 9 | "tag": "0000_flashy_infant_terrible", 10 | "breakpoints": true 11 | }, 12 | { 13 | "idx": 1, 14 | "version": "7", 15 | "when": 1763895779098, 16 | "tag": "0001_flaky_madelyne_pryor", 17 | "breakpoints": true 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /packages/ui/src/lib/format.ts: -------------------------------------------------------------------------------- 1 | export function formatDate( 2 | date: Date | string | number | undefined, 3 | opts: Intl.DateTimeFormatOptions = {}, 4 | ) { 5 | if (!date) return ""; 6 | 7 | try { 8 | return new Intl.DateTimeFormat("en-US", { 9 | month: opts.month ?? "long", 10 | day: opts.day ?? "numeric", 11 | year: opts.year ?? "numeric", 12 | ...opts, 13 | }).format(new Date(date)); 14 | } catch (_err) { 15 | return ""; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/email-templates/src/utils/render.ts: -------------------------------------------------------------------------------- 1 | import { render } from "@react-email/render"; 2 | import * as React from "react"; 3 | 4 | /** 5 | * Renders a React Email component to an HTML string 6 | * @param component - The React Email component to render 7 | * @returns The rendered HTML string 8 | */ 9 | export async function renderEmail( 10 | component: React.ReactElement, 11 | ): Promise { 12 | return await render(component, { 13 | pretty: false, 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /apps/webapp/src/lib/hooks/use-debounce.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | export function useDebounce(value: T, delay: number): T { 4 | const [debouncedValue, setDebouncedValue] = useState(value); 5 | 6 | useEffect(() => { 7 | const handler = setTimeout(() => { 8 | setDebouncedValue(value); 9 | }, delay); 10 | 11 | return () => { 12 | clearTimeout(handler); 13 | }; 14 | }, [value, delay]); 15 | 16 | return debouncedValue; 17 | } 18 | -------------------------------------------------------------------------------- /apps/www/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@refref/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "paths": { 5 | "@/.source": ["./.source"], 6 | "@/*": ["./*"] 7 | }, 8 | "declaration": false 9 | }, 10 | "include": [ 11 | "next-env.d.ts", 12 | "**/*.ts", 13 | "**/*.tsx", 14 | ".next/types/**/*.ts", 15 | "src/lib/dom/build/rrwebRecorderScript.cjs", 16 | "src/env.ts" 17 | , "scripts/lint.mts" ], 18 | "exclude": ["node_modules"] 19 | } 20 | -------------------------------------------------------------------------------- /apps/api/src/routes/v1/track.ts: -------------------------------------------------------------------------------- 1 | import { FastifyInstance } from "fastify"; 2 | import signupTrackRoutes from "./track/signup.js"; 3 | import purchaseTrackRoutes from "./track/purchase.js"; 4 | 5 | export default async function trackRoutes(fastify: FastifyInstance) { 6 | // Register signup tracking route 7 | await fastify.register(signupTrackRoutes, { prefix: "/signup" }); 8 | 9 | // Register purchase tracking route 10 | await fastify.register(purchaseTrackRoutes, { prefix: "/purchase" }); 11 | } 12 | -------------------------------------------------------------------------------- /packages/attribution-script/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@refref/typescript-config/base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "@/*": ["./src/*"] 7 | }, 8 | "declaration": false, 9 | "declarationMap": false, 10 | "module": "ESNext", 11 | "moduleResolution": "Bundler", 12 | "allowJs": true, 13 | "jsx": "preserve", 14 | "noEmit": true 15 | }, 16 | "include": ["**/*.ts", "**/*.tsx"], 17 | "exclude": ["node_modules", "dist"] 18 | } 19 | -------------------------------------------------------------------------------- /packages/attribution-script/src/constants.ts: -------------------------------------------------------------------------------- 1 | import type { AutoAttachMode } from "@/types"; 2 | 3 | export const DEFAULT_AUTO_ATTACH: AutoAttachMode = "data-refref"; 4 | 5 | export const FORM = { 6 | SELECTOR: "form[data-refref]", 7 | SELECTOR_ALL: "form", 8 | FIELD: "refcode", 9 | } as const; 10 | 11 | export const URL = { 12 | CODE_PARAM: "refcode", 13 | } as const; 14 | 15 | export const COOKIE = { 16 | CODE_KEY: "refref-refcode", 17 | MAX_AGE: 90 * 24 * 60 * 60, // 90 days in seconds 18 | } as const; 19 | -------------------------------------------------------------------------------- /apps/www/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "", 8 | "css": "app/global.css", 9 | "baseColor": "zinc", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | }, 20 | "iconLibrary": "lucide" 21 | } -------------------------------------------------------------------------------- /apps/api/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | 3 | export default defineConfig({ 4 | test: { 5 | globals: true, 6 | environment: "node", 7 | testTimeout: 30000, 8 | hookTimeout: 30000, 9 | setupFiles: ["./test/setup.ts"], 10 | env: { 11 | NODE_ENV: "test", 12 | // Mock database is used via Vitest mocks, but we need a dummy URL 13 | // to satisfy the plugin's validation 14 | DATABASE_URL: "postgresql://mock:mock@localhost:5432/mock", 15 | }, 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /apps/refer/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | 3 | export default defineConfig({ 4 | test: { 5 | globals: true, 6 | environment: "node", 7 | testTimeout: 30000, 8 | hookTimeout: 30000, 9 | setupFiles: ["./test/setup.ts"], 10 | env: { 11 | NODE_ENV: "test", 12 | // Mock database is used via Vitest mocks, but we need a dummy URL 13 | // to satisfy the plugin's validation 14 | DATABASE_URL: "postgresql://mock:mock@localhost:5432/mock", 15 | }, 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /apps/www/.gitignore: -------------------------------------------------------------------------------- 1 | # deps 2 | /node_modules 3 | 4 | # generated content 5 | .contentlayer 6 | .content-collections 7 | .source 8 | 9 | # test & build 10 | /coverage 11 | /.next/ 12 | /out/ 13 | /build 14 | *.tsbuildinfo 15 | 16 | # misc 17 | .DS_Store 18 | *.pem 19 | /.pnp 20 | .pnp.js 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | # others 26 | .env*.local 27 | .vercel 28 | next-env.d.ts 29 | 30 | # sitemap 31 | /public/sitemap.xml 32 | 33 | # remote blog content 34 | /content/blogs/* 35 | /public/blog/* 36 | /content/tmp/* -------------------------------------------------------------------------------- /packages/widget/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@refref/typescript-config/react-library.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "@/*": ["./src/*"] 7 | }, 8 | "declaration": false, 9 | "declarationMap": false, 10 | "module": "ESNext", 11 | "moduleResolution": "Bundler", 12 | "allowJs": true, 13 | "jsx": "preserve", 14 | "noEmit": true 15 | }, 16 | "include": ["**/*.ts", "**/*.tsx", "next-env.d.ts", ".next/types/**/*.ts"], 17 | "exclude": ["node_modules", "dist"] 18 | } 19 | -------------------------------------------------------------------------------- /apps/webapp/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "", 8 | "css": "../../packages/ui/src/styles/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true 11 | }, 12 | "iconLibrary": "lucide", 13 | "aliases": { 14 | "components": "@/components", 15 | "hooks": "@/hooks", 16 | "lib": "@/lib", 17 | "utils": "@refref/ui/lib/utils", 18 | "ui": "@refref/ui/components" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /apps/webapp/src/app/(authenticated)/layout.tsx: -------------------------------------------------------------------------------- 1 | import { auth } from "@/lib/auth"; 2 | import { headers } from "next/headers"; 3 | import { redirect } from "next/navigation"; 4 | 5 | export default async function MainLayout({ 6 | children, 7 | }: { 8 | children: React.ReactNode; 9 | }) { 10 | const session = await auth.api.getSession({ 11 | headers: await headers(), 12 | }); 13 | 14 | // Server-side redirect if no session is found 15 | if (!session) { 16 | redirect("/auth/sign-in"); 17 | } 18 | 19 | return <>{children}; 20 | } 21 | -------------------------------------------------------------------------------- /packages/refref-better-auth/build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from "unbuild"; 2 | 3 | export default defineBuildConfig({ 4 | entries: [ 5 | { 6 | input: "./src/index", 7 | outDir: "./dist", 8 | name: "index", 9 | format: ["cjs", "esm"], 10 | }, 11 | ], 12 | declaration: true, 13 | clean: true, 14 | failOnWarn: false, // Don't fail on warnings 15 | rollup: { 16 | emitCJS: true, 17 | esbuild: { 18 | target: "node16", 19 | }, 20 | }, 21 | externals: ["better-auth", "zod"], 22 | }); 23 | -------------------------------------------------------------------------------- /packages/widget/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "", 8 | "css": "../../packages/ui/src/styles/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true 11 | }, 12 | "iconLibrary": "lucide", 13 | "aliases": { 14 | "components": "@/components", 15 | "hooks": "@/hooks", 16 | "lib": "@/lib", 17 | "utils": "@refref/ui/lib/utils", 18 | "ui": "@refref/ui/components" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/ui/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "", 8 | "css": "src/styles/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true 11 | }, 12 | "iconLibrary": "lucide", 13 | "aliases": { 14 | "components": "@refref/ui/components", 15 | "utils": "@refref/ui/lib/utils", 16 | "hooks": "@refref/ui/hooks", 17 | "lib": "@refref/ui/lib", 18 | "ui": "@refref/ui/components" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /apps/www/content/docs/api/get-programs.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Get all programs 3 | description: Retrieve a list of all programs 4 | full: true 5 | _openapi: 6 | method: GET 7 | route: /programs 8 | toc: [] 9 | structuredData: 10 | headings: [] 11 | contents: 12 | - content: Retrieve a list of all programs 13 | --- 14 | 15 | {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} 16 | 17 | -------------------------------------------------------------------------------- /packages/typescript-config/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "declarationMap": true, 6 | "esModuleInterop": true, 7 | "incremental": false, 8 | "isolatedModules": true, 9 | "lib": ["es2022", "DOM", "DOM.Iterable"], 10 | "module": "NodeNext", 11 | "moduleDetection": "force", 12 | "moduleResolution": "NodeNext", 13 | "noUncheckedIndexedAccess": true, 14 | "resolveJsonModule": true, 15 | "skipLibCheck": true, 16 | "strict": true, 17 | "target": "ES2022" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/coredb/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@refref/typescript-config/base.json", 3 | "compilerOptions": { 4 | "module": "ESNext", 5 | "target": "ES2022", 6 | "lib": ["ES2022"], 7 | "outDir": "./dist", 8 | "rootDir": "./src", 9 | "declaration": true, 10 | "declarationMap": true, 11 | "moduleResolution": "bundler", 12 | "allowSyntheticDefaultImports": true, 13 | "esModuleInterop": true, 14 | "skipLibCheck": true, 15 | "strict": true, 16 | "noUncheckedIndexedAccess": true 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } -------------------------------------------------------------------------------- /apps/www/content/docs/api/get-participants.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Get all participants 3 | description: Retrieve a list of all participants 4 | full: true 5 | _openapi: 6 | method: GET 7 | route: /participants 8 | toc: [] 9 | structuredData: 10 | headings: [] 11 | contents: 12 | - content: Retrieve a list of all participants 13 | --- 14 | 15 | {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} 16 | 17 | -------------------------------------------------------------------------------- /apps/e2e/sanity/pages/acme/acme-base-page.ts: -------------------------------------------------------------------------------- 1 | import { Page } from "@playwright/test"; 2 | import { BasePage } from "../base-page"; 3 | 4 | /** 5 | * Base page for Acme test application pages 6 | * Acme app runs on port 3003 7 | */ 8 | export class AcmeBasePage extends BasePage { 9 | protected baseUrl: string; 10 | 11 | constructor(page: Page) { 12 | super(page); 13 | this.baseUrl = process.env.ACME_URL || "http://localhost:3003"; 14 | } 15 | 16 | /** 17 | * Navigate to a specific path in the Acme app 18 | */ 19 | async goto(path: string) { 20 | await this.page.goto(`${this.baseUrl}${path}`); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /apps/www/app/(home)/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from "react"; 2 | import { HomeLayout } from "fumadocs-ui/layouts/home"; 3 | import { baseOptions } from "@/app/layout.config"; 4 | import { Footer } from "@/components/ui/footer"; 5 | 6 | export default function Layout({ 7 | children, 8 | }: { 9 | children: ReactNode; 10 | }): React.ReactElement { 11 | return ( 12 | 13 |
14 |
15 | {children} 16 |
17 |
18 |
19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /apps/www/content/docs/api/get-program-by-id.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Get program by ID 3 | description: Retrieve a specific program by its ID 4 | full: true 5 | _openapi: 6 | method: GET 7 | route: /programs/{programId} 8 | toc: [] 9 | structuredData: 10 | headings: [] 11 | contents: 12 | - content: Retrieve a specific program by its ID 13 | --- 14 | 15 | {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} 16 | 17 | -------------------------------------------------------------------------------- /apps/acme/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@refref/acme", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Test application for RefRef integration testing and demos", 6 | "scripts": { 7 | "dev": "next dev --port 3003", 8 | "build": "next build", 9 | "start": "next start --port 3003" 10 | }, 11 | "dependencies": { 12 | "jose": "^6.1.1", 13 | "next": "15.1.9", 14 | "react": "^19.2.0", 15 | "react-dom": "^19.2.0" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "^20.11.5", 19 | "@types/react": "^19.2.0", 20 | "@types/react-dom": "^19.2.0", 21 | "typescript": "^5.3.3" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /apps/api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "ESNext", 5 | "lib": ["ES2022"], 6 | "moduleResolution": "bundler", 7 | "outDir": "./dist", 8 | "rootDir": "./src", 9 | "strict": true, 10 | "esModuleInterop": true, 11 | "skipLibCheck": true, 12 | "forceConsistentCasingInFileNames": true, 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noUnusedLocals": true, 16 | "noUnusedParameters": true, 17 | "noImplicitReturns": true, 18 | "noFallthroughCasesInSwitch": true 19 | }, 20 | "include": ["src/**/*"], 21 | "exclude": ["node_modules", "dist"] 22 | } 23 | -------------------------------------------------------------------------------- /apps/refer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "ESNext", 5 | "lib": ["ES2022"], 6 | "moduleResolution": "bundler", 7 | "outDir": "./dist", 8 | "rootDir": "./src", 9 | "strict": true, 10 | "esModuleInterop": true, 11 | "skipLibCheck": true, 12 | "forceConsistentCasingInFileNames": true, 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noUnusedLocals": true, 16 | "noUnusedParameters": true, 17 | "noImplicitReturns": true, 18 | "noFallthroughCasesInSwitch": true 19 | }, 20 | "include": ["src/**/*"], 21 | "exclude": ["node_modules", "dist"] 22 | } 23 | -------------------------------------------------------------------------------- /apps/webapp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@refref/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "types": ["vitest/globals"], 5 | "paths": { 6 | "@/*": [ 7 | "./src/*" 8 | ], 9 | "@refref/ui/*": [ 10 | "../../packages/ui/src/*" 11 | ] 12 | }, 13 | "disableSizeLimit": false, 14 | "declaration": false, 15 | "declarationMap": false 16 | }, 17 | "include": [ 18 | "**/*.ts", 19 | "**/*.tsx", 20 | "next-env.d.ts", 21 | "next.config.ts", 22 | "src/types/**/*.ts", 23 | ".next/types/**/*.ts" 24 | ], 25 | "exclude": [ 26 | "node_modules", 27 | ".next" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /apps/webapp/src/hooks/use-mobile.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | 3 | const MOBILE_BREAKPOINT = 768; 4 | 5 | export function useIsMobile() { 6 | const [isMobile, setIsMobile] = useState(undefined); 7 | 8 | useEffect(() => { 9 | const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); 10 | const onChange = () => { 11 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); 12 | }; 13 | mql.addEventListener("change", onChange); 14 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); 15 | return () => mql.removeEventListener("change", onChange); 16 | }, []); 17 | 18 | return !!isMobile; 19 | } 20 | -------------------------------------------------------------------------------- /apps/www/content/docs/api/get-participant-by-id.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Get participant by ID 3 | description: Retrieve a specific participant by their ID 4 | full: true 5 | _openapi: 6 | method: GET 7 | route: /participants/{participantId} 8 | toc: [] 9 | structuredData: 10 | headings: [] 11 | contents: 12 | - content: Retrieve a specific participant by their ID 13 | --- 14 | 15 | {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} 16 | 17 | -------------------------------------------------------------------------------- /apps/refer/.env.example: -------------------------------------------------------------------------------- 1 | # RefRef Refer Server Environment Variables 2 | # ========================================== 3 | # Copy this file to .env and fill in your values 4 | 5 | # Database Configuration (REQUIRED) 6 | # PostgreSQL connection string 7 | # For Docker: use the default below 8 | # For local: update with your PostgreSQL credentials 9 | DATABASE_URL="postgresql://postgres:postgres@localhost:5432/refref" 10 | 11 | # Server Configuration (OPTIONAL) 12 | # Port for the refer server (default: 3002) 13 | PORT=3002 14 | 15 | # Host to bind to (default: 0.0.0.0) 16 | HOST="0.0.0.0" 17 | 18 | # Log level: trace, debug, info, warn, error, fatal (default: info) 19 | LOG_LEVEL="info" 20 | -------------------------------------------------------------------------------- /packages/refref-better-auth/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @refref/better-auth 3 | * 4 | * Better Auth integration for RefRef referral tracking. 5 | * Automatically tracks user signups with referral attribution. 6 | */ 7 | 8 | // Main plugin export 9 | export { refrefAnalytics } from "./plugin"; 10 | 11 | // Type exports 12 | export type { 13 | RefRefPluginOptions, 14 | SignupTrackingData, 15 | TrackingResponse, 16 | SignupTrackingPayload, 17 | } from "./types"; 18 | 19 | // Utility exports (for advanced usage) 20 | export { RefRefAPIClient } from "./utils/api-client"; 21 | export { 22 | extractRefcodeFromRequest, 23 | extractRefcodeFromContext, 24 | } from "./utils/cookie"; 25 | -------------------------------------------------------------------------------- /packages/attribution-script/src/types.ts: -------------------------------------------------------------------------------- 1 | export type AutoAttachMode = "false" | "data-refref" | "all"; 2 | 3 | /** 4 | * MDN-compliant cookie attributes 5 | * Accepts any cookie attribute as per MDN spec. 6 | * Only attributes with defaults are explicitly typed. 7 | * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie 8 | */ 9 | export interface CookieOptions extends Record { 10 | Path?: string; // Default: "/" 11 | "Max-Age"?: number; // Default: 7776000 (90 days in seconds) 12 | SameSite?: "Strict" | "Lax" | "None"; // Default: "Lax" 13 | } 14 | 15 | export interface FormElement extends HTMLFormElement { 16 | [key: string]: unknown; 17 | } 18 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/use-mobile.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const MOBILE_BREAKPOINT = 768; 4 | 5 | export function useIsMobile() { 6 | const [isMobile, setIsMobile] = React.useState( 7 | undefined, 8 | ); 9 | 10 | React.useEffect(() => { 11 | const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); 12 | const onChange = () => { 13 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); 14 | }; 15 | mql.addEventListener("change", onChange); 16 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); 17 | return () => mql.removeEventListener("change", onChange); 18 | }, []); 19 | 20 | return !!isMobile; 21 | } 22 | -------------------------------------------------------------------------------- /apps/webapp/src/app/(authenticated)/(core)/rewards/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { SiteHeader } from "@/components/site-header"; 4 | import { SiteBreadcrumbs } from "@/components/site-breadcrumbs"; 5 | import { RewardsTable } from "@/components/rewards-table/rewards-table"; 6 | 7 | export default function RewardsPage() { 8 | const breadcrumbs = [{ label: "Rewards", href: "/rewards" }]; 9 | 10 | return ( 11 | <> 12 | } /> 13 |
14 |
15 | 16 |
17 |
18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /apps/www/source.config.ts: -------------------------------------------------------------------------------- 1 | import { 2 | defineConfig, 3 | defineDocs, 4 | defineCollections, 5 | frontmatterSchema, 6 | } from "fumadocs-mdx/config"; 7 | import { z } from "zod"; 8 | 9 | export const { docs, meta } = defineDocs({ 10 | dir: "content/docs", 11 | }); 12 | 13 | export const blog = defineCollections({ 14 | type: "doc", 15 | dir: "content/blogs", 16 | async: true, 17 | schema: frontmatterSchema.extend({ 18 | author: z.string(), 19 | image: z.string(), 20 | date: z.string().date().or(z.date()).optional(), 21 | priority: z.number().default(0), 22 | }), 23 | }); 24 | 25 | export default defineConfig({ 26 | mdxOptions: { 27 | // MDX options 28 | }, 29 | }); 30 | -------------------------------------------------------------------------------- /apps/e2e/scripts/cleanup-ports.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Cleanup script to kill processes on test server ports 4 | # This ensures a clean state before running Playwright tests 5 | 6 | PORTS=(3000 3001 3002 3003 8787) 7 | 8 | echo "Cleaning up processes on test server ports..." 9 | 10 | for PORT in "${PORTS[@]}"; do 11 | echo -n " Port $PORT: " 12 | 13 | # Find PIDs using the port 14 | PIDS=$(lsof -ti :$PORT 2>/dev/null) 15 | 16 | if [ -z "$PIDS" ]; then 17 | echo "✓ Free" 18 | else 19 | # Kill the processes 20 | echo "$PIDS" | xargs kill -9 2>/dev/null 21 | echo "✓ Cleaned (killed PIDs: $PIDS)" 22 | fi 23 | done 24 | 25 | echo "" 26 | echo "All ports cleaned. Ready to run tests." 27 | -------------------------------------------------------------------------------- /apps/webapp/src/app/(authenticated)/(core)/activity/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { SiteHeader } from "@/components/site-header"; 4 | import { SiteBreadcrumbs } from "@/components/site-breadcrumbs"; 5 | import { ActivityTable } from "@/components/activity-table/activity-table"; 6 | 7 | export default function ActivityPage() { 8 | const breadcrumbs = [{ label: "Activity", href: "/activity" }]; 9 | 10 | return ( 11 | <> 12 | } /> 13 |
14 |
15 | 16 |
17 |
18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /apps/www/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import * as LabelPrimitive from "@radix-ui/react-label"; 5 | 6 | import { cn } from "@/lib/utils"; 7 | 8 | function Label({ 9 | className, 10 | ...props 11 | }: React.ComponentProps) { 12 | return ( 13 | 21 | ); 22 | } 23 | 24 | export { Label }; 25 | -------------------------------------------------------------------------------- /apps/webapp/src/app/(authenticated)/(core)/participants/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { SiteHeader } from "@/components/site-header"; 4 | import { SiteBreadcrumbs } from "@/components/site-breadcrumbs"; 5 | import { ParticipantsTable } from "@/components/participants-table/participants-table"; 6 | 7 | export default function ParticipantsPage() { 8 | const breadcrumbs = [{ label: "Participants", href: "/participants" }]; 9 | 10 | return ( 11 | <> 12 | } /> 13 |
14 |
15 | 16 |
17 |
18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /packages/ui/src/components/label.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import * as LabelPrimitive from "@radix-ui/react-label"; 5 | 6 | import { cn } from "@refref/ui/lib/utils"; 7 | 8 | function Label({ 9 | className, 10 | ...props 11 | }: React.ComponentProps) { 12 | return ( 13 | 21 | ); 22 | } 23 | 24 | export { Label }; 25 | -------------------------------------------------------------------------------- /packages/eslint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@refref/eslint-config", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "private": true, 6 | "exports": { 7 | "./base": "./base.js", 8 | "./next-js": "./next.js", 9 | "./react-internal": "./react-internal.js" 10 | }, 11 | "devDependencies": { 12 | "@eslint/js": "^9.20.0", 13 | "@next/eslint-plugin-next": "^15.1.6", 14 | "eslint": "^9.20.0", 15 | "eslint-config-prettier": "^10.0.1", 16 | "eslint-plugin-only-warn": "^1.1.0", 17 | "eslint-plugin-react": "^7.37.4", 18 | "eslint-plugin-react-hooks": "^5.1.0", 19 | "eslint-plugin-turbo": "^2.4.0", 20 | "globals": "^15.15.0", 21 | "typescript": "^5.9.2", 22 | "typescript-eslint": "^8.39.1" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /apps/webapp/instrumentation-client.ts: -------------------------------------------------------------------------------- 1 | import posthog from "posthog-js"; 2 | import { env } from "./src/env"; 3 | 4 | // Only initialize PostHog if key is present and enabled 5 | if (env.NEXT_PUBLIC_POSTHOG_KEY) { 6 | if (env.NEXT_PUBLIC_POSTHOG_ENABLED) { 7 | posthog.init(env.NEXT_PUBLIC_POSTHOG_KEY, { 8 | api_host: "/ingest", 9 | ui_host: "https://us.posthog.com", 10 | defaults: "2025-05-24", 11 | capture_exceptions: true, // This enables capturing exceptions using Error Tracking 12 | debug: process.env.NODE_ENV === "development", 13 | loaded: (ph) => { 14 | if (!env.NEXT_PUBLIC_POSTHOG_ENABLED) { 15 | ph.opt_out_capturing(); 16 | } 17 | }, 18 | }); 19 | } 20 | } 21 | 22 | export { posthog }; 23 | -------------------------------------------------------------------------------- /apps/webapp/src/app/(authenticated)/settings/organization/general/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { OrganizationSettingsCards } from "@daveyplate/better-auth-ui"; 4 | import { Separator } from "@refref/ui/components/separator"; 5 | 6 | export default function OrganizationGeneralSettings() { 7 | return ( 8 |
9 |
10 |

Organization

11 |

12 | Manage your organization information and settings 13 |

14 |
15 | 16 | 17 | 18 | 19 |
20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /apps/api/src/routes/openapi.ts: -------------------------------------------------------------------------------- 1 | import { FastifyInstance, FastifyRequest, FastifyReply } from "fastify"; 2 | import { readFileSync } from "node:fs"; 3 | import { join, dirname } from "node:path"; 4 | import { fileURLToPath } from "node:url"; 5 | 6 | const __filename = fileURLToPath(import.meta.url); 7 | const __dirname = dirname(__filename); 8 | 9 | // Read OpenAPI spec at module load time 10 | const openapiSpec = readFileSync( 11 | join(__dirname, "../../openapi.yaml"), 12 | "utf-8", 13 | ); 14 | 15 | export default async function openapiRoutes(fastify: FastifyInstance) { 16 | fastify.get("/openapi", openapiHandler); 17 | } 18 | 19 | async function openapiHandler(_request: FastifyRequest, reply: FastifyReply) { 20 | return reply.type("text/yaml").send(openapiSpec); 21 | } 22 | -------------------------------------------------------------------------------- /apps/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "ESNext", 5 | "lib": ["ES2022"], 6 | "moduleResolution": "bundler", 7 | "outDir": "./dist", 8 | "strict": true, 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "noImplicitReturns": true, 17 | "noFallthroughCasesInSwitch": true, 18 | "types": ["node", "@playwright/test"] 19 | }, 20 | "include": [ 21 | "sanity/**/*", 22 | "utils/**/*", 23 | "playwright.config.ts" 24 | ], 25 | "exclude": ["node_modules", "dist", "test-results"] 26 | } 27 | -------------------------------------------------------------------------------- /apps/www/lib/source.ts: -------------------------------------------------------------------------------- 1 | import { docs, meta, blog as blogPosts } from "@/.source"; 2 | import { createMDXSource } from "fumadocs-mdx"; 3 | import { loader } from "fumadocs-core/source"; 4 | import { attachFile, createOpenAPI } from "fumadocs-openapi/server"; 5 | import { icons } from "lucide-react"; 6 | import { createElement } from "react"; 7 | 8 | export const source = loader({ 9 | baseUrl: "/docs", 10 | icon(icon) { 11 | if (icon && icon in icons) 12 | return createElement(icons[icon as keyof typeof icons]); 13 | }, 14 | source: createMDXSource(docs, meta), 15 | pageTree: { 16 | attachFile, 17 | }, 18 | }); 19 | 20 | export const blog = loader({ 21 | baseUrl: "/blog", 22 | source: createMDXSource(blogPosts, meta), 23 | }); 24 | 25 | export const openapi = createOpenAPI(); 26 | -------------------------------------------------------------------------------- /packages/eslint-config/base.js: -------------------------------------------------------------------------------- 1 | import js from "@eslint/js"; 2 | import eslintConfigPrettier from "eslint-config-prettier"; 3 | import turboPlugin from "eslint-plugin-turbo"; 4 | import tseslint from "typescript-eslint"; 5 | import onlyWarn from "eslint-plugin-only-warn"; 6 | 7 | /** 8 | * A shared ESLint configuration for the repository. 9 | * 10 | * @type {import("eslint").Linter.Config} 11 | * */ 12 | export const config = [ 13 | js.configs.recommended, 14 | eslintConfigPrettier, 15 | ...tseslint.configs.recommended, 16 | { 17 | plugins: { 18 | turbo: turboPlugin, 19 | }, 20 | rules: { 21 | "turbo/no-undeclared-env-vars": "warn", 22 | }, 23 | }, 24 | { 25 | plugins: { 26 | onlyWarn, 27 | }, 28 | }, 29 | { 30 | ignores: ["dist/**"], 31 | }, 32 | ]; 33 | -------------------------------------------------------------------------------- /apps/webapp/src/trpc/query-client.ts: -------------------------------------------------------------------------------- 1 | import { 2 | defaultShouldDehydrateQuery, 3 | QueryClient, 4 | } from "@tanstack/react-query"; 5 | import SuperJSON from "superjson"; 6 | 7 | export const createQueryClient = () => 8 | new QueryClient({ 9 | defaultOptions: { 10 | queries: { 11 | // With SSR, we usually want to set some default staleTime 12 | // above 0 to avoid refetching immediately on the client 13 | staleTime: 30 * 1000, 14 | }, 15 | dehydrate: { 16 | serializeData: SuperJSON.serialize, 17 | shouldDehydrateQuery: (query) => 18 | defaultShouldDehydrateQuery(query) || 19 | query.state.status === "pending", 20 | }, 21 | hydrate: { 22 | deserializeData: SuperJSON.deserialize, 23 | }, 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /apps/e2e/sanity/pages/base-page.ts: -------------------------------------------------------------------------------- 1 | import { Page } from "@playwright/test"; 2 | 3 | /** 4 | * Base page class that all page objects extend 5 | * Provides common functionality for page interactions 6 | */ 7 | export class BasePage { 8 | constructor(protected page: Page) {} 9 | 10 | /** 11 | * Navigate to a specific path 12 | */ 13 | async goto(path: string) { 14 | await this.page.goto(path); 15 | } 16 | 17 | /** 18 | * Wait for the page to be fully loaded 19 | */ 20 | async waitForPageLoad() { 21 | await this.page.waitForLoadState("networkidle"); 22 | } 23 | 24 | /** 25 | * Take a screenshot (useful for debugging) 26 | */ 27 | async screenshot(name: string) { 28 | await this.page.screenshot({ 29 | path: `test-results/screenshots/${name}.png`, 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /apps/webapp/src/app/(authenticated)/settings/product/secrets/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Separator } from "@refref/ui/components/separator"; 4 | import { ProductSecretsCard } from "@/components/settings/product/product-secrets-card"; 5 | 6 | export default function ProductSecretsSettings() { 7 | return ( 8 |
9 |
10 |

Secrets

11 |

12 | View your product credentials for API integration 13 |

14 |
15 | 16 | 17 | 18 |
19 | 20 |
21 |
22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /apps/www/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | 5 | function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { 6 | return ( 7 |