create-z3 0.0.47 → 0.0.49

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 (27) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.js +39 -38
  3. package/package.json +11 -11
  4. package/templates/nextjs/convex/auth/adapter/index.ts +7 -22
  5. package/templates/nextjs/convex/auth/index.ts +1 -1
  6. package/templates/nextjs/convex/auth/plugins/index.ts +6 -2
  7. package/templates/nextjs/convex/auth/sessions.ts +1 -1
  8. package/templates/nextjs/convex/auth.config.ts +7 -0
  9. package/templates/nextjs/convex/schema.ts +30 -2
  10. package/templates/nextjs/package.json +3 -2
  11. package/templates/nextjs/src/app/(frontend)/layout.tsx +21 -27
  12. package/templates/nextjs/src/auth/client.tsx +2 -4
  13. package/templates/nextjs/src/auth/permissions.ts +2 -2
  14. package/templates/nextjs/src/components/component-example.tsx +44 -492
  15. package/templates/nextjs/src/db/constants/index.ts +1 -0
  16. package/templates/tanstack-start/convex/auth/adapter/index.ts +7 -22
  17. package/templates/tanstack-start/convex/auth/index.ts +1 -1
  18. package/templates/tanstack-start/convex/auth/plugins/index.ts +5 -1
  19. package/templates/tanstack-start/convex/auth/sessions.ts +1 -1
  20. package/templates/tanstack-start/convex/auth.config.ts +7 -0
  21. package/templates/tanstack-start/convex/schema.ts +37 -2
  22. package/templates/tanstack-start/package.json +3 -2
  23. package/templates/tanstack-start/src/components/component-example.tsx +41 -460
  24. package/templates/tanstack-start/src/db/constants/index.ts +1 -0
  25. package/templates/tanstack-start/src/lib/auth/client.ts +2 -1
  26. package/templates/tanstack-start/src/lib/auth/permissions.ts +2 -2
  27. package/templates/tanstack-start/src/routes/auth/$authView.tsx +1 -1
@@ -1,503 +1,55 @@
1
1
  "use client"
2
2
 
3
- import * as React from "react"
3
+ import { TerminalIcon, UserIcon } from "lucide-react"
4
+ import Link from "next/link"
4
5
 
5
- import {
6
- Example,
7
- ExampleWrapper,
8
- } from "~/components/example"
9
- import {
10
- AlertDialog,
11
- AlertDialogAction,
12
- AlertDialogCancel,
13
- AlertDialogContent,
14
- AlertDialogDescription,
15
- AlertDialogFooter,
16
- AlertDialogHeader,
17
- AlertDialogMedia,
18
- AlertDialogTitle,
19
- AlertDialogTrigger,
20
- } from "~/components/ui/alert-dialog"
21
- import { Badge } from "~/components/ui/badge"
6
+ import { signOut, useSession } from "~/auth/client"
22
7
  import { Button } from "~/components/ui/button"
23
- import {
24
- Card,
25
- CardAction,
26
- CardContent,
27
- CardDescription,
28
- CardFooter,
29
- CardHeader,
30
- CardTitle,
31
- } from "~/components/ui/card"
32
- import {
33
- Combobox,
34
- ComboboxContent,
35
- ComboboxEmpty,
36
- ComboboxInput,
37
- ComboboxItem,
38
- ComboboxList,
39
- } from "~/components/ui/combobox"
40
- import {
41
- DropdownMenu,
42
- DropdownMenuCheckboxItem,
43
- DropdownMenuContent,
44
- DropdownMenuGroup,
45
- DropdownMenuItem,
46
- DropdownMenuLabel,
47
- DropdownMenuPortal,
48
- DropdownMenuRadioGroup,
49
- DropdownMenuRadioItem,
50
- DropdownMenuSeparator,
51
- DropdownMenuShortcut,
52
- DropdownMenuSub,
53
- DropdownMenuSubContent,
54
- DropdownMenuSubTrigger,
55
- DropdownMenuTrigger,
56
- } from "~/components/ui/dropdown-menu"
57
- import { Field, FieldGroup, FieldLabel } from "~/components/ui/field"
58
- import { Input } from "~/components/ui/input"
59
- import {
60
- Select,
61
- SelectContent,
62
- SelectGroup,
63
- SelectItem,
64
- SelectTrigger,
65
- SelectValue,
66
- } from "~/components/ui/select"
67
- import { Textarea } from "~/components/ui/textarea"
68
- import { PlusIcon, BluetoothIcon, MoreVerticalIcon, FileIcon, FolderIcon, FolderOpenIcon, FileCodeIcon, MoreHorizontalIcon, FolderSearchIcon, SaveIcon, DownloadIcon, EyeIcon, LayoutIcon, PaletteIcon, SunIcon, MoonIcon, MonitorIcon, UserIcon, CreditCardIcon, SettingsIcon, KeyboardIcon, LanguagesIcon, BellIcon, MailIcon, ShieldIcon, HelpCircleIcon, FileTextIcon, LogOutIcon } from "lucide-react"
69
8
  import { ThemeToggle } from "~/components/ui/theme-toggle"
