Skip to content

Commit 5d2685f

Browse files
authored
feat: Scoped packages Typescript Core/Browser implementation (#1149)
* feat: Initial commit * feat: Add tests with jest * feat: Add basic tests * feat: Strip tests * feat: Add tests for captureEvent/message * feat: Steamline options * feat: Added sdk options * feat: Write readme * feat: Move to new folder structure * fix: package.json * feat: Add js tests * feat: Add webpack in platform-browser to get bundle * fix: rename platform folder * fix: Remove Set * meta: Add todos * feat: Add headless chrome tests * ref: Rename Sdk to Integration * ref: Integration renaming * ref: Rename to adapter * fix: Implement real captureException and captureMessage * meta: Change naming * ref: Rename main files * feat: Add sharedClient sentry * feat: Add dsn parsing with tests * feat: Add tests for wrong dsn * fix: Naming of SentryError * feat: Add setOptions function to adapters * feat: Add global create function * feat: Remove multiple adapter architecture * feat: Add context handling * feat: Add breadcrumbs api * feat: Tunnel context to adapter * feat: Add breadcrumbCallback * feat: Add more test, Coverage, Add Sentry Log * ref: Add tslint and prettier support * fix: Browser tests * feat: Change browser adapter to reflect tslint * ci: Fix travis config * ci: Update yarn * ci: Build core before browser * ci: Fix path * ci: Use yarn link * ci: Use yarn link * fix: Different code review changes * ref: Code review changes * ref: make install return a promise * fix: Browser tests * fix: Remove node ts reference * meta: Add documentation * feat: Add npmignore * feat: package.json version changes * fix(ci): travis tests * ci: Fix travis build * ci: Fix travis and skip install * ci: Increase timeout to 60sec * ci: Remove increased timeout * feat: Use rollup instead of webpack * feat: Rename Browser to SentryBrowser * feat: Add size:check npm script Update .eslintignore * fix: package.json main * feat: Export ISentryBrowserOptions
1 parent af6228d commit 5d2685f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+17429
-7
lines changed

.eslintignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ example/
44
vendor/
55
test/
66
scripts/
7-
7+
packages/core/
8+
packages/browser/

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
* @kamilogorek
2+
packages/* @hazat

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,5 @@ scratch/
2020

2121
.idea
2222
*.sublime-*
23+
24+
yarn-error.log

.npmignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
build/
2+
docs/
3+
example/
4+
node_modules/
5+
packages/
6+
scripts/
7+
template/
8+
test/
9+
10+
.*
11+
karma.*
12+
Makefile
13+
npm-debug.log

.travis.yml

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
branches:
22
only:
33
- master
4+
45
sudo: false
56
language: node_js
67
node_js:
@@ -9,9 +10,30 @@ dist: trusty
910
cache:
1011
directories:
1112
- node_modules
12-
addons:
13-
chrome: stable
14-
firefox: latest
15-
sauce_connect: true
16-
script:
17-
- npm run test && if [ "$TRAVIS_SECURE_ENV_VARS" == "true" ]; then npm run test:ci; else exit 0; fi
13+
before_install:
14+
- curl -o- -L https://yarnpkg.com/install.sh | bash
15+
- export PATH="$HOME/.yarn/bin:$PATH"
16+
17+
matrix:
18+
include:
19+
- env: NAME="raven-js"
20+
addons:
21+
chrome: stable
22+
firefox: latest
23+
sauce_connect: true
24+
script:
25+
- npm run test && if [ "$TRAVIS_SECURE_ENV_VARS" == "true" ]; then npm run test:ci; else exit 0; fi
26+
- env: NAME="@sentry/browser"
27+
install: true
28+
script:
29+
- yarn link
30+
- cd packages/core && yarn link && yarn install && yarn dist
31+
- cd ../browser
32+
- yarn remove @sentry/core # this has to be removed once we released the package
33+
- yarn link "@sentry/core"
34+
- yarn link "raven-js"
35+
- yarn install && yarn test
36+
- env: NAME="@sentry/core"
37+
install: true
38+
script:
39+
- cd packages/core && yarn install && yarn test

.vscode/extensions.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
// See http://go.microsoft.com/fwlink/?LinkId=827846
3+
// for the documentation about the extensions.json format
4+
"recommendations": [
5+
"esbenp.prettier-vscode"
6+
]
7+
}

.vscode/settings.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"editor.tabSize": 2,
3+
"editor.rulers": [90],
4+
"[typescript]": {
5+
"editor.formatOnSave": true
6+
},
7+
"[javascript]": {
8+
"editor.formatOnSave": true
9+
},
10+
"prettier.typescriptEnable": [
11+
"typescript",
12+
"typescriptreact"
13+
],
14+
"search.exclude": {
15+
"**/node_modules": true,
16+
"**/bower_components": true,
17+
"**/dist/**": true
18+
},
19+
"tslint.autoFixOnSave": true,
20+
}

