nextworks 0.1.0-alpha.11 → 0.1.0-alpha.14

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 (57) hide show
  1. package/README.md +20 -9
  2. package/dist/kits/auth-core/.nextworks/docs/AUTH_CORE_README.md +3 -3
  3. package/dist/kits/auth-core/.nextworks/docs/AUTH_QUICKSTART.md +264 -244
  4. package/dist/kits/auth-core/app/(protected)/settings/profile/profile-form.tsx +120 -114
  5. package/dist/kits/auth-core/app/api/auth/forgot-password/route.ts +116 -114
  6. package/dist/kits/auth-core/app/api/auth/reset-password/route.ts +66 -63
  7. package/dist/kits/auth-core/app/api/auth/send-verify-email/route.ts +1 -1
  8. package/dist/kits/auth-core/app/api/users/[id]/route.ts +134 -127
  9. package/dist/kits/auth-core/app/auth/reset-password/page.tsx +186 -187
  10. package/dist/kits/auth-core/components/auth/dashboard.tsx +25 -2
  11. package/dist/kits/auth-core/components/auth/forgot-password-form.tsx +90 -90
  12. package/dist/kits/auth-core/components/auth/login-form.tsx +492 -467
  13. package/dist/kits/auth-core/components/auth/signup-form.tsx +28 -29
  14. package/dist/kits/auth-core/lib/auth.ts +46 -15
  15. package/dist/kits/auth-core/lib/forms/map-errors.ts +37 -11
  16. package/dist/kits/auth-core/lib/server/result.ts +45 -45
  17. package/dist/kits/auth-core/lib/validation/forms.ts +1 -2
  18. package/dist/kits/auth-core/package-deps.json +4 -2
  19. package/dist/kits/auth-core/types/next-auth.d.ts +1 -1
  20. package/dist/kits/blocks/.nextworks/docs/BLOCKS_QUICKSTART.md +2 -8
  21. package/dist/kits/blocks/.nextworks/docs/THEME_GUIDE.md +18 -1
  22. package/dist/kits/blocks/app/templates/productlaunch/page.tsx +0 -2
  23. package/dist/kits/blocks/components/sections/FAQ.tsx +0 -1
  24. package/dist/kits/blocks/components/sections/Newsletter.tsx +2 -2
  25. package/dist/kits/blocks/components/ui/switch.tsx +78 -78
  26. package/dist/kits/blocks/components/ui/theme-selector.tsx +1 -1
  27. package/dist/kits/blocks/lib/themes.ts +1 -0
  28. package/dist/kits/blocks/package-deps.json +4 -4
  29. package/dist/kits/data/.nextworks/docs/DATA_QUICKSTART.md +128 -112
  30. package/dist/kits/data/.nextworks/docs/DATA_README.md +2 -1
  31. package/dist/kits/data/app/api/posts/[id]/route.ts +83 -83
  32. package/dist/kits/data/app/api/posts/route.ts +136 -138
  33. package/dist/kits/data/app/api/seed-demo/route.ts +1 -2
  34. package/dist/kits/data/app/api/users/[id]/route.ts +29 -17
  35. package/dist/kits/data/app/api/users/check-email/route.ts +1 -1
  36. package/dist/kits/data/app/api/users/check-unique/route.ts +30 -27
  37. package/dist/kits/data/app/api/users/route.ts +0 -2
  38. package/dist/kits/data/app/examples/demo/create-post-form.tsx +108 -106
  39. package/dist/kits/data/app/examples/demo/page.tsx +2 -1
  40. package/dist/kits/data/app/examples/demo/seed-demo-button.tsx +1 -1
  41. package/dist/kits/data/components/admin/posts-manager.tsx +727 -719
  42. package/dist/kits/data/components/admin/users-manager.tsx +435 -432
  43. package/dist/kits/data/lib/server/result.ts +5 -2
  44. package/dist/kits/data/package-deps.json +1 -1
  45. package/dist/kits/data/scripts/seed-demo.mjs +1 -2
  46. package/dist/kits/forms/app/api/wizard/route.ts +76 -71
  47. package/dist/kits/forms/app/examples/forms/server-action/page.tsx +78 -71
  48. package/dist/kits/forms/components/hooks/useCheckUnique.ts +85 -79
  49. package/dist/kits/forms/components/ui/form/form-control.tsx +28 -28
  50. package/dist/kits/forms/components/ui/form/form-description.tsx +23 -22
  51. package/dist/kits/forms/components/ui/form/form-item.tsx +21 -21
  52. package/dist/kits/forms/components/ui/form/form-label.tsx +24 -24
  53. package/dist/kits/forms/components/ui/form/form-message.tsx +28 -29
  54. package/dist/kits/forms/components/ui/switch.tsx +78 -78
  55. package/dist/kits/forms/lib/forms/map-errors.ts +1 -1
  56. package/dist/kits/forms/lib/validation/forms.ts +1 -2
  57. package/package.json +1 -1
