nextworks 0.1.0-alpha.8 → 0.1.0-alpha.9

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 CHANGED
@@ -215,6 +215,17 @@ You can add a short “Nextworks setup” section to your app README:
215
215
 
216
216
  ---
217
217
 
218
+ ## License
219
+
220
+ The code in this CLI and the generated files is licensed under the MIT License (see `LICENSE`).
221
+
222
+ The placeholder images in the templates are sourced from Pexels and are
223
+ subject to the [Pexels License](https://www.pexels.com/license/).
224
+ They are included for demonstration purposes only and are **not** covered by
225
+ the MIT License.
226
+
227
+ ---
228
+
218
229
  ## Troubleshooting
219
230
 
220
231
  - **Prisma errors or missing migrations**
@@ -15,6 +15,8 @@
15
15
  "components/auth/minimal-logout-button.tsx",
16
16
  "app/(protected)/settings/profile/page.tsx",
17
17
  "app/(protected)/settings/profile/profile-form.tsx",
18
+ "app/(protected)/admin/posts/page.tsx",
19
+ "app/(protected)/admin/users/page.tsx",
18
20
  "components/ui/input.tsx",
19
21
  "components/ui/label.tsx",
20
22
  "components/ui/button.tsx",
@@ -33,6 +35,7 @@
33
35
  "app/api/auth/forgot-password/route.ts",
34
36
  "app/api/auth/reset-password/route.ts",
35
37
  "app/api/auth/send-verify-email/route.ts",
38
+ "app/api/users/[id]/route.ts",
36
39
  "app/api/signup/route.ts",
37
40
  "lib/auth.ts",
38
41
  "lib/auth-helpers.ts",
@@ -0,0 +1,29 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+
5
+ export default function AdminPostsPlaceholderPage() {
6
+ return (
7
+ <main className="mx-auto max-w-2xl px-4 py-12">
8
+ <h1 className="text-2xl font-semibold text-foreground">
9
+ Posts admin requires the Data kit
10
+ </h1>
11
+ <p className="mt-2 text-sm text-muted-foreground">
12
+ This project has the auth-core kit installed, which provides
13
+ authentication and basic admin scaffolding.
14
+ <br />
15
+ To create and manage posts, install the Data kit and wire up its admin
16
+ routes into your app.
17
+ </p>
18
+
19
+ <div className="mt-6 flex items-center gap-3 text-sm">
20
+ <Link
21
+ href="/dashboard"
22
+ className="text-primary underline-offset-4 hover:underline"
23
+ >
24
+ Back to dashboard
25
+ </Link>
26
+ </div>
27
+ </main>
28
+ );
29
+ }
@@ -0,0 +1,29 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+
5
+ export default function AdminUsersPlaceholderPage() {
6
+ return (
7
+ <main className="mx-auto max-w-2xl px-4 py-12">
8
+ <h1 className="text-2xl font-semibold text-foreground">
9
+ Users admin requires the Data kit
10
+ </h1>
11
+ <p className="mt-2 text-sm text-muted-foreground">
12
+ This project has the auth-core kit installed, which provides
13
+ authentication and basic admin scaffolding.
14
+ <br />
15
+ To manage users (list, filter, edit, etc.), install the Data kit and
16
+ add its admin routes to your app.
17
+ </p>
18
+
19
+ <div className="mt-6 flex items-center gap-3 text-sm">
20
+ <Link
21
+ href="/dashboard"
22
+ className="text-primary underline-offset-4 hover:underline"
23
+ >
24
+ Back to dashboard
25
+ </Link>
26
+ </div>
27
+ </main>
28
+ );
29
+ }
@@ -0,0 +1,127 @@
1
+ import { NextRequest } from "next/server";
2
+ import { prisma } from "@/lib/prisma";
3
+ import type { Prisma } from "@prisma/client";
4
+ import { jsonOk, jsonFail } from "@/lib/server/result";
5
+ import { getServerSession } from "next-auth";
6
+ import { authOptions } from "@/lib/auth";
7
+
8
+ // Ensure Prisma runs in Node.js (not Edge)
9
+ export const runtime = "nodejs";
10
+
11
+ type RouteContext = { params: Promise<{ id: string }> };
12
+
13
+ // Type guards/helpers (kept minimal here)
14
+ const hasErrorCode = (e: unknown, code: string): boolean =>
15
+ typeof e === "object" &&
16
+ e !== null &&
17
+ "code" in e &&
18
+ typeof (e as { code?: unknown }).code === "string" &&
19
+ (e as { code: string }).code === code;
20
+
21
+ export async function GET(_req: NextRequest, { params }: RouteContext) {
22
+ try {
23
+ const { id } = await params; // async params in Next.js 15
24
+
25
+ const user = await prisma.user.findUnique({
26
+ where: { id },
27
+ select: { id: true, name: true, email: true, role: true },
28
+ });
29
+
30
+ if (!user) {
31
+ return jsonFail("Not found", { status: 404 });
32
+ }
33
+
34
+ return jsonOk(user);
35
+ } catch (e) {
36
+ console.error("GET /api/users/[id] error:", e);
37
+ return jsonFail("Failed to fetch user", { status: 500 });
38
+ }
39
+ }
40
+
41
+ export async function PUT(req: NextRequest, { params }: RouteContext) {
42
+ try {
43
+ // Only admins may update other users. Allow self-update as well.
44
+ const session = await getServerSession(authOptions);
45
+ if (!session?.user) return jsonFail("Unauthorized", { status: 401 });
46
+
47
+ const { id } = await params;
48
+ const isAdmin = (session.user as { role?: string }).role === "admin";
49
+ const isSelf = (session.user as { id?: string }).id === id;
50
+ if (!isAdmin && !isSelf) return jsonFail("Forbidden", { status: 403 });
51
+
52
+ const body: unknown = await req.json();
53
+ if (typeof body !== "object" || body === null) {
54
+ return jsonFail("Body must be a JSON object", { status: 400 });
55
+ }
56
+
57
+ // Validate with Zod (imported lazily to keep this route light)
58
+ const { userUpdateSchema } = await import("@/lib/validation/forms");
59
+ try {
60
+ const parsed = userUpdateSchema.parse(body);
61
+
62
+ // Build Prisma-compatible update object
63
+ const data: Prisma.UserUpdateInput = {};
64
+ if (parsed.name !== undefined)
65
+ data.name = parsed.name === "" ? null : parsed.name;
66
+ if (parsed.email !== undefined) data.email = parsed.email;
67
+ if (parsed.image !== undefined)
68
+ data.image = parsed.image === "" ? null : parsed.image;
69
+ if (parsed.password !== undefined) {
70
+ // Hash password before saving
71
+ const { hashPassword } = await import("@/lib/hash");
72
+ data.password = await hashPassword(parsed.password as string);
73
+ }
74
+ if (parsed.emailVerified !== undefined)
75
+ data.emailVerified = parsed.emailVerified as any;
76
+
77
+ const updated = await prisma.user.update({
78
+ where: { id },
79
+ data,
80
+ });
81
+
82
+ return jsonOk(updated, { status: 200, message: "User updated" });
83
+ } catch (err) {
84
+ // Zod errors
85
+ if (err && typeof err === "object" && "issues" in (err as any)) {
86
+ const { jsonFromZod } = await import("@/lib/server/result");
87
+ return jsonFromZod(err as any, {
88
+ status: 400,
89
+ message: "Validation failed",
90
+ });
91
+ }
92
+ throw err;
93
+ }
94
+ } catch (e) {
95
+ console.error("PUT /api/users/[id] error:", e);
96
+ if (hasErrorCode(e, "P2025")) {
97
+ return jsonFail("Not found", { status: 404 });
98
+ }
99
+ return jsonFail("Failed to update user", { status: 500 });
100
+ }
101
+ }
102
+
103
+ export async function DELETE(_req: NextRequest, { params }: RouteContext) {
104
+ try {
105
+ const { requireAdminApi } = await import("@/lib/auth-helpers");
106
+ const session = await requireAdminApi();
107
+ if (!session) return jsonFail("Forbidden", { status: 403 });
108
+
109
+ const { id } = await params;
110
+
111
+ // Clean up dependent records first to avoid FK violations
112
+ await prisma.$transaction([
113
+ prisma.account.deleteMany({ where: { userId: id } }),
114
+ prisma.session.deleteMany({ where: { userId: id } }),
115
+ prisma.post.deleteMany({ where: { authorId: id } }),
116
+ prisma.user.delete({ where: { id } }),
117
+ ]);
118
+
119
+ return jsonOk({ ok: true }, { status: 200, message: "User deleted" });
120
+ } catch (e) {
121
+ console.error("DELETE /api/users/[id] error:", e);
122
+ if (hasErrorCode(e, "P2025")) {
123
+ return jsonFail("Not found", { status: 404 });
124
+ }
125
+ return jsonFail("Failed to delete user", { status: 500 });
126
+ }
127
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nextworks",
3
- "version": "0.1.0-alpha.8",
3
+ "version": "0.1.0-alpha.9",
4
4
  "description": "Nextworks CLI - Feature kits installer for Next.js apps",
5
5
  "main": "dist/index.js",
6
6
  "bin": {