tvi-cli 0.1.4
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/README.md +147 -0
- package/dist/index.js +4315 -0
- package/package.json +75 -0
- package/templates/addons/biome/biome.json.hbs +83 -0
- package/templates/addons/husky/.husky/pre-commit +1 -0
- package/templates/addons/pwa/apps/web/next/public/favicon/apple-touch-icon.png +0 -0
- package/templates/addons/pwa/apps/web/next/public/favicon/favicon-96x96.png +0 -0
- package/templates/addons/pwa/apps/web/next/public/favicon/favicon.svg +6 -0
- package/templates/addons/pwa/apps/web/next/public/favicon/site.webmanifest.hbs +21 -0
- package/templates/addons/pwa/apps/web/next/public/favicon/web-app-manifest-192x192.png +0 -0
- package/templates/addons/pwa/apps/web/next/public/favicon/web-app-manifest-512x512.png +0 -0
- package/templates/addons/pwa/apps/web/next/src/app/manifest.ts.hbs +26 -0
- package/templates/addons/pwa/apps/web/vite/public/logo.png +0 -0
- package/templates/addons/pwa/apps/web/vite/pwa-assets.config.ts.hbs +12 -0
- package/templates/addons/turborepo/turbo.json.hbs +43 -0
- package/templates/api/orpc/native/utils/orpc.ts.hbs +35 -0
- package/templates/api/orpc/server/base/src/lib/context.ts.hbs +125 -0
- package/templates/api/orpc/server/base/src/lib/orpc.ts.hbs +21 -0
- package/templates/api/orpc/server/next/src/app/rpc/[...all]/route.ts.hbs +23 -0
- package/templates/api/orpc/web/nuxt/app/plugins/orpc.ts.hbs +35 -0
- package/templates/api/orpc/web/react/base/src/utils/orpc.ts.hbs +42 -0
- package/templates/api/orpc/web/solid/src/utils/orpc.ts.hbs +30 -0
- package/templates/api/orpc/web/svelte/src/lib/orpc.ts.hbs +31 -0
- package/templates/api/trpc/native/utils/trpc.ts.hbs +32 -0
- package/templates/api/trpc/server/base/src/lib/context.ts.hbs +127 -0
- package/templates/api/trpc/server/base/src/lib/trpc.ts.hbs +26 -0
- package/templates/api/trpc/server/next/src/app/trpc/[trpc]/route.ts +14 -0
- package/templates/api/trpc/web/react/base/src/utils/trpc.ts.hbs +97 -0
- package/templates/auth/native/native-base/lib/auth-client.ts.hbs +13 -0
- package/templates/auth/native/nativewind/app/(drawer)/index.tsx.hbs +95 -0
- package/templates/auth/native/nativewind/components/sign-in.tsx.hbs +93 -0
- package/templates/auth/native/nativewind/components/sign-up.tsx.hbs +104 -0
- package/templates/auth/native/unistyles/app/(drawer)/index.tsx.hbs +179 -0
- package/templates/auth/native/unistyles/components/sign-in.tsx.hbs +134 -0
- package/templates/auth/native/unistyles/components/sign-up.tsx.hbs +152 -0
- package/templates/auth/server/base/src/lib/auth.ts.hbs +141 -0
- package/templates/auth/server/db/drizzle/mysql/src/db/schema/auth.ts +58 -0
- package/templates/auth/server/db/drizzle/postgres/src/db/schema/auth.ts +47 -0
- package/templates/auth/server/db/drizzle/sqlite/src/db/schema/auth.ts +55 -0
- package/templates/auth/server/db/mongoose/mongodb/src/db/models/auth.model.ts +68 -0
- package/templates/auth/server/db/prisma/mongodb/prisma/schema/auth.prisma +59 -0
- package/templates/auth/server/db/prisma/mysql/prisma/schema/auth.prisma +59 -0
- package/templates/auth/server/db/prisma/postgres/prisma/schema/auth.prisma +59 -0
- package/templates/auth/server/db/prisma/sqlite/prisma/schema/auth.prisma +59 -0
- package/templates/auth/server/next/src/app/api/auth/[...all]/route.ts +4 -0
- package/templates/auth/web/nuxt/app/components/SignInForm.vue +77 -0
- package/templates/auth/web/nuxt/app/components/SignUpForm.vue +84 -0
- package/templates/auth/web/nuxt/app/components/UserMenu.vue +42 -0
- package/templates/auth/web/nuxt/app/middleware/auth.ts +12 -0
- package/templates/auth/web/nuxt/app/pages/dashboard.vue +27 -0
- package/templates/auth/web/nuxt/app/pages/login.vue +24 -0
- package/templates/auth/web/nuxt/app/plugins/auth-client.ts +16 -0
- package/templates/auth/web/react/base/src/lib/auth-client.ts.hbs +10 -0
- package/templates/auth/web/react/next/src/app/dashboard/page.tsx.hbs +47 -0
- package/templates/auth/web/react/next/src/app/login/page.tsx +16 -0
- package/templates/auth/web/react/next/src/components/sign-in-form.tsx +135 -0
- package/templates/auth/web/react/next/src/components/sign-up-form.tsx +160 -0
- package/templates/auth/web/react/next/src/components/theme-provider.tsx +11 -0
- package/templates/auth/web/react/next/src/components/user-menu.tsx +60 -0
- package/templates/auth/web/react/react-router/src/components/sign-in-form.tsx +135 -0
- package/templates/auth/web/react/react-router/src/components/sign-up-form.tsx +160 -0
- package/templates/auth/web/react/react-router/src/components/user-menu.tsx +60 -0
- package/templates/auth/web/react/react-router/src/routes/dashboard.tsx.hbs +40 -0
- package/templates/auth/web/react/react-router/src/routes/login.tsx +13 -0
- package/templates/auth/web/react/tanstack-router/src/components/sign-in-form.tsx +139 -0
- package/templates/auth/web/react/tanstack-router/src/components/sign-up-form.tsx +164 -0
- package/templates/auth/web/react/tanstack-router/src/components/user-menu.tsx +62 -0
- package/templates/auth/web/react/tanstack-router/src/routes/dashboard.tsx.hbs +47 -0
- package/templates/auth/web/react/tanstack-router/src/routes/login.tsx +18 -0
- package/templates/auth/web/react/tanstack-start/src/components/sign-in-form.tsx +139 -0
- package/templates/auth/web/react/tanstack-start/src/components/sign-up-form.tsx +164 -0
- package/templates/auth/web/react/tanstack-start/src/components/user-menu.tsx +62 -0
- package/templates/auth/web/react/tanstack-start/src/routes/dashboard.tsx.hbs +51 -0
- package/templates/auth/web/react/tanstack-start/src/routes/login.tsx +18 -0
- package/templates/auth/web/solid/src/components/sign-in-form.tsx +132 -0
- package/templates/auth/web/solid/src/components/sign-up-form.tsx +158 -0
- package/templates/auth/web/solid/src/components/user-menu.tsx.hbs +55 -0
- package/templates/auth/web/solid/src/lib/auth-client.ts +5 -0
- package/templates/auth/web/solid/src/routes/dashboard.tsx +38 -0
- package/templates/auth/web/solid/src/routes/login.tsx +23 -0
- package/templates/auth/web/svelte/src/components/SignInForm.svelte +108 -0
- package/templates/auth/web/svelte/src/components/SignUpForm.svelte +142 -0
- package/templates/auth/web/svelte/src/components/UserMenu.svelte +54 -0
- package/templates/auth/web/svelte/src/lib/auth-client.ts +6 -0
- package/templates/auth/web/svelte/src/routes/dashboard/+page.svelte +31 -0
- package/templates/auth/web/svelte/src/routes/login/+page.svelte +12 -0
- package/templates/backend/convex/packages/backend/_gitignore +2 -0
- package/templates/backend/convex/packages/backend/convex/README.md +90 -0
- package/templates/backend/convex/packages/backend/convex/healthCheck.ts +7 -0
- package/templates/backend/convex/packages/backend/convex/schema.ts +9 -0
- package/templates/backend/convex/packages/backend/convex/todos.ts +42 -0
- package/templates/backend/convex/packages/backend/convex/tsconfig.json +25 -0
- package/templates/backend/convex/packages/backend/package.json.hbs +17 -0
- package/templates/backend/server/elysia/src/index.ts.hbs +72 -0
- package/templates/backend/server/express/src/index.ts.hbs +88 -0
- package/templates/backend/server/fastify/src/index.ts.hbs +155 -0
- package/templates/backend/server/hono/src/index.ts.hbs +133 -0
- package/templates/backend/server/next/next-env.d.ts +5 -0
- package/templates/backend/server/next/next.config.ts +7 -0
- package/templates/backend/server/next/package.json.hbs +24 -0
- package/templates/backend/server/next/src/app/route.ts +5 -0
- package/templates/backend/server/next/src/middleware.ts +19 -0
- package/templates/backend/server/next/tsconfig.json.hbs +33 -0
- package/templates/backend/server/server-base/_gitignore +52 -0
- package/templates/backend/server/server-base/package.json.hbs +28 -0
- package/templates/backend/server/server-base/src/routers/index.ts.hbs +53 -0
- package/templates/backend/server/server-base/tsconfig.json.hbs +39 -0
- package/templates/base/_gitignore +2 -0
- package/templates/base/package.json.hbs +11 -0
- package/templates/db/drizzle/mysql/drizzle.config.ts.hbs +10 -0
- package/templates/db/drizzle/mysql/src/db/index.ts.hbs +20 -0
- package/templates/db/drizzle/postgres/drizzle.config.ts.hbs +10 -0
- package/templates/db/drizzle/postgres/src/db/index.ts.hbs +12 -0
- package/templates/db/drizzle/sqlite/drizzle.config.ts.hbs +24 -0
- package/templates/db/drizzle/sqlite/src/db/index.ts.hbs +35 -0
- package/templates/db/mongoose/mongodb/src/db/index.ts.hbs +9 -0
- package/templates/db/prisma/mongodb/prisma/index.ts.hbs +5 -0
- package/templates/db/prisma/mongodb/prisma/schema/schema.prisma +10 -0
- package/templates/db/prisma/mongodb/prisma.config.ts.hbs +8 -0
- package/templates/db/prisma/mysql/prisma/index.ts +5 -0
- package/templates/db/prisma/mysql/prisma/schema/schema.prisma +10 -0
- package/templates/db/prisma/mysql/prisma.config.ts +8 -0
- package/templates/db/prisma/postgres/prisma/index.ts +5 -0
- package/templates/db/prisma/postgres/prisma/schema/schema.prisma.hbs +13 -0
- package/templates/db/prisma/postgres/prisma.config.ts.hbs +12 -0
- package/templates/db/prisma/sqlite/prisma/index.ts +5 -0
- package/templates/db/prisma/sqlite/prisma/schema/schema.prisma +10 -0
- package/templates/db/prisma/sqlite/prisma.config.ts +8 -0
- package/templates/examples/ai/native/nativewind/app/(drawer)/ai.tsx.hbs +155 -0
- package/templates/examples/ai/native/nativewind/polyfills.js +25 -0
- package/templates/examples/ai/native/unistyles/app/(drawer)/ai.tsx.hbs +279 -0
- package/templates/examples/ai/native/unistyles/polyfills.js +25 -0
- package/templates/examples/ai/server/next/src/app/ai/route.ts +15 -0
- package/templates/examples/ai/web/nuxt/app/pages/ai.vue +63 -0
- package/templates/examples/ai/web/react/next/src/app/ai/page.tsx +67 -0
- package/templates/examples/ai/web/react/react-router/src/routes/ai.tsx +64 -0
- package/templates/examples/ai/web/react/tanstack-router/src/routes/ai.tsx +69 -0
- package/templates/examples/ai/web/react/tanstack-start/src/routes/ai.tsx +69 -0
- package/templates/examples/ai/web/svelte/src/routes/ai/+page.svelte +98 -0
- package/templates/examples/todo/native/nativewind/app/(drawer)/todos.tsx.hbs +295 -0
- package/templates/examples/todo/native/unistyles/app/(drawer)/todos.tsx.hbs +340 -0
- package/templates/examples/todo/server/drizzle/base/src/routers/todo.ts.hbs +79 -0
- package/templates/examples/todo/server/drizzle/mysql/src/db/schema/todo.ts +7 -0
- package/templates/examples/todo/server/drizzle/postgres/src/db/schema/todo.ts +7 -0
- package/templates/examples/todo/server/drizzle/sqlite/src/db/schema/todo.ts +7 -0
- package/templates/examples/todo/server/mongoose/base/src/routers/todo.ts.hbs +66 -0
- package/templates/examples/todo/server/mongoose/mongodb/src/db/models/todo.model.ts +24 -0
- package/templates/examples/todo/server/prisma/base/src/routers/todo.ts.hbs +118 -0
- package/templates/examples/todo/server/prisma/mongodb/prisma/schema/todo.prisma +7 -0
- package/templates/examples/todo/server/prisma/mysql/prisma/schema/todo.prisma +7 -0
- package/templates/examples/todo/server/prisma/postgres/prisma/schema/todo.prisma +7 -0
- package/templates/examples/todo/server/prisma/sqlite/prisma/schema/todo.prisma +7 -0
- package/templates/examples/todo/web/nuxt/app/pages/todos.vue +108 -0
- package/templates/examples/todo/web/react/next/src/app/todos/page.tsx.hbs +245 -0
- package/templates/examples/todo/web/react/react-router/src/routes/todos.tsx.hbs +242 -0
- package/templates/examples/todo/web/react/tanstack-router/src/routes/todos.tsx.hbs +247 -0
- package/templates/examples/todo/web/react/tanstack-start/src/routes/todos.tsx.hbs +268 -0
- package/templates/examples/todo/web/solid/src/routes/todos.tsx.hbs +132 -0
- package/templates/examples/todo/web/svelte/src/routes/todos/+page.svelte.hbs +317 -0
- package/templates/extras/_npmrc.hbs +5 -0
- package/templates/extras/pnpm-workspace.yaml +3 -0
- package/templates/frontend/native/native-base/assets/adaptive-icon.png +0 -0
- package/templates/frontend/native/native-base/assets/favicon.png +0 -0
- package/templates/frontend/native/native-base/assets/icon.png +0 -0
- package/templates/frontend/native/native-base/assets/splash.png +0 -0
- package/templates/frontend/native/nativewind/_gitignore +25 -0
- package/templates/frontend/native/nativewind/app/(drawer)/(tabs)/_layout.tsx +46 -0
- package/templates/frontend/native/nativewind/app/(drawer)/(tabs)/index.tsx +19 -0
- package/templates/frontend/native/nativewind/app/(drawer)/(tabs)/two.tsx +19 -0
- package/templates/frontend/native/nativewind/app/(drawer)/_layout.tsx.hbs +67 -0
- package/templates/frontend/native/nativewind/app/(drawer)/index.tsx.hbs +95 -0
- package/templates/frontend/native/nativewind/app/+html.tsx +47 -0
- package/templates/frontend/native/nativewind/app/+not-found.tsx +29 -0
- package/templates/frontend/native/nativewind/app/_layout.tsx.hbs +126 -0
- package/templates/frontend/native/nativewind/app/modal.tsx +14 -0
- package/templates/frontend/native/nativewind/app-env.d.ts +2 -0
- package/templates/frontend/native/nativewind/app.json +46 -0
- package/templates/frontend/native/nativewind/babel.config.js +11 -0
- package/templates/frontend/native/nativewind/components/container.tsx +8 -0
- package/templates/frontend/native/nativewind/components/header-button.tsx +26 -0
- package/templates/frontend/native/nativewind/components/tabbar-icon.tsx +8 -0
- package/templates/frontend/native/nativewind/global.css +50 -0
- package/templates/frontend/native/nativewind/lib/android-navigation-bar.tsx +11 -0
- package/templates/frontend/native/nativewind/lib/constants.ts +18 -0
- package/templates/frontend/native/nativewind/lib/use-color-scheme.ts +12 -0
- package/templates/frontend/native/nativewind/metro.config.js +59 -0
- package/templates/frontend/native/nativewind/package.json.hbs +49 -0
- package/templates/frontend/native/nativewind/tailwind.config.js +59 -0
- package/templates/frontend/native/nativewind/tsconfig.json.hbs +23 -0
- package/templates/frontend/native/unistyles/_gitignore +24 -0
- package/templates/frontend/native/unistyles/app/(drawer)/(tabs)/_layout.tsx +39 -0
- package/templates/frontend/native/unistyles/app/(drawer)/(tabs)/index.tsx +37 -0
- package/templates/frontend/native/unistyles/app/(drawer)/(tabs)/two.tsx +37 -0
- package/templates/frontend/native/unistyles/app/(drawer)/_layout.tsx.hbs +87 -0
- package/templates/frontend/native/unistyles/app/(drawer)/index.tsx.hbs +194 -0
- package/templates/frontend/native/unistyles/app/+html.tsx +48 -0
- package/templates/frontend/native/unistyles/app/+not-found.tsx +65 -0
- package/templates/frontend/native/unistyles/app/_layout.tsx.hbs +104 -0
- package/templates/frontend/native/unistyles/app/modal.tsx +33 -0
- package/templates/frontend/native/unistyles/app.json +44 -0
- package/templates/frontend/native/unistyles/babel.config.js +20 -0
- package/templates/frontend/native/unistyles/breakpoints.ts +9 -0
- package/templates/frontend/native/unistyles/components/container.tsx +15 -0
- package/templates/frontend/native/unistyles/components/header-button.tsx +36 -0
- package/templates/frontend/native/unistyles/components/tabbar-icon.tsx +8 -0
- package/templates/frontend/native/unistyles/expo-env.d.ts +3 -0
- package/templates/frontend/native/unistyles/index.js +2 -0
- package/templates/frontend/native/unistyles/metro.config.js +20 -0
- package/templates/frontend/native/unistyles/package.json.hbs +50 -0
- package/templates/frontend/native/unistyles/theme.ts +98 -0
- package/templates/frontend/native/unistyles/tsconfig.json.hbs +17 -0
- package/templates/frontend/native/unistyles/unistyles.ts +27 -0
- package/templates/frontend/nuxt/_gitignore +24 -0
- package/templates/frontend/nuxt/app/app.config.ts +15 -0
- package/templates/frontend/nuxt/app/app.vue +13 -0
- package/templates/frontend/nuxt/app/assets/css/main.css +2 -0
- package/templates/frontend/nuxt/app/components/Header.vue.hbs +45 -0
- package/templates/frontend/nuxt/app/components/Loader.vue +5 -0
- package/templates/frontend/nuxt/app/components/ModeToggle.vue +23 -0
- package/templates/frontend/nuxt/app/layouts/default.vue.hbs +11 -0
- package/templates/frontend/nuxt/app/pages/index.vue.hbs +57 -0
- package/templates/frontend/nuxt/app/plugins/vue-query.ts.hbs +44 -0
- package/templates/frontend/nuxt/nuxt.config.ts.hbs +19 -0
- package/templates/frontend/nuxt/package.json.hbs +25 -0
- package/templates/frontend/nuxt/public/favicon.ico +0 -0
- package/templates/frontend/nuxt/public/robots.txt +2 -0
- package/templates/frontend/nuxt/server/tsconfig.json +3 -0
- package/templates/frontend/nuxt/tsconfig.json.hbs +9 -0
- package/templates/frontend/react/next/next-env.d.ts.hbs +5 -0
- package/templates/frontend/react/next/next.config.ts.hbs +5 -0
- package/templates/frontend/react/next/package.json.hbs +34 -0
- package/templates/frontend/react/next/postcss.config.mjs.hbs +5 -0
- package/templates/frontend/react/next/src/app/favicon.ico +0 -0
- package/templates/frontend/react/next/src/app/layout.tsx.hbs +41 -0
- package/templates/frontend/react/next/src/app/page.tsx.hbs +68 -0
- package/templates/frontend/react/next/src/components/mode-toggle.tsx.hbs +39 -0
- package/templates/frontend/react/next/src/components/providers.tsx.hbs +56 -0
- package/templates/frontend/react/next/src/components/theme-provider.tsx.hbs +11 -0
- package/templates/frontend/react/next/tsconfig.json.hbs +33 -0
- package/templates/frontend/react/react-router/package.json.hbs +42 -0
- package/templates/frontend/react/react-router/public/favicon.ico +0 -0
- package/templates/frontend/react/react-router/react-router.config.ts +6 -0
- package/templates/frontend/react/react-router/src/components/mode-toggle.tsx +37 -0
- package/templates/frontend/react/react-router/src/components/theme-provider.tsx +73 -0
- package/templates/frontend/react/react-router/src/root.tsx.hbs +152 -0
- package/templates/frontend/react/react-router/src/routes/_index.tsx.hbs +74 -0
- package/templates/frontend/react/react-router/src/routes.ts +4 -0
- package/templates/frontend/react/react-router/tsconfig.json.hbs +32 -0
- package/templates/frontend/react/react-router/vite.config.ts.hbs +33 -0
- package/templates/frontend/react/tanstack-router/index.html +12 -0
- package/templates/frontend/react/tanstack-router/package.json.hbs +41 -0
- package/templates/frontend/react/tanstack-router/src/components/mode-toggle.tsx +37 -0
- package/templates/frontend/react/tanstack-router/src/components/theme-provider.tsx +73 -0
- package/templates/frontend/react/tanstack-router/src/main.tsx.hbs +66 -0
- package/templates/frontend/react/tanstack-router/src/routes/__root.tsx.hbs +100 -0
- package/templates/frontend/react/tanstack-router/src/routes/index.tsx.hbs +74 -0
- package/templates/frontend/react/tanstack-router/tsconfig.json.hbs +23 -0
- package/templates/frontend/react/tanstack-router/vite.config.ts.hbs +39 -0
- package/templates/frontend/react/tanstack-start/package.json.hbs +44 -0
- package/templates/frontend/react/tanstack-start/public/robots.txt +3 -0
- package/templates/frontend/react/tanstack-start/src/router.tsx.hbs +144 -0
- package/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs +97 -0
- package/templates/frontend/react/tanstack-start/src/routes/index.tsx.hbs +74 -0
- package/templates/frontend/react/tanstack-start/tsconfig.json.hbs +33 -0
- package/templates/frontend/react/tanstack-start/vite.config.ts +8 -0
- package/templates/frontend/react/web-base/_gitignore +52 -0
- package/templates/frontend/react/web-base/components.json +21 -0
- package/templates/frontend/react/web-base/src/components/header.tsx.hbs +79 -0
- package/templates/frontend/react/web-base/src/components/loader.tsx +9 -0
- package/templates/frontend/react/web-base/src/components/ui/button.tsx +59 -0
- package/templates/frontend/react/web-base/src/components/ui/card.tsx +92 -0
- package/templates/frontend/react/web-base/src/components/ui/checkbox.tsx +30 -0
- package/templates/frontend/react/web-base/src/components/ui/dropdown-menu.tsx +257 -0
- package/templates/frontend/react/web-base/src/components/ui/input.tsx +21 -0
- package/templates/frontend/react/web-base/src/components/ui/label.tsx +22 -0
- package/templates/frontend/react/web-base/src/components/ui/skeleton.tsx +13 -0
- package/templates/frontend/react/web-base/src/components/ui/sonner.tsx +25 -0
- package/templates/frontend/react/web-base/src/index.css +134 -0
- package/templates/frontend/react/web-base/src/lib/utils.ts +6 -0
- package/templates/frontend/solid/_gitignore +7 -0
- package/templates/frontend/solid/index.html +13 -0
- package/templates/frontend/solid/package.json.hbs +27 -0
- package/templates/frontend/solid/public/robots.txt +3 -0
- package/templates/frontend/solid/src/components/header.tsx.hbs +38 -0
- package/templates/frontend/solid/src/components/loader.tsx +9 -0
- package/templates/frontend/solid/src/main.tsx.hbs +38 -0
- package/templates/frontend/solid/src/routes/__root.tsx.hbs +34 -0
- package/templates/frontend/solid/src/routes/index.tsx.hbs +61 -0
- package/templates/frontend/solid/src/styles.css +5 -0
- package/templates/frontend/solid/tsconfig.json.hbs +34 -0
- package/templates/frontend/solid/vite.config.js.hbs +39 -0
- package/templates/frontend/svelte/_gitignore +23 -0
- package/templates/frontend/svelte/_npmrc +1 -0
- package/templates/frontend/svelte/package.json.hbs +31 -0
- package/templates/frontend/svelte/src/app.css +5 -0
- package/templates/frontend/svelte/src/app.d.ts +13 -0
- package/templates/frontend/svelte/src/app.html +12 -0
- package/templates/frontend/svelte/src/components/Header.svelte.hbs +40 -0
- package/templates/frontend/svelte/src/lib/index.ts +1 -0
- package/templates/frontend/svelte/src/routes/+layout.svelte.hbs +54 -0
- package/templates/frontend/svelte/src/routes/+page.svelte.hbs +72 -0
- package/templates/frontend/svelte/static/favicon.png +0 -0
- package/templates/frontend/svelte/svelte.config.js +18 -0
- package/templates/frontend/svelte/tsconfig.json.hbs +24 -0
- package/templates/frontend/svelte/vite.config.ts +7 -0
- package/templates/runtime/workers/apps/server/wrangler.jsonc.hbs +34 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
import { pgTable, text, timestamp, boolean, serial } from "drizzle-orm/pg-core";
|
2
|
+
|
3
|
+
export const user = pgTable("user", {
|
4
|
+
id: text("id").primaryKey(),
|
5
|
+
name: text('name').notNull(),
|
6
|
+
email: text('email').notNull().unique(),
|
7
|
+
emailVerified: boolean('email_verified').notNull(),
|
8
|
+
image: text('image'),
|
9
|
+
createdAt: timestamp('created_at').notNull(),
|
10
|
+
updatedAt: timestamp('updated_at').notNull()
|
11
|
+
});
|
12
|
+
|
13
|
+
export const session = pgTable("session", {
|
14
|
+
id: text("id").primaryKey(),
|
15
|
+
expiresAt: timestamp('expires_at').notNull(),
|
16
|
+
token: text('token').notNull().unique(),
|
17
|
+
createdAt: timestamp('created_at').notNull(),
|
18
|
+
updatedAt: timestamp('updated_at').notNull(),
|
19
|
+
ipAddress: text('ip_address'),
|
20
|
+
userAgent: text('user_agent'),
|
21
|
+
userId: text('user_id').notNull().references(()=> user.id, { onDelete: 'cascade' })
|
22
|
+
});
|
23
|
+
|
24
|
+
export const account = pgTable("account", {
|
25
|
+
id: text("id").primaryKey(),
|
26
|
+
accountId: text('account_id').notNull(),
|
27
|
+
providerId: text('provider_id').notNull(),
|
28
|
+
userId: text('user_id').notNull().references(()=> user.id, { onDelete: 'cascade' }),
|
29
|
+
accessToken: text('access_token'),
|
30
|
+
refreshToken: text('refresh_token'),
|
31
|
+
idToken: text('id_token'),
|
32
|
+
accessTokenExpiresAt: timestamp('access_token_expires_at'),
|
33
|
+
refreshTokenExpiresAt: timestamp('refresh_token_expires_at'),
|
34
|
+
scope: text('scope'),
|
35
|
+
password: text('password'),
|
36
|
+
createdAt: timestamp('created_at').notNull(),
|
37
|
+
updatedAt: timestamp('updated_at').notNull()
|
38
|
+
});
|
39
|
+
|
40
|
+
export const verification = pgTable("verification", {
|
41
|
+
id: text("id").primaryKey(),
|
42
|
+
identifier: text('identifier').notNull(),
|
43
|
+
value: text('value').notNull(),
|
44
|
+
expiresAt: timestamp('expires_at').notNull(),
|
45
|
+
createdAt: timestamp('created_at'),
|
46
|
+
updatedAt: timestamp('updated_at')
|
47
|
+
});
|
@@ -0,0 +1,55 @@
|
|
1
|
+
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
2
|
+
|
3
|
+
export const user = sqliteTable("user", {
|
4
|
+
id: text("id").primaryKey(),
|
5
|
+
name: text("name").notNull(),
|
6
|
+
email: text("email").notNull().unique(),
|
7
|
+
emailVerified: integer("email_verified", { mode: "boolean" }).notNull(),
|
8
|
+
image: text("image"),
|
9
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
10
|
+
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
11
|
+
});
|
12
|
+
|
13
|
+
export const session = sqliteTable("session", {
|
14
|
+
id: text("id").primaryKey(),
|
15
|
+
expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
|
16
|
+
token: text("token").notNull().unique(),
|
17
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
18
|
+
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
19
|
+
ipAddress: text("ip_address"),
|
20
|
+
userAgent: text("user_agent"),
|
21
|
+
userId: text("user_id")
|
22
|
+
.notNull()
|
23
|
+
.references(() => user.id),
|
24
|
+
});
|
25
|
+
|
26
|
+
export const account = sqliteTable("account", {
|
27
|
+
id: text("id").primaryKey(),
|
28
|
+
accountId: text("account_id").notNull(),
|
29
|
+
providerId: text("provider_id").notNull(),
|
30
|
+
userId: text("user_id")
|
31
|
+
.notNull()
|
32
|
+
.references(() => user.id),
|
33
|
+
accessToken: text("access_token"),
|
34
|
+
refreshToken: text("refresh_token"),
|
35
|
+
idToken: text("id_token"),
|
36
|
+
accessTokenExpiresAt: integer("access_token_expires_at", {
|
37
|
+
mode: "timestamp",
|
38
|
+
}),
|
39
|
+
refreshTokenExpiresAt: integer("refresh_token_expires_at", {
|
40
|
+
mode: "timestamp",
|
41
|
+
}),
|
42
|
+
scope: text("scope"),
|
43
|
+
password: text("password"),
|
44
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
45
|
+
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
46
|
+
});
|
47
|
+
|
48
|
+
export const verification = sqliteTable("verification", {
|
49
|
+
id: text("id").primaryKey(),
|
50
|
+
identifier: text("identifier").notNull(),
|
51
|
+
value: text("value").notNull(),
|
52
|
+
expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
|
53
|
+
createdAt: integer("created_at", { mode: "timestamp" }),
|
54
|
+
updatedAt: integer("updated_at", { mode: "timestamp" }),
|
55
|
+
});
|
@@ -0,0 +1,68 @@
|
|
1
|
+
import mongoose from 'mongoose';
|
2
|
+
|
3
|
+
const { Schema, model } = mongoose;
|
4
|
+
|
5
|
+
const userSchema = new Schema(
|
6
|
+
{
|
7
|
+
_id: { type: String },
|
8
|
+
name: { type: String, required: true },
|
9
|
+
email: { type: String, required: true, unique: true },
|
10
|
+
emailVerified: { type: Boolean, required: true },
|
11
|
+
image: { type: String },
|
12
|
+
createdAt: { type: Date, required: true },
|
13
|
+
updatedAt: { type: Date, required: true },
|
14
|
+
},
|
15
|
+
{ collection: 'user' }
|
16
|
+
);
|
17
|
+
|
18
|
+
const sessionSchema = new Schema(
|
19
|
+
{
|
20
|
+
_id: { type: String },
|
21
|
+
expiresAt: { type: Date, required: true },
|
22
|
+
token: { type: String, required: true, unique: true },
|
23
|
+
createdAt: { type: Date, required: true },
|
24
|
+
updatedAt: { type: Date, required: true },
|
25
|
+
ipAddress: { type: String },
|
26
|
+
userAgent: { type: String },
|
27
|
+
userId: { type: String, ref: 'User', required: true },
|
28
|
+
},
|
29
|
+
{ collection: 'session' }
|
30
|
+
);
|
31
|
+
|
32
|
+
const accountSchema = new Schema(
|
33
|
+
{
|
34
|
+
_id: { type: String },
|
35
|
+
accountId: { type: String, required: true },
|
36
|
+
providerId: { type: String, required: true },
|
37
|
+
userId: { type: String, ref: 'User', required: true },
|
38
|
+
accessToken: { type: String },
|
39
|
+
refreshToken: { type: String },
|
40
|
+
idToken: { type: String },
|
41
|
+
accessTokenExpiresAt: { type: Date },
|
42
|
+
refreshTokenExpiresAt: { type: Date },
|
43
|
+
scope: { type: String },
|
44
|
+
password: { type: String },
|
45
|
+
createdAt: { type: Date, required: true },
|
46
|
+
updatedAt: { type: Date, required: true },
|
47
|
+
},
|
48
|
+
{ collection: 'account' }
|
49
|
+
);
|
50
|
+
|
51
|
+
const verificationSchema = new Schema(
|
52
|
+
{
|
53
|
+
_id: { type: String },
|
54
|
+
identifier: { type: String, required: true },
|
55
|
+
value: { type: String, required: true },
|
56
|
+
expiresAt: { type: Date, required: true },
|
57
|
+
createdAt: { type: Date },
|
58
|
+
updatedAt: { type: Date },
|
59
|
+
},
|
60
|
+
{ collection: 'verification' }
|
61
|
+
);
|
62
|
+
|
63
|
+
const User = model('User', userSchema);
|
64
|
+
const Session = model('Session', sessionSchema);
|
65
|
+
const Account = model('Account', accountSchema);
|
66
|
+
const Verification = model('Verification', verificationSchema);
|
67
|
+
|
68
|
+
export { User, Session, Account, Verification };
|
@@ -0,0 +1,59 @@
|
|
1
|
+
model User {
|
2
|
+
id String @id @map("_id")
|
3
|
+
name String
|
4
|
+
email String
|
5
|
+
emailVerified Boolean
|
6
|
+
image String?
|
7
|
+
createdAt DateTime
|
8
|
+
updatedAt DateTime
|
9
|
+
sessions Session[]
|
10
|
+
accounts Account[]
|
11
|
+
|
12
|
+
@@unique([email])
|
13
|
+
@@map("user")
|
14
|
+
}
|
15
|
+
|
16
|
+
model Session {
|
17
|
+
id String @id @map("_id")
|
18
|
+
expiresAt DateTime
|
19
|
+
token String
|
20
|
+
createdAt DateTime
|
21
|
+
updatedAt DateTime
|
22
|
+
ipAddress String?
|
23
|
+
userAgent String?
|
24
|
+
userId String
|
25
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
26
|
+
|
27
|
+
@@unique([token])
|
28
|
+
@@map("session")
|
29
|
+
}
|
30
|
+
|
31
|
+
model Account {
|
32
|
+
id String @id @map("_id")
|
33
|
+
accountId String
|
34
|
+
providerId String
|
35
|
+
userId String
|
36
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
37
|
+
accessToken String?
|
38
|
+
refreshToken String?
|
39
|
+
idToken String?
|
40
|
+
accessTokenExpiresAt DateTime?
|
41
|
+
refreshTokenExpiresAt DateTime?
|
42
|
+
scope String?
|
43
|
+
password String?
|
44
|
+
createdAt DateTime
|
45
|
+
updatedAt DateTime
|
46
|
+
|
47
|
+
@@map("account")
|
48
|
+
}
|
49
|
+
|
50
|
+
model Verification {
|
51
|
+
id String @id @map("_id")
|
52
|
+
identifier String
|
53
|
+
value String
|
54
|
+
expiresAt DateTime
|
55
|
+
createdAt DateTime?
|
56
|
+
updatedAt DateTime?
|
57
|
+
|
58
|
+
@@map("verification")
|
59
|
+
}
|
@@ -0,0 +1,59 @@
|
|
1
|
+
model User {
|
2
|
+
id String @id
|
3
|
+
name String @db.Text
|
4
|
+
email String
|
5
|
+
emailVerified Boolean
|
6
|
+
image String? @db.Text
|
7
|
+
createdAt DateTime
|
8
|
+
updatedAt DateTime
|
9
|
+
sessions Session[]
|
10
|
+
accounts Account[]
|
11
|
+
|
12
|
+
@@unique([email])
|
13
|
+
@@map("user")
|
14
|
+
}
|
15
|
+
|
16
|
+
model Session {
|
17
|
+
id String @id
|
18
|
+
expiresAt DateTime
|
19
|
+
token String
|
20
|
+
createdAt DateTime
|
21
|
+
updatedAt DateTime
|
22
|
+
ipAddress String? @db.Text
|
23
|
+
userAgent String? @db.Text
|
24
|
+
userId String
|
25
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
26
|
+
|
27
|
+
@@unique([token])
|
28
|
+
@@map("session")
|
29
|
+
}
|
30
|
+
|
31
|
+
model Account {
|
32
|
+
id String @id
|
33
|
+
accountId String @db.Text
|
34
|
+
providerId String @db.Text
|
35
|
+
userId String
|
36
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
37
|
+
accessToken String? @db.Text
|
38
|
+
refreshToken String? @db.Text
|
39
|
+
idToken String? @db.Text
|
40
|
+
accessTokenExpiresAt DateTime?
|
41
|
+
refreshTokenExpiresAt DateTime?
|
42
|
+
scope String? @db.Text
|
43
|
+
password String? @db.Text
|
44
|
+
createdAt DateTime
|
45
|
+
updatedAt DateTime
|
46
|
+
|
47
|
+
@@map("account")
|
48
|
+
}
|
49
|
+
|
50
|
+
model Verification {
|
51
|
+
id String @id
|
52
|
+
identifier String @db.Text
|
53
|
+
value String @db.Text
|
54
|
+
expiresAt DateTime
|
55
|
+
createdAt DateTime?
|
56
|
+
updatedAt DateTime?
|
57
|
+
|
58
|
+
@@map("verification")
|
59
|
+
}
|
@@ -0,0 +1,59 @@
|
|
1
|
+
model User {
|
2
|
+
id String @id @map("_id")
|
3
|
+
name String
|
4
|
+
email String
|
5
|
+
emailVerified Boolean
|
6
|
+
image String?
|
7
|
+
createdAt DateTime
|
8
|
+
updatedAt DateTime
|
9
|
+
sessions Session[]
|
10
|
+
accounts Account[]
|
11
|
+
|
12
|
+
@@unique([email])
|
13
|
+
@@map("user")
|
14
|
+
}
|
15
|
+
|
16
|
+
model Session {
|
17
|
+
id String @id @map("_id")
|
18
|
+
expiresAt DateTime
|
19
|
+
token String
|
20
|
+
createdAt DateTime
|
21
|
+
updatedAt DateTime
|
22
|
+
ipAddress String?
|
23
|
+
userAgent String?
|
24
|
+
userId String
|
25
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
26
|
+
|
27
|
+
@@unique([token])
|
28
|
+
@@map("session")
|
29
|
+
}
|
30
|
+
|
31
|
+
model Account {
|
32
|
+
id String @id @map("_id")
|
33
|
+
accountId String
|
34
|
+
providerId String
|
35
|
+
userId String
|
36
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
37
|
+
accessToken String?
|
38
|
+
refreshToken String?
|
39
|
+
idToken String?
|
40
|
+
accessTokenExpiresAt DateTime?
|
41
|
+
refreshTokenExpiresAt DateTime?
|
42
|
+
scope String?
|
43
|
+
password String?
|
44
|
+
createdAt DateTime
|
45
|
+
updatedAt DateTime
|
46
|
+
|
47
|
+
@@map("account")
|
48
|
+
}
|
49
|
+
|
50
|
+
model Verification {
|
51
|
+
id String @id @map("_id")
|
52
|
+
identifier String
|
53
|
+
value String
|
54
|
+
expiresAt DateTime
|
55
|
+
createdAt DateTime?
|
56
|
+
updatedAt DateTime?
|
57
|
+
|
58
|
+
@@map("verification")
|
59
|
+
}
|
@@ -0,0 +1,59 @@
|
|
1
|
+
model User {
|
2
|
+
id String @id @map("_id")
|
3
|
+
name String
|
4
|
+
email String
|
5
|
+
emailVerified Boolean
|
6
|
+
image String?
|
7
|
+
createdAt DateTime
|
8
|
+
updatedAt DateTime
|
9
|
+
sessions Session[]
|
10
|
+
accounts Account[]
|
11
|
+
|
12
|
+
@@unique([email])
|
13
|
+
@@map("user")
|
14
|
+
}
|
15
|
+
|
16
|
+
model Session {
|
17
|
+
id String @id @map("_id")
|
18
|
+
expiresAt DateTime
|
19
|
+
token String
|
20
|
+
createdAt DateTime
|
21
|
+
updatedAt DateTime
|
22
|
+
ipAddress String?
|
23
|
+
userAgent String?
|
24
|
+
userId String
|
25
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
26
|
+
|
27
|
+
@@unique([token])
|
28
|
+
@@map("session")
|
29
|
+
}
|
30
|
+
|
31
|
+
model Account {
|
32
|
+
id String @id @map("_id")
|
33
|
+
accountId String
|
34
|
+
providerId String
|
35
|
+
userId String
|
36
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
37
|
+
accessToken String?
|
38
|
+
refreshToken String?
|
39
|
+
idToken String?
|
40
|
+
accessTokenExpiresAt DateTime?
|
41
|
+
refreshTokenExpiresAt DateTime?
|
42
|
+
scope String?
|
43
|
+
password String?
|
44
|
+
createdAt DateTime
|
45
|
+
updatedAt DateTime
|
46
|
+
|
47
|
+
@@map("account")
|
48
|
+
}
|
49
|
+
|
50
|
+
model Verification {
|
51
|
+
id String @id @map("_id")
|
52
|
+
identifier String
|
53
|
+
value String
|
54
|
+
expiresAt DateTime
|
55
|
+
createdAt DateTime?
|
56
|
+
updatedAt DateTime?
|
57
|
+
|
58
|
+
@@map("verification")
|
59
|
+
}
|
@@ -0,0 +1,77 @@
|
|
1
|
+
<script setup lang="ts">
|
2
|
+
import z from 'zod/v4'
|
3
|
+
const {$authClient} = useNuxtApp()
|
4
|
+
import type { FormSubmitEvent } from '#ui/types'
|
5
|
+
|
6
|
+
const emit = defineEmits(['switchToSignUp'])
|
7
|
+
|
8
|
+
const toast = useToast()
|
9
|
+
const loading = ref(false)
|
10
|
+
|
11
|
+
const schema = z.object({
|
12
|
+
email: z.email('Invalid email address'),
|
13
|
+
password: z.string().min(8, 'Password must be at least 8 characters'),
|
14
|
+
})
|
15
|
+
|
16
|
+
type Schema = z.output<typeof schema>
|
17
|
+
|
18
|
+
const state = reactive({
|
19
|
+
email: '',
|
20
|
+
password: '',
|
21
|
+
})
|
22
|
+
|
23
|
+
async function onSubmit (event: FormSubmitEvent<Schema>) {
|
24
|
+
loading.value = true
|
25
|
+
try {
|
26
|
+
await $authClient.signIn.email(
|
27
|
+
{
|
28
|
+
email: event.data.email,
|
29
|
+
password: event.data.password,
|
30
|
+
},
|
31
|
+
{
|
32
|
+
onSuccess: () => {
|
33
|
+
toast.add({ title: 'Sign in successful' })
|
34
|
+
navigateTo('/dashboard', { replace: true })
|
35
|
+
},
|
36
|
+
onError: (error) => {
|
37
|
+
toast.add({ title: 'Sign in failed', description: error.error.message })
|
38
|
+
},
|
39
|
+
},
|
40
|
+
)
|
41
|
+
} catch (error: any) {
|
42
|
+
toast.add({ title: 'An unexpected error occurred', description: error.message || 'Please try again.' })
|
43
|
+
} finally {
|
44
|
+
loading.value = false
|
45
|
+
}
|
46
|
+
}
|
47
|
+
</script>
|
48
|
+
|
49
|
+
<template>
|
50
|
+
<div class="mx-auto w-full mt-10 max-w-md p-6">
|
51
|
+
<h1 class="mb-6 text-center text-3xl font-bold">Welcome Back</h1>
|
52
|
+
|
53
|
+
<UForm :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
|
54
|
+
<UFormField label="Email" name="email">
|
55
|
+
<UInput v-model="state.email" type="email" class="w-full" />
|
56
|
+
</UFormField>
|
57
|
+
|
58
|
+
<UFormField label="Password" name="password">
|
59
|
+
<UInput v-model="state.password" type="password" class="w-full" />
|
60
|
+
</UFormField>
|
61
|
+
|
62
|
+
<UButton type="submit" block :loading="loading">
|
63
|
+
Sign In
|
64
|
+
</UButton>
|
65
|
+
</UForm>
|
66
|
+
|
67
|
+
<div class="mt-4 text-center">
|
68
|
+
<UButton
|
69
|
+
variant="link"
|
70
|
+
@click="$emit('switchToSignUp')"
|
71
|
+
class="text-primary hover:text-primary-dark"
|
72
|
+
>
|
73
|
+
Need an account? Sign Up
|
74
|
+
</UButton>
|
75
|
+
</div>
|
76
|
+
</div>
|
77
|
+
</template>
|
@@ -0,0 +1,84 @@
|
|
1
|
+
<script setup lang="ts">
|
2
|
+
import z from 'zod/v4'
|
3
|
+
import type { FormSubmitEvent } from '#ui/types'
|
4
|
+
const {$authClient} = useNuxtApp()
|
5
|
+
|
6
|
+
const emit = defineEmits(['switchToSignIn'])
|
7
|
+
|
8
|
+
const toast = useToast()
|
9
|
+
const loading = ref(false)
|
10
|
+
|
11
|
+
const schema = z.object({
|
12
|
+
name: z.string().min(2, 'Name must be at least 2 characters'),
|
13
|
+
email: z.email('Invalid email address'),
|
14
|
+
password: z.string().min(8, 'Password must be at least 8 characters'),
|
15
|
+
})
|
16
|
+
|
17
|
+
type Schema = z.output<typeof schema>
|
18
|
+
|
19
|
+
const state = reactive({
|
20
|
+
name: '',
|
21
|
+
email: '',
|
22
|
+
password: '',
|
23
|
+
})
|
24
|
+
|
25
|
+
async function onSubmit (event: FormSubmitEvent<Schema>) {
|
26
|
+
loading.value = true
|
27
|
+
try {
|
28
|
+
await $authClient.signUp.email(
|
29
|
+
{
|
30
|
+
name: event.data.name,
|
31
|
+
email: event.data.email,
|
32
|
+
password: event.data.password,
|
33
|
+
},
|
34
|
+
{
|
35
|
+
onSuccess: () => {
|
36
|
+
toast.add({ title: 'Sign up successful' })
|
37
|
+
navigateTo('/dashboard', { replace: true })
|
38
|
+
},
|
39
|
+
onError: (error) => {
|
40
|
+
toast.add({ title: 'Sign up failed', description: error.error.message })
|
41
|
+
},
|
42
|
+
},
|
43
|
+
)
|
44
|
+
} catch (error: any) {
|
45
|
+
toast.add({ title: 'An unexpected error occurred', description: error.message || 'Please try again.' })
|
46
|
+
} finally {
|
47
|
+
loading.value = false
|
48
|
+
}
|
49
|
+
}
|
50
|
+
</script>
|
51
|
+
|
52
|
+
<template>
|
53
|
+
<div class="mx-auto w-full mt-10 max-w-md p-6">
|
54
|
+
<h1 class="mb-6 text-center text-3xl font-bold">Create Account</h1>
|
55
|
+
|
56
|
+
<UForm :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
|
57
|
+
<UFormField label="Name" name="name">
|
58
|
+
<UInput v-model="state.name" class="w-full" />
|
59
|
+
</UFormField>
|
60
|
+
|
61
|
+
<UFormField label="Email" name="email">
|
62
|
+
<UInput v-model="state.email" type="email" class="w-full" />
|
63
|
+
</UFormField>
|
64
|
+
|
65
|
+
<UFormField label="Password" name="password">
|
66
|
+
<UInput v-model="state.password" type="password" class="w-full" />
|
67
|
+
</UFormField>
|
68
|
+
|
69
|
+
<UButton type="submit" block :loading="loading">
|
70
|
+
Sign Up
|
71
|
+
</UButton>
|
72
|
+
</UForm>
|
73
|
+
|
74
|
+
<div class="mt-4 text-center">
|
75
|
+
<UButton
|
76
|
+
variant="link"
|
77
|
+
@click="$emit('switchToSignIn')"
|
78
|
+
class="text-primary hover:text-primary-dark"
|
79
|
+
>
|
80
|
+
Already have an account? Sign In
|
81
|
+
</UButton>
|
82
|
+
</div>
|
83
|
+
</div>
|
84
|
+
</template>
|
@@ -0,0 +1,42 @@
|
|
1
|
+
<script setup lang="ts">
|
2
|
+
|
3
|
+
const {$authClient} = useNuxtApp()
|
4
|
+
const session = $authClient.useSession()
|
5
|
+
const toast = useToast()
|
6
|
+
|
7
|
+
const handleSignOut = async () => {
|
8
|
+
try {
|
9
|
+
await $authClient.signOut({
|
10
|
+
fetchOptions: {
|
11
|
+
onSuccess: async () => {
|
12
|
+
toast.add({ title: 'Signed out successfully' })
|
13
|
+
await navigateTo('/', { replace: true, external: true })
|
14
|
+
},
|
15
|
+
onError: (error) => {
|
16
|
+
toast.add({ title: 'Sign out failed', description: error?.error?.message || 'Unknown error'})
|
17
|
+
}
|
18
|
+
},
|
19
|
+
})
|
20
|
+
} catch (error: any) {
|
21
|
+
toast.add({ title: 'An unexpected error occurred during sign out', description: error.message || 'Please try again.'})
|
22
|
+
}
|
23
|
+
}
|
24
|
+
</script>
|
25
|
+
|
26
|
+
<template>
|
27
|
+
<div>
|
28
|
+
<USkeleton v-if="session.isPending" class="h-9 w-24" />
|
29
|
+
|
30
|
+
<UButton v-else-if="!session.data" variant="outline" to="/login">
|
31
|
+
Sign In
|
32
|
+
</UButton>
|
33
|
+
|
34
|
+
<UButton
|
35
|
+
v-else
|
36
|
+
variant="solid"
|
37
|
+
icon="i-lucide-log-out"
|
38
|
+
label="Sign out"
|
39
|
+
@click="handleSignOut()"
|
40
|
+
/>
|
41
|
+
</div>
|
42
|
+
</template>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
export default defineNuxtRouteMiddleware(async (to, from) => {
|
2
|
+
if (import.meta.server) return
|
3
|
+
|
4
|
+
const { $authClient } = useNuxtApp()
|
5
|
+
const session = $authClient.useSession()
|
6
|
+
|
7
|
+
if (session.value.isPending || !session.value) {
|
8
|
+
if (to.path === "/dashboard") {
|
9
|
+
return navigateTo("/login");
|
10
|
+
}
|
11
|
+
}
|
12
|
+
});
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<script setup lang="ts">
|
2
|
+
import { useQuery } from '@tanstack/vue-query'
|
3
|
+
const {$authClient} = useNuxtApp()
|
4
|
+
|
5
|
+
definePageMeta({
|
6
|
+
middleware: ['auth']
|
7
|
+
})
|
8
|
+
|
9
|
+
const { $orpc } = useNuxtApp()
|
10
|
+
|
11
|
+
const session = $authClient.useSession()
|
12
|
+
|
13
|
+
const privateData = useQuery($orpc.privateData.queryOptions())
|
14
|
+
|
15
|
+
</script>
|
16
|
+
|
17
|
+
<template>
|
18
|
+
<div class="container mx-auto p-4">
|
19
|
+
<h1 class="text-2xl font-bold mb-4">Dashboard</h1>
|
20
|
+
<div v-if="session?.data?.user">
|
21
|
+
<p class="mb-2">Welcome {{ session.data.user.name }}</p>
|
22
|
+
</div>
|
23
|
+
<div v-if="privateData.status.value === 'pending'">Loading private data...</div>
|
24
|
+
<div v-else-if="privateData.status.value === 'error'">Error loading private data: {{ privateData.error.value?.message }}</div>
|
25
|
+
<p v-else-if="privateData.data.value">Private Data: {{ privateData.data.value.message }}</p>
|
26
|
+
</div>
|
27
|
+
</template>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<script setup lang="ts">
|
2
|
+
const { $authClient } = useNuxtApp();
|
3
|
+
import SignInForm from "~/components/SignInForm.vue";
|
4
|
+
import SignUpForm from "~/components/SignUpForm.vue";
|
5
|
+
|
6
|
+
const session = $authClient.useSession();
|
7
|
+
const showSignIn = ref(true);
|
8
|
+
|
9
|
+
watchEffect(() => {
|
10
|
+
if (!session?.value.isPending && session?.value.data) {
|
11
|
+
navigateTo("/dashboard", { replace: true });
|
12
|
+
}
|
13
|
+
});
|
14
|
+
</script>
|
15
|
+
|
16
|
+
<template>
|
17
|
+
<div>
|
18
|
+
<Loader v-if="session.isPending" />
|
19
|
+
<div v-else-if="!session.data">
|
20
|
+
<SignInForm v-if="showSignIn" @switch-to-sign-up="showSignIn = false" />
|
21
|
+
<SignUpForm v-else @switch-to-sign-in="showSignIn = true" />
|
22
|
+
</div>
|
23
|
+
</div>
|
24
|
+
</template>
|