v6.8.6: desktop 1.0.4 downloads, and a roadmap without status labels

This commit is contained in:
lockbitchat
2026-09-23 23:33:33 -04:00
parent 02380a7ecd
commit eac3009339
54 changed files with 334 additions and 475 deletions
+7
View File
@@ -1,5 +1,12 @@
# Changelog
## v6.8.6 — Desktop 1.0.4 downloads, and a simpler roadmap
The download buttons now give you desktop version 1.0.4, which fetches its relay
password from the site like the web app does. The roadmap no longer puts a label
such as "Released" or "Planned" on each step; the timeline shows where each one
stands on its own.
## v6.8.5 — The relay password is no longer built into the app
When two people cannot connect directly, calls and chats go through our relay
+1 -1
View File
@@ -9,7 +9,7 @@
No accounts. No servers storing your messages. No installation required.
[![License: MIT](https://img.shields.io/badge/License-MIT-f0892a.svg)](LICENSE)
[![Version](https://img.shields.io/badge/version-6.8.5-3ecf8e.svg)](CHANGELOG.md)
[![Version](https://img.shields.io/badge/version-6.8.6-3ecf8e.svg)](CHANGELOG.md)
[![Get it from the Snap Store](https://snapcraft.io/securebit-chat/badge.svg)](https://snapcraft.io/securebit-chat)
[![PWA](https://img.shields.io/badge/PWA-installable-3ecf8e.svg)](#install-as-an-app)
[![Encryption](https://img.shields.io/badge/crypto-ECDH%20P--384%20%C2%B7%20AES--256--GCM-blue.svg)](#security-model)
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/ar/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790208243441"></script>
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790208243441"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790208243441"></script>
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790208243441"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790208243441"></script>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/ar.js?v=1790208243441"></script>
<script type="module" src="/src/i18n/dict/ar.js?v=1790219928897"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790208243441"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790208243441"></script>
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790208243441"></script>
<script type="module" src="/dist/app.js?v=1790208243441"></script>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790208243441"></script>
<script src="/src/pwa/install-prompt.js?v=1790208243441" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790208243441" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790208243441"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
</body>
</html>
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/de/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790208243441"></script>
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790208243441"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790208243441"></script>
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790208243441"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790208243441"></script>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/de.js?v=1790208243441"></script>
<script type="module" src="/src/i18n/dict/de.js?v=1790219928897"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790208243441"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790208243441"></script>
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790208243441"></script>
<script type="module" src="/dist/app.js?v=1790208243441"></script>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790208243441"></script>
<script src="/src/pwa/install-prompt.js?v=1790208243441" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790208243441" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790208243441"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
</body>
</html>
+38 -38
View File
File diff suppressed because one or more lines are too long
+3 -3
View File
File diff suppressed because one or more lines are too long
Vendored
+2 -2
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -7,7 +7,7 @@ this document describes.
| | |
| --- | --- |
| Release | v6.8.5 |
| Release | v6.8.6 |
| Protocol version | 4.1 |
| Ratchet wire version | 1 |
@@ -347,5 +347,5 @@ no leg may stop a capture it borrowed.
## Scope
This describes the browser implementation as it stands in v6.8.5. It is not a
This describes the browser implementation as it stands in v6.8.6. It is not a
substitute for independent cryptographic review.
+2 -2
View File
@@ -153,7 +153,7 @@
</thead>
<tbody><tr>
<td>Release</td>
<td>v6.8.5</td>
<td>v6.8.6</td>
</tr>
<tr>
<td>Protocol version</td>
@@ -486,7 +486,7 @@
shared across every leg, and stopped when the call, the group or the tab ends;
no leg may stop a capture it borrowed.</p>
<h2 id="scope">Scope</h2>
<p>This describes the browser implementation as it stands in v6.8.5. It is not a
<p>This describes the browser implementation as it stands in v6.8.6. It is not a
substitute for independent cryptographic review.</p>
<nav class="more">
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/es/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790208243441"></script>
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790208243441"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790208243441"></script>
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790208243441"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790208243441"></script>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/es.js?v=1790208243441"></script>
<script type="module" src="/src/i18n/dict/es.js?v=1790219928897"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790208243441"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790208243441"></script>
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790208243441"></script>
<script type="module" src="/dist/app.js?v=1790208243441"></script>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790208243441"></script>
<script src="/src/pwa/install-prompt.js?v=1790208243441" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790208243441" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790208243441"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
</body>
</html>
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/fa/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790208243441"></script>
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790208243441"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790208243441"></script>
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790208243441"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790208243441"></script>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/fa.js?v=1790208243441"></script>
<script type="module" src="/src/i18n/dict/fa.js?v=1790219928897"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790208243441"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790208243441"></script>
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790208243441"></script>
<script type="module" src="/dist/app.js?v=1790208243441"></script>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790208243441"></script>
<script src="/src/pwa/install-prompt.js?v=1790208243441" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790208243441" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790208243441"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
</body>
</html>
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/fr/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790208243441"></script>
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790208243441"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790208243441"></script>
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790208243441"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790208243441"></script>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/fr.js?v=1790208243441"></script>
<script type="module" src="/src/i18n/dict/fr.js?v=1790219928897"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790208243441"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790208243441"></script>
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790208243441"></script>
<script type="module" src="/dist/app.js?v=1790208243441"></script>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790208243441"></script>
<script src="/src/pwa/install-prompt.js?v=1790208243441" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790208243441" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790208243441"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
</body>
</html>
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/he/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790208243441"></script>
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790208243441"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790208243441"></script>
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790208243441"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790208243441"></script>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/he.js?v=1790208243441"></script>
<script type="module" src="/src/i18n/dict/he.js?v=1790219928897"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790208243441"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790208243441"></script>
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790208243441"></script>
<script type="module" src="/dist/app.js?v=1790208243441"></script>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790208243441"></script>
<script src="/src/pwa/install-prompt.js?v=1790208243441" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790208243441" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790208243441"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
</body>
</html>
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/hi/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790208243441"></script>
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790208243441"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790208243441"></script>
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790208243441"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790208243441"></script>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/hi.js?v=1790208243441"></script>
<script type="module" src="/src/i18n/dict/hi.js?v=1790219928897"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790208243441"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790208243441"></script>
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790208243441"></script>
<script type="module" src="/dist/app.js?v=1790208243441"></script>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790208243441"></script>
<script src="/src/pwa/install-prompt.js?v=1790208243441" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790208243441" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790208243441"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
</body>
</html>
+18 -18
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790208243441"></script>
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790208243441"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790208243441"></script>
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,18 +287,18 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790208243441"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790208243441"></script>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790208243441"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790208243441"></script>
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -486,12 +486,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790208243441"></script>
<script type="module" src="/dist/app.js?v=1790208243441"></script>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790208243441"></script>
<script src="/src/pwa/install-prompt.js?v=1790208243441" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790208243441" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790208243441"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
</body>
</html>
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/ko/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790208243441"></script>
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790208243441"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790208243441"></script>
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790208243441"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790208243441"></script>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/ko.js?v=1790208243441"></script>
<script type="module" src="/src/i18n/dict/ko.js?v=1790219928897"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790208243441"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790208243441"></script>
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790208243441"></script>
<script type="module" src="/dist/app.js?v=1790208243441"></script>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790208243441"></script>
<script src="/src/pwa/install-prompt.js?v=1790208243441" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790208243441" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790208243441"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
</body>
</html>
-5
View File
@@ -105,11 +105,6 @@
"roadmap.progress": "أُنجزت {shipped} من أصل {total} محطّة",
"roadmap.upcoming": "{upcoming} في الطريق",
"roadmap.keyFeatures": "أبرز المزايا",
"roadmap.status.released": "صدرت",
"roadmap.status.current": "الحالية",
"roadmap.status.dev": "قيد التطوير",
"roadmap.status.planned": "مُخطّطة",
"roadmap.status.research": "قيد البحث",
"hero.headlineTop": "خطٌّ مباشر",
"hero.headlineBottom": "لا يقرأه إلّا أنتما.",
"hero.subheading": "تُولَّد المفاتيح على جهازك وتُتبادَل ندّاً لندّ. بلا حسابات وبلا خوادم تحفظ رسائلك.",
-5
View File
@@ -105,11 +105,6 @@
"roadmap.progress": "{shipped} von {total} Meilensteinen erreicht",
"roadmap.upcoming": "{upcoming} in Arbeit",
"roadmap.keyFeatures": "Kernfunktionen",
"roadmap.status.released": "Veröffentlicht",
"roadmap.status.current": "Aktuell",
"roadmap.status.dev": "In Entwicklung",
"roadmap.status.planned": "Geplant",
"roadmap.status.research": "Forschung",
"hero.headlineTop": "Eine direkte Leitung,",
"hero.headlineBottom": "die nur Sie beide lesen können.",
"hero.subheading": "Die Schlüssel entstehen auf Ihrem Gerät und werden direkt zwischen den Geräten ausgetauscht. Keine Konten, keine Server, die Ihre Nachrichten speichern.",
-5
View File
@@ -100,11 +100,6 @@
"roadmap.progress": "{shipped} of {total} milestones shipped",
"roadmap.upcoming": "{upcoming} on the way",
"roadmap.keyFeatures": "Key features",
"roadmap.status.released": "Released",
"roadmap.status.current": "Current",
"roadmap.status.dev": "In development",
"roadmap.status.planned": "Planned",
"roadmap.status.research": "Research",
"hero.headlineTop": "A direct line",
"hero.headlineBottom": "only you two can read.",
"hero.subheading": "Keys are generated on your device and exchanged peer-to-peer. No accounts, no servers storing your messages.",
-5
View File
@@ -105,11 +105,6 @@
"roadmap.progress": "{shipped} de {total} hitos completados",
"roadmap.upcoming": "{upcoming} en camino",
"roadmap.keyFeatures": "Funciones clave",
"roadmap.status.released": "Publicado",
"roadmap.status.current": "Actual",
"roadmap.status.dev": "En desarrollo",
"roadmap.status.planned": "Planificado",
"roadmap.status.research": "Investigación",
"hero.headlineTop": "Una línea directa",
"hero.headlineBottom": "que solo leéis vosotros dos.",
"hero.subheading": "Las claves se generan en tu dispositivo y se intercambian directamente entre pares. Sin cuentas y sin servidores que guarden tus mensajes.",
-5
View File
@@ -105,11 +105,6 @@
"roadmap.progress": "{shipped} از {total} نقطهٔ عطف انجام شد",
"roadmap.upcoming": "{upcoming} در راه است",
"roadmap.keyFeatures": "ویژگی‌های کلیدی",
"roadmap.status.released": "منتشر شد",
"roadmap.status.current": "کنونی",
"roadmap.status.dev": "در دست توسعه",
"roadmap.status.planned": "برنامه‌ریزی‌شده",
"roadmap.status.research": "پژوهش",
"hero.headlineTop": "خطی مستقیم",
"hero.headlineBottom": "که فقط شما دو نفر می‌خوانید.",
"hero.subheading": "کلیدها روی دستگاه شما ساخته و همتا‌به‌همتا مبادله می‌شوند. بدون حساب، بدون سروری که پیام‌هایتان را نگه دارد.",
-5
View File
@@ -100,11 +100,6 @@
"roadmap.progress": "{shipped} jalons sur {total} atteints",
"roadmap.upcoming": "{upcoming} à venir",
"roadmap.keyFeatures": "Fonctions clés",
"roadmap.status.released": "Publié",
"roadmap.status.current": "En cours",
"roadmap.status.dev": "En développement",
"roadmap.status.planned": "Planifié",
"roadmap.status.research": "Recherche",
"hero.headlineTop": "Une ligne directe",
"hero.headlineBottom": "que vous seuls pouvez lire.",
"hero.subheading": "Les clés sont créées sur votre appareil et échangées directement entre pairs. Aucun compte, aucun serveur ne conserve vos messages.",
-5
View File
@@ -105,11 +105,6 @@
"roadmap.progress": "{shipped} מתוך {total} אבני דרך הושלמו",
"roadmap.upcoming": "{upcoming} בדרך",
"roadmap.keyFeatures": "יכולות מרכזיות",
"roadmap.status.released": "שוחרר",
"roadmap.status.current": "נוכחי",
"roadmap.status.dev": "בפיתוח",
"roadmap.status.planned": "מתוכנן",
"roadmap.status.research": "מחקר",
"hero.headlineTop": "קו ישיר",
"hero.headlineBottom": "שרק שניכם יכולים לקרוא.",
"hero.subheading": "המפתחות נוצרים במכשיר שלכם ומוחלפים עמית־לעמית. בלי חשבונות, בלי שרתים ששומרים את ההודעות.",
-5
View File
@@ -100,11 +100,6 @@
"roadmap.progress": "{total} में से {shipped} पड़ाव पूरे",
"roadmap.upcoming": "{upcoming} बाक़ी",
"roadmap.keyFeatures": "मुख्य विशेषताएँ",
"roadmap.status.released": "जारी",
"roadmap.status.current": "अभी चालू",
"roadmap.status.dev": "विकास में",
"roadmap.status.planned": "नियोजित",
"roadmap.status.research": "शोध",
"hero.headlineTop": "एक सीधी लाइन,",
"hero.headlineBottom": "जिसे सिर्फ़ आप दोनों पढ़ सकें।",
"hero.subheading": "कुंजियाँ आपके उपकरण पर बनती हैं और सीधे दोनों पक्षों के बीच बदली जाती हैं। न कोई खाता, न कोई सर्वर जो आपके संदेश रखे।",
-5
View File
@@ -100,11 +100,6 @@
"roadmap.progress": "{total}개 중 {shipped}개 완료",
"roadmap.upcoming": "{upcoming}개 남음",
"roadmap.keyFeatures": "주요 기능",
"roadmap.status.released": "출시됨",
"roadmap.status.current": "진행 중",
"roadmap.status.dev": "개발 중",
"roadmap.status.planned": "예정",
"roadmap.status.research": "연구",
"hero.headlineTop": "두 사람만 읽을 수 있는",
"hero.headlineBottom": "직통 회선.",
"hero.subheading": "키는 여러분의 기기에서 만들어지고 두 기기 사이에서 곧바로 교환됩니다. 계정도 없고 메시지를 보관하는 서버도 없습니다.",
-5
View File
@@ -105,11 +105,6 @@
"roadmap.progress": "Пройдено {shipped} из {total} этапов",
"roadmap.upcoming": "{upcoming} впереди",
"roadmap.keyFeatures": "Ключевые возможности",
"roadmap.status.released": "Выпущено",
"roadmap.status.current": "Текущий",
"roadmap.status.dev": "В разработке",
"roadmap.status.planned": "Запланировано",
"roadmap.status.research": "Исследование",
"hero.headlineTop": "Прямая линия,",
"hero.headlineBottom": "которую прочитаете только вы двое.",
"hero.subheading": "Ключи создаются на вашем устройстве и передаются напрямую между участниками. Без учётных записей и без серверов, хранящих ваши сообщения.",
-5
View File
@@ -105,11 +105,6 @@
"roadmap.progress": "Пройдено {shipped} з {total} етапів",
"roadmap.upcoming": "{upcoming} попереду",
"roadmap.keyFeatures": "Ключові можливості",
"roadmap.status.released": "Випущено",
"roadmap.status.current": "Поточний",
"roadmap.status.dev": "У розробці",
"roadmap.status.planned": "Заплановано",
"roadmap.status.research": "Дослідження",
"hero.headlineTop": "Пряма лінія,",
"hero.headlineBottom": "яку прочитаєте лише ви двоє.",
"hero.subheading": "Ключі створюються на вашому пристрої й передаються напряму між учасниками. Без облікових записів і без серверів, що зберігають ваші повідомлення.",
-5
View File
@@ -105,11 +105,6 @@
"roadmap.progress": "{total} میں سے {shipped} سنگِ میل مکمل",
"roadmap.upcoming": "{upcoming} راستے میں",
"roadmap.keyFeatures": "نمایاں خصوصیات",
"roadmap.status.released": "جاری ہوا",
"roadmap.status.current": "موجودہ",
"roadmap.status.dev": "زیرِ تعمیر",
"roadmap.status.planned": "منصوبہ بند",
"roadmap.status.research": "تحقیق",
"hero.headlineTop": "ایک سیدھی لکیر",
"hero.headlineBottom": "جسے صرف آپ دونوں پڑھ سکتے ہیں۔",
"hero.subheading": "کلیدیں آپ کے آلے پر بنتی ہیں اور ہم‌سطح تبادلہ ہوتا ہے۔ نہ اکاؤنٹ، نہ کوئی سرور جو آپ کے پیغام محفوظ کرے۔",
-5
View File
@@ -100,11 +100,6 @@
"roadmap.progress": "已完成 {total} 个里程碑中的 {shipped} 个",
"roadmap.upcoming": "还有 {upcoming} 个",
"roadmap.keyFeatures": "核心功能",
"roadmap.status.released": "已发布",
"roadmap.status.current": "进行中",
"roadmap.status.dev": "开发中",
"roadmap.status.planned": "已规划",
"roadmap.status.research": "研究中",
"hero.headlineTop": "一条只有你们两人",
"hero.headlineBottom": "才能读懂的直连线路。",
"hero.subheading": "密钥在你的设备上生成,并在两端之间直接交换。无需账号,没有服务器保存你的消息。",
+7 -7
View File
@@ -1,10 +1,10 @@
{
"version": "1790208243441",
"buildVersion": "1790208243441",
"appVersion": "6.8.5",
"buildTime": "2026-09-24T00:04:03.480Z",
"buildId": "1790208243441-f39e902",
"gitHash": "f39e902",
"version": "1790219928897",
"buildVersion": "1790219928897",
"appVersion": "6.8.6",
"buildTime": "2026-09-24T03:18:48.935Z",
"buildId": "1790219928897-02380a7",
"gitHash": "02380a7",
"generated": true,
"generatedAt": "2026-09-24T00:04:03.481Z"
"generatedAt": "2026-09-24T03:18:48.936Z"
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "securebit-chat",
"version": "6.8.5",
"version": "6.8.6",
"description": "Secure P2P Communication Application with End-to-End Encryption",
"main": "index.html",
"scripts": {
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/ru/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790208243441"></script>
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790208243441"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790208243441"></script>
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790208243441"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790208243441"></script>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/ru.js?v=1790208243441"></script>
<script type="module" src="/src/i18n/dict/ru.js?v=1790219928897"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790208243441"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790208243441"></script>
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790208243441"></script>
<script type="module" src="/dist/app.js?v=1790208243441"></script>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790208243441"></script>
<script src="/src/pwa/install-prompt.js?v=1790208243441" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790208243441" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790208243441"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
</body>
</html>
+1 -1
View File
@@ -1696,7 +1696,7 @@ import { GroupCallMedia, mediaErrorCode } from './group/groupCallMedia.js';
// /download/v0.3.0/SecureBit.Chat_0.1.0_x64-setup.exe, a file that never
// existed, and the download 404s. A pinned tag keeps serving a real
// installer instead.
const SB_DESKTOP_VERSION = '1.0.3';
const SB_DESKTOP_VERSION = '1.0.4';
const SB_DESKTOP_RELEASE = `https://github.com/SecureBitChat/securebit-desktop/releases/download/v${SB_DESKTOP_VERSION}`;
const DOWNLOADS = {
mac: { name: 'macOS', format: '.dmg · Apple Silicon & Intel', icon: 'fab fa-apple', url: `${SB_DESKTOP_RELEASE}/SecureBit.Chat_${SB_DESKTOP_VERSION}_x64.dmg` },
+1 -1
View File
@@ -5,7 +5,7 @@
// The tag is pinned rather than using /releases/latest/download/: the filenames
// carry the version, so a `latest` link 404s the moment a newer release exists,
// whereas a pinned tag keeps serving a working (if older) installer.
const DESKTOP_VERSION = '1.0.3';
const DESKTOP_VERSION = '1.0.4';
const DESKTOP_RELEASE = `https://github.com/SecureBitChat/securebit-desktop/releases/download/v${DESKTOP_VERSION}`;
const DownloadApps = () => {
+8 -32
View File
@@ -44,33 +44,21 @@ function Roadmap() {
features: tList(`roadmap.${d.k}.features`)
}));
// `rgb` is the same colour as `color`, published as bare channels. The pill draws
// its fill and border from it at low alpha, and there is no way to add an alpha to
// a colour that a custom property has already resolved — hence the pair, which has
// to be kept in step.
// Three forms of the same status colour, because they are used three ways and only
// one of them is text. `color` is the word — it darkens in the light theme so it can
// be read on white. `solid` is the dot, which is a mark rather than a label and
// stays the brand colour in both themes. `rgb` is the channels, for the pill's fill
// and border at low alpha. The three have to be kept in step.
// The status of a milestone is shown by its marker on the timeline and the colour of
// its bullets, not by a word: the labels (Released, In development, ...) were taken
// out. `solid` is the dot colour, `line` the spine below it.
const META = {
released: { word: t('roadmap.status.released'), color: "var(--sb-green)", solid: "var(--sb-green-solid)", rgb: "var(--sb-green-rgb)", line: "rgba(var(--sb-green-rgb), 0.32)" },
current: { word: t('roadmap.status.current'), color: "var(--sb-orange)", solid: "var(--sb-orange-solid)", rgb: "var(--sb-orange-rgb)", line: "rgba(var(--sb-orange-rgb), 0.32)" },
dev: { word: t('roadmap.status.dev'), color: "var(--sb-yellow-2)", solid: "var(--sb-yellow-2-solid)", rgb: "var(--sb-yellow-2-rgb)", line: "rgba(var(--sb-ink), 0.08)" },
planned: { word: t('roadmap.status.planned'), color: "var(--sb-text-7)", solid: "var(--sb-text-7)", rgb: "var(--sb-text-7-rgb)", line: "rgba(var(--sb-ink), 0.08)" },
research: { word: t('roadmap.status.research'), color: "var(--sb-text-9)", solid: "var(--sb-text-9)", rgb: "var(--sb-text-9-rgb)", line: "rgba(var(--sb-ink), 0.08)" }
released: { solid: "var(--sb-green-solid)", line: "rgba(var(--sb-green-rgb), 0.32)" },
current: { solid: "var(--sb-orange-solid)", line: "rgba(var(--sb-orange-rgb), 0.32)" },
dev: { solid: "var(--sb-yellow-2-solid)", line: "rgba(var(--sb-ink), 0.08)" },
planned: { solid: "var(--sb-text-7)", line: "rgba(var(--sb-ink), 0.08)" },
research: { solid: "var(--sb-text-9)", line: "rgba(var(--sb-ink), 0.08)" }
};
const [open, setOpen] = React.useState({});
const isOpen = (i) => (open[i] === undefined ? DATA[i].status === 'current' : open[i]);
const toggle = (i) => setOpen((s) => ({ ...s, [i]: !isOpen(i) }));
// Was hexA(), which took the literal hex out of META and split it into channels by
// hand. Those literals are custom properties now, so there is nothing to parse at
// runtime — the browser does the substitution instead, and it does it again when
// the theme changes, which the old version could not.
const tint = (channels, a) => `rgba(${channels}, ${a})`;
const total = DATA.length;
const shipped = DATA.filter((d) => d.status === 'released' || d.status === 'current').length;
const upcoming = total - shipped;
@@ -162,18 +150,6 @@ function Roadmap() {
{!isMobile && <div style={{ marginTop: '3px', fontSize: '13.5px', color: 'var(--sb-text-6)' }}>{d.sub}</div>}
</div>
<div style={{ flex: 'none', display: 'flex', alignItems: 'center', gap: isMobile ? '8px' : '14px' }}>
{/* The status pill is desktop-only. On a phone its
word does not fit, and what was left — a bordered
box around a single coloured dot — said nothing the
marker on the timeline was not already saying in
the same colour, while taking room from the title.
So the whole pill goes, not just its label. */}
{!isMobile && (
<span style={{ display: 'inline-flex', alignItems: 'center', gap: '7px', padding: '6px 11px', borderRadius: '8px', background: tint(meta.rgb, 0.1), border: `1px solid ${tint(meta.rgb, 0.22)}`, fontFamily: MONO, fontSize: '10.5px', fontWeight: 600, color: meta.color, textTransform: 'uppercase', letterSpacing: '0.8px', whiteSpace: 'nowrap' }}>
<span style={{ width: '6px', height: '6px', borderRadius: '50%', background: meta.solid }} />
{meta.word}
</span>
)}
{!isMobile && <span style={{ fontFamily: MONO, fontSize: '12px', fontWeight: 500, color: 'var(--sb-text-7)', whiteSpace: 'nowrap', minWidth: '74px', textAlign: 'end' }}>{d.date}</span>}
<span style={{ color: 'var(--sb-text-9)', display: 'inline-flex', transition: 'transform .22s cubic-bezier(.2,.7,.3,1)', transform: opened ? 'rotate(180deg)' : 'rotate(0deg)' }}>
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.1" strokeLinecap="round" strokeLinejoin="round"><path d="M6 9l6 6 6-6" /></svg>
-5
View File
@@ -73,11 +73,6 @@ export const DICTIONARY = {
"roadmap.progress": "أُنجزت {shipped} من أصل {total} محطّة",
"roadmap.upcoming": "{upcoming} في الطريق",
"roadmap.keyFeatures": "أبرز المزايا",
"roadmap.status.released": "صدرت",
"roadmap.status.current": "الحالية",
"roadmap.status.dev": "قيد التطوير",
"roadmap.status.planned": "مُخطّطة",
"roadmap.status.research": "قيد البحث",
"hero.headlineTop": "خطٌّ مباشر",
"hero.headlineBottom": "لا يقرأه إلّا أنتما.",
"hero.subheading": "تُولَّد المفاتيح على جهازك وتُتبادَل ندّاً لندّ. بلا حسابات وبلا خوادم تحفظ رسائلك.",
-5
View File
@@ -73,11 +73,6 @@ export const DICTIONARY = {
"roadmap.progress": "{shipped} von {total} Meilensteinen erreicht",
"roadmap.upcoming": "{upcoming} in Arbeit",
"roadmap.keyFeatures": "Kernfunktionen",
"roadmap.status.released": "Veröffentlicht",
"roadmap.status.current": "Aktuell",
"roadmap.status.dev": "In Entwicklung",
"roadmap.status.planned": "Geplant",
"roadmap.status.research": "Forschung",
"hero.headlineTop": "Eine direkte Leitung,",
"hero.headlineBottom": "die nur Sie beide lesen können.",
"hero.subheading": "Die Schlüssel entstehen auf Ihrem Gerät und werden direkt zwischen den Geräten ausgetauscht. Keine Konten, keine Server, die Ihre Nachrichten speichern.",
-5
View File
@@ -73,11 +73,6 @@ export const DICTIONARY = {
"roadmap.progress": "{shipped} of {total} milestones shipped",
"roadmap.upcoming": "{upcoming} on the way",
"roadmap.keyFeatures": "Key features",
"roadmap.status.released": "Released",
"roadmap.status.current": "Current",
"roadmap.status.dev": "In development",
"roadmap.status.planned": "Planned",
"roadmap.status.research": "Research",
"hero.headlineTop": "A direct line",
"hero.headlineBottom": "only you two can read.",
"hero.subheading": "Keys are generated on your device and exchanged peer-to-peer. No accounts, no servers storing your messages.",
-5
View File
@@ -73,11 +73,6 @@ export const DICTIONARY = {
"roadmap.progress": "{shipped} de {total} hitos completados",
"roadmap.upcoming": "{upcoming} en camino",
"roadmap.keyFeatures": "Funciones clave",
"roadmap.status.released": "Publicado",
"roadmap.status.current": "Actual",
"roadmap.status.dev": "En desarrollo",
"roadmap.status.planned": "Planificado",
"roadmap.status.research": "Investigación",
"hero.headlineTop": "Una línea directa",
"hero.headlineBottom": "que solo leéis vosotros dos.",
"hero.subheading": "Las claves se generan en tu dispositivo y se intercambian directamente entre pares. Sin cuentas y sin servidores que guarden tus mensajes.",
-5
View File
@@ -73,11 +73,6 @@ export const DICTIONARY = {
"roadmap.progress": "{shipped} از {total} نقطهٔ عطف انجام شد",
"roadmap.upcoming": "{upcoming} در راه است",
"roadmap.keyFeatures": "ویژگی‌های کلیدی",
"roadmap.status.released": "منتشر شد",
"roadmap.status.current": "کنونی",
"roadmap.status.dev": "در دست توسعه",
"roadmap.status.planned": "برنامه‌ریزی‌شده",
"roadmap.status.research": "پژوهش",
"hero.headlineTop": "خطی مستقیم",
"hero.headlineBottom": "که فقط شما دو نفر می‌خوانید.",
"hero.subheading": "کلیدها روی دستگاه شما ساخته و همتا‌به‌همتا مبادله می‌شوند. بدون حساب، بدون سروری که پیام‌هایتان را نگه دارد.",
-5
View File
@@ -73,11 +73,6 @@ export const DICTIONARY = {
"roadmap.progress": "{shipped} jalons sur {total} atteints",
"roadmap.upcoming": "{upcoming} à venir",
"roadmap.keyFeatures": "Fonctions clés",
"roadmap.status.released": "Publié",
"roadmap.status.current": "En cours",
"roadmap.status.dev": "En développement",
"roadmap.status.planned": "Planifié",
"roadmap.status.research": "Recherche",
"hero.headlineTop": "Une ligne directe",
"hero.headlineBottom": "que vous seuls pouvez lire.",
"hero.subheading": "Les clés sont créées sur votre appareil et échangées directement entre pairs. Aucun compte, aucun serveur ne conserve vos messages.",
-5
View File
@@ -73,11 +73,6 @@ export const DICTIONARY = {
"roadmap.progress": "{shipped} מתוך {total} אבני דרך הושלמו",
"roadmap.upcoming": "{upcoming} בדרך",
"roadmap.keyFeatures": "יכולות מרכזיות",
"roadmap.status.released": "שוחרר",
"roadmap.status.current": "נוכחי",
"roadmap.status.dev": "בפיתוח",
"roadmap.status.planned": "מתוכנן",
"roadmap.status.research": "מחקר",
"hero.headlineTop": "קו ישיר",
"hero.headlineBottom": "שרק שניכם יכולים לקרוא.",
"hero.subheading": "המפתחות נוצרים במכשיר שלכם ומוחלפים עמית־לעמית. בלי חשבונות, בלי שרתים ששומרים את ההודעות.",
-5
View File
@@ -73,11 +73,6 @@ export const DICTIONARY = {
"roadmap.progress": "{total} में से {shipped} पड़ाव पूरे",
"roadmap.upcoming": "{upcoming} बाक़ी",
"roadmap.keyFeatures": "मुख्य विशेषताएँ",
"roadmap.status.released": "जारी",
"roadmap.status.current": "अभी चालू",
"roadmap.status.dev": "विकास में",
"roadmap.status.planned": "नियोजित",
"roadmap.status.research": "शोध",
"hero.headlineTop": "एक सीधी लाइन,",
"hero.headlineBottom": "जिसे सिर्फ़ आप दोनों पढ़ सकें।",
"hero.subheading": "कुंजियाँ आपके उपकरण पर बनती हैं और सीधे दोनों पक्षों के बीच बदली जाती हैं। न कोई खाता, न कोई सर्वर जो आपके संदेश रखे।",
-5
View File
@@ -73,11 +73,6 @@ export const DICTIONARY = {
"roadmap.progress": "{total}개 중 {shipped}개 완료",
"roadmap.upcoming": "{upcoming}개 남음",
"roadmap.keyFeatures": "주요 기능",
"roadmap.status.released": "출시됨",
"roadmap.status.current": "진행 중",
"roadmap.status.dev": "개발 중",
"roadmap.status.planned": "예정",
"roadmap.status.research": "연구",
"hero.headlineTop": "두 사람만 읽을 수 있는",
"hero.headlineBottom": "직통 회선.",
"hero.subheading": "키는 여러분의 기기에서 만들어지고 두 기기 사이에서 곧바로 교환됩니다. 계정도 없고 메시지를 보관하는 서버도 없습니다.",
-5
View File
@@ -73,11 +73,6 @@ export const DICTIONARY = {
"roadmap.progress": "Пройдено {shipped} из {total} этапов",
"roadmap.upcoming": "{upcoming} впереди",
"roadmap.keyFeatures": "Ключевые возможности",
"roadmap.status.released": "Выпущено",
"roadmap.status.current": "Текущий",
"roadmap.status.dev": "В разработке",
"roadmap.status.planned": "Запланировано",
"roadmap.status.research": "Исследование",
"hero.headlineTop": "Прямая линия,",
"hero.headlineBottom": "которую прочитаете только вы двое.",
"hero.subheading": "Ключи создаются на вашем устройстве и передаются напрямую между участниками. Без учётных записей и без серверов, хранящих ваши сообщения.",
-5
View File
@@ -73,11 +73,6 @@ export const DICTIONARY = {
"roadmap.progress": "Пройдено {shipped} з {total} етапів",
"roadmap.upcoming": "{upcoming} попереду",
"roadmap.keyFeatures": "Ключові можливості",
"roadmap.status.released": "Випущено",
"roadmap.status.current": "Поточний",
"roadmap.status.dev": "У розробці",
"roadmap.status.planned": "Заплановано",
"roadmap.status.research": "Дослідження",
"hero.headlineTop": "Пряма лінія,",
"hero.headlineBottom": "яку прочитаєте лише ви двоє.",
"hero.subheading": "Ключі створюються на вашому пристрої й передаються напряму між учасниками. Без облікових записів і без серверів, що зберігають ваші повідомлення.",
-5
View File
@@ -73,11 +73,6 @@ export const DICTIONARY = {
"roadmap.progress": "{total} میں سے {shipped} سنگِ میل مکمل",
"roadmap.upcoming": "{upcoming} راستے میں",
"roadmap.keyFeatures": "نمایاں خصوصیات",
"roadmap.status.released": "جاری ہوا",
"roadmap.status.current": "موجودہ",
"roadmap.status.dev": "زیرِ تعمیر",
"roadmap.status.planned": "منصوبہ بند",
"roadmap.status.research": "تحقیق",
"hero.headlineTop": "ایک سیدھی لکیر",
"hero.headlineBottom": "جسے صرف آپ دونوں پڑھ سکتے ہیں۔",
"hero.subheading": "کلیدیں آپ کے آلے پر بنتی ہیں اور ہم‌سطح تبادلہ ہوتا ہے۔ نہ اکاؤنٹ، نہ کوئی سرور جو آپ کے پیغام محفوظ کرے۔",
-5
View File
@@ -73,11 +73,6 @@ export const DICTIONARY = {
"roadmap.progress": "已完成 {total} 个里程碑中的 {shipped} 个",
"roadmap.upcoming": "还有 {upcoming} 个",
"roadmap.keyFeatures": "核心功能",
"roadmap.status.released": "已发布",
"roadmap.status.current": "进行中",
"roadmap.status.dev": "开发中",
"roadmap.status.planned": "已规划",
"roadmap.status.research": "研究中",
"hero.headlineTop": "一条只有你们两人",
"hero.headlineBottom": "才能读懂的直连线路。",
"hero.subheading": "密钥在你的设备上生成,并在两端之间直接交换。无需账号,没有服务器保存你的消息。",
+1 -1
View File
@@ -11,7 +11,7 @@ let DYNAMIC_CACHE = 'securebit-pwa-dynamic-v4.7.56';
// Build stamp — rewritten by scripts/post-build.js on every release so this file's
// bytes change each deploy. That is what makes the browser detect a new Service Worker,
// reinstall it, drop stale caches and (via controllerchange) prompt the page to update.
const SW_BUILD_VERSION = '1790208243441';
const SW_BUILD_VERSION = '1790219928897';
// Locale subdirectories, rewritten by scripts/build-i18n.js. Each localized page is a
// separate document at its own URL, so the shell has to be cached and served per
+12 -6
View File
@@ -384,13 +384,19 @@ const template = read('templates/index.template.html');
const roadmap = read('src/components/ui/Roadmap.jsx');
assert.equal(/parseInt\([^)]*\.slice\(1\)/.test(roadmap), false,
'a var() reference cannot be split into channels by hand; publish the channels instead');
assert.match(roadmap, /rgb: "var\(--sb-[a-z0-9-]+-rgb\)"/,
'the status table must carry the channels alongside the colour');
// The status pill is desktop-only: on a phone the word does not fit, and a bordered
// box around one dot repeats what the timeline marker already shows.
assert.match(roadmap, /\{!isMobile && \(\s*\n\s*<span style=\{\{ display: 'inline-flex'/,
'the whole status pill must be hidden on mobile, not only its label');
// The status pills (Released, In development, ...) were removed on every screen: the
// timeline marker already says where a milestone stands. Neither the component nor
// any language may bring the words back half-way.
assert.equal(/roadmap\.status\./.test(roadmap), false,
'the roadmap must not render a status label');
const localeFiles = readdirSync(new URL('../locales', import.meta.url))
.filter((f) => /^[a-z]{2}\.json$/.test(f));
assert.ok(localeFiles.length >= 13, 'every language file is checked');
for (const file of localeFiles) {
const raw = read(`locales/${file}`);
assert.equal(/"roadmap\.status\./.test(raw), false, `${file} still carries roadmap status labels`);
}
}
console.log('✅ theme switching');
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/uk/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790208243441"></script>
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790208243441"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790208243441"></script>
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790208243441"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790208243441"></script>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/uk.js?v=1790208243441"></script>
<script type="module" src="/src/i18n/dict/uk.js?v=1790219928897"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790208243441"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790208243441"></script>
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790208243441"></script>
<script type="module" src="/dist/app.js?v=1790208243441"></script>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790208243441"></script>
<script src="/src/pwa/install-prompt.js?v=1790208243441" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790208243441" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790208243441"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
</body>
</html>
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/ur/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790208243441"></script>
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790208243441"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790208243441"></script>
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790208243441"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790208243441"></script>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/ur.js?v=1790208243441"></script>
<script type="module" src="/src/i18n/dict/ur.js?v=1790219928897"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790208243441"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790208243441"></script>
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790208243441"></script>
<script type="module" src="/dist/app.js?v=1790208243441"></script>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790208243441"></script>
<script src="/src/pwa/install-prompt.js?v=1790208243441" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790208243441" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790208243441"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
</body>
</html>
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/zh/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790208243441"></script>
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790208243441"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790208243441">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790208243441"></script>
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790208243441">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790208243441">
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790208243441"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790208243441"></script>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/zh.js?v=1790208243441"></script>
<script type="module" src="/src/i18n/dict/zh.js?v=1790219928897"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790208243441"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790208243441"></script>
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790208243441"></script>
<script type="module" src="/dist/app.js?v=1790208243441"></script>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790208243441"></script>
<script src="/src/pwa/install-prompt.js?v=1790208243441" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790208243441" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790208243441"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
</body>
</html>