packages/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
dist/
2+
coverage/

packages/browser/.prettierrc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"trailingComma": "es5",
3+
"singleQuote": true,
4+
"printWidth": 90
5+
}

packages/browser/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Changelog
2+
3+
## v0.1.0
4+
5+
- Initial release

packages/browser/README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<p align="center">
2+
<a href="https://sentry.io" target="_blank" align="center">
3+
<img src="https://sentry-brand.storage.googleapis.com/sentry-logo-black.png" width="280">
4+
</a>
5+
<br/>
6+
<h1>Sentry Browser SDK Package</h1>
7+
</p>
8+
9+
[![npm version](https://img.shields.io/npm/v/@sentry/browser.svg)](https://www.npmjs.com/package/@sentry/browser)
10+
[![npm dm](https://img.shields.io/npm/dm/@sentry/browser.svg)](https://www.npmjs.com/package/@sentry/browser)
11+
[![npm dt](https://img.shields.io/npm/dt/@sentry/browser.svg)](https://www.npmjs.com/package/@sentry/browser)
12+
13+
## General
14+
15+
This package is meant to be used with the Core SDK package.
16+
17+
## Usage
18+
19+
First you have to create the core and `use` a corresponding SDK.
20+
```javascript
21+
import * as Sentry from '@sentry/core';
22+
import { Browser } from '@sentry/browser';
23+
24+
Sentry.create('__DSN__')
25+
.use(Browser)
26+
.install();
27+
```
28+
29+
After that you can call function on the global `sharedClient`:
30+
```javascript
31+
Sentry.getSharedClient().setTagsContext({ cordova: true });
32+
Sentry.getSharedClient().captureMessage('test message');
33+
Sentry.getSharedClient().captureBreadcrumb({ message: 'HOHOHOHO' });
34+
Sentry.getSharedClient().captureException(new Error('error'));
35+
```
36+
37+
If you don't want to use a global static instance of Sentry, you can create one on your own:
38+
39+
```javascript
40+
const client = await new Sentry.Client(dsn).use(MockAdapter).install()
41+
client.setTagsContext({ cordova: true });
42+
client.captureMessage('test message');
43+
client.captureBreadcrumb({ message: 'HOHOHOHO' });
44+
45+
// OR
46+
47+
new Sentry.Client('__DSN__')
48+
.use(MockAdapter)
49+
.install()
50+
.then(client => {
51+
client.setTagsContext({ cordova: true });
52+
client.captureMessage('test message');
53+
client.captureBreadcrumb({ message: 'HOHOHOHO' });
54+
});
55+
```
56+
57+
Notice, `install()` is a `Promise` but we internally wait until it is resolved,
58+
so it is save to call other function without waiting for it.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import * as Sentry from '@sentry/core';
2+
import { SentryBrowser } from '../lib/SentryBrowser';
3+
4+
// install() returns a promise after init
5+
Sentry.create('https://[email protected]/4291')
6+
.use(SentryBrowser)
7+
.install()
8+
.then(client => {
9+
client.setTagsContext({ cordova: true });
10+
client.captureBreadcrumb({ message: 'HOHOHOHO' });
11+
});
12+
13+
// This should also work because we internally await for adapter install
14+
Sentry.getSharedClient().captureMessage('PICKLE RIIIICK!');
15+
Sentry.getSharedClient().captureException(new Error('YOYOYOY'));
16+
17+
// throw new Error('YP Test');

packages/browser/__tests__/index.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title></title>
7+
</head>
8+
<body>
9+
<script src="../dist/bundle.js"></script>
10+
</body>
11+
</html>

packages/browser/__tests__/index.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/// <reference types="node" />
2+
/// <reference types="jest" />
3+
import * as Sentry from '@sentry/core';
4+
import * as fs from 'fs';
5+
import * as http from 'http';
6+
import * as path from 'path';
7+
import * as Puppeteer from 'puppeteer';
8+
import { SentryBrowser } from '../index';
9+
10+
describe('Browser Interface', () => {
11+
test('sending a message', async done => {
12+
let countExpects = 0;
13+
const expectedAssertions = 2;
14+
expect.assertions(expectedAssertions);
15+
16+
const server = http
17+
.createServer((request, response) => {
18+
if (request.url === '/index.html') {
19+
response.writeHead(200, { 'Content-Type': 'text/html' });
20+
const contents = fs.readFileSync(path.join(__dirname, './index.html'));
21+
response.write(contents);
22+
}
23+
if (request.url === '/dist/bundle.js') {
24+
response.writeHead(200, { 'Content-Type': 'text/javscript' });
25+
const contents = fs.readFileSync(path.join(__dirname, '../dist/bundle.js'));
26+
response.write(contents);
27+
}
28+
response.end();
29+
})
30+
.listen(8999);
31+
32+
const browser = await Puppeteer.launch({ headless: true });
33+
const page = await browser.newPage();
34+
35+
page.on('request', async request => {
36+
// @ts-ignore
37+
if (request.resourceType === 'xhr') {
38+
const data = JSON.parse(request.postData as any);
39+
if (data.exception) {
40+
expect(data.exception).not.toBeUndefined();
41+
} else {
42+
expect(data.message).toBe('PICKLE RIIIICK!');
43+
}
44+
countExpects++;
45+
}
46+
if (countExpects === expectedAssertions) {
47+
await browser.close();
48+
done();
49+
}
50+
});
51+
await page.goto('http://localhost:8999/index.html');
52+
server.close();
53+
});
54+
});

packages/browser/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { SentryBrowser, ISentryBrowserOptions } from './lib/SentryBrowser';

packages/browser/lib/SentryBrowser.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import { Client, Event, IAdapter, IBreadcrumb, IUser } from '@sentry/core';
2+
declare function require(path: string): any;
3+
const Raven = require('raven-js');
4+
5+
export interface ISentryBrowserOptions {
6+
allowSecretKey?: boolean;
7+
allowDuplicates?: boolean;
8+
}
9+
10+
export class SentryBrowser implements IAdapter {
11+
private client: Client;
12+
13+
constructor(client: Client, public options: ISentryBrowserOptions = {}) {
14+
this.client = client;
15+
}
16+
17+
public install(): Promise<boolean> {
18+
Raven.config(this.client.dsn.getDsn(false), this.options).install();
19+
return Promise.resolve(true);
20+
}
21+
22+
public getRaven() {
23+
return Raven;
24+
}
25+
26+
public setOptions(options: ISentryBrowserOptions) {
27+
Object.assign(this.options, options);
28+
Object.assign(Raven._globalOptions, this.options);
29+
return this;
30+
}
31+
32+
public captureException(exception: Error) {
33+
return new Promise<Event>((resolve, reject) => {
34+
const ravenSendRequest = Raven._sendProcessedPayload;
35+
Raven._sendProcessedPayload = (data: any) => {
36+
Raven._sendProcessedPayload = ravenSendRequest;
37+
resolve(data);
38+
};
39+
Raven.captureException(exception);
40+
});
41+
}
42+
43+
public captureMessage(message: string) {
44+
return new Promise<Event>((resolve, reject) => {
45+
const ravenSendRequest = Raven._sendProcessedPayload;
46+
Raven._sendProcessedPayload = (data: any) => {
47+
Raven._sendProcessedPayload = ravenSendRequest;
48+
resolve(data);
49+
};
50+
Raven.captureMessage(message);
51+
});
52+
}
53+
54+
public setBreadcrumbCallback(callback: (crumb: IBreadcrumb) => void) {
55+
Raven.setBreadcrumbCallback(callback);
56+
}
57+
58+
public captureBreadcrumb(crumb: IBreadcrumb) {
59+
return new Promise<IBreadcrumb>((resolve, reject) => {
60+
Raven.captureBreadcrumb(crumb);
61+
resolve(crumb);
62+
});
63+
}
64+
65+
public send(event: any) {
66+
return new Promise<Event>((resolve, reject) => {
67+
Raven._sendProcessedPayload(event, (error: any) => {
68+
if (error) {
69+
reject(error);
70+
return;
71+
}
72+
resolve(event);
73+
});
74+
});
75+
}
76+
77+
public setUserContext(user?: IUser) {
78+
Raven.setUserContext(user);
79+
return this;
80+
}
81+
82+
public setTagsContext(tags?: { [key: string]: any }) {
83+
Raven.setTagsContext(tags);
84+
return this;
85+
}
86+
87+
public setExtraContext(extra?: { [key: string]: any }) {
88+
Raven.setExtraContext(extra);
89+
return this;
90+
}
91+
92+
public clearContext() {
93+
Raven.clearContext();
94+
return this;
95+
}
96+
}

0 commit comments

Comments
 (0)