refactor: replace exportName with name throughout codebase
- Update TpmjsToolDefinitionSchema to only use 'name' field - Add 'sandbox' as valid category for sprites tools - Update all package.json files to use 'name' instead of 'exportName' - Update documentation and source files accordingly - Add 11 new sprites tools for sandbox/code-execution
This commit is contained in:
parent
b1dd3371cd
commit
2cd2b10cd0
91 changed files with 4019 additions and 195 deletions
|
|
@ -21,7 +21,7 @@ Load a tool from esm.sh and return its schema
|
|||
```json
|
||||
{
|
||||
"packageName": "firecrawl-aisdk",
|
||||
"exportName": "webSearchTool",
|
||||
"name": "webSearchTool",
|
||||
"version": "0.7.2",
|
||||
"importUrl": "https://esm.sh/firecrawl-aisdk@0.7.2"
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ Load a tool from esm.sh and return its schema
|
|||
{
|
||||
"success": true,
|
||||
"tool": {
|
||||
"exportName": "webSearchTool",
|
||||
"name": "webSearchTool",
|
||||
"description": "Search the web using Firecrawl",
|
||||
"inputSchema": { ... }
|
||||
}
|
||||
|
|
@ -46,7 +46,7 @@ Execute a tool with parameters
|
|||
```json
|
||||
{
|
||||
"packageName": "firecrawl-aisdk",
|
||||
"exportName": "webSearchTool",
|
||||
"name": "webSearchTool",
|
||||
"version": "0.7.2",
|
||||
"params": {
|
||||
"query": "latest AI news"
|
||||
|
|
@ -128,7 +128,7 @@ curl -X POST http://localhost:3001/load-and-describe \
|
|||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"packageName": "@tpmjs/hello",
|
||||
"exportName": "helloWorldTool",
|
||||
"name": "helloWorldTool",
|
||||
"version": "0.1.0"
|
||||
}'
|
||||
```
|
||||
|
|
@ -139,7 +139,7 @@ curl -X POST http://localhost:3001/execute-tool \
|
|||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"packageName": "@tpmjs/hello",
|
||||
"exportName": "helloWorldTool",
|
||||
"name": "helloWorldTool",
|
||||
"version": "0.1.0",
|
||||
"params": {}
|
||||
}'
|
||||
|
|
|
|||
|
|
@ -34,16 +34,16 @@ app.get('/health', (req, res) => {
|
|||
* Returns tool metadata (description, schema) without executing
|
||||
*/
|
||||
app.post('/load-and-describe', async (req, res) => {
|
||||
const { packageName, exportName, version, importUrl } = req.body;
|
||||
const { packageName, name, version, importUrl } = req.body;
|
||||
|
||||
if (!packageName || !exportName || !version) {
|
||||
if (!packageName || !name || !version) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Missing required fields: packageName, exportName, version',
|
||||
error: 'Missing required fields: packageName, name, version',
|
||||
});
|
||||
}
|
||||
|
||||
const cacheKey = `${packageName}::${exportName}`;
|
||||
const cacheKey = `${packageName}::${name}`;
|
||||
|
||||
try {
|
||||
let toolModule;
|
||||
|
|
@ -72,13 +72,13 @@ app.post('/load-and-describe', async (req, res) => {
|
|||
|
||||
// esm.sh returns ES modules, try to get default or named export
|
||||
const module = moduleExports.default || moduleExports;
|
||||
toolModule = module[exportName] || module;
|
||||
toolModule = module[name] || module;
|
||||
|
||||
if (!toolModule) {
|
||||
console.error(`❌ Export "${exportName}" not found. Available:`, Object.keys(module));
|
||||
console.error(`❌ Export "${name}" not found. Available:`, Object.keys(module));
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
error: `Export "${exportName}" not found in module`,
|
||||
error: `Export "${name}" not found in module`,
|
||||
availableExports: Object.keys(module),
|
||||
});
|
||||
}
|
||||
|
|
@ -108,7 +108,7 @@ app.post('/load-and-describe', async (req, res) => {
|
|||
res.json({
|
||||
success: true,
|
||||
tool: {
|
||||
exportName,
|
||||
name,
|
||||
description: toolModule.description,
|
||||
inputSchema: toolModule.inputSchema || toolModule.parameters?.shape || {},
|
||||
},
|
||||
|
|
@ -127,16 +127,16 @@ app.post('/load-and-describe', async (req, res) => {
|
|||
* Execute a dynamically loaded tool with parameters
|
||||
*/
|
||||
app.post('/execute-tool', async (req, res) => {
|
||||
const { packageName, exportName, version, importUrl, params } = req.body;
|
||||
const { packageName, name, version, importUrl, params } = req.body;
|
||||
|
||||
if (!packageName || !exportName || !version) {
|
||||
if (!packageName || !name || !version) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Missing required fields: packageName, exportName, version',
|
||||
error: 'Missing required fields: packageName, name, version',
|
||||
});
|
||||
}
|
||||
|
||||
const cacheKey = `${packageName}::${exportName}`;
|
||||
const cacheKey = `${packageName}::${name}`;
|
||||
const startTime = Date.now();
|
||||
|
||||
try {
|
||||
|
|
@ -151,7 +151,7 @@ app.post('/execute-tool', async (req, res) => {
|
|||
console.log(`📦 Importing for execution: ${url}`);
|
||||
|
||||
const module = await import(url);
|
||||
toolModule = module[exportName];
|
||||
toolModule = module[name];
|
||||
|
||||
if (!toolModule || !toolModule.execute) {
|
||||
return res.status(404).json({
|
||||
|
|
|
|||
|
|
@ -550,9 +550,9 @@ async function executeTool(req: Request): Promise<Response> {
|
|||
Deno.env.set(key, stringValue);
|
||||
|
||||
// ALSO set in Node.js process.env (for npm: imports)
|
||||
// @ts-ignore - process is available in Node.js compatibility mode
|
||||
// @ts-expect-error - process is available in Node.js compatibility mode
|
||||
if (typeof globalThis.process !== 'undefined' && globalThis.process.env) {
|
||||
// @ts-ignore - process.env exists in Node compat mode
|
||||
// @ts-expect-error - process.env exists in Node compat mode
|
||||
globalThis.process.env[key] = stringValue;
|
||||
}
|
||||
|
||||
|
|
@ -782,10 +782,10 @@ async function listExports(req: Request): Promise<Response> {
|
|||
error?: string;
|
||||
}> = [];
|
||||
|
||||
for (const exportName of allExports) {
|
||||
if (exportName === 'default') continue;
|
||||
for (const exportKey of allExports) {
|
||||
if (exportKey === 'default') continue;
|
||||
|
||||
let rawExport = module[exportName];
|
||||
let rawExport = module[exportKey];
|
||||
|
||||
// Check if it's a factory function
|
||||
if (typeof rawExport === 'function' && !rawExport.description && !rawExport.execute) {
|
||||
|
|
@ -809,14 +809,14 @@ async function listExports(req: Request): Promise<Response> {
|
|||
// Check if it's a valid AI SDK tool
|
||||
if (rawExport?.description && rawExport?.execute) {
|
||||
tools.push({
|
||||
name: exportName,
|
||||
name: exportKey,
|
||||
isValidTool: true,
|
||||
description: rawExport.description,
|
||||
});
|
||||
} else if (typeof rawExport === 'object' && rawExport !== null) {
|
||||
// It's an object but not a valid tool - might be a factory that needs specific config
|
||||
tools.push({
|
||||
name: exportName,
|
||||
name: exportKey,
|
||||
isValidTool: false,
|
||||
error: 'Not a valid AI SDK tool (missing description or execute)',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,27 +10,27 @@ interface ToolDetailPageProps {
|
|||
}
|
||||
|
||||
/**
|
||||
* Parse the URL slug to extract package name and optional export name
|
||||
* Parse the URL slug to extract package name and optional tool name
|
||||
*/
|
||||
function parseSlug(slug: string[]): { packageName: string; exportName?: string } {
|
||||
function parseSlug(slug: string[]): { packageName: string; toolName?: string } {
|
||||
// URL-decode slug components (@ comes as %40)
|
||||
const decodedSlug = slug.map((s) => decodeURIComponent(s));
|
||||
|
||||
if (decodedSlug[0]?.startsWith('@')) {
|
||||
// Scoped package: ['@scope', 'package', 'exportName?']
|
||||
// Scoped package: ['@scope', 'package', 'toolName?']
|
||||
const packageName = decodedSlug.slice(0, 2).join('/');
|
||||
const exportName = decodedSlug[2];
|
||||
return { packageName, exportName };
|
||||
const toolName = decodedSlug[2];
|
||||
return { packageName, toolName };
|
||||
}
|
||||
// Unscoped: ['package', 'exportName?']
|
||||
return { packageName: decodedSlug[0] || '', exportName: decodedSlug[1] };
|
||||
// Unscoped: ['package', 'toolName?']
|
||||
return { packageName: decodedSlug[0] || '', toolName: decodedSlug[1] };
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch tool data from database
|
||||
*/
|
||||
async function getTool(slug: string[]): Promise<Tool | null> {
|
||||
const { packageName, exportName } = parseSlug(slug);
|
||||
const { packageName, toolName } = parseSlug(slug);
|
||||
|
||||
if (!packageName) {
|
||||
return null;
|
||||
|
|
@ -49,7 +49,7 @@ async function getTool(slug: string[]): Promise<Tool | null> {
|
|||
const tool = await prisma.tool.findFirst({
|
||||
where: {
|
||||
packageId: pkg.id,
|
||||
...(exportName && { name: exportName }),
|
||||
...(toolName && { name: toolName }),
|
||||
},
|
||||
include: {
|
||||
package: true,
|
||||
|
|
@ -122,9 +122,9 @@ export async function generateMetadata({ params }: ToolDetailPageProps): Promise
|
|||
};
|
||||
}
|
||||
|
||||
const { packageName, exportName } = parseSlug(slug);
|
||||
const ogPath = exportName
|
||||
? `/api/og/tool/${encodeURIComponent(packageName)}/${encodeURIComponent(exportName)}`
|
||||
const { packageName, toolName } = parseSlug(slug);
|
||||
const ogPath = toolName
|
||||
? `/api/og/tool/${encodeURIComponent(packageName)}/${encodeURIComponent(toolName)}`
|
||||
: `/api/og/tool/${encodeURIComponent(packageName)}`;
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -102,41 +102,41 @@ export function normalizePath(path: string): string {
|
|||
}
|
||||
|
||||
/**
|
||||
* Parse tool path to extract package name and export name
|
||||
* Parse tool path to extract package name and tool name
|
||||
*/
|
||||
function parseToolPath(path: string): { packageName: string; exportName?: string } {
|
||||
function parseToolPath(path: string): { packageName: string; toolName?: string } {
|
||||
// Remove /tool/ prefix
|
||||
const segments = path.replace(/^\/tool\//, '').split('/');
|
||||
|
||||
let packageName: string;
|
||||
let exportName: string | undefined;
|
||||
let toolName: string | undefined;
|
||||
|
||||
if (segments[0]?.startsWith('@')) {
|
||||
// Scoped package: @scope/package/export
|
||||
// Scoped package: @scope/package/toolName
|
||||
packageName = segments.slice(0, 2).join('/');
|
||||
exportName = segments[2];
|
||||
toolName = segments[2];
|
||||
} else {
|
||||
// Unscoped: package/export
|
||||
// Unscoped: package/toolName
|
||||
packageName = segments[0] || '';
|
||||
exportName = segments[1];
|
||||
toolName = segments[1];
|
||||
}
|
||||
|
||||
return { packageName, exportName };
|
||||
return { packageName, toolName };
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch tool data from internal API
|
||||
*/
|
||||
async function fetchToolContent(path: string): Promise<PageContent> {
|
||||
const { packageName, exportName } = parseToolPath(path);
|
||||
const { packageName, toolName } = parseToolPath(path);
|
||||
|
||||
// Build API URL
|
||||
const baseUrl = process.env.VERCEL_URL
|
||||
? `https://${process.env.VERCEL_URL}`
|
||||
: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000';
|
||||
|
||||
const apiPath = exportName
|
||||
? `/api/tools/${encodeURIComponent(packageName)}/${encodeURIComponent(exportName)}`
|
||||
const apiPath = toolName
|
||||
? `/api/tools/${encodeURIComponent(packageName)}/${encodeURIComponent(toolName)}`
|
||||
: `/api/tools/${encodeURIComponent(packageName)}`;
|
||||
|
||||
try {
|
||||
|
|
@ -157,11 +157,11 @@ async function fetchToolContent(path: string): Promise<PageContent> {
|
|||
|
||||
return {
|
||||
pageType: 'tool',
|
||||
title: tool.name || exportName || packageName,
|
||||
title: tool.name || toolName || packageName,
|
||||
description: tool.description || `AI tool from ${packageName}`,
|
||||
keywords: [tool.package?.category || 'tool', 'AI', 'npm', packageName],
|
||||
tool: {
|
||||
name: tool.name || exportName || 'Tool',
|
||||
name: tool.name || toolName || 'Tool',
|
||||
packageName: tool.package?.npmPackageName || packageName,
|
||||
category: tool.package?.category || 'other',
|
||||
description: tool.description || '',
|
||||
|
|
@ -175,11 +175,11 @@ async function fetchToolContent(path: string): Promise<PageContent> {
|
|||
// Return basic content on failure
|
||||
return {
|
||||
pageType: 'tool',
|
||||
title: exportName || packageName,
|
||||
title: toolName || packageName,
|
||||
description: `AI tool from ${packageName}`,
|
||||
keywords: ['tool', 'AI', 'npm'],
|
||||
tool: {
|
||||
name: exportName || 'Tool',
|
||||
name: toolName || 'Tool',
|
||||
packageName,
|
||||
category: 'other',
|
||||
description: '',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue