export type BarterLane = "goods" | "services" | "data" | "open"; export type BarterListing = { id: string; author: string; title: string; /** What the poster brings to the table */ have: string; /** What they want back (goods, labor, crypto, favor, etc.) */ want: string; lane: BarterLane; body: string; ts: number; }; const KEY = "cyberlux-barter-v1"; function uid(): string { if (typeof crypto !== "undefined" && "randomUUID" in crypto) return crypto.randomUUID(); return `b_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`; } const seeds: BarterListing[] = [ { id: "barter-seed-1", author: "relay_op", title: "Entropy dongles → signed opsec consult", have: "Two hardware RNG sticks, sealed.", want: "2h walkthrough on compartmentalized laptop setup (signals only).", lane: "services", body: "No clearnet video. Text + voice on agreed onion comms. PGP on first ping.", ts: Date.now() - 7200000 * 10, }, { id: "barter-seed-2", author: "ledger_moth", title: "Monero for physical dead-tree cipher zines", have: "XMR at spot-ish — negotiate in-thread.", want: "High-res scans of 80s crypto zines, OCR optional.", lane: "goods", body: "Escrow via hub USD balance after Bitcoin verify, or agree plaintext terms in-thread.", ts: Date.now() - 7200000 * 6, }, { id: "barter-seed-3", author: "patchbay_7", title: "Studio time ↔ exploit courseware slides", have: "4h mixing desk + mastering chain on airgapped DAW session (training scenario).", want: "De-weaponized slide deck on heap grooming for class (no live targets).", lane: "data", body: "You send PDF, I send stems. Both sides verify hashes before swap.", ts: Date.now() - 7200000 * 3, }, { id: "barter-seed-4", author: "EU_shift", title: "Shipping label templates → mirror canary text", have: "Sanitized HTML snippets that look like phish (for training).", want: "Latest signed canary paragraph from hub ring — compare byte-for-byte.", lane: "open", body: "Teaching red-team vs blue-team reading. No live credential harvesting.", ts: Date.now() - 7200000 * 2, }, { id: "barter-seed-5", author: "void_cartographer", title: "Physical meet token ↔ CPU time", have: "Laser-cut acrylic ‘proof of attendance’ tokens (larp).", want: "Someone to crunch log anonymization on an offline CSV (class data).", lane: "services", body: "Coordinate only through your institution’s lab policy — this board is data, not logistics.", ts: Date.now() - 7200000 * 14, }, ]; export function loadBarter(): BarterListing[] { if (typeof window === "undefined") return seeds; try { const raw = localStorage.getItem(KEY); if (!raw) { saveBarter(seeds); return seeds; } const v = JSON.parse(raw) as BarterListing[]; if (!Array.isArray(v) || !v.length) { saveBarter(seeds); return seeds; } return v; } catch { return seeds; } } export function saveBarter(list: BarterListing[]): void { if (typeof window === "undefined") return; localStorage.setItem(KEY, JSON.stringify(list)); } const SEED_IDS = new Set(seeds.map((s) => s.id)); export function addBarterListing( L: Omit, ): BarterListing { const row: BarterListing = { id: uid(), ts: Date.now(), author: L.author.trim() || "Anonymous", title: L.title.trim(), have: L.have.trim(), want: L.want.trim(), lane: L.lane, body: L.body.trim(), }; const userRows = loadBarter().filter((r) => !SEED_IDS.has(r.id)); saveBarter([row, ...userRows, ...seeds]); return row; }