Commit Graph
34 Commits
Author SHA1 Message Date
ZacharyZhang-NY 70e595ddd4 fix(deps): update anyhow soundness patch 2026-07-10 00:08:30 -04:00
ZacharyZhang-NY e68b591a14 fix(deps): remove vulnerable grid release 2026-07-09 23:59:42 -04:00
ZacharyZhang-NY 27899bbc22 fix(deps): update vulnerable tar parser 2026-07-09 23:51:24 -04:00
ZacharyZhang-NY c28ec2bee8 feat(servo): isolate profiles with hardware sidecars 2026-07-09 20:27:22 -04:00
ZacharyZhang-NY 78dc86b18e feat(servo): upgrade to latest secure upstream snapshot 2026-07-09 16:00:50 -04:00
ZacharyZhang-NY 68a4507dbe update 2026-05-18 13:58:36 -04:00
ZacharyZhang-NY 40ab6b4874 feat(sync): round trip cloud snapshots 2026-05-16 00:01:28 -04:00
ZacharyZhang-NY 74b3de54ed Add email + OTP sign-in flow for cloud sync
Replace the "drop a session token in a file" workflow with a real
Chrome-style email login. The Cloudflare worker already had Better
Auth's `email-otp` plugin wired into `SEND_EMAIL`; this commit
builds the renderer-side counterpart.

Worker side:
- Move the OTP sender from `auth@elydora.com` to `browser@elydora.com`
  (wrangler.toml `allowed_sender_addresses` + better_auth.ts
  `EMAIL_OTP_FROM_ADDRESS`). Worker must be redeployed to pick this up.

Client side (`ely_sync_client::email_otp`):
- `send_email_otp(config, email)` POSTs `/api/auth/email-otp/send-verification-otp`
  with `{ email, type: "sign-in" }`.
- `verify_email_otp(config, email, otp)` POSTs `/api/auth/sign-in/email-otp`,
  reads the Better Auth session token from the JSON body's `token` field
  with the `Set-Cookie: better-auth.session_token=…` header as the
  documented fallback channel, and returns it as a `BearerToken`.

Shell side (`shell/auth.rs` + `shell/internal_pages/sync.rs`):
- New `AuthFlowPhase` (Idle / SendingCode / AwaitingOtp / Verifying /
  Error) tracks the in-flight form. Two off-thread workers run the
  HTTP exchanges so the GPUI render loop never blocks.
- Successful verify saves the bearer via `SyncEngine::install_bearer`
  and triggers an immediate snapshot upload, so the user is signed in
  + initial-synced in one click.
- Sync settings page replaces the bare "Sync now" button row with an
  account card: when SignedOut → email field + Send code → OTP field
  + Verify / Resend; when signed in → an account chip + Sign out.
- `trigger_cloud_sync_upload` no longer takes a `Context` param so
  the post-auth path can fire it from the inbox-drain pass without
  needing a window context.
2026-05-15 21:32:50 -04:00
ZacharyZhang-NY a47fbdc09c Wire SyncEngine into BrowserCore
Add per-profile sync orchestration to `ely_browser_core`:

- `SyncEngine::for_profile_dir` loads / generates the persistent
  device identity under `<profile_data>/sync/device.json` and reads
  the bearer token from `<profile_data>/sync/bearer.token`.
- `install_bearer` accepts (or clears) the Better Auth session
  token; everything else stays inert until a token is on disk.
- `upload_now(&BrowserCore)` serialises the user's bookmarks into a
  stable JSON snapshot, ships it via `SyncApiClient::upload_snapshot`,
  and remembers the resulting snapshot id / logical clock / device
  for the UI to surface.
- `BrowserCore::visible_bookmarks_for_sync` returns a read-only view
  the engine can iterate without touching the in-memory state.

The shell / settings-page wiring that calls `upload_now` ships
separately so this commit stays a pure model-layer change with no
runtime behaviour difference until the UI plugs in.
2026-05-15 17:10:30 -04:00
ZacharyZhang-NY 2081c6bd88 Update Cargo.lock for ely_sync_client deps 2026-05-15 17:05:14 -04:00
ZacharyZhang-NY a743435ea1 Transfer Servo IOSurface ports over Mach 2026-05-13 04:05:07 -04:00
ZacharyZhang-NY 05a7a0d67f Present Servo BGRA hardware surfaces 2026-05-13 00:22:00 -04:00
ZacharyZhang-NY a447d52262 T10.5: render IOSurface via gpui::surface(CVPixelBuffer) 2026-05-10 23:37:00 -04:00
ZacharyZhang-NY c4a6ea3c57 T10.4: import sidecar IOSurface mach port into a cached MTLTexture 2026-05-10 23:27:56 -04:00
ZacharyZhang-NY bb0bd0032f T10.2: extract IOSurface mach port from the hardware surface on macOS 2026-05-10 23:01:34 -04:00
ZacharyZhang-NY f7027e6ea5 Profile frame stages via sidecar histogram → ely::servo::perf 2026-05-10 22:30:57 -04:00
ZacharyZhang-NY 048c5dfecd Vendor a headless hardware RenderingContext for Servo
The first concrete step toward the T10 IOSurface zero-copy path
(plan in docs/t10-iosurface-plan.md). Before this commit the sidecar
process could only use `SoftwareRenderingContext` — CPU rasterising
plus an 8 MB RGBA readback per 1080p frame is most of where scroll
latency comes from after the file pipe (a80d039), Vec clone
(e02c0fd), texture dedup (7f3b8b4), and hash swap (3f184ee) have
all landed.

