feat(types): add comprehensive TPMJS field schemas with validation
- Add @tpmjs/types/tpmjs module with minimal and rich tier schemas - Define 12 valid tool categories (web-scraping, api-integration, etc.) - Add schemas for parameters, returns, authentication, pricing, links - Implement validateTpmjsField() with automatic tier detection - Add type guards (isTpmjsMinimal, isTpmjsRich) - Support optional rich fields: frameworks, aiAgent, status, tags Validation features: - Minimal tier: category, description (20-500 chars), example (10+ chars) - Rich tier: adds parameters, returns, auth, pricing, frameworks, etc. - Auto-detects tier based on presence of rich fields - Comprehensive error messages with Zod Export configuration: - Added ./tpmjs export to package.json - Updated tsup.config.ts entry points - Built and type-checked successfully 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
3ae9ced6fa
commit
1a86036ace
3 changed files with 205 additions and 1 deletions
|
|
@ -10,6 +10,10 @@
|
|||
"./registry": {
|
||||
"types": "./dist/registry.d.ts",
|
||||
"default": "./dist/registry.js"
|
||||
},
|
||||
"./tpmjs": {
|
||||
"types": "./dist/tpmjs.d.ts",
|
||||
"default": "./dist/tpmjs.js"
|
||||
}
|
||||
},
|
||||
"files": ["dist"],
|
||||
|
|
|
|||
200
packages/types/src/tpmjs.ts
Normal file
200
packages/types/src/tpmjs.ts
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
/**
|
||||
* Valid tool categories for TPMJS registry
|
||||
*/
|
||||
export const TPMJS_CATEGORIES = [
|
||||
'web-scraping',
|
||||
'data-processing',
|
||||
'file-operations',
|
||||
'communication',
|
||||
'database',
|
||||
'api-integration',
|
||||
'image-processing',
|
||||
'text-analysis',
|
||||
'automation',
|
||||
'ai-ml',
|
||||
'security',
|
||||
'monitoring',
|
||||
] as const;
|
||||
|
||||
export type TpmjsCategory = (typeof TPMJS_CATEGORIES)[number];
|
||||
|
||||
/**
|
||||
* Tool parameter schema
|
||||
*/
|
||||
export const TpmjsParameterSchema = z.object({
|
||||
name: z.string().min(1),
|
||||
type: z.string().min(1),
|
||||
description: z.string().min(1),
|
||||
required: z.boolean().default(false),
|
||||
default: z.unknown().optional(),
|
||||
});
|
||||
|
||||
export type TpmjsParameter = z.infer<typeof TpmjsParameterSchema>;
|
||||
|
||||
/**
|
||||
* Return value schema
|
||||
*/
|
||||
export const TpmjsReturnsSchema = z.object({
|
||||
type: z.string().min(1),
|
||||
description: z.string().min(1),
|
||||
});
|
||||
|
||||
export type TpmjsReturns = z.infer<typeof TpmjsReturnsSchema>;
|
||||
|
||||
/**
|
||||
* Authentication configuration schema
|
||||
*/
|
||||
export const TpmjsAuthenticationSchema = z.object({
|
||||
required: z.boolean(),
|
||||
type: z.enum(['api-key', 'oauth', 'basic-auth', 'custom']),
|
||||
envVar: z.string().optional(),
|
||||
docsUrl: z.string().url().optional(),
|
||||
});
|
||||
|
||||
export type TpmjsAuthentication = z.infer<typeof TpmjsAuthenticationSchema>;
|
||||
|
||||
/**
|
||||
* Pricing information schema
|
||||
*/
|
||||
export const TpmjsPricingSchema = z.object({
|
||||
model: z.enum(['free', 'freemium', 'paid', 'enterprise']),
|
||||
freeLimit: z.string().optional(),
|
||||
paidUrl: z.string().url().optional(),
|
||||
});
|
||||
|
||||
export type TpmjsPricing = z.infer<typeof TpmjsPricingSchema>;
|
||||
|
||||
/**
|
||||
* External links schema
|
||||
*/
|
||||
export const TpmjsLinksSchema = z.object({
|
||||
documentation: z.string().url().optional(),
|
||||
playground: z.string().url().optional(),
|
||||
repository: z.string().url().optional(),
|
||||
homepage: z.string().url().optional(),
|
||||
});
|
||||
|
||||
export type TpmjsLinks = z.infer<typeof TpmjsLinksSchema>;
|
||||
|
||||
/**
|
||||
* AI Agent guidance schema
|
||||
*/
|
||||
export const TpmjsAiAgentSchema = z.object({
|
||||
useCase: z.string().min(10),
|
||||
limitations: z.string().optional(),
|
||||
examples: z.array(z.string()).optional(),
|
||||
});
|
||||
|
||||
export type TpmjsAiAgent = z.infer<typeof TpmjsAiAgentSchema>;
|
||||
|
||||
/**
|
||||
* Minimal tier schema - required fields only
|
||||
* This is the minimum required to publish a tool to TPMJS
|
||||
*/
|
||||
export const TpmjsMinimalSchema = z.object({
|
||||
category: z.enum(TPMJS_CATEGORIES, {
|
||||
errorMap: () => ({
|
||||
message: `Category must be one of: ${TPMJS_CATEGORIES.join(', ')}`,
|
||||
}),
|
||||
}),
|
||||
description: z.string().min(20, 'Description must be at least 20 characters').max(500),
|
||||
example: z.string().min(10, 'Example must be at least 10 characters'),
|
||||
});
|
||||
|
||||
export type TpmjsMinimal = z.infer<typeof TpmjsMinimalSchema>;
|
||||
|
||||
/**
|
||||
* Rich tier schema - includes optional enhanced metadata
|
||||
* Tools with these fields get better visibility and quality scores
|
||||
*/
|
||||
export const TpmjsRichSchema = TpmjsMinimalSchema.extend({
|
||||
parameters: z.array(TpmjsParameterSchema).optional(),
|
||||
returns: TpmjsReturnsSchema.optional(),
|
||||
authentication: TpmjsAuthenticationSchema.optional(),
|
||||
pricing: TpmjsPricingSchema.optional(),
|
||||
frameworks: z
|
||||
.array(z.enum(['vercel-ai', 'langchain', 'llamaindex', 'haystack', 'semantic-kernel']))
|
||||
.optional(),
|
||||
links: TpmjsLinksSchema.optional(),
|
||||
tags: z.array(z.string().min(2).max(30)).max(10).optional(),
|
||||
status: z.enum(['experimental', 'beta', 'stable', 'deprecated']).optional(),
|
||||
aiAgent: TpmjsAiAgentSchema.optional(),
|
||||
});
|
||||
|
||||
export type TpmjsRich = z.infer<typeof TpmjsRichSchema>;
|
||||
|
||||
/**
|
||||
* Union type for either tier
|
||||
*/
|
||||
export type TpmjsField = TpmjsMinimal | TpmjsRich;
|
||||
|
||||
/**
|
||||
* Validation result type
|
||||
*/
|
||||
export interface ValidationResult {
|
||||
valid: boolean;
|
||||
tier: 'minimal' | 'rich' | null;
|
||||
data?: TpmjsField;
|
||||
errors?: z.ZodError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a tpmjs field and determines its tier
|
||||
*/
|
||||
export function validateTpmjsField(tpmjs: unknown): ValidationResult {
|
||||
// Try rich tier first
|
||||
const richResult = TpmjsRichSchema.safeParse(tpmjs);
|
||||
if (richResult.success) {
|
||||
// Check if it has any rich-tier fields
|
||||
const data = richResult.data;
|
||||
const hasRichFields =
|
||||
data.parameters ||
|
||||
data.returns ||
|
||||
data.authentication ||
|
||||
data.pricing ||
|
||||
data.frameworks ||
|
||||
data.links ||
|
||||
data.tags ||
|
||||
data.status ||
|
||||
data.aiAgent;
|
||||
|
||||
return {
|
||||
valid: true,
|
||||
tier: hasRichFields ? 'rich' : 'minimal',
|
||||
data: richResult.data,
|
||||
};
|
||||
}
|
||||
|
||||
// Try minimal tier
|
||||
const minimalResult = TpmjsMinimalSchema.safeParse(tpmjs);
|
||||
if (minimalResult.success) {
|
||||
return {
|
||||
valid: true,
|
||||
tier: 'minimal',
|
||||
data: minimalResult.data,
|
||||
};
|
||||
}
|
||||
|
||||
// Invalid
|
||||
return {
|
||||
valid: false,
|
||||
tier: null,
|
||||
errors: minimalResult.error,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard for minimal tier
|
||||
*/
|
||||
export function isTpmjsMinimal(tpmjs: unknown): tpmjs is TpmjsMinimal {
|
||||
return TpmjsMinimalSchema.safeParse(tpmjs).success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard for rich tier
|
||||
*/
|
||||
export function isTpmjsRich(tpmjs: unknown): tpmjs is TpmjsRich {
|
||||
return TpmjsRichSchema.safeParse(tpmjs).success;
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { defineConfig } from 'tsup';
|
||||
|
||||
export default defineConfig({
|
||||
entry: ['src/tool.ts', 'src/registry.ts'],
|
||||
entry: ['src/tool.ts', 'src/registry.ts', 'src/tpmjs.ts'],
|
||||
format: ['esm'],
|
||||
dts: true,
|
||||
clean: true,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue