Changelog
All notable changes to Elyra Framework are documented here. The format is based on Keep a Changelog, and the project adheres to Semantic Versioning.
While Elyra is pre-1.0, minor versions may contain breaking changes; these are called out under Changed with a migration note.
Unreleased
Testing
- The frontend runtime went from 9 tests to 56.
src/index.test.tsis split intoinvoke,channel,systemandtokensuites over a sharedtest-support.ts, covering the command framing and header contract, every error kind (command/validation/panic/forbidden/unknown), the cancellable path, the event pump's reconnect, backoff and give-up-on-403 behaviour, the snake_case/__sys/*payloads, and the no-token document.
Changed
-
Frontend toolchain moved to the current major line. The
rata newtemplate and the example app now scaffold Vite 8,@sveltejs/vite-plugin-svelte7 and Svelte 5.56 (from Vite 6 / plugin 5 / Svelte 5.20). The runtime package builds on TypeScript 7 and tests on Vitest 4.Upgrading: these raise the Node floor to
^20.19 || >=22.12, declared in both@elyra/runtimeand generated apps. Existing projects keep working on their pinned versions; to move, bump the three devDependencies together — plugin-svelte 7 requires Vite 8 and Svelte >=5.46 as peers. -
Dependency refresh across the workspace lockfile (tokio 1.53, thiserror 2.0.20, ureq 3.4, tray-icon 0.24.2 and friends). No API changes.
0.5.7 — 2026-07-29
A hardening + Laravel-parity release. The IPC surface is now gated by a
per-run token, an origin rule and a capability model; the event bus, the settings
store, the cache and the queue got the durability they were missing; and the
Laravel-shaped pieces that were absent — Log, Config, Secrets, TestApp, a
schema builder, pagination/aggregates/joins/soft deletes/transactions — landed.
Upgrading: four behaviour changes need attention, all listed under
Changed below (IPC token for hand-written frontends, opt-in capabilities for
destructive routes, sidecar_allow for frontend spawn, and the new Asset
shape). See docs/security.md for the new model.
Security
- IPC token + origin-scoped CORS.
Access-Control-Allow-Origin: *was sent on every response, including/__cmd/*,/__sidecar/*,/__sys/*and/__storage/*— any origin able to reach the protocol had full access to commands, the filesystem, the clipboard and process spawning. Production builds now send no CORS headers at all,rata devgets CORS for the exactELYRA_DEV_URLorigin only, and every/__*request must carry this run's random IPC token (injected into the webview asglobalThis.__ELYRA__.token, attached automatically by@elyra/runtimeasx-elyra-token). Rejected requests get403and surface asForbiddenErroron the frontend. - Capabilities for the frontend. Each
/__*route now maps to asecurity::Capability. The everyday ones are granted by default;StoreClear,CacheFlush,StorageDeleteandUpdaterInstallare opt-in viaApp::allow_frontend(..), anddeny_frontend(..)revokes any of them. The expensive ones are also rate-limited per window. - Sidecar spawn is deny-by-default.
/__sidecar/spawnaccepted any program + args from the frontend (arbitrary code execution from a single XSS). The frontend may now only spawn programs named viaApp::sidecar_allow(..); Rust-sideSidecar::spawnis unchanged. shell.openis policy-gated. Onlyhttp/https/mailto(plus schemes added withApp::allow_open_schemes(..)) are handed to the OS;file:URLs, relative/non-existent paths, and anything executable (.exe,.sh,.app,.desktop, …) are refused.App::deny_open_paths()blocks local paths too.- A strict CSP by default.
security::DEFAULT_CSPis served with every HTML response unless overridden withApp::csp(..)or disabled withApp::csp_disabled(). - Request bodies are bounded and depth-checked. 16 MiB by default
(
App::max_request_body), and MessagePack nested deeper than 64 levels is rejected before it reaches serde's recursive deserializer (a ~10 KB body could overflow the stack and abort the process). - Single-instance handshake is authenticated. The rendezvous moved from a
loopback TCP port with a guessable magic string to a
0600Unix socket (TCP on Windows) gated by a random per-install token, and forwarded deep links are now parsed and validated instead of prefix-matched. - Updater hardening. HTTPS is required for the manifest and the artifact
(loopback excepted,
allow_insecureto opt out), the download streams to disk with amax_artifact_bytescap instead of buffering in memory, and a failed signature check leaves nothing staged. - Secrets. New
secretsfeature:Secretsstores tokens in the OS keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service) instead of the clear-text settings file, withget_or_migrate_envto move off env vars. - New
docs/security.md: the IPC surface, the three gating mechanisms, dangerous operations, and a release checklist.
Added
Logfacade. Levels, targets, ISO-8601 timestamps, a rotating file sink (LogProvider::to_app_dir),ELYRA_LOGfor runtime control, andlog_path()for a "send us your log" button. Every command dispatch is traced with its duration; the framework'seprintln!s are gone.Configlayer.elyra.toml,config/*.toml,.envand process env merged into one dotted-key map with${VAR}expansion, typed accessors andsection(). Bound viaConfigProvider.- Test facilities.
elyra::testing::TestAppinvokes commands through the real middleware pipeline without a window (invoke,invoke_ok,invoke_err,invoke_validation_errors,events_on,assert_emitted), andTestShelldrives the actual/__*routing for IPC-level tests. - Schema builder.
elyra_db::Schema::create/table/drop/renamerenders DDL per driver (SQLite/MySQL/Postgres), withRustMigrationfor migrations written in Rust andrata make:migration --rustto scaffold them. - Query-builder parity.
where_like/where_null/where_not_null/where_between/or_where_eq, chainedorder_by,offset,join/left_join,count/sum/avg/min/max/exists,paginate(returningPage),chunk, bulkupdate/delete, soft deletes (#[model(soft_deletes)]+with_trashed/only_trashed/restore), andDatabase::transaction/begin. - Seeders.
App::seeder(..)+ELYRA_SEED=1; Rust migrations run withELYRA_MIGRATE=up|down. - Queue maturity. Retries with exponential backoff, per-job
JobOptions(attempts / backoff / timeout), a failed-jobs list withretry_failed,push_later, typeddispatch/on_typed, bounded capacity with backpressure, and multiple workers (QueueProvider::with_workers). - Typed event channels + bigint codegen.
App::event::<T>("channel")makesrata codegenemit anElyraEventsmap and a narrowedchannel();App::codegen_bigint()exports 64-bit integers asbigint. - Asset caching + ranges. Embedded assets are served borrowed (no per-request
copy) with
ETag,304handling,immutablecaching for fingerprinted files andRange/206support for media. - Cross-platform app menu.
App::menu(..)now renders on Windows and Linux (per-window menu bar via muda), not just macOS. - Bundling beyond macOS.
rata bundlebuilds a.deb(nodpkgneeded) plus a portable.tar.gzon Linux and a portable folder on Windows, and the macOSInfo.plistnow registersCFBundleURLTypesfrom[bundle].deep_link. @elyra/runtimeis publishable. Built todist/with.d.ts, anexportsmap,files, 9 vitest tests, and a provenance publish workflow.- Pool tuning.
DatabaseOptions(max connections, acquire timeout, idle / lifetime) and SQLiteWAL+busy_timeout+foreign_keysby default. - CI. Rust matrix across macOS/Linux/Windows, an MSRV (1.80) job,
cargo deny(advisories / licenses / bans / sources), arata newbuild smoke test, and runtime typecheck + tests + build.
Fixed
- Events reached only one window. The event bus kept a single shared queue, so
with several windows whichever one polled first took the batch and the others
silently lost the events. Each webview now identifies itself
(
x-elyra-client-id) and gets its own queue; anemitfans out to all of them. New:EventBus::next_batch_for,disconnect,client_count. - A panicking command hung the frontend forever. Non-cancellable commands were
dispatched inline in the task owning the protocol responder, so a panic (or a
missing container binding, which panics by design) dropped the responder without
a reply and
await invoke(..)never settled. Commands now always run on their own task; a panic becomes a500withx-elyra-error-kind: panic. - Structured errors were unusable.
Error::Commandprefixed every message with"command failed: ", so aValidationErrorsbag arrived ascommand failed: {"email":[…]}and could not be parsed — the documented validation flow was broken end to end. Messages are now verbatim, the response carriesx-elyra-error-kind, and the runtime throws a typedValidationErrorwith a parsederrorsbag. rata newproduced a project that couldn't build. The scaffold pinnedelyra = "0.1"(against a 0.5.x API) and@elyra/runtime^0.0.0; both now use the CLI's own version.- Store writes were neither atomic nor coalesced.
settings.jsonis now written to a temp file and renamed (with a.bakfallback on read), and bursts ofset()are debounced off the IPC thread instead of writing per call. - Cache was unbounded. Entry-count and byte budgets with LRU eviction
(
Cache::with_limits), and TTLs now use the wall clock as well as the monotonic one, so a deadline no longer freezes while the machine sleeps. - RateLimiter could overshoot its limit.
attempt()was a check followed by a separate increment; it now uses one atomicCache::increment_if_below. where_inand joins. Qualifiedtable.columnidentifiers are accepted (and validated) so joined columns can be filtered and ordered.
Fixed (post-tag)
- The cross-platform app menu broke non-
traybuilds off macOS.ABOUT_MENU_IDandUserEvent::MenuClickwere gated onany(target_os = "macos", feature = "tray"), but the new per-window menu references them unconditionally — socargo build --features databasefailed to compile on Linux and Windows. Both are now unconditional. Caught by the new CI matrix and therata newsmoke test. - Internal crates now carry a
versionalongside theirpath, whichcargo publishrequires andcargo deny's wildcard check flagged. - SQLite URLs built from a filesystem path were broken on Windows. The obvious
format!("sqlite://{}", path.display())produces a drive colon and backslashes where the URL grammar expects an authority and forward slashes, so SQLite answeredunable to open database file. Newelyra_db::sqlite_url(path)(andsqlite_url_opts) build it portably; the model tests now use it. This affected any app deriving its database path at runtime, not just the tests. - Linux builds now need
libxdo(the cross-platform app menu links muda); documented in the getting-started prerequisites. rata newscaffolded a project that still couldn't build. Correcting the version strings wasn't enough: Elyra isn't published to crates.io or npm, soelyra = "0.5.7"and@elyra/runtime@^0.5.7named packages that don't exist. The scaffold now depends on the matching tagged GitHub release — a git dependency for the crate, and the@elyra/runtimetarball attached to the release for the frontend (npm accepts a tarball URL but cannot install a git subdirectory).
Changed
AssetcarriesCow<'static, [u8]>plus anetag(wasVec<u8>+ mime only).CacheProviderandQueueProviderare now constructed (CacheProvider::new()/::with_limits(..),QueueProvider::new()/::with_workers(..)) instead of being unit structs.Queue::pushreturnsbool(falsewhen the queue is full) and the frontend'squeue.pushreports a full queue as an error instead of silently dropping.- Frontends that talk to the bridge without
@elyra/runtimemust now sendx-elyra-token(andx-elyra-client-idfor/__events); the token is exposed to page scripts asglobalThis.__ELYRA__.token. @elyra/runtimeships built output. The package now exportsdist/with.d.tsfiles instead of rawsrc/*.ts; bundlers other than Vite work as a result, and the version tracks the crate (0.5.7).elyraand@elyra/runtimeare both at 0.5.7;rata newpins the CLI's own version instead of a hard-coded one.- MSRV is now declared as 1.94 (was 1.80). The old value was never verified —
the new CI job showed it can't build at all, since sqlx 0.9 requires 1.94 and
several dependencies need
edition2024(Cargo 1.85+). Nothing regressed; the declaration was simply wrong.
0.5.6 — 2026-07-29
Added
- Rate limiter. A cache-backed
RateLimiter(Laravel-RateLimiter-style) —too_many_attempts/hit/attempts/remaining/clear/attempt, with self-expiring per-key counters. Get one viaCache::limiter(). - Task scheduler. A Laravel-
Schedule-styleSchedulerfor recurring background jobs —every/every_minutes/hourly/daily, async closures, bound viaSchedulerProvider. Interval-based (from app start), in-process; registration works before or after start. - Artisan-style generators.
rata make:command,make:provider, andmake:modelscaffold a source file undersrc/(with normalized snake/Pascal names and pluralized model tables) and print themod+ registration wiring step. Existing files are never overwritten. - Validation. A Laravel-style validator (
elyra::validation): check command input against a rule string ("required|email|min:18") and get a per-fieldValidationErrorsbag. Return it via?from a command and the frontend reads the structured errors withvalidationErrors(err)from@elyra/runtime. Rules:required,nullable,string,integer,numeric,boolean,email,url,min,max,size,in,same,confirmed. Core, no deps.
0.5.5 — 2026-07-25
Fixed
-
The bundle updater rejected every update. 0.5.4 verified the downloaded bundle with
codesign --verify --strict --quiet— butcodesignhas no--quietflag, so it exited 2 with "unrecognized option" on every run and the updater concluded that no update was correctly signed. Auto-update was dead on arrival for bundled apps: safe (nothing was installed) but useless.The verification now lives in its own function, carries codesign's own reason into the error message, and is covered by a positive test: a correctly signed bundle must be accepted, both freshly signed and after the
dittoround-trip the updater performs. Rejection tests alone could not catch this — a broken invocation rejects everything, which looks exactly like a working guard.
0.5.4 — 2026-07-25
Fixed
-
The auto-updater no longer breaks a signed macOS
.app.Updater::apply_and_relaunchreplaced only the running executable. Inside a code-signed bundle that is fatal: the signature sealsInfo.plistand every file underContents/, so dropping a new binary in — and leaving the.oldbackup beside it — broke the seal, and macOS then refused to launch the app at all with "The application can't be opened." The app had to be reinstalled by hand.The updater now detects that it is running inside
Foo.app/Contents/MacOS/and switches to whole-bundle replacement: the artifact must be a zip of the signed.app, which is expanded withditto(preserving extended attributes and the signature), verified withcodesign --verify --strict, checked to carry the sameCFBundleIdentifier, and only then swapped in with a rename inside the bundle's own directory — with the outgoing copy moved outside the bundle and a roll-back if the swap fails. Relaunch goes throughopenso LaunchServices re-registers the new bundle.A bare-binary artifact offered to a bundled app is now refused with an explanation instead of applied. Loose (unbundled) executables keep the previous in-place swap.
Releasing note: apps distributed as a signed
.appmust publish a zip of the bundle as the update artifact. A release that keeps publishing the bare executable will now be rejected by the client rather than installed.
0.5.3 — 2026-07-24
Added
rata bundleapp icon. The macOS bundle now generates the native dock/Finder icon: it renders the source image toContents/Resources/AppIcon.icns(sips+iconutil; SVGs rasterized at 1024 viaqlmanage,sipsfallback) and setsCFBundleIconFile. Configure with[bundle].icon, or it auto-detectsapp/public/icon.svg(shipped byrata new),icon.png, etc. Best-effort — the bundle still builds without it.
0.5.2 — 2026-07-22
Added
- Command cancellation.
invokeCancellable(command, ...args)in@elyra/runtimereturns{ id, result, cancel };cancel()aborts the in-flight command on the Rust side (via a request-id header + a/__cancelroute that aborts the command's task). Progress is done with the event bus (documented pattern) — no new API needed. - AI rate limiting + token budget.
AiBuilder::rate_limit(per_minute)throttles every provider call (waits, doesn't error);token_budget(max)refuses new prompts once cumulative tokens hit the cap (Error::Budget);Ai::tokens_used()reports the running total. - Opt-in CSP.
App::csp(policy)sets aContent-Security-Policyheader on HTML responses served overelyra://(off by default — a too-strict policy can break the webview).
Changed
- Locks no longer poison. Switched internal
std::sync::Mutextoparking_lot::Mutexacross the cache, event bus, sidecar, store, queue, windows, and the AI client — a panic while holding a lock can no longer cascade into a poisoned-lock crash.
Fixed
- Sidecar CPU spin. If every command sender dropped while a child was still
running, the owning task's
select!busy-looped on a closed channel at 100% CPU. The command arm is now disabled once the channel closes; the task only waits on the child to exit. - Unbounded EventBus growth. Emitted events buffered without limit when the
frontend was gone/reloading/slow. The queue is now capped (
MAX_QUEUED); when full the oldest half is dropped so a reconnecting frontend still gets recent state. - Cache TTL leak. Expired entries were only reclaimed when the same key was
read again.
CacheProvidernow starts a background sweeper (Cache::sweep) that drops expired entries periodically; it holds aWeakref and stops when the cache is dropped. - Predictable updater temp files. Downloaded updates were written to a static
path in the temp dir. They now use an unpredictable filename, refuse to open a
pre-existing path (
O_EXCL), and are created0600on Unix — mitigating symlink attacks and collisions on shared machines.
Changed
- Migrations run in a transaction. Each migration (and its history row) now commits atomically where the driver supports transactional DDL (SQLite, Postgres); a mid-file failure rolls back cleanly. MySQL auto-commits DDL, so partial state there remains possible — documented.
0.5.1 — 2026-07-17
Added
substrate-corecrate. A tiny, dependency-free crate defining the shared, backend-agnosticCache/Storage/Queuecontracts behind the "one ecosystem" facades — the same traits the Askr/Laravel side can implement. Elyra'sCache,Storage, andQueuenow implement them (re-exported aselyra::substrate); conformance is verified intests/substrate.rs.Cacheis byte-internal, sosubstrateget/putround-trip losslessly.
Changed
Cachestores values as bytes internally (the JSON/typed API is unchanged sugar on top). No behavior change for existing callers.
0.5.0 — 2026-07-17
Added
- Queue facade. An in-process background job queue with the same surface as
Laravel's
Queue::—pusha named job, register an async handler withon. Jobs run in order on a background task; status is emitted onelyra:queue(onQueue). Bind withQueueProvider; push from Rust (ctx.get::<Queue>()) or the frontend (queuein@elyra/runtime). In-process / non-durable by design (durable, cross-process queues are Askr's domain). - Storage facade. A filesystem disk with the same surface as Laravel's
Storage::—put/get/append/exists/delete/size/files/url, every path jailed to the disk root. Bind withStorageProvider::at(root); use from Rust (ctx.get::<Storage>()) or the frontend (storagein@elyra/runtime). - Cache facade. An ergonomic in-process, TTL-aware key-value cache with the
same surface as Laravel's
Cache::(and Askr's shared cache) —get/put/add/remember/increment/forget/flush, typed helpers, arbitrary JSON values. Bind withCacheProvider; use from Rust (ctx.get::<Cache>()) or the frontend (cachein@elyra/runtime). First of the shared "one ecosystem" facades that mirror the Askr/Laravel side over a local backend.
0.4.0 — 2026-07-15
Added
- AI reliability (
ai). Automatic retries with exponential backoff on transient failures / retryable statuses (AiBuilder::retries/retry_backoff), provider failover (Chat::failover([...])), and in-memory response caching for plain prompts (AiBuilder::cache/cache_ttl,clear_cache). - AI provider tools (
ai). Native, server-executed web search and web fetch (web_search/web_fetchonChat,WebSearch/WebFetch/UserLocation). Anthropic-native; OpenAI returnsUnsupported(Responses API not used yet). - AI audio (
ai). Text-to-speech (ai.speech(...).generate()→GeneratedAudio) and transcription (ai.transcribe(bytes, name).generate()), over OpenAI (gpt-4o-mini-tts/whisper-1defaults).
0.3.1 — 2026-07-14
Added
- AI SDK (
aifeature). A new Laravel-inspiredelyra-aicrate, re-exported aselyra::ai: anonymous + named agents (Agent), tools with an automatic tool-use loop (Tool), sub-agents (anAgentused as a tool viasub_agent/AgentTool), structured output (prompt_as::<T>viaserde+schemars), streaming (stream→StreamChunk, ideal for the event bus), images, embeddings, and an in-memory vector store for RAG (VectorStore+cosine_similarity) over Anthropic + OpenAI.AiProviderbinds an env-configuredAiclient into the container. Default text modelclaude-sonnet-5; imagesgpt-image-1. - Single-instance (
App::single_instance). Later launches focus the running window and forward their command line onelyra:second-instance(onSecondInstance), then exit. Portable loopback rendezvous with a per-app handshake. - Deep-linking (
App::deep_link("myapp")). Launch URL viadeepLink.initial(), later URLs onelyra:deep-link(onDeepLink) — macOS open-URL event + Windows/Linux scheme registration; pairs with single-instance for while-running delivery.
0.3.0 — 2026-07-14
Added
-
Sidecar processes (
sidecarfeature). Spawn and manage child processes viasidecarin@elyra/runtime(spawn/write/kill) or theelyra::sidecar::Sidecarhandle;stdout/stderrlines and exit stream on theelyra:sidecarchannel (onSidecar). No extra crate — usestokio. -
Autostart (
autostartfeature). Launch the app at login viaautostartin@elyra/runtime(enable/disable/isEnabled) or theelyra::autostartmodule. Backed byauto-launch(LaunchAgents / registry /.desktop). -
Settings store. A persistent key-value store (
storein@elyra/runtime,Storein the container) backed bysettings.jsonin the OS config dir —get/set/delete/all/clear, arbitrary JSON values. Core, no feature flag. -
Native application menu.
App::menu(Menu::new().submenu(Submenu::new("File")…))adds custom submenus (with accelerators) after the standard app + Edit menus; clicks emitelyra:menu(subscribe withonMenu). Rendered on macOS. -
Global shortcuts (
shortcutsfeature).App::global_shortcut("CmdOrCtrl+Shift+P")registers OS-level keyboard shortcuts; firing one emits theelyra:shortcutevent (subscribe withonShortcut). Backed byglobal-hotkey. -
Window-state persistence.
App::persist_window_state()remembers the primary window's size, position, and maximized state between runs (stored under the OS config directory, keyed by the About name). Dependency-free. -
Window control + file drop.
@elyra/runtimeexportsappWindow(minimize / maximize / fullscreen / close / focus / show / hide / center / setTitle / setSize) with live state viaappWindow.onState, andonFileDropfor native file drops. Backed by newWindowsmethods on the Rust side (usable from commands, with an optional target-window label). Core — no feature flag. -
UI components in
@elyra/runtime. Themed, dependency-free primitives:alert/confirm/promptdialogs,toast()notifications, a ⌘K command palette (registerCommands/openCommandPalette), andcontextMenu(). They read the app's CSS variables, matching the About / update components. -
System integration (
systemfeature). Native desktop essentials exposed through@elyra/runtime: file dialogs (dialog.open/dialog.save), opening URLs/files in the OS (shell.openExternal), the clipboard (clipboard.readText/writeText), OS notifications (notify), and standard paths (paths). Backed byrfd,open,arboard,notify-rust, anddirs; also usable from Rust via theelyra::systemmodule.
0.2.0 — 2026-07-13
Added
-
Models — relation auto-hydration. Declare a relation on a field (
#[model(has_many(Book, fk = "author_id"))] books: Vec<Book>) and the derive skips it as a column, defaults it to empty, and generates awith_<field>batch hydrator that fills it in one query — no more joining aHashMapby hand. Works forhas_many(Vec<T>),has_one/belongs_to(Option<T>;belongs_totargets must beClone). -
Models — non-
i64primary keys. A single-column primary key may now be any type (e.g.String), marked with#[model(id)]. The value is app-supplied and included in theINSERT(no key read-back), andfindtakes that key type. The defaulti64autoincrement behaviour is unchanged. Composite keys remain unsupported. -
Models — column-aware
belongs_to. The owning row is looked up against the related model's actual primary-key column (<T>::PK) instead of a hardcodedid, and the child's foreign key is read by column name — sobelongs_toworks even when the owner's PK column is renamed via#[model(column = "..")]. -
Codegen: serde container attributes are now reflected in the generated TypeScript via
specta-serde—rename/rename_all, tagged and untagged enums (as discriminated unions),flatten(as intersections), andskip. Elyra's numeric policy (64-bit ints and floats render asnumber) is applied on top. -
Database tests: model CRUD now runs against real MySQL and Postgres servers in CI (
model_servers.rs), exercising per-driver placeholders (?vs$n) and key retrieval (last_insert_idvsRETURNING). The tests are opt-in viaELYRA_TEST_MYSQL_URL/ELYRA_TEST_POSTGRES_URLand skip cleanly when unset.
Changed
- Updater:
UpdaterConfig::auto_checknow defaults tofalse. The silent startup check (and its toast) is opt-in via.auto_check(true), so apps no longer notify about updates on launch unless they ask to. - Dependencies: updated to their latest releases —
sqlx0.9 (dynamic SQL is now wrapped inAssertSqlSafe),ureq3,ed25519-dalek3,tray-icon0.24 +muda0.19, and acargo updateacross the tree. No public API changes. - Tooling: CI typechecks the runtime with TypeScript 7 and runs on
Node 24;
@msgpack/msgpackbumped to^3.1.3. - Docs: clarified that code signing, Apple ID / Developer ID, notarization, and binary distribution are the application's responsibility — not the framework's. Removed them from the roadmap and added an explicit "Out of scope" section.
0.1.0 — 2026-07-13
First public release. Everything below is compiled, clippy-clean, and tested
(SQLite for the database layer; GUI/OS integrations are launch-smoked, with
visual or side-effecting steps called out as unverified in the docs).
Added
Core
Appbuilder — fluent assembly of a desktop app: window options, container bindings, providers, middleware, commands, and assets.- Container +
Ctx— a type-keyed service container resolvable from any command, provider, or background task (ctx.get::<T>()). - Providers — two-phase
register/bootwiring, like Laravel service providers. - Middleware pipeline — outermost-first command middleware around dispatch.
IPC bridge
elyra://localhostcustom protocol — the whole app lives under one origin: assets, commands (/__cmd/*), and the event stream (/__events).- MessagePack wire format — compact argument arrays in, named maps out (structs decode to JS objects); no JSON in the hot path.
#[command] async fn— typed commands dispatched on a multi-thread tokio runtime; the UI thread never blocks.Resultcommands surfaceErras a rejected promise (CommandError).
Events
EventBus+channel()— Rust→frontend push over a multiplexed long-poll, batched per flush; a Svelte-readable store on the frontend.
Windows, tray, updater
- Multi-window — additional windows at startup or at runtime via the
container-bound
Windowshandle. - System tray (
trayfeature) — icon + menu; clicks arrive on thetrayevent channel. - Auto-updater (
updaterfeature) — ed25519-verified update manifest, semver comparison, HTTP fetch, and signature-checked staged download. - macOS application menu — an Edit menu (so ⌘C/⌘V/⌘X reach the webview) and a custom About item.
Data (database feature)
Database— one handle over SQLite / MySQL / Postgres via sqlx'sAnydriver, with per-driver placeholder rendering.- Migrations —
rata migratewith batches, reversibledown, and status. #[derive(Model)]— Active Record with CRUD, a typed query builder (where_*,where_in,order_by,limit,get/first),bool↔INTEGER mapping,#[model(column)],#[model(timestamps)], relations (has_many/has_one/belongs_to), and N+1-avoiding eager loading (load_<name>).
Codegen & runtime
rata codegen— specta types → TypeScript definitions and a typedapi.*facade that mirrors every#[command].@elyra/runtime—invoke(),channel(), and the generatedapi.*.
Tooling
- Ratatosk (
rata) —new(scaffold with the Grove theme),dev(Vite HMR +elyra://IPC),codegen,build,bundle(macOS.app+ ad-hoc signing), andmigrate.
UI components
- About dialog — set metadata once with
App::about(AboutInfo::new(..)); the shell serves it at/__aboutand@elyra/runtimerenders a themed dialog. On macOS the standard About <App> menu item opens it; from the frontend, callopenAbout(). - Update component —
App::updater(UpdaterConfig::new(..))adds a silent startup check,/__update/check+/__update/installendpoints, progress on theelyra:updatechannel, and a themed update toast in@elyra/runtime(available → install → download → restart).Updater::apply_and_relaunchreplaces the running binary and re-execs.