pulse_dev

pub.flutter-io.cn CI License: MIT

Pure Dart core for the Pulse Developer Intelligence SDK.

pulse_dev is Flutter-free and works in any Dart project β€” Flutter apps, CLI tools, or server-side Dart. It provides the event model, processing pipeline, privacy engine, network observer, performance instrumentation, and offline storage β€” all behind clean, replaceable interfaces.

For Flutter applications, use pulse_dev_flutter which builds on this package and provides the Pulse static API.


Features

  • πŸ“¦ Typed event model β€” ErrorEvent, ExceptionEvent, BreadcrumbEvent, CustomEvent, NetworkEvent, TransactionEvent
  • πŸ”€ Composable pipeline β€” pluggable EventProcessor chain β†’ sanitizer β†’ transport
  • πŸ”’ Privacy-first sanitization β€” recursive PII redaction for 20+ sensitive key patterns out of the box
  • 🌐 Network monitoring β€” framework-agnostic PulseNetworkObserver; adapters for dio and package:http sold separately
  • ⚑ Performance tracking β€” transactions, spans, and slow operation detection
  • πŸ’Ύ Offline queue β€” FIFO event queue with exponential backoff, configurable retry, and expiration
  • πŸ”Œ Pluggable transport β€” implement PulseTransport to send events anywhere
  • πŸ§ͺ Fully testable β€” injectable Clock, IdGenerator, PulseTransport, and PulseStorage

Installation

dependencies:
  pulse_dev: ^0.1.0

For Flutter projects, use pulse_dev_flutter instead β€” it re-exports everything from this package.


Quick Start (pure Dart)

import 'package:pulse_dev/pulse_dev.dart';

final config = PulseConfig(
  dsn: 'https://key@ingest.example.com/1',
  environment: 'production',
  release: '1.0.0',
  transport: MyHttpTransport(),
);

final pipeline = EventPipeline.fromConfig(config);

try {
  await riskyOperation();
} catch (e, st) {
  await pipeline.process(ExceptionEvent(
    id: const UuidGenerator().newId(),
    timestamp: const SystemClock().now(),
    sdkVersion: kPulseSdkVersion,
    appVersion: config.release,
    environment: config.environment,
    platform: PulsePlatform.dart,
    context: PulseContext.empty,
    exceptionType: e.runtimeType.toString(),
    message: e.toString(),
    stackTrace: st.toString(),
    breadcrumbs: const [],
    handled: true,
  ));
}

Custom Transport

Implement PulseTransport to deliver events to your backend:

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:pulse_dev/pulse_dev.dart';

final class MyHttpTransport implements PulseTransport {
  final Uri _endpoint;
  final String _apiKey;

  MyHttpTransport({required Uri endpoint, required String apiKey})
      : _endpoint = endpoint,
        _apiKey = apiKey;

  @override
  Future<PulseTransportResult> send(PulseEvent event) async {
    try {
      final response = await http.post(
        _endpoint,
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer $_apiKey',
        },
        body: jsonEncode(event.toJson()),
      );
      if (response.statusCode == 429 || response.statusCode >= 500) {
        return PulseTransportResult.retryableFailure;
      }
      if (response.statusCode >= 400) {
        return PulseTransportResult.permanentFailure;
      }
      return PulseTransportResult.success;
    } catch (_) {
      return PulseTransportResult.retryableFailure;
    }
  }

  @override
  Future<void> close() async {}
}

Custom Sanitizer

Override sensitive data redaction for your organisation's needs:

import 'package:pulse_dev/pulse_dev.dart';

final class MyOrgSanitizer extends DefaultSanitizer {
  MyOrgSanitizer()
      : super(
          config: const PulseSanitizationConfig(
            additionalRedactedKeys: {
              'employee_id',
              'internal_project_code',
              'client_secret',
            },
          ),
        );
}

Custom Event Processor

Enrich or filter events before transport:

import 'package:pulse_dev/pulse_dev.dart';

final class EnvironmentTagProcessor implements EventProcessor {
  final String region;

  const EnvironmentTagProcessor({required this.region});

  @override
  PulseEvent? process(PulseEvent event) {
    if (event is CustomEvent) {
      return CustomEvent(
        // copy fields and add region tag
        properties: {...event.properties, 'region': region},
        // ... other fields
      );
    }
    return event; // pass-through for other event types
  }
}

Network Monitoring

import 'package:pulse_dev/pulse_dev.dart';

final observer = PulseNetworkObserver(
  pipeline: pipeline,
  config: PulseNetworkConfig(
    enabled: true,
    captureHeaders: false,          // never capture headers by default
    captureBody: false,             // never capture body by default
    redactQueryParameters: const {'token', 'api_key'},
  ),
);

// Use with an HTTP adapter:
// - package:pulse_http β†’ PulseHttpClient
// - package:pulse_dio  β†’ PulseDioInterceptor

Performance Tracking

import 'package:pulse_dev/pulse_dev.dart';

final transaction = pipeline.startTransaction('checkout_flow');

try {
  final span = transaction.startSpan('validate_cart');
  await validateCart();
  span.finish();

  final paySpan = transaction.startSpan('process_payment');
  await processPayment();
  paySpan.finish();

  transaction.finish(status: 'ok');
} catch (e, st) {
  transaction.finish(status: 'error', error: e);
  rethrow;
}

Configuration Reference

PulseConfig(
  dsn: 'https://key@ingest.example.com/1',   // required
  environment: 'staging',                     // default: 'production'
  release: '2.0.0+42',                        // app version string
  debug: true,                                // verbose SDK logging
  enabled: true,                              // global kill-switch
  sampleRate: 0.25,                           // drop 75% of events (0.0–1.0)
  maxBreadcrumbs: 50,                         // breadcrumb ring buffer size
  transport: MyHttpTransport(),               // your delivery implementation
  sanitizer: MyOrgSanitizer(),               // custom privacy sanitization
  logger: MyDebugLogger(),                    // custom SDK-internal logging
  processors: [EnvironmentTagProcessor()],   // event enrichment chain
  network: PulseNetworkConfig(...),           // network monitoring options
  performance: PulsePerformanceConfig(...),   // performance monitoring options
  sanitization: PulseSanitizationConfig(...), // sanitization options
)

Package Description
pulse_dev_flutter Flutter integration β€” Pulse static API, error hooks, debug inspector
pulse_http package:http network adapter
pulse_dio package:dio network interceptor

Contributing

See CONTRIBUTING.md.

License

MIT β€” see LICENSE.

Libraries

pulse_dev
Pulse Core β€” Pure Dart Developer Intelligence SDK.