Diferencia 1.3.1 -> 1.3.3 del codigo de la APK oficial aplicada a tres
bandas encima de la rama: karma en el perfil, salas con directo, fotos
selladas, visibilidad de menciones, telefono por stream en Android y
las traducciones nuevas. Sin dependencias nuevas.
OasisMobile.css sigue siendo el del fork; del oficial solo se traen al
final las reglas de las piezas nuevas (karma, directo a pantalla
completa, salas en vivo, graphos).
Base del merge a tres bandas: git 0.9.5 de epsylon, esta rama y el src de la
APK oficial 1.3.1 (la variante movil: OASIS_MOBILE, regex sin \p{}, audio y
video de Android). Corre en el mismo nodejs-mobile 18.20.4 que ya usabamos.
Se conserva de la rama: Karvan, identidades y multicuenta, topbar y barra
inferior, borrado de EXIF sin sharp, filtro hot del foro, RTC sin STUN y los
modulos apagados en movil (wallet, banking, torrents).
Se toma de upstream lo que ya hace de serie: respuesta citada en chats, ssb-lan
en movil, configuracion en ~/.ssb/oasis (sobrevive a reinstalar el backend).
El asistente de bienvenida deja elegir workflow tambien en movil.
Upstream no usa ni un solo subdirectorio en src/views, src/backend, src/models,
src/client/assets/styles ni translations: todo plano. La rama habia creado dos
(views/fork/ y translations/fork/), que es lo que mas se separaba de su forma de
organizar el codigo. Se deshacen, y los ficheros pasan a llamarse como los suyos:
views/fork/hive_nav.js -> views/hive_views.js (como main_views.js)
views/fork/identities.js -> views/identities_view.js (como *_view.js)
translations/fork/i18n_fork.js -> translations/i18n_fork.js (junto a i18n.js)
backend/fork_routes.js -> backend/karvan_routes.js (familia karvan_*)
Ademas se retira una ruta duplicada: /legacy/export estaba declarada dos veces,
en backend.js (la del dev) y en el fichero de rutas de la rama, con el mismo
cuerpo salvo un && defensivo. Nacio cuando el formulario se paso a GET; al
devolverlo a POST quedo como copia exacta. Con ella se van legacyModel y
onboardingModel, que ya no hacia falta inyectar.
La cabecera del fichero de rutas explica ahora por que sigue existiendo, con los
datos medidos y no de memoria: backend.js concentra 625 rutas y se reescribe en
cada release (+833/-286 en la 0.9.2, +266/-31 en la 0.9.1), asi que una ruta
anadida en medio entra en conflicto cada vez.
Quedan diez ficheros propios, todos siguiendo la convencion de upstream, y
+247 lineas repartidas en 21 ficheros suyos (sin contar OasisMobile.css, que es
el tema de la rama).
Comprobado tras mover: arranque, las siete rutas principales, el selector de
identidades con sus siete entradas y su aviso, crear sala y enviar mensaje en
Karvan, y la exportacion de identidad por la ruta del dev.
Diagnosticado en el emulador. El backend moria al cargar backend.js:
SyntaxError: Invalid regular expression: /^#([\p{L}\p{N}_-]+)/:
Invalid property name in character class
libnode.so de nodejs-mobile viene sin ICU completo, asi que las propiedades Unicode
en expresiones regulares no existen y el fichero ni siquiera compila. La rama ya lo
habia resuelto con un rango explicito; al integrar 0.9.5 se reintrodujo la forma de
upstream y con ella el fallo. Afectaba a backend.js y a data_model.js.
Tras el arreglo el emulador arranca: 'Backend started on port 3000', 991 modulos,
285 ms de warmup.
Y se devuelven al overlay los nombres de tres categorias. Upstream los renombro en
0.9.5 (Network -> Community, Media -> Library, Fediverse -> Multiverse) y al
restaurar los ficheros de traduccion se colaron los suyos, cambiando las etiquetas
de los hexagonos. Lo destapo una captura de pantalla del usuario, no el codigo.
ssb_config pasa a derivar la cuenta de OASIS_ACCOUNT. Como ssb-config construye la
ruta desde el appname y gui.js saca el socket de config.path, cambiar ese literal
arrastra de forma coherente el almacen, la base de datos, los blobs, el secret y el
socket. Sin la variable se usa 'ssb', asi que las instalaciones existentes siguen en
~/.ssb y no notan nada.
El nombre se valida contra [a-zA-Z0-9][a-zA-Z0-9_-]{0,31} y cae a 'ssb' si no encaja.
No es de adorno: acaba en rutas de fichero y hay operaciones destructivas detras.
Comprobado que OASIS_ACCOUNT=../../etc no sale de sitio.
statePath separa tambien por cuenta cuando se usa OASIS_STATE_DIR. Sin eso, dos
identidades compartirian el estado que 0.9.5 empezo a guardar ahi, que es justo el
camino a partir el registro.
Y el arreglo que importa: doce sitios construian la ruta como os.homedir() + '/.ssb'
en vez de usar la de la cuenta. El peor era panicmode_model, que con varias
identidades habria borrado la equivocada; tambien exportmode y legacy_model, que
habrian exportado o restaurado la identidad de otra cuenta. Los de lectura
—main_models, stats_model y backend.js con gossip.json y ebt— habrian mirado siempre
la cuenta por defecto.
Falta la parte visible: el selector de identidad y el reinicio del proceso al
cambiar. Esta base es la que hacia falta para que eso no sea peligroso.
Verificado: con OASIS_ACCOUNT sin definir la ruta sigue siendo ~/.ssb; con 'trabajo'
pasa a ~/.trabajo; con un valor con .. o espacios se rechaza. Diez rutas OK con la
app en marcha, incluidas /peers y /stats, que son las que leen esos ficheros.
Karvan solo existia en la rejilla de hexagonos, que es de movil. En escritorio no
habia forma de llegar salvo escribiendo la URL.
Se anade renderKarvanLink en main_views, calcado de renderPollsLink —misma forma,
mismo checkMod por getConfig().modules, mismo navLink— y se invoca en el grupo
social junto a renderChatsLink. Entra tambien en modules_view y en la lista de
/modules de backend.js, para poder apagarlo como cualquier otro modulo, con sus
etiquetas en el overlay.
Los estilos del modulo pasan a src/client/assets/styles/karvan.css. Estaban dentro
de OasisMobile.css, que en escritorio no se carga, asi que las salas se habrian
visto sin formato. Va como hoja propia siguiendo el patron de highlight.css, que
tampoco pertenece a ningun tema: asi el modulo se ve igual con cualquier tema y en
las dos plataformas.
Verificado: karvan.css sirve 200 y se carga en las dos plantillas, el enlace aparece
en el menu lateral, y en movil la rejilla de hexagonos sigue igual.
Una revision a fondo del arbol contra 0.9.5 saco varios fallos, unos heredados y
otros que introdujo la propia integracion. Verificados uno a uno antes de tocar.
Recursos referenciados que no existian (los introduje al adoptar vistas de 0.9.5
que los usan, mientras la rama los habia borrado):
- Los cuatro temas *-SNH.css. settings_view ofrece Dark, Clear, Matrix y Purple,
pero solo estaba OasisMobile: elegir cualquiera daba 404 y la app se quedaba sin
estilos. Ahora los cuatro responden 200.
- pdf.min.mjs, pdf.worker.min.mjs y pdf-viewer.js, referenciados desde seis vistas.
Regresiones revertidas a 0.9.5 verbatim en catorce ficheros. Las de fondo:
- larp_model perdio getGoverningPeriodId, que backend.js llama: el anuncio de
gobierno no salia nunca, con el TypeError tragado por un catch.
- courts_view y search_view tenian selected: false, que hyperscript SI serializa
como atributo y HTML interpreta como seleccionado. La forma de upstream, el
spread condicional, es la correcta.
- pm_model perdio includeDeleted, projects_model la validacion de deadline pasado,
jobs_model el desempate por timestamp, middleware el flag de debug HTTP.
forum_view pasa a 0.9.5 conservando el filtro hot. Esto arregla un fallo activo: la
vista de la rama declaraba un cuarto parametro topic y backend.js llama con cinco
argumentos, asi que al abrir una respuesta el %clave del hilo se colaba como tema y
el hilo salia VACIO. Upstream pasa los mismos cinco argumentos a una firma de tres y
JS los ignora, que es lo correcto.
chats_view pasa a 0.9.5 y se implementa replyTo de verdad. Estaba muerto de punta a
punta: backend.js no leia ctx.query.replyTo ni pasaba el cuarto argumento a
sendMessage, asi que ningun mensaje llegaba a tener replyTo y la cita no se
renderizaba jamas. Ahora la cadena esta completa —modelo, GET, POST y vista— con
indice msgById armado antes de mezclar con las encuestas, y sin gate de movil:
responder a un mensaje no es una funcion de movil.
aria-label: encontrada la causa. No es que hyperaxe lo ignore, es que hyperscript
solo asigna como propiedad y html-element solo serializa atributos de su tabla, en
la que aria-* no esta; data-* si tiene rama propia, por eso las tablas responsive
funcionaban. Se arregla con el escape hatch attrs:{}, sin tocar node_modules.
prepare.sh copia README.md y falla si no esta: backend.js lo lee con readFileSync
sin try/catch, de modo que sin el fichero el backend muere con ENOENT al arrancar.
Verificado con la app en marcha: 17 rutas OK, los cuatro recursos que faltaban
sirviendo 200, aria-label emitido en el HTML, e interfaz intacta (10 categorias,
50 modulos, 7 accesos rapidos, 0 etiquetas vacias).
backend.js pasa a la version de 0.9.5 y baja de 1549 a 16 lineas de divergencia.
Sin esto los modulos que el dev ha anadido estaban portados pero inaccesibles: no
tenian rutas. Ahora /polls, /blogs y /mentions responden.
Reinyectado de la rama: el enganche de fork_routes, los tres gates de movil (no
abrir navegador al arrancar, no matar el sbot al borrar la cadena), el selector de
chats de la barra lateral movil, y los globals de la interfaz — el filtro
Personal/Community, la visibilidad de los hexagonos y el avatar de la topbar.
Esos globals no aparecian al clasificar el diff y su perdida dejaba la home sin
hexagonos; detectado al comparar el HTML servido.
bottomBarPickerView (la pantalla de personalizar la barra) vivia en main_views y se
perdia al adoptar 0.9.5. Pasa a fork/hive_nav.js, junto al resto de la interfaz de
la rama, y main_views la reexporta en una linea.
housing se porta pero apagado (housingMod off). Mantenerlo fuera obligaba a editar
83 referencias de backend.js en cada release; asi el fichero queda igual que
upstream y el modulo no aparece en la interfaz. Se portan tambien contentPdf,
housing_model y housing_view para cerrar los requires.
Verificado con la app en marcha: 29 rutas OK, hexagonos 10/47 con los filtros
Personal y Community dando 5 y 5, topbar con avatar, 7 accesos rapidos, orden de
hojas correcto, y Karvan creando sala y sirviendo el panel de videollamada.
Quedaban tres rutas propias sueltas dentro de la cadena de upstream:
/settings/bottombar (GET y POST, la personalizacion de la barra inferior) y
/legacy/export en GET, que upstream solo tiene en POST.
Con esto backend.js queda sin ninguna ruta de la rama: 8899 lineas frente a las
9067 de partida, y el unico rastro son las 4 lineas del require de fork_routes
en el array de middleware.
Verificado: el router monta las 11 rutas y backend.js no conserva referencias
a identificadores movidos.
backend.js concentra las 577 rutas de upstream en una sola cadena fluida y se
mueve +905/-298 lineas por release. Las 8 rutas de Karvan, su modelo, el import
de vistas y las tres funciones de relay cross-device vivian intercaladas ahi,
asi que cada integracion las ponia en conflicto.
Pasan a src/backend/fork_routes.js, un router propio que se inserta en la cadena
de middleware justo antes del router de upstream; lo que no casa cae a next().
Las dependencias (cooler, pull, pmModel, checkMod, getViewerId) se inyectan en
vez de reconstruirse, para no abrir un segundo cliente muxrpc contra el sbot.
backend.js pasa de 9067 a 8932 lineas. Quedan 2 lineas de enganche en lugar de 137.
Verificado: el router monta las 8 rutas (/karvan, /karvan/create, /karvan/:id,
/karvan/:id/invite, /karvan/:id/msg, /karvan/:id/msgs y /karvan/:id/signal en GET
y POST) y no quedan referencias huerfanas en backend.js.
Makes a Karvan room work between two different phones once they're connected to a pub:
- karvan_model: rooms track remoteFeeds (SSB ids of other participants); addRemoteFeed/
getRemoteFeeds/anyRemoteRooms (feed-id validated, capped at MAX_MEMBERS).
- backend: inviting registers the invitee's feed; joining by link registers the inviter's
feed (read from the invite PM). Posting a message publishes a private 'karvan-relay' to
those feeds; an efficient LIVE log-stream subscriber (createLogStream old:false live:true)
ingests incoming relays and injects them into the local mirror room (dedup by mid,
skips own → no loop). WebRTC SIGNAL frames are NOT relayed (too many/slow for the log).
- Chosen over a muxrpc plugin because a classic pub only replicates the LOG (store-and-forward);
live muxrpc wouldn't reach the other phone. No SSB-startup changes → no boot risk.
Verified: boot OK with the live stream, invite/adopt register feeds, message posts + relay
publishes, server stays up, 16/16 tests. Cross-device delivery needs the user's 2-phone+pub test.
Note: text chat only — video still needs the wrapper camera permission (Fase 3).
Dead code (from the abandoned thumb-zone/Explore-sheet nav experiment):
- OasisMobile.css: removed ~90 lines of orphaned CSS (.oasis-bottombar-fork/.bb-fab-*,
.hive-sheet*/.fork-sheet*/.hsq-*, .omt-spacer, .hive-sheet-seg/.hs-seg, dead
.oasis-bottombar-fixed) — no element emits any of them.
- main_views.js: removed renderHiveSheet() (never called; sole emitter of that CSS).
- karvan_view.js: dropped dead export karvanShortId + unused karvanView param.
- Added a style for .karvan-msg-live (client emitted it with no rule).
Karvan security (from the review):
- GET /karvan/:id only adopts a mirror room on a real navigation (sec-fetch-dest
document / Accept text/html), not on <img>/subresources → fixes a CSRF that could
spam/evict the user's ephemeral rooms.
- Cap room.members at 50 (was unbounded; each poll echoed it back).
- Reject signal payloads >16KB (SDP/ICE are tiny) — anti memory-DoS.
- karvan.js: guard malformed {kind:desc} signals so one bad signal can't abort a poll batch.
Tests: 15/15 (added members-cap + oversized-payload). Verified: CSRF fix (nav=200,
subresource=302), pages unchanged after CSS removal, boot clean.
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).
The hexagon hive was rendered in the header on EVERY page (~210px), pushing real
content far down on Peers/Market/Inbox/etc. Now a middleware flag
(__OASIS_SHOW_HIVE__ = path is /activity or /) gates renderHiveNav so the hive is
the home hub only; other pages get just the fixed topbar and their content up top.
Personal/Community and the bottombar still navigate everywhere.
Navigation fixes:
- The bottom "Explore" sheet no longer blocks the top bar: closed state is
visibility:hidden (out of hit-testing), so the top identity buttons and page
content always receive taps (fixes "top buttons don't work").
- Top bar is now identity only (logo, avatar). The Personal/Community filter
moved into the Explore sheet, next to the hive, as a segmented control.
New module "Karvan" (self-contained; inspired by karvan-protocol ephemeral rooms):
- Ephemeral/temporary chat rooms held only in RAM, self-destructing on idle
(30 min) / absolute (2 h) TTL — nothing is written to disk.
- Server relay chat (RAM + polling) as the reliable path, plus a WebRTC
data-channel layer (perfect negotiation, HTTP signaling mailbox) for instant
P2P delivery; degrades to the relay if WebRTC is unavailable. Data-channel
only (no camera/mic) so no wrapper permission changes are needed.
- Files: models/karvan_model.js, views/karvan_view.js, client/public/js/karvan.js;
routes /karvan* + karvanMod config + nav entry (network) + karvanTitle i18n (11 langs).
Additive and gated by OASIS_MOBILE / karvanMod; Linux and the UX_OASIS branch untouched.
- Topbar: single fixed line [logo][Personal][Community][avatar] in one dark
tone (#121212) with gold accents only; the hive hexagons scroll below it.
- Hive: Personal/Community filter the home hive from any page; opening a
category shows its modules as a 2x2 grid of square buttons (a lone odd
button is centered instead of left-aligned).
- Chats: per-message reply (?replyTo=), chat switcher strip and quote banner;
the message rate limit is lifted on mobile.
- Forums: optional subtopics (?topic=) with threaded rendering.
- Bottombar: fixed Inbox - PM - Write - Search - Graphos - Peers.
- Turn the header Personal/Community tabs into links to
/activity?hive=personal|community, so they work on every page (they take
you to the home and filter the hexagons), not only while already on
/activity — no more dead buttons off the home.
- Drop the "All" tab: entering shows all 10 categories; clicking a filter
that is already active toggles it off and shows all again.
- Filter the hive server-side (renderHiveNav reads the request filter set
by the middleware) instead of the CSS radio-hack, and drop the now-dead
half-filter CSS. Active tab is highlighted via the .active class.
renderMobileTopbar read global.__OASIS_SELF_AVATAR__, but nothing ever
set it, so the top-right circle always fell back to the default avatar
(noticeable in the start/welcome flow, where the profile card showed the
real picture but the topbar circle did not).
Populate the global in the throttled refresh middleware from
about.image(self): build /image/256/<blob> when a picture exists, else
leave it null so the topbar uses the default avatar.
Rebase onto upstream 0.9.0. Mobile topbar (logo->home, avatar->profile),
hexagon category nav (hive) and bottom bar; remove the six top-bar
buttons (inbox/pm/publish/search/graphos/peers) that cluttered the header.
Theme OasisMobileUX carries topbar/hexagon/bottombar styles.
- Selectable Oasis-Mobile-UX theme; mobile.css kept intact
- Hexagon category launcher on home (10 categories with expandable modules)
- Customizable bottom bar (up to 4 shortcuts, Peers/Invites fixed)
- Empty states and collapsible activity filters