[0.9.1] FORK_IA_UX: Fase 2 (invite) — invite a contact to a Karvan room by feed id over SSB
Reuses Oasis's own private-message invite pattern (like the industry module: pmModel.sendMessage([feed], 'KARVAN_INVITE', '... -> /karvan/<id>')), so the invite lands in the contact's inbox with a link — no new SSB code, no touching the SSB startup. Joining a room by link adopts a local mirror (karvanModel.adoptRoom, the id is the capability). Real-time cross-device signaling (media/text sync between the two mirrors) is the remaining Fase 2 piece (muxrpc ephemeral), deferred. Verified single-node: invite publishes to the inbox, validation, adopt, form; 13/13 model tests (added adoptRoom).
This commit is contained in:
parent
813bf16958
commit
af160dbd26
5 changed files with 81 additions and 4 deletions
|
|
@ -72,6 +72,32 @@ module.exports = ({ idleTtlMs = DEFAULT_IDLE_TTL_MS, absTtlMs = DEFAULT_ABS_TTL_
|
|||
return publicRoom(room);
|
||||
};
|
||||
|
||||
// Fase 2 (invitar): unirse a una sala por su id creando un ESPEJO local (desde un enlace/invitación).
|
||||
// El id es la "capacidad": quien lo tiene puede unirse. Aún NO conecta con la sala del otro nodo
|
||||
// (eso es la señalización cross-device, pendiente); crea la sala local para poder abrir el enlace.
|
||||
const adoptRoom = ({ id, title = "", ttlMinutes } = {}) => {
|
||||
if (!id || typeof id !== "string" || !/^[0-9a-f]{6,64}$/.test(id)) return null;
|
||||
const existing = rooms.get(id);
|
||||
if (existing) return publicRoom(existing);
|
||||
if (rooms.size >= MAX_ROOMS) {
|
||||
const oldest = [...rooms.values()].sort((a, b) => a.createdAt - b.createdAt)[0];
|
||||
if (oldest) destroy(oldest.id);
|
||||
}
|
||||
const createdAt = Date.now();
|
||||
let absMs = absTtlMs;
|
||||
const t = parseInt(ttlMinutes, 10);
|
||||
if (Number.isFinite(t) && t > 0) absMs = Math.min(t * 60000, MAX_ABS_TTL_MS);
|
||||
const room = {
|
||||
id, title: String(title || "").slice(0, 80), createdAt, expiresAt: createdAt + absMs,
|
||||
messages: [], signals: [], members: new Set(), seq: 0, sigSeq: 0, idleTimer: null, absTimer: null,
|
||||
};
|
||||
rooms.set(id, room);
|
||||
room.absTimer = setTimeout(() => destroy(id), absMs);
|
||||
if (room.absTimer.unref) room.absTimer.unref();
|
||||
resetIdle(room);
|
||||
return publicRoom(room);
|
||||
};
|
||||
|
||||
const listRooms = () =>
|
||||
[...rooms.values()].map(publicRoom).sort((a, b) => b.createdAt - a.createdAt);
|
||||
|
||||
|
|
@ -138,6 +164,7 @@ module.exports = ({ idleTtlMs = DEFAULT_IDLE_TTL_MS, absTtlMs = DEFAULT_ABS_TTL_
|
|||
|
||||
return {
|
||||
createRoom,
|
||||
adoptRoom,
|
||||
listRooms,
|
||||
getRoom,
|
||||
postMessage,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue