Files
dark-lord/lib/barterState.ts
drjones 78a071ba02 Harden onion boot flow and deepen site surfaces
Add persistent onion key backup and restore, improve startup resilience, and flesh out the major site verticals with richer navigation, search coverage, and operator documentation.

Made-with: Cursor
2026-04-07 21:35:52 -07:00

119 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 (fictional amount — negotiate in-thread).",
want: "High-res scans of 80s crypto zines, OCR optional.",
lane: "goods",
body: "Escrow via hub wallet credit only for this sim. Otherwise plaintext terms only.",
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 (fiction).",
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: "Drop coordination fiction only. Real world: use your institutions lab policy.",
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, "id" | "ts">,
): 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;
}