create-m5kdev 0.21.3 → 0.21.5

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 (40) hide show
  1. package/package.json +1 -1
  2. package/templates/minimal-app/.cursor/rules/module-module-guide.mdc +18 -20
  3. package/templates/minimal-app/AGENTS.md.tpl +4 -3
  4. package/templates/minimal-app/apps/email/src/emails/accountDeletionEmail.tsx.tpl +8 -4
  5. package/templates/minimal-app/apps/server/AGENTS.md.tpl +6 -5
  6. package/templates/minimal-app/apps/server/drizzle/generate-schema.ts.tpl +1 -5
  7. package/templates/minimal-app/apps/server/drizzle/seed.ts.tpl +96 -27
  8. package/templates/minimal-app/apps/server/src/app.ts.tpl +84 -64
  9. package/templates/minimal-app/apps/server/src/generated/schema.ts.tpl +13 -0
  10. package/templates/minimal-app/apps/server/src/index.ts.tpl +4 -1
  11. package/templates/minimal-app/apps/server/src/lib/auth.ts.tpl +7 -1
  12. package/templates/minimal-app/apps/server/src/modules/posts/posts.db.ts.tpl +1 -1
  13. package/templates/minimal-app/apps/server/src/modules/posts/posts.grants.ts.tpl +40 -40
  14. package/templates/minimal-app/apps/server/src/modules/posts/posts.module.ts.tpl +5 -11
  15. package/templates/minimal-app/apps/server/src/modules/posts/posts.repository.ts.tpl +2 -2
  16. package/templates/minimal-app/apps/server/src/modules/posts/posts.service.ts.tpl +4 -4
  17. package/templates/minimal-app/apps/server/src/modules/posts/posts.trpc.ts.tpl +1 -1
  18. package/templates/minimal-app/apps/server/src/types.ts.tpl +1 -3
  19. package/templates/minimal-app/apps/server/tsconfig.json.tpl +1 -0
  20. package/templates/minimal-app/apps/shared/.env.example.tpl +1 -0
  21. package/templates/minimal-app/apps/shared/.env.tpl +1 -0
  22. package/templates/minimal-app/apps/shared/src/modules/app/app.constants.ts.tpl +2 -0
  23. package/templates/minimal-app/apps/webapp/package.json.tpl +0 -1
  24. package/templates/minimal-app/apps/webapp/public/push-sw.js +2 -2
  25. package/templates/minimal-app/apps/webapp/src/Layout.tsx.tpl +51 -40
  26. package/templates/minimal-app/apps/webapp/src/Providers.tsx.tpl +21 -11
  27. package/templates/minimal-app/apps/webapp/src/Router.tsx.tpl +76 -20
  28. package/templates/minimal-app/apps/webapp/src/modules/notification/PushNotificationsPanel.tsx.tpl +12 -16
  29. package/templates/minimal-app/apps/webapp/src/modules/posts/PostsRoute.tsx.tpl +121 -119
  30. package/templates/minimal-app/apps/webapp/src/utils/trpc.ts.tpl +5 -3
  31. package/templates/minimal-app/apps/webapp/translations/en/blog-app.json.tpl +13 -1
  32. package/templates/minimal-app/apps/webapp/tsconfig.json.tpl +1 -0
  33. package/templates/minimal-app/pnpm-workspace.yaml.tpl +8 -8
  34. package/templates/minimal-app/apps/server/src/modules.ts.tpl +0 -33
  35. package/templates/minimal-app/apps/server/src/repository.ts.tpl +0 -6
  36. package/templates/minimal-app/apps/server/src/schema-modules.ts.tpl +0 -19
  37. package/templates/minimal-app/apps/server/src/service.ts.tpl +0 -7
  38. package/templates/minimal-app/apps/server/src/trpc.ts.tpl +0 -6
  39. package/templates/minimal-app/apps/server/src/workflow.ts.tpl +0 -4
  40. package/templates/minimal-app/apps/webapp/src/components/TrpcQueryProvider.tsx.tpl +0 -61
