allstak 1.1.0
allstak: ^1.1.0 copied to clipboard
AllStak Flutter SDK for error tracking, request telemetry, breadcrumbs, sanitization, and mobile observability.
1.1.0 — 2026-05-30 #
Changed — pub.dev package name #
- The published package name is now
allstak(wasallstak_flutter). Update your dependency toallstak: ^1.1.0and imports topackage:allstak/allstak.dart. The wire SDK identity is unchanged: events still reportsdkName: allstak-flutterand requests still sendUser-Agent: allstak-flutter/<version>.
Changed — Test-runtime session isolation #
- Forced session/log-bridge tests under
flutter testno longer write the production file-backed open-session marker. Production abnormal-session recovery is unchanged; the change prevents parallel test runs from recovering a marker left by another forced test and misreporting a normal session asabnormal.
Added — Auto-armed native crash capture (zero-config) #
- The native crash handlers are now armed automatically from
AllStak.runApp()andAllStak.init()(right afterWidgetsFlutterBinding.ensureInitialized()), so a host app gets iOS POSIX-signal + uncaught-exception and Android NDK/JVM crash capture — plus the next-launch drain of any stashed crash — with no extra call. Gated by the newAllStakConfig.autoInstallNativeHandlers(default on), always skipped under web (kIsWeb) and theflutter testruntime, and a silent no-op when the native side is unavailable.installNativeHandlers()stays as an explicit escape hatch and is now idempotent (the previous-launch crash is drained at most once). - Android NDK signal capture (
liballstak_crash.so) is now default-on in the pluginandroid/build.gradle: the CMake build is wired in automatically when an NDK is present, opt out withallstak.enableNdkCrashCapture=false, and it is auto-skipped (still builds as a pure-Kotlin library) when no NDK is installed, so adding the SDK never hard-fails a build.
Added — Automatic outbound HTTP instrumentation (dart:io + Dio) #
AllStak.runApp()now installs a process-wideHttpOverrides.globalso everydart:ioHttpClientis auto-instrumented as an outbound http-request (real method/host/path/status/duration) with distributed-trace headers (traceparent,x-allstak-*,baggage) injected — coveringpackage:http'sIOClient, Dio's default adapter,Image.network, etc., with zero per-call wiring. Requests to the SDK's own ingest host are skipped (no recursion); an app's pre-existingHttpOverridesis preserved (delegated to) and restored onclose(). Gated byAllStakConfig.enableHttpOverrides(default on), skipped under web and tests.allstak.httpClient()keeps working unchanged.- New dependency-free Dio interceptor:
AllStak.dioInterceptor(wrapperFactory: …)/allStakDioInterceptor(...)for apps that use a non-dart:ioDio adapter or disabled the global overrides. Duck-typed so the SDK never depends onpackage:dio. Seelib/src/dio_interceptor.dartandlib/src/http_overrides.dart.
Added — Automatic logging bridge #
AllStakConfig.captureLogs(default on) wires anAllStakLogBridgefrom init. Attach apackage:loggingstream with one line —AllStak.instance?.attachLogging(Logger.root.onRecord)— and records flow to/ingest/v1/logs;SEVERE/SHOUTrecords and any record carrying anerrorobject are promoted to a captured exception, stamped with the active trace/request ids. Duck-typed againstpackage:loggingso there is no SDK dependency on it. Skipped under theflutter testruntime. Seelib/src/log_bridge.dart.
Also in 1.1.0 — landed 2026-05-29 #
Added — Release-health session tracking (start/end + crash-free) #
- Automatic session lifecycle tied to the Flutter app lifecycle. On init the SDK
opens a session and POSTs
/ingest/v1/sessions/start; on graceful shutdown (or an explicitclose()/endSession()) it POSTs/ingest/v1/sessions/endwith the final status and accumulated duration. Sessions are never sampled so crash-free rates stay accurate. SessionStatusvocabulary (ok/exited/errored/crashed/abnormal) matches the backend/sessions/endcontract; an unhandled/fatal exception marks the sessioncrashed, feeding crash-free-sessions / crash-free-users release health on the server.- New
AllStakConfig.enableAutoSessionTracking(default on); a_SessionLifecycleObserver(WidgetsBindingObserver) drives end-on-detach.AllStak.sessionIdexposes the current session id, also stamped onto error / log / http payloads for correlation. Seelib/src/session.dart.
Added — Offline / persistent transport queue (survive restart + outage) #
- When the live transport cannot deliver an event (network outage, or events
still pending), the SDK persists the already PII-scrubbed wire bytes to a
line-oriented on-disk spool instead of dropping them, and drains the spool on
the next SDK init (AllStak offline-queue behavior). See
lib/src/offline_queue.dart(OfflineQueue,OfflineEntry, now exported from the package root). - Scrub-before-persist: only sanitized bytes ever touch disk. The spool is
bounded (max-entry cap + age-based eviction) and degrades to a silent no-op
when no persistent store is available (web / tests). Session lifecycle calls
(
/sessions/start,/sessions/end) are intentionally never persisted so a replayed stale session can't corrupt release-health math. - New
AllStakConfig.enableOfflineQueue(default on).
Added — Value-pattern PII scrubbing + sendDefaultPii #
- Extended the single sanitizer chokepoint (
lib/sanitizer.dart) with free-text VALUE scrubbing on top of the existing key-name redaction, providing comprehensive PII protection data-scrubbing parity:- Always (regardless of
sendDefaultPii): Luhn-valid credit-card numbers (13–19 digits, space/hyphen separators; Luhn-invalid digit runs such as order ids / timestamps are preserved) and hyphenated US SSNs. - Unless
sendDefaultPii=true(defaultfalse= ): email addresses and validated-octet IPv4 literals.
- Always (regardless of
- Value scrubbing skips identifiers that must reach the wire verbatim (stack-frame
filename/function/absPath, release/sdk/version/dist, URLs/paths/hosts,
trace/span/request ids, timestamps, the SDK's own
sessionId) and the explicitsetUsersubtree (intentional identity; not stripped bysendDefaultPii, following privacy-by-default best practices). Regexes compile once; strings >16 KB are skipped; per-value scrubbing is fail-open so it can never drop an event. - New
ScrubOptions+AllStakConfig.sendDefaultPii(default false) wire through the existingscrub()call in_send.
Added — Native signal / NDK crash capture (async-signal-safe) #
- Broadened native crash capture beyond uncaught-exception handlers, which miss
the dominant class of real mobile crashes:
- iOS (
ios/AllStakPlugin.swift): async-signal-safe POSIXsigactionhandlers for SIGSEGV/SIGABRT/SIGBUS/SIGILL/SIGFPE/SIGTRAP — the force-unwrap traps, bad-pointer accesses, and Mach-derived faults that never raise anNSException. Mirrors the siblingallstak-appleSignalCrashHandler: pre-allocated buffers + a pre-opened fd, singlewrite(), restore the previous disposition, re-raise. (Mach exception ports remain a future bonus; signal handlers are the priority and match the apple SDK.) - Android (
android/src/main/cpp/allstak_crash.c+CMakeLists.txt): an NDKsigactionhandler for the same signals, capturing NDK/native signal crashes the JVMThread.setDefaultUncaughtExceptionHandlermisses. Stack unwound via_Unwind_Backtrace; JNI install bridge passes the crash-file path. The handler makes NO JNI/heap calls — only async-signal-safe writes.
- iOS (
- The signal handler writes a minimal, fixed
ASKC1text record to a pre-opened fd under the app-support / files dir. On the next launch (normal context) the record is read, parsed (lib/src/native_crash.dart), and shipped through the existing_sendtransport as/ingest/v1/errorsmarkednative.crash=true. Stack frames ship as raw0x…return addresses for backend symbolication against uploaded debug images. - New
drainPendingSignalCrashMethodChannel method (iOS + Android) feeding the existing next-launch drain ininstallNativeHandlers(). - Gated behind
AllStakConfig.enableNativeCrashCapture(default on). Degrades gracefully: if the native lib is unavailable (web, tests, or an app that did not opt into the Android NDK build viaallstak.enableNdkCrashCapture=true), signal capture is a silent no-op and the SDK keeps working — adding the SDK never forces an NDK toolchain on apps.
Tests #
test/allstak_flutter_test.dart— session lifecycle (start/end POST contract, status transitions,sessionIdstamping, lifecycle-observer end-on-detach), release auto-detection ordering, and offline-queue integration via injected seams.test/offline_queue_test.dart— enqueue/drain round-trip, bounded cap + age eviction, scrub-before-persist invariant, no-store no-op, and corrupt-line tolerance.test/sanitizer_test.dart— value-pattern scrubbing (Luhn-valid CC vs. Luhn-invalid passthrough, hyphenated SSN, email + IPv4 gated bysendDefaultPii, verbatim-identifier skip list,setUsersubtree preserved) on top of the existing key-name denylist coverage.test/native_crash_test.dart— record parsing (well-formed iOS/Android, unknown-key tolerance, frame cap, corrupt/empty rejection, signal-name mapping), payload shaping (native.crash=truewire contract), and the next-launch drain handoff via a mocked native channel (install gating, drain sequence, opt-out, corrupt-drop).- Full suite green at HEAD (136 tests including the auto-instrumentation suite).
Verification (honest scope) #
- Dart:
flutter pub get+flutter analyze(no issues) +flutter test(all green) all pass;dart formatapplied. - Native syntax/type checks (no device/emulator here):
- iOS Swift:
swiftc -parseof the full plugin against the iphoneos SDK, andswiftc -typecheckof the extracted signal-handler logic against Darwin — both clean (validates thesigaction/backtrace/si_addrAPI usage). - Android C:
clang -fsyntax-only -std=c11 -Wall -Wextra(with JNI +android/log.h/unwind.hstubs, and against the host's realsignal.h) — clean. A real NDK/CMake/Gradle build was NOT run (no NDK installed here).
- iOS Swift:
- On-device E2E delivery of native signal/NDK crashes remains PENDING real device/emulator verification, consistent with the 1.0.3 note below.
1.0.3 — 2026-05-18 #
Fixed — Native plugin registration (Android + iOS) #
pubspec.yamlhad noflutter: plugin:declaration, so the native crash-capture plugins (AllStakPlugin.kt/AllStakPlugin.swift) were never added to the host app's plugin registrar. EveryinstallNativeHandlers()call hit thecatch (_)no-op and native crash capture was dead code.- Added
flutter: plugin: platforms:block declaringandroid.package = io.allstak.flutter,android.pluginClass = AllStakPlugin, andios.pluginClass = AllStakPlugin. - Added the platform module scaffolding required for the declaration to build/register:
android/build.gradle(com.android.library, namespaceio.allstak.flutter),android/src/main/AndroidManifest.xml, andios/allstak_flutter.podspec. - The MethodChannel name
io.allstak.flutter/nativealready matched on the Dart, Kotlin, and Swift sides — no channel rename was needed. - Verified via a throwaway consuming app:
GeneratedPluginRegistrantnow emitsnew io.allstak.flutter.AllStakPlugin()(Android) and[AllStakPlugin registerWithRegistrar:...](iOS). End-to-end native crash delivery still requires real device/emulator verification.
Added — Recursive payload sanitizer #
- New top-level
scrub(payload, {extraDenylist})inlib/sanitizer.dart. 25-term canonical denylist, recursive overMap/Iterable,[REDACTED]substitution,identityHashCodecycle protection. Pure (no caller mutation). Mobile-safe: synchronous, no I/O. - Wired into
AllStak._sendinlib/allstak_flutter.dart— every wire payload is scrubbed beforejsonEncode. One chokepoint protects errors, logs, http, native crashes. - Fail-open: sanitizer exceptions are logged in debug mode and the raw payload is sent so telemetry is never blocked.
Tests #
test/sanitizer_test.dart— 10 group tests (denylist, recursion, cycles, mutation, primitive passthrough, extension denylist, canary).test/allstak_flutter_test.dart— 1 new test asserting the canaryshould_not_leak_flutteris scrubbed in the actual_sendwire body recorded by the in-test HTTP server.- 34/34 tests pass.
1.0.2 #
- Fix: update Dart SDK constraint to
>=3.0.0 <4.0.0for broad compatibility. - Fix: correct repository URL to
github.com/allstak-io/allstak-flutter. - Add: CI workflow with flutter analyze and flutter test.
- Add: Release workflow with pub.dev trusted publishing.
1.0.1 #
- Initial public release of the AllStak Flutter SDK.
- Error tracking, structured logs, HTTP monitoring, distributed tracing, and cron monitoring for Flutter and Dart applications.
0.0.1 #
- Initial development release.