@flaredev/cli 0.1.2 → 0.2.0

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 (50) hide show
  1. package/dist/index.js +340 -163
  2. package/package.json +3 -2
  3. package/templates/app/app/api/openapi.json/route.ts +23 -0
  4. package/templates/app/app/api/reference/route.ts +36 -0
  5. package/templates/app/app/dashboard/account/page.tsx +38 -0
  6. package/templates/app/app/dashboard/layout.tsx +39 -0
  7. package/templates/app/app/dashboard/page.tsx +42 -9
  8. package/templates/app/app/forgot-password/page.tsx +22 -0
  9. package/templates/app/app/globals.css +109 -4
  10. package/templates/app/app/layout.tsx +28 -26
  11. package/templates/app/app/page.tsx +126 -13
  12. package/templates/app/app/reset-password/page.tsx +31 -0
  13. package/templates/app/app/sign-in/page.tsx +49 -33
  14. package/templates/app/app/sign-up/page.tsx +42 -23
  15. package/templates/app/app/two-factor/page.tsx +25 -0
  16. package/templates/app/components/account/security-settings.tsx +525 -0
  17. package/templates/app/components/admin/fields/country-field.tsx +152 -0
  18. package/templates/app/components/admin/fields/field-widget.tsx +186 -128
  19. package/templates/app/components/admin/fields/multi-select-field.tsx +46 -0
  20. package/templates/app/components/admin/fields/phone-field.tsx +86 -0
  21. package/templates/app/components/admin/resource-nav.tsx +120 -109
  22. package/templates/app/components/admin/resource-table.tsx +31 -1
  23. package/templates/app/components/auth/auth-shell.tsx +284 -0
  24. package/templates/app/components/auth/password-forms.tsx +79 -0
  25. package/templates/app/components/auth/provider-icons.tsx +39 -0
  26. package/templates/app/components/auth/sign-in-flow.tsx +315 -0
  27. package/templates/app/components/auth/sign-up-form.tsx +101 -0
  28. package/templates/app/components/auth/social-buttons.tsx +56 -0
  29. package/templates/app/components/auth/two-factor-form.tsx +124 -0
  30. package/templates/app/components/auth/ui.tsx +96 -0
  31. package/templates/app/components/dashboard/dashboard-nav.tsx +35 -0
  32. package/templates/app/components/marketing/product-preview.tsx +70 -0
  33. package/templates/app/components/marketing/site-header.tsx +39 -0
  34. package/templates/app/components/sign-out-button.tsx +1 -1
  35. package/templates/app/components/ui/checkbox.tsx +25 -0
  36. package/templates/app/components/ui/radio-group.tsx +29 -0
  37. package/templates/app/db/auth-schema.ts +167 -118
  38. package/templates/app/lib/admin-nav.ts +1 -1
  39. package/templates/app/lib/api-docs.ts +16 -0
  40. package/templates/app/lib/auth-client.ts +16 -1
  41. package/templates/app/lib/auth-config.ts +33 -0
  42. package/templates/app/lib/auth-emails.ts +94 -0
  43. package/templates/app/lib/auth.ts +81 -6
  44. package/templates/app/lib/site.ts +47 -0
  45. package/templates/app/lib/theme.ts +79 -0
  46. package/templates/app/migrations/0000_init.sql +32 -1
  47. package/templates/app/migrations/meta/0000_snapshot.json +215 -1
  48. package/templates/app/migrations/meta/_journal.json +1 -1
  49. package/templates/app/vite.config.ts +5 -3
  50. package/templates/app/components/auth-form.tsx +0 -120
