#!/usr/bin/env node /** * Idempotent content seeder. * * Reads content.json (same file the frontend bundles as offline fallback) * and creates any record that is missing in PocketBase, identified by its * `uid` field. Existing records are NEVER overwritten — after the first * seed, PocketBase owns the data and content is managed via the admin UI * (admin.greatbear.in). * * Required env: PB_SUPERUSER_EMAIL, PB_SUPERUSER_PASSWORD. Optional: PB_URL. */ import { existsSync, readFileSync } from 'node:fs' import { dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' const here = dirname(fileURLToPath(import.meta.url)) const PB_URL = process.env.PB_URL ?? 'http://127.0.0.1:8090' const EMAIL = process.env.PB_SUPERUSER_EMAIL const PASSWORD = process.env.PB_SUPERUSER_PASSWORD if (!EMAIL || !PASSWORD) { console.error('[seed] PB_SUPERUSER_EMAIL/PB_SUPERUSER_PASSWORD not set — skipping seed') process.exit(0) } // Inside the image content.json sits next to this script; in the repo it lives // with the frontend sources. const contentPath = [join(here, 'content.json'), join(here, '../app/src/data/content.json')].find( (path) => existsSync(path), ) if (!contentPath) { console.error('[seed] content.json not found — nothing to seed') process.exit(1) } const content = JSON.parse(readFileSync(contentPath, 'utf8')) async function auth() { const res = await fetch(`${PB_URL}/api/collections/_superusers/auth-with-password`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ identity: EMAIL, password: PASSWORD }), }) if (!res.ok) throw new Error(`superuser auth failed (HTTP ${res.status})`) const json = await res.json() return json.token } async function ensureRecord(collection, token, item) { const filter = encodeURIComponent(`uid="${item.uid}"`) const found = await fetch( `${PB_URL}/api/collections/${collection}/records?filter=${filter}`, { headers: { Authorization: token } }, ) if (!found.ok) throw new Error(`lookup failed for ${collection}/${item.uid} (HTTP ${found.status})`) const list = await found.json() if (list.items.length > 0) return 'exists' const created = await fetch(`${PB_URL}/api/collections/${collection}/records`, { method: 'POST', headers: { Authorization: token, 'Content-Type': 'application/json' }, body: JSON.stringify(item), }) if (!created.ok) { const body = await created.text() throw new Error(`create failed for ${collection}/${item.uid} (HTTP ${created.status}): ${body}`) } return 'created' } const COLLECTIONS = [ 'settings', 'stats', 'brews', 'experiences', 'testimonials', 'menu_categories', 'menu_items', 'pairings', ] try { const token = await auth() let created = 0 let existing = 0 for (const collection of COLLECTIONS) { const items = Array.isArray(content[collection]) ? content[collection] : content[collection] ? [content[collection]] : [] for (const item of items) { const result = await ensureRecord(collection, token, item) if (result === 'created') created++ else existing++ } } console.log(`[seed] done: ${created} created, ${existing} already present`) } catch (error) { console.error(`[seed] failed: ${error.message}`) process.exit(1) }