npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@wuguishifu/crash-observer

v0.0.1

Published

Expo native module that captures native-layer crashes (uncaught exceptions and POSIX signals) and delivers them to your own logging system on the next launch

Downloads

134

Readme

@wuguishifu/crash-observer

An Expo native module that captures crashes at the native layer (uncaught exceptions and, optionally, POSIX signals) and delivers them to your logging system on the next launch.

The library has no networking and no opinions about where reports go. A native crash kills the process, so reports can't reliably be sent in-process anyway — instead, the native layer persists each crash as a file, and on the next launch your JS handler receives the reports and sends them wherever you like (Sentry, your analytics pipeline, a plain HTTP endpoint, ...).

Quick start

import * as CrashObserver from '@wuguishifu/crash-observer';

// at app startup
CrashObserver.start({
  onReport: async (report) => {
    // plug in your own transport - throwing keeps the report for a retry
    await myLogger.send('native-crash', report);
  },
});

// attach whatever identifies the session in your system
CrashObserver.setContext({ userId: user.id, sessionId });

// leave a trail for debugging
CrashObserver.addBreadcrumb({ message: 'opened reader', category: 'navigation' });

Delivery semantics

  • Reports are written to app-private storage at crash time, one file per crash (multiple undelivered crashes don't overwrite each other).
  • On start({ onReport }), every pending report is passed to your handler, oldest first.
  • If the handler resolves, the report is deleted. If it throws, the report is kept and retried on the next start or flushPendingReports call — at-least-once delivery, so make your sink idempotent (report.id is stable).
  • At most maxPendingReports (default 10) reports are kept; the oldest are pruned.
  • start() resolves after delivery finishes. Call it without await if you don't want delivery to block startup.

API

| Function | Description | | --- | --- | | start(options) | Installs crash handlers and delivers pending reports to options.onReport. Returns { delivered, failed }. | | flushPendingReports(handler?) | Re-runs delivery (e.g. after connectivity returns). Defaults to the onReport from start. | | getPendingReports() | Returns undelivered reports, oldest first, without deleting them. | | deleteReport(id) / deleteAllReports() | Manual cleanup if you manage delivery yourself. | | setContext(values) | Merges values into the context attached to future reports. | | clearContext() | Removes all context values. | | addBreadcrumb(crumb) | Records a breadcrumb (message, category, level, data). Kept in memory, capped at maxBreadcrumbs. | | clearBreadcrumbs() | Removes all breadcrumbs. | | simulateCrash(type?) | Actually crashes the app to test the pipeline. Test builds only. |

StartOptions

| Option | Default | Description | | --- | --- | --- | | onReport | – | Your delivery handler. | | installSignalHandlersIOS | false | Also capture SIGSEGV/SIGABRT/etc. on iOS. Opt-in because signal handlers run in a constrained environment and can conflict with other crash SDKs. | | maxBreadcrumbs | 200 | In-memory breadcrumb cap. | | maxPendingReports | 10 | On-disk undelivered report cap. |

CrashReport

{
  id: string;                 // stable unique id (dedupe key)
  timestamp: number;          // epoch ms at capture time
  platform: 'ios' | 'android';
  kind: 'exception' | 'signal';
  name: string;               // e.g. NSRangeException, java.lang.NullPointerException, SIGSEGV
  message: string;
  stack: string;
  thread: string;
  app: { version, build, bundleId };
  device: { model, manufacturer, os };
  context: Record<string, unknown>;   // whatever you passed to setContext
  breadcrumbs: Breadcrumb[];
}

Testing the pipeline

simulateCrash schedules a real native crash off the JS call stack (so React error boundaries can't catch it). Relaunch the app afterwards and your onReport handler will receive the report.

import { simulateCrash, IOS_SIMULATED_CRASH_TYPES, ANDROID_SIMULATED_CRASH_TYPES } from '@wuguishifu/crash-observer';

simulateCrash('null_pointer');

Per-platform types are exported as IOS_SIMULATED_CRASH_TYPES and ANDROID_SIMULATED_CRASH_TYPES, with display labels in SIMULATED_CRASH_TYPE_LABELS.

What this library does not do

  • JS error handling — pair it with an ErrorBoundary / ErrorUtils handler for JS-level errors.
  • Symbolication — stacks are raw native stacks; symbolicate server-side if you need to.
  • Crashes handlers can't see — watchdog terminations, iOS OOM kills, and fatalError-style traps (unless signal handlers are enabled) are not captured.
  • Persistence of context/breadcrumbs across launches — they live in memory and are baked into the report at crash time; re-set them on each launch.