Repository navigation
0.0.9
Added
-
A monotonic clock, an interaction link, and exclusive self time land on every telescope record.
HttpRequestRecord,QueryRecord,EventRecord,MagicModelRecord,MagicCacheRecordandFramePerfRecordall gainatUs(anint? atUsconstructor param stored asatUs ?? FlutterTimeline.now, comparable across record types regardless of wall-clock skew),interactionId(String?) andlinkedBy(String?, one ofzone/frame/window), all three serialized intoJson.HttpRequestRecordadditionally carriesrequestId,startUsandendUsfor exact request/response pairing.FramePerfRecordgainsvsyncStartUsfromFrameTiming.timestampInMicroseconds(FramePhase.vsyncStart); its doc comment marks clock parity withatUsas needing live validation, since the engine documents that timestamp only as microseconds "from some epoch" and a widget test can only inject syntheticFrameTimingvalues, never a real engine-reported one. Every block in aFramePerfRecord.blocksmap gainsselfMicros:FramePerfWatcher's drain now computes each block's exclusive duration fromAggregatedTimings.timedBlocksstart/end nesting (a stack walk over blocks sorted by start, tie-broken by the longer block first) and subtracts directly nested children from the existing inclusivemicros.telescope:framesandtelescope:requestsprint the new fields,linkedByon its own when there is nointeractionId(thewindowcase). Every new constructor parameter is optional or defaulted, so a constructor call that does not passblocksby an explicit record type keeps compiling (magic_devtools/lib/src/telescope_integration.dartdoes); theblockstype is the one exception, below. The skill'srecords.md,mcp-tools.mdandcli-commands.mddocument every new key. (lib/src/records/*.dart,lib/src/watchers/frame_perf_watcher.dart,lib/src/commands/telescope_{frames,requests}_command.dart,skills/fluttersdk-telescope/references/) -
TelescopeRedaction, the credential lists behind the HTTP buffer, andHttpRequestRecord.copyWith.hideRequestHeaders,hideRequestParametersandhideResponseParametersadd names to the defaults (Laravel Telescope merges the same way, it never replaces),hiddenRequestHeaders/hiddenRequestParameters/hiddenResponseParametersread the lowercased lists,redactParameters(data, keys)returns a copy of a Map/List structure with every value under a matching key, at any depth, replaced bymask('********'), never mutating its input, andredactBody(body, keys)does the same for a JSON string, or pair by pair for a form-encoded one. An adapter calls one of them before it stringifies or truncates a body, since neither aMap.toString()nor a cut JSON string parses, and the store cannot mask what it cannot parse.copyWithreplacesrequestHeaders,requestBodyandresponseBodyand keeps every other field,atUsincluded. (lib/src/telescope_redaction.dart,lib/src/internal/redaction_lists.dart,lib/src/records/http_request_record.dart)
Changed
-
BREAKING:
FramePerfRecord.blocksisMap<String, ({int micros, int selfMicros, int count})>. It wasMap<String, ({int micros, int count})>, and Dart record types with different fields are not assignable to each other, so code that builds aFramePerfRecordfrom a map of the old record type, or declares a variable of the old type fromrecord.blocks, stops compiling. AddselfMicrosto the record literal (the inclusivemicrosis a safe value when the nesting is unknown) or let the type be inferred. The JSON shape only gains a key, so a reader ofext.telescope.framesoutput is unaffected. (lib/src/records/frame_perf_record.dart) -
The artisan floor names this batch's release.
fluttersdk_artisanmoves^0.0.16to^0.0.17. The old range already admitted 0.0.17, so a freshpub getresolves nothing differently; what changes is that the floor names the release this package is verified against. artisan 0.0.17 changesstop,restartand a failedstart --cdp-portto reap the app's whole process group, and telescope calls none of those APIs. (pubspec.yaml)
Security
- The HTTP buffer no longer stores credentials verbatim. It is served to AI agents over
ext.telescope.requestsand MCP, and a Magic app's bearer header, a login body'spasswordand a login answer's Sanctumtokenall landed in it as sent.TelescopeStore.recordHttpnow masks, before buffering and before emitting ononHttpRecord: the value of every request header namedauthorization,proxy-authorization,cookie,set-cookieorx-api-key, and, in a body that parses as a JSON object or array or reads as form-encoded (grant_type=password&password=..., where only the matching pair's value changes, and a bracketed key such asuser[password]orcodes[]matches on its last part, as a nested JSON key does), the value underpassword,password_confirmation,current_password,new_password,token,access_token,refresh_token,secret,client_secret,authorization_code,id_token,two_factor_tokenorrecovery_code(request) andtoken,access_token,refresh_token,plain_text_token,secret,client_secret,id_token,two_factor_token,recovery_codes,qr_urlorqr_svg(response), at any depth.qr_urlandqr_svgare on the list because both carry the TOTP secret thatsecretmasks. Names match case-insensitively. An empty value (null,false,'',[],{}) stays visible, a subtree deeper than 64 levels is masked whole so a pathological body cannot overflow the stack, any other body (plain text, a truncated snippet) is kept as given, and a JSON body with nothing to hide keeps its exact bytes. (lib/src/telescope_store.dart,lib/src/telescope_redaction.dart)