@microbuild/cli 0.1.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 (38) hide show
  1. package/README.md +555 -0
  2. package/dist/chunk-6YA3DSAE.js +362 -0
  3. package/dist/chunk-6YA3DSAE.js.map +1 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +2279 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/outdated-TV5ERBNC.js +110 -0
  8. package/dist/outdated-TV5ERBNC.js.map +1 -0
  9. package/dist/templates/api/auth-callback-route.ts +36 -0
  10. package/dist/templates/api/auth-headers.ts +72 -0
  11. package/dist/templates/api/auth-login-route.ts +63 -0
  12. package/dist/templates/api/auth-logout-route.ts +41 -0
  13. package/dist/templates/api/auth-user-route.ts +71 -0
  14. package/dist/templates/api/fields-route.ts +44 -0
  15. package/dist/templates/api/files-id-route.ts +116 -0
  16. package/dist/templates/api/files-route.ts +83 -0
  17. package/dist/templates/api/items-id-route.ts +120 -0
  18. package/dist/templates/api/items-route.ts +88 -0
  19. package/dist/templates/api/login-page.tsx +142 -0
  20. package/dist/templates/api/relations-route.ts +46 -0
  21. package/dist/templates/app/design-tokens.css +183 -0
  22. package/dist/templates/app/globals.css +58 -0
  23. package/dist/templates/app/layout.tsx +49 -0
  24. package/dist/templates/app/page.tsx +23 -0
  25. package/dist/templates/components/ColorSchemeToggle.tsx +35 -0
  26. package/dist/templates/lib/common-utils.ts +156 -0
  27. package/dist/templates/lib/hooks/index.ts +98 -0
  28. package/dist/templates/lib/services/index.ts +26 -0
  29. package/dist/templates/lib/theme.ts +241 -0
  30. package/dist/templates/lib/types/index.ts +10 -0
  31. package/dist/templates/lib/utils-index.ts +32 -0
  32. package/dist/templates/lib/utils.ts +14 -0
  33. package/dist/templates/lib/vform/index.ts +24 -0
  34. package/dist/templates/middleware/middleware.ts +29 -0
  35. package/dist/templates/supabase/client.ts +25 -0
  36. package/dist/templates/supabase/middleware.ts +66 -0
  37. package/dist/templates/supabase/server.ts +45 -0
  38. package/package.json +61 -0
