fix: seed script fails due to missing content field

The seed script fetches from /prompts.json without the ?full_content=true
parameter. The API only returns contentPreview by default, so the content
field is undefined, causing PrismaClientValidationError for every prompt.

Changes:
- Add ?full_content=true to the fetch URL
- Make content optional in RemotePrompt interface
- Skip prompts without content instead of failing

Before: Created 0 prompts (1595 skipped) with validation errors
After: Created 1576 prompts (19 skipped - no content)
This commit is contained in:
Aldo Jimenez
2026-03-29 19:10:49 -04:00
parent 41e4a95556
commit e4686cb9ee

View File

@@ -3,14 +3,15 @@ import bcrypt from "bcryptjs";
const prisma = new PrismaClient();
const PROMPTS_JSON_URL = "https://prompts.chat/prompts.json";
const PROMPTS_JSON_URL = "https://prompts.chat/prompts.json?full_content=true";
interface RemotePrompt {
/** Raw shape returned by the remote API — content may be absent. */
interface RemotePromptRaw {
id: string;
title: string;
slug: string;
description: string | null;
content: string;
content?: string;
type: string;
structuredFormat: string | null;
mediaUrl: string | null;
@@ -52,11 +53,20 @@ interface RemotePrompt {
}>;
}
interface RemotePromptsResponse {
count: number;
prompts: RemotePrompt[];
/** Validated prompt with required content field. */
type RemotePrompt = RemotePromptRaw & { content: string };
/** Type guard that narrows a raw API prompt to a validated RemotePrompt. */
function hasContent(prompt: RemotePromptRaw): prompt is RemotePrompt {
return typeof prompt.content === "string" && prompt.content.length > 0;
}
interface RemotePromptsResponse {
count: number;
prompts: RemotePromptRaw[];
}
/** Fetches all prompts from the remote prompts.chat API with full content. */
async function fetchPrompts(): Promise<RemotePromptsResponse> {
console.log(`📡 Fetching prompts from ${PROMPTS_JSON_URL}...`);
const response = await fetch(PROMPTS_JSON_URL);
@@ -68,12 +78,13 @@ async function fetchPrompts(): Promise<RemotePromptsResponse> {
return data;
}
/** Seeds the database with users, categories, tags, and prompts from prompts.chat. */
async function main() {
console.log("🌱 Seeding database from prompts.chat...");
// Create admin user for assigning prompts
const password = await bcrypt.hash("password123", 12);
const admin = await prisma.user.upsert({
where: { email: "admin@prompts.chat" },
update: {},
@@ -174,7 +185,7 @@ async function main() {
userIdMap.set(username, admin.id);
continue;
}
const user = await prisma.user.upsert({
where: { username },
update: { name: author.name, avatar: author.avatar },
@@ -225,6 +236,13 @@ async function main() {
};
const structuredFormat = remotePrompt.structuredFormat ? formatMap[remotePrompt.structuredFormat] : null;
// Skip prompts without content
if (!hasContent(remotePrompt)) {
console.warn(`⚠ Skipping prompt "${remotePrompt.title}" - no content`);
promptsSkipped++;
continue;
}
// Check if prompt already exists
const existingPrompt = await prisma.prompt.findFirst({
where: { slug: remotePrompt.slug },
@@ -280,6 +298,16 @@ async function main() {
}
console.log(`✅ Created ${promptsCreated} prompts (${promptsSkipped} skipped)`);
// Fail-fast if no prompts were created — likely an upstream API regression
const total = promptsCreated + promptsSkipped;
if (total > 0 && promptsCreated === 0) {
throw new Error(
`Seeding failed: 0 prompts created out of ${total} (${promptsSkipped} skipped). ` +
`This likely indicates an upstream API regression — check that ${PROMPTS_JSON_URL} returns content.`
);
}
console.log("\n🎉 Seeding complete!");
console.log("\n📋 Test credentials (password: password123):");
console.log(" Admin: admin@prompts.chat");