refactor: rename exportName to name across entire codebase

- Database: Migrate column export_name to name in tools table
- Prisma schema: Update Tool model to use name field
- Sync routes: Update keyword and changes sync to use name
- Railway executor: Update API endpoints to use name parameter
- API routes: Update all tool routes to use name field
- Web app: Update all pages and components
- Playground: Update tool loader and sidebar
- create-basic-tools: Update types and generators
- Scripts: Update sync and test scripts

Database migration was done via direct SQL:
  ALTER TABLE tools RENAME COLUMN export_name TO name;

The unique constraint remains on (package_id, name).

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ajax Davis 2025-12-17 17:19:21 +10:00
parent 1a1cc36ff0
commit ada3ffb341
44 changed files with 222 additions and 233 deletions

View file

@ -78,7 +78,7 @@ const TPMJS_API_URL = Deno.env.get('TPMJS_API_URL') || 'https://tpmjs.com';
*/
async function reportToolHealth(
packageName: string,
exportName: string,
name: string,
success: boolean,
error?: string
): Promise<void> {
@ -88,7 +88,7 @@ async function reportToolHealth(
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
packageName,
exportName,
name,
success,
error,
}),
@ -96,7 +96,7 @@ async function reportToolHealth(
if (response.ok) {
console.log(
`📊 Health reported for ${packageName}/${exportName}: ${success ? 'SUCCESS' : 'FAILURE'}`
`📊 Health reported for ${packageName}/${name}: ${success ? 'SUCCESS' : 'FAILURE'}`
);
} else {
console.warn(`⚠️ Failed to report health: ${response.status}`);
@ -113,7 +113,7 @@ async function reportToolHealth(
*/
async function updateToolSchema(
packageName: string,
exportName: string,
name: string,
description: string,
// biome-ignore lint/suspicious/noExplicitAny: JSON Schema can have any structure
inputSchema: any
@ -124,7 +124,7 @@ async function updateToolSchema(
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
packageName,
exportName,
name,
description,
inputSchema,
}),
@ -133,7 +133,7 @@ async function updateToolSchema(
if (response.ok) {
const data = await response.json();
console.log(
`📋 Schema updated for ${packageName}/${exportName}:`,
`📋 Schema updated for ${packageName}/${name}:`,
data.updated ? 'UPDATED' : 'NO CHANGE'
);
} else {
@ -216,19 +216,19 @@ function sanitizeJsonSchema(schema: any): any {
async function loadAndDescribe(req: Request): Promise<Response> {
try {
const body = await req.json();
const { packageName, exportName, version, importUrl, env } = body;
const { packageName, name, version, importUrl, env } = body;
if (!packageName || !exportName || !version) {
if (!packageName || !name || !version) {
return Response.json(
{
success: false,
error: 'Missing required fields: packageName, exportName, version',
error: 'Missing required fields: packageName, name, version',
},
{ status: 400 }
);
}
const cacheKey = `${packageName}::${exportName}`;
const cacheKey = `${packageName}::${name}`;
// biome-ignore lint/suspicious/noImplicitAnyLet: Tool type is determined dynamically after import
let toolModule;
@ -244,14 +244,14 @@ async function loadAndDescribe(req: Request): Promise<Response> {
console.log(`📦 Importing: ${url}`);
const module = await import(url);
let rawExport = module[exportName];
let rawExport = module[name];
if (!rawExport) {
console.error(`❌ Export "${exportName}" not found. Available:`, Object.keys(module));
console.error(`❌ Export "${name}" not found. Available:`, Object.keys(module));
return Response.json(
{
success: false,
error: `Export "${exportName}" not found in module`,
error: `Export "${name}" not found in module`,
availableExports: Object.keys(module),
},
{ status: 404 }
@ -266,7 +266,7 @@ async function loadAndDescribe(req: Request): Promise<Response> {
// Strategy 1: Try calling with no arguments
try {
console.log(` Trying: ${exportName}()`);
console.log(` Trying: ${name}()`);
factoryResult = rawExport();
if (factoryResult?.description && factoryResult?.execute) {
console.log(' ✅ Success with no-args factory');
@ -300,7 +300,7 @@ async function loadAndDescribe(req: Request): Promise<Response> {
// Try each config variation
for (const config of configVariations) {
try {
console.log(` Trying: ${exportName}(`, Object.keys(config), ')');
console.log(` Trying: ${name}(`, Object.keys(config), ')');
factoryResult = rawExport(config);
if (factoryResult?.description && factoryResult?.execute) {
console.log(' ✅ Success with config:', Object.keys(config));
@ -318,7 +318,7 @@ async function loadAndDescribe(req: Request): Promise<Response> {
try {
const firstValue = Object.values(env)[0];
if (firstValue) {
console.log(` Trying: ${exportName}(firstEnvValue)`);
console.log(` Trying: ${name}(firstEnvValue)`);
factoryResult = rawExport(firstValue);
if (factoryResult?.description && factoryResult?.execute) {
console.log(' ✅ Success with single-arg factory');
@ -336,7 +336,7 @@ async function loadAndDescribe(req: Request): Promise<Response> {
return Response.json(
{
success: false,
error: `Tool "${exportName}" is a factory function but couldn't be initialized. Tried: no-args, config object, and single-arg patterns.`,
error: `Tool "${name}" is a factory function but couldn't be initialized. Tried: no-args, config object, and single-arg patterns.`,
hint: 'This tool may require specific configuration. Check package documentation.',
},
{ status: 400 }
@ -436,7 +436,7 @@ async function loadAndDescribe(req: Request): Promise<Response> {
return Response.json(
{
success: false,
error: `Tool "${exportName}" has no valid inputSchema. Tools must use AI SDK jsonSchema(), Zod v4 toJSONSchema(), or Zod v3 schemas.`,
error: `Tool "${name}" has no valid inputSchema. Tools must use AI SDK jsonSchema(), Zod v4 toJSONSchema(), or Zod v3 schemas.`,
debug: {
hasInputSchema: !!toolModule.inputSchema,
availableMethods: toolModule.inputSchema ? Object.keys(toolModule.inputSchema) : [],
@ -453,16 +453,14 @@ async function loadAndDescribe(req: Request): Promise<Response> {
const sanitizedSchema = sanitizeJsonSchema(rawJsonSchema);
// Update TPM.js database with the schema (async, non-blocking)
updateToolSchema(packageName, exportName, toolModule.description, sanitizedSchema).catch(
(err) => {
console.warn('⚠️ Failed to update schema in database:', err);
}
);
updateToolSchema(packageName, name, toolModule.description, sanitizedSchema).catch((err) => {
console.warn('⚠️ Failed to update schema in database:', err);
});
return Response.json({
success: true,
tool: {
exportName,
name,
description: toolModule.description,
inputSchema: sanitizedSchema, // Plain JSON Schema - fully serializable
},
@ -486,32 +484,32 @@ async function executeTool(req: Request): Promise<Response> {
const startTime = Date.now();
// Declare these before try block so they're available in catch for error reporting
let packageName = 'unknown';
let exportName = 'unknown';
let toolName = 'unknown';
try {
const body = await req.json();
const { packageName: pkg, exportName: exp, version, importUrl, params, env } = body;
const { packageName: pkg, name, version, importUrl, params, env } = body;
packageName = pkg || 'unknown';
exportName = exp || 'unknown';
toolName = name || 'unknown';
console.log('📥 Execute request:', {
packageName,
exportName,
name: toolName,
version,
envKeys: env ? Object.keys(env) : [],
envValues: env || {},
});
if (!packageName || !exportName || !version) {
if (!packageName || !toolName || !version) {
return Response.json(
{
success: false,
error: 'Missing required fields: packageName, exportName, version',
error: 'Missing required fields: packageName, name, version',
},
{ status: 400 }
);
}
const cacheKey = `${packageName}::${exportName}`;
const cacheKey = `${packageName}::${toolName}`;
// Inject environment variables FIRST - before cache check and factory calls
// This ensures process.env is set when factory functions read from it
@ -561,7 +559,7 @@ async function executeTool(req: Request): Promise<Response> {
console.log(`📦 Importing for execution: ${url}`);
const module = await import(url);
let rawExport = module[exportName];
let rawExport = module[toolName];
if (!rawExport) {
return Response.json(
@ -587,7 +585,7 @@ async function executeTool(req: Request): Promise<Response> {
// Strategy 1: Try calling with no arguments
try {
console.log(` Trying: ${exportName}()`);
console.log(` Trying: ${toolName}()`);
factoryResult = rawExport();
if (factoryResult?.execute) {
console.log(' ✅ Success with no-args factory');
@ -621,7 +619,7 @@ async function executeTool(req: Request): Promise<Response> {
// Try each config variation
for (const config of configVariations) {
try {
console.log(` Trying: ${exportName}(`, Object.keys(config), ')');
console.log(` Trying: ${toolName}(`, Object.keys(config), ')');
factoryResult = rawExport(config);
if (factoryResult?.execute) {
console.log(' ✅ Success with config:', Object.keys(config));
@ -639,7 +637,7 @@ async function executeTool(req: Request): Promise<Response> {
try {
const firstValue = Object.values(env)[0];
if (firstValue) {
console.log(` Trying: ${exportName}(firstEnvValue)`);
console.log(` Trying: ${toolName}(firstEnvValue)`);
factoryResult = rawExport(firstValue);
if (factoryResult?.execute) {
console.log(' ✅ Success with single-arg factory');
@ -655,7 +653,7 @@ async function executeTool(req: Request): Promise<Response> {
return Response.json(
{
success: false,
error: `Tool "${exportName}" is a factory function but couldn't be initialized`,
error: `Tool "${toolName}" is a factory function but couldn't be initialized`,
executionTimeMs: Date.now() - startTime,
},
{ status: 400 }
@ -700,7 +698,7 @@ async function executeTool(req: Request): Promise<Response> {
console.log(`✅ Execution complete in ${executionTimeMs}ms`);
// Report successful execution to health service (non-blocking)
reportToolHealth(packageName, exportName, true).catch(() => {});
reportToolHealth(packageName, toolName, true).catch(() => {});
return Response.json({
success: true,
@ -712,7 +710,7 @@ async function executeTool(req: Request): Promise<Response> {
console.error('❌ Tool execution failed:', error);
// Report failed execution to health service (non-blocking)
reportToolHealth(packageName, exportName, false, error.message).catch(() => {});
reportToolHealth(packageName, toolName, false, error.message).catch(() => {});
return Response.json(
{