fix: update API route to use catch-all pattern for clean URLs

- Rename API route from [slug] to [...slug] for catch-all routing
- Update API handler to join slug segments for scoped packages
- Remove encodeURIComponent from frontend API call

This fixes the 404 error when accessing tool pages with scoped package names.
The sync workers will need to run to populate README data for existing tools.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ajax Davis 2025-11-29 22:57:54 +10:00
parent c52a044b47
commit 5feac0d2db
4 changed files with 68 additions and 4 deletions

View file

@ -6,21 +6,25 @@ export const dynamic = 'force-dynamic';
export const maxDuration = 60;
/**
* GET /api/tools/[slug]
* GET /api/tools/[...slug]
*
* Fetch a single tool by its NPM package name (slug)
* Supports catch-all routing for scoped packages like @tpmjs/text-transformer
*/
export async function GET(
_request: NextRequest,
{ params }: { params: Promise<{ slug: string }> }
{ params }: { params: Promise<{ slug: string[] }> }
): Promise<NextResponse> {
try {
const { slug } = await params;
// Join slug array to reconstruct package name (e.g., ['@tpmjs', 'text-transformer'] -> '@tpmjs/text-transformer')
const packageName = slug.join('/');
// Find the tool by npmPackageName
const tool = await prisma.tool.findUnique({
where: {
npmPackageName: decodeURIComponent(slug),
npmPackageName: packageName,
},
});

View file

@ -89,7 +89,7 @@ export default function ToolDetailPage({
const fetchTool = async () => {
try {
setLoading(true);
const response = await fetch(`/api/tools/${encodeURIComponent(slug)}`);
const response = await fetch(`/api/tools/${slug}`);
const data = await response.json();
if (data.success) {

30
packages/db/check-tool.js Normal file
View file

@ -0,0 +1,30 @@
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
async function main() {
const tool = await prisma.tool.findUnique({
where: { npmPackageName: '@tpmjs/text-transformer' },
select: {
npmPackageName: true,
npmVersion: true,
npmReadme: true,
},
});
if (tool) {
console.log('Tool found:', tool.npmPackageName, tool.npmVersion);
console.log('Has README:', tool.npmReadme ? `Yes (${tool.npmReadme.length} chars)` : 'No');
} else {
console.log('Tool @tpmjs/text-transformer not found in database');
// List all tools to see what's available
const allTools = await prisma.tool.findMany({
select: { npmPackageName: true },
take: 10,
});
console.log('\nAvailable tools:');
allTools.forEach((t) => console.log(' -', t.npmPackageName));
}
}
main().finally(() => prisma.$disconnect());

View file

@ -0,0 +1,30 @@
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
const tool = await prisma.tool.findUnique({
where: { npmPackageName: '@tpmjs/text-transformer' },
select: {
npmPackageName: true,
npmVersion: true,
npmReadme: true,
}
});
if (tool) {
console.log('Tool found:', tool.npmPackageName, tool.npmVersion);
console.log('Has README:', tool.npmReadme ? `Yes (${tool.npmReadme.length} chars)` : 'No');
} else {
console.log('Tool @tpmjs/text-transformer not found in database');
// List all tools to see what's available
const allTools = await prisma.tool.findMany({
select: { npmPackageName: true },
take: 10
});
console.log('\nAvailable tools:');
allTools.forEach(t => console.log(' -', t.npmPackageName));
}
}
main().finally(() => prisma.$disconnect());