@@ -1,15 +1,3 @@
1
- import {
2
- POST_FILTER_VALUES,
3
- POSTS_PAGE_SIZE,
4
- } from "{{PACKAGE_SCOPE}}/shared/modules/posts/posts.constants";
5
- import type {
6
- PostCreateInputSchema,
7
- PostPublishInputSchema,
8
- PostSoftDeleteInputSchema,
9
- PostsListInputSchema,
10
- PostsListOutputSchema,
11
- PostUpdateInputSchema,
12
- } from "{{PACKAGE_SCOPE}}/shared/modules/posts/posts.schema";
13
1
  import {
14
2
  Button,
15
3
  Card,
@@ -23,6 +11,18 @@ import {
23
11
  TextArea,
24
12
  } from "@heroui/react";
25
13
  import { useDialog } from "@m5kdev/web-ui/components/DialogProvider";
14
+ import {
15
+ POST_FILTER_VALUES,
16
+ POSTS_PAGE_SIZE,
17
+ } from "{{PACKAGE_SCOPE}}/shared/modules/posts/posts.constants";
18
+ import type {
19
+ PostCreateInputSchema,
20
+ PostPublishInputSchema,
21
+ PostSoftDeleteInputSchema,
22
+ PostsListInputSchema,
23
+ PostsListOutputSchema,
24
+ PostUpdateInputSchema,
25
+ } from "{{PACKAGE_SCOPE}}/shared/modules/posts/posts.schema";
26
26
  import { type UseQueryOptions, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
27
27
  import {
28
28
  ArrowLeftIcon,
@@ -78,7 +78,7 @@ function getReadingTime(content: string): string {
78
78
  }
79
79
 
80
80
  export function PostsRoute() {
81
- const { t } = useTranslation("blog-app");
81
+ const { t } = useTranslation("blog{{PACKAGE_SCOPE}}");
82
82
  const trpc = useTRPC();
83
83
  const queryClient = useQueryClient();
84
84
  const showDialog = useDialog();
@@ -235,7 +235,7 @@ export function PostsRoute() {
235
235
  showDialog({
236
236
  title: t("posts.deleteDialog.title"),
237
237
  description: t("posts.deleteDialog.body"),
238
- color: "danger",
238
+ intent: "danger",
239
239
  cancelable: true,
240
240
  confirmLabel: t("posts.deleteDialog.confirm"),
241
241
  cancelLabel: t("posts.deleteDialog.cancel"),
@@ -268,11 +268,7 @@ export function PostsRoute() {
268
268
  </h2>
269
269
  <p className="mt-4 max-w-2xl text-sm leading-7 text-muted-ink">{t("posts.hero.body")}</p>
270
270
  <div className="mt-6 flex flex-wrap gap-3">
271
- <Button
272
- className="rounded-full"
273
- variant="primary"
274
- onPress={openCreate}
275
- >
271
+ <Button className="rounded-full" variant="primary" onPress={openCreate}>
276
272
  <span className="inline-flex items-center gap-2">
277
273
  <PlusIcon className="h-4 w-4" />
278
274
  {t("posts.hero.new")}
@@ -337,17 +333,25 @@ export function PostsRoute() {
337
333
  </Select.Trigger>
338
334
  <Select.Popover>
339
335
  <ListBox>
340
- <ListBox.Item className="text-sm" id="all" textValue={t("posts.filters.all")}>
336
+ <ListBox.Item
337
+ className="text-sm"
338
+ id={`${statusFieldId}-all`}
339
+ textValue={t("posts.filters.all")}
340
+ >
341
341
  {t("posts.filters.all")}
342
342
  <ListBox.ItemIndicator />
343
343
  </ListBox.Item>
344
- <ListBox.Item className="text-sm" id="draft" textValue={t("posts.filters.draft")}>
344
+ <ListBox.Item
345
+ className="text-sm"
346
+ id={`${statusFieldId}-draft`}
347
+ textValue={t("posts.filters.draft")}
348
+ >
345
349
  {t("posts.filters.draft")}
346
350
  <ListBox.ItemIndicator />
347
351
  </ListBox.Item>
348
352
  <ListBox.Item
349
353
  className="text-sm"
350
- id="published"
354
+ id={`${statusFieldId}-published`}
351
355
  textValue={t("posts.filters.published")}
352
356
  >
353
357
  {t("posts.filters.published")}
@@ -395,6 +399,7 @@ export function PostsRoute() {
395
399
  deleteMutation.isPending && deleteMutation.variables?.id === row.id;
396
400
 
397
401
  return (
402
+ // biome-ignore lint/a11y/useSemanticElements: post row card with nested action buttons
398
403
  <Card
399
404
  key={row.id}
400
405
  role="button"
@@ -621,103 +626,100 @@ export function PostsRoute() {
621
626
  }}
622
627
  >
623
628
  <Modal.Backdrop>
624
- <Modal.Container scroll="inside" size="lg" className="max-w-5xl">
625
- <Modal.Dialog>
626
- <form
627
- className="contents"
628
- onSubmit={onSubmit}
629
- >
630
- <Modal.Header className="flex flex-col gap-2 px-6 pt-6">
631
- <p className="text-[0.68rem] font-semibold uppercase tracking-[0.28em] text-amber-700/80">
632
- {editorState.id ? t("posts.editor.editEyebrow") : t("posts.editor.newEyebrow")}
633
- </p>
634
- <Modal.Heading className="font-editorial text-4xl leading-none text-ink">
635
- {editorState.id ? t("posts.editor.editTitle") : t("posts.editor.newTitle")}
636
- </Modal.Heading>
637
- </Modal.Header>
638
- <Modal.Body className="grid gap-4 px-6 pb-2">
639
- <div className="grid gap-2">
640
- <Label className="text-sm font-medium" htmlFor={editorTitleId}>
641
- {t("posts.editor.fields.title")}
642
- </Label>
643
- <Input
644
- id={editorTitleId}
645
- className="rounded-lg"
646
- variant="secondary"
647
- value={editorState.title}
648
- onChange={(event) =>
649
- setEditorState((state) => ({ ...state, title: event.target.value }))
650
- }
651
- isRequired
652
- />
653
- </div>
654
- <div className="grid gap-2">
655
- <Label className="text-sm font-medium" htmlFor={editorSlugId}>
656
- {t("posts.editor.fields.slug")}
657
- </Label>
658
- <Input
659
- id={editorSlugId}
660
- className="rounded-lg"
661
- variant="secondary"
662
- value={editorState.slug}
663
- onChange={(event) =>
664
- setEditorState((state) => ({ ...state, slug: event.target.value }))
665
- }
666
- />
667
- </div>
668
- <div className="grid gap-2">
669
- <Label className="text-sm font-medium" htmlFor={editorExcerptId}>
670
- {t("posts.editor.fields.excerpt")}
671
- </Label>
672
- <TextArea
673
- id={editorExcerptId}
674
- className="rounded-lg min-h-[5.5rem]"
675
- variant="secondary"
676
- rows={3}
677
- value={editorState.excerpt}
678
- onChange={(event) =>
679
- setEditorState((state) => ({ ...state, excerpt: event.target.value }))
680
- }
681
- />
682
- </div>
683
- <div className="grid gap-2">
684
- <Label className="text-sm font-medium" htmlFor={editorContentId}>
685
- {t("posts.editor.fields.content")}
686
- </Label>
687
- <TextArea
688
- id={editorContentId}
689
- className="rounded-lg min-h-[12rem]"
690
- variant="secondary"
691
- rows={10}
692
- value={editorState.content}
693
- onChange={(event) =>
694
- setEditorState((state) => ({ ...state, content: event.target.value }))
695
- }
696
- isRequired
697
- />
698
- </div>
699
- </Modal.Body>
700
- <Modal.Footer className="px-6 pb-6">
701
- <Button
702
- className="rounded-full"
703
- variant="tertiary"
704
- type="button"
705
- onPress={() => setIsEditorOpen(false)}
706
- >
707
- {t("posts.editor.cancel")}
708
- </Button>
709
- <Button
710
- className="rounded-full"
711
- variant="primary"
712
- type="submit"
713
- isPending={createMutation.isPending || updateMutation.isPending}
714
- >
715
- {editorState.id ? t("posts.editor.save") : t("posts.editor.create")}
716
- </Button>
717
- </Modal.Footer>
718
- </form>
719
- </Modal.Dialog>
720
- </Modal.Container>
629
+ <Modal.Container scroll="inside" size="lg" className="max-w-5xl">
630
+ <Modal.Dialog>
631
+ <form className="contents" onSubmit={onSubmit}>
632
+ <Modal.Header className="flex flex-col gap-2 px-6 pt-6">
633
+ <p className="text-[0.68rem] font-semibold uppercase tracking-[0.28em] text-amber-700/80">
634
+ {editorState.id ? t("posts.editor.editEyebrow") : t("posts.editor.newEyebrow")}
635
+ </p>
636
+ <Modal.Heading className="font-editorial text-4xl leading-none text-ink">
637
+ {editorState.id ? t("posts.editor.editTitle") : t("posts.editor.newTitle")}
638
+ </Modal.Heading>
639
+ </Modal.Header>
640
+ <Modal.Body className="grid gap-4 px-6 pb-2">
641
+ <div className="grid gap-2">
642
+ <Label className="text-sm font-medium" htmlFor={editorTitleId}>
643
+ {t("posts.editor.fields.title")}
644
+ </Label>
645
+ <Input
646
+ id={editorTitleId}
647
+ className="rounded-lg"
648
+ variant="secondary"
649
+ value={editorState.title}
650
+ onChange={(event) =>
651
+ setEditorState((state) => ({ ...state, title: event.target.value }))
652
+ }
653
+ required
654
+ />
655
+ </div>
656
+ <div className="grid gap-2">
657
+ <Label className="text-sm font-medium" htmlFor={editorSlugId}>
658
+ {t("posts.editor.fields.slug")}
659
+ </Label>
660
+ <Input
661
+ id={editorSlugId}
662
+ className="rounded-lg"
663
+ variant="secondary"
664
+ value={editorState.slug}
665
+ onChange={(event) =>
666
+ setEditorState((state) => ({ ...state, slug: event.target.value }))
667
+ }
668
+ />
669
+ </div>
670
+ <div className="grid gap-2">
671
+ <Label className="text-sm font-medium" htmlFor={editorExcerptId}>
672
+ {t("posts.editor.fields.excerpt")}
673
+ </Label>
674
+ <TextArea
675
+ id={editorExcerptId}
676
+ className="rounded-lg min-h-[5.5rem]"
677
+ variant="secondary"
678
+ rows={3}
679
+ value={editorState.excerpt}
680
+ onChange={(event) =>
681
+ setEditorState((state) => ({ ...state, excerpt: event.target.value }))
682
+ }
683
+ />
684
+ </div>
685
+ <div className="grid gap-2">
686
+ <Label className="text-sm font-medium" htmlFor={editorContentId}>
687
+ {t("posts.editor.fields.content")}
688
+ </Label>
689
+ <TextArea
690
+ id={editorContentId}
691
+ className="rounded-lg min-h-[12rem]"
692
+ variant="secondary"
693
+ rows={10}
694
+ value={editorState.content}
695
+ onChange={(event) =>
696
+ setEditorState((state) => ({ ...state, content: event.target.value }))
697
+ }
698
+ required
699
+ />
700
+ </div>
701
+ </Modal.Body>
702
+ <Modal.Footer className="px-6 pb-6">
703
+ <Button
704
+ className="rounded-full"
705
+ variant="tertiary"
706
+ type="button"
707
+ onPress={() => setIsEditorOpen(false)}
708
+ >
709
+ {t("posts.editor.cancel")}
710
+ </Button>
711
+ <Button
712
+ className="rounded-full"
713
+ variant="primary"
714
+ type="submit"
715
+ isPending={createMutation.isPending || updateMutation.isPending}
716
+ >
717
+ {editorState.id ? t("posts.editor.save") : t("posts.editor.create")}
718
+ </Button>
719
+ </Modal.Footer>
720
+ </form>
721
+ </Modal.Dialog>
722
+ </Modal.Container>
721
723
  </Modal.Backdrop>
722
724
  </Modal>
723
725
  </div>
@@ -1,4 +1,6 @@
1
+ import { useAppTRPC } from "@m5kdev/frontend/modules/app/hooks/useAppTrpc";
1
2
  import type { AppRouter } from "{{PACKAGE_SCOPE}}/server/types";
2
- import { createTRPCContext } from "@trpc/tanstack-react-query";
3
-
4
- export const { TRPCProvider, useTRPC, useTRPCClient } = createTRPCContext<AppRouter>();
3
+ import type { TRPCOptionsProxy } from "@trpc/tanstack-react-query";
4
+ export function useTRPC(): TRPCOptionsProxy<AppRouter> {
5
+ return useAppTRPC<AppRouter>();
6
+ }
@@ -12,7 +12,13 @@
12
12
  "auth": "Better Auth"
13
13
  },
14
14
  "navigation": {
15
- "posts": "Posts"
15
+ "posts": "Posts",
16
+ "members": "Members",
17
+ "childOrgs": "Child orgs",
18
+ "orgPreferences": "Org preferences",
19
+ "profile": "Profile",
20
+ "invites": "Invites",
21
+ "admin": "Admin"
16
22
  },
17
23
  "push": {
18
24
  "eyebrow": "Browser push",
@@ -117,5 +123,11 @@
117
123
  "deleted": "Post archived.",
118
124
  "validation": "Title and content are required."
119
125
  }
126
+ },
127
+ "auth": {
128
+ "header": {
129
+ "eyebrow": "Framework Starter",
130
+ "tagline": "A minimal m5kdev starter with auth, tRPC, and one polished posts module."
131
+ }
120
132
  }
121
133
  }
@@ -2,6 +2,7 @@
2
2
  "extends": "@m5kdev/config/tsconfig.vite.json",
3
3
  "compilerOptions": {
4
4
  "baseUrl": ".",
5
+ "ignoreDeprecations": "6.0",
5
6
  "rootDir": ".",
6
7
  "outDir": "dist",
7
8
  "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
@@ -3,18 +3,17 @@ packages:
3
3
 
4
4
  catalog:
5
5
  '@biomejs/biome': 2.2.0
6
- '@heroui/react': 3.0.2
7
- '@heroui/styles': 3.0.2
6
+ '@heroui/react': 3.0.3
7
+ '@heroui/styles': 3.0.3
8
8
  '@libsql/client': 0.17.0
9
- '@m5kdev/backend': 0.3.3
10
- '@m5kdev/commons': 0.3.3
11
- '@m5kdev/config': 0.3.3
12
- '@m5kdev/frontend': 0.3.3
13
- '@m5kdev/web-ui': 0.3.3
9
+ '@m5kdev/backend': 0.21.3
10
+ '@m5kdev/commons': 0.21.3
11
+ '@m5kdev/config': 0.21.3
12
+ '@m5kdev/frontend': 0.21.3
13
+ '@m5kdev/web-ui': 0.21.3
14
14
  '@react-email/components': 1.0.1
15
15
  '@tailwindcss/vite': 4.1.11
16
16
  '@tanstack/react-query': 5.83.0
17
- '@tanstack/react-query-devtools': 5.83.0
18
17
  '@trpc/client': 11.4.3
19
18
  '@trpc/server': 11.4.3
20
19
  '@trpc/tanstack-react-query': 11.4.3
@@ -32,6 +31,7 @@ catalog:
32
31
  drizzle-orm: 0.44.3
33
32
  express: 4.21.2
34
33
  i18next: 25.3.2
34
+ ioredis: 5.7.0
35
35
  lucide-react: 0.488.0
36
36
  neverthrow: 8.2.0
37
37
  nuqs: 2.4.3
@@ -1,33 +0,0 @@
1
- import { defineBackendModules } from "@m5kdev/backend/app";
2
- import { AuthModule } from "@m5kdev/backend/modules/auth/auth.module";
3
- import { EmailModule } from "@m5kdev/backend/modules/email/email.module";
4
- import { NotificationModule } from "@m5kdev/backend/modules/notification/notification.module";
5
- import { WorkflowModule } from "@m5kdev/backend/modules/workflow/workflow.module";
6
- import { templates } from "{{PACKAGE_SCOPE}}/email";
7
- import { PostsModule } from "./modules/posts/posts.module";
8
-
9
- export const emailBackendModule = new EmailModule(templates as never);
10
-
11
- export const authBackendModule = new AuthModule();
12
-
13
- export const workflowBackendModule = new WorkflowModule({
14
- queues: {
15
- fast: { concurrency: 5 },
16
- },
17
- defaultQueue: "fast",
18
- defaults: {
19
- timeout: 60_000,
20
- jobOptions: { removeOnComplete: { age: 3600 } },
21
- },
22
- });
23
-
24
- export const notificationBackendModule = new NotificationModule();
25
- export const postsBackendModule = new PostsModule();
26
-
27
- export const backendModules = defineBackendModules([
28
- emailBackendModule,
29
- authBackendModule,
30
- workflowBackendModule,
31
- notificationBackendModule,
32
- postsBackendModule,
33
- ] as const);
@@ -1,6 +0,0 @@
1
- import { builtBackendApp } from "./app";
2
-
3
- export const authRepository = builtBackendApp.modules.auth.repositories.auth;
4
- export const workflowRepository = builtBackendApp.modules.workflow.repositories.workflow;
5
- export const notificationRepository = builtBackendApp.modules.notification.repositories.notification;
6
- export const postsRepository = builtBackendApp.modules.posts.repositories.posts;
@@ -1,19 +0,0 @@
1
- import { defineBackendModule, defineBackendModules } from "@m5kdev/backend/app";
2
- import {
3
- authBackendModule,
4
- notificationBackendModule,
5
- postsBackendModule,
6
- workflowBackendModule,
7
- } from "./modules";
8
-
9
- export const emailSchemaModule = defineBackendModule({
10
- id: "email",
11
- });
12
-
13
- export const backendSchemaModules = defineBackendModules([
14
- emailSchemaModule,
15
- authBackendModule,
16
- workflowBackendModule,
17
- notificationBackendModule,
18
- postsBackendModule,
19
- ] as const);
@@ -1,7 +0,0 @@
1
- import { builtBackendApp, emailService } from "./app";
2
-
3
- export { emailService };
4
-
5
- export const authService = builtBackendApp.modules.auth.services.auth;
6
- export const postsService = builtBackendApp.modules.posts.services.posts;
7
- export const notificationService = builtBackendApp.modules.notification.services.notification;
@@ -1,6 +0,0 @@
1
- export {
2
- appRouter,
3
- type AppRouter,
4
- type RouterInputs,
5
- type RouterOutputs,
6
- } from "./app";
@@ -1,4 +0,0 @@
1
- import { builtBackendApp } from "./app";
2
-
3
- export const workflowService = builtBackendApp.modules.workflow.services.workflow;
4
- export const workflowRegistry = builtBackendApp.workflow!.registry;
@@ -1,61 +0,0 @@
1
- import type { AppRouter } from "{{PACKAGE_SCOPE}}/server/types";
2
- import { transformer } from "@m5kdev/commons/utils/trpc";
3
- import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
4
- import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
5
- import { createTRPCClient, httpBatchLink } from "@trpc/client";
6
- import { type ReactNode, useState } from "react";
7
- import { TRPCProvider } from "@/utils/trpc";
8
-
9
- let browserQueryClient: QueryClient | undefined;
10
-
11
- function createQueryClient() {
12
- return new QueryClient({
13
- defaultOptions: {
14
- queries: {
15
- staleTime: 60 * 1000,
16
- },
17
- },
18
- });
19
- }
20
-
21
- function getQueryClient() {
22
- if (typeof window === "undefined") {
23
- return createQueryClient();
24
- }
25
-
26
- if (!browserQueryClient) {
27
- browserQueryClient = createQueryClient();
28
- }
29
-
30
- return browserQueryClient;
31
- }
32
-
33
- export function TrpcQueryProvider({ children }: { children: ReactNode }) {
34
- const queryClient = getQueryClient();
35
- const [trpcClient] = useState(() =>
36
- createTRPCClient<AppRouter>({
37
- links: [
38
- httpBatchLink({
39
- url: `${import.meta.env.VITE_SERVER_URL}/trpc`,
40
- fetch(url, options) {
41
- return fetch(url, {
42
- ...options,
43
- body: options?.body ? (options.body as BodyInit | null | undefined) : undefined,
44
- credentials: "include",
45
- });
46
- },
47
- transformer,
48
- }),
49
- ],
50
- })
51
- );
52
-
53
- return (
54
- <QueryClientProvider client={queryClient}>
55
- <TRPCProvider trpcClient={trpcClient} queryClient={queryClient}>
56
- {children}
57
- </TRPCProvider>
58
- <ReactQueryDevtools client={queryClient} />
59
- </QueryClientProvider>
60
- );
61
- }