Skip to content

Record isolates, compare calls, chart a session, dock the inspector and hold or mock requests - #14

Merged
tonytonycoder11 merged 9 commits into
mainfrom
beyond-the-interceptor
Oct 24, 2026
Merged

tonytonycoder11 merged 9 commits into
mainfrom
beyond-the-interceptor

Conversation

@tonytonycoder11

Copy link
Copy Markdown
Contributor

Five milestones of 0.2.0 in one branch, so that CI runs once: calls from other isolates (M19), comparing two calls (M17), statistics and a timeline (M20), dock mode (M21) and mocks and breakpoints (M18). Each has its own commit, in that order. Four more follow: one from a review of the whole branch, two from running the example on an Android emulator, and one line of documentation.

Calls from other isolates. Overrides belong to one isolate, so a call made with Isolate.run or compute was never seen. Flutwire.run and Flutwire.compute stand in for them, and an isolate you start yourself calls Flutwire.attach(). The isolate records its own calls with the redaction and the size limit of the app and sends each snapshot over a named port to the main isolate, which puts the call in the history under an id of its own, because two isolates can number their calls the same.

Comparing two calls. Select two calls and the compare button opens them side by side: the overview, the query, the header fields and the bodies, with what differs marked. Text is compared by line with Myers' algorithm, bounded to 1500 edits so that two bodies with nothing in common cost a bounded amount of work. JSON and XML are laid out first, so a change of indentation is not a difference, a form is compared field by field, and anything else as bytes.

Statistics and a timeline. A summary gives the counts, the error rate, the average, the median and the 95th percentile, the ten slowest calls and the hosts ranked by how often they fail. The timeline lays the latest hundred calls on one line, with the wait for the first byte apart from the answer coming in, and counts how many were in flight at once. A WebSocket, an event stream and a call held at a breakpoint count as calls but take no part in the times.

Dock mode. Flutwire.builder lays the app and the inspector out in one row or column, so the inspector sits beside the app on a wide screen and under it on a phone. The app is always the first child of the same flex, so docking never rebuilds it and it keeps its state, and it sees the smaller screen through its own MediaQuery. The panel has a navigator of its own, so Back stays inside it, the strip between the two resizes it, and the side and the size are kept.

Mocks and breakpoints. FlutwireConfig.interception is off by default, because this is the first thing Flutwire does that changes traffic. A rule matches the address of a request, with * for any run of characters, and optionally its method, and the newest enabled rule that matches wins. A mock answers with a stored response and never opens a connection. A breakpoint holds the request when the app closes it, opens it in the editor used for sending a call again, and sends it on as it was, sends it changed as a call that repeats the original, or stops it so that the app's call fails. Switching a breakpoint off or deleting it sends on what it holds, because a wide rule could otherwise be undone only one request at a time. It works through the dart:io capture, so it does nothing on the web, and a call made in another isolate is recorded but never mocked or held. The held editor shows the real header fields, authorization included, because the request has not been recorded yet.

What the review found, and fixed. Sending or stopping a held request while another one waited closed the next request's editor and left its own on screen, because the page popped whatever was on top. A second abort of a mocked request threw. The recorder's interception hooks were public on an exported class and are internal now. The text writes of a request, the way a body is edited, the bar at the foot of an editor and the routes to a call, a comparison and the rules were each written twice or three times, and a few members were used by tests only.

What the emulator found, and fixed. After a request had been held for a while the average and the percentiles went to minutes, because a held call lasts as long as somebody looked at it. A history kept from earlier runs squeezed the timeline into a corner and ran the labels of its axis together, so it now starts after the latest pause of two minutes. The Save button of the rule editor had shrunk to its text since the bottom bar was shared, and a rule's address was cut before its path.

Checked. The flutwire suite has 1112 tests and the three adapters 15, 12 and 19, all passing, and flutter analyze --fatal-infos and the format check are clean. I ran the other CI jobs locally: the four flutter pub publish --dry-runs, the lowest versions of each package, and the example for Android, the iOS simulator, macOS and the web. On an Android emulator I made a mock and a breakpoint from a call, watched the inspector come forward over the app when a request was held, sent it on changed and as it was, switched the breakpoint off with a request held, docked the inspector, compared two calls, opened the statistics and ran a call through Flutwire.run.

Not checked. Only Android was run. iOS, macOS and the web were built and not run, and none of this touches native code. The Protobuf decoder has still not met a descriptor set from a real protoc. A mock made from a call serves the placeholder where the redaction masked a value, which the editor shows but does not flag.

Targets 0.2.0, Tier 2, M17 to M21.

Interception is off until the app sets FlutwireConfig.interception, because
it is the first thing Flutwire does that changes traffic. A rule matches the
address and optionally the method of a request. A mock answers with a stored
response and sends nothing. A breakpoint holds the request while the app
waits, opens it in the editor used for sending a call again, and sends it on
as it was, sends it changed as a call that repeats the original, or stops it.
Sending or stopping a held request while another one waits used to pop the
page on top of the stack, which by then was the next request's editor. The
page now takes itself off the stack before the request is released, and where
something was pushed over it in the meantime it is removed in place.

A second abort of a mocked request no longer throws, and the interception
hooks of the recorder are internal to the package, as it is exported.

The text writes of a request, the way a body is edited, the bar at the foot of
an editor and the routes to a call, a comparison, the rules and a rule editor
are each written once. Members that only tests used are gone.
A breakpoint that is too wide holds up the app with a request for every call
it makes, and the only way out was to send them on one at a time. A held
request now names the rule that holds it, and when that rule is switched off
or deleted the request goes out as it was held.

The axis and the bars of the timeline repaint when the theme or the ticks
change, the labels of the axis are disposed, and the top bar of the inspector
asks the dock itself instead of being handed two callbacks for it.
Running the example on a device showed four things the tests did not.

A call that was held at a breakpoint took as long as somebody looked at it,
which pulled the average and the percentiles up to minutes. It is now marked
as held whether it was stopped, sent changed or sent as it was, and it takes
no part in the times.

A history that is kept from one run to the next holds calls from hours back,
which squeezed the latest ones into the corner of the timeline and ran the
labels of its axis into each other. The timeline now starts after the latest
pause of two minutes, and a label that would touch the one before it is left
out.

The Save button of the rule editor had shrunk to the width of its text since
the bottom bar was shared, and the address of a rule in the list was cut
before its path. The button fills the bar again and the address wraps over
three lines, staying with its method.
@trueup-by-nacode-studios

Copy link
Copy Markdown

This pull request adds no capability the code did not already have.

68 files read · 3607 ms · against 8b56bbc · engine 1.4.1

@tonytonycoder11 tonytonycoder11 moved this to In progress in Flutwire Oct 24, 2026
@tonytonycoder11
tonytonycoder11 merged commit 7644e94 into main Oct 24, 2026
6 checks passed
@tonytonycoder11
tonytonycoder11 deleted the beyond-the-interceptor branch October 24, 2026 13:48
@tonytonycoder11 tonytonycoder11 moved this from In progress to Shipped in Flutwire Oct 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Shipped

Development

Successfully merging this pull request may close these issues.

1 participant