Commit Graph
7 Commits
Author SHA1 Message Date
BFlat e7ae0f4426 M9: share links can comment: a comment access level beside edit and view (#1525) (#1576)
Someone who joins with a comment link (or its join code) sees the file live and adds, replies to, reacts to and resolves comment threads, but can't change the design: their app refuses other edits and the server accepts a comment link's batch only when every change in it touches comment threads. Sharing online makes a comment link and code beside the edit and view ones; the Share popover offers Can edit, Can comment and Can view, and the commenter's toolbar shows a Can comment badge with Move, Hand and Comment.

Backward compatible: clients announce the comments word; one that doesn't is welcomed with a comment link as a viewer and gets comment links listed as view links, a level this build doesn't know reads as view, and an older server that can't make a comment link leaves the share without one.
2026-10-30 07:29:40 +07:00
BFlat f6ccef0c5d M9: a per-address budget for server admin requests, and join codes found by hash (#1075) (#1552)
* M9: a per-address budget for server admin requests, and join codes found by hash (#1075)

* M9: the server tests share one snapshot and address helper (#1075)
2026-10-30 00:20:57 +07:00
BFlat 436cfa1b96 M9: the replay log is bounded in bytes by default (#1069) (#1524)
The batches a session keeps for apps that reconnect were bounded only by count on a desktop host
and a private figcraft-server (`max_log_bytes` defaulted to usize::MAX). It now defaults to
64 MiB, and figcraft-server takes it from a new `max_log_mb` setting (default 64; open to the
public, also at most a quarter of `max_file_mb` as before). An app behind the trimmed log catches
up with a snapshot, as it already did past the count limits. The protocol is unchanged.

Nine 8 MiB renames with default limits: all 75.5 MB kept before, 58.7 MB after.

Fixes #1069
2026-10-29 20:02:46 +07:00
bflatastic 6720ea4a21 M9: share with a join code: online through the built-in server or on the local network
The Share popover is one flow: Online (the file is published to the server in
Preferences and the server names its links with short codes) or Local network
(the app hosts; the code carries its address and the session's secret), one
Start sharing button, the code large with Copy code and Copy link, who is here,
can edit / can view, and Stop sharing. Join with a code is one field in the
popover, on the home screen and in the Join dialog, for a code of either kind
or an invite link.

Protocol (within version 2, new variants last): Resolve / Resolved and Admin
code. The server keeps a stretched hash and the wrapped token, never the code,
and limits wrong codes per address (with a lockout) and for everyone. Older
servers leave the links in place of a code; older apps join by link.

collab.share, collab.join {code}, code and share in collab.peers; the server
preference defaults to the built-in server and can be reset or turned off.
2026-10-12 19:42:28 +07:00
bflatastic b7af7c7ef7 M9: open hosting mode for public figcraft-server
Config-gated (open_publish): anyone publishes without the server key and
gets an owner token (128-bit, shown once, stored hashed) that manages only
that file. Per-address limits (X-Forwarded-For only from trusted_proxy,
bounded tables), global caps, idle expiry, reports, persisted blocks,
files list --sort, check, GET /healthz on the same listener, startup
warnings. The app asks the server first, publishes without a key when it
is open, shows the owner token once, the host/terms line, the expiry date
and a report button; collab.serverInfo, collab.manageFile, collab.report
and pref.publishServer for MCP/CLI. Protocol additions stay within
version 2, gated like signals.
2026-10-12 11:40:03 +07:00
bflatastic def6f84b22 M11: plugin directory on figcraft-server
A self-hosted plugin directory, with no third-party service: `figcraft-server` keeps plugin bundles,
the app browses, installs and updates from it, and `figcraft-cli` publishes to it.

- **Bundles** (`figcraft_plugin::bundle`): a plugin's manifest, module and up to 32 plain-named
  assets in one uncompressed, length-prefixed binary form (nothing can expand beyond the bytes
  sent). Its SHA-256 names it. `Bundle::decode` never allocates beyond its input and refuses
  trailing bytes; `Bundle::check` parses the manifest (refusing a plugin API this build doesn't
  run), requires a version of 1-4 numbers, compiles the module without running it (only the
  sandbox's imports allowed) and checks asset names (no paths, no dot files, no Windows device
  names, unique ignoring case). Manifests gain an optional `author`.
- **Protocol**: a new connection kind next to managing and team-library connections:
  `OpenPlugins {key}` then `Plugins {list | fetch | publish | unpublish}`. Browsing needs no
  credential; publishing and unpublishing need the server key (a wrong key is refused). Older
  servers refuse the connection and the app says the server has no plugin directory. The protocol
  version is unchanged; old clients are unaffected.
- **Server** (`apps/figcraft-server/src/directory.rs`): `<data>/plugins/index.json` plus
  `<data>/plugins/<sha256>.bin`, so no publisher-chosen name reaches the file system. Every publish
  is checked in full and must be a newer version; caps `max_plugins` (versions, 0 turns it off),
  `max_plugin_mb` (<= 32), `max_plugins_mb`. Fetches re-hash the file before sending (a damaged
  bundle is never sent) and share a download budget (~32 MiB/s) so a flood is refused, not queued.
  Damaged index entries are skipped and reported, never deleted; an unreadable index lists nothing
  and refuses writes until the operator fixes it. Operator moderation:
  `figcraft-server plugins [list]` and `plugins remove ID [--version V]` (offline or through the
  running server). Logs name ids and versions, never keys.
- **App**: Plugins > Manage plugins gets Installed / Browse tabs. Browse lists a server's plugins
  (version, author as typed, size, access) with a search; nothing is fetched until Browse is
  pressed. Install / Update open a confirmation listing the permissions asked for, the source and
  the SHA-256; only its button downloads. The download must match the listed SHA-256 (and the one
  shown), then is checked like an imported plugin before anything is written. Installed plugins
  live per user under `<settings>/FigCraft/Plugins/<hash of id>/` and run in the same sandbox;
  Remove deletes the folder.
- **Commands**: `plugin.directory.list {server?, query?}`, `plugin.directory.install {id, version?,
  confirm, server?, sha256?}` (refused without `confirm: true`; never opens a dialog),
  `plugin.directory.publish {path | plugin, server}`, `plugin.directory.unpublish {id, version?,
  server}`. `ui.set {pluginsTab, pluginConfirm}` on the control channel.
- **CLI**: `figcraft-cli plugin publish FOLDER --server ws://host:port/` with the key from
  `FIGCRAFT_SERVER_KEY` (or `?key=`), never printed.
- Docs: plugins.md (directories, publishing, commands, manifest), server.md (operating the
  directory: access, checks, caps, moderation, backups, security), collab-protocol.md, mcp.md,
  cli.md, control-protocol.md, target-app-parity area 18 and Ecosystem, ROADMAP, roadmap.md M11,
  gaps.md gap 6. Plugins & widgets 55%/32% -> 60%/35%, 10-30 h -> 8-26 h.
2026-10-12 05:28:53 +07:00
BFlat 07fa4d92ed M9: standalone collaboration server with share links and permissions (#112)
figcraft-server hosts many files over the same hub the app uses for sessions, persists each as a checksummed snapshot plus an append-only log (synced before replies, compacted, damaged files skipped and reported) so restarts lose nothing confirmed, and gives per-file share links with edit or view access (hashed 128-bit tokens, revocable). The app can publish a file to a server and join server-hosted files; view-only tabs refuse edits. Protocol version 2.
2026-10-11 10:19:03 +07:00