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
@@ -1,275 +0,0 @@
1
- import * as React from "react";
2
- import { createFileRoute, redirect } from "@tanstack/react-router";
3
- import { useForm } from "@tanstack/react-form";
4
- import { z } from "zod";
5
- import { toast } from "sonner";
6
- import { Loader2, User } from "lucide-react";
7
-
8
- import { Button } from "@workspace/ui/components/button";
9
- import { Input } from "@workspace/ui/components/input";
10
- import {
11
- Card,
12
- CardContent,
13
- CardDescription,
14
- CardFooter,
15
- CardHeader,
16
- CardTitle,
17
- } from "@workspace/ui/components/card";
18
- import { Field, FieldError, FieldLabel } from "@workspace/ui/components/field";
19
- import { Avatar, AvatarFallback, AvatarImage } from "@workspace/ui/components/avatar";
20
- import { Separator } from "@workspace/ui/components/separator";
21
-
22
- import { authClient } from "@/lib/auth-client";
23
-
24
- const profileSchema = z.object({
25
- name: z.string().min(1, "Name is required"),
26
- });
27
-
28
- const passwordSchema = z
29
- .object({
30
- currentPassword: z.string().min(1, "Current password is required"),
31
- newPassword: z.string().min(8, "New password must be at least 8 characters"),
32
- confirmPassword: z.string().min(1, "Confirm password is required"),
33
- })
34
- .refine((data) => data.newPassword === data.confirmPassword, {
35
- message: "Passwords do not match",
36
- path: ["confirmPassword"],
37
- });
38
-
39
- export const Route = createFileRoute("/_auth/account")({
40
- beforeLoad: async () => {
41
- const { data: session } = await authClient.getSession();
42
- if (!session) {
43
- throw redirect({
44
- to: "/login",
45
- search: {
46
- redirect: "/account",
47
- },
48
- });
49
- }
50
- return { session };
51
- },
52
- component: AccountPage,
53
- });
54
-
55
- function AccountPage() {
56
- const { session } = Route.useRouteContext();
57
- const [loading, setLoading] = React.useState(false);
58
- const user = session.user;
59
-
60
- const profileForm = useForm({
61
- defaultValues: {
62
- name: user.name || "",
63
- },
64
- validators: {
65
- onChange: profileSchema,
66
- },
67
- onSubmit: async ({ value }) => {
68
- setLoading(true);
69
- const { error } = await authClient.updateUser({
70
- name: value.name,
71
- });
72
-
73
- if (error) {
74
- toast.error(error.message || "Failed to update profile");
75
- } else {
76
- toast.success("Profile updated successfully");
77
- }
78
- setLoading(false);
79
- },
80
- });
81
-
82
- const passwordForm = useForm({
83
- defaultValues: {
84
- currentPassword: "",
85
- newPassword: "",
86
- confirmPassword: "",
87
- },
88
- validators: {
89
- onChange: passwordSchema,
90
- },
91
- onSubmit: async ({ value }) => {
92
- setLoading(true);
93
- const { error } = await authClient.changePassword({
94
- currentPassword: value.currentPassword,
95
- newPassword: value.newPassword,
96
- });
97
-
98
- if (error) {
99
- toast.error(error.message || "Failed to change password");
100
- } else {
101
- toast.success("Password changed successfully");
102
- passwordForm.reset();
103
- }
104
- setLoading(false);
105
- },
106
- });
107
-
108
- return (
109
- <div className="container max-w-4xl py-10">
110
- <div className="flex flex-col gap-8">
111
- <div>
112
- <h1 className="text-3xl font-bold">Account Settings</h1>
113
- <p className="text-muted-foreground">Manage your profile and account preferences.</p>
114
- </div>
115
-
116
- <Separator />
117
-
118
- <div className="grid gap-8">
119
- {/* Profile Section */}
120
- <Card>
121
- <CardHeader>
122
- <CardTitle>Profile</CardTitle>
123
- <CardDescription>Update your personal information.</CardDescription>
124
- </CardHeader>
125
- <CardContent className="space-y-6">
126
- <div className="flex items-center gap-4">
127
- <Avatar className="h-20 w-20">
128
- <AvatarImage src={user.image || ""} />
129
- <AvatarFallback className="text-2xl">
130
- {user.name.charAt(0) || <User className="h-10 w-10" />}
131
- </AvatarFallback>
132
- </Avatar>
133
- <div className="space-y-1">
134
- <p className="text-sm font-medium leading-none">{user.name}</p>
135
- <p className="text-sm text-muted-foreground">{user.email}</p>
136
- </div>
137
- </div>
138
-
139
- <form
140
- onSubmit={(e) => {
141
- e.preventDefault();
142
- e.stopPropagation();
143
- profileForm.handleSubmit();
144
- }}
145
- className="space-y-4"
146
- >
147
- <profileForm.Field
148
- name="name"
149
- children={(field) => (
150
- <Field>
151
- <FieldLabel htmlFor={field.name}>Display Name</FieldLabel>
152
- <Input
153
- id={field.name}
154
- value={field.state.value}
155
- onBlur={field.handleBlur}
156
- onChange={(e) => field.handleChange(e.target.value)}
157
- />
158
- <FieldError />
159
- </Field>
160
- )}
161
- />
162
- <Button type="submit" disabled={loading}>
163
- {loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
164
- Update Profile
165
- </Button>
166
- </form>
167
- </CardContent>
168
- </Card>
169
-
170
- {/* Password Section */}
171
- <Card>
172
- <CardHeader>
173
- <CardTitle>Security</CardTitle>
174
- <CardDescription>Change your password to keep your account secure.</CardDescription>
175
- </CardHeader>
176
- <CardContent>
177
- <form
178
- onSubmit={(e) => {
179
- e.preventDefault();
180
- e.stopPropagation();
181
- passwordForm.handleSubmit();
182
- }}
183
- className="space-y-4"
184
- >
185
- <passwordForm.Field
186
- name="currentPassword"
187
- children={(field) => (
188
- <Field>
189
- <FieldLabel htmlFor={field.name}>Current Password</FieldLabel>
190
- <Input
191
- id={field.name}
192
- type="password"
193
- value={field.state.value}
194
- onBlur={field.handleBlur}
195
- onChange={(e) => field.handleChange(e.target.value)}
196
- />
197
- <FieldError />
198
- </Field>
199
- )}
200
- />
201
- <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
202
- <passwordForm.Field
203
- name="newPassword"
204
- children={(field) => (
205
- <Field>
206
- <FieldLabel htmlFor={field.name}>New Password</FieldLabel>
207
- <Input
208
- id={field.name}
209
- type="password"
210
- value={field.state.value}
211
- onBlur={field.handleBlur}
212
- onChange={(e) => field.handleChange(e.target.value)}
213
- />
214
- <FieldError />
215
- </Field>
216
- )}
217
- />
218
- <passwordForm.Field
219
- name="confirmPassword"
220
- children={(field) => (
221
- <Field>
222
- <FieldLabel htmlFor={field.name}>Confirm New Password</FieldLabel>
223
- <Input
224
- id={field.name}
225
- type="password"
226
- value={field.state.value}
227
- onBlur={field.handleBlur}
228
- onChange={(e) => field.handleChange(e.target.value)}
229
- />
230
- <FieldError />
231
- </Field>
232
- )}
233
- />
234
- </div>
235
- <Button type="submit" variant="secondary" disabled={loading}>
236
- {loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
237
- Change Password
238
- </Button>
239
- </form>
240
- </CardContent>
241
- </Card>
242
-
243
- {/* Danger Zone */}
244
- <Card className="border-destructive/50">
245
- <CardHeader>
246
- <CardTitle className="text-destructive">Danger Zone</CardTitle>
247
- <CardDescription>Permanently delete your account and all data.</CardDescription>
248
- </CardHeader>
249
- <CardFooter>
250
- <Button
251
- variant="destructive"
252
- onClick={async () => {
253
- if (
254
- confirm(
255
- "Are you sure you want to delete your account? This action cannot be undone.",
256
- )
257
- ) {
258
- const { error } = await authClient.deleteUser();
259
- if (error) {
260
- toast.error(error.message || "Failed to delete account");
261
- } else {
262
- window.location.href = "/";
263
- }
264
- }
265
- }}
266
- >
267
- Delete Account
268
- </Button>
269
- </CardFooter>
270
- </Card>
271
- </div>
272
- </div>
273
- </div>
274
- );
275
- }
@@ -1,58 +0,0 @@
1
- import { createFileRoute, redirect } from "@tanstack/react-router";
2
- import { authClient } from "@/lib/auth-client";
3
- import { orpc } from "@/lib/orpc";
4
-
5
- export const Route = createFileRoute("/_auth/dashboard")({
6
- beforeLoad: async () => {
7
- const { data: session } = await authClient.getSession();
8
- if (!session) {
9
- throw redirect({
10
- to: "/",
11
- });
12
- }
13
- return { session };
14
- },
15
- loader: async () => {
16
- try {
17
- const data = await orpc.getSecretData();
18
- return { secretData: data.secret };
19
- } catch (err: any) {
20
- return { secretData: "Error: " + (err.message || "Unknown error") };
21
- }
22
- },
23
- component: Dashboard,
24
- });
25
-
26
- function Dashboard() {
27
- const { session } = Route.useRouteContext();
28
- const { secretData } = Route.useLoaderData();
29
-
30
- return (
31
- <div className="flex min-h-svh p-6">
32
- <div className="flex max-w-md min-w-0 flex-col gap-4 text-sm leading-loose">
33
- <div>
34
- <h1 className="text-2xl font-bold">Dashboard</h1>
35
- <p>Welcome, {session.user.name}!</p>
36
- <p>This is a protected page. Only authenticated users can see this.</p>
37
-
38
- <div className="mt-6 rounded-lg border bg-gray-50 p-4">
39
- <h2 className="font-semibold mb-2">Secure oRPC Data:</h2>
40
- <p className="font-mono text-xs">{secretData}</p>
41
- </div>
42
-
43
- <div className="mt-4 flex gap-2">
44
- <button
45
- onClick={async () => {
46
- await authClient.signOut();
47
- window.location.href = "/";
48
- }}
49
- className="rounded bg-red-500 px-4 py-2 text-white hover:bg-red-600"
50
- >
51
- Sign Out
52
- </button>
53
- </div>
54
- </div>
55
- </div>
56
- </div>
57
- );
58
- }
@@ -1,46 +0,0 @@
1
- import { createFileRoute, redirect } from "@tanstack/react-router";
2
- import { authClient } from "@/lib/auth-client";
3
- import { useSecretData } from "@workspace/orpc/react";
4
-
5
- export const Route = createFileRoute("/_auth/examples/client-orpc-auth")({
6
- beforeLoad: async () => {
7
- const { data: session } = await authClient.getSession();
8
- if (!session) {
9
- throw redirect({
10
- to: "/login",
11
- search: {
12
- redirect: "/examples/client-orpc-auth",
13
- },
14
- });
15
- }
16
- return { session };
17
- },
18
- component: ClientORPCAuth,
19
- });
20
-
21
- function ClientORPCAuth() {
22
- const { session } = Route.useRouteContext();
23
-
24
- const { data, isLoading } = useSecretData();
25
-
26
- return (
27
- <div className="flex flex-col gap-4">
28
- <h1 className="text-2xl font-bold">Client + oRPC (Authenticated)</h1>
29
- <p>This page is protected and fetches secret data on the client using TanStack Query.</p>
30
-
31
- <div className="rounded-lg border p-4">
32
- <h2 className="font-semibold">User Session:</h2>
33
- <pre className="text-xs bg-muted p-2 rounded">{JSON.stringify(session, null, 2)}</pre>
34
- </div>
35
-
36
- <div className="rounded-lg border p-4">
37
- <h2 className="font-semibold">Secret Data (Client-side):</h2>
38
- {isLoading ? (
39
- <p>Loading...</p>
40
- ) : (
41
- <pre className="text-xs bg-muted p-2 rounded">{JSON.stringify(data, null, 2)}</pre>
42
- )}
43
- </div>
44
- </div>
45
- );
46
- }
@@ -1,23 +0,0 @@
1
- import { Outlet, createFileRoute } from "@tanstack/react-router";
2
- import { SidebarProvider, SidebarTrigger } from "@workspace/ui/components/sidebar";
3
- import { AuthSidebar } from "@/components/app-sidebar";
4
-
5
- export const Route = createFileRoute("/_auth")({
6
- component: AuthLayout,
7
- });
8
-
9
- function AuthLayout() {
10
- return (
11
- <SidebarProvider>
12
- <AuthSidebar />
13
- <main className="flex flex-1 flex-col overflow-hidden">
14
- <header className="flex h-16 shrink-0 items-center gap-2 border-b px-4">
15
- <SidebarTrigger />
16
- </header>
17
- <div className="flex-1 overflow-auto p-4">
18
- <Outlet />
19
- </div>
20
- </main>
21
- </SidebarProvider>
22
- );
23
- }