diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..3dcbfc4 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,11 @@ +{ + "trailingComma": "none", + "tabWidth": 2, + "printWidth": 98, + "semi": true, + "quoteProps": "as-needed", + "bracketSpacing": true, + "arrowParens": "always", + "endOfLine": "lf", + "singleQuote": false +} \ No newline at end of file diff --git a/lerna.json b/lerna.json index cbaae3e..0ecb1d0 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", + "version": "0.31.8", "npmClient": "yarn", - "version": "0.31.5", "useWorkspaces": true } \ No newline at end of file diff --git a/package.json b/package.json index caa04be..1431427 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,15 @@ "name": "traceo-sdk", "private": true, "scripts": { + "bootstrap": "lerna bootstrap", "build": "lerna run build", - "build:tarball": "lerna run build:tarball" + "build:tarball": "lerna run build:tarball", + "lint:prettier": "lerna run lint:prettier" }, "workspaces": [ - "packages/node" + "packages/node", + "packages/browser", + "packages/react" ], "devDependencies": { "@types/node": "10.17.0", @@ -20,14 +24,20 @@ "@types/jest": "^29.2.0", "eslint": "^8.8.0", "jest": "^26.5.5", - "npm-run-all": "^4.1.2", "os": "^0.1.2", - "prettier": "^2.5.1", "prettier-check": "^2.0.0", - "rimraf": "^3.0.2", "rollup": "^2.66.1", "ts-node": "^10.4.0", - "tslint": "^5.11.0" + "tslint": "^5.11.0", + "@types/react": "^16.9.49", + "@types/react-dom": "^16.9.8", + "lint-staged": "^10.5.3", + "npm-run-all": "^4.1.5", + "prettier": "2.1.2", + "react": "^18.1.0", + "react-dom": "^18.1.0", + "rimraf": "^3.0.2", + "webpack": "^5.11.0" }, "jest": { "verbose": false, diff --git a/.prettierc.json b/packages/browser/.eslintrc.js similarity index 100% rename from .prettierc.json rename to packages/browser/.eslintrc.js diff --git a/packages/browser/README.md b/packages/browser/README.md new file mode 100644 index 0000000..2f5f9f9 --- /dev/null +++ b/packages/browser/README.md @@ -0,0 +1 @@ +# Traceo SDK Browser \ No newline at end of file diff --git a/packages/browser/package.json b/packages/browser/package.json new file mode 100644 index 0000000..488788e --- /dev/null +++ b/packages/browser/package.json @@ -0,0 +1,35 @@ +{ + "name": "@traceo-sdk/browser", + "version": "0.31.8", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "license": "MIT", + "files": [ + "dist" + ], + "homepage": "https://github.com/traceo-dev/traceo-sdk", + "repository": { + "type": "git", + "url": "git://github.com/traceo-dev/traceo-sdk.git" + }, + "scripts": { + "build": "tsc -p ./tsconfig.json --outDir dist", + "build:tarball": "yarn build && npm pack", + "prebuild": "rimraf ./dist", + "lint": "run-s lint:prettier", + "lint:prettier": "prettier ./src/**/*.{js,ts,tsx} --write", + "prepack": "yarn lint", + "test": "jest", + "test:watch": "jest --watch --notify" + }, + "dependencies": { + "bowser": "2.11.0" + }, + "publishConfig": { + "access": "public" + }, + "browser": { + "http": false, + "https": false + } +} \ No newline at end of file diff --git a/packages/browser/src/client.ts b/packages/browser/src/client.ts new file mode 100644 index 0000000..24b92d6 --- /dev/null +++ b/packages/browser/src/client.ts @@ -0,0 +1,32 @@ +import { IBrowserClient, TraceoOptions } from "./types/client"; +import { Transport } from "./transport"; +import { utils } from "./utils"; + +export abstract class BrowserClient implements IBrowserClient { + public headers!: { [key: string]: any }; + public options: TraceoOptions; + public transport: Transport; + + constructor(options: TraceoOptions) { + this.options = options; + this.transport = new Transport(this.options); + + this.initSDK(); + } + + public abstract postInitSDK(): void; + + public sendError(error: Error): void { + const browser = utils.browserDetails(); + this.transport.send({ + type: error.name, + message: error.message, + stack: error.stack as string, + browser + }, this.headers); + } + + private initSDK(): void { + this.postInitSDK(); + } +} diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts new file mode 100644 index 0000000..cd4edc8 --- /dev/null +++ b/packages/browser/src/index.ts @@ -0,0 +1,7 @@ +export { BrowserClient } from "./client"; +export type { + Dictionary, + IBrowserClient, + TraceoOptions, + TraceoBrowserError as TraceoError +} from "./types/client"; diff --git a/packages/browser/src/transport/fetch.ts b/packages/browser/src/transport/fetch.ts new file mode 100644 index 0000000..c77db55 --- /dev/null +++ b/packages/browser/src/transport/fetch.ts @@ -0,0 +1,19 @@ +import { ITransport, RequestOptions } from "../types/transport"; + +export class FetchTransport implements ITransport { + private _options: RequestOptions; + + constructor(options: RequestOptions) { + this._options = options; + } + + public async request(): Promise { + const options: RequestInit = { + method: this._options.method, + headers: this._options.headers, + body: JSON.stringify(this._options.body) + }; + + await fetch(this._options.url, options); + } +} diff --git a/packages/browser/src/transport/index.ts b/packages/browser/src/transport/index.ts new file mode 100644 index 0000000..dad1098 --- /dev/null +++ b/packages/browser/src/transport/index.ts @@ -0,0 +1,53 @@ +import { Dictionary, TraceoOptions } from "../types/client"; +import { RequestOptions } from "../types/transport"; +import { FetchTransport } from "./fetch"; +import { XhrTransport } from "./xhr"; + +export class Transport { + private _options: TraceoOptions; + + constructor(options: TraceoOptions) { + this._options = options; + } + + public send(body: object, headers: Dictionary) { + try { + const options = this.requestOptions(body, headers); + this.transport(options).request(); + } catch (error) { + console.log("Error sending data to traceo: ", error); + } + } + + private transport(options: RequestOptions) { + if (window.XMLHttpRequest && !window.fetch) { + return new XhrTransport(options); + } + + return new FetchTransport(options); + } + + private requestOptions(body: {}, headers: Dictionary): RequestOptions { + const reqUrl = this.clientURL; + + // http://localhost:3000/api/worker/incident/app-id + const url = `${reqUrl.origin}/api/worker/incident/${this._options.appId}`; + + return { + protocol: reqUrl.protocol, + headers: { + "Content-Type": "application/json", + ...headers + }, + host: reqUrl.hostname, + method: "POST", + url, + port: reqUrl.port, + body + }; + } + + private get clientURL(): URL { + return new URL(this._options.url); + } +} diff --git a/packages/browser/src/transport/xhr.ts b/packages/browser/src/transport/xhr.ts new file mode 100644 index 0000000..3742396 --- /dev/null +++ b/packages/browser/src/transport/xhr.ts @@ -0,0 +1,36 @@ +import { ITransport, RequestOptions } from "../types/transport"; + +const XHR_DONE = 4; +export class XhrTransport implements ITransport { + public _options: RequestOptions; + + constructor(options: RequestOptions) { + this._options = options; + } + + public async request(): Promise { + new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.open(this._options.method, this._options.url, true); + + this.setRequestHeaders(xhr); + + xhr.onreadystatechange = () => { + if (xhr.readyState === XHR_DONE) { + resolve({ + status: xhr.status + }); + } + }; + + xhr.onerror = reject; + xhr.send(JSON.stringify(this._options.body)); + }); + } + + private setRequestHeaders(xhr: XMLHttpRequest): void { + Object.entries(this._options.headers).map(([value, key]) => { + xhr.setRequestHeader(key, value); + }); + } +} diff --git a/packages/browser/src/types/browser.ts b/packages/browser/src/types/browser.ts new file mode 100644 index 0000000..069df85 --- /dev/null +++ b/packages/browser/src/types/browser.ts @@ -0,0 +1,19 @@ +export type BrowserInfoType = { + browser: { + name?: string; + version?: string; + }; + os: { + name?: string; + version?: string; + versionName?: string; + }; + platform: { + type?: string; + }; + engine: { + name?: string; + version?: string; + }; + url: string; +}; \ No newline at end of file diff --git a/packages/browser/src/types/client.ts b/packages/browser/src/types/client.ts new file mode 100644 index 0000000..62d9538 --- /dev/null +++ b/packages/browser/src/types/client.ts @@ -0,0 +1,15 @@ +export interface TraceoOptions { + apiKey: string; + appId: string; + url: string; +} + +export interface TraceoBrowserError extends Error {} + +export interface IBrowserClient { + sendError(error: TraceoBrowserError): void; +} + +export type Dictionary = { + [key: string]: T; +}; diff --git a/packages/browser/src/types/transport.ts b/packages/browser/src/types/transport.ts new file mode 100644 index 0000000..df7201a --- /dev/null +++ b/packages/browser/src/types/transport.ts @@ -0,0 +1,23 @@ +import { BrowserInfoType } from "./browser"; +import { Dictionary } from "./client"; + +export interface ITransport { + request(): Promise; +} + +export type RequestOptions = { + body: object; + headers: Dictionary; + url: string; + protocol: string; //"http" | "https" + port: string | number; + host: string; + method: "POST" | "GET" | "PATCH" | "DELETE"; +}; + +export type BrowserIncidentType = { + type: string; + message: string; + stack: string; + browser: BrowserInfoType; +}; diff --git a/packages/browser/src/utils.ts b/packages/browser/src/utils.ts new file mode 100644 index 0000000..6fc7436 --- /dev/null +++ b/packages/browser/src/utils.ts @@ -0,0 +1,24 @@ +import Bowser from "bowser"; +import { BrowserInfoType } from "./types/browser"; + +const bowser = Bowser.getParser(window.navigator.userAgent); + +const browserDetails = (): BrowserInfoType => { + const browser = bowser.getBrowser(); + const engine = bowser.getEngine(); + const platform = bowser.getPlatform(); + const os = bowser.getOS(); + const url = window.location.href; + + return { + browser, + engine, + platform, + os, + url + }; +}; + +export const utils = { + browserDetails +}; diff --git a/packages/browser/tsconfig.json b/packages/browser/tsconfig.json new file mode 100644 index 0000000..01465df --- /dev/null +++ b/packages/browser/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "alwaysStrict": false, + "declaration": true, + "declarationMap": true, + "downlevelIteration": true, + "importHelpers": true, + "inlineSources": true, + "isolatedModules": true, + "lib": ["es6", "dom"], + "moduleResolution": "node", + "noErrorTruncation": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noImplicitUseStrict": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "preserveWatchOutput": true, + "sourceMap": true, + "strict": true, + "strictBindCallApply": false, + "target": "es6", + "esModuleInterop": true + }, + "exclude": ["node_modules", "dist"], + "include": ["src/**/*"] +} diff --git a/packages/node/package.json b/packages/node/package.json index 64cf936..52db4af 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -1,6 +1,6 @@ { "name": "@traceo-sdk/node", - "version": "0.31.7", + "version": "0.31.8", "author": "Traceo", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -18,7 +18,7 @@ "build:tarball": "yarn build && npm pack", "prebuild": "rimraf ./dist", "lint": "run-s lint:prettier", - "lint:prettier": "prettier */**/*.{js,ts} --write", + "lint:prettier": "prettier ./src/**/*.{js,ts,tsx} --write", "prepack": "yarn lint", "test": "jest", "test:watch": "jest --watch --notify" diff --git a/packages/node/src/client.ts b/packages/node/src/client.ts index 0404947..e771201 100644 --- a/packages/node/src/client.ts +++ b/packages/node/src/client.ts @@ -18,9 +18,9 @@ export class Client { this.options = options; this.headers = { - "x-sdk-name": "Node.js", + "x-sdk-name": "node", "x-sdk-version": TRACEO_SDK_VERSION, - "x-sdk-key": this.options.apiKey, + "x-sdk-key": this.options.apiKey }; this.logger = new Logger(); diff --git a/packages/node/src/core/http.ts b/packages/node/src/core/http.ts index 0195d66..2e7dacd 100644 --- a/packages/node/src/core/http.ts +++ b/packages/node/src/core/http.ts @@ -25,16 +25,10 @@ export class HttpModule { return HttpModule.instance; } - public request({ - url, - method = "POST", - body, - onError, - callback, - }: RequestOptionsType) { + public request({ url, method = "POST", body, onError, callback }: RequestOptionsType) { const requestOptions = { ...this.requestHeaders(method), - ...this.requestOptions(url, method), + ...this.requestOptions(url, method) }; const httpModule = this.requestModule(); @@ -47,11 +41,7 @@ export class HttpModule { request.end(); } - private requestWriteBody( - method: RequestType, - request: http.ClientRequest, - body: {} - ) { + private requestWriteBody(method: RequestType, request: http.ClientRequest, body: {}) { if (method === "POST") { request.write(JSON.stringify(body)); } @@ -65,10 +55,7 @@ export class HttpModule { return new URL(this.host); } - private requestOptions( - url: string, - method: RequestType - ): http.RequestOptions { + private requestOptions(url: string, method: RequestType): http.RequestOptions { const reqUrl = this.clientURL; const path = new URL(url, this.host); @@ -77,21 +64,21 @@ export class HttpModule { port: reqUrl.port, host: reqUrl.hostname, method, - path: `${path.pathname}/${Client.config.appId}`, + path: `${path.pathname}/${Client.config.appId}` }; } private requestHeaders(method: RequestType) { const headers = Client.client.headers; const baseHeaders = { - ...headers, + ...headers }; if (method !== "POST") return baseHeaders; return { headers: { "Content-Type": "application/json", - ...baseHeaders, - }, + ...baseHeaders + } }; } } diff --git a/packages/node/src/exceptions/handler.ts b/packages/node/src/exceptions/handler.ts index a245976..107153f 100644 --- a/packages/node/src/exceptions/handler.ts +++ b/packages/node/src/exceptions/handler.ts @@ -1,7 +1,7 @@ import { stacktrace } from "stacktrace-parser-node"; import { HttpModule } from "../core/http"; import { isClientConnected } from "../core/is"; -import { TraceoError, Incident } from "../types"; +import { TraceoError, NodeIncidentType } from "../types"; import { getOsDetails } from "../helpers"; /** @@ -27,7 +27,7 @@ export const catchException = async (error: any) => { }; const handleException = async (error: TraceoError) => { - const event: Incident = await prepareException(error); + const event: NodeIncidentType = await prepareException(error); const httpModule = HttpModule.getInstance(); httpModule.request({ url: "/api/worker/incident", @@ -37,21 +37,21 @@ const handleException = async (error: TraceoError) => { `Traceo Error. Something went wrong while sending new Incident to Traceo. Please report this issue.` ); console.error(`Caused by: ${error.message}`); - }, + } }); }; -const prepareException = async (error: TraceoError): Promise => { +const prepareException = async (error: TraceoError): Promise => { const { stack } = error; const platform = getOsDetails(); const { message, name, traces } = await stacktrace.parse(error); - const event: Incident = { + const event: NodeIncidentType = { type: name, message, traces, stack, - platform, + platform }; return event; diff --git a/packages/node/src/exceptions/middleware.ts b/packages/node/src/exceptions/middleware.ts index f7bda46..d61c095 100644 --- a/packages/node/src/exceptions/middleware.ts +++ b/packages/node/src/exceptions/middleware.ts @@ -2,7 +2,7 @@ import { TraceoError, TraceoIncomingMessage, TraceoServerResponse, - ErrorMiddlewareOptions, + ErrorMiddlewareOptions } from "../types"; import { isClientConnected, isLocalhost } from "../core/is"; import { getProtocol, getIp } from "../helpers"; @@ -50,10 +50,7 @@ export const errorMiddleware = (options: ErrorMiddlewareOptions = {}) => { }; }; -const isToCatch = ( - req: TraceoIncomingMessage, - options: ErrorMiddlewareOptions = {} -): boolean => { +const isToCatch = (req: TraceoIncomingMessage, options: ErrorMiddlewareOptions = {}): boolean => { if (options.allowHttp !== undefined && !options.allowHttp) { const isSecure = getProtocol(req) === "https" ? true : false; if (!isSecure) { diff --git a/packages/node/src/helpers.ts b/packages/node/src/helpers.ts index 50645d2..21c5f67 100644 --- a/packages/node/src/helpers.ts +++ b/packages/node/src/helpers.ts @@ -1,9 +1,7 @@ import { Platform, TraceoIncomingMessage } from "./types"; import * as os from "os"; -export const getIp = ( - req: TraceoIncomingMessage -): string | string[] | undefined => { +export const getIp = (req: TraceoIncomingMessage): string | string[] | undefined => { return req.headers["x-forwarded-for"] || req.socket.remoteAddress; }; @@ -15,13 +13,12 @@ export const getOsDetails = (): Platform => { return { arch: os.arch(), platform: os.platform(), - release: os.release(), + release: os.release() // version: os.version(), }; }; -export const toDecimalNumber = (val: number, decimal: number = 2) => - Number(val.toFixed(decimal)); +export const toDecimalNumber = (val: number, decimal: number = 2) => Number(val.toFixed(decimal)); // export const sanitizeDsn = (dsn: string) => { // const [secretKey, rest] = dsn diff --git a/packages/node/src/logger.ts b/packages/node/src/logger.ts index 6df14db..6029191 100644 --- a/packages/node/src/logger.ts +++ b/packages/node/src/logger.ts @@ -44,10 +44,7 @@ export class Logger { return this.printMessage(this.getEntryFromArgs(args), LogLevel.Debug); } - private printMessage( - { message }: { message: string }, - level: LogLevel - ): void { + private printMessage({ message }: { message: string }, level: LogLevel): void { const timestamp = this.timestamp; const messagePayload = `[TraceoLogger][${level.toUpperCase()}] - ${timestamp} - ${message}`; @@ -62,7 +59,7 @@ export class Logger { message, timestamp, unix: Math.floor(Date.now() / 1000), - resources: this.resources, + resources: this.resources }; this.logsQueue.push(requestPayload); @@ -81,7 +78,7 @@ export class Logger { }, callback: () => { this.logsQueue = []; - }, + } }); } } @@ -93,7 +90,7 @@ export class Logger { minute: "numeric", second: "numeric", day: "2-digit", - month: "2-digit", + month: "2-digit" }; return new Date(Date.now()).toLocaleString( undefined, @@ -108,7 +105,7 @@ export class Logger { packageVersion: process.env["npm_package_version"], traceoVersion: process.env["npm_package_dependencies_@traceo-sdk/node"] ?? - process.env["npm_package_devDependencies_@traceo-sdk/node"], + process.env["npm_package_devDependencies_@traceo-sdk/node"] }; } @@ -116,7 +113,7 @@ export class Logger { return Object.assign( {}, { - message: format.apply(null, args), + message: format.apply(null, args) } ); } diff --git a/packages/node/src/metrics/default/cpu-usage.ts b/packages/node/src/metrics/default/cpu-usage.ts index 54e6f33..7a87571 100644 --- a/packages/node/src/metrics/default/cpu-usage.ts +++ b/packages/node/src/metrics/default/cpu-usage.ts @@ -15,8 +15,7 @@ export class CpuUsageMetrics implements IMetrics { const idleDifference = endMeasure.idle - this.measureStart.idle; const totalDifference = endMeasure.total - this.measureStart.total; - const cpuUsage = - Math.round((100 - (100 * idleDifference) / totalDifference) * 100) / 100; + const cpuUsage = Math.round((100 - (100 * idleDifference) / totalDifference) * 100) / 100; return cpuUsage; } diff --git a/packages/node/src/metrics/default/event-loop.ts b/packages/node/src/metrics/default/event-loop.ts index 830f359..0532c0f 100644 --- a/packages/node/src/metrics/default/event-loop.ts +++ b/packages/node/src/metrics/default/event-loop.ts @@ -17,7 +17,7 @@ export class EventLoopMetrics implements IMetrics { constructor() { if (perf_hooks && perf_hooks.monitorEventLoopDelay) { this.histogram = perf_hooks.monitorEventLoopDelay({ - resolution: 10, + resolution: 10 }); this.histogram.enable(); } @@ -28,7 +28,7 @@ export class EventLoopMetrics implements IMetrics { loop_min: toDecimalNumber(this.histogram.min / 1e6), loop_max: toDecimalNumber(this.histogram.max / 1e6), loop_mean: toDecimalNumber(this.histogram.mean / 1e6), - loop_stddev: toDecimalNumber(this.histogram.stddev / 1e6), + loop_stddev: toDecimalNumber(this.histogram.stddev / 1e6) }; this.histogram.reset(); diff --git a/packages/node/src/metrics/default/gc-observer.ts b/packages/node/src/metrics/default/gc-observer.ts index f629928..a9bc80f 100644 --- a/packages/node/src/metrics/default/gc-observer.ts +++ b/packages/node/src/metrics/default/gc-observer.ts @@ -33,8 +33,8 @@ export class GCObserver implements IMetrics { return { duration: { total: toDecimalNumber(total), - average: toDecimalNumber(average), - }, + average: toDecimalNumber(average) + } }; } } diff --git a/packages/node/src/metrics/default/heap.ts b/packages/node/src/metrics/default/heap.ts index bb2d130..09f07b7 100644 --- a/packages/node/src/metrics/default/heap.ts +++ b/packages/node/src/metrics/default/heap.ts @@ -15,7 +15,7 @@ export class HeapMetrics implements IMetrics { return { heap_used: this.usedHeap, heap_total: this.totalHeap, - heap_rss: this.rss, + heap_rss: this.rss // heap_detached_contexts: this.detachedContextsNumber, // heap_native_contexts: this.nativeContextsNumber, }; diff --git a/packages/node/src/metrics/default/memory-usage.ts b/packages/node/src/metrics/default/memory-usage.ts index ead606e..91794aa 100644 --- a/packages/node/src/metrics/default/memory-usage.ts +++ b/packages/node/src/metrics/default/memory-usage.ts @@ -9,7 +9,7 @@ export class MemoryUsageMetrics implements IMetrics { public collect(): MemoryUsageMetricType { return { memory_usage_mb: this.usedMemory, - memory_usage_percentage: this.percentageUsage, + memory_usage_percentage: this.percentageUsage }; } diff --git a/packages/node/src/metrics/runner.ts b/packages/node/src/metrics/runner.ts index 8a1882b..9797bdd 100644 --- a/packages/node/src/metrics/runner.ts +++ b/packages/node/src/metrics/runner.ts @@ -38,8 +38,7 @@ export class MetricsRunner { return; } - this.interval = - this.client.options.scrapMetricsInterval || DEFAULT_INTERVAL; + this.interval = this.client.options.scrapMetricsInterval || DEFAULT_INTERVAL; this.http = HttpModule.getInstance(); @@ -76,7 +75,7 @@ export class MetricsRunner { load_avg: this.loadAvg, ...memory, ...heap, - ...eventLoop, + ...eventLoop }; return metrics; @@ -90,7 +89,7 @@ export class MetricsRunner { counter: this.clientCounterMetrics, meauserement: this.clientMeauserementMetrics, gauge: this.clientGaugeMetrics, - timeSeries: this.clientTimeSeriesMetrics, + timeSeries: this.clientTimeSeriesMetrics }; this.http.request({ @@ -104,7 +103,7 @@ export class MetricsRunner { }, callback: () => { this.clearClientMetrics(); - }, + } }); } diff --git a/packages/node/src/scrapper.ts b/packages/node/src/scrapper.ts index 92bab6a..e5f3559 100644 --- a/packages/node/src/scrapper.ts +++ b/packages/node/src/scrapper.ts @@ -18,14 +18,14 @@ export class Scrapper { const data = { node: { ...this.heap, - ...this.nodeVersion, + ...this.nodeVersion }, os: this.osData, ...this.packageJsonDependencies, npm: rest, traceo: { - version: traceoVersion, - }, + version: traceoVersion + } }; this.http.request({ @@ -36,7 +36,7 @@ export class Scrapper { `Traceo Error. Something went wrong while sending new runtime data to Traceo. Please report this issue.` ); console.error(`Caused by: ${error.message}`); - }, + } }); } @@ -51,7 +51,7 @@ export class Scrapper { npm_package_name: packageName, npm_package_description: packageDescription, npm_package_version: packageVersion, - npm_package_dependencies_traceo: traceoVersion, + npm_package_dependencies_traceo: traceoVersion } = process.env; return { @@ -59,7 +59,7 @@ export class Scrapper { packageDescription, packageName, packageVersion, - traceoVersion, + traceoVersion }; } @@ -77,7 +77,7 @@ export class Scrapper { "homedir", "tmpdir", "type", - "hostname", + "hostname" ]; for (const [key, _] of Object.entries(os)) { if (osDataToScrap.includes(key)) { diff --git a/packages/node/src/types/events.ts b/packages/node/src/types/events.ts index 486ac93..7d29062 100644 --- a/packages/node/src/types/events.ts +++ b/packages/node/src/types/events.ts @@ -7,18 +7,16 @@ export interface EventResponse { body?: string; } -export interface Incident { +export type NodeIncidentType = { type: string; message: string; stack: string; traces: Trace[]; - env?: Environment; platform: Platform; -} +}; export interface Platform { arch: string; platform: string; release: string; - // version: string; } diff --git a/packages/node/src/types/http.ts b/packages/node/src/types/http.ts index 4f6c63d..ba36a64 100644 --- a/packages/node/src/types/http.ts +++ b/packages/node/src/types/http.ts @@ -19,12 +19,12 @@ export interface RequestOptions extends http.RequestOptions { export enum RequestStatus { SUCCESS = "success", - ERROR = "error", + ERROR = "error" } export enum HTTP_ENDPOINT { LOG = "/api/worker/log", INCIDENT = "/api/worker/incident", RUNTIME = "/api/worker/runtime", - METRICS = "/api/worker/metrics", + METRICS = "/api/worker/metrics" } diff --git a/packages/node/src/types/logger.ts b/packages/node/src/types/logger.ts index 4dc49af..effc217 100644 --- a/packages/node/src/types/logger.ts +++ b/packages/node/src/types/logger.ts @@ -3,7 +3,7 @@ export enum LogLevel { Log = "log", Info = "info", Warn = "warn", - Error = "error", + Error = "error" } export interface TraceoLog { diff --git a/packages/react/package.json b/packages/react/package.json new file mode 100644 index 0000000..6406303 --- /dev/null +++ b/packages/react/package.json @@ -0,0 +1,34 @@ +{ + "name": "@traceo-sdk/react", + "version": "0.31.8", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "license": "MIT", + "files": [ + "dist" + ], + "homepage": "https://github.com/traceo-dev/traceo-sdk", + "repository": { + "type": "git", + "url": "git://github.com/traceo-dev/traceo-sdk.git" + }, + "scripts": { + "build": "tsc -p ./tsconfig.json --outDir dist", + "build:tarball": "yarn build && npm pack", + "prebuild": "rimraf ./dist", + "lint": "run-s lint:prettier", + "lint:prettier": "prettier ./src/**/*.{js,ts,tsx} --write", + "prepack": "yarn lint", + "test": "jest", + "test:watch": "jest --watch --notify" + }, + "dependencies": { + "@traceo-sdk/browser": "0.31.8" + }, + "peerDependencies": { + "react": ">= 16.8.6 < 19" + }, + "publishConfig": { + "access": "public" + } +} \ No newline at end of file diff --git a/packages/react/src/ErrorBoundary.tsx b/packages/react/src/ErrorBoundary.tsx new file mode 100644 index 0000000..c5b738a --- /dev/null +++ b/packages/react/src/ErrorBoundary.tsx @@ -0,0 +1,52 @@ +import React from "react"; +import { IBrowserClient } from "@traceo-sdk/browser"; + +type FallbackProps = (props?: { error: Error; componentStack: string }) => React.ReactElement; + +type ErrorBoundaryProps = { + traceo: IBrowserClient; + children: React.ReactNode; + fallback?: FallbackProps; + onError?(error: Error, componentStack: string): void; +}; + +type ErrorBoundaryState = { + error?: Error; + stacktrace?: string; +}; + +export class ErrorBoundary extends React.Component { + public state: ErrorBoundaryState = { + error: undefined, + stacktrace: undefined + }; + + public componentDidCatch(error: Error, { componentStack }: React.ErrorInfo): void { + const { traceo, onError } = this.props; + + if (onError) { + onError(error, componentStack); + } + + traceo.sendError(error); + this.setState({ error, stacktrace: componentStack }); + } + + public render(): React.ReactNode { + const { children, fallback } = this.props; + const { error, stacktrace } = this.state; + + if (error) { + if (fallback) { + return fallback({ + error, + componentStack: stacktrace as string + }); + } + + return null; + } + + return children; + } +} diff --git a/packages/react/src/client.ts b/packages/react/src/client.ts new file mode 100644 index 0000000..4750601 --- /dev/null +++ b/packages/react/src/client.ts @@ -0,0 +1,16 @@ +import { BrowserClient, TraceoOptions } from "@traceo-sdk/browser"; + +export class Client extends BrowserClient { + constructor(options: TraceoOptions) { + super(options); + + this.options = options; + this.headers = { + "x-sdk-name": "react", + "x-sdk-version": "0.31.8", + "x-sdk-key": this.options.apiKey + }; + } + + public postInitSDK(): void {} +} diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts new file mode 100644 index 0000000..625bf62 --- /dev/null +++ b/packages/react/src/index.ts @@ -0,0 +1,2 @@ +export { ErrorBoundary } from "./ErrorBoundary"; +export { Client as TraceoClient } from "./client"; diff --git a/packages/react/tsconfig.json b/packages/react/tsconfig.json new file mode 100644 index 0000000..4c81eff --- /dev/null +++ b/packages/react/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "esModuleInterop": true, + "jsx": "react", + "alwaysStrict": false, + "declaration": true, + "declarationMap": true, + "downlevelIteration": true, + "importHelpers": true, + "inlineSources": true, + "isolatedModules": true, + "lib": ["es6", "dom"], + "moduleResolution": "node", + "noErrorTruncation": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noImplicitUseStrict": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "preserveWatchOutput": true, + "sourceMap": true, + "strict": true, + "strictBindCallApply": false, + "target": "es6" + }, + "exclude": ["node_modules", "dist"], + "include": ["src/**/*"] +}