vantage 0.1.0
vantage: ^0.1.0 copied to clipboard
An in-app QA & developer-tools HUD for Flutter — device simulation, widget inspection, and an extensible plugin architecture for building QA tooling.
Changelog #
0.1.0 #
Redaction keeps the document parseable — approved api-change, 2026-08-01 #
VantageDefaultRedactor now emits a quoted mask where it replaced a quoted
value, so {"password": "hunter2"} redacts to {"password": "[REDACTED]"}
instead of the unparseable {"password": [REDACTED]}. Every text artifact in a
bug bundle goes through this redactor, so the old behaviour handed a developer a
jsonDecode failure on exactly the artifacts that had carried something
sensitive. No public symbol changed — behaviour only.
- Unquoted values are unchanged: form-encoded bodies, query strings and plain
log lines have no quotes to preserve, so
token=abc&page=2still redacts totoken=[REDACTED]&page=2. Pinned by a test, so the fix cannot over-reach. redact()is still idempotent, and the shared corpus is unaffected — it asserts a secret's absence, never the mask's shape.- This closes the item the entry below recorded as "Known and unchanged".
Redaction — approved api-change, 2026-08-01 #
VantageDefaultRedactor guards every contributor's text artifact on the way
into a bug bundle, and a shared corpus found it leaking 13 credential shapes. All
are now covered. No public symbol changed — behaviour only.
- Keys match separator-insensitively, so
accessToken,access_tokenandaccess-tokenare one rule. Dart JSON is overwhelmingly camelCase, so this was the common case, not an edge case. - New key coverage:
sessionId,cvv,cvc,pin,ssn,creditCard,cardNumber,accountNumber,routingNumber,iban,otp,passphrase,credentials,privateKey, and the usual auth headers (Authentication,X-Csrf-Token,X-Amz-Security-Token,X-Firebase-AppCheckand friends). - New shape coverage, for secrets with no key beside them: JWTs (self-
identifying — the header segment always begins
eyJ), credentials embedded in a URL (https://user:pw@host, masking the whole pair), card numbers written in groups (spaces defeat the plain 13–19 digit rule), and US SSNs. - Fixed: the unquoted-value branch swallowed the closing quote of an enclosing
JSON string literal, so redacting a
key=valueshape inside a literal produced unparseable JSON — on exactly the failed-request payloads a tester files a bug about.
Known and unchanged at the time of this entry — superseded by the entry above,
same day: the mask was emitted unquoted, so masking a quoted JSON value yielded
technically invalid JSON. Still best-effort, not a guarantee — the
class dartdoc states what it does and does not catch, and
vantageRedactionCorpus in vantage_network_core pins both.
Core 1.1 — capability batch #
EventSource+ a host-owned merged, timestamped, ring-buffered event bus (VantageScope.eventBus, default capacity 500). RegisteredEventSourceplugins are relayed automatically and stamped with their pluginid.ExportContributor+ an export pipeline with mandatory redaction of text artifacts (VantageScope.buildExport).VantageSensitivity.sensitiveartifacts are dropped unless explicitly requested; text artifacts always pass throughVantageRedactor; plugin ids and filenames are sanitized to one safe path segment each (no traversal); a throwing contributor is isolated and recorded in the manifest.- Scope is stated in the manifest rather than overclaimed:
redacted: truecovers text only, alongsideredactionScope: 'text-artifacts-only'andunredactedBinaryArtifacts.VantageDefaultRedactoris pattern-based best-effort — a safety net over data the plugin already redacted, never the only line of defence. - Email masking is opt-in (
VantageDefaultRedactor(maskEmails: true)) and the pipeline enables it forVantageSensitivity.sensitiveartifacts only, so an ordinary log keeps the addresses a tester needs. - Breaking (experimental API):
ExportContributor.buildExportnow takes aVantageExportContext. Nothing implemented the mixin before, so no plugin is affected.
- Scope is stated in the manifest rather than overclaimed:
VantageScope.captureApp({pixelRatio})— PNG bytes of the app subtree from a core-ownedRepaintBoundaryplaced above the app and inside the simulation. Returns null (never throws) where rasterization is unavailable, before the first paint, or for apixelRatiooutside(0, 8].- The host now detaches every plugin (
onDetach) whenVantageis disposed, so anEventSource's stream controller is released with its plugin. VantageStorage+VantageMemoryStorage: namespaced, debug-only key-value persistence forString/bool/int/double, inert underkReleaseMode. An invalid namespace throwsArgumentError(not an assert), and views nest (a/b/). Core still depends on the Flutter SDK only; a persistent adapter is a later federated package.VantageScope.appRootElementis now populated by the host (same boundary ascaptureApp). No signature change — the getter existed since 1.0; its doc comment now states exactly which element it is (the boundary wrapping the app, whose single child is the app's own root).- Contract-test kit:
expectVantageEventSourceIsBroadcast,expectVantageExportArtifactsSafe, plus four new tests insiderunVantagePluginContractTests(lifecycle-with-scope, broadcast events, bundle-safe artifacts, export-survives-null-capture). src/api/experimental.dartis now a compatibility re-export ofvantage_event.dart+vantage_export.dart.
Slice 1 #
- Initial repository scaffold: pub workspace + melos, strict lints
(
very_good_analysis), CI (format · analyze · api-guard · test), the frozen-contract guard, and the Slice 1 (core shell + plugin API) design spec. - Core shell:
Vantage+Vantage.appBuilder, controller, registry, scope, activation gesture, bubble + docked shell styles, quick actions, contract kit.