feat: categories seeding script

This commit is contained in:
Zotov Ivan Yuryevich
2026-04-16 21:33:56 +03:00
parent 2aa629baa1
commit e88775a863
19 changed files with 190 additions and 1 deletions

View File

@@ -0,0 +1,171 @@
#!/usr/bin/env node
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const root = path.resolve(__dirname, "..");
const categoriesDir = path.join(root, "src", "content", "categories");
const defaultEndpoint = "http://localhost:1337/graphql";
const endpoint =
process.env.STRAPI_GRAPHQL_URL ??
process.env.PUBLIC_GRAPHQL_URL ??
defaultEndpoint;
const token =
process.env.STRAPI_TOKEN ??
process.env.STRAPI_API_TOKEN ??
process.env.AUTH_TOKEN;
function readCategorySource(slug) {
const filePath = path.join(categoriesDir, `${slug}.json`);
if (!fs.existsSync(filePath)) {
throw new Error(`Missing source file: ${path.relative(root, filePath)}`);
}
return JSON.parse(fs.readFileSync(filePath, "utf8"));
}
function discoverCategorySlugs() {
if (!fs.existsSync(categoriesDir)) {
throw new Error(`Categories directory missing: ${path.relative(root, categoriesDir)}`);
}
const slugs = [];
for (const dirent of fs.readdirSync(categoriesDir, { withFileTypes: true })) {
if (!dirent.isFile() || !dirent.name.endsWith(".json")) continue;
const slug = path.basename(dirent.name, ".json");
const source = readCategorySource(slug);
const { group } = source;
if (group !== "solution" && group !== "service") {
throw new Error(
`Category ${slug} has invalid group "${String(group)}". Expected "solution" or "service".`
);
}
slugs.push(slug);
}
if (slugs.length === 0) {
throw new Error(`No *.json categories in ${path.relative(root, categoriesDir)}`);
}
return slugs;
}
async function gql(query, variables = {}) {
const headers = {
"Content-Type": "application/json",
Accept: "application/graphql-response+json, application/json",
};
if (token) {
headers.Authorization = `Bearer ${token}`;
}
const response = await fetch(endpoint, {
method: "POST",
headers,
body: JSON.stringify({ query, variables }),
});
if (!response.ok) {
throw new Error(`GraphQL HTTP ${response.status}: ${response.statusText}`);
}
const payload = await response.json();
if (payload.errors?.length) {
const messages = payload.errors.map((err) => err.message).join("; ");
throw new Error(`GraphQL error: ${messages}`);
}
return payload.data;
}
async function categoryExists(slug) {
const query = `
query CategoryBySlug($slug: String!) {
categories(filters: { slug: { eq: $slug } }, pagination: { limit: 1 }) {
documentId
}
}
`;
const data = await gql(query, { slug });
return Array.isArray(data?.categories) && data.categories.length > 0;
}
async function createCategory(input) {
const mutation = `
mutation CreateCategory($data: CategoryInput!) {
createCategory(data: $data) {
documentId
slug
title
group
}
}
`;
const data = await gql(mutation, { data: input });
return data?.createCategory;
}
async function seedCategories(slugs) {
let createdCount = 0;
let skippedCount = 0;
for (const slug of slugs) {
const source = readCategorySource(slug);
const { title, description = "", group } = source;
if (group !== "solution" && group !== "service") {
throw new Error(
`Category ${slug} has invalid group "${String(group)}". Expected "solution" or "service".`
);
}
if (await categoryExists(slug)) {
skippedCount += 1;
console.log(`SKIP ${slug} (already exists)`);
continue;
}
const created = await createCategory({
slug,
title,
description,
group,
});
createdCount += 1;
console.log(
`CREATE ${created.slug} -> ${created.title} [group=${created.group}]`
);
}
return { createdCount, skippedCount };
}
async function main() {
console.log(`Seeding categories to ${endpoint}`);
if (!token) {
console.warn(
"No STRAPI token provided. If endpoint is protected, set STRAPI_TOKEN."
);
}
const slugs = discoverCategorySlugs();
const { createdCount, skippedCount } = await seedCategories(slugs);
console.log(
`Done. created=${createdCount}, skipped=${skippedCount}, total=${createdCount + skippedCount}`
);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});