Comparing version 0.0.1 to 0.0.5
@@ -8,68 +8,4 @@ 'use strict'; | ||
/*! ***************************************************************************** | ||
Copyright (c) Microsoft Corporation. All rights reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use | ||
this file except in compliance with the License. You may obtain a copy of the | ||
License at http://www.apache.org/licenses/LICENSE-2.0 | ||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED | ||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
MERCHANTABLITY OR NON-INFRINGEMENT. | ||
See the Apache Version 2.0 License for specific language governing permissions | ||
and limitations under the License. | ||
***************************************************************************** */ | ||
var __assign = function() { | ||
__assign = Object.assign || function __assign(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
function __awaiter(thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
} | ||
function __generator(thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
} | ||
var Toucan = /** @class */ (function () { | ||
function Toucan(options) { | ||
class Toucan { | ||
constructor(options) { | ||
this.options = options; | ||
@@ -89,3 +25,3 @@ this.url = new core.API(options.dsn).getStoreEndpointWithUrlEncodedAuth(); | ||
*/ | ||
Toucan.prototype.setTag = function (key, value) { | ||
setTag(key, value) { | ||
if (!this.tags) { | ||
@@ -95,3 +31,3 @@ this.tags = {}; | ||
this.tags[key] = value; | ||
}; | ||
} | ||
/** | ||
@@ -102,5 +38,5 @@ * Set an object that will be merged sent as tags data with the event. | ||
*/ | ||
Toucan.prototype.setTags = function (tags) { | ||
this.tags = __assign(__assign({}, this.tags), tags); | ||
}; | ||
setTags(tags) { | ||
this.tags = { ...this.tags, ...tags }; | ||
} | ||
/** | ||
@@ -112,3 +48,3 @@ * Records a new breadcrumb which will be attached to future events. | ||
*/ | ||
Toucan.prototype.addBreadcrumb = function (breadcrumb) { | ||
addBreadcrumb(breadcrumb) { | ||
if (!breadcrumb.timestamp) { | ||
@@ -118,3 +54,3 @@ breadcrumb.timestamp = this.timestamp(); | ||
this.breadcrumbs.push(breadcrumb); | ||
}; | ||
} | ||
/** | ||
@@ -126,7 +62,7 @@ * Captures an exception event and sends it to Sentry. | ||
*/ | ||
Toucan.prototype.captureException = function (exception) { | ||
var event = this.buildEvent({}); | ||
captureException(exception) { | ||
const event = this.buildEvent({}); | ||
this.options.event.waitUntil(this.reportException(event, exception)); | ||
return event.event_id; | ||
}; | ||
} | ||
/** | ||
@@ -139,8 +75,7 @@ * Captures a message event and sends it to Sentry. | ||
*/ | ||
Toucan.prototype.captureMessage = function (message, level) { | ||
if (level === void 0) { level = "info"; } | ||
var event = this.buildEvent({ level: level, message: message }); | ||
captureMessage(message, level = "info") { | ||
const event = this.buildEvent({ level, message }); | ||
this.options.event.waitUntil(this.postEvent(event)); | ||
return event.event_id; | ||
}; | ||
} | ||
/** | ||
@@ -151,5 +86,5 @@ * Updates user context information for future events. | ||
*/ | ||
Toucan.prototype.setUser = function (user) { | ||
setUser(user) { | ||
this.user = user ? user : undefined; | ||
}; | ||
} | ||
/** | ||
@@ -162,5 +97,5 @@ * In Cloudflare Workers it’s not possible to read event.request's body after having generated a response (if you attempt to, it throws an exception). | ||
*/ | ||
Toucan.prototype.setRequestBody = function (body) { | ||
setRequestBody(body) { | ||
this.request.data = body; | ||
}; | ||
} | ||
/** | ||
@@ -171,4 +106,4 @@ * Builds a Sentry Event and calls waitUntil on the current worker event. | ||
*/ | ||
Toucan.prototype.postEvent = function (data) { | ||
var headers = { | ||
postEvent(data) { | ||
const headers = { | ||
"Content-Type": "application/json", | ||
@@ -179,5 +114,5 @@ }; | ||
body: JSON.stringify(data), | ||
headers: headers, | ||
headers, | ||
}); | ||
}; | ||
} | ||
/** | ||
@@ -189,20 +124,39 @@ * Builds event payload. Applies beforeSend. | ||
*/ | ||
Toucan.prototype.buildEvent = function (additionalData) { | ||
buildEvent(additionalData) { | ||
var _a; | ||
var pkg = this.options.pkg; | ||
const pkg = this.options.pkg; | ||
// 'release' option takes precedence, if not present - try to derive from package.json | ||
var release = this.options.release | ||
const release = this.options.release | ||
? this.options.release | ||
: pkg | ||
? pkg.name + "-" + pkg.version | ||
? `${pkg.name}-${pkg.version}` | ||
: undefined; | ||
// per https://docs.sentry.io/development/sdk-dev/event-payloads/#required-attributes | ||
var payload = __assign(__assign({ event_id: uuid.v4().replace(/-/g, ""), logger: "EdgeWorker", platform: "node", release: release, environment: this.options.environment, user: this.user, timestamp: this.timestamp(), level: "error", modules: pkg | ||
? __assign(__assign({}, pkg.dependencies), pkg.devDependencies) : undefined, breadcrumbs: this.getBreadcrumbs(), tags: this.tags }, additionalData), { request: __assign({}, this.request), sdk: { | ||
const payload = { | ||
event_id: uuid.v4().replace(/-/g, ""), | ||
logger: "EdgeWorker", | ||
platform: "node", | ||
release, | ||
environment: this.options.environment, | ||
user: this.user, | ||
timestamp: this.timestamp(), | ||
level: "error", | ||
modules: pkg | ||
? { | ||
...pkg.dependencies, | ||
...pkg.devDependencies, | ||
} | ||
: undefined, | ||
breadcrumbs: this.getBreadcrumbs(), | ||
tags: this.tags, | ||
...additionalData, | ||
request: { ...this.request }, | ||
sdk: { | ||
name: "toucan-js", | ||
version: "0.0.1", | ||
} }); | ||
var beforeSend = (_a = this.options.beforeSend) !== null && _a !== void 0 ? _a : this.beforeSend; | ||
version: "0.0.5", | ||
}, | ||
}; | ||
const beforeSend = (_a = this.options.beforeSend) !== null && _a !== void 0 ? _a : this.beforeSend; | ||
return beforeSend(payload); | ||
}; | ||
} | ||
/** | ||
@@ -214,6 +168,6 @@ * Converts data from fetch event's Request to Sentry Request used in Sentry Event | ||
*/ | ||
Toucan.prototype.toSentryRequest = function (request) { | ||
toSentryRequest(request) { | ||
// Build cookies | ||
var cookieString = request.headers.get("cookie"); | ||
var cookies = undefined; | ||
const cookieString = request.headers.get("cookie"); | ||
let cookies = undefined; | ||
if (cookieString) { | ||
@@ -225,6 +179,5 @@ try { | ||
} | ||
var headers = {}; | ||
const headers = {}; | ||
// Build headers (omit cookie header, because we built in in the previous step) | ||
for (var _i = 0, _a = request.headers; _i < _a.length; _i++) { | ||
var _b = _a[_i], k = _b[0], v = _b[1]; | ||
for (const [k, v] of request.headers) { | ||
if (k !== "cookie") { | ||
@@ -234,11 +187,11 @@ headers[k] = v; | ||
} | ||
var url = new URL(request.url); | ||
const url = new URL(request.url); | ||
return { | ||
method: request.method, | ||
url: url.protocol + "//" + url.hostname + url.pathname, | ||
url: `${url.protocol}//${url.hostname}${url.pathname}`, | ||
query_string: url.search, | ||
cookies: cookies, | ||
headers: headers, | ||
cookies, | ||
headers, | ||
}; | ||
}; | ||
} | ||
/** | ||
@@ -256,9 +209,9 @@ * This SDK's implementation of beforeSend. If 'beforeSend' is not provided in options, this implementation will be applied. | ||
*/ | ||
Toucan.prototype.beforeSend = function (event) { | ||
var request = event.request; | ||
beforeSend(event) { | ||
const request = event.request; | ||
if (request) { | ||
// Let's try to remove sensitive data from incoming Request | ||
var whitelistedHeaders = this.options.whitelistedHeaders; | ||
var whitelistedCookies = this.options.whitelistedCookies; | ||
var whitelistedSearchParams = this.options.whitelistedSearchParams; | ||
const whitelistedHeaders = this.options.whitelistedHeaders; | ||
const whitelistedCookies = this.options.whitelistedCookies; | ||
const whitelistedSearchParams = this.options.whitelistedSearchParams; | ||
if (whitelistedHeaders) { | ||
@@ -277,8 +230,8 @@ request.headers = this.applyWhitelist(request.headers, whitelistedHeaders); | ||
if (whitelistedSearchParams) { | ||
var params_1 = Object.fromEntries(new URLSearchParams(request.query_string)); | ||
var whitelistedParams_1 = new URLSearchParams(); | ||
Object.keys(this.applyWhitelist(params_1, whitelistedSearchParams)).forEach(function (whitelistedKey) { | ||
whitelistedParams_1.set(whitelistedKey, params_1[whitelistedKey]); | ||
const params = Object.fromEntries(new URLSearchParams(request.query_string)); | ||
const whitelistedParams = new URLSearchParams(); | ||
Object.keys(this.applyWhitelist(params, whitelistedSearchParams)).forEach((whitelistedKey) => { | ||
whitelistedParams.set(whitelistedKey, params[whitelistedKey]); | ||
}); | ||
request.query_string = whitelistedParams_1.toString(); | ||
request.query_string = whitelistedParams.toString(); | ||
} | ||
@@ -291,3 +244,3 @@ else { | ||
return event; | ||
}; | ||
} | ||
/** | ||
@@ -300,11 +253,10 @@ * Helper function that applies 'whitelist' on 'obj' keys. | ||
*/ | ||
Toucan.prototype.applyWhitelist = function (obj, whitelist) { | ||
if (obj === void 0) { obj = {}; } | ||
var predicate = function (item) { return false; }; | ||
applyWhitelist(obj = {}, whitelist) { | ||
let predicate = (item) => false; | ||
if (whitelist instanceof RegExp) { | ||
predicate = function (item) { return whitelist.test(item); }; | ||
predicate = (item) => whitelist.test(item); | ||
} | ||
else if (Array.isArray(whitelist)) { | ||
var whitelistLowercased_1 = whitelist.map(function (item) { return item.toLowerCase(); }); | ||
predicate = function (item) { return whitelistLowercased_1.includes(item); }; | ||
const whitelistLowercased = whitelist.map((item) => item.toLowerCase()); | ||
predicate = (item) => whitelistLowercased.includes(item); | ||
} | ||
@@ -316,15 +268,15 @@ else { | ||
return Object.keys(obj) | ||
.map(function (key) { return key.toLowerCase(); }) | ||
.filter(function (key) { return predicate(key); }) | ||
.reduce(function (whitelisted, key) { | ||
.map((key) => key.toLowerCase()) | ||
.filter((key) => predicate(key)) | ||
.reduce((whitelisted, key) => { | ||
whitelisted[key] = obj[key]; | ||
return whitelisted; | ||
}, {}); | ||
}; | ||
} | ||
/** | ||
* A number representing the seconds elapsed since the UNIX epoch. | ||
*/ | ||
Toucan.prototype.timestamp = function () { | ||
timestamp() { | ||
return Date.now() / 1000; | ||
}; | ||
} | ||
/** | ||
@@ -337,18 +289,9 @@ * Builds Exception as per https://docs.sentry.io/development/sdk-dev/event-payloads/exception/, adds it to the event, | ||
*/ | ||
Toucan.prototype.reportException = function (event, error) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var stacktrace; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, this.buildStackTrace(error)]; | ||
case 1: | ||
stacktrace = _a.sent(); | ||
event.exception = { | ||
values: [{ type: error.name, value: error.message, stacktrace: stacktrace }], | ||
}; | ||
return [2 /*return*/, this.postEvent(event)]; | ||
} | ||
}); | ||
}); | ||
}; | ||
async reportException(event, error) { | ||
const stacktrace = await this.buildStackTrace(error); | ||
event.exception = { | ||
values: [{ type: error.name, value: error.message, stacktrace }], | ||
}; | ||
return this.postEvent(event); | ||
} | ||
/** | ||
@@ -360,35 +303,25 @@ * Builds Stacktrace as per https://docs.sentry.io/development/sdk-dev/event-payloads/stacktrace/ | ||
*/ | ||
Toucan.prototype.buildStackTrace = function (error) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var stack, e_1; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
_a.trys.push([0, 2, , 3]); | ||
return [4 /*yield*/, stacktraceJs.fromError(error)]; | ||
case 1: | ||
stack = _a.sent(); | ||
return [2 /*return*/, { | ||
frames: stack.map(function (frame) { | ||
return { | ||
colno: frame.columnNumber, | ||
lineno: frame.lineNumber, | ||
filename: frame.fileName, | ||
"function": frame.functionName, | ||
}; | ||
}), | ||
}]; | ||
case 2: | ||
e_1 = _a.sent(); | ||
return [2 /*return*/, {}]; | ||
case 3: return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
}; | ||
async buildStackTrace(error) { | ||
try { | ||
const stack = await stacktraceJs.fromError(error); | ||
return { | ||
frames: stack.map((frame) => { | ||
return { | ||
colno: frame.columnNumber, | ||
lineno: frame.lineNumber, | ||
filename: frame.fileName, | ||
function: frame.functionName, | ||
}; | ||
}), | ||
}; | ||
} | ||
catch (e) { | ||
return {}; | ||
} | ||
} | ||
/** | ||
* Get the breadcrumbs. If the stack size exceeds MAX_BREADCRUMBS, returns the last MAX_BREADCRUMBS breadcrumbs. | ||
*/ | ||
Toucan.prototype.getBreadcrumbs = function () { | ||
var MAX_BREADCRUMBS = 100; | ||
getBreadcrumbs() { | ||
const MAX_BREADCRUMBS = 100; | ||
if (this.breadcrumbs.length > MAX_BREADCRUMBS) { | ||
@@ -400,6 +333,5 @@ return this.breadcrumbs.slice(this.breadcrumbs.length - MAX_BREADCRUMBS); | ||
} | ||
}; | ||
return Toucan; | ||
}()); | ||
} | ||
} | ||
module.exports = Toucan; |
@@ -144,1 +144,2 @@ import { Options as SentryOptions, User, Event as SentryEvent, Breadcrumb as SentryBreadcrumb } from "@sentry/types"; | ||
export {}; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -6,68 +6,4 @@ import { API } from '@sentry/core'; | ||
/*! ***************************************************************************** | ||
Copyright (c) Microsoft Corporation. All rights reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use | ||
this file except in compliance with the License. You may obtain a copy of the | ||
License at http://www.apache.org/licenses/LICENSE-2.0 | ||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED | ||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
MERCHANTABLITY OR NON-INFRINGEMENT. | ||
See the Apache Version 2.0 License for specific language governing permissions | ||
and limitations under the License. | ||
***************************************************************************** */ | ||
var __assign = function() { | ||
__assign = Object.assign || function __assign(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
function __awaiter(thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
} | ||
function __generator(thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
} | ||
var Toucan = /** @class */ (function () { | ||
function Toucan(options) { | ||
class Toucan { | ||
constructor(options) { | ||
this.options = options; | ||
@@ -87,3 +23,3 @@ this.url = new API(options.dsn).getStoreEndpointWithUrlEncodedAuth(); | ||
*/ | ||
Toucan.prototype.setTag = function (key, value) { | ||
setTag(key, value) { | ||
if (!this.tags) { | ||
@@ -93,3 +29,3 @@ this.tags = {}; | ||
this.tags[key] = value; | ||
}; | ||
} | ||
/** | ||
@@ -100,5 +36,5 @@ * Set an object that will be merged sent as tags data with the event. | ||
*/ | ||
Toucan.prototype.setTags = function (tags) { | ||
this.tags = __assign(__assign({}, this.tags), tags); | ||
}; | ||
setTags(tags) { | ||
this.tags = { ...this.tags, ...tags }; | ||
} | ||
/** | ||
@@ -110,3 +46,3 @@ * Records a new breadcrumb which will be attached to future events. | ||
*/ | ||
Toucan.prototype.addBreadcrumb = function (breadcrumb) { | ||
addBreadcrumb(breadcrumb) { | ||
if (!breadcrumb.timestamp) { | ||
@@ -116,3 +52,3 @@ breadcrumb.timestamp = this.timestamp(); | ||
this.breadcrumbs.push(breadcrumb); | ||
}; | ||
} | ||
/** | ||
@@ -124,7 +60,7 @@ * Captures an exception event and sends it to Sentry. | ||
*/ | ||
Toucan.prototype.captureException = function (exception) { | ||
var event = this.buildEvent({}); | ||
captureException(exception) { | ||
const event = this.buildEvent({}); | ||
this.options.event.waitUntil(this.reportException(event, exception)); | ||
return event.event_id; | ||
}; | ||
} | ||
/** | ||
@@ -137,8 +73,7 @@ * Captures a message event and sends it to Sentry. | ||
*/ | ||
Toucan.prototype.captureMessage = function (message, level) { | ||
if (level === void 0) { level = "info"; } | ||
var event = this.buildEvent({ level: level, message: message }); | ||
captureMessage(message, level = "info") { | ||
const event = this.buildEvent({ level, message }); | ||
this.options.event.waitUntil(this.postEvent(event)); | ||
return event.event_id; | ||
}; | ||
} | ||
/** | ||
@@ -149,5 +84,5 @@ * Updates user context information for future events. | ||
*/ | ||
Toucan.prototype.setUser = function (user) { | ||
setUser(user) { | ||
this.user = user ? user : undefined; | ||
}; | ||
} | ||
/** | ||
@@ -160,5 +95,5 @@ * In Cloudflare Workers it’s not possible to read event.request's body after having generated a response (if you attempt to, it throws an exception). | ||
*/ | ||
Toucan.prototype.setRequestBody = function (body) { | ||
setRequestBody(body) { | ||
this.request.data = body; | ||
}; | ||
} | ||
/** | ||
@@ -169,4 +104,4 @@ * Builds a Sentry Event and calls waitUntil on the current worker event. | ||
*/ | ||
Toucan.prototype.postEvent = function (data) { | ||
var headers = { | ||
postEvent(data) { | ||
const headers = { | ||
"Content-Type": "application/json", | ||
@@ -177,5 +112,5 @@ }; | ||
body: JSON.stringify(data), | ||
headers: headers, | ||
headers, | ||
}); | ||
}; | ||
} | ||
/** | ||
@@ -187,20 +122,39 @@ * Builds event payload. Applies beforeSend. | ||
*/ | ||
Toucan.prototype.buildEvent = function (additionalData) { | ||
buildEvent(additionalData) { | ||
var _a; | ||
var pkg = this.options.pkg; | ||
const pkg = this.options.pkg; | ||
// 'release' option takes precedence, if not present - try to derive from package.json | ||
var release = this.options.release | ||
const release = this.options.release | ||
? this.options.release | ||
: pkg | ||
? pkg.name + "-" + pkg.version | ||
? `${pkg.name}-${pkg.version}` | ||
: undefined; | ||
// per https://docs.sentry.io/development/sdk-dev/event-payloads/#required-attributes | ||
var payload = __assign(__assign({ event_id: v4().replace(/-/g, ""), logger: "EdgeWorker", platform: "node", release: release, environment: this.options.environment, user: this.user, timestamp: this.timestamp(), level: "error", modules: pkg | ||
? __assign(__assign({}, pkg.dependencies), pkg.devDependencies) : undefined, breadcrumbs: this.getBreadcrumbs(), tags: this.tags }, additionalData), { request: __assign({}, this.request), sdk: { | ||
const payload = { | ||
event_id: v4().replace(/-/g, ""), | ||
logger: "EdgeWorker", | ||
platform: "node", | ||
release, | ||
environment: this.options.environment, | ||
user: this.user, | ||
timestamp: this.timestamp(), | ||
level: "error", | ||
modules: pkg | ||
? { | ||
...pkg.dependencies, | ||
...pkg.devDependencies, | ||
} | ||
: undefined, | ||
breadcrumbs: this.getBreadcrumbs(), | ||
tags: this.tags, | ||
...additionalData, | ||
request: { ...this.request }, | ||
sdk: { | ||
name: "toucan-js", | ||
version: "0.0.1", | ||
} }); | ||
var beforeSend = (_a = this.options.beforeSend) !== null && _a !== void 0 ? _a : this.beforeSend; | ||
version: "0.0.5", | ||
}, | ||
}; | ||
const beforeSend = (_a = this.options.beforeSend) !== null && _a !== void 0 ? _a : this.beforeSend; | ||
return beforeSend(payload); | ||
}; | ||
} | ||
/** | ||
@@ -212,6 +166,6 @@ * Converts data from fetch event's Request to Sentry Request used in Sentry Event | ||
*/ | ||
Toucan.prototype.toSentryRequest = function (request) { | ||
toSentryRequest(request) { | ||
// Build cookies | ||
var cookieString = request.headers.get("cookie"); | ||
var cookies = undefined; | ||
const cookieString = request.headers.get("cookie"); | ||
let cookies = undefined; | ||
if (cookieString) { | ||
@@ -223,6 +177,5 @@ try { | ||
} | ||
var headers = {}; | ||
const headers = {}; | ||
// Build headers (omit cookie header, because we built in in the previous step) | ||
for (var _i = 0, _a = request.headers; _i < _a.length; _i++) { | ||
var _b = _a[_i], k = _b[0], v = _b[1]; | ||
for (const [k, v] of request.headers) { | ||
if (k !== "cookie") { | ||
@@ -232,11 +185,11 @@ headers[k] = v; | ||
} | ||
var url = new URL(request.url); | ||
const url = new URL(request.url); | ||
return { | ||
method: request.method, | ||
url: url.protocol + "//" + url.hostname + url.pathname, | ||
url: `${url.protocol}//${url.hostname}${url.pathname}`, | ||
query_string: url.search, | ||
cookies: cookies, | ||
headers: headers, | ||
cookies, | ||
headers, | ||
}; | ||
}; | ||
} | ||
/** | ||
@@ -254,9 +207,9 @@ * This SDK's implementation of beforeSend. If 'beforeSend' is not provided in options, this implementation will be applied. | ||
*/ | ||
Toucan.prototype.beforeSend = function (event) { | ||
var request = event.request; | ||
beforeSend(event) { | ||
const request = event.request; | ||
if (request) { | ||
// Let's try to remove sensitive data from incoming Request | ||
var whitelistedHeaders = this.options.whitelistedHeaders; | ||
var whitelistedCookies = this.options.whitelistedCookies; | ||
var whitelistedSearchParams = this.options.whitelistedSearchParams; | ||
const whitelistedHeaders = this.options.whitelistedHeaders; | ||
const whitelistedCookies = this.options.whitelistedCookies; | ||
const whitelistedSearchParams = this.options.whitelistedSearchParams; | ||
if (whitelistedHeaders) { | ||
@@ -275,8 +228,8 @@ request.headers = this.applyWhitelist(request.headers, whitelistedHeaders); | ||
if (whitelistedSearchParams) { | ||
var params_1 = Object.fromEntries(new URLSearchParams(request.query_string)); | ||
var whitelistedParams_1 = new URLSearchParams(); | ||
Object.keys(this.applyWhitelist(params_1, whitelistedSearchParams)).forEach(function (whitelistedKey) { | ||
whitelistedParams_1.set(whitelistedKey, params_1[whitelistedKey]); | ||
const params = Object.fromEntries(new URLSearchParams(request.query_string)); | ||
const whitelistedParams = new URLSearchParams(); | ||
Object.keys(this.applyWhitelist(params, whitelistedSearchParams)).forEach((whitelistedKey) => { | ||
whitelistedParams.set(whitelistedKey, params[whitelistedKey]); | ||
}); | ||
request.query_string = whitelistedParams_1.toString(); | ||
request.query_string = whitelistedParams.toString(); | ||
} | ||
@@ -289,3 +242,3 @@ else { | ||
return event; | ||
}; | ||
} | ||
/** | ||
@@ -298,11 +251,10 @@ * Helper function that applies 'whitelist' on 'obj' keys. | ||
*/ | ||
Toucan.prototype.applyWhitelist = function (obj, whitelist) { | ||
if (obj === void 0) { obj = {}; } | ||
var predicate = function (item) { return false; }; | ||
applyWhitelist(obj = {}, whitelist) { | ||
let predicate = (item) => false; | ||
if (whitelist instanceof RegExp) { | ||
predicate = function (item) { return whitelist.test(item); }; | ||
predicate = (item) => whitelist.test(item); | ||
} | ||
else if (Array.isArray(whitelist)) { | ||
var whitelistLowercased_1 = whitelist.map(function (item) { return item.toLowerCase(); }); | ||
predicate = function (item) { return whitelistLowercased_1.includes(item); }; | ||
const whitelistLowercased = whitelist.map((item) => item.toLowerCase()); | ||
predicate = (item) => whitelistLowercased.includes(item); | ||
} | ||
@@ -314,15 +266,15 @@ else { | ||
return Object.keys(obj) | ||
.map(function (key) { return key.toLowerCase(); }) | ||
.filter(function (key) { return predicate(key); }) | ||
.reduce(function (whitelisted, key) { | ||
.map((key) => key.toLowerCase()) | ||
.filter((key) => predicate(key)) | ||
.reduce((whitelisted, key) => { | ||
whitelisted[key] = obj[key]; | ||
return whitelisted; | ||
}, {}); | ||
}; | ||
} | ||
/** | ||
* A number representing the seconds elapsed since the UNIX epoch. | ||
*/ | ||
Toucan.prototype.timestamp = function () { | ||
timestamp() { | ||
return Date.now() / 1000; | ||
}; | ||
} | ||
/** | ||
@@ -335,18 +287,9 @@ * Builds Exception as per https://docs.sentry.io/development/sdk-dev/event-payloads/exception/, adds it to the event, | ||
*/ | ||
Toucan.prototype.reportException = function (event, error) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var stacktrace; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, this.buildStackTrace(error)]; | ||
case 1: | ||
stacktrace = _a.sent(); | ||
event.exception = { | ||
values: [{ type: error.name, value: error.message, stacktrace: stacktrace }], | ||
}; | ||
return [2 /*return*/, this.postEvent(event)]; | ||
} | ||
}); | ||
}); | ||
}; | ||
async reportException(event, error) { | ||
const stacktrace = await this.buildStackTrace(error); | ||
event.exception = { | ||
values: [{ type: error.name, value: error.message, stacktrace }], | ||
}; | ||
return this.postEvent(event); | ||
} | ||
/** | ||
@@ -358,35 +301,25 @@ * Builds Stacktrace as per https://docs.sentry.io/development/sdk-dev/event-payloads/stacktrace/ | ||
*/ | ||
Toucan.prototype.buildStackTrace = function (error) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var stack, e_1; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
_a.trys.push([0, 2, , 3]); | ||
return [4 /*yield*/, fromError(error)]; | ||
case 1: | ||
stack = _a.sent(); | ||
return [2 /*return*/, { | ||
frames: stack.map(function (frame) { | ||
return { | ||
colno: frame.columnNumber, | ||
lineno: frame.lineNumber, | ||
filename: frame.fileName, | ||
"function": frame.functionName, | ||
}; | ||
}), | ||
}]; | ||
case 2: | ||
e_1 = _a.sent(); | ||
return [2 /*return*/, {}]; | ||
case 3: return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
}; | ||
async buildStackTrace(error) { | ||
try { | ||
const stack = await fromError(error); | ||
return { | ||
frames: stack.map((frame) => { | ||
return { | ||
colno: frame.columnNumber, | ||
lineno: frame.lineNumber, | ||
filename: frame.fileName, | ||
function: frame.functionName, | ||
}; | ||
}), | ||
}; | ||
} | ||
catch (e) { | ||
return {}; | ||
} | ||
} | ||
/** | ||
* Get the breadcrumbs. If the stack size exceeds MAX_BREADCRUMBS, returns the last MAX_BREADCRUMBS breadcrumbs. | ||
*/ | ||
Toucan.prototype.getBreadcrumbs = function () { | ||
var MAX_BREADCRUMBS = 100; | ||
getBreadcrumbs() { | ||
const MAX_BREADCRUMBS = 100; | ||
if (this.breadcrumbs.length > MAX_BREADCRUMBS) { | ||
@@ -398,6 +331,5 @@ return this.breadcrumbs.slice(this.breadcrumbs.length - MAX_BREADCRUMBS); | ||
} | ||
}; | ||
return Toucan; | ||
}()); | ||
} | ||
} | ||
export default Toucan; |
{ | ||
"name": "toucan-js", | ||
"version": "0.0.1", | ||
"version": "0.0.5", | ||
"description": "Cloudflare Workers client for Sentry", | ||
@@ -10,3 +10,4 @@ "main": "dist/index.cjs.js", | ||
"build": "rollup -c", | ||
"dev": "rollup -c -w" | ||
"dev": "rollup -c -w", | ||
"test": "jest" | ||
}, | ||
@@ -28,18 +29,21 @@ "repository": { | ||
"@sentry/core": "^5.15.4", | ||
"uuid": "^7.0.3", | ||
"cookie": "^0.4.0", | ||
"stacktrace-js": "^2.0.2" | ||
"stacktrace-js": "^2.0.2", | ||
"uuid": "^7.0.3" | ||
}, | ||
"devDependencies": { | ||
"@rollup/plugin-commonjs": "^11.0.2", | ||
"@rollup/plugin-node-resolve": "^7.1.1", | ||
"@rollup/plugin-commonjs": "^11.0.2", | ||
"@rollup/plugin-replace": "^2.3.1", | ||
"@sentry/types": "^5.15.4", | ||
"@types/cookie": "^0.3.3", | ||
"@types/jest": "^25.2.1", | ||
"@types/stacktrace-js": "^2.0.3", | ||
"@types/uuid": "^7.0.2", | ||
"jest": "^25.3.0", | ||
"rollup": "^2.3.4", | ||
"rollup-plugin-typescript2": "^0.27.0", | ||
"ts-jest": "^25.3.1", | ||
"ts-loader": "^6.2.2", | ||
"typescript": "^3.8.3", | ||
"ts-loader": "^6.2.2", | ||
"webpack": "^4.42.1", | ||
@@ -46,0 +50,0 @@ "webpack-cli": "^3.3.11" |
@@ -0,6 +1,13 @@ | ||
<p align="center"> | ||
<img src="https://tinyurl.com/u4oo7cp" alt="Logo" height="300"> | ||
</p> | ||
[](https://www.npmjs.com/package/toucan-js) | ||
[](https://www.npmjs.com/package/toucan-js) | ||
[](https://www.npmjs.com/package/toucan-js) | ||
# toucan-js | ||
Toucan is reliable [Sentry](https://docs.sentry.io/) client for [Cloudflare Workers](https://developers.cloudflare.com/workers/). It adheres to [Sentry unified API guidelines](https://docs.sentry.io/development/sdk-dev/unified-api/) - with minor differences. | ||
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/). | ||
Lightweight. Easy to use. In TypeScript. | ||
@@ -18,3 +25,3 @@ ## Usage | ||
addEventListener("fetch", (event) => { | ||
addEventListener("fetch", event => { | ||
const sentry = new Toucan({ | ||
@@ -21,0 +28,0 @@ dsn: "dsn...", |
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
7
0
81
36285
16
759