Skip to content

Beaver 1.20.0

Choose a tag to compare

@kononenkoAnton kononenkoAnton released this 24 Sep 01:59
· 269 commits to main since this release

Added

  • Log feed: the filter survives reconnects and relaunches, and
    changing it keeps the selected row when it still matches.
    Right-click → Show in Context clears the filter and lands on the
    row.
  • Log feed: multi-select and ⌘C. Selected rows copy as
    HH:mm:ss.SSS [LEVEL] subsystem/category: message lines. The detail
    pane has Copy data / Copy context.
  • Log feed keyboard: ⌘F focuses Search & highlight, ⌘G / ⇧⌘G step
    through matches, e / ⇧E jump to the next / previous error.
  • Log feed: Time column shows its time zone, plus an optional
    Δ column (right-click the header): the time since the previous
    row, or since the selected row when one is selected.
  • Log feed: "⏎ N lines" badge on rows whose message is cut off.
  • Log feed: search event data. The {} chip on Filter / Exclude
    also matches each event's JSON payload. It's off by default, since
    it's slower on big sessions, and saved filters keep it.
  • Storages: edit and copy-key on every key row. Hover a key for
    copy key / copy value / edit / delete; edit reuses the Add-key
    sheet with the key locked. Namespace rows show + / copy right
    next to the name, and Add key is now a green + tile beside the
    Session / Local / Keychain tabs.
  • Storages: changed values flash. After a Reload or auto-refresh,
    keys that appeared or changed get a brief yellow highlight (a
    collapsed namespace flashes on their behalf).
  • Storages: spaces are caught before sending. The device splits
    commands on spaces, so a space in the key, namespace or value blocks
    Save, and the warning says what the device would do instead ("it
    would store a in a namespace named b"). JSON values are sent
    compact; a JSON string containing a space still blocks, explained.
  • Storages: edits are checked. After a save or delete Beaver reads
    the key back from the next snapshot and says Applied (with
    Undo) or Device didn't apply this — see the log. Keychain
    writes ask first. Edit / delete hide for a layer whose command the
    device doesn't list in cmdlist.
  • Storages: multi-line value editor. Stored JSON opens
    pretty-printed and must parse before Save; smart quotes stay off.
  • Storages: search shows matches per layer. Each tab shows its
    match count; clicking it jumps to that layer's first match.
  • Storages: ⌘F focuses search, ⌘R reloads, and a row's
    right-click menu has Edit… / Delete….
  • Storages: "as of" time and a Disconnected — cached strip show
    how old the storage on screen is.
  • Storages: Export storage only, with Redact Keychain values
    on by default. The file uses zapp-support's
    {storageType: {namespace: {key: value}}} shape and opens in Beaver.
  • Storages: the full-value popover has the row's buttons — copy key,
    copy value, edit, delete — plus copy decoded value (pretty-printed
    JSON / decoded text) for JSON-string, Base64 and JWT values.
  • Storages: edit and delete fields inside a JSON value. Expand a
    value stored as JSON text (e.g. player-storage →
    {"volume":0.8}) and hover a field for edit / delete. The SDK
    can only replace a whole key, so Beaver rewrites the JSON with that
    one change and sends it back; the sheet previews the full command.
    Base64 and JWT values stay read-only (re-encoding / a broken
    signature). Row buttons on top-level keys now appear on hover, like
    inner rows.
  • Storages: layer tabs show an icon (clock / database / lock), the
    name in sentence case and a namespace count with a tooltip; empty
    layers are dimmed.

Fixed

  • Log feed: live streaming no longer refetches the session. Each
    append fetches only the new rows and merges them in place, including
    events that arrive late with an earlier timestamp. On a 100k-event
    session an append drops from ~150 ms to under a millisecond. Past
    the 1M-row cap the feed now keeps the newest rows, not the oldest.
  • Log feed: % and _ in Filter / Exclude are literal, regex
    terms ignore case like plain ones, and an invalid regex outlines its
    pill in red instead of silently showing no rows.
  • A failed write shows an error toast instead of dropping events
    silently.
  • Storages: unchanged snapshots no longer pile up. Auto-refresh
    stored a full copy of every layer every 2 s; an unchanged report now
    only updates its time.
  • Storages: overlapping reloads could show stale values and flash
    rows that hadn't changed. A reload that has been overtaken is dropped.
  • Storages: the delete dialog no longer mentions other devices.
  • Storages: the list could stop updating. After a new snapshot
    arrived the key list could keep showing old values until the tab was
    reopened. It now refreshes as soon as the device reports new storage.
  • JSON 0 and 1 showed as false / true in every tree (storage,
    log detail). They are numbers again; only real booleans read as such.
  • Storages: keys stored without a namespace (the SDK reports them
    as {"player-storage": {"undefined": …}}) now show as a plain key,
    and edit / delete target the key itself instead of undefined.

Changed

  • Log feed follows the tail by being at the bottom (D3). Scroll up
    and it stops; a floating N new ↓ pill counts what arrived and
    takes you back. The Auto-scroll toggle is gone.
  • Log detail pane: the message is a monospaced, scrollable block,
    and very large payloads show 200 entries per level with
    Show more.
  • Storages tab restructured (D30 + D31). Session / Local /
    Keychain are back as tabs at the top (one layer visible at a
    time). Inside each tab, every namespace (applicaster.v2,
    continue-watching, etc.) is an expandable row — click the
    chevron (or anywhere on the row) to reveal its inner
    key: value pairs inline. Per-row icons:
    namespace rows have copy-all-as-JSON / add-key-inside
    (no delete — the SDK can't wipe a whole namespace in one call);
    scalar top-level and inner key rows have copy-value / trash.
    The right-side detail pane is gone — everything's visible inline,
    and deeply nested values can be inspected via copy-as-JSON.
  • Tab switches preserve per-screen state (D32). Log feed and
    Storages no longer lose filter / sort / exclude / selected
    layer / expanded namespaces / search term when you jump
    between tabs. State only resets when the session changes,
    which is the expected reset point.
  • Storages tab redesigned with better information density
    (D37).
    Inner rows use a larger monospaced font with more
    breathing room. Every other row picks up a zebra-stripe tint
    so long lists are easier to scan. A new hover-revealed
    expand button on long strings and container values opens a
    read-only popover with the full content monospaced and
    scrollable. Namespace tab chips are a little bigger so they
    read as proper navigation.
  • Add-key sheet now inherits the active layer. The
    Session / Local / Keychain picker is gone — the sheet uses
    whichever tab you opened it from and shows the chosen layer
    as a small colour-coded chip in the title row. There's a new
    optional "Namespace" field if you want the new key to land
    inside a subscope (e.g., applicaster.v2); leave it empty to
    write at the layer's root.

Removed

  • The unused full-text index (event_fts) and its triggers — inserts
    and session deletes no longer pay for them (D40).
  • Inline edit on storage values. Changing a value now means
    delete + add. The common case (flip a feature flag) is binary
    anyway; keeping edit would re-introduce a sheet for a flow that
    should be peek-and-poke.
  • Editing affordances on past sessions (D35). Add / Reload /
    Auto-refresh / per-row add and delete now stay hidden when
    viewing any session other than the live one — those buttons
    would silently no-op because the device that recorded the past
    session is gone. Read-only (copy, expand, search, export) stay
    available so past sessions are still browsable.

Added

  • Network tab. A new tab lists every HTTP(S) request the SDK
    reports (network wire frames, PROTOCOL.md §4.3): method, host +
    path, status (colour-coded: green 2xx, orange 4xx, red 5xx/
    failed), and duration. Select a row to see request/response
    headers and the body rendered as a JSON tree. Filter by search
    text, method, status class, or host (include/exclude); the filter
    bar mirrors the Log feed's. Rows persist per session and reopen
    with it; clearing the log feed clears the Network tab too. Sent
    today by iOS (quick-brick-xray ≥ #2676); Android support is in
    review (Zapp-Frameworks#2869).
    Each request also still appears once in the Log feed under
    native_application/network_requests — that's the SDK's existing
    behaviour and is unchanged (D39).
  • Session export/import now include network requests. An
    exported file carries a top-level "network" array alongside
    "events" and "storage" whenever the session has any; importing
    a file replays those entries back into the new session, same as
    events and storage.
  • Device context in the toolbar. A small chip on the leading
    edge of the toolbar shows the app name, version, device model,
    platform, and OS that recorded the active session. Pulled from
    the SDK's well-known applicaster.v2 storage namespace.
    Right-click the chip → "Copy device fingerprint" copies the
    joined string for pasting into bug reports.
  • Device fingerprint persisted per session (D34). A schema
    migration adds app_name, app_version, device_model,
    platform, and os_version columns to the session table.
    Captured automatically the first time applicaster.v2 arrives,
    then surfaced on Session list rows so past sessions show
    "Miami Heat 11.0.1 · iPhone 15 Pro Max · iOS 26.4.2" instead of
    just a timestamp. Sessions recorded before this build stay
    blank — only future ones backfill.
  • Toast notifications (D33). A small chip slides down from
    the top of the window after every copy / save / delete /
    bookmark / filter action and self-dismisses after 2 seconds.
    Confirms actions that used to be silent (especially copies to
    the clipboard).
  • "Show level and above" right-click action. New entry in the
    log row context menu sets the minimum level to the row you
    clicked — right-click a Warning to instantly hide verbose /
    debug / info noise. A sibling "Reset level to Verbose" appears
    when a level filter is active.
  • One-click install URL (D36). New landing page at
    https://applicaster.github.io/Beaver/ with a Download button
    that always serves the newest signed + notarized build.
    Backed by a stable-named Beaver.zip asset on every Release.
  • Auto-load storage on connect. When a device connects while
    the user is on the Storages tab, the first storage.list now
    fires automatically — no need to click Reload to see anything.

Internal

  • Source tree renamed LoggerNext → Beaver (D38). Xcode
    project, source folder, app entry struct, entitlements, target,
    scheme, SPM library, and the release.sh build output all
    switch to Beaver. The bundle identifier
    (com.applicaster.LoggerNext) and the on-disk Application
    Support path (~/Library/Application Support/LoggerNext/) stay
    put so existing installs keep their data and Sparkle in-place
    upgrades remain valid. Pure refactor — no user-visible change.

Fixed

  • Bookmark popover showed empty after the first bookmark.
    Race between the fire-and-forget write Task and the popover's
    read against LogStore. MainWindow now subscribes to
    .bookmarksChanged and keeps the snapshot continuously
    fresh, so the popover reflects current state regardless of
    scheduling order.
  • "Nothing to show" empty state was left-pinned on Storages.
    Parent LazyVStack(alignment: .leading) was inheriting; the
    empty state now restores its native centered layout via
    .frame(maxWidth: .infinity). The accompanying message also
    branches on session state — past sessions no longer promise a
    Reload that can't work.
  • Toolbar buttons had inconsistent widths. All six action
    buttons are now pinned to 76pt so labels like "Jump To Time"
    no longer stretch past their neighbours.
  • Top control-bar heights now match across tabs. The Log
    feed filter row and the Storages tab row are both pinned to
    48pt so the strip below the toolbar reads as one consistent
    shape regardless of which tab is active.
  • Sessions footer hugged the sidebar seam. The 'N sessions'
    footer now uses .bar material and a wider leading inset so
    the sidebar's rounded corner no longer bleeds through.
  • Add / delete keys inside a namespace. The "+" button on a
    namespace row opens the Add-key sheet with the parent
    pre-filled; the trash button on an inner row deletes just that
    one key. Both use the SDK's existing 3rd-arg subscope on
    storage.<wireKey>.set/delete, no protocol changes.
  • Storage edit / delete / add (D6). The Storages detail pane now
    has Edit and Delete buttons for top-level keys, plus an "Add key"
    button in the top bar. Hits the SDK's existing
    storage.<namespace>.set / storage.<namespace>.delete console
    commands (already shipped — no SDK change needed). Auto-refreshes
    after each change so the table reflects the new state.
  • Jump to Time toolbar button. Click → pick a target time → table
    scrolls to the event with the closest timestamp. Respects the active
    filter, so "what happened at 14:13:42?" inside a level≥warning view
    snaps to the nearest warning around that time. Sets Pause so the
    jump doesn't get yanked away by streaming events.
  • Filter-aware Export. The toolbar's Export action now respects
    the active Log-feed filter. Narrow the view with level/search/exclude
    pills, click Export, and the resulting JSON contains only the rows
    you're looking at. Button label changes to "Export (filtered)" when
    a filter is active so it's clear what's being shipped. Clear the
    filter to export the whole session as before.
  • Saved filter presets. Click the ★ button at the leading edge of
    the filter bar to save the current level/include/exclude combination
    under a name. Apply with one click; delete on hover; the icon fills
    in when an active preset matches the current filter.