create-pilotprojects-app 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/dist/helpers/copy.js +32 -0
  2. package/dist/helpers/install.js +18 -0
  3. package/dist/helpers/package-json.js +25 -0
  4. package/dist/index.js +54 -0
  5. package/dist/prompts.js +75 -0
  6. package/dist/scaffold.js +84 -0
  7. package/dist/types.js +1 -0
  8. package/package.json +39 -0
  9. package/templates/apps/mobile/.env.example +15 -0
  10. package/templates/apps/mobile/app/(auth)/login.tsx +86 -0
  11. package/templates/apps/mobile/app/(tabs)/_layout.tsx +10 -0
  12. package/templates/apps/mobile/app/(tabs)/index.tsx +30 -0
  13. package/templates/apps/mobile/app/_layout.tsx +58 -0
  14. package/templates/apps/mobile/app.config.ts +73 -0
  15. package/templates/apps/mobile/babel.config.js +9 -0
  16. package/templates/apps/mobile/eas.json +48 -0
  17. package/templates/apps/mobile/global.css +44 -0
  18. package/templates/apps/mobile/lib/supabase.ts +15 -0
  19. package/templates/apps/mobile/lib/trpc/client.ts +30 -0
  20. package/templates/apps/mobile/package.json +48 -0
  21. package/templates/apps/mobile/tsconfig.json +16 -0
  22. package/templates/apps/web/.env.development.example +22 -0
  23. package/templates/apps/web/app/(auth)/login/page.tsx +102 -0
  24. package/templates/apps/web/app/(dashboard)/dashboard/page.tsx +21 -0
  25. package/templates/apps/web/app/(dashboard)/layout.tsx +14 -0
  26. package/templates/apps/web/app/api/trpc/[trpc]/route.ts +32 -0
  27. package/templates/apps/web/app/globals.css +51 -0
  28. package/templates/apps/web/app/layout.tsx +25 -0
  29. package/templates/apps/web/lib/trpc/client.tsx +7 -0
  30. package/templates/apps/web/lib/trpc/provider.tsx +37 -0
  31. package/templates/apps/web/lib/trpc/server.ts +20 -0
  32. package/templates/apps/web/middleware.ts +10 -0
  33. package/templates/apps/web/package.json +44 -0
  34. package/templates/apps/web/postcss.config.js +6 -0
  35. package/templates/apps/web/sentry.client.config.ts +10 -0
  36. package/templates/apps/web/sentry.edge.config.ts +6 -0
  37. package/templates/apps/web/sentry.server.config.ts +7 -0
  38. package/templates/apps/web/tailwind.config.ts +12 -0
  39. package/templates/apps/web/tsconfig.json +16 -0
  40. package/templates/apps/web/types/css.d.ts +1 -0
  41. package/templates/base/.prettierrc.js +9 -0
  42. package/templates/base/_gitignore +30 -0
  43. package/templates/base/package.json +30 -0
  44. package/templates/base/turbo.json +33 -0
  45. package/templates/packages/api/package.json +23 -0
  46. package/templates/packages/api/src/features/auth/auth.router.ts +8 -0
  47. package/templates/packages/api/src/features/auth/auth.schema.ts +9 -0
  48. package/templates/packages/api/src/features/auth/auth.service.ts +24 -0
  49. package/templates/packages/api/src/features/user/user.router.ts +21 -0
  50. package/templates/packages/api/src/features/user/user.schema.ts +13 -0
  51. package/templates/packages/api/src/features/user/user.service.ts +41 -0
  52. package/templates/packages/api/src/index.ts +9 -0
  53. package/templates/packages/api/src/root.ts +10 -0
  54. package/templates/packages/api/src/trpc.ts +42 -0
  55. package/templates/packages/api/tsconfig.json +4 -0
  56. package/templates/packages/auth/package.json +26 -0
  57. package/templates/packages/auth/src/client.ts +8 -0
  58. package/templates/packages/auth/src/index.ts +3 -0
  59. package/templates/packages/auth/src/middleware.ts +25 -0
  60. package/templates/packages/auth/src/server.ts +15 -0
  61. package/templates/packages/auth/tsconfig.json +4 -0
  62. package/templates/packages/config/eslint/base.js +28 -0
  63. package/templates/packages/config/eslint/nextjs.js +10 -0
  64. package/templates/packages/config/eslint/react-native.js +18 -0
  65. package/templates/packages/config/package.json +13 -0
  66. package/templates/packages/config/typescript/base.json +17 -0
  67. package/templates/packages/config/typescript/nextjs.json +18 -0
  68. package/templates/packages/config/typescript/react-native.json +11 -0
  69. package/templates/packages/db/.env.example +1 -0
  70. package/templates/packages/db/drizzle.config.ts +13 -0
  71. package/templates/packages/db/package.json +28 -0
  72. package/templates/packages/db/src/index.ts +14 -0
  73. package/templates/packages/db/src/schema/index.ts +1 -0
  74. package/templates/packages/db/src/schema/users.ts +13 -0
  75. package/templates/packages/db/tsconfig.json +4 -0
  76. package/templates/packages/email/package.json +23 -0
  77. package/templates/packages/email/src/index.ts +2 -0
  78. package/templates/packages/email/src/resend.ts +8 -0
  79. package/templates/packages/email/src/templates/welcome.tsx +54 -0
  80. package/templates/packages/email/tsconfig.json +8 -0
  81. package/templates/packages/ui/package.json +38 -0
  82. package/templates/packages/ui/src/lib/utils.ts +6 -0
  83. package/templates/packages/ui/src/native/button.tsx +58 -0
  84. package/templates/packages/ui/src/native/card.tsx +41 -0
  85. package/templates/packages/ui/src/native/input.tsx +24 -0
  86. package/templates/packages/ui/src/native.d.ts +24 -0
  87. package/templates/packages/ui/src/tailwind-preset.ts +50 -0
  88. package/templates/packages/ui/src/web/button.tsx +49 -0
  89. package/templates/packages/ui/src/web/card.tsx +51 -0
  90. package/templates/packages/ui/src/web/input.tsx +22 -0
  91. package/templates/packages/ui/tsconfig.json +8 -0
  92. package/templates/packages/validators/package.json +20 -0
  93. package/templates/packages/validators/src/auth.ts +15 -0
  94. package/templates/packages/validators/src/index.ts +2 -0
  95. package/templates/packages/validators/src/user.ts +8 -0
  96. package/templates/packages/validators/tsconfig.json +4 -0
