bugsplat
Version:
error reporting for js
154 lines • 6.07 kB
JavaScript
import { validateResponseBody, } from './bugsplat-response';
export function createStandardizedCallStack(error) {
if (!error.stack?.includes('Error:')) {
return `Error: ${error.message}\n${error.stack}`;
}
return error.stack;
}
export async function tryParseResponseJson(response) {
let parsed;
try {
parsed = await response.json();
}
catch {
parsed = {};
}
return parsed;
}
const isError = (val) => Boolean(val?.stack);
function isFileRef(data) {
return typeof data === 'object' && data !== null && typeof data.uri === 'string';
}
export function appendAttachment(body, attachment) {
const { filename, data } = attachment;
if (data instanceof Uint8Array) {
body.append(filename, new Blob([data]), filename);
return;
}
if (isFileRef(data)) {
body.append(filename, { uri: data.uri, type: data.type, name: filename }, filename);
return;
}
body.append(filename, data, filename);
}
export class BugSplat {
database;
application;
version;
_formData = () => new FormData();
_fetch = globalThis.fetch.bind(globalThis);
_appKey = '';
_attributes = {};
_description = '';
_email = '';
_user = '';
constructor(database, application, version) {
this.database = database;
this.application = application;
this.version = version;
}
async post(errorToPost, options) {
options = options || {};
const appKey = options.appKey || this._appKey;
const user = options.user || this._user;
const email = options.email || this._email;
const description = options.description || this._description;
const attributes = options.attributes || this._attributes;
const callstack = createStandardizedCallStack(isError(errorToPost) ? errorToPost : new Error(errorToPost));
const url = this._getEnv('BUGSPLAT_CRASH_POST_URL') || `https://${this.database}.bugsplat.com/post/js/`;
const body = this._formData();
body.append('database', this.database);
body.append('appName', this.application);
body.append('appVersion', this.version);
body.append('appKey', appKey);
body.append('user', user);
body.append('email', email);
body.append('description', description);
body.append('callstack', callstack);
if (Object.keys(attributes).length > 0) {
body.append('attributes', JSON.stringify(attributes));
}
for (const attachment of options.attachments || []) {
appendAttachment(body, attachment);
}
console.log('BugSplat Error:', errorToPost);
console.log('BugSplat Url:', url);
const response = await this._fetch(url, { method: 'POST', body });
const json = await tryParseResponseJson(response);
console.log('BugSplat POST status code:', response.status);
console.log('BugSplat POST response body:', json);
if (response.status === 400) {
return this._createReturnValue(new Error('BugSplat Error: Bad request'), json, errorToPost);
}
if (response.status === 429) {
return this._createReturnValue(new Error('BugSplat Error: Rate limit of one crash per second exceeded'), json, errorToPost);
}
if (!response.ok) {
return this._createReturnValue(new Error('BugSplat Error: Unknown error'), json, errorToPost);
}
if (!validateResponseBody(json)) {
return this._createReturnValue(new Error('BugSplat Error: Invalid response received'), json, errorToPost);
}
return this._createReturnValue(null, json, errorToPost);
}
async postFeedback(title, options) {
options = options || {};
const appKey = options.appKey || this._appKey;
const user = options.user || this._user;
const email = options.email || this._email;
const description = options.description || this._description;
const attributes = options.attributes || this._attributes;
const baseUrl = this._getEnv('BUGSPLAT_FEEDBACK_POST_URL') || `https://${this.database}.bugsplat.com/post/feedback/`;
const body = this._formData();
body.append('database', this.database);
body.append('appName', this.application);
body.append('appVersion', this.version);
body.append('title', title);
body.append('appKey', appKey);
body.append('user', user);
body.append('email', email);
body.append('description', description);
if (Object.keys(attributes).length > 0) {
body.append('attributes', JSON.stringify(attributes));
}
for (const attachment of options.attachments || []) {
appendAttachment(body, attachment);
}
console.log('BugSplat Feedback:', title);
const response = await this._fetch(baseUrl, { method: 'POST', body });
const json = await tryParseResponseJson(response);
if (!response.ok) {
return this._createReturnValue(new Error('BugSplat Error: Failed to post feedback'), json, title);
}
if (!validateResponseBody(json)) {
return this._createReturnValue(new Error('BugSplat Error: Invalid response received'), json, title);
}
return this._createReturnValue(null, json, title);
}
setDefaultAppKey(appKey) {
this._appKey = appKey;
}
setDefaultAttributes(attributes) {
this._attributes = attributes;
}
setDefaultDescription(description) {
this._description = description;
}
setDefaultEmail(email) {
this._email = email;
}
setDefaultUser(user) {
this._user = user;
}
_getEnv(key) {
return typeof process !== 'undefined' ? process.env?.[key] : undefined;
}
_createReturnValue(error, response, original) {
return {
error,
response,
original,
};
}
}
//# sourceMappingURL=bugsplat.js.map