The blocker is purely architectural: `servo-paint-api 0.1` exposes
`OffscreenRenderingContext` only as a child of
`WindowRenderingContext`, which requires a `DisplayHandle +
WindowHandle`. The sidecar has no window. The underlying
`SurfmanRenderingContext` glue *can* drive a hardware adapter
against a `SurfaceType::Generic` offscreen surface, but its
constructor is private. Until the upstream PR lands, this commit
vendors the minimal slice of that glue into `ely_servo_host`:

  * `HardwareOffscreenContext::new(size)` uses
    `Connection::new() → create_adapter()` (real GPU, not the
    software adapter) and a `SurfaceType::Generic` offscreen
    surface. On macOS the surfman CGL backend backs that surface
    with an `IOSurface` — exactly the thing the IOSurface bridge
    in subsequent commits will reach for.
  * Implements `servo::RenderingContext` so it slots into
    `ServoBuilder::rendering_context` wherever the existing
    `SoftwareRenderingContext` does, with no other Servo-side
    knowledge.
  * Scope deliberately narrow: only the methods Servo's headless
    readback actually calls. `create_texture` /
    `destroy_texture` / `connection` / `refresh_driver` fall
    through to the trait's `None` defaults. `read_to_image` inlines
    the upstream `Framebuffer::read_framebuffer_to_image` helper so
    we don't reach for a private helper that may change shape.
  * No `RawWindowHandle` and no `RefreshDriver` — both belong to
    paths the headless sidecar doesn't take.

The whole thing is feature-gated on `hardware-render`. Default
builds compile zero new lines; the additional surfman / gleam /
glow / euclid / image / log deps are all `optional = true`. Sidecar
binary still uses `SoftwareServoHost` until a follow-up commit
threads the new context in behind a CLI flag.

A smoke test at `tests/hardware_rendering_context.rs` constructs
the context. On a host with a real GPU it returns `Ok`; on a no-GPU
CI host it logs the surfman cause and reports `ok` rather than
failing the suite — the test is guarding the wiring, not the
hardware availability. On this Mac it constructs cleanly.

