Skip to content

Commit

Permalink
Merge pull request #2 from spatie/js-client-maintenance
Browse files Browse the repository at this point in the history
JavaScript client maintenance
  • Loading branch information
sebastiandedeyne authored Sep 20, 2024
2 parents 491262f + 6899cbc commit 0bda351
Show file tree
Hide file tree
Showing 47 changed files with 963 additions and 719 deletions.
38 changes: 36 additions & 2 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,38 @@
{
"printWidth": 120,
"tabWidth": 4,
"useTabs": false,
"semi": true,
"singleQuote": true,
"tabWidth": 4
}
"jsxSingleQuote": false,
"quoteProps": "consistent",
"trailingComma": "es5",
"bracketSpacing": true,
"bracketSameLine": false,
"arrowParens": "always",
"htmlWhitespaceSensitivity": "css",
"endOfLine": "lf",
"singleAttributePerLine": false,
"overrides": [
{
"files": [
"*.ts",
"*.tsx",
"*.js",
"*.jsx"
],
"options": {
"plugins": [
"@trivago/prettier-plugin-sort-imports"
],
"importOrder": [
"^w",
"^../",
"^./"
],
"importOrderSeparation": true,
"importOrderSortSpecifiers": true
}
}
]
}
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@
"devDependencies": {
"husky": "^8.0.3",
"lint-staged": "^15.2.0",
"prettier": "^3.1.1"
"prettier": "^3.3.3"
},
"lint-staged": {
"*.{js,json,vue,ts,tsx}": "prettier --write"
},
"dependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.3.0"
}
}
202 changes: 202 additions & 0 deletions packages/js/src/Flare.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
import { Api } from './api';
import { collectContext } from './context';
import { CLIENT_VERSION, KEY, SOURCEMAP_VERSION } from './env';
import { getSolutions } from './solutions';
import { createStackTrace } from './stacktrace';
import {
Config,
Context,
Glow,
MessageLevel,
Report,
SolutionProvider,
SolutionProviderExtraParameters,
} from './types';
import { assert, assertKey, assertSolutionProvider, now } from './util';

export class Flare {
config: Config = {
key: KEY,
version: CLIENT_VERSION,
sourcemapVersion: SOURCEMAP_VERSION,
stage: '',
maxGlowsPerReport: 30,
reportingUrl: 'https://reporting.flareapp.io/api/reports',
debug: false,
beforeEvaluate: (error) => error,
beforeSubmit: (report) => report,
};

glows: Glow[] = [];
context: Context = { context: {} };
solutionProviders: SolutionProvider[] = [];

constructor(public http: Api = new Api()) {}

light(key: string = KEY, debug: boolean = false): Flare {
this.config.key = key;
this.config.debug = debug;

return this;
}

configure(config: Partial<Config>): Flare {
this.config = { ...this.config, ...config };

return this;
}

test(): Promise<void> {
return this.report(new Error('The Flare client is set up correctly!'));
}

glow(name: string, level: MessageLevel = 'info', data: object | object[] = []): Flare {
const time = now();

this.glows.push({
name,
message_level: level,
meta_data: data,
time,
microtime: time,
});

if (this.glows.length > this.config.maxGlowsPerReport) {
this.glows = this.glows.slice(this.glows.length - this.config.maxGlowsPerReport);
}

return this;
}

clearGlows(): Flare {
this.glows = [];

return this;
}

addContext(name: string, value: any): Flare {
this.context.context[name] = value;

return this;
}

addContextGroup(groupName: string, value: object): Flare {
this.context[groupName] = value;

return this;
}

registerSolutionProvider(solutionProvider: SolutionProvider): Flare {
if (!assertSolutionProvider(solutionProvider, this.config.debug)) {
return this;
}

this.solutionProviders.push(solutionProvider);

return this;
}

async report(
error: Error,
context: Context = {},
extraSolutionParameters: SolutionProviderExtraParameters = {}
): Promise<void> {
const errorToReport = await this.config.beforeEvaluate(error);

if (!errorToReport) {
return;
}

const report = await this.createReportFromError(error, context, extraSolutionParameters);

if (!report) {
return;
}

return this.sendReport(report);
}

async reportMessage(message: string, context: Context = {}, exceptionClass: string = 'Log'): Promise<void> {
const stackTrace = await createStackTrace(Error(), this.config.debug);

// The first item in the stacktrace is from this file, and irrelevant
stackTrace.shift();

this.sendReport({
notifier: `Flare JavaScript client v${CLIENT_VERSION}`,
exception_class: exceptionClass,
seen_at: now(),
message: message,
language: 'javascript',
glows: this.glows,
context: collectContext({ ...context, ...this.context }),
stacktrace: stackTrace,
sourcemap_version_id: this.config.sourcemapVersion,
solutions: [],
stage: this.config.stage,
});
}

createReportFromError(
error: Error,
context: Context = {},
extraSolutionParameters: SolutionProviderExtraParameters = {}
): Promise<Report | false> {
if (!assert(error, 'No error provided.', this.config.debug)) {
return Promise.resolve(false);
}

const seenAt = now();

return Promise.all([
getSolutions(this.solutionProviders, error, extraSolutionParameters),
createStackTrace(error, this.config.debug),
]).then((result) => {
const [solutions, stacktrace] = result;

assert(stacktrace.length, "Couldn't generate stacktrace of this error: " + error, this.config.debug);

return {
notifier: `Flare JavaScript client v${CLIENT_VERSION}`,
exception_class: error.constructor && error.constructor.name ? error.constructor.name : 'undefined',
seen_at: seenAt,
message: error.message,
language: 'javascript',
glows: this.glows,
context: collectContext({ ...context, ...this.context }),
stacktrace,
sourcemap_version_id: this.config.sourcemapVersion,
solutions,
stage: this.config.stage,
};
});
}

async sendReport(report: Report): Promise<void> {
if (!assertKey(this.config.key, this.config.debug)) {
return;
}

const reportToSubmit = await this.config.beforeSubmit(report);

if (!reportToSubmit) {
return;
}

return this.http.report(reportToSubmit, this.config.reportingUrl, this.config.key);
}

// Deprecated, the following methods exist for backwards compatibility.

set beforeEvaluate(beforeEvaluate: Config['beforeEvaluate']) {
this.config.beforeEvaluate = beforeEvaluate ?? '';
}

set beforeSubmit(beforeSubmit: Config['beforeSubmit']) {
this.config.beforeSubmit = beforeSubmit ?? '';
}

set stage(stage: string | undefined) {
this.config.stage = stage ?? '';
}
}
Loading

0 comments on commit 0bda351

Please sign in to comment.