create-croissant 0.1.57 → 0.1.59

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 (74) hide show
  1. package/package.json +2 -1
  2. package/template/apps/platform/package.json +1 -0
  3. package/template/apps/platform/src/components/access-denied.tsx +32 -0
  4. package/template/apps/platform/src/components/app-sidebar.tsx +30 -50
  5. package/template/apps/platform/src/lib/auth-utils.ts +17 -3
  6. package/template/apps/platform/src/routes/__root.tsx +1 -1
  7. package/template/apps/platform/src/routes/_auth/account.tsx +7 -9
  8. package/template/apps/platform/src/routes/_auth/dashboard.tsx +8 -7
  9. package/template/apps/platform/src/routes/_auth/examples/client-orpc-auth.tsx +6 -9
  10. package/template/apps/platform/src/routes/_auth/examples/ssr-orpc-auth.tsx +8 -9
  11. package/template/apps/platform/src/routes/_auth.tsx +2 -2
  12. package/template/apps/platform/src/routes/_public.tsx +2 -2
  13. package/template/apps/platform/src/routes/api/auth/$.ts +25 -15
  14. package/template/apps/platform/src/routes/api/rpc.$.ts +15 -8
  15. package/template/docker-compose.yml +1 -3
  16. package/template/package.json +1 -12
  17. package/template/packages/auth/package.json +2 -2
  18. package/template/packages/auth/src/lib/auth.ts +10 -0
  19. package/template/apps/desktop/.vscode/extensions.json +0 -3
  20. package/template/apps/desktop/README.md +0 -7
  21. package/template/apps/desktop/index.html +0 -14
  22. package/template/apps/desktop/package.json +0 -40
  23. package/template/apps/desktop/public/tauri.svg +0 -6
  24. package/template/apps/desktop/public/vite.svg +0 -1
  25. package/template/apps/desktop/src/App.css +0 -116
  26. package/template/apps/desktop/src/App.tsx +0 -51
  27. package/template/apps/desktop/src/assets/react.svg +0 -1
  28. package/template/apps/desktop/src/components/app-sidebar.tsx +0 -186
  29. package/template/apps/desktop/src/components/login-form.tsx +0 -160
  30. package/template/apps/desktop/src/components/search-form.tsx +0 -19
  31. package/template/apps/desktop/src/components/signup-form.tsx +0 -206
  32. package/template/apps/desktop/src/components/version-switcher.tsx +0 -54
  33. package/template/apps/desktop/src/env.d.ts +0 -1
  34. package/template/apps/desktop/src/lib/auth-client.ts +0 -5
  35. package/template/apps/desktop/src/lib/orpc.ts +0 -10
  36. package/template/apps/desktop/src/main.tsx +0 -12
  37. package/template/apps/desktop/src/routeTree.gen.ts +0 -240
  38. package/template/apps/desktop/src/router.tsx +0 -19
  39. package/template/apps/desktop/src/routes/__root.tsx +0 -52
  40. package/template/apps/desktop/src/routes/_auth/account.tsx +0 -275
  41. package/template/apps/desktop/src/routes/_auth/dashboard.tsx +0 -58
  42. package/template/apps/desktop/src/routes/_auth/examples/client-orpc-auth.tsx +0 -46
  43. package/template/apps/desktop/src/routes/_auth.tsx +0 -23
  44. package/template/apps/desktop/src/routes/_public/examples/client-orpc.tsx +0 -330
  45. package/template/apps/desktop/src/routes/_public/index.tsx +0 -66
  46. package/template/apps/desktop/src/routes/_public/login.tsx +0 -34
  47. package/template/apps/desktop/src/routes/_public/signup.tsx +0 -31
  48. package/template/apps/desktop/src/routes/_public.tsx +0 -23
  49. package/template/apps/desktop/src/vite-env.d.ts +0 -1
  50. package/template/apps/desktop/src-tauri/Cargo.toml +0 -25
  51. package/template/apps/desktop/src-tauri/build.rs +0 -3
  52. package/template/apps/desktop/src-tauri/capabilities/default.json +0 -7
  53. package/template/apps/desktop/src-tauri/icons/128x128.png +0 -0
  54. package/template/apps/desktop/src-tauri/icons/128x128@2x.png +0 -0
  55. package/template/apps/desktop/src-tauri/icons/32x32.png +0 -0
  56. package/template/apps/desktop/src-tauri/icons/Square107x107Logo.png +0 -0
  57. package/template/apps/desktop/src-tauri/icons/Square142x142Logo.png +0 -0
  58. package/template/apps/desktop/src-tauri/icons/Square150x150Logo.png +0 -0
  59. package/template/apps/desktop/src-tauri/icons/Square284x284Logo.png +0 -0
  60. package/template/apps/desktop/src-tauri/icons/Square30x30Logo.png +0 -0
  61. package/template/apps/desktop/src-tauri/icons/Square310x310Logo.png +0 -0
  62. package/template/apps/desktop/src-tauri/icons/Square44x44Logo.png +0 -0
  63. package/template/apps/desktop/src-tauri/icons/Square71x71Logo.png +0 -0
  64. package/template/apps/desktop/src-tauri/icons/Square89x89Logo.png +0 -0
  65. package/template/apps/desktop/src-tauri/icons/StoreLogo.png +0 -0
  66. package/template/apps/desktop/src-tauri/icons/icon.icns +0 -0
  67. package/template/apps/desktop/src-tauri/icons/icon.ico +0 -0
  68. package/template/apps/desktop/src-tauri/icons/icon.png +0 -0
  69. package/template/apps/desktop/src-tauri/src/lib.rs +0 -14
  70. package/template/apps/desktop/src-tauri/src/main.rs +0 -6
  71. package/template/apps/desktop/src-tauri/tauri.conf.json +0 -35
  72. package/template/apps/desktop/tsconfig.json +0 -17
  73. package/template/apps/desktop/tsconfig.node.json +0 -10
  74. package/template/apps/desktop/vite.config.ts +0 -40
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-croissant",
3
- "version": "0.1.57",
3
+ "version": "0.1.59",
4
4
  "description": "Scaffold a new project using the Croissant Stack",