@@ -0,0 +1,44 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ :root {
6
+ --background: #ffffff;
7
+ --foreground: #0f172a;
8
+ --card: #ffffff;
9
+ --card-foreground: #0f172a;
10
+ --primary: #3b82f6;
11
+ --primary-foreground: #f8fafc;
12
+ --secondary: #f1f5f9;
13
+ --secondary-foreground: #1e293b;
14
+ --muted: #f1f5f9;
15
+ --muted-foreground: #64748b;
16
+ --accent: #f1f5f9;
17
+ --accent-foreground: #1e293b;
18
+ --destructive: #ef4444;
19
+ --destructive-foreground: #f8fafc;
20
+ --border: #e2e8f0;
21
+ --input: #e2e8f0;
22
+ --ring: #3b82f6;
23
+ --radius: 6px;
24
+ }
25
+
26
+ .dark {
27
+ --background: #0f172a;
28
+ --foreground: #f8fafc;
29
+ --card: #0f172a;
30
+ --card-foreground: #f8fafc;
31
+ --primary: #60a5fa;
32
+ --primary-foreground: #1e293b;
33
+ --secondary: #1e293b;
34
+ --secondary-foreground: #f8fafc;
35
+ --muted: #1e293b;
36
+ --muted-foreground: #94a3b8;
37
+ --accent: #1e293b;
38
+ --accent-foreground: #f8fafc;
39
+ --destructive: #7f1d1d;
40
+ --destructive-foreground: #f8fafc;
41
+ --border: #1e293b;
42
+ --input: #1e293b;
43
+ --ring: #1d4ed8;
44
+ }
@@ -0,0 +1,15 @@
1
+ import { createClient } from "@supabase/supabase-js";
2
+ import AsyncStorage from "@react-native-async-storage/async-storage";
3
+
4
+ export const supabase = createClient(
5
+ process.env.EXPO_PUBLIC_SUPABASE_URL!,
6
+ process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY!,
7
+ {
8
+ auth: {
9
+ storage: AsyncStorage,
10
+ autoRefreshToken: true,
11
+ persistSession: true,
12
+ detectSessionInUrl: false,
13
+ },
14
+ },
15
+ );
@@ -0,0 +1,30 @@
1
+ import { createTRPCReact } from "@trpc/react-query";
2
+ import { createTRPCClient, httpBatchLink } from "@trpc/client";
3
+ import superjson from "superjson";
4
+
5
+ import type { AppRouter } from "{{PACKAGE_SCOPE}}/api";
6
+
7
+ import { supabase } from "../supabase";
8
+
9
+ // Used for hooks: trpc.user.me.useQuery() etc.
10
+ export const trpc = createTRPCReact<AppRouter>();
11
+
12
+ // Used to create the underlying client passed to TRPCProvider
13
+ export function makeTRPCClient() {
14
+ return createTRPCClient<AppRouter>({
15
+ links: [
16
+ httpBatchLink({
17
+ url: `${process.env.EXPO_PUBLIC_API_URL}/api/trpc`,
18
+ transformer: superjson,
19
+ async headers() {
20
+ const {
21
+ data: { session },
22
+ } = await supabase.auth.getSession();
23
+ return session?.access_token
24
+ ? { Authorization: `Bearer ${session.access_token}` }
25
+ : {};
26
+ },
27
+ }),
28
+ ],
29
+ });
30
+ }
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@{{PACKAGE_SCOPE_SAFE}}/mobile",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "main": "expo-router/entry",
6
+ "scripts": {
7
+ "dev": "expo start",
8
+ "android": "expo start --android",
9
+ "ios": "expo start --ios",
10
+ "build:dev": "eas build --profile development --platform all",
11
+ "build:uat": "eas build --profile uat --platform all",
12
+ "build:production": "eas build --profile production --platform all",
13
+ "update:uat": "eas update --channel uat",
14
+ "update:production": "eas update --channel production",
15
+ "lint": "eslint . --ext .ts,.tsx",
16
+ "type-check": "tsc --noEmit"
17
+ },
18
+ "dependencies": {
19
+ "{{PACKAGE_SCOPE}}/api": "workspace:*",
20
+ "{{PACKAGE_SCOPE}}/auth": "workspace:*",
21
+ "{{PACKAGE_SCOPE}}/ui": "workspace:*",
22
+ "{{PACKAGE_SCOPE}}/validators": "workspace:*",
23
+ "@supabase/supabase-js": "^2.45.0",
24
+ "@react-native-async-storage/async-storage": "^2.0.0",
25
+ "@tanstack/react-query": "^5.56.0",
26
+ "@trpc/client": "^11.0.0",
27
+ "@trpc/react-query": "^11.0.0",
28
+ "@sentry/react-native": "^5.26.0",
29
+ "expo": "~52.0.0",
30
+ "expo-apple-authentication": "^7.1.0",
31
+ "expo-font": "~13.0.0",
32
+ "expo-router": "~4.0.0",
33
+ "expo-status-bar": "~2.0.0",
34
+ "nativewind": "~4.1.0",
35
+ "posthog-react-native": "^3.2.0",
36
+ "react": "18.3.1",
37
+ "react-native": "0.76.0",
38
+ "superjson": "^2.2.0",
39
+ "zod": "^3.23.0"
40
+ },
41
+ "devDependencies": {
42
+ "@babel/core": "^7.24.0",
43
+ "@types/react": "~18.3.0",
44
+ "eslint": "^8.57.0",
45
+ "tailwindcss": "^3.4.0",
46
+ "typescript": "^5.5.0"
47
+ }
48
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "extends": "{{PACKAGE_SCOPE}}/config/typescript/react-native",
3
+ "compilerOptions": {
4
+ "paths": {
5
+ "@/*": ["./*"]
6
+ }
7
+ },
8
+ "include": [
9
+ "**/*.ts",
10
+ "**/*.tsx",
11
+ ".expo/types/**/*.ts",
12
+ "expo-env.d.ts",
13
+ "nativewind-env.d.ts"
14
+ ],
15
+ "exclude": ["node_modules"]
16
+ }
@@ -0,0 +1,22 @@
1
+ # Supabase (development project)
2
+ DATABASE_URL=postgresql://postgres:postgres@localhost:54322/postgres
3
+ SUPABASE_URL=http://localhost:54321
4
+ SUPABASE_ANON_KEY=
5
+ SUPABASE_SERVICE_ROLE_KEY=
6
+ NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
7
+ NEXT_PUBLIC_SUPABASE_ANON_KEY=
8
+
9
+ # Sentry (optional — leave empty to disable)
10
+ SENTRY_DSN=
11
+ SENTRY_AUTH_TOKEN=
12
+ NEXT_PUBLIC_SENTRY_DSN=
13
+
14
+ # PostHog (optional)
15
+ NEXT_PUBLIC_POSTHOG_KEY=
16
+ POSTHOG_KEY=
17
+
18
+ # Google Analytics (optional)
19
+ NEXT_PUBLIC_GA_MEASUREMENT_ID=
20
+
21
+ # App
22
+ APP_URL=http://localhost:3000
@@ -0,0 +1,102 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import { useRouter } from "next/navigation";
5
+
6
+ import { createBrowserClient } from "{{PACKAGE_SCOPE}}/auth/client";
7
+ import { Button } from "{{PACKAGE_SCOPE}}/ui/web/button";
8
+ import { Input } from "{{PACKAGE_SCOPE}}/ui/web/input";
9
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "{{PACKAGE_SCOPE}}/ui/web/card";
10
+
11
+ export default function LoginPage() {
12
+ const router = useRouter();
13
+ const supabase = createBrowserClient();
14
+
15
+ const [email, setEmail] = useState("");
16
+ const [password, setPassword] = useState("");
17
+ const [error, setError] = useState<string | null>(null);
18
+ const [loading, setLoading] = useState(false);
19
+
20
+ async function handleLogin(e: React.FormEvent) {
21
+ e.preventDefault();
22
+ setLoading(true);
23
+ setError(null);
24
+
25
+ const { error } = await supabase.auth.signInWithPassword({ email, password });
26
+
27
+ if (error) {
28
+ setError(error.message);
29
+ setLoading(false);
30
+ return;
31
+ }
32
+
33
+ router.push("/dashboard");
34
+ }
35
+
36
+ return (
37
+ <div className="flex min-h-screen flex-col items-center justify-center bg-muted/40 px-4">
38
+ <div className="mb-8 flex flex-col items-center gap-2">
39
+ <div className="flex h-12 w-12 items-center justify-center rounded-xl bg-primary text-lg font-bold text-primary-foreground">
40
+ A
41
+ </div>
42
+ <span className="text-xl font-semibold text-foreground">{{PROJECT_NAME}}</span>
43
+ </div>
44
+
45
+ <Card className="w-full max-w-sm shadow-md">
46
+ <CardHeader className="space-y-1 pb-4">
47
+ <CardTitle className="text-xl">Welcome back</CardTitle>
48
+ <CardDescription>Sign in to your account to continue</CardDescription>
49
+ </CardHeader>
50
+ <CardContent>
51
+ <form onSubmit={handleLogin} className="flex flex-col gap-5">
52
+ <div className="flex flex-col gap-1.5" suppressHydrationWarning>
53
+ <label htmlFor="email" className="text-sm font-medium text-foreground">
54
+ Email
55
+ </label>
56
+ <Input
57
+ id="email"
58
+ type="email"
59
+ placeholder="you@example.com"
60
+ value={email}
61
+ onChange={(e) => setEmail(e.target.value)}
62
+ required
63
+ />
64
+ </div>
65
+
66
+ <div className="flex flex-col gap-1.5" suppressHydrationWarning>
67
+ <div className="flex items-center justify-between">
68
+ <label htmlFor="password" className="text-sm font-medium text-foreground">
69
+ Password
70
+ </label>
71
+ <a href="/forgot-password" className="text-xs text-primary hover:underline">
72
+ Forgot password?
73
+ </a>
74
+ </div>
75
+ <Input
76
+ id="password"
77
+ type="password"
78
+ placeholder="••••••••"
79
+ value={password}
80
+ onChange={(e) => setPassword(e.target.value)}
81
+ required
82
+ />
83
+ </div>
84
+
85
+ {error && <p className="text-sm text-destructive">{error}</p>}
86
+
87
+ <Button type="submit" size="lg" className="w-full" disabled={loading}>
88
+ {loading ? "Signing in…" : "Sign in"}
89
+ </Button>
90
+ </form>
91
+ </CardContent>
92
+ </Card>
93
+
94
+ <p className="mt-6 text-sm text-muted-foreground">
95
+ Don&apos;t have an account?{" "}
96
+ <a href="/register" className="font-medium text-primary hover:underline">
97
+ Sign up
98
+ </a>
99
+ </p>
100
+ </div>
101
+ );
102
+ }
@@ -0,0 +1,21 @@
1
+ import { api } from "@/lib/trpc/server";
2
+ import { Card, CardContent, CardHeader, CardTitle } from "{{PACKAGE_SCOPE}}/ui/web/card";
3
+
4
+ export default async function DashboardPage() {
5
+ const user = await api.user.me();
6
+
7
+ return (
8
+ <main className="container mx-auto p-8">
9
+ <Card className="max-w-md">
10
+ <CardHeader>
11
+ <CardTitle>Welcome back</CardTitle>
12
+ </CardHeader>
13
+ <CardContent>
14
+ <p className="text-muted-foreground">
15
+ {user.displayName ?? user.email}
16
+ </p>
17
+ </CardContent>
18
+ </Card>
19
+ </main>
20
+ );
21
+ }
@@ -0,0 +1,14 @@
1
+ import { redirect } from "next/navigation";
2
+ import { cookies } from "next/headers";
3
+
4
+ import { createServerClient } from "{{PACKAGE_SCOPE}}/auth/server";
5
+
6
+ export default async function DashboardLayout({ children }: { children: React.ReactNode }) {
7
+ const cookieStore = await cookies();
8
+ const supabase = createServerClient(cookieStore);
9
+ const { data: { user } } = await supabase.auth.getUser();
10
+
11
+ if (!user) redirect("/login");
12
+
13
+ return <>{children}</>;
14
+ }
@@ -0,0 +1,32 @@
1
+ import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
2
+ import { cookies } from "next/headers";
3
+
4
+ import { appRouter } from "{{PACKAGE_SCOPE}}/api";
5
+ import { db } from "{{PACKAGE_SCOPE}}/db";
6
+ import { createServerClient } from "{{PACKAGE_SCOPE}}/auth/server";
7
+
8
+ async function createContext() {
9
+ const cookieStore = await cookies();
10
+ const supabase = createServerClient(cookieStore);
11
+ const { data: { session } } = await supabase.auth.getSession();
12
+
13
+ return {
14
+ db,
15
+ session: session ?? null,
16
+ user: session?.user ?? null,
17
+ };
18
+ }
19
+
20
+ const handler = (req: Request) =>
21
+ fetchRequestHandler({
22
+ endpoint: "/api/trpc",
23
+ req,
24
+ router: appRouter,
25
+ createContext,
26
+ onError:
27
+ process.env.NODE_ENV === "development"
28
+ ? ({ error }) => console.error("tRPC error:", error)
29
+ : undefined,
30
+ });
31
+
32
+ export { handler as GET, handler as POST };
@@ -0,0 +1,51 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ @layer base {
6
+ :root {
7
+ --background: 0 0% 100%;
8
+ --foreground: 222.2 84% 4.9%;
9
+ --card: 0 0% 100%;
10
+ --card-foreground: 222.2 84% 4.9%;
11
+ --primary: 221.2 83.2% 53.3%;
12
+ --primary-foreground: 210 40% 98%;
13
+ --secondary: 210 40% 96.1%;
14
+ --secondary-foreground: 222.2 47.4% 11.2%;
15
+ --muted: 210 40% 96.1%;
16
+ --muted-foreground: 215.4 16.3% 46.9%;
17
+ --accent: 210 40% 96.1%;
18
+ --accent-foreground: 222.2 47.4% 11.2%;
19
+ --destructive: 0 84.2% 60.2%;
20
+ --destructive-foreground: 210 40% 98%;
21
+ --border: 214.3 31.8% 91.4%;
22
+ --input: 214.3 31.8% 91.4%;
23
+ --ring: 221.2 83.2% 53.3%;
24
+ --radius: 0.5rem;
25
+ }
26
+
27
+ .dark {
28
+ --background: 222.2 84% 4.9%;
29
+ --foreground: 210 40% 98%;
30
+ --card: 222.2 84% 4.9%;
31
+ --card-foreground: 210 40% 98%;
32
+ --primary: 217.2 91.2% 59.8%;
33
+ --primary-foreground: 222.2 47.4% 11.2%;
34
+ --secondary: 217.2 32.6% 17.5%;
35
+ --secondary-foreground: 210 40% 98%;
36
+ --muted: 217.2 32.6% 17.5%;
37
+ --muted-foreground: 215 20.2% 65.1%;
38
+ --accent: 217.2 32.6% 17.5%;
39
+ --accent-foreground: 210 40% 98%;
40
+ --destructive: 0 62.8% 30.6%;
41
+ --destructive-foreground: 210 40% 98%;
42
+ --border: 217.2 32.6% 17.5%;
43
+ --input: 217.2 32.6% 17.5%;
44
+ --ring: 224.3 76.3% 48%;
45
+ }
46
+ }
47
+
48
+ @layer base {
49
+ * { @apply border-border; }
50
+ body { @apply bg-background text-foreground; }
51
+ }
@@ -0,0 +1,25 @@
1
+ import type { Metadata } from "next";
2
+ import { Inter } from "next/font/google";
3
+ import { ThemeProvider } from "next-themes";
4
+
5
+ import { TRPCProvider } from "@/lib/trpc/provider";
6
+ import "./globals.css";
7
+
8
+ const inter = Inter({ subsets: ["latin"], variable: "--font-sans" });
9
+
10
+ export const metadata: Metadata = {
11
+ title: "{{PROJECT_NAME}}",
12
+ description: "Built with the Pilotprojects monorepo boilerplate",
13
+ };
14
+
15
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
16
+ return (
17
+ <html lang="en" suppressHydrationWarning>
18
+ <body className={`${inter.variable} font-sans antialiased`}>
19
+ <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
20
+ <TRPCProvider>{children}</TRPCProvider>
21
+ </ThemeProvider>
22
+ </body>
23
+ </html>
24
+ );
25
+ }
@@ -0,0 +1,7 @@
1
+ "use client";
2
+
3
+ import { createTRPCReact } from "@trpc/react-query";
4
+
5
+ import type { AppRouter } from "{{PACKAGE_SCOPE}}/api";
6
+
7
+ export const trpc = createTRPCReact<AppRouter>();
@@ -0,0 +1,37 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
5
+ import { httpBatchLink } from "@trpc/client";
6
+ import superjson from "superjson";
7
+
8
+ import { trpc } from "./client";
9
+
10
+ function getBaseUrl() {
11
+ if (typeof window !== "undefined") return "";
12
+ if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`;
13
+ return `http://localhost:${process.env.PORT ?? 3000}`;
14
+ }
15
+
16
+ export function TRPCProvider({ children }: { children: React.ReactNode }) {
17
+ const [queryClient] = useState(
18
+ () => new QueryClient({ defaultOptions: { queries: { staleTime: 60_000 } } }),
19
+ );
20
+
21
+ const [trpcClient] = useState(() =>
22
+ trpc.createClient({
23
+ links: [
24
+ httpBatchLink({
25
+ url: `${getBaseUrl()}/api/trpc`,
26
+ transformer: superjson,
27
+ }),
28
+ ],
29
+ }),
30
+ );
31
+
32
+ return (
33
+ <trpc.Provider client={trpcClient} queryClient={queryClient}>
34
+ <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
35
+ </trpc.Provider>
36
+ );
37
+ }
@@ -0,0 +1,20 @@
1
+ import { createCallerFactory } from "@trpc/server";
2
+ import { cookies } from "next/headers";
3
+
4
+ import { appRouter } from "{{PACKAGE_SCOPE}}/api";
5
+ import { db } from "{{PACKAGE_SCOPE}}/db";
6
+ import { createServerClient } from "{{PACKAGE_SCOPE}}/auth/server";
7
+
8
+ const createCaller = createCallerFactory(appRouter);
9
+
10
+ export const api = createCaller(async () => {
11
+ const cookieStore = await cookies();
12
+ const supabase = createServerClient(cookieStore);
13
+ const { data: { session } } = await supabase.auth.getSession();
14
+
15
+ return {
16
+ db,
17
+ session: session ?? null,
18
+ user: session?.user ?? null,
19
+ };
20
+ });
@@ -0,0 +1,10 @@
1
+ import { updateSession } from "{{PACKAGE_SCOPE}}/auth/middleware";
2
+ import type { NextRequest } from "next/server";
3
+
4
+ export async function middleware(request: NextRequest) {
5
+ return updateSession(request);
6
+ }
7
+
8
+ export const config = {
9
+ matcher: ["/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)"],
10
+ };
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@{{PACKAGE_SCOPE_SAFE}}/web",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "build": "next build",
7
+ "dev": "next dev --turbo",
8
+ "lint": "next lint",
9
+ "type-check": "tsc --noEmit",
10
+ "start": "next start"
11
+ },
12
+ "dependencies": {
13
+ "{{PACKAGE_SCOPE}}/api": "workspace:*",
14
+ "{{PACKAGE_SCOPE}}/auth": "workspace:*",
15
+ "{{PACKAGE_SCOPE}}/ui": "workspace:*",
16
+ "{{PACKAGE_SCOPE}}/validators": "workspace:*",
17
+ "@supabase/supabase-js": "^2.45.0",
18
+ "@supabase/ssr": "^0.5.0",
19
+ "@tanstack/react-query": "^5.56.0",
20
+ "@trpc/client": "^11.0.0",
21
+ "@trpc/react-query": "^11.0.0",
22
+ "@trpc/server": "^11.0.0",
23
+ "@sentry/nextjs": "^8.30.0",
24
+ "next": "15.0.0",
25
+ "posthog-js": "^1.161.0",
26
+ "posthog-node": "^4.2.0",
27
+ "react": "^18.3.0",
28
+ "react-dom": "^18.3.0",
29
+ "superjson": "^2.2.0",
30
+ "zod": "^3.23.0",
31
+ "@next/third-parties": "^14.2.0"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^20.0.0",
35
+ "@types/react": "^18.3.0",
36
+ "@types/react-dom": "^18.3.0",
37
+ "eslint": "^8.57.0",
38
+ "eslint-config-next": "15.0.0",
39
+ "tailwindcss": "^3.4.0",
40
+ "autoprefixer": "^10.4.0",
41
+ "postcss": "^8.4.0",
42
+ "typescript": "^5.5.0"
43
+ }
44
+ }
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ };
@@ -0,0 +1,10 @@
1
+ import * as Sentry from "@sentry/nextjs";
2
+
3
+ Sentry.init({
4
+ dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
5
+ environment: process.env.NODE_ENV,
6
+ tracesSampleRate: process.env.NODE_ENV === "production" ? 0.2 : 1.0,
7
+ replaysSessionSampleRate: 0.1,
8
+ replaysOnErrorSampleRate: 1.0,
9
+ integrations: [Sentry.replayIntegration()],
10
+ });
@@ -0,0 +1,6 @@
1
+ import * as Sentry from "@sentry/nextjs";
2
+
3
+ Sentry.init({
4
+ dsn: process.env.SENTRY_DSN,
5
+ tracesSampleRate: 0.1,
6
+ });
@@ -0,0 +1,7 @@
1
+ import * as Sentry from "@sentry/nextjs";
2
+
3
+ Sentry.init({
4
+ dsn: process.env.SENTRY_DSN,
5
+ environment: process.env.NODE_ENV,
6
+ tracesSampleRate: process.env.NODE_ENV === "production" ? 0.2 : 1.0,
7
+ });
@@ -0,0 +1,12 @@
1
+ import { preset } from "{{PACKAGE_SCOPE}}/ui/tailwind-preset";
2
+ import type { Config } from "tailwindcss";
3
+
4
+ export default {
5
+ presets: [preset],
6
+ content: [
7
+ "./app/**/*.{ts,tsx}",
8
+ "./components/**/*.{ts,tsx}",
9
+ "../../packages/ui/src/web/**/*.{ts,tsx}",
10
+ ],
11
+ plugins: [require("tailwindcss-animate")],
12
+ } satisfies Config;
@@ -0,0 +1,16 @@
1
+ {
2
+ "extends": "{{PACKAGE_SCOPE}}/config/typescript/nextjs",
3
+ "compilerOptions": {
4
+ "paths": {
5
+ "@/*": ["./*"]
6
+ },
7
+ "noEmit": true
8
+ },
9
+ "include": [
10
+ "next-env.d.ts",
11
+ "**/*.ts",
12
+ "**/*.tsx",
13
+ ".next/types/**/*.ts"
14
+ ],
15
+ "exclude": ["node_modules"]
16
+ }
@@ -0,0 +1 @@
1
+ declare module '*.css';
@@ -0,0 +1,9 @@
1
+ /** @type {import("prettier").Config} */
2
+ module.exports = {
3
+ semi: true,
4
+ singleQuote: false,
5
+ tabWidth: 2,
6
+ trailingComma: "all",
7
+ printWidth: 100,
8
+ plugins: ["prettier-plugin-tailwindcss"],
9
+ };
@@ -0,0 +1,30 @@
1
+ # Dependencies
2
+ node_modules/
3
+ .pnp
4
+ .pnp.js
5
+
6
+ # Build outputs
7
+ dist/
8
+ .next/
9
+ out/
10
+
11
+ # Environment variables
12
+ .env
13
+ .env.local
14
+ .env.development
15
+ .env.uat
16
+ .env.production
17
+ !.env.*.example
18
+
19
+ # Turbo
20
+ .turbo/
21
+
22
+ # Expo
23
+ .expo/
24
+ apps/mobile/android/
25
+ apps/mobile/ios/
26
+
27
+ # Misc
28
+ .DS_Store
29
+ *.pem
30
+ coverage/