44 lines
1.9 KiB
TypeScript
44 lines
1.9 KiB
TypeScript
/**
|
|
* Import AI/software digest items into ai.news_items (public /trackers/ai news tab).
|
|
* Idempotent: upserts on url (date, title, note and section are overwritten).
|
|
*
|
|
* bun scripts/ai-news-import.ts ai-news.json # upsert
|
|
* bun scripts/ai-news-import.ts --dry-run ai-news.json # validate only
|
|
*
|
|
* JSON: an array of
|
|
* { "date": "2026-10-26", "title": "…", "url": "https://…", "note": "one line", "section": "ai" }
|
|
* section is "ai" or "software" (default "ai"); note may be null or omitted.
|
|
* Uses DB_URL (the app role on prod). On stan-ovh, run it inside the app image, e.g.
|
|
* sudo docker run --rm --network backend --env-file <app env> -v $PWD/ai-news.json:/tmp/in.json:ro \
|
|
* <app image> bun scripts/ai-news-import.ts /tmp/in.json
|
|
* or from the repo with DB_URL pointing at 127.0.0.1:5440 (never echo it).
|
|
*/
|
|
import { readFile } from 'node:fs/promises';
|
|
import { drizzle } from 'drizzle-orm/postgres-js';
|
|
import postgres from 'postgres';
|
|
import { newsFile, upsertNews } from '../src/lib/server/ai-import';
|
|
|
|
const args = process.argv.slice(2);
|
|
const dryRun = args.includes('--dry-run');
|
|
const files = args.filter((a) => !a.startsWith('--'));
|
|
if (files.length !== 1) {
|
|
console.error('usage: bun scripts/ai-news-import.ts [--dry-run] <file.json>');
|
|
process.exit(2);
|
|
}
|
|
const parsed = newsFile.safeParse(JSON.parse(await readFile(files[0], 'utf8')));
|
|
if (!parsed.success) {
|
|
for (const issue of parsed.error.issues.slice(0, 50))
|
|
console.error(`${issue.path.join('.')}: ${issue.message}`);
|
|
process.exit(1);
|
|
}
|
|
console.log(`Valid: ${parsed.data.length} news items`);
|
|
if (dryRun) process.exit(0);
|
|
if (!process.env.DB_URL) throw new Error('DB_URL is required');
|
|
const client = postgres(process.env.DB_URL, { max: 1, onnotice: () => {} });
|
|
try {
|
|
const n = await upsertNews(drizzle({ client }), parsed.data);
|
|
console.log(`Upserted ${n} news items`);
|
|
} finally {
|
|
await client.end();
|
|
}
|