70
9
 
71
10
  export function ComponentExample() {
72
- return (
73
- <ExampleWrapper>
74
- <ThemeToggle className="absolute w-md:top-10 right-10 top-2" />
75
- <CardExample />
76
- <FormExample />
77
- </ExampleWrapper>
78
- )
79
- }
80
-
81
- function CardExample() {
82
- return (
83
- <Example title="Card" className="items-center justify-center">
84
- <Card className="relative w-full max-w-sm overflow-hidden pt-0">
85
- <div className="bg-primary absolute inset-0 z-30 aspect-video opacity-50 mix-blend-color" />
86
- <img
87
- src="https://images.unsplash.com/photo-1604076850742-4c7221f3101b?q=80&w=1887&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
88
- alt="Photo by mymind on Unsplash"
89
- title="Photo by mymind on Unsplash"
90
- className="relative z-20 aspect-video w-full object-cover brightness-60 grayscale"
91
- />
92
- <CardHeader>
93
- <CardTitle>Observability Plus is replacing Monitoring</CardTitle>
94
- <CardDescription>
95
- Switch to the improved way to explore your data, with natural
96
- language. Monitoring will no longer be available on the Pro plan in
97
- November, 2025
98
- </CardDescription>
99
- </CardHeader>
100
- <CardFooter>
101
- <AlertDialog>
102
- <AlertDialogTrigger render={<Button />}>
103
- <PlusIcon data-icon="inline-start" />
104
- Show Dialog
105
- </AlertDialogTrigger>
106
- <AlertDialogContent size="sm">
107
- <AlertDialogHeader>
108
- <AlertDialogMedia>
109
- <BluetoothIcon
110
- />
111
- </AlertDialogMedia>
112
- <AlertDialogTitle>Allow accessory to connect?</AlertDialogTitle>
113
- <AlertDialogDescription>
114
- Do you want to allow the USB accessory to connect to this
115
- device?
116
- </AlertDialogDescription>
117
- </AlertDialogHeader>
118
- <AlertDialogFooter>
119
- <AlertDialogCancel>Don&apos;t allow</AlertDialogCancel>
120
- <AlertDialogAction>Allow</AlertDialogAction>
121
- </AlertDialogFooter>
122
- </AlertDialogContent>
123
- </AlertDialog>
124
- <Badge variant="secondary" className="ml-auto">
125
- Warning
126
- </Badge>
127
- </CardFooter>
128
- </Card>
129
- </Example>
130
- )
131
- }
132
-
133
- const frameworks = [
134
- "Next.js",
135
- "SvelteKit",
136
- "Nuxt.js",
137
- "Remix",
138
- "Astro",
139
- ] as const
140
-
141
- const roleItems = [
142
- { label: "Developer", value: "developer" },
143
- { label: "Designer", value: "designer" },
144
- { label: "Manager", value: "manager" },
145
- { label: "Other", value: "other" },
146
- ]
147
-
148
- function FormExample() {
149
- const [notifications, setNotifications] = React.useState({
150
- email: true,
151
- sms: false,
152
- push: true,
153
- })
154
- const [theme, setTheme] = React.useState("light")
11
+ const { data: session } = useSession()
155
12
 
156
13
  return (
157
- <Example title="Form">
158
- <Card className="w-full max-w-md">
159
- <CardHeader>
160
- <CardTitle>User Information</CardTitle>
161
- <CardDescription>Please fill in your details below</CardDescription>
162
- <CardAction>
163
- <DropdownMenu>
164
- <DropdownMenuTrigger
165
- render={<Button variant="ghost" size="icon" />}
166
- >
167
- <MoreVerticalIcon
168
- />
169
- <span className="sr-only">More options</span>
170
- </DropdownMenuTrigger>
171
- <DropdownMenuContent align="end" className="w-56">
172
- <DropdownMenuGroup>
173
- <DropdownMenuLabel>File</DropdownMenuLabel>
174
- <DropdownMenuItem>
175
- <FileIcon
176
- />
177
- New File
178
- <DropdownMenuShortcut>⌘N</DropdownMenuShortcut>
179
- </DropdownMenuItem>
180
- <DropdownMenuItem>
181
- <FolderIcon
182
- />
183
- New Folder
184
- <DropdownMenuShortcut>⇧⌘N</DropdownMenuShortcut>
185
- </DropdownMenuItem>
186
- <DropdownMenuSub>
187
- <DropdownMenuSubTrigger>
188
- <FolderOpenIcon
189
- />
190
- Open Recent
191
- </DropdownMenuSubTrigger>
192
- <DropdownMenuPortal>
193
- <DropdownMenuSubContent>
194
- <DropdownMenuGroup>
195
- <DropdownMenuLabel>Recent Projects</DropdownMenuLabel>
196
- <DropdownMenuItem>
197
- <FileCodeIcon
198
- />
199
- Project Alpha
200
- </DropdownMenuItem>
201
- <DropdownMenuItem>
202
- <FileCodeIcon
203
- />
204
- Project Beta
205
- </DropdownMenuItem>
206
- <DropdownMenuSub>
207
- <DropdownMenuSubTrigger>
208
- <MoreHorizontalIcon
209
- />
210
- More Projects
211
- </DropdownMenuSubTrigger>
212
- <DropdownMenuPortal>
213
- <DropdownMenuSubContent>
214
- <DropdownMenuItem>
215
- <FileCodeIcon
216
- />
217
- Project Gamma
218
- </DropdownMenuItem>
219
- <DropdownMenuItem>
220
- <FileCodeIcon
221
- />
222
- Project Delta
223
- </DropdownMenuItem>
224
- </DropdownMenuSubContent>
225
- </DropdownMenuPortal>
226
- </DropdownMenuSub>
227
- </DropdownMenuGroup>
228
- <DropdownMenuSeparator />
229
- <DropdownMenuGroup>
230
- <DropdownMenuItem>
231
- <FolderSearchIcon
232
- />
233
- Browse...
234
- </DropdownMenuItem>
235
- </DropdownMenuGroup>
236
- </DropdownMenuSubContent>
237
- </DropdownMenuPortal>
238
- </DropdownMenuSub>
239
- <DropdownMenuSeparator />
240
- <DropdownMenuItem>
241
- <SaveIcon
242
- />
243
- Save
244
- <DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
245
- </DropdownMenuItem>
246
- <DropdownMenuItem>
247
- <DownloadIcon
248
- />
249
- Export
250
- <DropdownMenuShortcut>⇧⌘E</DropdownMenuShortcut>
251
- </DropdownMenuItem>
252
- </DropdownMenuGroup>
253
- <DropdownMenuSeparator />
254
- <DropdownMenuGroup>
255
- <DropdownMenuLabel>View</DropdownMenuLabel>
256
- <DropdownMenuCheckboxItem
257
- checked={notifications.email}
258
- onCheckedChange={(checked) =>
259
- setNotifications({
260
- ...notifications,
261
- email: checked === true,
262
- })
263
- }
264
- >
265
- <EyeIcon
266
- />
267
- Show Sidebar
268
- </DropdownMenuCheckboxItem>
269
- <DropdownMenuCheckboxItem
270
- checked={notifications.sms}
271
- onCheckedChange={(checked) =>
272
- setNotifications({
273
- ...notifications,
274
- sms: checked === true,
275
- })
276
- }
277
- >
278
- <LayoutIcon
279
- />
280
- Show Status Bar
281
- </DropdownMenuCheckboxItem>
282
- <DropdownMenuSub>
283
- <DropdownMenuSubTrigger>
284
- <PaletteIcon
285
- />
286
- Theme
287
- </DropdownMenuSubTrigger>
288
- <DropdownMenuPortal>
289
- <DropdownMenuSubContent>
290
- <DropdownMenuGroup>
291
- <DropdownMenuLabel>Appearance</DropdownMenuLabel>
292
- <DropdownMenuRadioGroup
293
- value={theme}
294
- onValueChange={setTheme}
295
- >
296
- <DropdownMenuRadioItem value="light">
297
- <SunIcon
298
- />
299
- Light
300
- </DropdownMenuRadioItem>
301
- <DropdownMenuRadioItem value="dark">
302
- <MoonIcon
303
- />
304
- Dark
305
- </DropdownMenuRadioItem>
306
- <DropdownMenuRadioItem value="system">
307
- <MonitorIcon
308
- />
309
- System
310
- </DropdownMenuRadioItem>
311
- </DropdownMenuRadioGroup>
312
- </DropdownMenuGroup>
313
- </DropdownMenuSubContent>
314
- </DropdownMenuPortal>
315
- </DropdownMenuSub>
316
- </DropdownMenuGroup>
317
- <DropdownMenuSeparator />
318
- <DropdownMenuGroup>
319
- <DropdownMenuLabel>Account</DropdownMenuLabel>
320
- <DropdownMenuItem>
321
- <UserIcon
322
- />
323
- Profile
324
- <DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
325
- </DropdownMenuItem>
326
- <DropdownMenuItem>
327
- <CreditCardIcon
328
- />
329
- Billing
330
- </DropdownMenuItem>
331
- <DropdownMenuSub>
332
- <DropdownMenuSubTrigger>
333
- <SettingsIcon
334
- />
335
- Settings
336
- </DropdownMenuSubTrigger>
337
- <DropdownMenuPortal>
338
- <DropdownMenuSubContent>
339
- <DropdownMenuGroup>
340
- <DropdownMenuLabel>Preferences</DropdownMenuLabel>
341
- <DropdownMenuItem>
342
- <KeyboardIcon
343
- />
344
- Keyboard Shortcuts
345
- </DropdownMenuItem>
346
- <DropdownMenuItem>
347
- <LanguagesIcon
348
- />
349
- Language
350
- </DropdownMenuItem>
351
- <DropdownMenuSub>
352
- <DropdownMenuSubTrigger>
353
- <BellIcon
354
- />
355
- Notifications
356
- </DropdownMenuSubTrigger>
357
- <DropdownMenuPortal>
358
- <DropdownMenuSubContent>
359
- <DropdownMenuGroup>
360
- <DropdownMenuLabel>
361
- Notification Types
362
- </DropdownMenuLabel>
363
- <DropdownMenuCheckboxItem
364
- checked={notifications.push}
365
- onCheckedChange={(checked) =>
366
- setNotifications({
367
- ...notifications,
368
- push: checked === true,
369
- })
370
- }
371
- >
372
- <BellIcon
373
- />
374
- Push Notifications
375
- </DropdownMenuCheckboxItem>
376
- <DropdownMenuCheckboxItem
377
- checked={notifications.email}
378
- onCheckedChange={(checked) =>
379
- setNotifications({
380
- ...notifications,
381
- email: checked === true,
382
- })
383
- }
384
- >
385
- <MailIcon
386
- />
387
- Email Notifications
388
- </DropdownMenuCheckboxItem>
389
- </DropdownMenuGroup>
390
- </DropdownMenuSubContent>
391
- </DropdownMenuPortal>
392
- </DropdownMenuSub>
393
- </DropdownMenuGroup>
394
- <DropdownMenuSeparator />
395
- <DropdownMenuGroup>
396
- <DropdownMenuItem>
397
- <ShieldIcon
398
- />
399
- Privacy & Security
400
- </DropdownMenuItem>
401
- </DropdownMenuGroup>
402
- </DropdownMenuSubContent>
403
- </DropdownMenuPortal>
404
- </DropdownMenuSub>
405
- </DropdownMenuGroup>
406
- <DropdownMenuSeparator />
407
- <DropdownMenuGroup>
408
- <DropdownMenuItem>
409
- <HelpCircleIcon
410
- />
411
- Help & Support
412
- </DropdownMenuItem>
413
- <DropdownMenuItem>
414
- <FileTextIcon
415
- />
416
- Documentation
417
- </DropdownMenuItem>
418
- </DropdownMenuGroup>
419
- <DropdownMenuSeparator />
420
- <DropdownMenuGroup>
421
- <DropdownMenuItem variant="destructive">
422
- <LogOutIcon
423
- />
424
- Sign Out
425
- <DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
426
- </DropdownMenuItem>
427
- </DropdownMenuGroup>
428
- </DropdownMenuContent>
429
- </DropdownMenu>
430
- </CardAction>
431
- </CardHeader>
432
- <CardContent>
433
- <form>
434
- <FieldGroup>
435
- <div className="grid grid-cols-2 gap-4">
436
- <Field>
437
- <FieldLabel htmlFor="small-form-name">Name</FieldLabel>
438
- <Input
439
- id="small-form-name"
440
- placeholder="Enter your name"
441
- required
442
- />
443
- </Field>
444
- <Field>
445
- <FieldLabel htmlFor="small-form-role">Role</FieldLabel>
446
- <Select items={roleItems} defaultValue={null}>
447
- <SelectTrigger id="small-form-role">
448
- <SelectValue />
449
- </SelectTrigger>
450
- <SelectContent>
451
- <SelectGroup>
452
- {roleItems.map((item) => (
453
- <SelectItem key={item.value} value={item.value}>
454
- {item.label}
455
- </SelectItem>
456
- ))}
457
- </SelectGroup>
458
- </SelectContent>
459
- </Select>
460
- </Field>
461
- </div>
462
- <Field>
463
- <FieldLabel htmlFor="small-form-framework">
464
- Framework
465
- </FieldLabel>
466
- <Combobox items={frameworks}>
467
- <ComboboxInput
468
- id="small-form-framework"
469
- placeholder="Select a framework"
470
- required
471
- />
472
- <ComboboxContent>
473
- <ComboboxEmpty>No frameworks found.</ComboboxEmpty>
474
- <ComboboxList>
475
- {(item) => (
476
- <ComboboxItem key={item} value={item}>
477
- {item}
478
- </ComboboxItem>
479
- )}
480
- </ComboboxList>
481
- </ComboboxContent>
482
- </Combobox>
483
- </Field>
484
- <Field>
485
- <FieldLabel htmlFor="small-form-comments">Comments</FieldLabel>
486
- <Textarea
487
- id="small-form-comments"
488
- placeholder="Add any additional comments"
489
- />
490
- </Field>
491
- <Field orientation="horizontal">
492
- <Button type="submit">Submit</Button>
493
- <Button variant="outline" type="button">
494
- Cancel
495
- </Button>
496
- </Field>
497
- </FieldGroup>
498
- </form>
499
- </CardContent>
500
- </Card>
501
- </Example>
14
+ <div className="bg-background flex min-h-screen flex-col items-center justify-center gap-8 p-6 text-center">
15
+ <div className="absolute top-4 right-4 flex items-center gap-2">
16
+ {session?.user && (
17
+ <>
18
+ <div className="bg-muted flex size-8 items-center justify-center rounded-full">
19
+ <UserIcon className="text-muted-foreground size-4" />
20
+ </div>
21
+ <span className="text-sm font-medium">{session.user.name}</span>
22
+ </>
23
+ )}
24
+ <ThemeToggle />
25
+ </div>
26
+
27
+ <div className="flex flex-col items-center gap-4">
28
+ <div className="bg-foreground text-background flex size-14 items-center justify-center rounded-2xl">
29
+ <TerminalIcon className="size-7" />
30
+ </div>
31
+ <div className="flex flex-col gap-1">
32
+ <h1 className="text-3xl font-bold tracking-tight">create-z3-app</h1>
33
+ <p className="text-muted-foreground max-w-sm text-base">
34
+ A full-stack starter with Next.js, Convex, and Better Auth — ready to ship.
35
+ </p>
36
+ </div>
37
+ </div>
38
+
39
+ <div className="flex gap-3">
40
+ {session?.user ? (
41
+ <Button variant="outline" onClick={() => signOut()}>Sign out</Button>
42
+ ) : (
43
+ <>
44
+ <Button nativeButton={false} render={<Link href="/auth/sign-up" />}>Sign up</Button>
45
+ <Button nativeButton={false} variant="outline" render={<Link href="/auth/sign-in" />}>Sign in</Button>
46
+ </>
47
+ )}
48
+ </div>
49
+
50
+ <code className="bg-muted text-muted-foreground rounded-lg px-4 py-2 text-sm font-mono">
51
+ npm create z3-app@latest
52
+ </code>
53
+ </div>
502
54
  )
503
55
  }
