@flaredev/cli 0.1.2 → 0.3.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.
- package/bin/flare.js +9 -1
- package/dist/index.js +985 -337
- package/package.json +3 -2
- package/templates/app/app/admin/page.tsx +9 -61
- package/templates/app/app/api/openapi.json/route.ts +23 -0
- package/templates/app/app/api/reference/route.ts +36 -0
- package/templates/app/app/dashboard/account/page.tsx +40 -0
- package/templates/app/app/{admin → dashboard}/actions.ts +109 -11
- package/templates/app/app/dashboard/import-actions.ts +91 -0
- package/templates/app/app/dashboard/layout.tsx +42 -0
- package/templates/app/app/dashboard/observability/page.tsx +174 -0
- package/templates/app/app/dashboard/page.tsx +123 -9
- package/templates/app/app/forgot-password/page.tsx +22 -0
- package/templates/app/app/globals.css +109 -4
- package/templates/app/app/layout.tsx +28 -26
- package/templates/app/app/page.tsx +126 -13
- package/templates/app/app/reset-password/page.tsx +31 -0
- package/templates/app/app/sign-in/page.tsx +49 -33
- package/templates/app/app/sign-up/page.tsx +42 -23
- package/templates/app/app/two-factor/page.tsx +25 -0
- package/templates/app/app/verify-email/page.tsx +33 -0
- package/templates/app/components/account/security-settings.tsx +522 -0
- package/templates/app/components/auth/auth-shell.tsx +284 -0
- package/templates/app/components/auth/otp-input.tsx +95 -0
- package/templates/app/components/auth/password-field.tsx +116 -0
- package/templates/app/components/auth/password-forms.tsx +76 -0
- package/templates/app/components/auth/provider-icons.tsx +39 -0
- package/templates/app/components/auth/sign-in-flow.tsx +306 -0
- package/templates/app/components/auth/sign-up-form.tsx +93 -0
- package/templates/app/components/auth/social-buttons.tsx +56 -0
- package/templates/app/components/auth/two-factor-form.tsx +139 -0
- package/templates/app/components/auth/ui.tsx +96 -0
- package/templates/app/components/auth/use-resend.ts +44 -0
- package/templates/app/components/auth/verify-email-form.tsx +135 -0
- package/templates/app/components/{admin/admin-header.tsx → dashboard/dashboard-header.tsx} +78 -78
- package/templates/app/components/{admin/resource-nav.tsx → dashboard/dashboard-sidebar.tsx} +66 -9
- package/templates/app/components/dashboard/export-button.tsx +41 -0
- package/templates/app/components/dashboard/fields/country-field.tsx +152 -0
- package/templates/app/components/{admin → dashboard}/fields/field-widget.tsx +186 -128
- package/templates/app/components/{admin → dashboard}/fields/file-field.tsx +302 -302
- package/templates/app/components/dashboard/fields/multi-select-field.tsx +46 -0
- package/templates/app/components/dashboard/fields/phone-field.tsx +86 -0
- package/templates/app/components/dashboard/import-dialog.tsx +487 -0
- package/templates/app/components/dashboard/page-header.tsx +57 -0
- package/templates/app/components/dashboard/resource-form-dialog.tsx +80 -0
- package/templates/app/components/{admin → dashboard}/resource-form-page.tsx +61 -55
- package/templates/app/components/{admin → dashboard}/resource-form.tsx +165 -139
- package/templates/app/components/dashboard/resource-stats.tsx +53 -0
- package/templates/app/components/{admin → dashboard}/resource-table.tsx +331 -251
- package/templates/app/components/{admin → dashboard}/row-actions.tsx +144 -111
- package/templates/app/components/dashboard/stat-card.tsx +69 -0
- package/templates/app/components/dashboard/table-selection.tsx +185 -0
- package/templates/app/components/dashboard/traffic-chart.tsx +32 -0
- package/templates/app/components/marketing/product-preview.tsx +70 -0
- package/templates/app/components/marketing/site-header.tsx +39 -0
- package/templates/app/components/sign-out-button.tsx +1 -1
- package/templates/app/components/ui/checkbox.tsx +25 -0
- package/templates/app/components/ui/radio-group.tsx +29 -0
- package/templates/app/db/auth-schema.ts +167 -118
- package/templates/app/db/flare-schema.ts +33 -1
- package/templates/app/lib/analytics.ts +121 -0
- package/templates/app/lib/api-docs.ts +16 -0
- package/templates/app/lib/audit.ts +80 -0
- package/templates/app/lib/auth-client.ts +16 -1
- package/templates/app/lib/auth-config.ts +38 -0
- package/templates/app/lib/auth-emails.ts +94 -0
- package/templates/app/lib/auth.ts +115 -6
- package/templates/app/lib/cache.ts +83 -83
- package/templates/app/lib/csv.ts +24 -0
- package/templates/app/lib/dashboard-nav.ts +15 -0
- package/templates/app/lib/{admin.ts → dashboard.ts} +138 -103
- package/templates/app/lib/password-rules.ts +159 -0
- package/templates/app/lib/site.ts +56 -0
- package/templates/app/lib/theme.ts +79 -0
- package/templates/app/migrations/0000_init.sql +47 -4
- package/templates/app/migrations/meta/0000_snapshot.json +311 -1
- package/templates/app/migrations/meta/_journal.json +1 -1
- package/templates/app/vite.config.ts +5 -3
- package/templates/app/worker-configuration.d.ts +15764 -0
- package/templates/locks/package-lock.json +9189 -0
- package/templates/locks/pnpm-lock.yaml +6347 -0
- package/templates/app/app/admin/layout.tsx +0 -32
- package/templates/app/components/auth-form.tsx +0 -120
- package/templates/app/lib/admin-nav.ts +0 -15
- /package/templates/app/components/{admin → dashboard}/fields/date-field.tsx +0 -0
- /package/templates/app/components/{admin → dashboard}/fields/relation-field.tsx +0 -0
- /package/templates/app/components/{admin → dashboard}/query.ts +0 -0
- /package/templates/app/components/{admin → dashboard}/resource-icon.tsx +0 -0
- /package/templates/app/components/{admin → dashboard}/resource-table-toolbar.tsx +0 -0
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { cookies } from "next/headers";
|
|
2
|
-
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
|
|
3
|
-
import { Toaster } from "@/components/ui/sonner";
|
|
4
|
-
import { AdminHeader, type Theme } from "@/components/admin/admin-header";
|
|
5
|
-
import { ResourceNav } from "@/components/admin/resource-nav";
|
|
6
|
-
import { adminLinks } from "@/lib/admin-nav";
|
|
7
|
-
import { requireAdmin, visibleResources } from "@/lib/admin";
|
|
8
|
-
|
|
9
|
-
export default async function AdminLayout({ children }: { children: React.ReactNode }) {
|
|
10
|
-
const { session } = await requireAdmin();
|
|
11
|
-
const jar = await cookies();
|
|
12
|
-
const theme = (jar.get("flare-theme")?.value ?? "system") as Theme;
|
|
13
|
-
const collapsed = jar.get("sidebar_state")?.value === "false";
|
|
14
|
-
|
|
15
|
-
const resources = (await visibleResources()).map((resource) => ({
|
|
16
|
-
name: resource.name,
|
|
17
|
-
pluralLabel: resource.pluralLabel,
|
|
18
|
-
slug: resource.slug,
|
|
19
|
-
icon: resource.icon,
|
|
20
|
-
}));
|
|
21
|
-
|
|
22
|
-
return (
|
|
23
|
-
<SidebarProvider defaultOpen={!collapsed}>
|
|
24
|
-
<ResourceNav appName="__APP_NAME__" resources={resources} links={adminLinks} />
|
|
25
|
-
<SidebarInset>
|
|
26
|
-
<AdminHeader user={{ name: session.user.name, email: session.user.email }} initialTheme={theme} />
|
|
27
|
-
<main className="flex-1 p-6 md:p-8">{children}</main>
|
|
28
|
-
</SidebarInset>
|
|
29
|
-
<Toaster theme={theme} />
|
|
30
|
-
</SidebarProvider>
|
|
31
|
-
);
|
|
32
|
-
}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useState, type FormEvent } from "react";
|
|
4
|
-
import { authClient } from "@/lib/auth-client";
|
|
5
|
-
|
|
6
|
-
const PROVIDER_LABELS: Record<string, string> = { google: "Google", github: "GitHub" };
|
|
7
|
-
|
|
8
|
-
const inputClass =
|
|
9
|
-
"w-full rounded-md border border-[var(--border)] bg-transparent px-3 py-2 text-sm outline-none focus:border-[var(--foreground)]";
|
|
10
|
-
|
|
11
|
-
export function AuthForm({
|
|
12
|
-
mode,
|
|
13
|
-
next,
|
|
14
|
-
socialProviders = [],
|
|
15
|
-
initialError = null,
|
|
16
|
-
}: {
|
|
17
|
-
mode: "sign-in" | "sign-up";
|
|
18
|
-
next: string;
|
|
19
|
-
socialProviders?: string[];
|
|
20
|
-
initialError?: string | null;
|
|
21
|
-
}) {
|
|
22
|
-
const [error, setError] = useState<string | null>(initialError);
|
|
23
|
-
const [pending, setPending] = useState(false);
|
|
24
|
-
|
|
25
|
-
async function onSubmit(event: FormEvent<HTMLFormElement>) {
|
|
26
|
-
event.preventDefault();
|
|
27
|
-
setError(null);
|
|
28
|
-
setPending(true);
|
|
29
|
-
const form = new FormData(event.currentTarget);
|
|
30
|
-
const email = String(form.get("email"));
|
|
31
|
-
const password = String(form.get("password"));
|
|
32
|
-
|
|
33
|
-
const { error } =
|
|
34
|
-
mode === "sign-up"
|
|
35
|
-
? await authClient.signUp.email({ email, password, name: String(form.get("name")) })
|
|
36
|
-
: await authClient.signIn.email({ email, password });
|
|
37
|
-
|
|
38
|
-
if (error) {
|
|
39
|
-
setError(error.message ?? "Something went wrong. Please try again.");
|
|
40
|
-
setPending(false);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
// Full navigation so server components re-render with the new session cookie.
|
|
44
|
-
window.location.assign(next);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async function signInWithProvider(provider: string) {
|
|
48
|
-
setError(null);
|
|
49
|
-
setPending(true);
|
|
50
|
-
// Redirects the browser to the provider; failures come back to /sign-in?error=...
|
|
51
|
-
const { error } = await authClient.signIn.social({
|
|
52
|
-
provider,
|
|
53
|
-
callbackURL: next,
|
|
54
|
-
errorCallbackURL: `/sign-in?next=${encodeURIComponent(next)}`,
|
|
55
|
-
});
|
|
56
|
-
if (error) {
|
|
57
|
-
setError(error.message ?? "Could not start sign-in. Please try again.");
|
|
58
|
-
setPending(false);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return (
|
|
63
|
-
<div className="flex flex-col gap-4">
|
|
64
|
-
{socialProviders.length > 0 && (
|
|
65
|
-
<>
|
|
66
|
-
<div className="flex flex-col gap-2">
|
|
67
|
-
{socialProviders.map((provider) => (
|
|
68
|
-
<button
|
|
69
|
-
key={provider}
|
|
70
|
-
type="button"
|
|
71
|
-
disabled={pending}
|
|
72
|
-
onClick={() => signInWithProvider(provider)}
|
|
73
|
-
className="rounded-md border border-[var(--border)] px-4 py-2 text-sm font-medium hover:bg-[var(--surface-muted)] disabled:opacity-60"
|
|
74
|
-
>
|
|
75
|
-
Continue with {PROVIDER_LABELS[provider] ?? provider}
|
|
76
|
-
</button>
|
|
77
|
-
))}
|
|
78
|
-
</div>
|
|
79
|
-
<p className="text-center text-xs text-[var(--foreground-muted)]">or use email</p>
|
|
80
|
-
</>
|
|
81
|
-
)}
|
|
82
|
-
|
|
83
|
-
<form onSubmit={onSubmit} className="flex flex-col gap-4">
|
|
84
|
-
{mode === "sign-up" && (
|
|
85
|
-
<label className="flex flex-col gap-1.5 text-sm font-medium">
|
|
86
|
-
Name
|
|
87
|
-
<input name="name" required autoComplete="name" className={inputClass} />
|
|
88
|
-
</label>
|
|
89
|
-
)}
|
|
90
|
-
<label className="flex flex-col gap-1.5 text-sm font-medium">
|
|
91
|
-
Email
|
|
92
|
-
<input name="email" type="email" required autoComplete="email" className={inputClass} />
|
|
93
|
-
</label>
|
|
94
|
-
<label className="flex flex-col gap-1.5 text-sm font-medium">
|
|
95
|
-
Password
|
|
96
|
-
<input
|
|
97
|
-
name="password"
|
|
98
|
-
type="password"
|
|
99
|
-
required
|
|
100
|
-
minLength={8}
|
|
101
|
-
autoComplete={mode === "sign-up" ? "new-password" : "current-password"}
|
|
102
|
-
className={inputClass}
|
|
103
|
-
/>
|
|
104
|
-
</label>
|
|
105
|
-
{error && (
|
|
106
|
-
<p role="alert" className="text-sm text-[var(--danger)]">
|
|
107
|
-
{error}
|
|
108
|
-
</p>
|
|
109
|
-
)}
|
|
110
|
-
<button
|
|
111
|
-
type="submit"
|
|
112
|
-
disabled={pending}
|
|
113
|
-
className="rounded-md bg-[var(--foreground)] px-4 py-2 text-sm font-medium text-[var(--background)] disabled:opacity-60"
|
|
114
|
-
>
|
|
115
|
-
{pending ? "Please wait…" : mode === "sign-up" ? "Create account" : "Sign in"}
|
|
116
|
-
</button>
|
|
117
|
-
</form>
|
|
118
|
-
</div>
|
|
119
|
-
);
|
|
120
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// Extra admin sidebar links (maintained by flare generators such as `flare gen security`).
|
|
2
|
-
// Add your own links outside the generated block.
|
|
3
|
-
// generated:start
|
|
4
|
-
export interface AdminLink {
|
|
5
|
-
label: string;
|
|
6
|
-
href: string;
|
|
7
|
-
/** A resource icon name, e.g. "shield" (see components/admin/resource-icon.tsx). */
|
|
8
|
-
icon: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const generatedAdminLinks: AdminLink[] = [];
|
|
12
|
-
// generated:end
|
|
13
|
-
|
|
14
|
-
/** Links shown under "Platform" in the admin sidebar. */
|
|
15
|
-
export const adminLinks: AdminLink[] = [...generatedAdminLinks];
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|