release: offline mode + local pass-and-play (hotseat) — proposed v1.12.0 #212

Merged
developer merged 79 commits from development into master 2026-07-07 14:40:43 +00:00
3 changed files with 31 additions and 1 deletions
Showing only changes of commit 05c445e4da - Show all commits
+13 -1
View File
@@ -1263,7 +1263,19 @@ the ad-banner slot. A **cold launch already in offline mode** boots from the per
profile (the profile is saved on every online adopt/refresh) — `bootstrap` skips the session profile (the profile is saved on every online adopt/refresh) — `bootstrap` skips the session
adoption and profile fetch that would otherwise hang with no network, and lands straight in the adoption and profile fetch that would otherwise hang with no network, and lands straight in the
offline lobby; without a cached profile (an install that was never online) it drops the sticky flag offline lobby; without a cached profile (an install that was never online) it drops the sticky flag
and boots online instead. The gateway registers the `.webmanifest` MIME type and boots online instead. Beyond the sticky toggle the app **auto-detects connectivity**: the
reactive flag carries an *auto* bit, so a self-entered offline (no network) is transient
(session-only, never persisted) and self-heals to online when the network returns, while a deliberate
one (the toggle, or the cold-start dialog's *Switch*) persists. At cold start `navigator.onLine ===
false` enters offline for the session; otherwise a single bounded reachability probe (a `profile.get`,
~3 s) decides — success boots online, a timeout on an eligible install raises a *No connection* dialog
(*Switch* = sticky offline, *Wait for network* = boot online with the reachability watcher retrying).
Mid-session the `window` `online`/`offline` events drive it — `offline` auto-enters, `online`
re-verifies reachability before returning — backed by a `navigator.onLine` poll because those events
are unreliable on some platforms (notably iOS PWAs). Offline is a real **transport kill switch**
(every gateway call is refused, so no traffic leaks); the reachability probe is the one call exempt
from it (it is the return-to-online mechanism), and the transient reachability watcher is suppressed
while offline. The gateway registers the `.webmanifest` MIME type
in-process (the distroless image has no `/etc/mime.types`). Hash-named `/assets/*` are served in-process (the distroless image has no `/etc/mime.types`). Hash-named `/assets/*` are served
`immutable` (a relaunch is a cache hit, not a re-download); the HTML shells are `immutable` (a relaunch is a cache hit, not a re-download); the HTML shells are
`no-cache` so a new deploy is picked up — both containers apply the same caching. An `no-cache` so a new deploy is picked up — both containers apply the same caching. An
+9
View File
@@ -268,6 +268,15 @@ the app quietly preloads the dictionaries for the player's enabled variants whil
(once installed) launches from a precached shell even with no network. The mode is device-scoped and (once installed) launches from a precached shell even with no network. The mode is device-scoped and
sticky across launches. sticky across launches.
The app also **enters offline mode on its own** when it cannot reach the network. On a cold launch
with no connection it switches to offline for that session; when the device is online but the gateway
stays silent for a few seconds it asks first — *No connection. Switch to offline mode?*, with
**Switch** (go offline) or **Wait for network** (keep retrying online). While the app is open, losing
the network — airplane mode — switches to offline automatically, and restoring it returns online by
itself. A self-entered offline is temporary: it reverts to online the moment the network is back, and
the next launch re-checks. A **deliberate** offline — the Settings toggle, or **Switch** in that
dialog — is the player's choice: it is kept, and never undone automatically.
### Social: friends, block, chat, nudge ### Social: friends, block, chat, nudge
Become friends in two ways: redeem a **one-time code** the other player issues (six Become friends in two ways: redeem a **one-time code** the other player issues (six
digits, valid for twelve hours), or send a **request to someone you have played digits, valid for twelve hours), or send a **request to someone you have played
+9
View File
@@ -273,6 +273,15 @@ e-mail) либо ввод фразы. Активные игры форфейтя
запускается из прекешированного шелла даже без сети. Режим привязан к устройству и сохраняется между запускается из прекешированного шелла даже без сети. Режим привязан к устройству и сохраняется между
запусками. запусками.
Приложение также **само включает офлайн-режим**, когда не может достучаться до сети. При холодном
запуске без связи оно переходит в офлайн на текущую сессию; когда устройство онлайн, но шлюз молчит
несколько секунд, оно сперва спрашивает — *Нет связи. Включить офлайн-режим?*, с выбором **Включить**
(уйти в офлайн) или **Ждать сеть** (продолжить попытки онлайн). Пока приложение открыто, потеря сети —
режим полёта — переключает в офлайн автоматически, а её восстановление само возвращает онлайн.
Самостоятельно включённый офлайн временный: он возвращается в онлайн, как только сеть появилась, и
следующий запуск проверяет заново. **Осознанный** офлайн — тумблер в Настройках или **Включить** в том
диалоге — это выбор игрока: он сохраняется и никогда не отменяется автоматически.
### Социальное: друзья, блок, чат, nudge ### Социальное: друзья, блок, чат, nudge
Подружиться можно двумя способами: погасить **одноразовый код**, который выпускает Подружиться можно двумя способами: погасить **одноразовый код**, который выпускает
другой игрок (шесть цифр, действует двенадцать часов), либо отправить **заявку другой игрок (шесть цифр, действует двенадцать часов), либо отправить **заявку