Skip to content

Commit

Permalink
Improve TypeScript usage (#612)
Browse files Browse the repository at this point in the history
* Use Rollup + tsc to generate type definitions

* Fix types

* Update type tests

* Exclude internal fields

* Combine typedefs into one

* Update docs

* Fix publish config

* Simplify exported type declarations

* Fix TS tests

* Update CHANGELOG.md

Co-authored-by: Josh Wood <josh@honeybadger.io>
  • Loading branch information
shalvah and joshuap committed Jul 19, 2021
1 parent 427900e commit 7d49aab
Show file tree
Hide file tree
Showing 20 changed files with 309 additions and 186 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased][latest]
### Fixed
- TypeScript: Add missing methods typedefs (#611)
- Internal: Fixed TypeScript types, added null checks, automated type declaration files

## [3.2.1] - 2021-05-17
### Fixed
Expand Down
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,20 @@ See https://github.com/honeybadger-io/honeybadger-js/blob/master/CHANGELOG.md
## Development

1. Run `npm install`.
2. To run the test suite by itself, use `npm test`.
3. To run the tests across all supported platforms, set up a [BrowserStack](https://www.browserstack.com/)
2. To run unit tests for both browser and server builds: `npm test`. Or separately: `npm run test:browser`, `npm run test:server`.
3. To run integration tests across all supported platforms, set up a [BrowserStack](https://www.browserstack.com/)
account and use `BROWSERSTACK_USERNAME=your_username BROWSERSTACK_ACCESS_KEY=your-access-key npm run test:integration`.
4. To test the TypeScript type definitions: `npm run tsd`.

### Bundling and types
This project is _isomorphic_, meaning it's a single library which contains both browser and server builds. It's written in TypeScript, and transpiled and bundled with Rollup. Our Rollup config generates three main files:
1. The server build, which transpiles `src/server.ts` and its dependencies into `dist/server/honeybadger.js`.
2. The browser build, which transpiles `src/browser.ts` and its dependencies into `dist/browser/honeybadger.js`.
3. The minified browser build, which transpiles `src/browser.ts` and its dependencies into `dist/browser/honeybadger.min.js` (+ source maps).

In addition, the TypeScript type declaration for each build is generated into its `types/` directory (ie `dist/browser/types/browser.d.ts` and `dist/server/types/server.d.ts`).

However, since the package is isomorphic, TypeScript users will likely be writing `import * as Honeybadger from '@honeybadger-io/js'` or `import Honeybadger = require('@honeybadger-io/js')` in their IDE. Our `package.json` has ` main` and `browser` fields that determine which build they get, but [there can only be a single type declaration file](https://github.com/Microsoft/TypeScript/issues/29128). So we use an extra file in the project root, `honeybadger.d.ts`, that combines the types from both builds.

## Releasing

Expand Down
110 changes: 4 additions & 106 deletions honeybadger.d.ts
Original file line number Diff line number Diff line change
@@ -1,109 +1,7 @@
// Type definitions for honeybadger.js
// Project: https://github.com/honeybadger-io/honeybadger-js
import { NextFunction, Request, Response } from 'express'
import Server from './dist/server/types/server'
import Browser from './dist/browser/types/browser'

declare class Honeybadger {
public getVersion(): string
public factory(opts?: Partial<Honeybadger.Config>): Honeybadger
public notify(notice: Error | string | Partial<Honeybadger.Notice>, name?: string | Partial<Honeybadger.Notice>, extra?: string | Partial<Honeybadger.Notice>): Honeybadger.Notice | false
public configure(opts: Partial<Honeybadger.Config>): Honeybadger
public beforeNotify(func: Honeybadger.BeforeNotifyHandler): Honeybadger
public afterNotify(func: Honeybadger.AfterNotifyHandler): Honeybadger
public setContext(context: Record<string, unknown>): Honeybadger
public resetContext(context?: Record<string, unknown>): Honeybadger
public clear(): Honeybadger
public addBreadcrumb(message: string, opts?: Partial<Honeybadger.BreadcrumbRecord>): Honeybadger

// Server middleware
public requestHandler(req: Request, res: Response, next: NextFunction): void
public errorHandler(err: any, req: Request, _res: Response, next: NextFunction): unknown
public lambdaHandler(handler: any): (event: any, context: any, callback: any) => void
}

declare namespace Honeybadger {
interface Logger {
log(...args: unknown[]): unknown
info(...args: unknown[]): unknown
debug(...args: unknown[]): unknown
warn(...args: unknown[]): unknown
error(...args: unknown[]): unknown
}

interface Config {
apiKey: string | undefined
endpoint: string,
developmentEnvironments: string[]
environment: string | undefined
hostname: string | undefined
projectRoot: string | undefined
component: string | undefined
action: string | undefined
revision: string | undefined
disabled: boolean
debug: boolean
reportData: boolean
breadcrumbsEnabled: boolean | Partial<{ dom: boolean, network: boolean, navigation: boolean, console: boolean }>
maxBreadcrumbs: number
maxObjectDepth: number
logger: Logger
enableUncaught: boolean
afterUncaught: (err: Error) => void
enableUnhandledRejection: boolean
tags: string | string[] | unknown
filters: string[]
[x: string]: unknown

// Browser
async: boolean
maxErrors: number
}

interface BeforeNotifyHandler {
(notice: Notice): boolean | void
}

interface AfterNotifyHandler {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(error: any, notice: Notice): boolean | void
}

interface Notice {
id: string | undefined,
name: string,
message: string,
stack: string,
backtrace: BacktraceFrame[],
fingerprint?: string | undefined,
url?: string | undefined,
component?: string | undefined,
action?: string | undefined,
context: Record<string, unknown>,
cgiData: Record<string, unknown>,
params: Record<string, unknown>,
session: Record<string, unknown>,
headers: Record<string, unknown>,
cookies: Record<string, unknown> | string,
projectRoot?: string | undefined,
environment?: string | undefined,
revision?: string | undefined,
afterNotify?: AfterNotifyHandler
tags: string | string[]
}

interface BacktraceFrame {
file: string,
method: string,
number: number,
column: number
}

interface BreadcrumbRecord {
category: string,
message: string,
metadata: Record<string, unknown>,
timestamp: string
}
}

declare const singleton: Honeybadger
export = singleton
declare const Honeybadger: typeof Server & typeof Browser
export = Honeybadger
131 changes: 127 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@
"test:integration:browserstack": "npm run test:integration",
"test:integration:headless": "HEADLESS=1 npm run test:integration",
"tsd": "npm run build && tsd",
"build": "rollup -c && cp honeybadger.d.ts dist/server && cp honeybadger.d.ts dist/browser",
"build": "rollup -c && node ./scripts/copy-typedefs.js",
"release": "shipjs prepare"
},
"dependencies": {
"@types/express": "^4.17.13",
"stacktrace-parser": "^0.1.10"
},
"devDependencies": {
Expand Down Expand Up @@ -74,5 +75,10 @@
"dist",
"honeybadger.d.ts"
],
"tsd": {
"compilerOptions": {
"strict": false
}
},
"types": "./honeybadger.d.ts"
}

0 comments on commit 7d49aab

Please sign in to comment.