Commit graph

76 commits

Author SHA1 Message Date
CRT
1789e07d7a Theme engine: a rule is read as it takes effect (a Tailwind opacity utility's nested @supports value, not its solid fallback); unsupported @supports groups are left out; reach() is exported for site adapters 2026-09-30 21:04:12 +07:00
CRT
6d3f91bf2e Feature modules: a feature ported from a plugin keeps that plugin's words (words), so nothing is retranslated; the keep-my-changes question takes its own line 2026-09-30 19:53:11 +07:00
CRT
1f95d27018 Locales: the area cards, the Fixes list, modes and the feature settings words in all 48 translated languages (machine) 2026-09-30 19:37:56 +07:00
CRT
bd6b4860d7 Feature modules in a new app, i18n rename, and what the first area port needed
- create-waybetter: the generated app has a feature table (one area, one feature, three modes), a feature module, the registry in its runtime, the cards and the first-run screen in its panel
- waybetter i18n rename --map <file> [--copy]: keys move or are copied in every catalog with each language's own value
- feature context: win (no globals in a module), text() for a feature's words (t('...') is read as a whole catalog key by the i18n tools)
- probes: `when` (only counts while the part of the page it lives in is there)
- cards: a caret, an empty area says its features come later; the first-run screen takes the whole panel
2026-09-30 19:25:15 +07:00
CRT
d8619c7482 Panel: area plugin cards with per-feature toggles, the Fixes list, modes (first-run screen and Settings)
- PanelSite.features: the app's feature table; AreaPlugins draws one card per area (switch, count, grouped features, Settings button that runs the area's command in the site tab) and the core flags as Fixes
- a feature still backed by an old plugin file is switched through plugin_set_enabled from its card and left out of the JavaScript plugins list
- Modes: Onboarding (three cards, recommended preselected; an existing setup may be kept) and ModeSettings with the keep-my-changes question; openOnboardingWhenDue for ShellSite.start
- flags are saved sparsely (only what differs from the table's defaults)
- PanelSite.appearance.extra; palette commands of an area are listed under its name
- the kit's words for feature settings and health notes; English in the framework catalog
2026-09-30 18:34:14 +07:00
CRT
365f55f604 Host: 256 feature flags, the onboarding mode (mode_get/mode_set, shell-only), and the one-time move of replaced plugin files to feature flags
- settings: MAX_FEATURES 64 -> 256 (an older app's whole-map backup still validates)
- modes: ModeState {mode, onboarded, existing} in modes.json; existing is decided natively on the first start
- plugins::migrate: PluginHost.superseded (file -> flag); enabled and as shipped -> flag on and the file goes; edited -> kept, flag left off; marker written last, every step repeatable; map_backup for imported enabled lists
- a superseded file is never written again by install_bundled
- create-waybetter: the host command list and PluginHost.superseded
2026-09-30 18:34:13 +07:00
CRT
f31b00eec7 Feature modules: a feature table (areas, flags, modes), a registry that runs a module only on its surfaces, one shared observer for every feature and plugin, settings from a schema, selector health with self-pause
- featureTable.ts: areas, per-feature flags, core flags, modes as presets; sparse storage, ownership (an area that is off turns off what it owns), mode switching that keeps or drops manual changes, table validation
- featureModules.ts: createFeatureRegistry (flag + surface gating, scoped context, palette commands under the area with a budget of 5, settings dialog, probes, hotfix selector overrides and kill flags)
- settingsForm.ts: a settings schema normalizes stored values and draws the controls from the UI kit
- domHub observeSelector; api.observe goes through the shared hub (a root of the caller's own keeps its observer)
- createFeatureFlags: a delivery is the whole state (a flag it does not name is at its default), resolve() for ownership, current()
2026-09-30 18:11:42 +07:00
CRT
8567a1e26c build-env: MSVC C and C++ lose the build paths too (/d1trimfile in CL, /PDBALTPATH in LINK)
A library a build script compiles with MSVC (CMake, the cc crate) kept its
absolute source paths through __FILE__: -ffile-prefix-map exists only on gcc
and clang. cl.exe and link.exe read CL and LINK themselves, so the roots are
trimmed whatever runs the compiler. Longest root first: the first match wins.
2026-09-30 17:48:27 +07:00
CRT
31dabca439 Comments: X's own panel sections are Tweaks and Drafts (My Space removed for now)
wayBetter for X took My Space (profile customization) out; the framework only named it in
comments as an example of an app's own section and runtime member.
2026-09-30 16:52:50 +07:00
CRT
3b08a615c3 waybetter 0.6.0: path-free native builds (build-env) and the privacy-scan release gate
A Rust binary embeds the absolute paths of its sources, and on a developer's machine those hold
the account name. waybetter build-env runs a build with the home folder, the workspace, CARGO_HOME,
RUSTUP_HOME and CARGO_TARGET_DIR remapped to /home, /src, /cargo, /rustup and /target (flags already
set are kept), a path-free PDB reference on MSVC and the same mapping for C sources on gcc and clang.

waybetter privacy-scan searches files, binaries (UTF-8, UTF-16), archives (zip, tar, gzip, zstd,
.deb, DMG; NSIS, AppImage and xz through 7-Zip or the matching tool), git-tracked files and a whole
history for the terms of a file kept outside every repository plus the machine's account name. Hits
are printed masked; a container that cannot be opened is a failure.

waybetter release windows builds with build-env; both release commands refuse an artifact with a hit.
The scaffolded app gets desktop:build and privacy:scan scripts.
2026-09-30 15:58:25 +07:00
CRT
ff950511a3 i18n: supported and community language tiers
Automatic language choices resolve only to supported languages; community
translations are listed apart in Settings and offered as a one-click switch.
waybetter i18n check reads `supported` and generates `tier` into languages.json.
2026-09-30 15:48:11 +07:00
CRT
8460719404 locales: light review of the 11 most-used languages (terminology, wording; 272 strings) 2026-09-30 14:59:59 +07:00
CRT
cb2bfc7872 waybetter 0.5.0: docs for the host's page commands, the runtime composition, the i18n command and dev-tools 2026-09-30 14:48:06 +07:00
CRT
5c64f2f6f8 dev-tools: the generic development harnesses (perf probes, close check, tab and webview stress)
Moved from wayBetter for X; an app passes its own origin, process name, scripts and fixtures.
2026-09-30 14:48:06 +07:00
CRT
3d1c08bba4 waybetter i18n check|extract: an app's catalogs against the framework's rules
Configured by waybetter.i18n.json in the app's root; --write regenerates languages.json and the native localization files (macOS, Linux).
2026-09-30 14:48:05 +07:00
CRT
a71505d5c0 locales: the Windows installer's words (wb.installer.*) and its language files, generated from the catalogs
Moved from wayBetter for X: 27 messages in 51 languages, and windows/languages/<Language>.nsh for the 17 NSIS languages Tauri does not ship (scripts/installer-languages.mjs writes and checks them).
2026-09-30 14:48:04 +07:00
CRT
cceb5182e9 create-waybetter: a new app gets the real panel, the composed runtime and the host's commands
- src/shell/Panel.tsx is createPanel (waybetter/shell/panel) with the app's home page: Home,
  Plugins with custom CSS, Accounts and Settings, growing with what the app serves.
- src/runtime/main.ts is composed with waybetter/runtime/siteRuntime (feature flags, page strings,
  plugin API views per @permissions, the floating panel button).
- Native: the host serves the plugin, custom CSS, feature flag and settings commands
  (AppConfig::new(&SITE, title, &plugins::HOST), app::page_scripts on a loaded page); the app keeps
  tab_report and site_ready. site-tab grants the host's open_panel on the site only, checked with
  assert_site_only.
- HOST_COMMANDS follows commands.rs again (shell_ready, tab_still_ready and the new ones; SITE).
2026-09-30 14:28:55 +07:00
CRT
290123f0b4 runtime: the site runtime's composition (siteRuntime, pageStrings, panelButton, commandReport)
What every app's page runtime entry did by hand (moved from wayBetter for X's inject/entry.tsx):

- siteRuntime.ts: pageInvoke (the IPC bridge read at call time), createFeatureFlags (parts that
  install on enable and dispose on disable, the flags native code delivers, a deck column's
  overrides on top of them, recorded at once and applied when <html> exists) and
  installSiteRuntime (the runtime object with the members native code calls, the plugin API views,
  developer-mode errors, its window names, the queued native deliveries, the command report).
- pageStrings.ts: the page's language (English built in, deliveries checked as data, the
  bundled-plugin namespace rule).
- panelButton.ts: the way into the panel from the page (the site's own navigation entry when the
  adapter mounts one, else a floating button that hides under the site's overlays and sits above
  its bottom bar).
- commandReport.ts: the palette command report and developer-mode start errors.
- tests/siteRuntime.test.ts.
2026-09-30 14:28:54 +07:00
CRT
205ee82296 host: plugins, custom CSS, feature flags, settings and open_panel are host commands
run_app now keeps and serves what every app's panel and page need, with the same caller checks
as the rest (commands::SHELL: shell_only first; testkit::assert_host_guards covers them):

- app.rs: PageState (the plugin store in app data `plugins`, the feature flags, ShellSettings)
  managed by the host; commands plugins_list, plugin_set_enabled, plugins_open_folder,
  custom_css_get/set, features_get/set, settings_get/set (moved from wayBetter for X). The app
  reads the state through app::page(), gets a loaded document's scripts from app::page_scripts()
  (flags, links, custom CSS, plugins) and writes through set_features/set_settings/set_custom_css
  (a backup import). AppConfig takes the app's PluginHost (AppConfig::new(site, title, plugins))
  and an optional home_url. SiteHooks::navigation_started and new_window_mode default to the
  owner's link settings.
- settings.rs (pure, tested): ShellSettings { homeUrl, externalLinks, siteLinks, restoreTabs }
  with its input form (missing fields take the defaults; `xLinks`, the name wayBetter for X used,
  is read as siteLinks), links_script ({ site: mode }), feature validation and features_script.
- commands::SITE + open_panel: a tab on the site's origin asks the shell to open the app's panel
  (site_tab_only first). testkit: assert_site_only(command, site) checks that every capability
  granting a site command is a tab capability limited to the site's URLs; assert_host_commands and
  assert_host_guards include the site commands.
- shell frame backupModel: a settings section that still says xLinks compares as siteLinks.
2026-09-30 14:28:52 +07:00
CRT
cecaf93639 docs: the panel in the framework (what an app supplies, which sections it gets, words, native commands) 2026-09-30 14:03:41 +07:00
CRT
00b193506f shell: the panel, createPanel(site) (moved from wayBetter for X)
packages/shell/src/panel (waybetter/shell/panel): an app's own tab. An app describes itself
(PanelSite: brand and the home page's words, its own sections and their order, its theme store,
catalog and the preview component a theme document is drawn in, Make's examples and docs, the
install controller, its languages, what its native side serves) and createPanel returns the
component for ShellSite.panel. It is in the shell package because it is drawn in the frame and
shares its stores, native bridge and language.

- Panel.tsx (header, settings search over every settings section, navigation, toasts; Accounts
  and Updates), nav.ts (which built-in sections an app gets: each shows only when the app serves
  what it needs; the app's sections in its order), Home.tsx (hero, highlights, About from the
  app's data), controls.tsx + panel.css.
- Appearance.tsx, ThemeBuilder.tsx + builderModel.ts + builder.css, fonts/ (FontBrowser, FontRoles,
  catalog, the offline Google Fonts list; scripts/google-fonts-catalog.mjs regenerates it):
  the theme documents are the runtime's, the store, catalog, accents, draft palette, file suffix
  and preview are the app's (PanelSite.themes).
- Plugins.tsx (the plugins list and custom CSS over the host's plugins_*/custom_css_*),
  StoreSection.tsx, MakePanel.tsx + makeModel.ts + MarkdownDoc.tsx + markdown.ts + make.css (the
  examples, the theme file and the docs are the app's), Settings.tsx (links and session over
  settings_get/set with `siteLinks`, keyword alerts, the media panel), FeatureToggles.tsx
  (useFeatures + FeatureGroups over features_get/set: the app names its flags and groups),
  PowerSettings.tsx (deck defaults from site.deck: its flags and presets; DeckPreset gets `name`
  and `hint`), BackupPanel.tsx + backup.css, DeveloperPanel.tsx, LanguageSettings.tsx, compare.ts.
- frame: language.ts (createLanguage: follow the site / the system / one language, i18n_set;
  moved from the app), appI18n.ts (createAppI18n: the app's typed i18n instance, useT, dates and
  numbers; the app passes React's useSyncExternalStore), formatDate in i18n.ts (ShellI18n.date).
- tests/panel.test.ts: every panel key has English and is used, sections per app, the builder
  model, the font catalog, plugin header rules, the UI kit demos, Markdown, compare.
- npm package: exports ./shell/panel, ./shell/panel/*, ./shell/panel/*.css; the build is
  scripts/build.mjs (the shell is compiled with the runtime sources it imports under one root and
  its imports are pointed at dist/runtime; stylesheets and the font list are copied).
2026-09-30 14:03:40 +07:00
CRT
6ef78c0c30 locales: the panel's words (wb.*), 51 languages
- 668 wb.* messages for the panel (navigation, settings search, accounts, updates, Appearance, the
  Theme Builder, fonts, plugins, custom CSS, Make, Power User, settings, backup and sync, developer
  mode, the controls), moved with every translation from wayBetter for X's catalogs; `{site}`
  stands where the English said "X" (49 keys; the app passes "X", so X reads the same). Keys that
  named X got site-neutral names (settings.links.site*, settings.language.followSite*,
  builder.leadingSite, builder.liveOnSite, fonts.asSite, make.siteDefaultLeading, features.default).
  English source: shell/src/panel/panelMessages.ts.
- One translation could not take `{site}` (hu wb.settings.alerts.hint never named the site) and
  falls back to English.
- locales/en.meta.json: the translator notes of the moved keys (40), among them the one fragment a
  language may leave empty (wb.make.step2Before); the catalog test reads it.
- runtime/tests/i18n.test.ts: en.json is the kit, shell-model, store, shell-frame and panel source.
2026-09-30 14:03:09 +07:00
CRT
9aa3fc9c17 The Windows installer is the framework's: a setup run again opens the installed app
packages/waybetter/windows/installer.nsi (shipped in the npm package) is the NSIS
template wayBetter for X used, made generic: an app that was renamed keeps its
registry keys by defining WAYBETTER_LEGACY_NAME in its installer hooks; without it
the keys are Tauri's defaults.

Run by hand (no /UPDATE) it installs only when it is newer than what is installed.
With the same or a newer version installed it installs nothing, opens the installed
exe (the single-instance guard shows the running window) and exits 0, so an old
setup can no longer replace or downgrade an install the updater has moved on.
/FORCE reinstalls the same version, /NORUN is kept, the updater path is unchanged.

create-waybetter apps use the template (bundle.windows.nsis, per-user).
wayBetter for X's page is waybetter.fyi/x in the READMEs.
2026-09-30 13:55:00 +07:00
CRT
2008967c04 fix(shell): coordinate startup cover and tab stills 2026-09-30 12:25:46 +07:00
CRT
fd99901bb2 runtime + host: the theme engine (theme documents, choice catalog, page runtime, fonts; native theme state)
The site-independent theme engine moves from wayBetter for X into the framework:
- runtime/themeSpec.ts: theme document types, the schema's defaults (BASE_*), sanitizing,
  import, overrides, ensureContrast, font roles/stacks, font choices, backgrounds.
- runtime/themeChoice.ts: ThemeChoice and createThemeCatalog(builtins) (normalize, base,
  resolve, palette, all), choiceForId, serializeChoice.
- runtime/themeRuntime.ts: installThemeRuntime(win, site) (live CSS over the site's rules,
  --wb-* vars, site color mode, first-frame snapshot), collectRules, resolvedFonts.
- runtime/fonts.ts: bundled fonts and owner-downloaded Google Fonts from bytes.
- themeApi exports hexToRgb, mix and MONO_FAMILIES (one copy: themeTokens and themeSpec use them).
- host theme.rs: ThemeChoice/ThemeScopes over a site's ThemeSite (envelope checks against
  theme.schema.json, which theme a tab shows, page color, delivery script).
2026-09-29 13:07:59 +07:00
CRT
cc80cb5ca9 lockfile: waybetter 0.4.0 2026-09-29 12:50:33 +07:00
CRT
3e58a5c11a docs: the shell frame in the framework (what a site supplies, styles, words, native commands)
README: "The shell frame" (createShell, the ShellSite slots and features, frame words and styles,
bootScript, preview mocks, the native commands and events it uses), the layout, the create-waybetter
app, how wayBetter for X consumes it. npm README: waybetter/shell/frame.
2026-09-29 12:47:19 +07:00
CRT
ceee9b7c4f create-waybetter: a new app's shell is the framework's shell frame
The app skeleton's src/shell/main.tsx calls createShell with the site (pages, account rules, search,
address chips, a Home link, a Plugins section) and src/shell/Panel.tsx (the app's own tab: the
plugins, switched on or off live); app.css themes it with the --wb-c-* tokens. build.mjs bundles
the shell with waybetter/build (JSX, CSS into dist/shell.css) and writes bootScript() as boot.js.
desktop.rs keeps the frame's titlebar (custom_titlebar: true) and forwards shortcuts and link drags
(BridgeOptions::ALL); the shell capability grants the frame's window calls. Native features the
skeleton does not wire up (workspaces, sync, developer mode, plugin commands) are off in the site.
Dependencies: react, react-dom, dockview, waybetter ^0.4.0.

Tests: sources import only published subpaths (patterns included), main.tsx uses createShell, the
shell capability has the resize permission, and the skeleton typechecks with the React types.
2026-09-29 12:47:18 +07:00
CRT
068168469c shell: the shell frame, createShell(site) (moved from wayBetter for X)
packages/shell/src/frame (waybetter/shell/frame): the whole shell of an app. An app describes its
site (ShellSite: names and pages, account rules, search, address chips and completions, its panel
tab, the new-tab page, palette items, deck column kinds and flags and an optional compose dock, the
media panel's composer rule, a theme store, overlays, the native features it serves) and passes
its Tauri API and i18n instance; createShell returns the root component.

- Shell.tsx: dockview host (tabs in the titlebar row, splits, drag-link drops, shortcuts, context
  menu, deck back-and-forth, session restore, workspace on start, overlay raise); state.ts (pane
  placeholders, tabs_sync one-in-flight via syncGate, shell_raise layer, profiles, layout).
- WebPanel (address bar), NewTabPage, CommandPalette + paletteModel (frame groups; site items),
  DeckView + AddColumnDialog + deckStore (site column kinds), PaneTheme + themeStore
  (createThemeStore over the app's ThemeAdapter) + chromeTheme (ChromeTheme input) + themeScopes,
  Titlebar + TitlebarExtras + icons + brand (wB mark data URI), AccountSwitcher + accountModel,
  workspaces + workspaceModel, backupModel, syncHost, devHost + devModel, pluginCommandStore,
  MediaPanel + mediaModel, searchInput, hooks, bridge (installPreviewMocks), i18n, boot.ts
  (bootScript: the first-frame boot.js), CSS themed with --wb-* tokens.
- paneModel: paneVisibility, raiseSupported, cssRgb; deckModel: isSourcePage.
- Includes the live-QA titlebar fix (dock ResizeObserver + rAF titlebar marks, dock sized by its
  insets).
- tests/frame.test.ts: every frame key has English and is used, palette order with a site,
  address fallback, layout gate, boot script, chrome variables, switcher rules, workspaces,
  deck settings with site flags.
- npm package 0.4.0: exports ./shell/frame, ./shell/frame/*, ./shell/frame/*.css (copied by the
  build); dockview and acorn optional peers; root devDependencies dockview, acorn.
2026-09-29 12:47:10 +07:00
CRT
892de6cbf4 install screen: where an install comes from, in the owner's language
The source line ("wayBetter Store (signed catalog, sha256 verified)", "Link: <host>", "A file you
dropped") is built from the source kind and URL with the wb.install.source.* messages instead of
showing native code's English label.
2026-09-29 12:47:09 +07:00
CRT
cc5a351fe9 locales: the shell frame's words (wb.*) and the install screen's source line, 51 languages
- 245 wb.* messages for the shell frame (tabs, address bar, new-tab page, palette, account
  switcher, decks, workspaces, chips, media panel, pane themes, backup preview), moved with every
  translation from wayBetter for X's catalogs; `{site}` stands where the English said "X" (10
  keys; the app passes "X", so X reads the same). English source: shell/src/frame/frameMessages.ts.
- wb.install.source.store|link|file: where an install comes from, translated in every locale
  (native code's label is English only).
- runtime/tests/i18n.test.ts: en.json is the kit, shell-model, store and shell-frame source.
2026-09-29 12:46:57 +07:00
CRT
c3964ec378 docs: run_app, commands/testkit, waybetter release and waybetter/build 2026-09-29 11:51:25 +07:00
CRT
231e18de0a create-waybetter: the app skeleton runs on run_app, testkit, waybetter/build and waybetter release
The generated desktop.rs is config + SiteHooks + its own commands; build.rs uses
commands::manifest; capability files grant the host's commands; tests/security.rs uses testkit;
scripts/build.mjs uses buildRuntime; waybetter.release.json and release scripts (placeholder URLs).
A test keeps HOST_COMMANDS in step with commands.rs.
2026-09-29 11:51:25 +07:00
CRT
4af85299c8 cli: waybetter release windows|macos and waybetter/build (0.3.0)
release: signed NSIS/universal-macOS releases and latest.json (merge, built-in shape check plus the
app's own validator), upload steps printed only, configured by the app's waybetter.release.json;
the key is read only into the build environment or passed to the Tauri signer by path.
build: buildRuntime() bundles a page runtime IIFE with the app's esbuild (?inline CSS as text,
catalog strings limited to the runtime's prefixes). esbuild is an optional peer.
2026-09-29 11:51:24 +07:00
CRT
0b6b17a9c3 host: run_app — the window, shell, tab webviews and generic commands for every app
The `app` feature (App / run_app, AppConfig, SiteHooks): registers the Tauri plugins every app
uses (single-instance, deep-link and updater opt-in, window-state, opener, process, notification,
dialog), makes app data, loads profiles and the language, builds the window (restore, lost-geometry
reset, helper-close routing, native resize follow) and the transparent shell, and serves tabs_sync,
tab_navigate, tab_action, open_external_url, shell_focus, shell_raise, window_system_menu,
profiles_get/set, i18n_get/set (shell-only) and tab_shortcut, tab_link_drag (tab-only). The tab
builder is generic; the app fills in SiteHooks. `commands` lists them (manifest() for build.rs),
`testkit` checks capability files and caller guards, i18n::page_script is origin-guarded.
check:tauri now checks the app feature.
2026-09-29 11:51:24 +07:00
CRT
4be7102bb2 docs: what the host gives an app now includes the generic native features
Layout and "What the host gives an app": bridge, backup, sync,
workspaces, devmode, alerts, media (+ clipboard), gfonts, fonts,
updater, plugins::commands; apps enable the tauri and net features.
2026-09-29 11:22:55 +07:00
CRT
d3ed72ea4d host: the tab bridge ships from waybetter-host; create-waybetter uses it
tab-bridge.js (moved from wayBetter for X) is served by bridge::SOURCE,
or by bridge::script(BridgeOptions) with shortcut and link-drag
forwarding switched off for a shell that does not handle them (a
forwarded shortcut is taken from the page). Tests: one options line,
only tab_report/tab_shortcut/tab_link_drag, every forwarded shortcut is
one tabs::valid_shortcut accepts. Generated apps now inject
bridge::script(BridgeOptions::REPORT_ONLY) instead of writing their own
duplicated src-tauri/runtime/tab-bridge.js.
2026-09-29 11:22:54 +07:00
CRT
3e6cbe0773 docs: the Store in the framework (shared catalog format, keys, tooling, trust model, adding it)
- docs/STORE.md: one signed catalog for every app (format 2, `apps` per item, field rules), Ed25519
  signing and key rotation, `waybetter store build|sign|verify` with an app config, install links,
  the trust model, and how an app adds the Store (StoreConfig, command wrappers, InstallHost,
  StoreView, tokens, strings).
- README: `store` in the layout and in what the host gives an app; the shell's Store modules.
- npm README: the Store components, models, schema and command.
2026-09-29 11:21:37 +07:00
CRT
f116f1b10b host: updater (signed native updates and the hotfix channel)
updater (tauri + net features): the launch handshake, the cached hotfix
(re-verified on every load), the 30 min +/- 5 check loop, download and
verification through tauri-plugin-updater, the size-capped hotfix fetch
(no identifiers), hotfix delivery to the site's tabs, and status/apply/
ready for the app's shell-only commands. An UpdaterConfig carries what
differs per app: SiteSpec, hotfix URL and public key, page global/event,
manual download page, user agent and the "update ready" hook.
2026-09-29 11:17:54 +07:00
CRT
7307bbed22 host: self-hosted Google Fonts (gfonts) and the font cache (fonts)
gfonts (pure): CSS2 API URLs, the fonts.googleapis.com/fonts.gstatic.com
allowlist, CSS parsing and face selection, woff2 checks, the sha256
manifest cache format and the page script, whose origin guard and
runtime global now come from the SiteSpec. fonts (net feature): the
download client (allowlist re-checked per request, no redirects, size
caps), the family/preview caches and install/remove/faces/preview for the
app's shell-only commands. Tests and CSS fixtures moved with them.
2026-09-29 11:15:10 +07:00
CRT
caef87775f host: gallery folders and the opt-in clipboard history
media: gallery settings (absolute folders, deduplicated), listing and
resolving images only directly inside owner-chosen folders (links must
stay inside), data URLs, the bounded clipboard history with its index
and image files, PNG encoding. media::clipboard (tauri feature): reading
the OS clipboard, the Windows change counter, skipping copies marked
private by password managers, and the opt-in polling loop (records from
the next copy after opting in; releases the clipboard while off).
2026-09-29 11:13:01 +07:00
CRT
3c238d9e2d cli: waybetter store build|sign|verify, the store catalog JSON Schema
Moved from wayBetter for X (scripts/build-store.mjs, scripts/sign-store.mjs) into the `waybetter`
npm package, generic over the app:

- bin/waybetter.mjs + cli/store.mjs. `build --config <store.config.mjs>`: the config names its app
  and returns its items (metadata, file path + bytes, optional preview); build replaces only that
  app's items in the shared catalog (other apps' items and files stay), removes files only its old
  items used, fills url/sha256/size/apps, and validates the whole catalog with the rules apps apply
  natively before anything is written. `sign` (and `sign --init`: create the key once, 0600, never
  overwritten) signs the exact catalog bytes; `verify` checks the signature with any listed public
  key (rotation) and the catalog rules. The private key is never printed, copied or moved; --key
  defaults to $WAYBETTER_STORE_KEY. pluginHeader() for configs.
- store-catalog.schema.json (format 2, `apps` per item), exported with the CLI module.
- Tests: multi-app builds in one folder, refusals (bad items, duplicates, paths outside the folder,
  hosts), schema vs CLI rules, sign/verify round trip incl. rotation and tampering, no key
  material printed. jsonSchema.mjs learns minItems, uniqueItems and allOf.
2026-09-29 11:12:38 +07:00
CRT
f1588c3acd shell: the Store view and install screen as framework React components, strings in the framework catalogs
Moved from wayBetter for X so every wayBetter app gets the Store UI; the app passes its native
bridge, theme adapter, translator and (optionally) its own controls and button classes.

- storeModel.ts: wire types of the native store commands (InstallPreview, StoreCatalogView,
  LinkEvent, StoreItem with `apps`), permission badges in the site's words, categories, item state
  (install/installed/update/changed locally/built in), search, free theme ids, versions, previews.
- installController.ts: the install screen's state machine (links incl. those queued before the
  shell listened, dropped files, store items, cancel, confirm), generic over the app's theme format
  (`ThemeAdapter`: parse, ids, facts, save) and its bridge (`StoreBackend`: invoke/listen).
- InstallDialog.tsx (`InstallHost`): the screen (Install enabled after 1 s, Enter never installs,
  tabs hidden via setOverlay) and the window-wide drop target. StoreView.tsx: search, kinds,
  categories, cards, permission badges, install/update/remove; default controls or the app's.
- store.css: both, themed with framework `--wb-*` tokens (documented; dark defaults).
- storeMessages.ts + every framework catalog: 120 `wb.store.*`, `wb.install.*`, `wb.permission.*`
  messages moved from the app catalogs with all existing translations; the six that named X take
  `{site}`; generic words the components need copied with their translations.
- npm package: exports for the new modules and store.css, optional react/react-dom peers; @types
  for the typecheck. Tests: models, controller flows with a fake bridge, every looked-up key exists.
2026-09-29 11:08:04 +07:00
CRT
d65cc08070 host: Cargo.lock with both the store module and the alerts plugin
The alerts commit was locked against the tree before the store module
landed and dropped the store's packages (ed25519-dalek, reqwest, ...);
this is the store commit's lockfile plus tauri-plugin-notification.
2026-09-29 11:06:56 +07:00
CRT
846a5f09cc host: keyword alerts and native notifications
alerts: keyword settings (normalized, deduplicated, bounded), the
configured-keyword check, plain bounded snippets, the per-keyword and
global Throttle and an AlertGate over any KeywordMatch (one notification
per item). With the tauri feature, alerts::notify shows a native OS
notification (tauri-plugin-notification, registered by the app).
2026-09-29 11:05:49 +07:00
CRT
1629c6acc9 host: store module: install links, allow-list, signed multi-app catalog, staging and installs
Moved from wayBetter for X (distribution.rs + desktop_store.rs) so every wayBetter app gets the
Store; the app keeps its Tauri command wrappers and a `StoreConfig`.

- store::catalog (pure): `StoreConfig` (app id in the shared catalog, product, user agent, link
  scheme, store URL, public keys, allowed hosts), `AllowedHost` (raw-files-only rule for a code
  host; DEFAULT_HOSTS = waybetter.fyi, cdn1.crt.fyi, git.crt.fyi raw), install-link parsing,
  download allow-list, theme validation, catalog format 2: every item names its `apps`; the whole
  catalog is verified (Ed25519 over the exact bytes with any listed key, so keys rotate; strict
  schema; ids/files unique per app) and each app gets only its own items (another app's item is
  shape-checked but not held to this app's hosts); per-item sha256/size, install records, versions.
- store::install: `Store` (pending links, staged installs with TTL/bound, MIN_REVIEW before a
  commit, commit writes exactly the staged bytes after re-validation via PluginStore::install,
  plugin remove, records file, verified catalog + offline copy verified again when read back,
  StoreView). Plugin start/stop scripts run through a function the app passes.
- store::net (`net` feature): no-redirect, no-cookie reqwest fetch with caps; stage_link,
  stage_item, catalog(refresh).
- Tests: links, per-app allow-lists and schemes, themes, signatures incl. tampering and key
  rotation, multi-app filtering, bad items, staging/commit/remove/records/offline copy on disk,
  fetch refuses anything off the allow-list. test:rust and check:tauri build with `net`.
2026-09-29 11:05:25 +07:00
CRT
c14dce3862 host: palette commands and developer mode watcher
plugins::commands: the palette commands a site tab reports (validated and
capped as a whole) and the page script that runs one, now built from the
SiteSpec (runtime global, primary origin) instead of a hard-coded x.com.
devmode: the debounced polling watcher (plugins, custom.css, one theme
file), reload order, DevError and theme-file reading; the app turns the
document into its own theme state through a callback.
2026-09-29 11:02:07 +07:00
CRT
b2744c1a45 pageLang: report X's language even when installed before <html> exists or before the IPC bridge
At document start (where the app installs the X runtime) there is no <html> element yet, so
the lang report never ran and "Follow X" never learned X's language (found live: siteLang
stayed null). It now reads lang again at readystatechange/DOMContentLoaded, and a report
that fails (no bridge yet) is retried with a bounded backoff. Tests.
2026-09-29 11:01:53 +07:00
CRT
49d9a9457b host: saved workspaces validation
Named tab/pane/deck layouts, bounded and well-formed (slug ids, 1-60
character names, known tab kinds, http(s) URLs, size caps), moved from
the wayBetter for X app unchanged with its tests.
2026-09-29 10:59:20 +07:00
CRT
b4109fc282 host: settings backup envelope and encrypted folder sync
backup: the versioned .waybetter envelope (format/version checks, only the
app's registered sections kept), secret-key scrubbing, the plugins /
customCss / accounts sections every app has, plugin import checks and
atomic writes. sync: Argon2id + XChaCha20-Poly1305 snapshots of the
settings backup in a folder the owner syncs, moved unchanged from the
wayBetter for X app with its tests.
2026-09-29 10:58:15 +07:00