Commit graph

122 commits

Author SHA1 Message Date
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
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
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
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
c686c376ab i18n: framework catalogs for the 51 languages X offers, and tests
Kit and shell-model words (18 keys) per locale, machine-drafted except English. Tests cover
locale normalization, fallback chains, direction, ICU-lite formatting and quoting, the runtime,
catalog rules (plural-only arguments, missing forms, allowEmpty), plugin strings, and that every
framework catalog passes the checks.
2026-09-29 09:53:49 +07:00
CRT
2b8161fedc i18n: dependency-free message runtime, catalog checks, plugin strings, native strings
- runtime/i18n.ts: ICU-lite messages (placeholders as text, Intl.PluralRules plurals with exact
  forms, selectordinal, select, number/date/time), fallback chains (pt-BR -> pt -> en, ar-x-fm ->
  ar), X and legacy code aliases, RTL by locale, lazy catalogs, live onChange. Apostrophes are
  literal except right before { } # or another apostrophe.
- runtime/i18nCheck.ts: rules for contributed catalogs (shape, keys, syntax, placeholder parity,
  select options, markup/control characters, lengths). An argument English only uses to choose a
  plural form may be dropped; missing plural forms are warnings; meta "allowEmpty" fragments.
- runtime/pluginI18n.ts: api.i18n bound per plugin (register/t/locale/dir/onChange/number/date/
  relative/list); the UI kit's own words follow the app's language. pageLang.ts reports the
  site's <html lang>. shell/messages.ts: shell-model words.
- waybetter-host i18n.rs: NativeStrings (validated plain text, caps, one-pass {name} fill, page
  payload by prefix), system_locales via sys-locale; TabState.lang.
- JSON Schemas for catalogs and translator notes; npm exports waybetter/i18n, /i18n/check,
  /i18n/plugin.
