diff --git a/apps/web/scripts/migrate-posts.ts b/apps/web/scripts/migrate-posts.ts deleted file mode 100644 index af5d656..0000000 --- a/apps/web/scripts/migrate-posts.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { getPayload } from "payload"; -import configPromise from "../payload.config"; -import fs from "fs"; -import path from "path"; -import { parseMarkdownToLexical } from "@mintel/payload-ai"; - -function parseMatter(content: string) { - const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/); - if (!match) return { data: {}, content }; - const data: Record = {}; - match[1].split("\n").forEach((line) => { - const [key, ...rest] = line.split(":"); - if (key && rest.length) { - const field = key.trim(); - let val = rest.join(":").trim(); - if (val.startsWith("[")) { - // basic array parsing - data[field] = val - .slice(1, -1) - .split(",") - .map((s) => s.trim().replace(/^["']|["']$/g, "")); - } else { - data[field] = val.replace(/^["']|["']$/g, ""); - } - } - }); - return { data, content: match[2].trim() }; -} - -async function run() { - const payload = await getPayload({ config: configPromise }); - const contentDir = path.join(process.cwd(), "content", "blog"); - const files = fs.readdirSync(contentDir).filter((f) => f.endsWith(".mdx")); - - for (const file of files) { - const filePath = path.join(contentDir, file); - const content = fs.readFileSync(filePath, "utf-8"); - const { data, content: body } = parseMatter(content); - - const slug = file.replace(/\.mdx$/, ""); - console.log(`Migrating ${slug}...`); - - try { - const existing = await payload.find({ - collection: "posts", - where: { slug: { equals: slug } }, - }); - - const lexicalBlocks = parseMarkdownToLexical(body); - const lexicalAST = { - root: { - type: "root", - format: "", - indent: 0, - version: 1, - children: lexicalBlocks, - direction: "ltr", - }, - }; - - // Handle thumbnail mapping - let featuredImageId = null; - if (data.thumbnail) { - try { - // Remove leading slash and find local file - const localPath = path.join( - process.cwd(), - "public", - data.thumbnail.replace(/^\//, ""), - ); - const fileName = path.basename(localPath); - - if (fs.existsSync(localPath)) { - // Check if media already exists in Payload - const existingMedia = await payload.find({ - collection: "media", - where: { filename: { equals: fileName } }, - }); - - if (existingMedia.docs.length > 0) { - featuredImageId = existingMedia.docs[0].id; - } else { - // Upload new media item - const fileData = fs.readFileSync(localPath); - const { size } = fs.statSync(localPath); - - const newMedia = await payload.create({ - collection: "media", - data: { - alt: data.title || fileName, - }, - file: { - data: fileData, - name: fileName, - mimetype: fileName.endsWith(".png") - ? "image/png" - : fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") - ? "image/jpeg" - : "image/webp", - size, - }, - }); - featuredImageId = newMedia.id; - console.log(` ↑ Uploaded thumbnail: ${fileName}`); - } - } - } catch (e) { - console.warn( - ` ⚠ Warning: Could not process thumbnail ${data.thumbnail}`, - ); - } - } - - if (existing.docs.length === 0) { - await payload.create({ - collection: "posts", - data: { - title: data.title || slug, - slug, - description: data.description || "", - date: data.date - ? new Date(data.date).toISOString() - : new Date().toISOString(), - tags: (data.tags || []).map((t: string) => ({ tag: t })), - content: lexicalAST as any, - featuredImage: featuredImageId, - }, - }); - console.log(`✔ Inserted ${slug}`); - } else { - await payload.update({ - collection: "posts", - id: existing.docs[0].id, - data: { - content: lexicalAST as any, - featuredImage: featuredImageId, - }, - }); - console.log(`✔ Updated AST and thumbnail for ${slug}`); - } - } catch (err: any) { - console.error(`✘ FAILED ${slug}: ${err.message}`); - if (err.data?.errors) { - console.error( - ` Validation errors:`, - JSON.stringify(err.data.errors, null, 2), - ); - } - } - } - - console.log("Migration complete."); - process.exit(0); -} - -run().catch(console.error); diff --git a/apps/web/scripts/seed-blog-posts.ts b/apps/web/scripts/seed-blog-posts.ts deleted file mode 100644 index 46cc965..0000000 --- a/apps/web/scripts/seed-blog-posts.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { getPayload } from "payload"; -import configPromise from "../payload.config"; -import fs from "fs"; -import path from "path"; -import { parseMarkdownToLexical } from "@mintel/payload-ai"; - -function extractFrontmatter(content: string) { - const fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/); - if (!fmMatch) return {}; - const fm = fmMatch[1]; - const titleMatch = fm.match(/title:\s*"?([^"\n]+)"?/); - const descMatch = fm.match(/description:\s*"?([^"\n]+)"?/); - const tagsMatch = fm.match(/tags:\s*\[(.*?)\]/); - - return { - title: titleMatch ? titleMatch[1] : "Untitled Draft", - description: descMatch ? descMatch[1] : "No description", - tags: tagsMatch - ? tagsMatch[1].split(",").map((s) => s.trim().replace(/"/g, "")) - : [], - }; -} - -async function run() { - try { - const payload = await getPayload({ config: configPromise }); - console.log("Payload initialized."); - - const draftsDir = path.resolve(process.cwd(), "content/drafts"); - const publicBlogDir = path.resolve(process.cwd(), "public/blog"); - - if (!fs.existsSync(draftsDir)) { - console.log(`Drafts directory not found at ${draftsDir}`); - process.exit(0); - } - - const files = fs.readdirSync(draftsDir).filter((f) => f.endsWith(".md")); - let count = 0; - - for (const file of files) { - console.log(`Processing ${file}...`); - const filePath = path.join(draftsDir, file); - const content = fs.readFileSync(filePath, "utf8"); - - const fm = extractFrontmatter(content); - const lexicalNodes = parseMarkdownToLexical(content); - const lexicalContent = { - root: { - type: "root", - format: "" as const, - indent: 0, - version: 1, - direction: "ltr" as const, - children: lexicalNodes, - }, - }; - - // Upload thumbnail if exists - let featuredImageId = null; - const thumbPath = path.join(publicBlogDir, `${file}.png`); - if (fs.existsSync(thumbPath)) { - console.log(`Uploading thumbnail ${file}.png...`); - const fileData = fs.readFileSync(thumbPath); - const stat = fs.statSync(thumbPath); - - try { - const newMedia = await payload.create({ - collection: "media", - data: { - alt: `Thumbnail for ${fm.title}`, - }, - file: { - data: fileData, - name: `optimized-${file}.png`, - mimetype: "image/png", - size: stat.size, - }, - }); - featuredImageId = newMedia.id; - } catch (e) { - console.log("Failed to upload thumbnail", e); - } - } - - const tagsArray = fm.tags.map((tag) => ({ tag })); - - const slug = fm.title - .toLowerCase() - .replace(/[^a-z0-9]+/g, "-") - .replace(/(^-|-$)/g, "") - .substring(0, 60); - - // Check if already exists - const existing = await payload.find({ - collection: "posts", - where: { slug: { equals: slug } }, - }); - - if (existing.totalDocs === 0) { - await payload.create({ - collection: "posts", - data: { - title: fm.title, - slug: slug, - description: fm.description, - date: new Date().toISOString(), - tags: tagsArray, - featuredImage: featuredImageId, - content: lexicalContent, - _status: "published", - }, - }); - console.log(`Created CMS entry for ${file}.`); - count++; - } else { - console.log(`Post with slug ${slug} already exists. Skipping.`); - } - } - - console.log( - `Migration successful! Added ${count} new optimized posts to the database.`, - ); - process.exit(0); - } catch (e) { - console.error("Migration failed:", e); - process.exit(1); - } -} - -run();