5
5
  "repository": {
6
6
  "type": "git",
@@ -33,6 +33,7 @@
33
33
  "@types/inquirer": "^9.0.9",
34
34
  "@types/node": "^25.6.0",
35
35
  "tsup": "^8.5.1",
36
+ "typescript": "6.0.3",
36
37
  "@workspace/config-typescript": "0.0.0"
37
38
  },
38
39
  "scripts": {
@@ -37,6 +37,7 @@
37
37
  "@workspace/config-typescript": "workspace:*",
38
38
  "dotenv": "^17.4.2",
39
39
  "drizzle-kit": "^0.31.10",
40
+ "typescript": "6.0.3",
40
41
  "vite": "^8.0.10"
41
42
  }
42
43
  }
@@ -0,0 +1,32 @@
1
+ import * as React from "react";
2
+ import { Link } from "@tanstack/react-router";
3
+ import { Lock } from "lucide-react";
4
+ import { buttonVariants } from "@workspace/ui/components/button";
5
+
6
+ export function AccessDenied() {
7
+ return (
8
+ <div className="flex flex-col items-center justify-center h-[60vh] gap-4 text-center">
9
+ <div className="rounded-full bg-muted p-6">
10
+ <Lock className="h-12 w-12 text-muted-foreground" />
11
+ </div>
12
+ <h2 className="text-2xl font-bold tracking-tight">Access Denied</h2>
13
+ <p className="text-muted-foreground max-w-[400px]">
14
+ You need to be logged in to access this page. Please sign in to view this content.
15
+ </p>
16
+ <div className="flex gap-2">
17
+ <Link
18
+ to="/login"
19
+ className={buttonVariants({ variant: "default" })}
20
+ >
21
+ Sign In
22
+ </Link>
23
+ <Link
24
+ to="/"
25
+ className={buttonVariants({ variant: "outline" })}
26
+ >
27
+ Go Home
28
+ </Link>
29
+ </div>
30
+ </div>
31
+ );
32
+ }
@@ -20,8 +20,8 @@ import { ModeToggle } from "@workspace/ui/components/mode-toggle";
20
20
 
