Comparing version 0.0.9 to 1.0.0
@@ -10,4 +10,12 @@ 'use strict'; | ||
constructor(options) { | ||
if (!options.dsn || options.dsn.length === 0) { | ||
// If an empty DSN is passed, we should treat it as valid option which signifies disabling the SDK. | ||
this.url = ""; | ||
this.disabled = true; | ||
} | ||
else { | ||
this.url = new core.API(options.dsn).getStoreEndpointWithUrlEncodedAuth(); | ||
this.disabled = false; | ||
} | ||
this.options = options; | ||
this.url = new core.API(options.dsn).getStoreEndpointWithUrlEncodedAuth(); | ||
this.user = undefined; | ||
@@ -18,2 +26,21 @@ this.request = this.toSentryRequest(options.event.request); | ||
this.beforeSend = this.beforeSend.bind(this); | ||
/** | ||
* Wrap all class methods in a proxy that: | ||
* 1. Wraps all code in try/catch to handle internal erros gracefully. | ||
* 2. Prevents execution if disabled = true | ||
*/ | ||
return new Proxy(this, { | ||
get: (target, key, receiver) => { | ||
return (...args) => { | ||
if (this.disabled) | ||
return; | ||
try { | ||
return Reflect.get(target, key, receiver).apply(target, args); | ||
} | ||
catch (err) { | ||
console.warn(err); | ||
} | ||
}; | ||
}, | ||
}); | ||
} | ||
@@ -145,3 +172,3 @@ /** | ||
name: "toucan-js", | ||
version: "0.0.9", | ||
version: "1.0.0", | ||
}, | ||
@@ -170,3 +197,3 @@ }; | ||
// Build headers (omit cookie header, because we built in in the previous step) | ||
for (const [k, v] of request.headers) { | ||
for (const [k, v] of request.headers.entries()) { | ||
if (k !== "cookie") { | ||
@@ -173,0 +200,0 @@ headers[k] = v; |
@@ -1,27 +0,35 @@ | ||
import { Options as SentryOptions, User, Event as SentryEvent, Breadcrumb as SentryBreadcrumb } from "@sentry/types"; | ||
declare type Options = { | ||
dsn: NonNullable<SentryOptions["dsn"]>; | ||
event: FetchEvent; | ||
environment?: SentryOptions["environment"]; | ||
release?: SentryOptions["release"]; | ||
beforeSend?: (event: Event) => Event; | ||
pkg?: Record<string, any>; | ||
whitelistedHeaders?: string[] | RegExp; | ||
whitelistedCookies?: string[] | RegExp; | ||
whitelistedSearchParams?: string[] | RegExp; | ||
}; | ||
declare type Level = "fatal" | "error" | "warning" | "info" | "debug"; | ||
declare type Breadcrumb = Omit<SentryBreadcrumb, "level"> & { | ||
level?: Level; | ||
}; | ||
declare type Event = Omit<SentryEvent, "level" | "breadcrumbs"> & { | ||
level?: Level; | ||
breadcrumbs?: Breadcrumb[]; | ||
}; | ||
/** | ||
* Sentry client for Cloudflare Workers. | ||
* Adheres to https://docs.sentry.io/development/sdk-dev/overview/ | ||
*/ | ||
import { User } from "@sentry/types"; | ||
import { Options, Breadcrumb, Level } from "./types"; | ||
export default class Toucan { | ||
/** | ||
* If an empty DSN is passed, we should treat it as valid option which signifies disabling the SDK. | ||
*/ | ||
private disabled; | ||
/** | ||
* Options passed to constructor. See Options type. | ||
*/ | ||
private options; | ||
/** | ||
* Full store endpoint with auth search params. Parsed from options.dsn. | ||
*/ | ||
private url; | ||
/** | ||
* Sentry user object. | ||
*/ | ||
private user?; | ||
/** | ||
* Sentry request object transformed from incoming event.request. | ||
*/ | ||
private request; | ||
/** | ||
* Sentry breadcrumbs array. | ||
*/ | ||
private breadcrumbs; | ||
/** | ||
* Sentry tags object. | ||
*/ | ||
private tags?; | ||
@@ -143,3 +151,2 @@ constructor(options: Options); | ||
} | ||
export {}; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -8,4 +8,12 @@ import { API } from '@sentry/core'; | ||
constructor(options) { | ||
if (!options.dsn || options.dsn.length === 0) { | ||
// If an empty DSN is passed, we should treat it as valid option which signifies disabling the SDK. | ||
this.url = ""; | ||
this.disabled = true; | ||
} | ||
else { | ||
this.url = new API(options.dsn).getStoreEndpointWithUrlEncodedAuth(); | ||
this.disabled = false; | ||
} | ||
this.options = options; | ||
this.url = new API(options.dsn).getStoreEndpointWithUrlEncodedAuth(); | ||
this.user = undefined; | ||
@@ -16,2 +24,21 @@ this.request = this.toSentryRequest(options.event.request); | ||
this.beforeSend = this.beforeSend.bind(this); | ||
/** | ||
* Wrap all class methods in a proxy that: | ||
* 1. Wraps all code in try/catch to handle internal erros gracefully. | ||
* 2. Prevents execution if disabled = true | ||
*/ | ||
return new Proxy(this, { | ||
get: (target, key, receiver) => { | ||
return (...args) => { | ||
if (this.disabled) | ||
return; | ||
try { | ||
return Reflect.get(target, key, receiver).apply(target, args); | ||
} | ||
catch (err) { | ||
console.warn(err); | ||
} | ||
}; | ||
}, | ||
}); | ||
} | ||
@@ -143,3 +170,3 @@ /** | ||
name: "toucan-js", | ||
version: "0.0.9", | ||
version: "1.0.0", | ||
}, | ||
@@ -168,3 +195,3 @@ }; | ||
// Build headers (omit cookie header, because we built in in the previous step) | ||
for (const [k, v] of request.headers) { | ||
for (const [k, v] of request.headers.entries()) { | ||
if (k !== "cookie") { | ||
@@ -171,0 +198,0 @@ headers[k] = v; |
{ | ||
"name": "toucan-js", | ||
"version": "0.0.9", | ||
"version": "1.0.0", | ||
"description": "Cloudflare Workers client for Sentry", | ||
@@ -33,2 +33,3 @@ "main": "dist/index.cjs.js", | ||
"devDependencies": { | ||
"@cloudflare/workers-types": "^1.0.7", | ||
"@rollup/plugin-commonjs": "^11.0.2", | ||
@@ -40,2 +41,3 @@ "@rollup/plugin-node-resolve": "^7.1.1", | ||
"@types/jest": "^25.2.1", | ||
"@types/service-worker-mock": "^2.0.1", | ||
"@types/stacktrace-js": "^2.0.3", | ||
@@ -46,2 +48,3 @@ "@types/uuid": "^7.0.2", | ||
"rollup-plugin-typescript2": "^0.27.0", | ||
"service-worker-mock": "^2.0.5", | ||
"ts-jest": "^25.3.1", | ||
@@ -48,0 +51,0 @@ "ts-loader": "^6.2.2", |
<p align="center"> | ||
<img src="https://tinyurl.com/u4oo7cp" alt="Logo" height="300"> | ||
<img src="https://i.imgur.com/zHw4F3x.jpg" alt="Logo" height="300"> | ||
</p> | ||
@@ -11,5 +11,10 @@ | ||
Toucan is reliable [Sentry](https://docs.sentry.io/) client for [Cloudflare Workers](https://developers.cloudflare.com/workers/). Follows [Sentry unified API guidelines](https://docs.sentry.io/development/sdk-dev/unified-api/). | ||
Toucan is a reliable [Sentry](https://docs.sentry.io/) client for [Cloudflare Workers](https://developers.cloudflare.com/workers/). Follows [Sentry unified API guidelines](https://docs.sentry.io/development/sdk-dev/unified-api/). | ||
## Motivation | ||
In Cloudflare Workers isolate model, it is inadvisable to [set or mutate global state within the event handler](https://developers.cloudflare.com/workers/about/how-it-works). The most of JavaScript SDKs use static methods that mutate global state with request metadata, breadcrumbs, tags... This is reasonable, because they were implemented for environments where concurrency does not inherently exist. However, using these SDKs in Workers leads to race conditions, such as logging breadcrumbs and request metadata of interleaved events. | ||
Toucan was created with Workers concurrent model in mind. Being a JavaScript class instantiated per-event, this kind of race-conditions do not exist, because all request metadata are scoped to a particular fetch event. | ||
## Usage | ||
@@ -26,3 +31,3 @@ | ||
addEventListener("fetch", event => { | ||
addEventListener("fetch", (event) => { | ||
const sentry = new Toucan({ | ||
@@ -83,1 +88,20 @@ dsn: "dsn...", | ||
| beforeSend | (event: Event) => Event | This function is applied to all events before sending to Sentry. If provided, all whitelists are ignored. | | ||
## Sensitive data | ||
Toucan does not send [PII (Personally Identifiable Information)](https://docs.sentry.io/data-management/sensitive-data/) by default. | ||
This includes: | ||
- All request Headers | ||
- All request Cookies | ||
- All request search params | ||
- Request body | ||
You will need to whitelist potentially sensitive data using: | ||
- whitelistedHeaders option (array of headers or Regex) | ||
- whitelistedCookies option (array of cookies or Regex) | ||
- whitelistedSearchParams option (array of search params or Regex) | ||
- toucan.setRequestBody function (stringified JSON) | ||
- beforeSend option (if you need more flexibility than whitelistedX functions) |
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
41601
9
853
0
105
19