ContactSnag
Bugsnag utilities for Contactlab's applications.
This package embeds 2 main functionalities:
-
Javascript wrapper for Bugsnag: importing
ContactSnag
in your code gives you access to a "lazy" and "side-effect aware" Bugsnag client that exposes the same APIs of the original SDK. -
Webpack plugin: ContactSnag exposes (as dependecy) the
webpack-bugsnag-plugins
in order to upload sourcemaps and report builds using Webpack (take a look here for available configuration).
It is fully written in TypeScript and extensively uses fp-ts
library.
Requirements
- TypeScript >= v4.1.0
-
fp-ts
>= v2.8.0 -
io-ts
>= v2.2.10
Installation
Get the latest version from NPM registry:
$ npm install contactsnag fp-ts io-ts --save
# -- or --
$ yarn add contactsnag fp-ts io-ts
ContactSnag Client
The package exposes a single ContactSnag
function.
This receives a configuration object and returns a ContactSnag client:
declare function ContactSnag(conf: Config): Client;
Config
is a kind of subset of Bugsnag's configuration options with some differences:
-
appVersion
,enabledReleaseStages
, andreleaseStage
are required properties; -
endpoints
andenabledBreadcrumbTypes
cannot be set/overwritten.
Client
is a custom data structure which embeds some Bugsnag.Client
features, guarantees a lazy initialization and that an error is raised if a wrong configuration is passed.
interface Client {
readonly client: () => ActualClient;
readonly start: () => void;
readonly notify: (
error: Bugsnag.NotifiableError,
onError?: Bugsnag.OnErrorCallback
) => IOEither<Error, void>;
readonly setUser: (user: Bugsnag.User) => IOEither<Error, void>;
}
The ActualClient
type encodes the three different states of the ContactSnag client:
type ActualClient = ConfigError | Still | Started;
ConfigError
represents a not valid configuration provided to the client's creation function:
interface ConfigError {
readonly type: 'ConfigError';
readonly error: Error;
}
Still
represents a not started client:
interface Still {
readonly type: 'Still';
readonly config: Config;
}
Started
represents a started client:
interface Started {
readonly type: 'Started';
readonly bugsnag: Bugsnag.Client;
}
Each time a Client
's method is called, it will internally check (a.k.a. fold) the current state and execute an operation.
client()
Returns the current ActualClient
.
start()
Starts the client if it's in the Still
state, otherwise it does nothing.
notify()
Returns a void
effectful operation that can fail (IOEither
).
When the IO
is ran:
- if the client is in the
Started
state, it will notify an error to Bugsnag or will fail if the Bugsnag client raises an exception; - if the client is in the
ConfigError
state, it will return aLeft<Error>
("configuration error"); - if the client is in the
Still
state, it will return aLeft<Error>
("not yet started error").
Usage example
Notify Bugsnag with a custom error message:
import {ContactSnag} from 'contactsnag';
const client = ContactSnag({
apiKey: 'TEST-API-KEY',
appVersion: '1.2.3',
enabledReleaseStages: ['production'],
releaseStage: 'production'
});
// Set notification on button click
document.getElementById('btn').addEventListener('click', () =>
client.notify(new Error('Custom error message'), event => {
event.addMetadata('custom', 'errname', 'My error name');
})()
);
// Start Bugsnag
client.start();
setUser()
Returns a void
effectful operation that can fail (IOEither
).
When the IO
is ran:
- if the client is in the
Started
state, it will set the provided user on the Bugsnag client; - if the client is in the
ConfigError
state, it will return aLeft<Error>
("configuration error"); - if the client is in the
Still
state, it will return aLeft<Error>
("not yet started error").
Usage example
Set a user for the entire session:
import {ContactSnag} from 'contactsnag';
const client = ContactSnag({
apiKey: 'TEST-API-KEY',
appVersion: '1.2.3',
enabledReleaseStages: ['production'],
releaseStage: 'production'
});
// Start Bugsnag
client.start();
// Set user after 1 second
setTimeout(() => {
client.setUser({id: '1'})();
}, 1000);
Contributing
Opening issues is always welcome.
Then, fork the repository or create a new branch, write your code and send a pull request.
This project uses Prettier (automatically applied as pre-commit hook), ESLint (with TypeScript integration) and Jest.
Tests are run with:
$ npm test