21
21
  import { authClient } from "@/lib/auth-client";
22
22
 
23
- // This is sample data.
24
- export const authNavItems = [
23
+ // Unified navigation items
24
+ export const navItems = [
25
25
  {
26
26
  title: "Dashboard",
27
27
  items: [
@@ -35,22 +35,6 @@ export const authNavItems = [
35
35
  },
36
36
  ],
37
37
  },
38
- {
39
- title: "Examples",
40
- items: [
41
- {
42
- title: "SSR + oRPC (Auth)",
43
- url: "/examples/ssr-orpc-auth",
44
- },
45
- {
46
- title: "Client + oRPC (Auth)",
47
- url: "/examples/client-orpc-auth",
48
- },
49
- ],
50
- },
51
- ];
52
-
53
- export const publicNavItems = [
54
38
  {
55
39
  title: "Welcome",
56
40
  items: [
@@ -75,10 +59,18 @@ export const publicNavItems = [
75
59
  title: "SSR + oRPC",
76
60
  url: "/examples/ssr-orpc",
77
61
  },
62
+ {
63
+ title: "SSR + oRPC (Auth)",
64
+ url: "/examples/ssr-orpc-auth",
65
+ },
78
66
  {
79
67
  title: "Client + oRPC",
80
68
  url: "/examples/client-orpc",
81
69
  },
70
+ {
71
+ title: "Client + oRPC (Auth)",
72
+ url: "/examples/client-orpc-auth",
73
+ },
82
74
  {
83
75
  title: "ISR",
84
76
  url: "/examples/isr",
@@ -87,27 +79,8 @@ export const publicNavItems = [
87
79
  },
88
80
  ];
89
81
 
90
- interface AppSidebarProps extends React.ComponentProps<typeof Sidebar> {
91
- items?: Array<{
92
- title: string;
93
- items: Array<{
94
- title: string;
95
- url: string;
96
- }>;
97
- }>;
98
- }
99
-
100
- export function AuthSidebar(props: React.ComponentProps<typeof Sidebar>) {
101
- return <AppSidebar items={authNavItems} {...props} />;
102
- }
103
-
104
- export function PublicSidebar(props: React.ComponentProps<typeof Sidebar>) {
105
- return <AppSidebar items={publicNavItems} {...props} />;
106
- }
107
-
108
- export function AppSidebar({ items = authNavItems, ...props }: AppSidebarProps) {
82
+ export function AppSidebar(props: React.ComponentProps<typeof Sidebar>) {
109
83
  const { data: session } = authClient.useSession();
110
-
111
84
  const user = session?.user || null;
112
85
 
113
86
  return (
@@ -119,22 +92,29 @@ export function AppSidebar({ items = authNavItems, ...props }: AppSidebarProps)
119
92
  </div>
120
93
  </SidebarHeader>
121
94
  <SidebarContent>
122
- {items.map((item) => (
95
+ {navItems.map((item) => (
123
96
  <SidebarGroup key={item.title}>
124
97
  <SidebarGroupLabel>{item.title}</SidebarGroupLabel>
125
98
  <SidebarGroupContent>
126
99
  <SidebarMenu>
127
- {item.items.map((subItem) => (
128
- <SidebarMenuItem key={subItem.title}>
129
- <SidebarMenuButton
130
- render={
131
- <Link to={subItem.url} activeProps={{ className: "bg-sidebar-accent" }} />
132
- }
133
- >
134
- {subItem.title}
135
- </SidebarMenuButton>
136
- </SidebarMenuItem>
137
- ))}
100
+ {item.items.map((subItem) => {
101
+ // Hide Login/Signup if user is already logged in
102
+ if (user && (subItem.url === "/login" || subItem.url === "/signup")) {
103
+ return null;
104
+ }
105
+
106
+ return (
107
+ <SidebarMenuItem key={subItem.title}>
108
+ <SidebarMenuButton
109
+ render={
110
+ <Link to={subItem.url} activeProps={{ className: "bg-sidebar-accent" }} />
111
+ }
112
+ >
113
+ {subItem.title}
114
+ </SidebarMenuButton>
115
+ </SidebarMenuItem>
116
+ );
117
+ })}
138
118
  </SidebarMenu>
139
119
  </SidebarGroupContent>
140
120
  </SidebarGroup>
@@ -1,13 +1,27 @@
1
1
  import { createServerFn } from "@tanstack/react-start";
2
- import { getRequest } from "@tanstack/react-start/server";
2
+ import { getRequestHeaders } from "@tanstack/react-start/server";
3
3
  import { auth } from "@workspace/auth/lib/auth";
4
4
 
5
5
  export const getSessionFn = createServerFn({ method: "GET" }).handler(async () => {
6
- const request = getRequest();
6
+ const headers = getRequestHeaders();
7
7
 
8
8
  const session = await auth.api.getSession({
9
- headers: request.headers,
9
+ headers,
10
10
  });
11
11
 
12
12
  return session;
13
13
  });
14
+
15
+ export const ensureSessionFn = createServerFn({ method: "GET" }).handler(async () => {
16
+ const headers = getRequestHeaders();
17
+
18
+ const session = await auth.api.getSession({
19
+ headers,
20
+ });
21
+
22
+ if (!session) {
23
+ throw new Error("Unauthorized");
24
+ }
25
+
26
+ return session;
27
+ });
@@ -11,7 +11,7 @@ import {
11
11
  EmptyHeader,
12
12
  EmptyTitle,
13
13
  } from "@workspace/ui/components/empty";
14
- import { Button, buttonVariants } from "@workspace/ui/components/button";
14
+ import { buttonVariants } from "@workspace/ui/components/button";
15
15
 
16
16
  import appCss from "@workspace/ui/globals.css?url";
17
17
 
@@ -1,9 +1,10 @@
1
1
  import * as React from "react";
2
- import { createFileRoute, redirect } from "@tanstack/react-router";
2
+ import { createFileRoute } from "@tanstack/react-router";
3
3
  import { useForm } from "@tanstack/react-form";
4
4
  import { z } from "zod";
5
5
  import { toast } from "sonner";
6
6
  import { Loader2, User } from "lucide-react";
7
+ import { AccessDenied } from "@/components/access-denied";
7
8
 
8
9
  import { Button } from "@workspace/ui/components/button";
9
10
  import { Input } from "@workspace/ui/components/input";
@@ -40,14 +41,6 @@ const passwordSchema = z
40
41
  export const Route = createFileRoute("/_auth/account")({
41
42
  beforeLoad: async () => {
42
43
  const session = await getSessionFn();
43
- if (!session) {
44
- throw redirect({
45
- to: "/login",
46
- search: {
47
- redirect: "/account",
48
- },
49
- });
50
- }
51
44
  return { session };
52
45
  },
53
46
  component: AccountPage,
@@ -56,6 +49,11 @@ export const Route = createFileRoute("/_auth/account")({
56
49
  function AccountPage() {
57
50
  const { session } = Route.useRouteContext();
58
51
  const [loading, setLoading] = React.useState(false);
52
+
53
+ if (!session) {
54
+ return <AccessDenied />;
55
+ }
56
+
59
57
  const user = session.user;
60
58
 
61
59
  const profileForm = useForm({
@@ -1,19 +1,16 @@
1
- import { createFileRoute, redirect } from "@tanstack/react-router";
1
+ import { createFileRoute } from "@tanstack/react-router";
2
2
  import { getSessionFn } from "@/lib/auth-utils";
3
3
  import { authClient } from "@/lib/auth-client";
4
4
  import { orpc } from "@/lib/orpc";
5
+ import { AccessDenied } from "@/components/access-denied";
5
6
 
6
7
  export const Route = createFileRoute("/_auth/dashboard")({
7
8
  beforeLoad: async () => {
8
9
  const session = await getSessionFn();
9
- if (!session) {
10
- throw redirect({
11
- to: "/",
12
- });
13
- }
14
10
  return { session };
15
11
  },
16
- loader: async () => {
12
+ loader: async ({ context }) => {
13
+ if (!context.session) return { secretData: null };
17
14
  try {
18
15
  const data = await orpc.getSecretData();
19
16
  return { secretData: data.secret };
@@ -28,6 +25,10 @@ function Dashboard() {
28
25
  const { session } = Route.useRouteContext();
29
26
  const { secretData } = Route.useLoaderData();
30
27
 
28
+ if (!session) {
29
+ return <AccessDenied />;
30
+ }
31
+
31
32
  return (
32
33
  <div className="flex min-h-svh p-6">
33
34
  <div className="flex max-w-md min-w-0 flex-col gap-4 text-sm leading-loose">
@@ -1,18 +1,11 @@
1
- import { createFileRoute, redirect } from "@tanstack/react-router";
1
+ import { createFileRoute } from "@tanstack/react-router";
2
2
  import { getSessionFn } from "@/lib/auth-utils";
3
3
  import { useSecretData } from "@workspace/orpc/react";
4
+ import { AccessDenied } from "@/components/access-denied";
4
5
 
5
6
  export const Route = createFileRoute("/_auth/examples/client-orpc-auth")({
6
7
  beforeLoad: async () => {
7
8
  const session = await getSessionFn();
8
- if (!session) {
9
- throw redirect({
10
- to: "/login",
11
- search: {
12
- redirect: "/examples/client-orpc-auth",
13
- },
14
- });
15
- }
16
9
  return { session };
17
10
  },
18
11
  component: ClientORPCAuth,
@@ -23,6 +16,10 @@ function ClientORPCAuth() {
23
16
 
24
17
  const { data, isLoading } = useSecretData();
25
18
 
19
+ if (!session) {
20
+ return <AccessDenied />;
21
+ }
22
+
26
23
  return (
27
24
  <div className="flex flex-col gap-4">
28
25
  <h1 className="text-2xl font-bold">Client + oRPC (Authenticated)</h1>
@@ -1,10 +1,13 @@
1
- import { createFileRoute, redirect } from "@tanstack/react-router";
1
+ import { createFileRoute } from "@tanstack/react-router";
2
2
  import { createServerFn } from "@tanstack/react-start";
3
3
  import { getSessionFn } from "@/lib/auth-utils";
4
4
  import { orpc } from "@/lib/orpc";
5
+ import { AccessDenied } from "@/components/access-denied";
5
6
 
6
7
  const getSecretData = createServerFn({ method: "GET" }).handler(async () => {
7
8
  try {
9
+ const session = await getSessionFn();
10
+ if (!session) return { secretData: null, error: "Unauthorized" };
8
11
  const secretData = await orpc.getSecretData();
9
12
  return { secretData };
10
13
  } catch {
@@ -15,14 +18,6 @@ const getSecretData = createServerFn({ method: "GET" }).handler(async () => {
15
18
  export const Route = createFileRoute("/_auth/examples/ssr-orpc-auth")({
16
19
  beforeLoad: async () => {
17
20
  const session = await getSessionFn();
18
- if (!session) {
19
- throw redirect({
20
- to: "/login",
21
- search: {
22
- redirect: "/examples/ssr-orpc-auth",
23
- },
24
- });
25
- }
26
21
  return { session };
27
22
  },
28
23
  loader: () => getSecretData(),
@@ -33,6 +28,10 @@ function SSRORPCAuth() {
33
28
  const { session } = Route.useRouteContext();
34
29
  const { secretData, error } = Route.useLoaderData();
35
30
 
31
+ if (!session) {
32
+ return <AccessDenied />;
33
+ }
34
+
36
35
  return (
37
36
  <div className="flex flex-col gap-4">
38
37
  <h1 className="text-2xl font-bold">SSR + oRPC (Authenticated)</h1>
@@ -1,6 +1,6 @@
1
1
  import { Outlet, createFileRoute } from "@tanstack/react-router";
2
2
  import { SidebarProvider, SidebarTrigger } from "@workspace/ui/components/sidebar";
3
- import { AuthSidebar } from "@/components/app-sidebar";
3
+ import { AppSidebar } from "@/components/app-sidebar";
4
4
 
5
5
  export const Route = createFileRoute("/_auth")({
6
6
  component: AuthLayout,
@@ -9,7 +9,7 @@ export const Route = createFileRoute("/_auth")({
9
9
  function AuthLayout() {
10
10
  return (
11
11
  <SidebarProvider>
12
- <AuthSidebar />
12
+ <AppSidebar />
13
13
  <main className="flex flex-1 flex-col overflow-hidden">
14
14
  <header className="flex h-16 shrink-0 items-center gap-2 border-b px-4">
15
15
  <SidebarTrigger />
@@ -1,6 +1,6 @@
1
1
  import { Outlet, createFileRoute } from "@tanstack/react-router";
2
2
  import { SidebarProvider, SidebarTrigger } from "@workspace/ui/components/sidebar";
3
- import { PublicSidebar } from "@/components/app-sidebar";
3
+ import { AppSidebar } from "@/components/app-sidebar";
4
4
 
5
5
  export const Route = createFileRoute("/_public")({
6
6
  component: PublicLayout,
@@ -9,7 +9,7 @@ export const Route = createFileRoute("/_public")({
9
9
  function PublicLayout() {
10
10
  return (
11
11
  <SidebarProvider>
12
- <PublicSidebar />
12
+ <AppSidebar />
13
13
  <main className="flex flex-1 flex-col overflow-hidden">
14
14
  <header className="flex h-16 shrink-0 items-center gap-2 border-b px-4">
15
15
  <SidebarTrigger />
@@ -1,34 +1,44 @@
1
1
  import { auth } from "@workspace/auth/lib/auth";
2
2
  import { createFileRoute } from "@tanstack/react-router";
3
3
 
4
- const CORS_HEADERS = {
5
- "Access-Control-Allow-Origin": "*",
6
- "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
7
- "Access-Control-Allow-Headers": "Content-Type, Authorization",
8
- "Access-Control-Allow-Credentials": "true",
9
- };
10
-
11
4
  export const Route = createFileRoute("/api/auth/$")({
12
5
  server: {
13
6
  handlers: {
14
7
  GET: async ({ request }: { request: Request }) => {
15
8
  const response = await auth.handler(request);
16
- Object.entries(CORS_HEADERS).forEach(([key, value]) => {
17
- response.headers.set(key, value);
18
- });
9
+ const origin = request.headers.get("Origin");
10
+ if (origin) {
11
+ response.headers.set("Access-Control-Allow-Origin", origin);
12
+ }
13
+ response.headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
14
+ response.headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
15
+ response.headers.set("Access-Control-Allow-Credentials", "true");
19
16
  return response;
20
17
  },
21
18
  POST: async ({ request }: { request: Request }) => {
22
19
  const response = await auth.handler(request);
23
- Object.entries(CORS_HEADERS).forEach(([key, value]) => {
24
- response.headers.set(key, value);
25
- });
20
+ const origin = request.headers.get("Origin");
21
+ if (origin) {
22
+ response.headers.set("Access-Control-Allow-Origin", origin);
23
+ }
24
+ response.headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
25
+ response.headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
26
+ response.headers.set("Access-Control-Allow-Credentials", "true");
26
27
  return response;
27
28
  },
28
- OPTIONS: async () => {
29
+ OPTIONS: async ({ request }: { request: Request }) => {
30
+ const origin = request.headers.get("Origin");
31
+ const headers: Record<string, string> = {
32
+ "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
33
+ "Access-Control-Allow-Headers": "Content-Type, Authorization",
34
+ "Access-Control-Allow-Credentials": "true",
35
+ };
36
+ if (origin) {
37
+ headers["Access-Control-Allow-Origin"] = origin;
38
+ }
29
39
  return new Response(null, {
30
40
  status: 204,
31
- headers: CORS_HEADERS,
41
+ headers,
32
42
  });
33
43
  },
34
44
  },
@@ -28,7 +28,10 @@ export const Route = createFileRoute("/api/rpc/$")({
28
28
  });
29
29
 
30
30
  if (response) {
31
- response.headers.set("Access-Control-Allow-Origin", "*");
31
+ const origin = request.headers.get("Origin");
32
+ if (origin) {
33
+ response.headers.set("Access-Control-Allow-Origin", origin);
34
+ }
32
35
  response.headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
33
36
  response.headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
34
37
  response.headers.set("Access-Control-Allow-Credentials", "true");
@@ -36,15 +39,19 @@ export const Route = createFileRoute("/api/rpc/$")({
36
39
 
37
40
  return response ?? new Response("Not Found", { status: 404 });
38
41
  },
39
- OPTIONS: async () => {
42
+ OPTIONS: async ({ request }) => {
43
+ const origin = request.headers.get("Origin");
44
+ const headers: Record<string, string> = {
45
+ "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
46
+ "Access-Control-Allow-Headers": "Content-Type, Authorization",
47
+ "Access-Control-Allow-Credentials": "true",
48
+ };
49
+ if (origin) {
50
+ headers["Access-Control-Allow-Origin"] = origin;
51
+ }
40
52
  return new Response(null, {
41
53
  status: 204,
42
- headers: {
43
- "Access-Control-Allow-Origin": "*",
44
- "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
45
- "Access-Control-Allow-Headers": "Content-Type, Authorization",
46
- "Access-Control-Allow-Credentials": "true",
47
- },
54
+ headers,
48
55
  });
49
56
  },
50
57
  },
@@ -1,8 +1,6 @@
1
- version: "3.8"
2
-
3
1
  services:
4
2
  db:
5
- image: postgres:latest
3
+ image: postgres:17-alpine
6
4
  container_name: croissant-stack
7
5
  environment:
8
6
  POSTGRES_PASSWORD: postgres
@@ -14,8 +14,6 @@
14
14
  "quality:fix": "turbo quality:fix",
15
15
  "typecheck": "turbo typecheck",
16
16
  "ci": "pnpm run lint && pnpm run typecheck && pnpm run build",
17
- "dev:desktop": "turbo run dev --filter=desktop",
18
- "build:desktop": "turbo run build --filter=desktop",
19
17
  "db:up": "docker compose up -d",
20
18
  "db:down": "docker compose down",
21
19
  "db:logs": "docker compose logs -f",
@@ -41,14 +39,5 @@
41
39
  "engines": {
42
40
  "node": ">=20"
43
41
  },
44
- "packageManager": "pnpm@11.1.2",
45
- "pnpm": {
46
- "onlyBuiltDependencies": [
47
- "@prisma/client",
48
- "better-sqlite3",
49
- "esbuild",
50
- "msw",
51
- "unrs-resolver"
52
- ]
53
- }
42
+ "packageManager": "pnpm@11.1.2"
54
43
  }
@@ -9,15 +9,15 @@
9
9
  },
10
10
  "scripts": {
11
11
  "typecheck": "tsc --noEmit",
12
- "generate": "better-auth generate --output ../db/src/lib/auth-schema.ts"
12
+ "generate": "auth generate --output ../db/src/lib/auth-schema.ts"
13
13
  },
14
14
  "dependencies": {
15
15
  "@workspace/db": "workspace:*",
16
16
  "better-auth": "1.6.11"
17
17
  },
18
18
  "devDependencies": {
19
- "@better-auth/cli": "^1.4.22",
20
19
  "@workspace/config-typescript": "workspace:*",
20
+ "auth": "^1.6.11",
21
21
  "drizzle-kit": "^0.31.10",
22
22
  "tsx": "^4.21.0"
23
23
  }
@@ -1,6 +1,7 @@
1
1
  import { betterAuth } from "better-auth";
2
2
  import { drizzleAdapter } from "better-auth/adapters/drizzle";
3
3
  import { db } from "@workspace/db";
4
+ import { tanstackStartCookies } from "better-auth/tanstack-start";
4
5
 
5
6
  export const auth = betterAuth({
6
7
  database: drizzleAdapter(db, {
@@ -8,6 +9,15 @@ export const auth = betterAuth({
8
9
  }),
9
10
  baseURL: process.env.BETTER_AUTH_URL,
10
11
  emailAndPassword: { enabled: true },
12
+ advanced: {
13
+ cookiePrefix: "croissant",
14
+ useSecureCookies: true,
15
+ },
16
+ cookie: {
17
+ sameSite: "none",
18
+ secure: true,
19
+ },
20
+ plugins: [tanstackStartCookies()],
11
21
  });
12
22
 
13
23
  export type Session = typeof auth.$Infer.Session;
@@ -1,3 +0,0 @@
1
- {
2
- "recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"]
3
- }
@@ -1,7 +0,0 @@
1
- # Tauri + React + Typescript
2
-
3
- This template should help get you started developing with Tauri, React and Typescript in Vite.
4
-
5
- ## Recommended IDE Setup
6
-
7
- - [VS Code](https://code.visualstudio.com/) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)
@@ -1,14 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>Tauri + React + Typescript</title>
8
- </head>
9
-
10
- <body>
11
- <div id="root"></div>
12
- <script type="module" src="/src/main.tsx"></script>
13
- </body>
14
- </html>
@@ -1,40 +0,0 @@
1
- {
2
- "name": "desktop",
3
- "version": "0.1.0",
4
- "private": true,
5
- "type": "module",
6
- "scripts": {
7
- "dev": "vite",
8
- "build": "tsc && vite build",
9
- "preview": "vite preview",
10
- "tauri": "tauri"
11
- },
12
- "dependencies": {
13
- "@noble/ciphers": "^2.2.0",
14
- "@tailwindcss/vite": "^4.2.4",
15
- "@tanstack/react-router": "^1.168.24",
16
- "@tanstack/router-plugin": "^1.167.27",
17
- "@tauri-apps/api": "^2",
18
- "@tauri-apps/plugin-opener": "^2",
19
- "@workspace/auth": "workspace:*",
20
- "@workspace/orpc": "workspace:*",
21
- "@workspace/ui": "workspace:*",
22
- "better-auth": "1.6.11",
23
- "lucide-react": "^1.11.0",
24
- "react": "19.2.5",
25
- "react-dom": "19.2.5",
26
- "sonner": "^2.0.7",
27
- "tailwindcss": "^4.2.4"
28
- },
29
- "devDependencies": {
30
- "@tauri-apps/cli": "^2",
31
- "@types/node": "^25.6.0",
32
- "@types/react": "19.2.14",
33
- "@types/react-dom": "19.2.3",
34
- "@vitejs/plugin-react": "^4.6.0",
35
- "@workspace/config-typescript": "workspace:*",
36
- "typescript": "~5.8.3",
37
- "vite": "^8.0.10",
38
- "vite-tsconfig-paths": "^6.1.1"
39
- }
40
- }