<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/packages/meshbay-hub/src/meshbay_hub/static/style.css, branch 0.21</title>
<subtitle>MeshBay — read-only public mirror</subtitle>
<id>https://git.meshbay.org/meshbay.git/atom?h=0.21</id>
<link rel='self' href='https://git.meshbay.org/meshbay.git/atom?h=0.21'/>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/'/>
<updated>2026-10-17T21:54:17Z</updated>
<entry>
<title>fix(spa): match results keep the theme's text color</title>
<updated>2026-10-17T21:54:17Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-17T21:54:17Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=8f9741955133858545905b0e66b8b2f90b000710'/>
<id>urn:sha1:8f9741955133858545905b0e66b8b2f90b000710</id>
<content type='text'>
Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix(hub): scope every :hover rule to devices that can hover</title>
<updated>2026-10-16T08:10:24Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-16T08:10:24Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=88f4ade0ee1e1a2b6011fd39320ede34d493929f'/>
<id>urn:sha1:88f4ade0ee1e1a2b6011fd39320ede34d493929f</id>
<content type='text'>
A tap left buttons in :hover on touchscreens (pager arrows, nav, player...).
All rules now sit in @media (hover: hover); test_hover_scoped.py holds it.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(auth): the recovery key never reaches the hub</title>
<updated>2026-10-15T12:25:00Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-15T12:25:00Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=28c77b7648b2a44a18be64ec44344d91cccfd742'/>
<id>urn:sha1:28c77b7648b2a44a18be64ec44344d91cccfd742</id>
<content type='text'>
Ticking "also e-mail it to me" at registration sent the recovery key R in
the register body, and the hub appended it to the verification e-mail: the
hub saw R in clear on its way out, and the resend door — no captcha — let
anyone who knew a pending username and address have the hub mail a
"recovery key" of their choosing.

The box is gone. The recovery screen offers "E-mail it to myself", a mailto:
link that opens the person's own mail application with the key filled in;
the desktop shell hands mailto: to the system (http, https and mailto only)
and the Android shell to a mail application (ACTION_SENDTO). The CLI drops
--email-recovery-key and prints the key, as before. The hub mails the code
alone, and refuses a register that still carries a recovery_key rather than
dropping it, so an older client offering the option cannot tell someone
their key was sent when it was not.

A mailbox holding R remains, with the reset code that reaches the same
mailbox, enough to recover the account's identities; the link says so, and
it is the person's choice.

Checked in Chrome and Firefox (headless, the real page against a stubbed
hub) and by the CLI's end-to-end registration against a local hub. The
Android change was not built here, and the desktop link was not clicked in
the application.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(hub): one account, several linked nodes</title>
<updated>2026-10-15T07:33:28Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-15T07:33:28Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=1e8eae1f3de765fcd8163716de6e5fe5aab5a034'/>
<id>urn:sha1:1e8eae1f3de765fcd8163716de6e5fe5aab5a034</id>
<content type='text'>
An account links up to MAX_NODES_PER_ACCOUNT node keys (node_keys table)
instead of the one users.pk_node_ed25519; the migration carries each
account's key over and the downgrade keeps the last one linked.
/v1/nodes/auth accepts any linked key, and its token names the key that
won it (nk). PUT /me/node_key adds a key, idempotently, 409 past the
limit; DELETE /me/node_key names the key: a browser session any of its
own, a node only its own. Unlinking a key closes that node's socket and
refuses its tokens at once, on REST and on the socket; the account's other
nodes are untouched. /pubkeys no longer gives a node key to other accounts,
and gives the caller its last linked one, which installed desktop apps read.

The node reports waiting_for_node_key while its key is unlinked and signs
in again as soon as the hub says so, so a key linked again is back within
seconds; unlinking itself signs in first to hold a token naming its key.

Profile -&gt; Linked nodes lists each node (connected, last seen, IP, linked
since, This machine in the desktop app) with Copy and Unlink, and adds a
key by hand. The Node page banner, Create group and the desktop app add
this machine's key instead of replacing another's. Messages that pointed
at Settings -&gt; Link Node point at Profile -&gt; Linked nodes.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(node): skip a file the disk stops answering for, then pause its root</title>
<updated>2026-10-14T08:17:49Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-14T08:17:49Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=80ac882346b474bb7ea4e8c8afd4694bd13dd9dd'/>
<id>urn:sha1:80ac882346b474bb7ea4e8c8afd4694bd13dd9dd</id>
<content type='text'>
A Windows tester's scan stuck for good on one directory of a large disk:
one read that never returned held the indexer's only thread, and with it
every root behind that one.