@@ -0,0 +1,72 @@
1
+ /**
2
+ * API Auth Headers Helper
3
+ *
4
+ * Forwards authentication tokens from Supabase session to DaaS backend.
5
+ * This file is copied to your project by the Microbuild CLI.
6
+ *
7
+ * @microbuild/origin: api-routes/auth-headers
8
+ * @microbuild/version: 1.0.0
9
+ */
10
+
11
+ import { createClient } from '@/lib/supabase/server';
12
+
13
+ /**
14
+ * Get authentication headers for DaaS API requests
15
+ * Extracts the access token from the current Supabase session
16
+ */
17
+ export async function getAuthHeaders(): Promise<HeadersInit> {
18
+ const supabase = await createClient();
19
+ const { data: { session } } = await supabase.auth.getSession();
20
+
21
+ const headers: HeadersInit = {
22
+ 'Content-Type': 'application/json',
23
+ };
24
+
25
+ if (session?.access_token) {
26
+ headers['Authorization'] = `Bearer ${session.access_token}`;
27
+ }
28
+
29
+ return headers;
30
+ }
31
+
32
+ /**
33
+ * Get the DaaS backend URL from environment
34
+ */
35
+ export function getDaasUrl(): string {
36
+ const url = process.env.NEXT_PUBLIC_MICROBUILD_DAAS_URL;
37
+ if (!url) {
38
+ throw new Error('NEXT_PUBLIC_MICROBUILD_DAAS_URL is not configured in .env.local');
39
+ }
40
+ return url;
41
+ }
42
+
43
+ /**
44
+ * Make an authenticated request to the DaaS backend
45
+ */
46
+ export async function daasRequest<T = unknown>(
47
+ path: string,
48
+ options: RequestInit = {}
49
+ ): Promise<{ data: T | null; error: Error | null }> {
50
+ try {
51
+ const baseUrl = getDaasUrl();
52
+ const headers = await getAuthHeaders();
53
+
54
+ const response = await fetch(`${baseUrl}${path}`, {
55
+ ...options,
56
+ headers: {
57
+ ...headers,
58
+ ...options.headers,
59
+ },
60
+ });
61
+
62
+ if (!response.ok) {
63
+ const errorData = await response.json().catch(() => ({}));
64
+ throw new Error(errorData.errors?.[0]?.message || `Request failed: ${response.status}`);
65
+ }
66
+
67
+ const data = await response.json();
68
+ return { data: data.data ?? data, error: null };
69
+ } catch (error) {
70
+ return { data: null, error: error as Error };
71
+ }
72
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Auth Login API Route (Proxy)
3
+ *
4
+ * Proxies login requests to the DaaS backend.
5
+ * This ensures no CORS issues because the browser only talks to the same-origin Next.js server.
6
+ *
7
+ * Pattern: Browser → Next.js API Route → DaaS Backend → Supabase Auth
8
+ *
9
+ * @microbuild/origin: api-routes/auth-login
10
+ * @microbuild/version: 1.0.0
11
+ */
12
+
13
+ import { NextRequest, NextResponse } from 'next/server';
14
+ import { createClient } from '@/lib/supabase/server';
15
+
16
+ /**
17
+ * POST /api/auth/login
18
+ *
19
+ * Authenticates user with email/password via Supabase Auth.
20
+ * The session cookie is set server-side, avoiding CORS issues.
21
+ */
22
+ export async function POST(request: NextRequest) {
23
+ try {
24
+ const { email, password } = await request.json();
25
+
26
+ if (!email || !password) {
27
+ return NextResponse.json(
28
+ { errors: [{ message: 'Email and password are required' }] },
29
+ { status: 400 }
30
+ );
31
+ }
32
+
33
+ const supabase = await createClient();
34
+
35
+ const { data, error } = await supabase.auth.signInWithPassword({
36
+ email,
37
+ password,
38
+ });
39
+
40
+ if (error) {
41
+ return NextResponse.json(
42
+ { errors: [{ message: error.message }] },
43
+ { status: 401 }
44
+ );
45
+ }
46
+
47
+ return NextResponse.json({
48
+ data: {
49
+ user: data.user,
50
+ session: {
51
+ access_token: data.session?.access_token,
52
+ expires_at: data.session?.expires_at,
53
+ },
54
+ },
55
+ });
56
+ } catch (error) {
57
+ console.error('Login error:', error);
58
+ return NextResponse.json(
59
+ { errors: [{ message: error instanceof Error ? error.message : 'Login failed' }] },
60
+ { status: 500 }
61
+ );
62
+ }
63
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Auth Logout API Route (Proxy)
3
+ *
4
+ * Proxies logout requests through the Next.js server.
5
+ * Clears the Supabase session cookie server-side.
6
+ *
7
+ * @microbuild/origin: api-routes/auth-logout
8
+ * @microbuild/version: 1.0.0
9
+ */
10
+
11
+ import { NextResponse } from 'next/server';
12
+ import { createClient } from '@/lib/supabase/server';
13
+
14
+ /**
15
+ * POST /api/auth/logout
16
+ *
17
+ * Signs out the current user and clears session cookies.
18
+ */
19
+ export async function POST() {
20
+ try {
21
+ const supabase = await createClient();
22
+
23
+ const { error } = await supabase.auth.signOut();
24
+
25
+ if (error) {
26
+ console.error('Logout error:', error);
27
+ return NextResponse.json(
28
+ { errors: [{ message: error.message }] },
29
+ { status: 500 }
30
+ );
31
+ }
32
+
33
+ return NextResponse.json({ data: { message: 'Logged out successfully' } });
34
+ } catch (error) {
35
+ console.error('Unexpected logout error:', error);
36
+ return NextResponse.json(
37
+ { errors: [{ message: 'Failed to logout' }] },
38
+ { status: 500 }
39
+ );
40
+ }
41
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Auth User API Route (Proxy)
3
+ *
4
+ * Returns the currently authenticated user's information.
5
+ * Proxies through the Next.js server to avoid CORS issues.
6
+ *
7
+ * @microbuild/origin: api-routes/auth-user
8
+ * @microbuild/version: 1.0.0
9
+ */
10
+
11
+ import { NextResponse } from 'next/server';
12
+ import { createClient } from '@/lib/supabase/server';
13
+ import { getAuthHeaders, getDaasUrl } from '@/lib/api/auth-headers';
14
+
15
+ /**
16
+ * GET /api/auth/user
17
+ *
18
+ * Returns current user info. Tries DaaS backend first (for full user profile
19
+ * with roles/permissions), falls back to Supabase Auth user.
20
+ */
21
+ export async function GET() {
22
+ try {
23
+ const supabase = await createClient();
24
+ const { data: { user }, error: authError } = await supabase.auth.getUser();
25
+
26
+ if (authError || !user) {
27
+ return NextResponse.json(
28
+ { errors: [{ message: 'Authentication required' }] },
29
+ { status: 401 }
30
+ );
31
+ }
32
+
33
+ // Try to get enhanced user profile from DaaS backend
34
+ try {
35
+ const headers = await getAuthHeaders();
36
+ const daasUrl = getDaasUrl();
37
+
38
+ const response = await fetch(`${daasUrl}/api/users/me`, {
39
+ headers,
40
+ cache: 'no-store',
41
+ });
42
+
43
+ if (response.ok) {
44
+ const data = await response.json();
45
+ return NextResponse.json({ data: data.data || data });
46
+ }
47
+ } catch {
48
+ // DaaS not available, fall back to Supabase user
49
+ }
50
+
51
+ // Fallback: return basic Supabase user info
52
+ return NextResponse.json({
53
+ data: {
54
+ id: user.id,
55
+ email: user.email,
56
+ first_name: user.user_metadata?.first_name || null,
57
+ last_name: user.user_metadata?.last_name || null,
58
+ avatar: user.user_metadata?.avatar || null,
59
+ status: 'active',
60
+ role: null,
61
+ admin_access: false,
62
+ },
63
+ });
64
+ } catch (error) {
65
+ console.error('Auth user error:', error);
66
+ return NextResponse.json(
67
+ { errors: [{ message: 'Failed to get user info' }] },
68
+ { status: 500 }
69
+ );
70
+ }
71
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Fields API Route
3
+ *
4
+ * Proxies field schema requests to the DaaS backend.
5
+ * Required for CollectionForm, VForm, and dynamic field rendering.
6
+ *
7
+ * @microbuild/origin: api-routes/fields
8
+ * @microbuild/version: 1.0.0
9
+ */
10
+
11
+ import { NextRequest, NextResponse } from 'next/server';
12
+ import { getAuthHeaders, getDaasUrl } from '@/lib/api/auth-headers';
13
+
14
+ type RouteParams = { params: Promise<{ collection: string }> };
15
+
16
+ export async function GET(
17
+ request: NextRequest,
18
+ { params }: RouteParams
19
+ ) {
20
+ try {
21
+ const { collection } = await params;
22
+ const headers = await getAuthHeaders();
23
+ const daasUrl = getDaasUrl();
24
+
25
+ const response = await fetch(`${daasUrl}/api/fields/${collection}`, {
26
+ headers,
27
+ cache: 'no-store',
28
+ });
29
+
30
+ if (!response.ok) {
31
+ const error = await response.json().catch(() => ({ errors: [{ message: 'Request failed' }] }));
32
+ return NextResponse.json(error, { status: response.status });
33
+ }
34
+
35
+ const data = await response.json();
36
+ return NextResponse.json(data);
37
+ } catch (error) {
38
+ console.error('Fields API error:', error);
39
+ return NextResponse.json(
40
+ { errors: [{ message: error instanceof Error ? error.message : 'Internal server error' }] },
41
+ { status: 500 }
42
+ );
43
+ }
44
+ }
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Single File API Route
3
+ *
4
+ * Proxies single file operations to the DaaS backend.
5
+ *
6
+ * @microbuild/origin: api-routes/files-id
7
+ * @microbuild/version: 1.0.0
8
+ */
9
+
10
+ import { NextRequest, NextResponse } from 'next/server';
11
+ import { getAuthHeaders, getDaasUrl } from '@/lib/api/auth-headers';
12
+
13
+ type RouteParams = { params: Promise<{ id: string }> };
14
+
15
+ /**
16
+ * GET /api/files/[id]
17
+ * Get file metadata by ID
18
+ */
19
+ export async function GET(
20
+ request: NextRequest,
21
+ { params }: RouteParams
22
+ ) {
23
+ try {
24
+ const { id } = await params;
25
+ const headers = await getAuthHeaders();
26
+ const daasUrl = getDaasUrl();
27
+
28
+ const response = await fetch(`${daasUrl}/api/files/${id}`, {
29
+ headers,
30
+ cache: 'no-store',
31
+ });
32
+
33
+ if (!response.ok) {
34
+ const error = await response.json().catch(() => ({ errors: [{ message: 'Request failed' }] }));
35
+ return NextResponse.json(error, { status: response.status });
36
+ }
37
+
38
+ const data = await response.json();
39
+ return NextResponse.json(data);
40
+ } catch (error) {
41
+ console.error('Files GET by ID error:', error);
42
+ return NextResponse.json(
43
+ { errors: [{ message: error instanceof Error ? error.message : 'Internal server error' }] },
44
+ { status: 500 }
45
+ );
46
+ }
47
+ }
48
+
49
+ /**
50
+ * PATCH /api/files/[id]
51
+ * Update file metadata
52
+ */
53
+ export async function PATCH(
54
+ request: NextRequest,
55
+ { params }: RouteParams
56
+ ) {
57
+ try {
58
+ const { id } = await params;
59
+ const headers = await getAuthHeaders();
60
+ const daasUrl = getDaasUrl();
61
+ const body = await request.json();
62
+
63
+ const response = await fetch(`${daasUrl}/api/files/${id}`, {
64
+ method: 'PATCH',
65
+ headers,
66
+ body: JSON.stringify(body),
67
+ });
68
+
69
+ if (!response.ok) {
70
+ const error = await response.json().catch(() => ({ errors: [{ message: 'Request failed' }] }));
71
+ return NextResponse.json(error, { status: response.status });
72
+ }
73
+
74
+ const data = await response.json();
75
+ return NextResponse.json(data);
76
+ } catch (error) {
77
+ console.error('Files PATCH error:', error);
78
+ return NextResponse.json(
79
+ { errors: [{ message: error instanceof Error ? error.message : 'Internal server error' }] },
80
+ { status: 500 }
81
+ );
82
+ }
83
+ }
84
+
85
+ /**
86
+ * DELETE /api/files/[id]
87
+ * Delete a file
88
+ */
89
+ export async function DELETE(
90
+ request: NextRequest,
91
+ { params }: RouteParams
92
+ ) {
93
+ try {
94
+ const { id } = await params;
95
+ const headers = await getAuthHeaders();
96
+ const daasUrl = getDaasUrl();
97
+
98
+ const response = await fetch(`${daasUrl}/api/files/${id}`, {
99
+ method: 'DELETE',
100
+ headers,
101
+ });
102
+
103
+ if (!response.ok) {
104
+ const error = await response.json().catch(() => ({ errors: [{ message: 'Request failed' }] }));
105
+ return NextResponse.json(error, { status: response.status });
106
+ }
107
+
108
+ return NextResponse.json({ data: null });
109
+ } catch (error) {
110
+ console.error('Files DELETE error:', error);
111
+ return NextResponse.json(
112
+ { errors: [{ message: error instanceof Error ? error.message : 'Internal server error' }] },
113
+ { status: 500 }
114
+ );
115
+ }
116
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Files API Route
3
+ *
4
+ * Proxies file operations to the DaaS backend.
5
+ * Required for file upload components.
6
+ *
7
+ * @microbuild/origin: api-routes/files
8
+ * @microbuild/version: 1.0.0
9
+ */
10
+
11
+ import { NextRequest, NextResponse } from 'next/server';
12
+ import { getAuthHeaders, getDaasUrl } from '@/lib/api/auth-headers';
13
+
14
+ /**
15
+ * GET /api/files
16
+ * List files with optional filtering
17
+ */
18
+ export async function GET(request: NextRequest) {
19
+ try {
20
+ const headers = await getAuthHeaders();
21
+ const daasUrl = getDaasUrl();
22
+
23
+ // Forward query parameters
24
+ const searchParams = request.nextUrl.searchParams.toString();
25
+ const url = `${daasUrl}/api/files${searchParams ? `?${searchParams}` : ''}`;
26
+
27
+ const response = await fetch(url, {
28
+ headers,
29
+ cache: 'no-store',
30
+ });
31
+
32
+ if (!response.ok) {
33
+ const error = await response.json().catch(() => ({ errors: [{ message: 'Request failed' }] }));
34
+ return NextResponse.json(error, { status: response.status });
35
+ }
36
+
37
+ const data = await response.json();
38
+ return NextResponse.json(data);
39
+ } catch (error) {
40
+ console.error('Files GET error:', error);
41
+ return NextResponse.json(
42
+ { errors: [{ message: error instanceof Error ? error.message : 'Internal server error' }] },
43
+ { status: 500 }
44
+ );
45
+ }
46
+ }
47
+
48
+ /**
49
+ * POST /api/files
50
+ * Upload a file
51
+ */
52
+ export async function POST(request: NextRequest) {
53
+ try {
54
+ const headers = await getAuthHeaders();
55
+ const daasUrl = getDaasUrl();
56
+
57
+ // Get the form data from the request
58
+ const formData = await request.formData();
59
+
60
+ // Remove Content-Type header to let fetch set it with boundary for multipart
61
+ const { 'Content-Type': _, ...restHeaders } = headers as Record<string, string>;
62
+
63
+ const response = await fetch(`${daasUrl}/api/files`, {
64
+ method: 'POST',
65
+ headers: restHeaders,
66
+ body: formData,
67
+ });
68
+
69
+ if (!response.ok) {
70
+ const error = await response.json().catch(() => ({ errors: [{ message: 'Upload failed' }] }));
71
+ return NextResponse.json(error, { status: response.status });
72
+ }
73
+
74
+ const data = await response.json();
75
+ return NextResponse.json(data);
76
+ } catch (error) {
77
+ console.error('Files POST error:', error);
78
+ return NextResponse.json(
79
+ { errors: [{ message: error instanceof Error ? error.message : 'Internal server error' }] },
80
+ { status: 500 }
81
+ );
82
+ }
83
+ }
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Items Single Item API Route
3
+ *
4
+ * Proxies single item CRUD operations to the DaaS backend.
5
+ *
6
+ * @microbuild/origin: api-routes/items-id
7
+ * @microbuild/version: 1.0.0
8
+ */
9
+
10
+ import { NextRequest, NextResponse } from 'next/server';
11
+ import { getAuthHeaders, getDaasUrl } from '@/lib/api/auth-headers';
12
+
13
+ type RouteParams = { params: Promise<{ collection: string; id: string }> };
14
+
15
+ /**
16
+ * GET /api/items/[collection]/[id]
17
+ * Get a single item by ID
18
+ */
19
+ export async function GET(
20
+ request: NextRequest,
21
+ { params }: RouteParams
22
+ ) {
23
+ try {
24
+ const { collection, id } = await params;
25
+ const headers = await getAuthHeaders();
26
+ const daasUrl = getDaasUrl();
27
+
28
+ // Forward query parameters (e.g., fields)
29
+ const searchParams = request.nextUrl.searchParams.toString();
30
+ const url = `${daasUrl}/api/items/${collection}/${id}${searchParams ? `?${searchParams}` : ''}`;
31
+
32
+ const response = await fetch(url, {
33
+ headers,
34
+ cache: 'no-store',
35
+ });
36
+
37
+ if (!response.ok) {
38
+ const error = await response.json().catch(() => ({ errors: [{ message: 'Request failed' }] }));
39
+ return NextResponse.json(error, { status: response.status });
40
+ }
41
+
42
+ const data = await response.json();
43
+ return NextResponse.json(data);
44
+ } catch (error) {
45
+ console.error('Items GET by ID error:', error);
46
+ return NextResponse.json(
47
+ { errors: [{ message: error instanceof Error ? error.message : 'Internal server error' }] },
48
+ { status: 500 }
49
+ );
50
+ }
51
+ }
52
+
53
+ /**
54
+ * PATCH /api/items/[collection]/[id]
55
+ * Update an existing item
56
+ */
57
+ export async function PATCH(
58
+ request: NextRequest,
59
+ { params }: RouteParams
60
+ ) {
61
+ try {
62
+ const { collection, id } = await params;
63
+ const headers = await getAuthHeaders();
64
+ const daasUrl = getDaasUrl();
65
+ const body = await request.json();
66
+
67
+ const response = await fetch(`${daasUrl}/api/items/${collection}/${id}`, {
68
+ method: 'PATCH',
69
+ headers,
70
+ body: JSON.stringify(body),
71
+ });
72
+
73
+ if (!response.ok) {
74
+ const error = await response.json().catch(() => ({ errors: [{ message: 'Request failed' }] }));
75
+ return NextResponse.json(error, { status: response.status });
76
+ }
77
+
78
+ const data = await response.json();
79
+ return NextResponse.json(data);
80
+ } catch (error) {
81
+ console.error('Items PATCH error:', error);
82
+ return NextResponse.json(
83
+ { errors: [{ message: error instanceof Error ? error.message : 'Internal server error' }] },
84
+ { status: 500 }
85
+ );
86
+ }
87
+ }
88
+
89
+ /**
90
+ * DELETE /api/items/[collection]/[id]
91
+ * Delete an item
92
+ */
93
+ export async function DELETE(
94
+ request: NextRequest,
95
+ { params }: RouteParams
96
+ ) {
97
+ try {
98
+ const { collection, id } = await params;
99
+ const headers = await getAuthHeaders();
100
+ const daasUrl = getDaasUrl();
101
+
102
+ const response = await fetch(`${daasUrl}/api/items/${collection}/${id}`, {
103
+ method: 'DELETE',
104
+ headers,
105
+ });
106
+
107
+ if (!response.ok) {
108
+ const error = await response.json().catch(() => ({ errors: [{ message: 'Request failed' }] }));
109
+ return NextResponse.json(error, { status: response.status });
110
+ }
111
+
112
+ return NextResponse.json({ data: null });
113
+ } catch (error) {
114
+ console.error('Items DELETE error:', error);
115
+ return NextResponse.json(
116
+ { errors: [{ message: error instanceof Error ? error.message : 'Internal server error' }] },
117
+ { status: 500 }
118
+ );
119
+ }
120
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Items Collection API Route
3
+ *
4
+ * Proxies CRUD operations for collection items to the DaaS backend.
5
+ * Supports Directus-compatible query parameters.
6
+ *
7
+ * @microbuild/origin: api-routes/items
8
+ * @microbuild/version: 1.0.0
9
+ */
10
+
11
+ import { NextRequest, NextResponse } from 'next/server';
12
+ import { getAuthHeaders, getDaasUrl } from '@/lib/api/auth-headers';
13
+
14
+ type RouteParams = { params: Promise<{ collection: string }> };
15
+
16
+ /**
17
+ * GET /api/items/[collection]
18
+ * List items with optional filtering, sorting, and pagination
19
+ */
20
+ export async function GET(
21
+ request: NextRequest,
22
+ { params }: RouteParams
23
+ ) {
24
+ try {
25
+ const { collection } = await params;
26
+ const headers = await getAuthHeaders();
27
+ const daasUrl = getDaasUrl();
28
+
29
+ // Forward all query parameters
30
+ const searchParams = request.nextUrl.searchParams.toString();
31
+ const url = `${daasUrl}/api/items/${collection}${searchParams ? `?${searchParams}` : ''}`;
32
+
33
+ const response = await fetch(url, {
34
+ headers,
35
+ cache: 'no-store',
36
+ });
37
+
38
+ if (!response.ok) {
39
+ const error = await response.json().catch(() => ({ errors: [{ message: 'Request failed' }] }));
40
+ return NextResponse.json(error, { status: response.status });
41
+ }
42
+
43
+ const data = await response.json();
44
+ return NextResponse.json(data);
45
+ } catch (error) {
46
+ console.error('Items GET error:', error);
47
+ return NextResponse.json(
48
+ { errors: [{ message: error instanceof Error ? error.message : 'Internal server error' }] },
49
+ { status: 500 }
50
+ );
51
+ }
52
+ }
53
+
54
+ /**
55
+ * POST /api/items/[collection]
56
+ * Create a new item
57
+ */
58
+ export async function POST(
59
+ request: NextRequest,
60
+ { params }: RouteParams
61
+ ) {
62
+ try {
63
+ const { collection } = await params;
64
+ const headers = await getAuthHeaders();
65
+ const daasUrl = getDaasUrl();
66
+ const body = await request.json();
67
+
68
+ const response = await fetch(`${daasUrl}/api/items/${collection}`, {
69
+ method: 'POST',
70
+ headers,
71
+ body: JSON.stringify(body),
72
+ });
73
+
74
+ if (!response.ok) {
75
+ const error = await response.json().catch(() => ({ errors: [{ message: 'Request failed' }] }));
76
+ return NextResponse.json(error, { status: response.status });
77
+ }
78
+
79
+ const data = await response.json();
80
+ return NextResponse.json(data);
81
+ } catch (error) {
82
+ console.error('Items POST error:', error);
83
+ return NextResponse.json(
84
+ { errors: [{ message: error instanceof Error ? error.message : 'Internal server error' }] },
85
+ { status: 500 }
86
+ );
87
+ }
88
+ }