tpmjs/sync-hello.ts
Ajax Davis 48c41e8733 feat: add use cases marketing product with AI-generated content
Transform qualifying scenarios into marketing-ready use cases with:
- AI-generated titles, descriptions, ROI estimates, business value
- Persona/industry/category taxonomy for targeting
- Browseable feed with filtering and ranking
- SEO-optimized case study pages
- Daily cron job for generation and ranking

Database:
- Add Persona, Industry, Category lookup tables
- Add UseCase model with marketing content fields
- Add junction tables for personas/industries/categories
- Add SocialProof model for cached metrics

API:
- GET /api/use-cases - Global directory with filtering
- GET /api/use-cases/[id] - Individual use case details
- GET /api/public/users/[username]/collections/[slug]/use-cases
- POST /api/cron/use-cases - Nightly generation job

Frontend:
- /use-cases - Global feed with persona dropdown
- /use-cases/[slug] - SEO case study page
- /[username]/collections/[slug]/use-cases - Collection feed
- UseCasesFeed component - Sortable table component
- UseCaseCaseStudy component - Full case study layout
2026-01-20 16:17:35 +10:00

115 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { PrismaClient } from '@prisma/client';
import { validateTpmjsField } from '@tpmjs/types/tpmjs';
const prisma = new PrismaClient();
async function syncHello() {
try {
console.log('Fetching @tpmjs/hello from npm...');
const response = await fetch('https://registry.npmjs.org/@tpmjs/hello');
const data = await response.json();
const latest = data['dist-tags'].latest;
const pkg = data.versions[latest];
console.log(`\nPackage: ${pkg.name}@${pkg.version}`);
console.log(`Keywords: ${pkg.keywords.join(', ')}`);
console.log(`\ntpmjs field:`, JSON.stringify(pkg.tpmjs, null, 2));
// Validate
const validation = validateTpmjsField(pkg.tpmjs);
if (!validation.valid) {
console.error('\n❌ Invalid tpmjs field:', validation.errors);
process.exit(1);
}
console.log(`\n✅ Valid tpmjs field (${validation.tier} tier)`);
console.log(`Tools to create: ${validation.tools?.length || 0}`);
// Upsert Package
const packageRecord = await prisma.package.upsert({
where: { npmPackageName: pkg.name },
create: {
npmPackageName: pkg.name,
npmVersion: pkg.version,
npmPublishedAt: new Date(pkg.time[pkg.version]),
npmDownloadsLastMonth: 0,
category: validation.packageData?.category,
env: validation.packageData?.env || null,
frameworks: validation.packageData?.frameworks || [],
tier: validation.tier!,
discoveryMethod: 'manual',
isOfficial: pkg.name.startsWith('@tpmjs/'),
},
update: {
npmVersion: pkg.version,
npmPublishedAt: new Date(pkg.time[pkg.version]),
category: validation.packageData?.category,
env: validation.packageData?.env || null,
frameworks: validation.packageData?.frameworks || [],
tier: validation.tier!,
},
});
console.log(`\n✅ Package upserted: ${packageRecord.id}`);
// Get existing tools
const existingTools = await prisma.tool.findMany({
where: { packageId: packageRecord.id },
});
console.log(`\nExisting tools: ${existingTools.length}`);
// Upsert each tool
for (const toolDef of validation.tools || []) {
const tool = await prisma.tool.upsert({
where: {
packageId_name: {
packageId: packageRecord.id,
name: toolDef.name,
},
},
create: {
packageId: packageRecord.id,
name: toolDef.name,
description: toolDef.description,
parameters: toolDef.parameters ? (toolDef.parameters as any) : undefined,
returns: toolDef.returns ? (toolDef.returns as any) : undefined,
aiAgent: toolDef.aiAgent ? (toolDef.aiAgent as any) : undefined,
qualityScore: null,
},
update: {
description: toolDef.description,
parameters: toolDef.parameters ? (toolDef.parameters as any) : undefined,
returns: toolDef.returns ? (toolDef.returns as any) : undefined,
aiAgent: toolDef.aiAgent ? (toolDef.aiAgent as any) : undefined,
},
});
console.log(`✅ Tool upserted: ${tool.name} (${tool.id})`);
}
// Delete orphaned tools
const orphanedTools = existingTools.filter(
(existingTool) => !validation.tools?.some((toolDef) => toolDef.name === existingTool.name)
);
if (orphanedTools.length > 0) {
await prisma.tool.deleteMany({
where: { id: { in: orphanedTools.map((t) => t.id) } },
});
console.log(`\n🗑 Deleted ${orphanedTools.length} orphaned tools`);
}
console.log('\n✅ Sync complete!');
} catch (error) {
console.error('\n❌ Sync failed:', error);
process.exit(1);
} finally {
await prisma.$disconnect();
}
}
syncHello();