- A disk call is timed by its silence, not its length: each directory
  entry listed and each megabyte read counts as an answer. After 60 s of
  silence the call is abandoned on its daemon thread, the file is noted
  unread and the scan goes on.
- Three silent files in a row pause the root (not persisted). Resume
  skips the files already known to give no answer; a restart, a replug
  or a change to the file retries them.
- The walk is per directory with os.scandir: a subdirectory that cannot
  be listed costs itself, and a listing that stops answering pauses the
  root at once. A scan no longer stats anything from the event loop.
- The log names the file after 10 s of silence, the indexing band shows
  it, and Group settings shows the paused root, where it stuck and the
  unread files with their reason, on the node's machine only.
- generate_http_api.py writes LF on Windows too.

Verified with real kernel-blocked opens (an unacknowledged oplock) in the
installed frozen app.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix: keep the photo lightbox's close button on a phone screen</title>
<updated>2026-10-12T10:57:49Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-12T10:57:49Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=13e7980071ab11b07b5d473e43506c6cb4ab637e'/>
<id>urn:sha1:13e7980071ab11b07b5d473e43506c6cb4ab637e</id>
<content type='text'>
The bar was 457 px wide and pushed the close button to 397..437 px, off a
360 px phone. Delete leaves the lightbox (it stays on the tile's menu:
right-click, or press and hold), and below 768 px the bar drops the file
name, the zoom label and 100%.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat: keep the sidebar for groups; search in the nav, the rest in the user menu</title>
<updated>2026-10-11T23:27:00Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-11T23:27:00Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=3324b4eb701e34f64e859dd90937793ccf7f75c5'/>
<id>urn:sha1:3324b4eb701e34f64e859dd90937793ccf7f75c5</id>
<content type='text'>
Search is an icon in the nav, left of the tray button and the bell, and marks
itself current on its page. Administration, Node, Create group and Android
Sync moved to the user menu, between Settings and the theme, each under the
condition it had in the sidebar. The sidebar keeps Public groups and the
groups.

On a phone, a tablet or the Android application the menu trigger is the
avatar alone (max-width 768px or a coarse pointer); the name is the dropdown's
first line, one line with an ellipsis. Measured: a 20-character handle put the
trigger 159 px off a 320 px screen with search and transfers in the nav, and a
64-character one pushed the dropdown 122 px off the left.

Creating a group is a desktop-application feature by design: a hand-typed
#/create-group no longer opens the form in a browser, and QUICKSTART step 6
now says to use the desktop application instead of the browser.

test_layout_responsive read only the first 768px media block; it reads them
all now.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat: let the operator pause and resume a root's indexing (MNP 6.2)</title>
<updated>2026-10-11T22:17:32Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-11T22:17:32Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=14911aae21ec4975f7a805b91e3c4867cb41974b'/>
<id>urn:sha1:14911aae21ec4975f7a805b91e3c4867cb41974b</id>
<content type='text'>
A whole-root walk now checks its root before every file: removed or
ejected, it stops instead of reading the drive to the end; paused, it
finishes from the hash cache alone. A paused root is not watched, not
swept by reconcile and survives a restart (roster), its indexed files
stay served. Resume runs the reconcile sweep over the root, so entries
and their enrichment are kept.

Signed root_pause / root_resume over MNP, loopback routes, CLI
`root pause|resume`, a pause button on the indexing dock and
pause/resume in the roots table of Group settings.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(hub): tell the person at sign-up what the hub keeps and why</title>
<updated>2026-10-11T21:43:35Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-11T21:43:34Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=f6f107e02c7a4aa7326c9a82310a239327d81ed6'/>
<id>urn:sha1:f6f107e02c7a4aa7326c9a82310a239327d81ed6</id>
<content type='text'>
A line under the Register button: creating an account accepts the hub's
terms of use, and the law requires the hub to keep the connection log (IP
address, date, action) for one year, even after the account is deleted. It
links to the legal pages of the hub in use, so a self-hosted hub shows its
own operator's documents.

A notice, not a checkbox: the account rests on the contract and the log on a
legal obligation, so there is no consent to ask for, and one that blocks
sign-up would be neither free nor withdrawable.

legalUrl() moves to platform.js, shared by the sidebar and the form.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(photos): show a phone's clips in their albums</title>
<updated>2026-10-10T13:26:45Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-10T13:26:45Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=1521cc1ac0cca7ee8786056f84fa399d5cc268f9'/>
<id>urn:sha1:1521cc1ac0cca7ee8786056f84fa399d5cc268f9</id>
<content type='text'>
Videos in a photo folder are thumbnailed by the node, counted and marked in
the album, and played in the group's video player from the lightbox; the
slideshow passes them by.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
</feed>