@@ -6,6 +6,7 @@ export const TABLE_SLUG_ACCOUNTS = "account" as const;
6
6
  export const TABLE_SLUG_SESSIONS = "session" as const;
7
7
  export const TABLE_SLUG_VERIFICATIONS = "verification" as const;
8
8
  export const TABLE_SLUG_JWKS = "jwks" as const;
9
+ export const TABLE_SLUG_API_KEYS = "apikey" as const;
9
10
 
10
11
  export const COLLECTION_SLUG_MEDIA = "media" as const;
11
12
 
@@ -46,6 +46,12 @@ export const convexAdapter = <DataModel extends GenericDataModel>(
46
46
 
47
47
  return {
48
48
  id: "convex",
49
+ // Tell the convex() plugin this context supports mutations. It checks
50
+ // ctx.context.adapter.options?.isRunMutationCtx — if falsy it replaces all
51
+ // adapter writes with silent no-ops. HTTP actions always have runMutation.
52
+ options: {
53
+ isRunMutationCtx: "runMutation" in ctx,
54
+ },
49
55
 
50
56
  create: async ({ data, model, select }): Promise<any> => {
51
57
  return await ctx.runMutation(internal.auth.db.dbCreate, {
@@ -185,34 +191,12 @@ export const convexAdapter = <DataModel extends GenericDataModel>(
185
191
  if (data && fieldAttributes.type === "date") {
186
192
  return new Date(data).getTime();
187
193
  }
188
- // Handle array fields - Better Auth may send single values or arrays
189
- if ((fieldAttributes.type as string)?.endsWith("[]")) {
190
- // If already an array, return as-is
191
- if (Array.isArray(data)) {
192
- return data
193
- }
194
- // If it's a string that looks like JSON array, parse it
195
- if (typeof data === "string") {
196
- try {
197
- const parsed = JSON.parse(data)
198
- return Array.isArray(parsed) ? parsed : [data]
199
- } catch {
200
- // If parsing fails, wrap the string in an array
201
- return [data]
202
- }
203
- }
204
- // For any other value type, wrap in array
205
- if (data !== null && data !== undefined) {
206
- return [data]
207
- }
208
- }
209
194
  return data;
210
195
  },
211
196
  customTransformOutput: ({ data, fieldAttributes }) => {
212
197
  if (data && fieldAttributes.type === "date") {
213
198
  return new Date(data).getTime();
214
199
  }
215
- // Arrays are stored natively in Convex, no transformation needed for output
216
200
  return data;
217
201
  },
218
202
  debugLogs: config.debugLogs ?? false,
@@ -226,6 +210,7 @@ export const convexAdapter = <DataModel extends GenericDataModel>(
226
210
  supportsDates: false,
227
211
  supportsJSON: true,
228
212
  supportsNumericIds: false,
213
+ supportsArrays: true,
229
214
  transaction: false,
230
215
  usePlural: false,
231
216
  },
@@ -39,7 +39,7 @@ export const createAuth = (
39
39
  trustedOrigins: [process.env.SITE_URL!],
40
40
  user: {
41
41
  additionalFields: {
42
- role: {
42
+ roles: {
43
43
  type: "string[]",
44
44
  defaultValue: [USER_ROLES.user],
45
45
  required: true
@@ -1,4 +1,7 @@
1
- import { admin, apiKey } from "better-auth/plugins"
1
+ import { admin } from "better-auth/plugins"
2
+ import { apiKey } from "@better-auth/api-key"
3
+ import { convex } from "@convex-dev/better-auth/plugins"
4
+ import authConfig from "@convex/auth.config"
2
5
  import { USER_ROLES } from "~/db/constants"
3
6
 
4
7
  const plugins = [
@@ -7,6 +10,7 @@ const plugins = [
7
10
  defaultRole: USER_ROLES.user
8
11
  }),
9
12
  apiKey(),
13
+ convex({ authConfig }),
10
14
  ]
11
15
 
12
16
  export default plugins
@@ -53,7 +53,7 @@ export const getSessionWithUser = query({
53
53
  email: user.email,
54
54
  emailVerified: user.emailVerified,
55
55
  image: user.image,
56
- role: user.role,
56
+ roles: user.roles,
57
57
  },
58
58
  };
59
59
  },
@@ -0,0 +1,7 @@
1
+ import type { AuthConfig } from "convex/server"
2
+
3
+ import { getAuthConfigProvider } from "@convex-dev/better-auth/auth-config"
4
+
5
+ export default {
6
+ providers: [getAuthConfigProvider()],
7
+ } satisfies AuthConfig