@@ -8,13 +8,13 @@
8
8
  "@radix-ui/react-alert-dialog": "^1.1.15",
9
9
  "@radix-ui/react-dropdown-menu": "^2.1.16",
10
10
  "tailwind-merge": "^3.3.1",
11
- "tw-animate-css": "^1.3.7",
11
+ "tw-animate-css": "^1.4.0",
12
12
  "next-themes": "^0.4.6",
13
13
  "motion": "^12.23.12",
14
14
  "sonner": "^2.0.7",
15
- "@nextworks/blocks-core": "0.1.0-alpha.0",
16
- "@nextworks/blocks-sections": "0.1.0-alpha.0",
17
- "@nextworks/blocks-templates": "0.1.0-alpha.0"
15
+ "@nextworks/blocks-core": "0.1.0-alpha.14",
16
+ "@nextworks/blocks-sections": "0.1.0-alpha.14",
17
+ "@nextworks/blocks-templates": "0.1.0-alpha.14"
18
18
  },
19
19
  "devDependencies": {
20
20
  "tailwindcss": "^4.1.12"
@@ -1,112 +1,128 @@
1
- # nextworks — Data kit quickstart
2
-
3
- This document explains how to use the Data (crud) kit in the nextworks starter project.
4
-
5
- Prerequisites
6
-
7
- - A running PostgreSQL database and `DATABASE_URL` set in `.env`.
8
- - Auth kit installed and configured (NextAuth + Prisma). The Data kit relies on NextAuth session for access control.
9
- - In the monorepo, this is already wired up.
10
- - In your own app via the CLI, the recommended alpha setup is to install Blocks (with sections + templates) + Auth Core + Forms first, then Data:
11
-
12
- ```bash
13
- npx nextworks add blocks --sections --templates
14
- npx nextworks add auth-core
15
- npx nextworks add forms
16
- npx nextworks add data
17
- ```
18
-
19
- then follow the Prisma and `.env` steps below.
20
-
21
- - Forms kit (optional but recommended) for form primitives.
22
-
23
- Setup
24
-
25
- 1. Install dependencies and generate Prisma client:
26
-
27
- npm install
28
- npx prisma generate
29
-
30
- 2. Run migrations (creates User/Post tables):
31
-
32
- Make sure you have merged the Auth + Data models into your `prisma/schema.prisma` before running migrations.
33
-
34
- npx prisma migrate dev
35
-
36
- 3. Seed a demo admin user and posts locally (optional):
37
-
38
- # Set env vars or use defaults
39
-
40
- SEED_ADMIN_EMAIL=admin@example.com SEED_ADMIN_PASSWORD=password123 node ./scripts/seed-demo.mjs
41
-
42
- 4. Run the dev server:
43
-
44
- npm run dev
45
-
46
- Usage & testing
47
-
48
- - Sign in at /auth/login using the seeded admin credentials (admin@example.com / password123).
49
- - Visit /admin/posts to create/edit/delete posts. The UI supports pagination, search (title contains), and sort by createdAt.
50
- - Visit /admin/users to view users (admin-only).
51
-
52
- Notes
53
-
54
- - Server-side RBAC: all modifying APIs (POST/PUT/DELETE) require a valid session, and user-level checks ensure only authors or admins can modify posts. The users list API requires admin access.
55
- - Published flag: posts have a `published` boolean in Prisma. The admin UI exposes the published checkbox when creating or editing posts.
56
-
57
- Troubleshooting
58
-
59
- - If users list returns 403, ensure your signed-in user has role = 'admin'. You can promote a user with Prisma Studio or by running:
60
-
61
- npx prisma db executeRaw "UPDATE \"User\" SET role = 'admin' WHERE email = 'admin@example.com';"
62
-
63
- - If migrations fail, try:
64
-
65
- npx prisma migrate reset
66
-
67
- Files & kit manifest
68
-
69
- If you plan to package a Data kit, here are the primary files, API routes and components used by the Data example flows. This manifest is intended to help packaging and documentation — adjust paths if you extract the kit into another project.
70
-
71
- Files
72
-
73
- - app/api/posts/route.ts
74
- - app/api/posts/[id]/route.ts
75
- - app/api/users/route.ts
76
- - app/api/users/[id]/route.ts
77
- - app/api/users/check-unique/route.ts
78
- - app/api/users/check-email/route.ts
79
- - app/api/seed-demo/route.ts
80
- - app/api/signup/route.ts
81
- - components/admin/admin-header.tsx
82
- - components/admin/posts-manager.tsx
83
- - components/admin/users-manager.tsx
84
- - app/(protected)/admin/users/page.tsx
85
- - app/(protected)/admin/posts/page.tsx
86
- - app/examples/demo/create-post-form.tsx
87
- - app/examples/demo/page.tsx
88
- - lib/prisma.ts
89
- - lib/server/result.ts
90
- - lib/utils.ts
91
- - lib/validation/forms.ts
92
- - scripts/seed-demo.mjs
93
-
94
- API routes (list)
95
-
96
- - /api/posts (GET/POST) -> app/api/posts/route.ts
97
- - /api/posts/:id (GET/PUT/DELETE) -> app/api/posts/[id]/route.ts
98
- - /api/users (GET/POST) -> app/api/users/route.ts
99
- - /api/users/:id (GET/PUT/DELETE) -> app/api/users/[id]/route.ts
100
- - /api/users/check-unique -> app/api/users/check-unique/route.ts
101
- - /api/users/check-email -> app/api/users/check-email/route.ts
102
- - /api/seed-demo -> app/api/seed-demo/route.ts
103
- - /api/signup -> app/api/signup/route.ts
104
-
105
- Notes
106
-
107
- - The Data kit relies on NextAuth sessions for access control — see lib/auth-helpers.ts and lib/auth.ts for server-side helpers and RBAC checks.
108
- - The API routes return ApiResult envelope objects (see lib/server/result.ts) and the client uses lib/forms/map-errors.ts to map server validation errors into react-hook-form where appropriate.
109
-
110
- Feedback
111
-
112
- - File issues in the repo; note that CLI packaging for the Data kit is not yet implemented — this quickstart is for the repository as-is.
1
+ # nextworks — Data kit quickstart
2
+
3
+ This document explains how to use the Data (crud) kit in the nextworks starter project.
4
+
5
+ Prerequisites
6
+
7
+ - Prisma is required (this kit is Prisma-coupled by design).
8
+ - A running PostgreSQL database and `DATABASE_URL` set in `.env`.
9
+ - Auth kit installed and configured (NextAuth + Prisma). The Data kit relies on NextAuth session for access control.
10
+
11
+ - In the monorepo, this is already wired up.
12
+ - In your own app via the CLI, the recommended alpha setup is to install Blocks (with sections + templates) + Auth Core + Forms first, then Data:
13
+
14
+ ```bash
15
+ npx nextworks add blocks --sections --templates
16
+ npx nextworks add auth-core
17
+ npx nextworks add forms
18
+ npx nextworks add data
19
+ ```
20
+
21
+ then follow the Prisma and `.env` steps below.
22
+
23
+ - Forms kit (optional but recommended) for form primitives.
24
+
25
+ Setup
26
+
27
+ 1. Install dependencies and generate Prisma client:
28
+
29
+ npm install
30
+ npx prisma generate
31
+
32
+ 2. Run migrations (creates User/Post tables):
33
+
34
+ Make sure you have merged the Auth + Data models into your `prisma/schema.prisma` before running migrations.
35
+
36
+ npx prisma migrate dev
37
+
38
+ 3. Seed a demo admin user and posts locally (optional):
39
+
40
+ # Set env vars or use defaults
41
+
42
+ SEED_ADMIN_EMAIL=admin@example.com SEED_ADMIN_PASSWORD=password123 node ./scripts/seed-demo.mjs
43
+
44
+ 4. Run the dev server:
45
+
46
+ npm run dev
47
+
48
+ ### Windows + Prisma + Next 16 (Turbopack) note
49
+
50
+ If you are on **Windows** and have installed the **Auth Core** or **Data** kits (which use Prisma under the hood) on **Next 16+**, the Next dev server may need permission to create symlinks for the Prisma client. On Windows, this can cause errors like:
51
+
52
+ > `create symlink to ../../../../node_modules/@prisma/client`
53
+ > `Caused by: A required privilege is not held by the client. (os error 1314)`
54
+
55
+ If you see this (often surfaced as a 500 on `/api/auth/session` or a NextAuth `CLIENT_FETCH_ERROR`), do one of the following:
56
+
57
+ - **Recommended**: Enable **Developer Mode** in Windows (Settings → For developers → Developer mode). This allows symlinks in normal terminals.
58
+ - Or: Run your dev server from an **elevated PowerShell/terminal** ("Run as administrator").
59
+
60
+ After doing one of these, restart `npm run dev` and reload your app.
61
+
62
+ Usage & testing
63
+
64
+ - Sign in at /auth/login using the seeded admin credentials (admin@example.com / password123).
65
+ - Visit /admin/posts to create/edit/delete posts. The UI supports pagination, search (title contains), and sort by createdAt.
66
+ - Visit /admin/users to view users (admin-only).
67
+
68
+ Notes
69
+
70
+ - Server-side RBAC: all modifying APIs (POST/PUT/DELETE) require a valid session, and user-level checks ensure only authors or admins can modify posts. The users list API requires admin access.
71
+ - Published flag: posts have a `published` boolean in Prisma. The admin UI exposes the published checkbox when creating or editing posts.
72
+
73
+ Troubleshooting
74
+
75
+ - If users list returns 403, ensure your signed-in user has role = 'admin'. You can promote a user with Prisma Studio or by running:
76
+
77
+ npx prisma db executeRaw "UPDATE \"User\" SET role = 'admin' WHERE email = 'admin@example.com';"
78
+
79
+ - If migrations fail, try:
80
+
81
+ npx prisma migrate reset
82
+
83
+ Files & kit manifest
84
+
85
+ If you plan to package a Data kit, here are the primary files, API routes and components used by the Data example flows. This manifest is intended to help packaging and documentation — adjust paths if you extract the kit into another project.
86
+
87
+ Files
88
+
89
+ - app/api/posts/route.ts
90
+ - app/api/posts/[id]/route.ts
91
+ - app/api/users/route.ts
92
+ - app/api/users/[id]/route.ts
93
+ - app/api/users/check-unique/route.ts
94
+ - app/api/users/check-email/route.ts
95
+ - app/api/seed-demo/route.ts
96
+ - app/api/signup/route.ts
97
+ - components/admin/admin-header.tsx
98
+ - components/admin/posts-manager.tsx
99
+ - components/admin/users-manager.tsx
100
+ - app/(protected)/admin/users/page.tsx
101
+ - app/(protected)/admin/posts/page.tsx
102
+ - app/examples/demo/create-post-form.tsx
103
+ - app/examples/demo/page.tsx
104
+ - lib/prisma.ts
105
+ - lib/server/result.ts
106
+ - lib/utils.ts
107
+ - lib/validation/forms.ts
108
+ - scripts/seed-demo.mjs
109
+
110
+ API routes (list)
111
+
112
+ - /api/posts (GET/POST) -> app/api/posts/route.ts
113
+ - /api/posts/:id (GET/PUT/DELETE) -> app/api/posts/[id]/route.ts
114
+ - /api/users (GET/POST) -> app/api/users/route.ts
115
+ - /api/users/:id (GET/PUT/DELETE) -> app/api/users/[id]/route.ts
116
+ - /api/users/check-unique -> app/api/users/check-unique/route.ts
117
+ - /api/users/check-email -> app/api/users/check-email/route.ts
118
+ - /api/seed-demo -> app/api/seed-demo/route.ts
119
+ - /api/signup -> app/api/signup/route.ts
120
+
121
+ Notes
122
+
123
+ - The Data kit relies on NextAuth sessions for access control — see lib/auth-helpers.ts and lib/auth.ts for server-side helpers and RBAC checks.
124
+ - The API routes return ApiResult envelope objects (see lib/server/result.ts) and the client uses lib/forms/map-errors.ts to map server validation errors into react-hook-form where appropriate.
125
+
126
+ Feedback
127
+
128
+ - File issues in the repo; note that CLI packaging for the Data kit is not yet implemented — this quickstart is for the repository as-is.
@@ -75,7 +75,8 @@ If you choose a different database provider, update the `provider` field in your
75
75
  Notes and important behavior
76
76
 
77
77
  - Kit dependencies:
78
- - Data depends on Auth (for RBAC/session) and Forms (for form primitives/validation). The CLI currently auto-installs `auth-core` and `forms` when you run `nextworks add data` to ensure the required pieces are present. If you prefer an interactive prompt instead of auto-install, the CLI can be adjusted to prompt (ask the maintainers).
78
+ - Data requires Prisma (this kit is Prisma-coupled by design) and depends on Auth (for RBAC/session) and Forms (for form primitives/validation).
79
+ - The CLI currently auto-installs `auth-core` and `forms` when you run `nextworks add data` to ensure the required pieces are present. If you prefer an interactive prompt instead of auto-install, the CLI can be adjusted to prompt (ask the maintainers).
79
80
  - The kit's package-deps.json lists runtime and dev dependencies that the CLI will merge into the project's package.json; after installation you must run npm install in the project.
80
81
 
81
82
  - Standalone admin components:
@@ -1,83 +1,83 @@
1
- import { prisma } from "@/lib/prisma";
2
- import { z } from "zod";
3
- import { postSchema } from "@/lib/validation/forms";
4
- import { jsonOk, jsonFail, jsonFromZod } 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
- export async function PUT(req: Request, { params }: RouteContext) {
14
- try {
15
- const { id } = await params;
16
-
17
- // Require authenticated session
18
- const session = await getServerSession(authOptions);
19
- if (!session?.user) {
20
- return jsonFail("Unauthorized", { status: 401 });
21
- }
22
-
23
- // Only admins or the post author may update
24
- const post = await prisma.post.findUnique({ where: { id } });
25
- if (!post) return jsonFail("Not found", { status: 404 });
26
-
27
- const isAdmin = (session.user as { role?: string }).role === "admin";
28
- const isAuthor = (session.user as { id?: string }).id === post.authorId;
29
- if (!isAdmin && !isAuthor) {
30
- return jsonFail("Forbidden", { status: 403 });
31
- }
32
-
33
- // Validate only the fields we allow to update. Make them optional so partial updates (e.g. { published: true }) work.
34
- const updateSchema = postSchema
35
- .pick({ title: true, content: true, published: true })
36
- .partial();
37
- const body = await req.json();
38
- const data = updateSchema.parse(body);
39
-
40
- // Build Prisma update object only with provided fields to avoid overwriting with undefined
41
- const updateData: any = {};
42
- if (data.title !== undefined) updateData.title = data.title;
43
- if (data.content !== undefined) updateData.content = data.content ?? null;
44
- if (data.published !== undefined) updateData.published = data.published;
45
-
46
- const updated = await prisma.post.update({
47
- where: { id },
48
- data: updateData,
49
- });
50
- return jsonOk(updated, { status: 200, message: "Post updated" });
51
- } catch (error: unknown) {
52
- if (error instanceof z.ZodError) {
53
- return jsonFromZod(error, { status: 400, message: "Validation failed" });
54
- }
55
- return jsonFail("Failed to update post", { status: 500 });
56
- }
57
- }
58
-
59
- export async function DELETE(_req: Request, { params }: RouteContext) {
60
- try {
61
- const { id } = await params; // await params
62
-
63
- const session = await getServerSession(authOptions);
64
- if (!session?.user) {
65
- return jsonFail("Unauthorized", { status: 401 });
66
- }
67
-
68
- const post = await prisma.post.findUnique({ where: { id } });
69
- if (!post) return jsonFail("Not found", { status: 404 });
70
-
71
- const isAdmin = (session.user as { role?: string }).role === "admin";
72
- const isAuthor = (session.user as { id?: string }).id === post.authorId;
73
- if (!isAdmin && !isAuthor) {
74
- return jsonFail("Forbidden", { status: 403 });
75
- }
76
-
77
- await prisma.post.delete({ where: { id } }); // If Int: id: Number(id)
78
- return jsonOk({ ok: true }, { status: 200, message: "Post deleted" });
79
- } catch (e) {
80
- console.error("DELETE /api/posts/[id] error:", e);
81
- return jsonFail("Failed to delete post", { status: 500 });
82
- }
83
- }
1
+ import { prisma } from "@/lib/prisma";
2
+ import { z } from "zod";
3
+ import { postSchema } from "@/lib/validation/forms";
4
+ import { jsonOk, jsonFail, jsonFromZod } 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
+ export async function PUT(req: Request, { params }: RouteContext) {
14
+ try {
15
+ const { id } = await params;
16
+
17
+ // Require authenticated session
18
+ const session = await getServerSession(authOptions);
19
+ if (!session?.user) {
20
+ return jsonFail("Unauthorized", { status: 401 });
21
+ }
22
+
23
+ // Only admins or the post author may update
24
+ const post = await prisma.post.findUnique({ where: { id } });
25
+ if (!post) return jsonFail("Not found", { status: 404 });
26
+
27
+ const isAdmin = (session.user as { role?: string }).role === "admin";
28
+ const isAuthor = (session.user as { id?: string }).id === post.authorId;
29
+ if (!isAdmin && !isAuthor) {
30
+ return jsonFail("Forbidden", { status: 403 });
31
+ }
32
+
33
+ // Validate only the fields we allow to update. Make them optional so partial updates (e.g. { published: true }) work.
34
+ const updateSchema = postSchema
35
+ .pick({ title: true, content: true, published: true })
36
+ .partial();
37
+ const body = await req.json();
38
+ const data = updateSchema.parse(body);
39
+
40
+ // Build Prisma update object only with provided fields to avoid overwriting with undefined
41
+ const updateData: Parameters<typeof prisma.post.update>[0]["data"] = {};
42
+ if (data.title !== undefined) updateData.title = data.title;
43
+ if (data.content !== undefined) updateData.content = data.content ?? null;
44
+ if (data.published !== undefined) updateData.published = data.published;
45
+
46
+ const updated = await prisma.post.update({
47
+ where: { id },
48
+ data: updateData,
49
+ });
50
+ return jsonOk(updated, { status: 200, message: "Post updated" });
51
+ } catch (error: unknown) {
52
+ if (error instanceof z.ZodError) {
53
+ return jsonFromZod(error, { status: 400, message: "Validation failed" });
54
+ }
55
+ return jsonFail("Failed to update post", { status: 500 });
56
+ }
57
+ }
58
+
59
+ export async function DELETE(_req: Request, { params }: RouteContext) {
60
+ try {
61
+ const { id } = await params; // await params
62
+
63
+ const session = await getServerSession(authOptions);
64
+ if (!session?.user) {
65
+ return jsonFail("Unauthorized", { status: 401 });
66
+ }
67
+
68
+ const post = await prisma.post.findUnique({ where: { id } });
69
+ if (!post) return jsonFail("Not found", { status: 404 });
70
+
71
+ const isAdmin = (session.user as { role?: string }).role === "admin";
72
+ const isAuthor = (session.user as { id?: string }).id === post.authorId;
73
+ if (!isAdmin && !isAuthor) {
74
+ return jsonFail("Forbidden", { status: 403 });
75
+ }
76
+
77
+ await prisma.post.delete({ where: { id } }); // If Int: id: Number(id)
78
+ return jsonOk({ ok: true }, { status: 200, message: "Post deleted" });
79
+ } catch (e: unknown) {
80
+ console.error("DELETE /api/posts/[id] error:", e);
81
+ return jsonFail("Failed to delete post", { status: 500 });
82
+ }
83
+ }