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.
- package/package.json +2 -1
- package/template/apps/platform/package.json +1 -0
- package/template/apps/platform/src/components/access-denied.tsx +32 -0
- package/template/apps/platform/src/components/app-sidebar.tsx +30 -50
- package/template/apps/platform/src/lib/auth-utils.ts +17 -3
- package/template/apps/platform/src/routes/__root.tsx +1 -1
- package/template/apps/platform/src/routes/_auth/account.tsx +7 -9
- package/template/apps/platform/src/routes/_auth/dashboard.tsx +8 -7
- package/template/apps/platform/src/routes/_auth/examples/client-orpc-auth.tsx +6 -9
- package/template/apps/platform/src/routes/_auth/examples/ssr-orpc-auth.tsx +8 -9
- package/template/apps/platform/src/routes/_auth.tsx +2 -2
- package/template/apps/platform/src/routes/_public.tsx +2 -2
- package/template/apps/platform/src/routes/api/auth/$.ts +25 -15
- package/template/apps/platform/src/routes/api/rpc.$.ts +15 -8
- package/template/docker-compose.yml +1 -3
- package/template/package.json +1 -12
- package/template/packages/auth/package.json +2 -2
- package/template/packages/auth/src/lib/auth.ts +10 -0
- package/template/apps/desktop/.vscode/extensions.json +0 -3
- package/template/apps/desktop/README.md +0 -7
- package/template/apps/desktop/index.html +0 -14
- package/template/apps/desktop/package.json +0 -40
- package/template/apps/desktop/public/tauri.svg +0 -6
- package/template/apps/desktop/public/vite.svg +0 -1
- package/template/apps/desktop/src/App.css +0 -116
- package/template/apps/desktop/src/App.tsx +0 -51
- package/template/apps/desktop/src/assets/react.svg +0 -1
- package/template/apps/desktop/src/components/app-sidebar.tsx +0 -186
- package/template/apps/desktop/src/components/login-form.tsx +0 -160
- package/template/apps/desktop/src/components/search-form.tsx +0 -19
- package/template/apps/desktop/src/components/signup-form.tsx +0 -206
- package/template/apps/desktop/src/components/version-switcher.tsx +0 -54
- package/template/apps/desktop/src/env.d.ts +0 -1
- package/template/apps/desktop/src/lib/auth-client.ts +0 -5
- package/template/apps/desktop/src/lib/orpc.ts +0 -10
- package/template/apps/desktop/src/main.tsx +0 -12
- package/template/apps/desktop/src/routeTree.gen.ts +0 -240
- package/template/apps/desktop/src/router.tsx +0 -19
- package/template/apps/desktop/src/routes/__root.tsx +0 -52
- package/template/apps/desktop/src/routes/_auth/account.tsx +0 -275
- package/template/apps/desktop/src/routes/_auth/dashboard.tsx +0 -58
- package/template/apps/desktop/src/routes/_auth/examples/client-orpc-auth.tsx +0 -46
- package/template/apps/desktop/src/routes/_auth.tsx +0 -23
- package/template/apps/desktop/src/routes/_public/examples/client-orpc.tsx +0 -330
- package/template/apps/desktop/src/routes/_public/index.tsx +0 -66
- package/template/apps/desktop/src/routes/_public/login.tsx +0 -34
- package/template/apps/desktop/src/routes/_public/signup.tsx +0 -31
- package/template/apps/desktop/src/routes/_public.tsx +0 -23
- package/template/apps/desktop/src/vite-env.d.ts +0 -1
- package/template/apps/desktop/src-tauri/Cargo.toml +0 -25
- package/template/apps/desktop/src-tauri/build.rs +0 -3
- package/template/apps/desktop/src-tauri/capabilities/default.json +0 -7
- package/template/apps/desktop/src-tauri/icons/128x128.png +0 -0
- package/template/apps/desktop/src-tauri/icons/128x128@2x.png +0 -0
- package/template/apps/desktop/src-tauri/icons/32x32.png +0 -0
- package/template/apps/desktop/src-tauri/icons/Square107x107Logo.png +0 -0
- package/template/apps/desktop/src-tauri/icons/Square142x142Logo.png +0 -0
- package/template/apps/desktop/src-tauri/icons/Square150x150Logo.png +0 -0
- package/template/apps/desktop/src-tauri/icons/Square284x284Logo.png +0 -0
- package/template/apps/desktop/src-tauri/icons/Square30x30Logo.png +0 -0
- package/template/apps/desktop/src-tauri/icons/Square310x310Logo.png +0 -0
- package/template/apps/desktop/src-tauri/icons/Square44x44Logo.png +0 -0
- package/template/apps/desktop/src-tauri/icons/Square71x71Logo.png +0 -0
- package/template/apps/desktop/src-tauri/icons/Square89x89Logo.png +0 -0
- package/template/apps/desktop/src-tauri/icons/StoreLogo.png +0 -0
- package/template/apps/desktop/src-tauri/icons/icon.icns +0 -0
- package/template/apps/desktop/src-tauri/icons/icon.ico +0 -0
- package/template/apps/desktop/src-tauri/icons/icon.png +0 -0
- package/template/apps/desktop/src-tauri/src/lib.rs +0 -14
- package/template/apps/desktop/src-tauri/src/main.rs +0 -6
- package/template/apps/desktop/src-tauri/tauri.conf.json +0 -35
- package/template/apps/desktop/tsconfig.json +0 -17
- package/template/apps/desktop/tsconfig.node.json +0 -10
- 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.
|
|
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": {
|
|
@@ -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
|
-
//
|
|
24
|
-
export const
|
|
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
|
-
|
|
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
|
-
{
|
|
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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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 {
|
|
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
|
|
6
|
+
const headers = getRequestHeaders();
|
|
7
7
|
|
|
8
8
|
const session = await auth.api.getSession({
|
|
9
|
-
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 {
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 {
|
|
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
|
-
<
|
|
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 {
|
|
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
|
-
<
|
|
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
|
-
|
|
17
|
-
|
|
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
|
-
|
|
24
|
-
|
|
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
|
|
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
|
-
|
|
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
|
},
|
package/template/package.json
CHANGED
|
@@ -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": "
|
|
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,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
|
-
}
|