@@ -1,33 +1,49 @@
1
- import Link from "next/link";
2
- import { redirect } from "next/navigation";
3
- import { AuthForm } from "@/components/auth-form";
4
- import { enabledSocialProviders } from "@/lib/auth";
5
- import { getSession, safeRedirectPath } from "@/lib/session";
6
-
7
- export default async function SignInPage({
8
- searchParams,
9
- }: {
10
- searchParams: Promise<{ next?: string; error?: string }>;
11
- }) {
12
- const params = await searchParams;
13
- const next = safeRedirectPath(params.next);
14
- if (await getSession()) redirect(next);
15
-
16
- return (
17
- <main className="mx-auto flex min-h-screen max-w-sm flex-col justify-center gap-6 p-6">
18
- <h1 className="text-2xl font-semibold">Sign in</h1>
19
- <AuthForm
20
- mode="sign-in"
21
- next={next}
22
- socialProviders={enabledSocialProviders()}
23
- initialError={params.error ? "Sign-in with that provider failed. Please try again." : null}
24
- />
25
- <p className="text-sm text-[var(--foreground-muted)]">
26
- No account?{" "}
27
- <Link href={`/sign-up?next=${encodeURIComponent(next)}`} className="font-medium text-[var(--foreground)] underline">
28
- Create one
29
- </Link>
30
- </p>
31
- </main>
32
- );
33
- }
1
+ import Link from "next/link";
2
+ import { redirect } from "next/navigation";
3
+ import { AuthShell } from "@/components/auth/auth-shell";
4
+ import { SignInFlow } from "@/components/auth/sign-in-flow";
5
+ import { enabledSocialProviders } from "@/lib/auth";
6
+ import { authConfig } from "@/lib/auth-config";
7
+ import { getSession, safeRedirectPath } from "@/lib/session";
8
+ import { site } from "@/lib/site";
9
+ import { theme } from "@/lib/theme";
10
+
11
+ export const metadata = { title: "Sign in" };
12
+
13
+ const ERRORS: Record<string, string> = {
14
+ oauth: "Sign-in with that provider didn't finish. Try again.",
15
+ link: "That sign-in link has expired or was already used. Ask for a new one.",
16
+ };
17
+
18
+ export default async function SignInPage({ searchParams }: { searchParams: Promise<{ next?: string; error?: string; reset?: string }> }) {
19
+ const params = await searchParams;
20
+ const next = safeRedirectPath(params.next);
21
+ if (await getSession()) redirect(next);
22
+
23
+ const copy = theme.signIn(site.name);
24
+ return (
25
+ <AuthShell
26
+ page="sign-in"
27
+ title={copy.title}
28
+ subtitle={(copy as { subtitle?: string }).subtitle}
29
+ footer={
30
+ <>
31
+ Don&apos;t have an account?{" "}
32
+ <Link href={`/sign-up?next=${encodeURIComponent(next)}`} className="font-medium text-link hover:underline">
33
+ Sign up
34
+ </Link>
35
+ </>
36
+ }
37
+ >
38
+ <SignInFlow
39
+ providers={enabledSocialProviders()}
40
+ socialPlacement={theme.social}
41
+ socialStyle={theme.socialStyle}
42
+ methods={{ magicLink: authConfig.magicLink, emailOtp: authConfig.emailOtp, passkeys: authConfig.passkeys }}
43
+ next={next}
44
+ initialError={params.error ? (ERRORS[params.error] ?? "Sign-in didn't finish. Try again.") : null}
45
+ initialNotice={params.reset ? "Your password is changed. Sign in with the new one." : null}
46
+ />
47
+ </AuthShell>
48
+ );
49
+ }
@@ -1,23 +1,42 @@
1
- import Link from "next/link";
2
- import { redirect } from "next/navigation";
3
- import { AuthForm } from "@/components/auth-form";
4
- import { enabledSocialProviders } from "@/lib/auth";
5
- import { getSession, safeRedirectPath } from "@/lib/session";
6
-
7
- export default async function SignUpPage({ searchParams }: { searchParams: Promise<{ next?: string }> }) {
8
- const next = safeRedirectPath((await searchParams).next);
9
- if (await getSession()) redirect(next);
10
-
11
- return (
12
- <main className="mx-auto flex min-h-screen max-w-sm flex-col justify-center gap-6 p-6">
13
- <h1 className="text-2xl font-semibold">Create an account</h1>
14
- <AuthForm mode="sign-up" next={next} socialProviders={enabledSocialProviders()} />
15
- <p className="text-sm text-[var(--foreground-muted)]">
16
- Already registered?{" "}
17
- <Link href={`/sign-in?next=${encodeURIComponent(next)}`} className="font-medium text-[var(--foreground)] underline">
18
- Sign in
19
- </Link>
20
- </p>
21
- </main>
22
- );
23
- }
1
+ import Link from "next/link";
2
+ import { redirect } from "next/navigation";
3
+ import { AuthShell } from "@/components/auth/auth-shell";
4
+ import { SignUpForm } from "@/components/auth/sign-up-form";
5
+ import { enabledSocialProviders } from "@/lib/auth";
6
+ import { authConfig } from "@/lib/auth-config";
7
+ import { getSession, safeRedirectPath } from "@/lib/session";
8
+ import { site } from "@/lib/site";
9
+ import { theme } from "@/lib/theme";
10
+
11
+ export const metadata = { title: "Create an account" };
12
+
13
+ export default async function SignUpPage({ searchParams }: { searchParams: Promise<{ next?: string }> }) {
14
+ const params = await searchParams;
15
+ const next = safeRedirectPath(params.next);
16
+ if (await getSession()) redirect(next);
17
+
18
+ const copy = theme.signUp(site.name);
19
+ return (
20
+ <AuthShell
21
+ page="sign-up"
22
+ title={copy.title}
23
+ subtitle={(copy as { subtitle?: string }).subtitle}
24
+ footer={
25
+ <>
26
+ Already have an account?{" "}
27
+ <Link href={`/sign-in?next=${encodeURIComponent(next)}`} className="font-medium text-link hover:underline">
28
+ Sign in
29
+ </Link>
30
+ </>
31
+ }
32
+ >
33
+ <SignUpForm
34
+ providers={enabledSocialProviders()}
35
+ socialPlacement={theme.social}
36
+ socialStyle={theme.socialStyle}
37
+ next={next}
38
+ verifyFirst={authConfig.requireEmailVerification}
39
+ />
40
+ </AuthShell>
41
+ );
42
+ }
@@ -0,0 +1,25 @@
1
+ import Link from "next/link";
2
+ import { AuthShell } from "@/components/auth/auth-shell";
3
+ import { TwoFactorForm } from "@/components/auth/two-factor-form";
4
+ import { authConfig } from "@/lib/auth-config";
5
+ import { safeRedirectPath } from "@/lib/session";
6
+
7
+ export const metadata = { title: "Verify it's you" };
8
+
9
+ /** Reached after a correct password on an account with two-factor on (lib/auth-client.ts sends people here). */
10
+ export default async function TwoFactorPage({ searchParams }: { searchParams: Promise<{ next?: string }> }) {
11
+ const { next } = await searchParams;
12
+ return (
13
+ <AuthShell
14
+ title="Verify it's you"
15
+ subtitle="Your account uses two-factor authentication."
16
+ footer={
17
+ <Link href="/sign-in" className="font-medium text-link hover:underline">
18
+ Use a different account
19
+ </Link>
20
+ }
21
+ >
22
+ <TwoFactorForm methods={authConfig.twoFactor} next={safeRedirectPath(next)} />
23
+ </AuthShell>
24
+ );
25
+ }