The `expect_used` / `unwrap_used` workspace lints are honoured —
fallible reads return `None` instead of panicking, no `.expect()` /
`.unwrap()` survives in the vendored body. The two `unsafe` blocks
(loading GL function pointers via surfman's `get_proc_address`) are
the same blocks upstream uses, with `#[expect(unsafe_code)]` to
override the workspace `unsafe_code = "deny"` lint locally.

cargo test --bin ely_app: 120 passed.
cargo test -p ely_servo_host --features servo-engine,hardware-render
  --test hardware_rendering_context: 1 passed (constructs cleanly).
Pre-existing `manages_real_servo_webview_lifecycle` failure on
servo.org is unrelated (reproduces on b8795bf without this change,
already documented in T7's commit history).
2026-05-10 20:50:59 -04:00
ZacharyZhang-NY 3f184ee941 Swap SipHash13 → AHash for the live-frame dedup key + record T10 plan
Two T10-flavoured changes in one commit, each independently ship-able
on its own:

1. `web_surface_frame::rgba_hash` switches from std's
   `DefaultHasher` (SipHash13, ~1.5 GB/s) to `ahash::AHasher`
   (~10 GB/s). At 1080p (8 MB per frame) the dedup key drops from
   ~5 ms to ~0.8 ms per cache-miss frame, returning roughly 25 % of
   the 16 ms scroll budget that was being spent hashing the
   newly-arrived RGBA payload. ahash was already in the dependency
   graph transitively via hashbrown, so this only adds a direct
   `ahash = "0.8"` line and one Cargo.lock entry.

2. `docs/t10-iosurface-plan.md` records the full architectural
   roadmap for the actual zero-copy path that supersedes the
   software-pipe pipeline: `OffscreenRenderingContext` against a
   hardware surfman adapter, IOSurface-backed surface on macOS,
   mach-port handoff to the GPUI process, MTLTexture import as an
   external sampler. The document explains why each currently
   shipped commit (`840255f`, `a80d039`, `e02c0fd`, `7f3b8b4`, plus
   this hash swap) is a stepping stone that eventually deletes
   itself once the IOSurface path lands, and names the upstream
   API gap in `servo-paint-api` that blocks step 2.

cargo test --bin ely_app: 120 passed, 0 failed, 2 ignored.
Hash collision probability remains ~1 in 2^64; AHash uses the same
keyspace as the previous SipHash13.
2026-05-10 20:25:01 -04:00
ZacharyZhang-NY 840255f88c Lift the web canvas out of in-flow so the input overlay lands on screen
A GPUI harness boots a real ElyShell, navigates to an external URL, and
asks the input_overlay's sibling canvas tracker where it laid out. On
main before this change the canvas reports

    Bounds { origin: (309, window_height - 17), size: (W - 326, content_h) }

i.e. the overlay's top edge sits at the very bottom of the visible
window. Every user click in the visible area lands above (or beside)
the overlay; the on_mouse_down + capture_any_mouse_up listeners never
even see the event because the hitbox is off-screen. Twelve commits
chased focus/coords/outcome enums on the sidecar side while every click
in the live shell hit empty space.

Root cause: in render_web_surface the rendered web image (img / loading
div / error page) was a non-absolute child of a `.relative().size_full()`
wrapper. The non-absolute child claims `size_full` block-flow height
inside that wrapper, which made the wrapper's intrinsic height
content_height + content_height. The two `.absolute().size_full()`
siblings (viewport_tracker, input_overlay) then sized against that
inflated parent and were positioned in the bottom half — exactly
content_height below where they were supposed to be.

Fix: keep the relative wrapper as the layout owner of the panel slot
(size_full, overflow_hidden, min_w_0) and put the rendered image into
an absolute `inset_0` child of its own. viewport_tracker and
input_overlay stay as absolute siblings. With the image out of in-flow
the wrapper sizes to its parent and the overlay's hitbox lands at
y = top of content area (71 in a 1080-tall window) instead of
y = window_height - 17.

GPUI test harness (`gpui_harness_tests.rs`) is the holdout set:
  - `baseline_overlay_div_receives_simulated_click` proves GPUI's
    occlude + capture_any_mouse_up primitive works under TestAppContext.
  - `baseline_overlay_with_full_listener_combo_receives_click` proves
    the exact listener combo render_input_overlay uses works in
    isolation.
  - `ely_shell_external_canvas_lays_out_inside_window` boots a real
    ElyShell, navigates, and asserts the overlay's measured bounds fit
    inside the visible window. Without the fix above, this test trips
    on bounds extending below the window bottom.

The three new store-layer tests in web_surface_tests.rs pin per-tab
isolation, zero-delta short-circuit, and resize-mid-drain decoupling
invariants the harness work flushed out.

ely_app picks up gpui's test-support feature as a dev-dependency so the
harness can use VisualTestContext + simulate_mouse_*.

cargo test --bin ely_app: 112 passed (was 108 + 4 new harness/store tests).

Remaining work (not in this commit): even with the layout fixed, the
harness shows MouseUp's capture_any_mouse_up still doesn't fire on the
ElyShell tree, while MouseDown's bubble does. Some sibling/ancestor
listener in the live shell is eating the MouseUp capture phase that
the standalone listener-combo baseline does not. Tracked separately.
2026-05-10 17:38:10 -04:00
ZacharyZhang-NY 71088bccb0 Add AppearanceSettings to ely_domain
Introduces a small persistent appearance contract: WallpaperTheme
(Dawn/Violet/Mint/Slate), ThemeMode (System/Light/Dark), reduce_motion.
Defaults to Dawn + System + motion-on. Field accessors and setters live
on the struct so the core can mutate without exposing internals; serde
support uses kebab-case so the on-disk form matches the design CSS
naming.

Tests cover defaults, mutation independence, and a JSON round-trip with
the kebab-case names. serde_json is added as a dev-dependency only —
the production crate does not depend on it.
2026-05-09 18:46:58 -04:00
ZacharyZhang-NY 189b9b8b89 Add current page download pipeline 2026-05-09 12:54:24 -04:00
ZacharyZhang-NY 058d377eab Add elyspace core import export model 2026-05-08 23:05:53 -04:00
ZacharyZhang-NY 2fb6b15e2d Render Servo sidecar frames in shell 2026-05-08 12:43:38 -04:00
ZacharyZhang-NY fcdc2de076 Add Servo sidecar snapshot command 2026-05-08 12:17:41 -04:00
ZacharyZhang-NY b4aedad593 Add about internal page 2026-05-08 00:29:29 -04:00
ZacharyZhang-NY e30d14728b Verify plugin signatures 2026-05-07 23:41:08 -04:00
ZacharyZhang-NY 36aefc929c Store plugin packages 2026-05-07 23:10:34 -04:00
ZacharyZhang-NY cb3ac30b89 Validate plugin manifests 2026-05-07 22:34:34 -04:00
ZacharyZhang-NY a6e1482648 Calculate download checksums 2026-05-07 22:15:56 -04:00
ZacharyZhang-NY 7370ae14b9 Add download file actions 2026-05-07 21:56:09 -04:00
ZacharyZhang-NY ba312e5b85 Add favorite tab controls 2026-05-07 19:33:50 -04:00
ZacharyZhang-NY 1020fa871b Open searches from command bar 2026-05-07 19:20:12 -04:00
ZacharyZhang-NY b787486f8e Add Servo engine host runtime 2026-05-07 18:47:37 -04:00
ZacharyZhang-NY d9a27f3dc4 Initialize Rust GPUI browser shell 2026-05-07 18:27:15 -04:00