2026-09-29 09:53:48 +07:00
CRT
c404dd3dd0 runtime: styles for created roots are constructed sheets (CSP-proof)
- styles.ts: adoptStyles(root, css) adopts a constructed stylesheet into a shadow root or document
  (not governed by a page's CSP, parsed once, stays with the root when its host is moved);
  <style> fallback where constructable sheets are missing or refused.
- UI kit: the kit's shadow root and each dialog's `css` use it (dialog CSS goes with the dialog).
- Plugin API: api.adoptCSS(root, css) and scope.adoptCSS (removed on dispose); injectCSS keeps its
  <style> and, when a CSP leaves it without a sheet, applies the same rules as an adopted sheet.
- tests/styles.test.ts.
2026-09-29 04:09:14 +07:00
CRT
0c1ea611e7 runtime: plugin commands for the command palette (api.commands / scope.commands: register, list, run, owner = the starting plugin, removed on stop, caps, in-page shortcuts); host: start/stop scripts own and drop a plugin's commands; dev_start_script with sourceURL + devError for live reload; devErrors (file:line from a start failure) 2026-09-29 01:35:44 +07:00
CRT
26684e18d7 Plugin permissions and app installs: @permissions header, per-plugin API views, validated install/remove
- host plugins.rs: PERMISSIONS, parse_permissions, ScriptPlugin.permissions/problems (None = legacy,
  full API), validate_plugin (file name, 2 MiB, UTF-8 text without binary bytes, header with @name
  and @version, valid @permissions, network:none refused when the code calls network APIs),
  source_findings, PluginStore::install (atomic rename, never enables, keeps the enabled state on
  update) / remove / is_enabled / file_hash. start/stop scripts run the module body, construction,
  start() and stop() inside window.<global>.withPlugin(id, grants, fn) when the runtime has it.
- runtime permissions.ts: parsePermissions, scopePluginApi (undeclared gated members throw a
  PluginPermissionError; scope().ui gated like api.ui), createPluginContext (the view of the plugin
  whose code runs; legacy = full API). A declaration and guard rail, not a sandbox.
- The `commands` permission name comes from the parallel palette-commands work (its API lands there).
2026-09-29 01:08:52 +07:00
CRT
b6dd47e0d5 runtime: font roles in the theme API (fonts per role, --wb-font-<role> vars, UI kit uses the dialog/mono roles); theme schema: font.roles with Google Fonts source 2026-09-28 23:56:37 +07:00
CRT
434b187638 runtime column: set the column attributes on scan (config delivered at document start has no <html> yet), no scrollbar in columns, unread only above both the read items and what is on screen, a hidden 1 px webview counts as off screen 2026-09-28 23:42:21 +07:00
CRT
4bc8c6a933 create-waybetter: npm create waybetter scaffolds plugins (JS/TS), themes and whole apps
- plugin: *.plugin.js with the store header and start/stop on api.scope, storage, observe,
  onKey, the UI kit (toast with action, ui.h settings dialog) and api.theme/--wb-* vars;
  --ts makes a TypeScript project typed by the waybetter package (build keeps the header first)
- theme: JSON with "$schema" -> theme.schema.json, palette derived like themeFromColors,
  font roles (family, tweet), presets
- app: Tauri 2 + waybetter-host + runtime + shell models: SiteSpec, SiteAdapter, shell/tab-chrome/
  site-tab capabilities, tabs_sync, plugin store, a site-only command; presets for youtube.com,
  kick.com, twitch.tv with placeholder selectors; host crate via submodule, path or git
- tests generate into temp dirs: headers via parse_meta (new plugin_meta example), plugin code
  against createCorePluginApi's members, themes against the schema, app TS with tsc against the
  built package, app Rust with cargo metadata/check/test
- wired into bun run check (typecheck incl. checkJs, build:packages, test:create) and pack:check
2026-09-28 23:17:32 +07:00
CRT
376e74884e Deck columns (Power User Mode): shell deckModel (bounded decks, paging layout, focus, unread totals), runtime column mode (hide site chrome, fill width, filters, unread tracking, no requests), host ColumnConfig bounds, TabRole, deck shortcuts, capped unread in TabState; column boxes skip rail rules 2026-09-28 22:55:57 +07:00
CRT
f6d52512a0 runtime: plugin UI kit (api.ui: toast, alert, confirm, prompt, dialog, modal) and theme API (api.theme, --wb-* vars); theme JSON Schema; waybetter 0.2.0
The kit draws in one shadow DOM host in the active theme's colors, corners and font and repaints
live; accessible dialogs (focus trap and return, Esc/Enter rules, alertdialog for alerts and
confirms), stacking with inert, toasts with actions, reduced motion, text-only content (ui.h),
and scope.ui closes a plugin's dialogs on dispose. api.toast routes to it.
2026-09-28 21:47:09 +07:00
CRT
894a9de48f One system for every app: WhatsApp/Discord-style targets run in the same Tauri shell; site is waybetter.fyi 2026-09-28 06:40:57 +07:00
CRT
8821624241 Public: README links npm and the site; package points at git.crt.fyi (0.1.1) 2026-09-28 06:12:55 +07:00
CRT
e5c91a1563 npm: publish as one package waybetter (waybetter/runtime/*, waybetter/shell/*); @waybetter scope is taken 2026-09-28 05:54:03 +07:00
CRT
faf4e5909e README: projects using wayBetter (wayBetter for X first) 2026-09-28 05:46:46 +07:00
CRT
96512c7bb0 packages: make runtime and shell publishable to npm
Drop private from @waybetter/runtime and @waybetter/shell (root stays
private), add per-module exports with types/import conditions backed by
a tsc build (rewriteRelativeImportExtensions rewrites .ts specifiers to
.js in dist), files/sideEffects/engines/keywords/publishConfig, a
prepublishOnly that builds and tests, and a README + copied LICENSE per
package. Root gains build:packages and pack:check scripts. dist/ is
gitignored; the desktop app keeps importing raw src/*.ts by relative
path, unaffected.
2026-09-28 05:41:01 +07:00
CRT
43a9e2e1a7 Extract the wayBetter framework core from wayBetter for X
Site-agnostic parts of the X app, behind a small site adapter:

- crates/waybetter-host: webview-label security policy and tab rect
  clamp, account profiles with native-owned accounts (AccountRules),
  plugin store with bundled-plugin upgrades (PluginHost), signed
  data-only hotfix channel, update scheduling and crash handshake, tab
  payloads/link routing/tab-chrome validation, and (feature "tauri")
  webview helpers and the Windows system menu.
- packages/runtime: DOM hub, request hub, plugin API core, OKLab theme
  color model, split-view rail hiding, link routing and account
  reporting, each configured by a SiteAdapter.
- packages/shell: address bar, pane, link-drop, profile, palette and
  update-chip models, and window controls with the Tauri API injected.

Tests moved/adapted from the app: 45 Rust (headless), 40 TypeScript.
2026-09-28 03:01:33 +07:00