@@ -1,444 +0,0 @@
/**
* Dev seed — заполняет store фейковыми контактами и сообщениями для UI-теста.
*
* Запускается один раз при монтировании layout'а если store пустой
* (useDevSeed). Реальные контакты через WS/HTTP приходят позже —
* `upsertContact` перезаписывает mock'и по address'у .
*
* Цели seed'а :
* 1. Показать все три типа чатов (direct / group / channel) с разным
* поведением sender-meta.
* 2. Наполнить список чатов до скролла (15+ контактов).
* 3. В каждом чате — ≥15 сообщений для скролла в chat view.
* 4. Продемонстрировать "staircase" (run'ы одного отправителя
* внутри 1h-окна) и переключения между отправителями.
*/
import { useEffect } from 'react' ;
import { useStore } from './store' ;
import type { Contact , Message } from './types' ;
// ─── Детерминированные «pubkey» (64 hex символа) ───────────────────
function fakeHex ( seed : number ) : string {
let h = '' ;
let x = seed ;
for ( let i = 0 ; i < 32 ; i ++ ) {
x = ( x * 1103515245 + 12345 ) & 0xffffffff ;
h += ( x & 0xff ) . toString ( 16 ) . padStart ( 2 , '0' ) ;
}
return h ;
}
const now = ( ) = > Math . floor ( Date . now ( ) / 1000 ) ;
const MINE = fakeHex ( 9999 ) ;
// ─── Контакты ──────────────────────────────────────────────────────
// 16 штук: 5 DM + 6 групп + 5 каналов. Поле `addedAt` задаёт порядок в
// списке когда нет messages — ordering-fallback.
const mockContacts : Contact [ ] = [
// ── DM ──────────────────────────────────────────────────────────
{ address : fakeHex ( 1001 ) , x25519Pub : fakeHex ( 2001 ) ,
username : 'jordan' , addedAt : Date.now ( ) - 60 * 60 * 1 _000 , kind : 'direct' } ,
{ address : fakeHex ( 1002 ) , x25519Pub : fakeHex ( 2002 ) ,
alias : 'Myles Wagner' , addedAt : Date.now ( ) - 2 * 60 * 60 * 1 _000 , kind : 'direct' } ,
{ address : fakeHex ( 1010 ) , x25519Pub : fakeHex ( 2010 ) ,
username : 'sarah_k' , addedAt : Date.now ( ) - 3 * 60 * 60 * 1 _000 , kind : 'direct' ,
unread : 2 } ,
{ address : fakeHex ( 1011 ) , x25519Pub : fakeHex ( 2011 ) ,
alias : 'Mom' , addedAt : Date.now ( ) - 5 * 60 * 60 * 1 _000 , kind : 'direct' } ,
{ address : fakeHex ( 1012 ) , x25519Pub : fakeHex ( 2012 ) ,
username : 'alex_dev' , addedAt : Date.now ( ) - 6 * 60 * 60 * 1 _000 , kind : 'direct' } ,
// ── Groups ─────────────────────────────────────────────────────
{ address : fakeHex ( 1003 ) , x25519Pub : fakeHex ( 2003 ) ,
alias : 'Tahoe weekend 🌲' , addedAt : Date.now ( ) - 4 * 60 * 60 * 1 _000 , kind : 'group' } ,
{ address : fakeHex ( 1004 ) , x25519Pub : fakeHex ( 2004 ) ,
alias : 'Knicks tickets' , addedAt : Date.now ( ) - 5 * 60 * 60 * 1 _000 , kind : 'group' ,
unread : 3 } ,
{ address : fakeHex ( 1020 ) , x25519Pub : fakeHex ( 2020 ) ,
alias : 'Family' , addedAt : Date.now ( ) - 8 * 60 * 60 * 1 _000 , kind : 'group' } ,
{ address : fakeHex ( 1021 ) , x25519Pub : fakeHex ( 2021 ) ,
alias : 'Work eng' , addedAt : Date.now ( ) - 12 * 60 * 60 * 1 _000 , kind : 'group' ,
unread : 7 } ,
{ address : fakeHex ( 1022 ) , x25519Pub : fakeHex ( 2022 ) ,
alias : 'Book club' , addedAt : Date.now ( ) - 24 * 60 * 60 * 1 _000 , kind : 'group' } ,
{ address : fakeHex ( 1023 ) , x25519Pub : fakeHex ( 2023 ) ,
alias : 'Tuesday D&D 🎲' , addedAt : Date.now ( ) - 30 * 60 * 60 * 1 _000 , kind : 'group' } ,
// (Channel seeds removed in v2.0.0 — channels replaced by the social feed.)
] ;
// ─── Генератор сообщений ───────────────────────────────────────────
// Альт-отправители для group-чатов — нужны только как идентификатор `from`.
const P_TYRA = fakeHex ( 3001 ) ;
const P_MYLES = fakeHex ( 3002 ) ;
const P_NATE = fakeHex ( 3003 ) ;
const P_TYLER = fakeHex ( 3004 ) ;
const P_MOM = fakeHex ( 3005 ) ;
const P_DAD = fakeHex ( 3006 ) ;
const P_SIS = fakeHex ( 3007 ) ;
const P_LEAD = fakeHex ( 3008 ) ;
const P_PM = fakeHex ( 3009 ) ;
const P_QA = fakeHex ( 3010 ) ;
const P_DESIGN = fakeHex ( 3011 ) ;
const P_ANNA = fakeHex ( 3012 ) ;
const P_DM_PEER = fakeHex ( 3013 ) ;
type Msg = Omit < Message , 'id' > ;
function list ( prefix : string , list : Msg [ ] ) : Message [ ] {
return list . map ( ( m , i ) = > ( { . . . m , id : ` ${ prefix } _ ${ i } ` } ) ) ;
}
function mockMessagesFor ( contact : Contact ) : Message [ ] {
const peer = contact . x25519Pub ;
// ── DM: @jordan ────────────────────────────────────────────────
if ( contact . username === 'jordan' ) {
// Важно: id'ы сообщений используются в replyTo.id, поэтому
// указываем их явно где нужно сшить thread.
const msgs : Message [ ] = list ( 'jordan' , [
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 22 , text : 'Hey, have a sec later today?' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 21 , read : true , text : 'yep around 4pm' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 20 , text : 'cool, coffee at the corner spot?' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 19 , read : true , text : 'works' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 4 , text : 'just parked 🚗' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 4 , text : 'see you in 5' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 3 , read : true , text : "that was a great catchup" } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 3 , text : "totally — thanks for the book rec" } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 40 , text : 'Hey Jordan - Got tickets to the Knicks game tomorrow, let me know if you want to come!' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 39 , text : "we've got floor seats 🔥" } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 38 , text : "starts at 7, pregame at the bar across the street" } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 14 , read : true , edited : true , text : 'Ah sadly I already have plans' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 13 , read : true , text : 'maybe next time?' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 5 , text : "no worries — enjoy whatever you're up to" } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 2 , text : "wish you could make it tho 🏀" } ,
] ) ;
// Пришьём reply: MINE-сообщение "Ah sadly…" отвечает на "Hey Jordan - Got tickets…"
const target = msgs . find ( m = > m . text . startsWith ( 'Hey Jordan - Got tickets' ) ) ;
const mine = msgs . find ( m = > m . text === 'Ah sadly I already have plans' ) ;
if ( target && mine ) {
mine . replyTo = {
id : target.id ,
author : '@jordan' ,
text : target.text ,
} ;
}
return msgs ;
}
// ── DM: Myles Wagner ───────────────────────────────────────────
if ( contact . alias === 'Myles Wagner' ) {
return list ( 'myles' , [
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 30 , text : 'saw the draft, left a bunch of comments' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 29 , read : true , text : 'thx, going through them now' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 29 , text : 'no rush — tomorrow is fine' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 5 , text : 'lunch today?' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 4 , read : true , text : "can't, stuck in reviews" } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 4 , read : true , text : 'tomorrow?' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 4 , text : '✅ tomorrow' } ,
{
from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 2 , text : '' ,
attachment : {
kind : 'voice' ,
uri : 'voice-demo://myles-1' ,
duration : 17 ,
} ,
} ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 25 , text : 'the dchain repo finally built for me' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 25 , text : 'docker weirdness was the issue' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 21 , read : true , text : "nice, told you the WSL path would do it" } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 20 , text : 'So good!' } ,
] ) ;
}
// ── DM: @sarah_k (с unread=2) ──────────────────────────────────
if ( contact . username === 'sarah_k' ) {
return list ( 'sarah' , [
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 30 , text : "hey! been a while" } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 28 , read : true , text : 'yeah, finally surfaced after the launch crunch' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 27 , text : 'how did it go?' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 27 , read : true , text : "pretty well actually 🙏" } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 2 , text : 'btw drinks on friday?' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 2 , text : 'that new wine bar' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 2 , text : 'around 7 if you can make it' } ,
] ) ;
}
// ── DM: Mom ────────────────────────────────────────────────────
if ( contact . alias === 'Mom' ) {
return list ( 'mom' , [
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 48 , text : 'Did you see the photos from the trip?' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 47 , read : true , text : 'not yet, send them again?' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 47 , text : 'ok' } ,
{
from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 46 , text : '' ,
attachment : {
kind : 'image' ,
uri : 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800' ,
width : 800 , height : 533 , mime : 'image/jpeg' ,
} ,
} ,
{
from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 46 , text : '' ,
attachment : {
kind : 'image' ,
uri : 'https://images.unsplash.com/photo-1519681393784-d120267933ba?w=800' ,
width : 800 , height : 533 , mime : 'image/jpeg' ,
} ,
} ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 30 , read : true , text : 'wow, grandma looks great' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 30 , text : 'she asked about you!' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 7 , text : 'call later?' } ,
] ) ;
}
// ── DM: @alex_dev ──────────────────────────────────────────────
if ( contact . username === 'alex_dev' ) {
return list ( 'alex' , [
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 12 , text : 'did you try the new WASM build?' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 11 , read : true , text : 'yeah, loader error on start' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 11 , text : 'path encoding issue again?' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 10 , read : true , text : 'probably, checking now' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 8 , read : true , text : 'yep, was the trailing slash' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 8 , text : 'classic 😅' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 7 , text : 'PR for that incoming tomorrow' } ,
] ) ;
}
// ── Group: Tahoe weekend 🌲 ────────────────────────────────────
if ( contact . alias === 'Tahoe weekend 🌲' ) {
const msgs : Message [ ] = list ( 'tahoe' , [
{ from : P_TYRA , mine : false , timestamp : now ( ) - 60 * 60 * 50 , text : "who's in for Tahoe this weekend?" } ,
{ from : P_MYLES , mine : false , timestamp : now ( ) - 60 * 60 * 49 , text : "me!" } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 48 , read : true , text : "count me in" } ,
{ from : P_TYRA , mine : false , timestamp : now ( ) - 60 * 60 * 48 , text : "woohoo 🎉" } ,
{ from : P_ANNA , mine : false , timestamp : now ( ) - 60 * 60 * 47 , text : "planning friday night → sunday evening yeah?" } ,
{ from : P_TYRA , mine : false , timestamp : now ( ) - 60 * 60 * 46 , text : "yep, maybe leave friday after lunch" } ,
{ from : P_MYLES , mine : false , timestamp : now ( ) - 60 * 60 * 30 , text : "I made this itinerary with Grok, what do you think?" } ,
{ from : P_MYLES , mine : false , timestamp : now ( ) - 60 * 60 * 30 , text : "Day 1: Eagle Falls hike" } ,
{ from : P_MYLES , mine : false , timestamp : now ( ) - 60 * 60 * 30 , text : "Day 2: Emerald bay kayak" } ,
{ from : P_MYLES , mine : false , timestamp : now ( ) - 60 * 60 * 30 , text : "Day 3: lazy breakfast then drive back" } ,
{
from : P_MYLES , mine : false , timestamp : now ( ) - 60 * 60 * 30 , text : '' ,
attachment : {
kind : 'file' ,
uri : 'https://example.com/Lake_Tahoe_Itinerary.pdf' ,
name : 'Lake_Tahoe_Itinerary.pdf' ,
size : 97_280 , // ~95 KB
mime : 'application/pdf' ,
} ,
} ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 24 , read : true , edited : true , text : "Love it — Eagle falls looks insane" } ,
{ from : P_ANNA , mine : false , timestamp : now ( ) - 60 * 60 * 24 , text : "Eagle falls was stunning last year!" } ,
{ from : P_TYRA , mine : false , timestamp : now ( ) - 60 * 31 , text : "who's excited for Tahoe this weekend?" } ,
{ from : P_TYRA , mine : false , timestamp : now ( ) - 60 * 30 , text : "I've been checking the forecast — sun all weekend 🌞" } ,
{ from : P_MYLES , mine : false , timestamp : now ( ) - 60 * 22 , text : "I made this itinerary with Grok, what do you think?" } ,
{ from : P_MYLES , mine : false , timestamp : now ( ) - 60 * 21 , text : "Day 1 we can hit Eagle Falls" } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 14 , read : true , edited : true , text : "Love it — Eagle falls looks insane" } ,
{
from : P_TYRA , mine : false , timestamp : now ( ) - 60 * 3 , text : 'pic from my last trip 😍' ,
attachment : {
kind : 'image' ,
uri : 'https://images.unsplash.com/photo-1505245208761-ba872912fac0?w=800' ,
width : 800 ,
height : 1000 ,
mime : 'image/jpeg' ,
} ,
} ,
] ) ;
// Thread: mine "Love it — Eagle falls looks insane" — ответ на
// Myles'овский itinerary-PDF. Берём ПЕРВЫЙ match "Day 1 we can hit
// Eagle Falls" и пришиваем е г о к первому mine-bubble'у .
const target = msgs . find ( m = > m . text === 'Day 1 we can hit Eagle Falls' ) ;
const reply = msgs . find ( m = > m . text === 'Love it — Eagle falls looks insane' && m . mine ) ;
if ( target && reply ) {
reply . replyTo = {
id : target.id ,
author : 'Myles Wagner' ,
text : target.text ,
} ;
}
return msgs ;
}
// ── Group: Knicks tickets ──────────────────────────────────────
if ( contact . alias === 'Knicks tickets' ) {
return list ( 'knicks' , [
{ from : P_NATE , mine : false , timestamp : now ( ) - 60 * 60 * 20 , text : "quick group update — got 5 tickets for thursday" } ,
{ from : P_TYLER , mine : false , timestamp : now ( ) - 60 * 60 * 19 , text : 'wow nice' } ,
{ from : P_TYLER , mine : false , timestamp : now ( ) - 60 * 60 * 19 , text : 'where are we seated?' } ,
{ from : P_NATE , mine : false , timestamp : now ( ) - 60 * 60 * 19 , text : 'section 102, row 12' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 18 , read : true , text : 'thats a great spot' } ,
{ from : P_ANNA , mine : false , timestamp : now ( ) - 60 * 60 * 18 , text : "can someone venmo nate 🙏" } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 17 , read : true , text : 'sending now' } ,
{ from : P_NATE , mine : false , timestamp : now ( ) - 60 * 32 , text : "Ok who's in for tomorrow's game?" } ,
{ from : P_NATE , mine : false , timestamp : now ( ) - 60 * 31 , text : 'Got 2 extra tickets, first-come-first-served' } ,
{ from : P_TYLER , mine : false , timestamp : now ( ) - 60 * 27 , text : "I'm in!" } ,
{ from : P_TYLER , mine : false , timestamp : now ( ) - 60 * 26 , text : 'What time does it start?' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 20 , read : true , text : "Let's meet at the bar around 6?" } ,
{ from : P_NATE , mine : false , timestamp : now ( ) - 60 * 15 , text : 'Sounds good' } ,
] ) ;
}
// ── Group: Family ──────────────────────────────────────────────
if ( contact . alias === 'Family' ) {
return list ( 'family' , [
{ from : P_MOM , mine : false , timestamp : now ( ) - 60 * 60 * 36 , text : 'remember grandma birthday on sunday' } ,
{ from : P_DAD , mine : false , timestamp : now ( ) - 60 * 60 * 36 , text : 'noted 🎂' } ,
{ from : P_SIS , mine : false , timestamp : now ( ) - 60 * 60 * 35 , text : 'who is bringing the cake?' } ,
{ from : P_MOM , mine : false , timestamp : now ( ) - 60 * 60 * 35 , text : "I'll get it from the bakery" } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 34 , read : true , text : 'I can pick up flowers' } ,
{ from : P_SIS , mine : false , timestamp : now ( ) - 60 * 60 * 34 , text : 'perfect' } ,
{ from : P_DAD , mine : false , timestamp : now ( ) - 60 * 60 * 8 , text : 'forecast is rain sunday — backup plan?' } ,
{ from : P_MOM , mine : false , timestamp : now ( ) - 60 * 60 * 8 , text : "we'll move indoors, the living room works" } ,
{ from : P_SIS , mine : false , timestamp : now ( ) - 60 * 60 * 7 , text : 'works!' } ,
] ) ;
}
// ── Group: Work eng (unread=7) ─────────────────────────────────
if ( contact . alias === 'Work eng' ) {
return list ( 'work' , [
{ from : P_LEAD , mine : false , timestamp : now ( ) - 60 * 60 * 16 , text : 'standup at 10 moved to 11 today btw' } ,
{ from : P_PM , mine : false , timestamp : now ( ) - 60 * 60 * 16 , text : 'thanks!' } ,
{ from : P_QA , mine : false , timestamp : now ( ) - 60 * 60 * 15 , text : "the staging deploy broke again 🙃" } ,
{ from : P_LEAD , mine : false , timestamp : now ( ) - 60 * 60 * 15 , text : "ugh, looking" } ,
{ from : P_LEAD , mine : false , timestamp : now ( ) - 60 * 60 * 14 , text : 'fixed — migration was stuck' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 13 , read : true , text : 'Worked for me now 👍' } ,
{ from : P_PM , mine : false , timestamp : now ( ) - 60 * 60 * 5 , text : 'reminder: demo tomorrow, slides by eod' } ,
{ from : P_LEAD , mine : false , timestamp : now ( ) - 60 * 60 * 4 , text : 'Ill handle the technical half' } ,
{ from : P_DESIGN , mine : false , timestamp : now ( ) - 60 * 60 * 4 , text : 'just posted the v2 mocks in figma' } ,
{ from : P_PM , mine : false , timestamp : now ( ) - 60 * 60 * 3 , text : 'chatting with sales — 3 new trials this week' } ,
{ from : P_QA , mine : false , timestamp : now ( ) - 60 * 60 * 2 , text : 'flaky test on CI — investigating' } ,
{ from : P_LEAD , mine : false , timestamp : now ( ) - 60 * 30 , text : 'okay seems like CI is green now' } ,
{ from : P_LEAD , mine : false , timestamp : now ( ) - 60 * 28 , text : 'retry passed' } ,
{ from : P_PM , mine : false , timestamp : now ( ) - 60 * 20 , text : "we're good for release" } ,
] ) ;
}
// ── Group: Book club ───────────────────────────────────────────
if ( contact . alias === 'Book club' ) {
return list ( 'book' , [
{ from : P_ANNA , mine : false , timestamp : now ( ) - 60 * 60 * 96 , text : 'next month: "Project Hail Mary"?' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 95 , read : true , text : '👍' } ,
{ from : P_SIS , mine : false , timestamp : now ( ) - 60 * 60 * 94 , text : 'yes please' } ,
{ from : P_TYRA , mine : false , timestamp : now ( ) - 60 * 60 * 48 , text : 'halfway through — so good' } ,
{ from : P_ANNA , mine : false , timestamp : now ( ) - 60 * 60 * 48 , text : 'love the linguistics angle' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 30 , read : true , text : "rocky is my favourite character in years" } ,
{ from : P_SIS , mine : false , timestamp : now ( ) - 60 * 60 * 28 , text : 'agreed' } ,
{ from : P_ANNA , mine : false , timestamp : now ( ) - 60 * 60 * 24 , text : "let's meet sunday 4pm?" } ,
] ) ;
}
// ── Group: Tuesday D&D 🎲 ──────────────────────────────────────
if ( contact . alias === 'Tuesday D&D 🎲' ) {
return list ( 'dnd' , [
{ from : P_LEAD , mine : false , timestamp : now ( ) - 60 * 60 * 72 , text : 'Session 14 recap up on the wiki' } ,
{ from : P_ANNA , mine : false , timestamp : now ( ) - 60 * 60 * 72 , text : '🙏' } ,
{ from : P_TYRA , mine : false , timestamp : now ( ) - 60 * 60 * 50 , text : 'can we start 30min late next tuesday? commute issue' } ,
{ from : P_LEAD , mine : false , timestamp : now ( ) - 60 * 60 * 50 , text : 'sure' } ,
{ from : MINE , mine : true , timestamp : now ( ) - 60 * 60 * 49 , read : true , text : 'works for me' } ,
{ from : P_LEAD , mine : false , timestamp : now ( ) - 60 * 60 * 32 , text : 'we pick up where we left — in the dragons cave' } ,
{ from : P_ANNA , mine : false , timestamp : now ( ) - 60 * 60 * 32 , text : 'excited 🐉' } ,
] ) ;
}
// ── Channel: dchain_updates ────────────────────────────────────
if ( contact . username === 'dchain_updates' ) {
return list ( 'dchain_updates' , [
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 96 , text : '🔨 v0.0.1-alpha tagged on Gitea' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 72 , text : 'PBFT equivocation-detection тесты зелёные' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 60 , text : 'New: /api/peers теперь включает peer-version info' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 48 , text : '📘 Docs overhaul merged: docs/README.md' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 36 , text : 'Schema migration scaffold landed (no-op для текущей версии)' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 20 , text : '🚀 v0.0.1 released' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 20 + 10 , text : 'Includes: auto-update from Gitea, peer-version gossip, schema migrations' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 20 + 20 , text : 'Check /api/well-known-version for the full feature list' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 12 , text : 'Thanks to all testers — feedback drives the roadmap 🙏' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 3 , text : 'v0.0.2 roadmap published: https://git.vsecoder.vodka/vsecoder/dchain' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 30 , text : 'quick heads-up: nightly builds switching to new docker-slim base' } ,
] ) ;
}
// ── Channel: Relay broadcasts ──────────────────────────────────
if ( contact . alias === '⚡ Relay broadcasts' ) {
return list ( 'relay_bc' , [
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 48 , text : 'Relay fleet snapshot: 12 active, 3 inactive' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 40 , text : 'Relay #3 came online in US-east' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 30 , text : 'Validator set updated: 3→4' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 20 , text : 'PBFT view-change детектирован и отработан на блоке 184120' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 15 , text : 'Mailbox eviction ran — 42 stale envelopes' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 5 , text : 'Relay #8 slashed for equivocation — evidence at block 184202' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 2 , text : 'Relay #12 came online in EU-west, registering now…' } ,
] ) ;
}
// ── Channel: Tech news ────────────────────────────────────────
if ( contact . alias === '📰 Tech news' ) {
return list ( 'tech_news' , [
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 120 , text : 'Rust 1.78 released — new lints for raw pointers' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 100 , text : 'Go 1.23 ships range-over-func officially' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 80 , text : 'Expo SDK 54 drops — new-architecture default' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 60 , text : 'CVE-2026-1337 patched in libsodium (update your keys)' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 40 , text : 'Matrix protocol adds post-quantum handshakes' } ,
{
from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 30 , text : 'Data-center aerial view — new hyperscaler in Iceland' ,
attachment : {
kind : 'image' ,
uri : 'https://images.unsplash.com/photo-1558494949-ef010cbdcc31?w=800' ,
width : 800 , height : 533 , mime : 'image/jpeg' ,
} ,
} ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 20 , text : 'IETF draft: "DNS-over-blockchain"' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 6 , text : 'GitHub tightens 2FA defaults for orgs' } ,
] ) ;
}
// ── Channel: Design inspo (unread=12) ──────────────────────────
if ( contact . alias === '🎨 Design inspo' ) {
return list ( 'design_inspo' , [
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 160 , text : 'Weekly pick: Linear UI v3 breakdown' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 140 , text : 'Figma file of the week: "Command bar patterns"' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 120 , text : 'Motion study: Stripe checkout shake-error animation' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 100 , text : "10 great empty-state illustrations (blogpost)" } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 80 , text : 'Tool: Hatch — colour-palette extractor from photos' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 60 , text : '🔮 Trend watch: glassmorphism is back (again)' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 40 , text : 'Twitter thread: why rounded buttons are the default' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 20 , text : 'Framer templates — black friday sale' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 3 , text : 'New typeface: "Grotesk Pro" — free for personal use' } ,
] ) ;
}
// ── Channel: NBA scores ────────────────────────────────────────
if ( contact . alias === '🏀 NBA scores' ) {
return list ( 'nba' , [
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 160 , text : 'Lakers 112 — Warriors 108 (OT)' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 130 , text : 'Celtics 128 — Heat 115' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 100 , text : 'Nuggets 119 — Thunder 102' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 70 , text : "Knicks 101 — Bulls 98" } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 48 , text : 'Mavericks 130 — Kings 127' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 24 , text : 'Bucks 114 — Sixers 110' } ,
{ from : peer , mine : false , timestamp : now ( ) - 60 * 60 * 4 , text : 'Live: Lakers leading 78-72 at half' } ,
] ) ;
}
return [ ] ;
}
// ─── Hook ──────────────────────────────────────────────────────────
export function useDevSeed() {
const contacts = useStore ( s = > s . contacts ) ;
const setContacts = useStore ( s = > s . setContacts ) ;
const setMessages = useStore ( s = > s . setMessages ) ;
useEffect ( ( ) = > {
if ( contacts . length > 0 ) return ;
setContacts ( mockContacts ) ;
for ( const c of mockContacts ) {
const msgs = mockMessagesFor ( c ) ;
if ( msgs . length > 0 ) setMessages ( c . address , msgs ) ;
}
} , [ contacts . length , setContacts , setMessages ] ) ;
}