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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@walshydev/toucan-js

v2.6.1

Published

Cloudflare Workers client for Sentry

Downloads

47

Readme

npm version npm version npm version

toucan-js

Toucan is a Sentry client for Cloudflare Workers written in TypeScript.

Usage

npm install --save toucan-js

FetchEvent

import Toucan from 'toucan-js';

addEventListener('fetch', (event) => {
  const sentry = new Toucan({
    dsn: 'dsn...',
    context: event, // Includes 'waitUntil', which is essential for Sentry logs to be delivered. Also includes 'request' -- no need to set it separately.
    allowedHeaders: ['user-agent'],
    allowedSearchParams: /(.*)/,
  });

  sentry.setUser({ id: '1234' });

  event.respondWith(async () => {
    try {
      // Your code

      return new Response('OK', {
        status: 200,
        statusText: 'OK',
      });
    } catch (err) {
      sentry.captureException(err);
      return new Response('Something went wrong', {
        status: 500,
        statusText: 'Internal Server Error',
      });
    }
  });
});

ScheduledEvent

import Toucan from 'toucan-js';

addEventListener('scheduled', (event) => {
  const sentry = new Toucan({
    dsn: 'dsn...',
    context: event, // Includes 'waitUntil', which is essential for Sentry logs to be delivered. Note that there's no request in 'scheduled' events context.
  });

  event.waitUntil(async () => {
    try {
      // Your code
    } catch (err) {
      sentry.captureException(err);
    }
  });
});

Equivalent of above as a module (.mjs)

import Toucan from 'toucan-js';

export default {
  async fetch(request: Request, env: Env, context: Context) {
    const sentry = new Toucan({
      dsn: 'dsn...',
      context, // Includes 'waitUntil', which is essential for Sentry logs to be delivered. Modules workers do not include 'request' in context -- you'll need to set it separately.
      request, // request is not included in 'context', so we set it here.
      allowedHeaders: ['user-agent'],
      allowedSearchParams: /(.*)/,
    });

    try {
      // Your code

      return new Response('OK', {
        status: 200,
        statusText: 'OK',
      });
    } catch (err) {
      sentry.captureException(err);
      return new Response('Something went wrong', {
        status: 500,
        statusText: 'Internal Server Error',
      });
    }
  },
  async scheduled(controller: Controller, env: Env, context: Context) {
    const sentry = new Toucan({
      dsn: 'dsn...',
      context, // Includes 'waitUntil', which is essential for Sentry logs to be delivered. Note that there's no request in 'scheduled' events context.
    });

    context.waitUntil(async () => {
      try {
        // Your code
      } catch (err) {
        sentry.captureException(err);
      }
    });
  },
};

Durable Objects

import Toucan from 'toucan-js';

export class DurableObjectExample {
  state: DurableObjectState;

  constructor(state: DurableObjectState, env: Env) {
    this.state = state;

    // You're not going to instantiate toucan-js here, because that would lead to race-conditions.
  }

  async fetch(request: Request) {
    // Note that we do not need to set 'context' here -- in Durable Objects it is not necessary to explicitly call 'waitUntil' to extend runtime - Durable Objects make sure that all I/O is finished before deconstructing. 'waitUntil' in Durable Objects only exists for backwards compatibility.
    const sentry = new Toucan({
      dsn: 'dsn...',
      request,
      allowedHeaders: ['user-agent'],
      allowedSearchParams: /(.*)/,
      context: this.state, // OPTIONAL: 'context' really isn't necessary in Durable Objects -- as mentioned above, we don't need 'waitUntil' for 'toucan-js' to successfully deliver logs to Sentry. If you provide 'context', 'toucan-js' will call 'waitUntil' instead of just calling 'fetch'. No difference.
    });

    try {
      // your code

      return new Response('OK', {
        status: 200,
        statusText: 'OK',
      });
    } catch (err) {
      sentry.captureException(err);
      return new Response('Something went wrong', {
        status: 500,
        statusText: 'Internal Server Error',
      });
    }
  }
}

Features

  • addBreadcumb: Records a new breadcrumb which will be attached to future events.
  • captureException: Captures an exception event and sends it to Sentry.
  • captureMessage: Captures a message event and sends it to Sentry.
  • setRequestBody: Records incoming request's body which will be attached to future events.
  • setTag: Set key:value that will be sent as tags data with the event.
  • setTags: Set an object that will be merged sent as tags data with the event.
  • setExtra: Set key:value that will be sent as extra data with the event.
  • setExtras: Set an object that will be merged sent as extra data with the event.
  • setUser: Updates user context information for future events.
  • setFingerprint: Overrides the Sentry default grouping.
  • withScope: Creates a new scope and executes the given operation within. The scope is automatically removed once the operation finishes or throws.

