Capture the current CyberLux UI, commerce, messaging, and Tor ops updates so local main can be pushed to the remote. Made-with: Cursor
338 lines
28 KiB
TypeScript
338 lines
28 KiB
TypeScript
/**
|
||
* CyberLux storefront catalog — in-universe listings (see site footer for real-world status).
|
||
*
|
||
* Images: each SKU gets a stable Unsplash URL via `resolveProductImage` (hashed by id).
|
||
* To use your own file: put it in `public/shop-assets/` and set `assetFile: "my-photo.webp"` on that SKU.
|
||
*/
|
||
|
||
import { sellerIdForProduct } from "@/lib/shopSellers";
|
||
|
||
export type ShopCurrency = "BTC" | "ETH" | "USD" | "XMR";
|
||
|
||
export type ShopProduct = {
|
||
id: string;
|
||
name: string;
|
||
description: string;
|
||
price: number;
|
||
currency: ShopCurrency;
|
||
category: string;
|
||
/** Assigned in SHOP_PRODUCTS from sellerIdForProduct — stable per SKU */
|
||
sellerId: string;
|
||
limited?: boolean;
|
||
glowColor?: string;
|
||
/** Drop a file at public/shop-assets/{assetFile} to override the remote image */
|
||
assetFile?: string;
|
||
};
|
||
|
||
/** Unsplash photo paths — royalty-free hotlink; rotate by product id */
|
||
const UNSPLASH_ROTATOR = [
|
||
"photo-1563013544-824ae1b704d3",
|
||
"photo-1553062407-98eeb64c6a62",
|
||
"photo-1523275335684-37898b6baf30",
|
||
"photo-1505740420928-5e560c06d30e",
|
||
"photo-1542291026-7eec264c27ff",
|
||
"photo-1526170375885-4d8ecf77b99f",
|
||
"photo-1518544801979-152483f7e79e",
|
||
"photo-1550751827-4bd374c3f58b",
|
||
"photo-1618005188914-3c8315f33e6f",
|
||
"photo-1558618047-3c8c76ca7d13",
|
||
"photo-1551288049-bebda4e38f71",
|
||
"photo-1635070041078-e363dbe005cb",
|
||
"photo-1517694712202-14dd9538aa97",
|
||
"photo-1526374965328-7f61d4dc18c5",
|
||
"photo-1555949963-aa79dcee981c",
|
||
"photo-1614854262312-209b1c0b2c7b",
|
||
"photo-1592503254549-83d24b4fc4a6",
|
||
"photo-1593359677876-a0bb1c3a8095",
|
||
"photo-1611162616305-c69b3fa7fbe0",
|
||
"photo-1581091226825-a6a2a5aee158",
|
||
"photo-1518770660439-4636190af475",
|
||
"photo-1460925895917-afdab827c52f",
|
||
"photo-1451187580459-43490279c0fa",
|
||
"photo-1582719478250-c89cae4dc85b",
|
||
"photo-1559757148-5c350d0d3c56",
|
||
"photo-1584433144859-1fc3ab64a54f",
|
||
"photo-1512941937669-90a1b58e7e9c",
|
||
"photo-1605812860427-4024433a70fd",
|
||
"photo-1563986768609-322da13575f3",
|
||
"photo-1639762681485-074b7f938ba0",
|
||
] as const;
|
||
|
||
function hashId(id: string): number {
|
||
let h = 0;
|
||
for (let i = 0; i < id.length; i++) h = (h + id.charCodeAt(i) * (i + 1)) % 2147483647;
|
||
return Math.abs(h);
|
||
}
|
||
|
||
/** Remote image URL (internet) or your file under public/shop-assets/ */
|
||
export function resolveProductImage(p: ShopProduct): string {
|
||
if (p.assetFile?.trim()) {
|
||
return `/shop-assets/${p.assetFile.replace(/^\/+/, "")}`;
|
||
}
|
||
const idx = hashId(p.id) % UNSPLASH_ROTATOR.length;
|
||
const path = UNSPLASH_ROTATOR[idx]!;
|
||
return `https://images.unsplash.com/${path}?w=800&q=85&auto=format&fit=crop`;
|
||
}
|
||
|
||
const GLOWS = [
|
||
"neon-cyan",
|
||
"neon-purple",
|
||
"neon-pink",
|
||
"neon-green",
|
||
"neon-yellow",
|
||
"neon-red",
|
||
"neon-blue",
|
||
] as const;
|
||
|
||
type Seed = Omit<ShopProduct, "id" | "glowColor" | "category" | "sellerId"> & { id?: string };
|
||
|
||
type ProductDraft = Omit<ShopProduct, "sellerId">;
|
||
|
||
function block(category: string, items: Seed[]): ProductDraft[] {
|
||
return items.map((raw, j) => {
|
||
const id = raw.id ?? `${category.slice(0, 3)}-${hashId(`${category}-${raw.name}-${j}`).toString(36)}`;
|
||
const { id: _drop, ...rest } = raw;
|
||
return {
|
||
id,
|
||
glowColor: GLOWS[hashId(id) % GLOWS.length],
|
||
...rest,
|
||
category,
|
||
};
|
||
});
|
||
}
|
||
|
||
/** Everything offered in the shop — expand by adding more `block(...)` rows */
|
||
const ALL_BLOCKS: ProductDraft[] = [
|
||
...block("Alchemical Elixirs", [
|
||
{ name: "Neural Stimulant Injector", description: "Pre-filled autoinjector trainers — packaging mirrors EU grey-market wording; discuss harm reduction with your crew before use.", price: 0.085, currency: "BTC", limited: true },
|
||
{ name: "Cognitive patch kit (12h)", description: "Transdermal placebo narrative for discussing FDA vs grey-market copy.", price: 0.019, currency: "XMR" },
|
||
{ name: "Synaptic dampener v2", description: "Plot device for ‘too much focus’ cyberpunk arcs — pure chrome.", price: 0.042, currency: "ETH" },
|
||
{ name: "RNA mimic cream (theatrical)", description: "Salon-grade tub with aggressive RNA branding — parse the ingredient deck before you trust the claims.", price: 124, currency: "USD" },
|
||
{ name: "Dream-state diffuser oil", description: "Diffuser blend marketed for lucid downtime — ships as 30ml amber bottle, COA on request.", price: 0.007, currency: "BTC" },
|
||
{ name: "Circadian hijack glasses", description: "Blue-shift fable hardware — compare to real sleep science slides.", price: 0.011, currency: "ETH" },
|
||
{ name: "Quad-core adrenaline tabs", description: "Press-fit tabs, stim-forward copy — contraindicated if you run hot BP; novelty packaging only where law allows.", price: 0.003, currency: "BTC" },
|
||
{ name: "Empathy rollback serum", description: "Satirical item naming — discuss manipulation in vendor prose.", price: 0.028, currency: "XMR", limited: true },
|
||
{ name: "Vagus nerve tickler wand", description: "Machined aluminum grip, wellness-grade marketing — verify medical claims independently.", price: 89, currency: "USD" },
|
||
{ name: "Mitochondria vanity stack", description: "Stacks-Sigma meme inventory for listing trust workshops.", price: 0.015, currency: "ETH" },
|
||
{ name: "CRISPR cosplay pipette set", description: "Plastic props only; lab safety tangent.", price: 0.008, currency: "BTC" },
|
||
{ name: "Nano-lattice bandage roll", description: "Tactical-wrap roll with lattice weave claims — IFAK-adjacent staging prop.", price: 0.031, currency: "XMR" },
|
||
{ name: "Hormone whisperer lozenges", description: "Wild claims section — annotate red flags.", price: 42, currency: "USD" },
|
||
{ name: "Deep-sleep coffin pod (mini)", description: "Showpiece prop; ergonomics vs marketing photos.", price: 1.12, currency: "BTC", limited: true },
|
||
{ name: "Bio-firewall nasal gel", description: "Saline-forward gel marketed as ‘bio-firewall’ — novelty wellness SKU with aggressive copy.", price: 0.006, currency: "ETH" },
|
||
]),
|
||
...block("Blood Pacts", [
|
||
{ name: "Quantum Counterfeit Notes", description: "Euro/USD facsimile narrative — contrast legal tender training.", price: 1.25, currency: "ETH", limited: true },
|
||
{ name: "Quantum‑Forged Euros brick", description: "UV-reactive novelty brick facsimile — training prop for banknote exam teams.", price: 2.4, currency: "BTC" },
|
||
{ name: "Wash-trade tutorial ledger", description: "Ledger skinsheet pack demonstrating wash arcs — compliance training desks only.", price: 350, currency: "USD" },
|
||
{ name: "Tornado nostalgia mixer tile", description: "Ceramic coaster etched with retro tumbler motif — office lore for chain-hopping traders.", price: 0.018, currency: "XMR" },
|
||
{ name: "Bearer bond hologram folio", description: "Hologram theatre for verifying embossing vs phishing scans.", price: 0.055, currency: "BTC" },
|
||
{ name: "Flash-loan bedtime story PDF", description: "Illustrated DeFi risk fable — onboarding gift for desk traders; watermarked PDF drop.", price: 0.002, currency: "ETH" },
|
||
{ name: "OTC desk stress toy", description: "Squeeze toy shaped like a bid/ask spread arrow.", price: 19, currency: "USD" },
|
||
{ name: "Ponzi pyramid desk lamp", description: "Conversation starter for MLM vs crypto scams.", price: 0.009, currency: "BTC" },
|
||
{ name: "ISO-4217 mood ring set", description: "Currency-code jewelry — macroeconomics icebreaker.", price: 0.014, currency: "ETH" },
|
||
{ name: "Dark-pool goggles (UV)", description: "UV-party wraparounds with liquidity-pool etch — con-floor flex piece.", price: 76, currency: "USD" },
|
||
{ name: "Satoshi séance board", description: "Ouija-but-for-txids gag merch for history-of-Bitcoin week.", price: 0.022, currency: "XMR" },
|
||
{ name: "Rug-pull rip cord keychain", description: "Pull cord plays airhorn.wav — memes in risk lectures.", price: 12, currency: "USD" },
|
||
{ name: "Synthetic stablecoin snow globe", description: "Glitter settles ‘slowly’ — talk peg mechanics.", price: 0.033, currency: "ETH" },
|
||
{ name: "Wire-instructions rubber stamp", description: "Rubber stamp of a phishing wire template — redact exercise.", price: 28, currency: "USD" },
|
||
{ name: "Credit-default swap aromatherapy", description: "Scented candles named after 2008 instruments — dark humor.", price: 0.004, currency: "BTC" },
|
||
]),
|
||
...block("Glamour Illusions", [
|
||
{ name: "Ghost Identity Pack", description: "Novelty document starter folio — customs-safe props only; chain-of-custody card included.", price: 3.8, currency: "BTC", limited: true },
|
||
{ name: "Burner SSN bingo card", description: "Bingo of invalid patterns; teaches checksum thinking.", price: 0.012, currency: "ETH" },
|
||
{ name: "Deepfake voice coupon (fake)", description: "Coupon promising cloned voice — discuss consent frameworks.", price: 54, currency: "USD" },
|
||
{ name: "Rubber face mesh MVP", description: "Theatrical mask — biometrics vs presentation attack discussion.", price: 0.19, currency: "XMR" },
|
||
{ name: "Nom de guerre generator dial", description: "Spinner toy producing alias suggestions — OPSEC naming.", price: 22, currency: "USD" },
|
||
{ name: "PGP key birthday card", description: "Paper card with mini public key block — party trick.", price: 0.005, currency: "BTC" },
|
||
{ name: "SIM-swap panic button (prop)", description: "Big red prop — carrier escalation roleplay.", price: 15, currency: "USD" },
|
||
{ name: "Synthetic genealogy tome", description: "Fake family tree book for social-engineering awareness.", price: 0.041, currency: "ETH" },
|
||
{ name: "Iris-print latte art stencil", description: "Coffee stencil of an iris — biometrics humor.", price: 9, currency: "USD" },
|
||
{ name: "Deadname incinerator USB shell", description: "Empty USB case labeled dramatically — data hygiene talk.", price: 0.017, currency: "XMR" },
|
||
{ name: "Notary cosplay embosser", description: "Manual embosser with comic sans seal — trust UX jokes.", price: 31, currency: "USD" },
|
||
{ name: "Ghost resume parchment", description: "Aged paper stock for redacted CV workshop.", price: 0.008, currency: "BTC" },
|
||
{ name: "Witness protection hoodie", description: "Blank hoodie with detachable name tag — anonymity chat.", price: 0.024, currency: "ETH" },
|
||
{ name: "Forged signature practice pad", description: "Legal-only handwriting exercise pad — anti-fraud angle.", price: 17, currency: "USD" },
|
||
]),
|
||
...block("Ward Enchantments", [
|
||
{ name: "Zero‑Day Exploit Kit (sandbox)", description: "Lab-only PoC bundle narrative — legal use disclaimers printed on sleeve.", price: 12.5, currency: "ETH", limited: true },
|
||
{ name: "Darknet VPN Router", description: "Hardware VLAN folklore; compare to real router hardening checklists.", price: 0.5, currency: "XMR" },
|
||
{ name: "Air-gapped Faraday lunchbox", description: "Metal mesh tin for phones — teaches Faraday basics.", price: 44, currency: "USD" },
|
||
{ name: "EDR evasion board game", description: "Roll dice to patch telemetry — tabletop IR prep.", price: 0.026, currency: "BTC" },
|
||
{ name: "Tor-shaped stress squishy", description: "Slow-rise foam onion — desk lounge swag for relay operators.", price: 11, currency: "USD" },
|
||
{ name: "Memory-safe tea cozy", description: "Knitted cozy labeled ‘no buffer overflows here’.", price: 0.013, currency: "ETH" },
|
||
{ name: "ROP-chain friendship bracelet", description: "Stainless charms stamped with gadget glyphs — wear-stack for con-floor insiders.", price: 7, currency: "USD" },
|
||
{ name: "Purple-team piñata", description: "Filled with paper ‘findings’ slips — team-building prop.", price: 33, currency: "USD" },
|
||
{ name: "Canary token confetti cannon", description: "Party cannon shoots paper canary strings — debut alerting.", price: 0.021, currency: "XMR" },
|
||
{ name: "SIEM-themed scented candle", description: "Smells like ‘log rotation’ — joke SKU for SOC night shift.", price: 18, currency: "USD" },
|
||
{ name: "Firewall prayer candle", description: "Saints of iptables — discuss faith vs config management.", price: 0.004, currency: "BTC" },
|
||
{ name: "Quantum-safe bumper sticker", description: "Bumper sticker pack hyping PQC migration timelines.", price: 0.009, currency: "ETH" },
|
||
{ name: "Bug-bounty bingo night kit", description: "Cards with OWASP categories — socialize triage vocabulary.", price: 26, currency: "USD" },
|
||
{ name: "Yubikey trench coat lining", description: "Sew-in loops for 12 keys — physical key mgmt humor.", price: 0.038, currency: "BTC" },
|
||
{ name: "Password-spray supersoaker (empty)", description: "Bright plastic supersoaker — discuss rate limits metaphorically.", price: 14, currency: "USD" },
|
||
{ name: "Red-team nerf darts (foam)", description: "Foam darts tagged ‘lateral movement’ — safe play fights.", price: 0.006, currency: "XMR" },
|
||
]),
|
||
...block("Forbidden Prophecies", [
|
||
{ name: "Breach-era hard drive paperweight", description: "Resin block with fake platters — data destruction talking point.", price: 0.016, currency: "BTC" },
|
||
{ name: "CSV of emotions (parody)", description: "Joke spreadsheet about feelings — privacy vs oversharing.", price: 3, currency: "USD" },
|
||
{ name: "Anonymized pet photos dataset", description: "Synthetic dog shots, metadata-stripped tarball — ML sandbox starter.", price: 0.011, currency: "ETH" },
|
||
{ name: "Pastebin snowshoes", description: "Foam snowshoes with ‘expiring URL’ stickers — opsec metaphor.", price: 55, currency: "USD" },
|
||
{ name: "Doxxing dodgeball (foam)", description: "Foam stress ball stenciled PII — conference giveaway for privacy talks.", price: 12, currency: "USD" },
|
||
{ name: "Hash-slinging souvenir spatula", description: "Kitchen spatula etched with SHA-256 joke.", price: 0.007, currency: "BTC" },
|
||
{ name: "Journalists’ USB condom charm", description: "Tiny rubber USB blocker on keyring — supply-chain hygiene.", price: 8, currency: "USD" },
|
||
{ name: "DLC for older leaks (empty case)", description: "Empty steel case promising ‘expansion packs’ — hype satire.", price: 0.029, currency: "XMR" },
|
||
{ name: "Redaction marker stadium pack", description: "Black markers labeled for FOIA fantasy workshops.", price: 19, currency: "USD" },
|
||
{ name: "Telemetry piñata (no network)", description: "Offline piñata with paper ‘events’ — logging trivia.", price: 27, currency: "USD" },
|
||
{ name: "GDPR meditation tape", description: "Cassette of white noise labeled ‘right to be forgotten’.", price: 0.005, currency: "ETH" },
|
||
{ name: "Metadata shedding lint roller", description: "Gag lint roller ‘removes EXIF’ — teach real exiftool after.", price: 6, currency: "USD" },
|
||
{ name: "Leak-themed escape room clue pack", description: "Chain-of-custody puzzle cards for escape-room operators — sealed deck.", price: 0.02, currency: "BTC" },
|
||
{ name: "Ransom note magnetic poetry", description: "Fridge magnets of cliché ransom phrases — decrypt jokes.", price: 15, currency: "USD" },
|
||
]),
|
||
...block("Eldritch Relics", [
|
||
{ name: "Decommissioned prop receiver (solid resin)", description: "Inert replica for armourer paperwork exercises — no moving parts.", price: 0.32, currency: "XMR", limited: true },
|
||
{ name: "Orange-tip training carbine (airsoft)", description: "Clear plastic training piece — jurisdiction checklist included.", price: 199, currency: "USD" },
|
||
{ name: "Ballistic gel dessert mold", description: "Silicone mold shaped like gel block — baking + terminal ballistics pun.", price: 24, currency: "USD" },
|
||
{ name: "Blade geometry slide rule", description: "Plastic slide rule for grind angles — metallurgy intro.", price: 0.014, currency: "ETH" },
|
||
{ name: "Non-firing museum rack mount", description: "Wall mount for decommissioned props — discuss secure storage law.", price: 48, currency: "USD" },
|
||
{ name: "Rubber training bayonet", description: "Soft bayonet for stage combat class.", price: 32, currency: "USD" },
|
||
{ name: "Blueprints wall art (demil)", description: "Poster schematics with ‘demilled’ watermark — ITAR conversation.", price: 0.018, currency: "BTC" },
|
||
{ name: "Snap-cap choir set", description: "Harmless snap caps for chorus-line dry-fire drills (supervised).", price: 41, currency: "USD" },
|
||
{ name: "Range officer clipboard folio", description: "Clipboard with safety checklist prompts.", price: 17, currency: "USD" },
|
||
{ name: "Kevlar-thread friendship bracelet", description: "Braided accent band — marketing references aramid; tensile spec on vendor sheet.", price: 0.009, currency: "XMR" },
|
||
]),
|
||
...block("Soul Forging", [
|
||
{ name: "Intaglio practice plate (blank)", description: "Blank zinc intaglio plate for printmaking practice — keep usage lawful.", price: 67, currency: "USD" },
|
||
{ name: "UV counterfeit reveal postcard set", description: "Postcards with hidden UV layers — doc verification labs.", price: 0.012, currency: "BTC" },
|
||
{ name: "Microprint magnifier chain", description: "Jeweler loupe necklace — inspect fine printing legitimately.", price: 21, currency: "USD" },
|
||
{ name: "Hologram sticker starter pack", description: "generic shiny stickers — compare to banknote holograms.", price: 0.008, currency: "ETH" },
|
||
{ name: "Passport photo booth curtain (prop)", description: "Curtain fabric roll for mock booth setup.", price: 56, currency: "USD" },
|
||
{ name: "Raised-seal cosplay wax sticks", description: "Assorted wax sticks for hobby embossing — not for government documents.", price: 13, currency: "USD" },
|
||
{ name: "Typography-of-banknotes poster", description: "Serif anatomy poster for design-history class.", price: 0.015, currency: "XMR" },
|
||
{ name: "Frank Abagnale movie night kit", description: "Popcorn + discussion guide — fraud history framed responsibly.", price: 9, currency: "USD" },
|
||
{ name: "Watermark cotton paper sampler", description: "Sampler pack of cotton bond — conservation chemistry tangent.", price: 34, currency: "USD" },
|
||
{ name: "Forgery panic flowchart scroll", description: "Wall scroll for ‘if you find a fake, then…’ decisions.", price: 0.006, currency: "BTC" },
|
||
{ name: "Embossing press desk toy", description: "Desktop lever press for foil hobby work — keep off official parchment.", price: 88, currency: "USD" },
|
||
{ name: "Counterfeit color-match Pantone joke book", description: "Parody swatch book — teach perceptual tricks.", price: 0.022, currency: "ETH" },
|
||
{ name: "Notarization rubber duck", description: "Duck with stamp hat — debug your trust assumptions.", price: 5, currency: "USD" },
|
||
]),
|
||
...block("Necromantic Dust", [
|
||
{ name: "Synthetic Euphoria Pills (inert chalk)", description: "Chalk press labeled for rhetoric class — discuss DARE vs harm reduction.", price: 0.024, currency: "BTC" },
|
||
{ name: "Liquid Dream Serum (colored water)", description: "Glass dram with dye — prop only, MSDS sheet is a poem.", price: 0.18, currency: "XMR", limited: true },
|
||
{ name: "Round-bottom flask stress orb", description: "Squishy flask — lab safety mascot.", price: 10, currency: "USD" },
|
||
{ name: "Periodic table shower curtain", description: "Actually useful chemistry dorm decor.", price: 29, currency: "USD" },
|
||
{ name: "Nitrogen dewar shot glass (steel)", description: "Steel mini cup shaped like dewar — LN₂ jokes, not included.", price: 0.011, currency: "ETH" },
|
||
{ name: "Fume hood sash height sticker pack", description: "Vinyl stickers reminding sash position — lab tours.", price: 7, currency: "USD" },
|
||
{ name: "GHS pictogram cookie cutters", description: "Bake hazard-symbol cookies — safety comms.", price: 16, currency: "USD" },
|
||
{ name: "Precursor-themed spice labels (joke)", description: "Labels for cumin jar saying ‘not a precursor’ — legal humor.", price: 0.004, currency: "BTC" },
|
||
{ name: "Affinity chromatography plush column", description: "Stuffed toy shaped like a column — biochem softness.", price: 37, currency: "USD" },
|
||
{ name: "CRC Handbook coaster set", description: "Coasters printed with fake constants — trivia nights.", price: 0.019, currency: "XMR" },
|
||
{ name: "Ampoule snap practice kit (sugar)", description: "Sugar ampoules for snapping motion drills — no glass cuts.", price: 23, currency: "USD" },
|
||
{ name: "Titration mood light", description: "Lamp that shifts color like pH — aesthetics of indicators.", price: 44, currency: "USD" },
|
||
{ name: "Beaker creature plush", description: "Monster made of stacked beakers — PPE still required.", price: 0.013, currency: "ETH" },
|
||
{ name: "Lab notebook with waterproof lies", description: "Notebook advertising ‘indestructible claims’ — epistemology gag.", price: 18, currency: "USD" },
|
||
]),
|
||
...block("Fey Offerings", [
|
||
{ name: "Blue Raspberry Bubblegum brick", description: "Bulk gum for candy-market grid — sticker claims ‘encrypted flavor’.", price: 0.002, currency: "BTC" },
|
||
{ name: "Sour Watermelon wedge bag", description: "Sour belts in Mylar — discuss packaging OPSEC as metaphor.", price: 0.0015, currency: "BTC" },
|
||
{ name: "Mystery Mix Cryptobag", description: "Assorted odds; QR on label resolves to nutrition facts PDF.", price: 0.005, currency: "BTC", limited: true },
|
||
{ name: "Glow-in-the-Dark Taffy rope", description: "UV-reactive taffy for blacklight display case only.", price: 0.003, currency: "ETH" },
|
||
{ name: "Tor onion gummy mold", description: "Silicone mold shaped like Tor logo onions — make gummies legally.", price: 14, currency: "USD" },
|
||
{ name: "Monero-mint chocolate bar", description: "Dark-mint bar in foil printed with ring-sig artwork — ships cold-packed.", price: 0.007, currency: "XMR" },
|
||
{ name: "Hash-brownie mix (literal potato)", description: "Potato hash brown mix — pun SKU for blockchain week.", price: 8, currency: "USD" },
|
||
{ name: "PGP-signed lollipop", description: "Lollipop with wrapper showing fake ASCII armor — unwrap carefully.", price: 0.004, currency: "BTC" },
|
||
{ name: "Dead-drop jawbreaker", description: "Layers of color like nested containers — tradecraft candy metaphor.", price: 6, currency: "USD" },
|
||
{ name: "Honey-pot honey jar", description: "Real jar of honey labeled honeypot — Infosec picnic.", price: 17, currency: "USD" },
|
||
{ name: "Zero-knowledge nougat", description: "Nougat bar claiming ‘you taste it but can’t prove it’ — ZKP joke.", price: 0.006, currency: "ETH" },
|
||
{ name: "Bitcoin-orange rock candy geode", description: "Rock candy geode dyed BTC orange — geology + crypto pun.", price: 11, currency: "USD" },
|
||
{ name: "Cold-storage ice pop molds", description: "Popsicle molds shaped like hardware wallets — summer syllabus.", price: 13, currency: "USD" },
|
||
{ name: "Mixer-themed cotton candy floss sugar", description: "Pastel sugars labeled hop1/hop2/hop3 — sweet talk about mixers.", price: 20, currency: "USD" },
|
||
]),
|
||
...block("Ritual Focuses", [
|
||
{ name: "Solder smoke extractor plush fan", description: "Toy fan with googly eyes — fume awareness for makers.", price: 36, currency: "USD" },
|
||
{ name: "JTAG duck debugger", description: "Rubber duck with labeled test points — hardware RE humor.", price: 0.017, currency: "BTC" },
|
||
{ name: "TPM tamper-evident sticker sheet", description: "Destructive void labels for chassis sealing — audits love these.", price: 12, currency: "USD" },
|
||
{ name: "Flipper Zero cosplay foam", description: "Foam replica — discuss responsible RF rules.", price: 0.01, currency: "ETH" },
|
||
{ name: "Airgap Ethernet cable (sewn shut)", description: "Cable sewn closed — literal air gap joke.", price: 9, currency: "USD" },
|
||
{ name: "SD-card sorting tray", description: "3D-print tray for forensic imaging class prop sorting.", price: 25, currency: "USD" },
|
||
{ name: "Logic analyzer hair clip (prop)", description: "Hair clip shaped like LA probes — signal integrity vibes.", price: 7, currency: "USD" },
|
||
{ name: "Raspberry Pi oven mitt", description: "Oven mitt with GPIO pinout print — kitchen cluster jokes.", price: 18, currency: "USD" },
|
||
{ name: "KVM switch fidget cube", description: "Cube with tiny clicky KVM toggles — focus toy for admins.", price: 0.014, currency: "XMR" },
|
||
{ name: "PDU power-strip storybook", description: "Kids book about not overloading circuits — datacenter bedtime.", price: 15, currency: "USD" },
|
||
]),
|
||
...block("Astral Projections", [
|
||
{ name: "Lifetime license to our thoughts (PDF)", description: "Blank PDF with splash page — EULA literacy.", price: 0.001, currency: "ETH" },
|
||
{ name: "NFT of this paragraph (screenshot)", description: "PNG screenshot — discuss provenance vs possession.", price: 0.008, currency: "BTC" },
|
||
{ name: "Vaporware roadmap deck template", description: "Keynote template full of vague quarters.", price: 5, currency: "USD" },
|
||
{ name: "SaaS subscription to nothing", description: "Stripe-looking receipt for $0/mo — dark patterns talk.", price: 0, currency: "USD" },
|
||
{ name: "Cracked screen wallpaper pack", description: "PNG wallpapers — social engineering bait awareness.", price: 3, currency: "USD" },
|
||
{ name: "ISO27001 compliance cat video", description: "MP4 of cat knocking audit binder off desk.", price: 0.003, currency: "XMR" },
|
||
{ name: "Phishing email mad-libs HTML", description: "Template with blanks for grammar of scams.", price: 0.006, currency: "BTC" },
|
||
{ name: "API rate-limit lullaby MP3", description: "Lo-fi beats for waiting on 429 responses.", price: 7, currency: "USD" },
|
||
{ name: "Kubernetes yaml horoscope", description: "Text files mapping star signs to misconfig jokes.", price: 0.004, currency: "ETH" },
|
||
{ name: "Dark-mode-only whitepaper (empty)", description: "White PDF named ironically — accessibility tangent.", price: 2, currency: "USD" },
|
||
]),
|
||
...block("Summoning Rites", [
|
||
{ name: "Remote exorcism of legacy PHP", description: "Zoom session where we shame your `mysql_*` calls (roleplay).", price: 0.09, currency: "BTC" },
|
||
{ name: "Tarot for TLS certificate expiry", description: "Performative reading of cert timelines — automate after.", price: 45, currency: "USD" },
|
||
{ name: "On-site donut-driven threat modeling", description: "Bring donuts, draw stride threats on napkins.", price: 120, currency: "USD" },
|
||
{ name: "ASMR packet capture whisper stream", description: "1hr ambient `.pcap` readout — sleep for nerds.", price: 0.016, currency: "XMR" },
|
||
{ name: "Corporate values alignment séance", description: "Parody workshop aligning ‘synergy’ with firewall rules.", price: 0.027, currency: "ETH" },
|
||
{ name: "Retrospective on your retrospective", description: "Facilitator block booking — billed in 0.25 agile-day increments.", price: 88, currency: "USD" },
|
||
{ name: "Perl poetry code review", description: "Critique of badly written haiku in Perl — nostalgia service.", price: 0.012, currency: "BTC" },
|
||
{ name: "Blockchain-of-custody bakery pickup", description: "We sign a paper chain while you pick up muffins.", price: 35, currency: "USD" },
|
||
]),
|
||
];
|
||
|
||
function dedupeById(products: ProductDraft[]): ProductDraft[] {
|
||
const seen = new Set<string>();
|
||
const out: ProductDraft[] = [];
|
||
for (const p of products) {
|
||
if (seen.has(p.id)) continue;
|
||
seen.add(p.id);
|
||
out.push(p);
|
||
}
|
||
return out;
|
||
}
|
||
|
||
export const SHOP_PRODUCTS: ShopProduct[] = dedupeById(ALL_BLOCKS).map((p) => ({
|
||
...p,
|
||
sellerId: sellerIdForProduct(p.id),
|
||
}));
|
||
|
||
export function shopProductsForSeller(sellerId: string): ShopProduct[] {
|
||
return SHOP_PRODUCTS.filter((p) => p.sellerId === sellerId);
|
||
}
|
||
|
||
export const SHOP_PRODUCT_COUNT = SHOP_PRODUCTS.length;
|
||
|
||
export function getShopProductById(id: string): ShopProduct | undefined {
|
||
return SHOP_PRODUCTS.find((p) => p.id === id);
|
||
}
|
||
|
||
export function shopCategoryCounts(): { name: string; count: number; icon: string }[] {
|
||
const icons: Record<string, string> = {
|
||
"Alchemical Elixirs": "🧪",
|
||
"Blood Pacts": "🩸",
|
||
"Glamour Illusions": "🎭",
|
||
"Ward Enchantments": "🛡️",
|
||
"Forbidden Prophecies": "📜",
|
||
"Eldritch Relics": "🗡️",
|
||
"Soul Forging": "⚒️",
|
||
"Necromantic Dust": "⚱️",
|
||
"Fey Offerings": "🍄",
|
||
"Ritual Focuses": "🔮",
|
||
"Astral Projections": "✨",
|
||
"Summoning Rites": "🕯️",
|
||
};
|
||
const m = new Map<string, number>();
|
||
for (const p of SHOP_PRODUCTS) {
|
||
m.set(p.category, (m.get(p.category) ?? 0) + 1);
|
||
}
|
||
return [...m.entries()]
|
||
.map(([name, count]) => ({ name, count, icon: icons[name] ?? "⬡" }))
|
||
.sort((a, b) => a.name.localeCompare(b.name));
|
||
}
|
||
|
||
export function featuredShopProducts(n = 8): ShopProduct[] {
|
||
return [...SHOP_PRODUCTS].sort((a, b) => (b.limited ? 1 : 0) - (a.limited ? 1 : 0) || hashId(a.id) - hashId(b.id)).slice(0, n);
|
||
}
|