@seo-console/package 1.0.3 → 1.0.4
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 +111 -38
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,31 +29,37 @@ NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
|
|
|
29
29
|
|
|
30
30
|
The package will automatically detect and use Supabase if these are set.
|
|
31
31
|
|
|
32
|
-
### Step 2: Create API Routes
|
|
32
|
+
### Step 2: Create API Routes (REQUIRED - This is why you're getting 404 errors!)
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
**⚠️ CRITICAL:** The package does NOT include API routes. You MUST create them in your Next.js app. The 404 error you're seeing means the API route doesn't exist yet.
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
**Create `app/api/seo-records/route.ts`:**
|
|
37
37
|
|
|
38
38
|
```typescript
|
|
39
39
|
import { NextRequest, NextResponse } from "next/server";
|
|
40
|
-
import {
|
|
41
|
-
|
|
42
|
-
getSEORecordByRoute,
|
|
43
|
-
createSEORecord,
|
|
44
|
-
updateSEORecord,
|
|
45
|
-
deleteSEORecord
|
|
46
|
-
} from "@seo-console/package/server";
|
|
40
|
+
import { detectStorageConfig, createStorageAdapter } from "@seo-console/package";
|
|
41
|
+
import { createSEORecordSchema } from "@seo-console/package/server";
|
|
47
42
|
|
|
48
43
|
// GET - Fetch all SEO records
|
|
49
44
|
export async function GET() {
|
|
50
45
|
try {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
46
|
+
// Auto-detect storage type (file or Supabase)
|
|
47
|
+
const config = detectStorageConfig();
|
|
48
|
+
const storage = createStorageAdapter(config);
|
|
49
|
+
|
|
50
|
+
// Check if storage is available
|
|
51
|
+
const isAvailable = await storage.isAvailable();
|
|
52
|
+
if (!isAvailable) {
|
|
53
|
+
return NextResponse.json(
|
|
54
|
+
{ error: "Storage not available" },
|
|
55
|
+
{ status: 500 }
|
|
56
|
+
);
|
|
54
57
|
}
|
|
55
|
-
|
|
58
|
+
|
|
59
|
+
const records = await storage.getRecords();
|
|
60
|
+
return NextResponse.json({ data: records || [] });
|
|
56
61
|
} catch (error) {
|
|
62
|
+
console.error("Error fetching SEO records:", error);
|
|
57
63
|
return NextResponse.json(
|
|
58
64
|
{ error: error instanceof Error ? error.message : "Failed to fetch records" },
|
|
59
65
|
{ status: 500 }
|
|
@@ -65,48 +71,111 @@ export async function GET() {
|
|
|
65
71
|
export async function POST(request: NextRequest) {
|
|
66
72
|
try {
|
|
67
73
|
const body = await request.json();
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
|
|
75
|
+
// Validate the request body
|
|
76
|
+
const validated = createSEORecordSchema.parse(body);
|
|
77
|
+
|
|
78
|
+
// Auto-detect storage type
|
|
79
|
+
const config = detectStorageConfig();
|
|
80
|
+
const storage = createStorageAdapter(config);
|
|
81
|
+
|
|
82
|
+
const record = await storage.createRecord(validated);
|
|
83
|
+
return NextResponse.json({ data: record }, { status: 201 });
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.error("Error creating SEO record:", error);
|
|
86
|
+
if (error instanceof Error) {
|
|
87
|
+
return NextResponse.json(
|
|
88
|
+
{ error: error.message },
|
|
89
|
+
{ status: 400 }
|
|
90
|
+
);
|
|
71
91
|
}
|
|
72
|
-
return NextResponse.json(
|
|
92
|
+
return NextResponse.json(
|
|
93
|
+
{ error: "Invalid request" },
|
|
94
|
+
{ status: 400 }
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Create `app/api/seo-records/[id]/route.ts`:**
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
104
|
+
import { detectStorageConfig, createStorageAdapter } from "@seo-console/package";
|
|
105
|
+
import { updateSEORecordSchema } from "@seo-console/package/server";
|
|
106
|
+
|
|
107
|
+
interface RouteParams {
|
|
108
|
+
params: Promise<{ id: string }>;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// GET - Get a single SEO record
|
|
112
|
+
export async function GET(
|
|
113
|
+
request: NextRequest,
|
|
114
|
+
{ params }: RouteParams
|
|
115
|
+
) {
|
|
116
|
+
try {
|
|
117
|
+
const { id } = await params;
|
|
118
|
+
const config = detectStorageConfig();
|
|
119
|
+
const storage = createStorageAdapter(config);
|
|
120
|
+
|
|
121
|
+
const record = await storage.getRecordById(id);
|
|
122
|
+
|
|
123
|
+
if (!record) {
|
|
124
|
+
return NextResponse.json(
|
|
125
|
+
{ error: "Record not found" },
|
|
126
|
+
{ status: 404 }
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return NextResponse.json({ data: record });
|
|
73
131
|
} catch (error) {
|
|
74
132
|
return NextResponse.json(
|
|
75
|
-
{ error: error instanceof Error ? error.message : "Failed to
|
|
133
|
+
{ error: error instanceof Error ? error.message : "Failed to fetch record" },
|
|
76
134
|
{ status: 500 }
|
|
77
135
|
);
|
|
78
136
|
}
|
|
79
137
|
}
|
|
80
138
|
|
|
81
|
-
//
|
|
82
|
-
export async function
|
|
139
|
+
// PATCH - Update an SEO record
|
|
140
|
+
export async function PATCH(
|
|
141
|
+
request: NextRequest,
|
|
142
|
+
{ params }: RouteParams
|
|
143
|
+
) {
|
|
83
144
|
try {
|
|
145
|
+
const { id } = await params;
|
|
84
146
|
const body = await request.json();
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
147
|
+
|
|
148
|
+
const validated = updateSEORecordSchema.parse({ ...body, id });
|
|
149
|
+
const config = detectStorageConfig();
|
|
150
|
+
const storage = createStorageAdapter(config);
|
|
151
|
+
|
|
152
|
+
const record = await storage.updateRecord(validated);
|
|
153
|
+
return NextResponse.json({ data: record });
|
|
90
154
|
} catch (error) {
|
|
155
|
+
if (error instanceof Error) {
|
|
156
|
+
return NextResponse.json(
|
|
157
|
+
{ error: error.message },
|
|
158
|
+
{ status: 400 }
|
|
159
|
+
);
|
|
160
|
+
}
|
|
91
161
|
return NextResponse.json(
|
|
92
|
-
{ error:
|
|
93
|
-
{ status:
|
|
162
|
+
{ error: "Invalid request" },
|
|
163
|
+
{ status: 400 }
|
|
94
164
|
);
|
|
95
165
|
}
|
|
96
166
|
}
|
|
97
167
|
|
|
98
168
|
// DELETE - Delete an SEO record
|
|
99
|
-
export async function DELETE(
|
|
169
|
+
export async function DELETE(
|
|
170
|
+
request: NextRequest,
|
|
171
|
+
{ params }: RouteParams
|
|
172
|
+
) {
|
|
100
173
|
try {
|
|
101
|
-
const {
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const result = await deleteSEORecord(id);
|
|
107
|
-
if (!result.success) {
|
|
108
|
-
return NextResponse.json({ error: result.error?.message }, { status: 500 });
|
|
109
|
-
}
|
|
174
|
+
const { id } = await params;
|
|
175
|
+
const config = detectStorageConfig();
|
|
176
|
+
const storage = createStorageAdapter(config);
|
|
177
|
+
|
|
178
|
+
await storage.deleteRecord(id);
|
|
110
179
|
return NextResponse.json({ success: true });
|
|
111
180
|
} catch (error) {
|
|
112
181
|
return NextResponse.json(
|
|
@@ -117,6 +186,10 @@ export async function DELETE(request: NextRequest) {
|
|
|
117
186
|
}
|
|
118
187
|
```
|
|
119
188
|
|
|
189
|
+
> **Important:** These API routes use the storage adapter system, which automatically works with:
|
|
190
|
+
> - **File storage** (default) - if no Supabase credentials are set
|
|
191
|
+
> - **Supabase** - if `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_ANON_KEY` are set
|
|
192
|
+
|
|
120
193
|
### Step 3: Add Admin Pages
|
|
121
194
|
|
|
122
195
|
Create the admin SEO section in your Next.js app. This will be accessible as a new tab in your admin area.
|