Minimal options

| Option | Type | Description | | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | context | Context | This can be any object that contains waitUntil, and optionally request. It can be FetchEvent, ScheduledEvent, DurableObjectState, or .mjs context. Note that DurableObjectState and .mjs ctx don't include request, you will need to set it as 'request' option. | | dsn | string | Sentry Data Source Name. If an empty DSN is passed, we treat it as valid option which signifies disabling the SDK. | | event | DEPRECATED: Use 'context'. FetchEvent | ScheduledEvent | Workers event. Toucan needs this to be able to call waitUntil. | | |

Other options

| Option | Type | Description | | ------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | allowedCookies | string[] | RegExp | Array of allowed cookies, or a regular expression used to explicitly allow cookies of incoming request. If not provided, cookies will not be logged. No effect without request in context. | | allowedHeaders | string[] | RegExp | Array of allowed headers, or a regular expression used to explicitly allow headers of incoming request. If not provided, headers will not be logged. No effect without request in context. | | allowedSearchParams | string[] | RegExp | Array of allowed search params, or a regular expression used to explicitly allow search params of incoming request. If not provided, search params will not be logged. No effect without request in context. | | attachStacktrace | boolean | Attaches stacktraces to capture message. Default true. | | beforeSend | (event: Event) => Event | This function is applied to all events before sending to Sentry. If provided, all allowlists are ignored. | | debug | boolean | Turns debug mode on or off. If debug is enabled, toucan-js will attempt to print out useful debugging information. | | environment | string | Your application's environment (production/staging/...). | | maxBreadcrumbs | number | This variable controls the total amount of breadcrumbs that should be captured. This defaults to 100. | | pkg | object | Essentially your package.json. Toucan will use it to read project name, version, dependencies, and devDependencies. | | release | string | Release tag. | | request | Request | You will want to use this option in Durable Object or .mjs Worker, where request isn't included in context. | | rewriteFrames | { root?: string, iteratee?: (frame: StackFrame) => StackFrame } | Allows you to apply a transformation to each frame of the stack trace. root path will be appended to the basename of the current frame's url. iteratee is a function that takes the frame, applies any transformation on it and returns it back. | | tracesSampleRate | number | Configures the sample rate as a percentage of events to be sent in the range of 0.0 to 1.0. The default is 1.0 which means that 100% of events are sent. If set to 0.1 only 10% of events will be sent. Events are picked randomly. Invalid sample rate (number between 0 and 1 inclusive) results in skipped event. Replaces deprecated sampleRate option. | | tracesSampler | (samplingContext: SamplingContext) => number | boolean | Function to compute sample rate dynamically and filter unwanted traces. Should return a number (sample rate between 0 and 1 inclusive), or a boolean (returning true is equivalent to returning 1 and returning false is equivalent to returning 0). SamplingContext contains request property (if applicable), which includes information about incoming request, but it's safe to read other surrounding state in the closure, such as your worker's environment variables. Invalid return value results in skipped event. tracesSampler takes precedence over tracesSampleRate option. | | transportOptions | { headers?: Record<string, string> } | Custom headers to be passed to Sentry. |

Sensitive data

By default, Toucan does not send any Request property that could carry PII (Personally Identifiable Information) to Sentry.

This includes:

  • All request Headers
  • All request Cookies
  • All request search params
  • Request body

You will need to explicitly allow these data using:

  • allowedHeaders option (array of headers or Regex)
  • allowedCookies option (array of cookies or Regex)
  • allowedSearchParams option (array of search params or Regex)
  • toucan.setRequestBody function
  • beforeSend option (if you need more flexibility than allowedX functions)

Known issues

Source Maps

Make sure to use the absolute paths on the stack frames and Sentry's artifacts, the default ~/ will not match them properly. Any absolute path will work (i.e., /). You will need to use rewriteFrames option to add the prefix to the stack frames.

const toucan = new Toucan({
  dsn: ...
  event,
  rewriteFrames: {
    root: '/'
  }
}

Changing the Sentry's artifacts URL depends on plugin you use to upload your source maps.

Example configuration using @sentry/webpack-plugin:

const SentryWebpackPlugin = require('@sentry/webpack-plugin');
const pkg = require('./package.json');

module.exports = {
  entry: './src/index.ts',
  target: 'webworker',
  devtool: 'source-map',
  plugins: [
    new SentryWebpackPlugin({
      release: `${pkg.name}-${pkg.version}`,
      include: './dist',
      urlPrefix: '/',
    }),
  ],
};

For more information, see this issue.