bugsnag-types (empty) → 1.0.0.0
raw patch · 29 files changed
+2003/−0 lines, 29 filesdep +aesondep +basedep +bugsnag-types
Dependencies added: aeson, base, bugsnag-types, hspec, text
Files
- CHANGELOG.md +0/−0
- README.md +0/−0
- bugsnag-types.cabal +102/−0
- src/Data/Bugsnag/Types/Application.hs +105/−0
- src/Data/Bugsnag/Types/BinaryArch.hs +33/−0
- src/Data/Bugsnag/Types/Breadcrumb.hs +77/−0
- src/Data/Bugsnag/Types/BreadcrumbType.hs +52/−0
- src/Data/Bugsnag/Types/DependentNotifier.hs +41/−0
- src/Data/Bugsnag/Types/Device.hs +108/−0
- src/Data/Bugsnag/Types/ErrorType.hs +37/−0
- src/Data/Bugsnag/Types/Event.hs +181/−0
- src/Data/Bugsnag/Types/Exception.hs +54/−0
- src/Data/Bugsnag/Types/FeatureFlag.hs +37/−0
- src/Data/Bugsnag/Types/Notifier.hs +51/−0
- src/Data/Bugsnag/Types/Payload.hs +54/−0
- src/Data/Bugsnag/Types/Prelude.hs +34/−0
- src/Data/Bugsnag/Types/Request.hs +59/−0
- src/Data/Bugsnag/Types/RuntimeVersion.hs +239/−0
- src/Data/Bugsnag/Types/Session.hs +49/−0
- src/Data/Bugsnag/Types/SessionEvent.hs +41/−0
- src/Data/Bugsnag/Types/Severity.hs +30/−0
- src/Data/Bugsnag/Types/SeverityReason.hs +82/−0
- src/Data/Bugsnag/Types/SeverityReasonAttributes.hs +65/−0
- src/Data/Bugsnag/Types/SeverityReasonType.hs +80/−0
- src/Data/Bugsnag/Types/Stackframe.hs +108/−0
- src/Data/Bugsnag/Types/Thread.hs +57/−0
- src/Data/Bugsnag/Types/User.hs +46/−0
- test/Data/Bugsnag/Types/PayloadSpec.hs +179/−0
- test/Spec.hs +2/−0
+ CHANGELOG.md view
+ README.md view
+ bugsnag-types.cabal view
@@ -0,0 +1,102 @@+cabal-version: 1.18+name: bugsnag-types+version: 1.0.0.0+license: MIT+maintainer: pbrisbin@gmail.com+author: Patrick Brisbin+homepage: https://codeberg.org/pbrisbin/bugsnag-haskell#readme+synopsis: Types for the Bugsnag error reporter for Haskell+description: Please see README.md+category: Web+build-type: Simple+extra-doc-files:+ CHANGELOG.md+ README.md++flag examples+ description: Build the examples+ default: False++library+ exposed-modules:+ Data.Bugsnag.Types.Application+ Data.Bugsnag.Types.BinaryArch+ Data.Bugsnag.Types.Breadcrumb+ Data.Bugsnag.Types.BreadcrumbType+ Data.Bugsnag.Types.DependentNotifier+ Data.Bugsnag.Types.Device+ Data.Bugsnag.Types.ErrorType+ Data.Bugsnag.Types.Event+ Data.Bugsnag.Types.Exception+ Data.Bugsnag.Types.FeatureFlag+ Data.Bugsnag.Types.Notifier+ Data.Bugsnag.Types.Payload+ Data.Bugsnag.Types.Prelude+ Data.Bugsnag.Types.Request+ Data.Bugsnag.Types.RuntimeVersion+ Data.Bugsnag.Types.Session+ Data.Bugsnag.Types.SessionEvent+ Data.Bugsnag.Types.Severity+ Data.Bugsnag.Types.SeverityReason+ Data.Bugsnag.Types.SeverityReasonAttributes+ Data.Bugsnag.Types.SeverityReasonType+ Data.Bugsnag.Types.Stackframe+ Data.Bugsnag.Types.Thread+ Data.Bugsnag.Types.User++ hs-source-dirs: src+ other-modules: Paths_bugsnag_types+ default-language: GHC2021+ default-extensions:+ DeriveAnyClass DerivingStrategies DuplicateRecordFields LambdaCase+ NoFieldSelectors NoImplicitPrelude OverloadedRecordDot+ OverloadedStrings++ ghc-options:+ -fwrite-ide-info -Weverything -Wno-all-missed-specialisations+ -Wno-missed-specialisations -Wno-missing-exported-signatures+ -Wno-missing-import-lists -Wno-missing-kind-signatures+ -Wno-missing-local-signatures -Wno-missing-safe-haskell-mode+ -Wno-monomorphism-restriction -Wno-prepositive-qualified-module+ -Wno-safe -Wno-unsafe++ build-depends:+ aeson >=2.1.2.1,+ base >=4.17.2.1 && <5,+ text >=2.0.2++ if impl(ghc >=9.8)+ ghc-options:+ -Wno-missing-role-annotations -Wno-missing-poly-kind-signatures++test-suite spec+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ hs-source-dirs: test+ other-modules:+ Data.Bugsnag.Types.PayloadSpec+ Paths_bugsnag_types++ default-language: GHC2021+ default-extensions:+ DeriveAnyClass DerivingStrategies DuplicateRecordFields LambdaCase+ NoFieldSelectors NoImplicitPrelude OverloadedRecordDot+ OverloadedStrings++ ghc-options:+ -fwrite-ide-info -Weverything -Wno-all-missed-specialisations+ -Wno-missed-specialisations -Wno-missing-exported-signatures+ -Wno-missing-import-lists -Wno-missing-kind-signatures+ -Wno-missing-local-signatures -Wno-missing-safe-haskell-mode+ -Wno-monomorphism-restriction -Wno-prepositive-qualified-module+ -Wno-safe -Wno-unsafe -threaded -rtsopts -with-rtsopts=-N++ build-depends:+ aeson >=2.1.2.1,+ base >=4.17.2.1 && <5,+ bugsnag-types,+ hspec >=2.10.10++ if impl(ghc >=9.8)+ ghc-options:+ -Wno-missing-role-annotations -Wno-missing-poly-kind-signatures
+ src/Data/Bugsnag/Types/Application.hs view
@@ -0,0 +1,105 @@+module Data.Bugsnag.Types.Application+ ( Application (..)+ , exampleApplication+ , defaultApplication+ )+where++import Data.Bugsnag.Types.Prelude++import Data.Bugsnag.Types.BinaryArch++-- | Information about the app where the error occurred. These fields are+-- optional but highly recommended. To display custom app data alongside+-- these standard fields on the dashboard, the custom data should be+-- included in the @metaData@ object in an @app@ object.+data Application = Application+ { id :: Maybe Text+ -- ^ A unique ID for the application.+ , version :: Maybe Text+ -- ^ The version number of the application which generated the error.+ , versionCode :: Maybe Int+ -- ^ The+ -- <https://developer.android.com/studio/publish/versioning.html version code>+ -- of the application (Android only)+ , bundleVersion :: Maybe Text+ -- ^ The+ -- <https://developer.apple.com/library/content/technotes/tn2420/_index.html bundle version\/build number>+ -- of the application (iOS\/macOS\/tvOS only)+ , codeBundleId :: Maybe Text+ -- ^ A unique identifier to identify a code bundle release when using tools+ -- like CodePush (mobile only).+ , buildUUID :: Maybe Text+ -- ^ A build ID that is required to identify a specific build when the+ -- version and version code are the same.+ , releaseStage :: Maybe Text+ -- ^ The release stage that this error occurred in, for example+ -- \"development\", \"staging\" or \"production\".+ , type_ :: Maybe Text+ -- ^ A specialized type of the application, such as the worker queue or web+ -- framework used, like \"rails\", \"mailman\", or \"celery\".+ , dsymUUIDs :: Maybe [Text]+ -- ^ The UUIDs of the <http://lldb.llvm.org/symbols.html debug symbols file>+ -- corresponding to this application, if any.+ , duration :: Maybe Int+ -- ^ How long the app has been running for in milliseconds.+ , durationInForeground :: Maybe Int+ -- ^ How long the app has been in the foreground of the device in+ -- milliseconds.+ , inForeground :: Maybe Bool+ -- ^ Whether or not the app was in the foreground when the error occurred.+ , isLaunching :: Maybe Bool+ -- ^ Whether or not the app was still launching when the error occurred.+ , binaryArch :: Maybe BinaryArch+ -- ^ The architecture of the running binary.+ , runningOnRosetta :: Maybe Bool+ -- ^ Whether the application is running on the Rosetta emulator for Mac.+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON Application where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON Application where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultApplication :: Application+defaultApplication =+ Application+ { id = Nothing+ , version = Nothing+ , versionCode = Nothing+ , bundleVersion = Nothing+ , codeBundleId = Nothing+ , buildUUID = Nothing+ , releaseStage = Nothing+ , type_ = Nothing+ , dsymUUIDs = Nothing+ , duration = Nothing+ , durationInForeground = Nothing+ , inForeground = Nothing+ , isLaunching = Nothing+ , binaryArch = Nothing+ , runningOnRosetta = Nothing+ }++exampleApplication :: Application+exampleApplication =+ Application+ { id = Just "com.bugsnag.android.example.debug"+ , version = Just "1.1.3"+ , versionCode = Just 12+ , bundleVersion = Just "1.0.2"+ , codeBundleId = Just "1.0-1234"+ , buildUUID = Just "BE5BA3D0-971C-4418-9ECF-E2D1ABCB66BE"+ , releaseStage = Just "staging"+ , type_ = Just "rails"+ , dsymUUIDs = Just ["e6173678256785afd940392abee"]+ , duration = Just 1275+ , durationInForeground = Just 983+ , inForeground = Just True+ , isLaunching = Just True+ , binaryArch = Just exampleBinaryArch+ , runningOnRosetta = Just True+ }
+ src/Data/Bugsnag/Types/BinaryArch.hs view
@@ -0,0 +1,33 @@+module Data.Bugsnag.Types.BinaryArch+ ( BinaryArch (..)+ , exampleBinaryArch+ )+where++import Data.Bugsnag.Types.Prelude++-- | The architecture of the running binary.+data BinaryArch+ = X86+ | X86_64+ | Arm32+ | Arm64+ | Arm64e+ | Armv6+ | Armv7+ | Armv7f+ | Armv7k+ | Armv7s+ | Armv8+ | Amd64+ deriving stock (Bounded, Enum, Eq, Generic, Show)++instance FromJSON BinaryArch where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON BinaryArch where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++exampleBinaryArch :: BinaryArch+exampleBinaryArch = X86
+ src/Data/Bugsnag/Types/Breadcrumb.hs view
@@ -0,0 +1,77 @@+module Data.Bugsnag.Types.Breadcrumb+ ( Breadcrumb (..)+ , exampleBreadcrumb+ , defaultBreadcrumb+ )+where++import Data.Bugsnag.Types.Prelude++import Data.Bugsnag.Types.BreadcrumbType++data Breadcrumb = Breadcrumb+ { timestamp :: Text+ -- ^ The time at which the event occurred, in+ -- <https://tools.ietf.org/html/rfc3339#section-5.8 ISO 8601 format>.+ , name :: Text+ -- ^ A short summary describing the event, such as the user action taken or a+ -- new application state.+ , type_ :: BreadcrumbType+ -- ^ A category which describes the breadcrumb, from the list of allowed+ -- values.+ --+ -- - @navigation@ - Changing screens or content being displayed, with a+ -- defined destination and optionally a previous location.+ --+ -- - @request@ - Sending and receiving requests and responses.+ --+ -- - @process@ - Performing an intensive task or query.+ --+ -- - @log@ - Messages and severity sent to a logging platform.+ --+ -- - @user@ - Actions performed by the user, like text input, button+ -- presses, or confirming\/cancelling an alert dialog.+ --+ -- - @state@ - Changing the overall state of an app, such as closing,+ -- pausing, or being moved to the background, as well as device state+ -- changes like memory or battery warnings and network connectivity+ -- changes.+ --+ -- - @error@ - An error which was reported to BugSnag encountered in the+ -- same session.+ --+ -- - @manual@ - User-defined, manually added breadcrumbs.+ , metaData :: Maybe (KeyMap Text)+ -- ^ Additional information about the event, as key\/value pairs.+ --+ -- > {+ -- > "to": "PauseView",+ -- > "from": "PodBayDoorView"+ -- > }+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON Breadcrumb where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON Breadcrumb where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultBreadcrumb :: Text -> Text -> BreadcrumbType -> Breadcrumb+defaultBreadcrumb timestamp name type_ =+ Breadcrumb+ { timestamp+ , name+ , type_+ , metaData = Nothing+ }++exampleBreadcrumb :: Breadcrumb+exampleBreadcrumb =+ Breadcrumb+ { timestamp = "2016-07-19T12:17:27-0700"+ , name = "Open menu"+ , type_ = exampleBreadcrumbType+ , metaData = Nothing+ }
+ src/Data/Bugsnag/Types/BreadcrumbType.hs view
@@ -0,0 +1,52 @@+module Data.Bugsnag.Types.BreadcrumbType+ ( BreadcrumbType (..)+ , exampleBreadcrumbType+ )+where++import Data.Bugsnag.Types.Prelude++-- | A category which describes the breadcrumb, from the list of allowed+-- values.+--+-- - @navigation@ - Changing screens or content being displayed, with a+-- defined destination and optionally a previous location.+--+-- - @request@ - Sending and receiving requests and responses.+--+-- - @process@ - Performing an intensive task or query.+--+-- - @log@ - Messages and severity sent to a logging platform.+--+-- - @user@ - Actions performed by the user, like text input, button+-- presses, or confirming\/cancelling an alert dialog.+--+-- - @state@ - Changing the overall state of an app, such as closing,+-- pausing, or being moved to the background, as well as device state+-- changes like memory or battery warnings and network connectivity+-- changes.+--+-- - @error@ - An error which was reported to BugSnag encountered in the+-- same session.+--+-- - @manual@ - User-defined, manually added breadcrumbs.+data BreadcrumbType+ = Navigation+ | Request+ | Process+ | Log+ | User+ | State+ | Error+ | Manual+ deriving stock (Bounded, Enum, Eq, Generic, Show)++instance FromJSON BreadcrumbType where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON BreadcrumbType where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++exampleBreadcrumbType :: BreadcrumbType+exampleBreadcrumbType = Navigation
+ src/Data/Bugsnag/Types/DependentNotifier.hs view
@@ -0,0 +1,41 @@+module Data.Bugsnag.Types.DependentNotifier+ ( DependentNotifier (..)+ , exampleDependentNotifier+ , defaultDependentNotifier+ )+where++import Data.Bugsnag.Types.Prelude++data DependentNotifier = DependentNotifier+ { name :: Text+ -- ^ The notifier name.+ , version :: Text+ -- ^ The notifier\'s current version.+ , url :: Text+ -- ^ The URL associated with the notifier.+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON DependentNotifier where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON DependentNotifier where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultDependentNotifier :: Text -> Text -> Text -> DependentNotifier+defaultDependentNotifier name version url =+ DependentNotifier+ { name+ , version+ , url+ }++exampleDependentNotifier :: DependentNotifier+exampleDependentNotifier =+ DependentNotifier+ { name = "Bugsnag Android"+ , version = "2.1.10"+ , url = "https://github.com/bugsnag/bugsnag-android"+ }
+ src/Data/Bugsnag/Types/Device.hs view
@@ -0,0 +1,108 @@+module Data.Bugsnag.Types.Device+ ( Device (..)+ , exampleDevice+ , defaultDevice+ )+where++import Data.Bugsnag.Types.Prelude++import Data.Bugsnag.Types.RuntimeVersion++-- | Information about the computer\/device running the app. These fields are+-- optional but highly recommended. To display custom device data alongside+-- these standard fields on the dashboard, the custom data should be+-- included in the @metaData@ object in a @device@ object.+data Device = Device+ { hostname :: Maybe Text+ -- ^ The hostname of the server running your code, if applicable.+ , id :: Maybe Text+ -- ^ A unique identifier for the device.+ , manufacturer :: Maybe Text+ -- ^ The manufacturer of the device.+ , model :: Maybe Text+ -- ^ The model of the device.+ , modelNumber :: Maybe Text+ -- ^ The model number of the device.+ , osName :: Maybe Text+ -- ^ The device\'s operating system name.+ , osVersion :: Maybe Text+ -- ^ The device\'s operating system version.+ , freeMemory :: Maybe Int+ -- ^ The number of bytes unused in the device\'s RAM.+ , totalMemory :: Maybe Int+ -- ^ The number of total bytes in the device\'s RAM.+ , freeDisk :: Maybe Int+ -- ^ The number of unused bytes on the drive running the application.+ , browserName :: Maybe Text+ -- ^ If a web application, the web browser used by the device.+ , browserVersion :: Maybe Text+ -- ^ If a web application, the version of the browser used by the device.+ , jailbroken :: Maybe Bool+ -- ^ Whether or not the device has been modified to give users root access.+ , orientation :: Maybe Text+ -- ^ The orientation of the device at the time of the error.+ , time :: Maybe Text+ -- ^ The time at which the error occurred, in+ -- <https://tools.ietf.org/html/rfc3339#section-5.8 ISO 8601 format>.+ , cpuAbi :: Maybe [Text]+ -- ^ The <https://developer.android.com/ndk/guides/abis ABIs> supported by+ -- the device (Android only).+ , runtimeVersions :: Maybe RuntimeVersion+ , macCatalystiOSVersion :: Maybe Text+ -- ^ The device\'s Mac Catalyst iOS version.+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON Device where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON Device where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultDevice :: Device+defaultDevice =+ Device+ { hostname = Nothing+ , id = Nothing+ , manufacturer = Nothing+ , model = Nothing+ , modelNumber = Nothing+ , osName = Nothing+ , osVersion = Nothing+ , freeMemory = Nothing+ , totalMemory = Nothing+ , freeDisk = Nothing+ , browserName = Nothing+ , browserVersion = Nothing+ , jailbroken = Nothing+ , orientation = Nothing+ , time = Nothing+ , cpuAbi = Nothing+ , runtimeVersions = Nothing+ , macCatalystiOSVersion = Nothing+ }++exampleDevice :: Device+exampleDevice =+ Device+ { hostname = Just "web1.internal"+ , id = Just "fd124e87760c4281aef"+ , manufacturer = Just "LGE"+ , model = Just "Nexus 6P"+ , modelNumber = Just "600"+ , osName = Just "android"+ , osVersion = Just "8.0.1"+ , freeMemory = Just 183879616+ , totalMemory = Just 201326592+ , freeDisk = Just 13478064128+ , browserName = Just "Chrome"+ , browserVersion = Just "61.0.3163.100"+ , jailbroken = Nothing+ , orientation = Just "portrait"+ , time = Just "2018-08-07T10:16:34.564Z"+ , cpuAbi = Just ["x86_64"]+ , runtimeVersions = Just exampleRuntimeVersion+ , macCatalystiOSVersion = Just "14.0"+ }
+ src/Data/Bugsnag/Types/ErrorType.hs view
@@ -0,0 +1,37 @@+module Data.Bugsnag.Types.ErrorType+ ( ErrorType (..)+ , exampleErrorType+ )+where++import Data.Bugsnag.Types.Prelude++-- | This should be set to indicate the type of runtime the thread was+-- running on so that the stacktrace can be parsed correctly.+data ErrorType+ = Android+ | Browserjs+ | C+ | Cocoa+ | Csharp+ | Electronnodejs+ | Electronrendererjs+ | Expojs+ | Go+ | Java+ | Nodejs+ | Php+ | Python+ | Reactnativejs+ | Ruby+ deriving stock (Bounded, Enum, Eq, Generic, Show)++instance FromJSON ErrorType where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON ErrorType where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++exampleErrorType :: ErrorType+exampleErrorType = Android
+ src/Data/Bugsnag/Types/Event.hs view
@@ -0,0 +1,181 @@+module Data.Bugsnag.Types.Event+ ( Event (..)+ , exampleEvent+ , defaultEvent+ )+where++import Data.Bugsnag.Types.Prelude++import Data.Bugsnag.Types.Application+import Data.Bugsnag.Types.Breadcrumb+import Data.Bugsnag.Types.Device+import Data.Bugsnag.Types.Exception+import Data.Bugsnag.Types.FeatureFlag+import Data.Bugsnag.Types.Request+import Data.Bugsnag.Types.Session+import Data.Bugsnag.Types.Severity+import Data.Bugsnag.Types.SeverityReason+import Data.Bugsnag.Types.Thread+import Data.Bugsnag.Types.User++data Event = Event+ { exceptions :: [Exception]+ -- ^ An array of exceptions that occurred during this event. There must be at+ -- least one entry. Most of the time there will only be one exception, but+ -- some languages support \"nested\" or \"caused by\" exceptions. In this+ -- case, exceptions should be unwrapped and added to the array one at a+ -- time. The array should be in order from the outermost error to the+ -- innermost. For example, the first element in the array should be the+ -- error caused by the second element, and so on.+ , breadcrumbs :: Maybe [Breadcrumb]+ -- ^ An array of user- and system-initiated events which led up to an error,+ -- providing additional context. This list is sequential and ordered newest+ -- to oldest.+ , request :: Maybe Request+ , threads :: Maybe [Thread]+ -- ^ An array of background threads. This is optional but recommended for+ -- apps that rely heavily on threading. Threads should be in an order that+ -- makes sense for your application.+ , context :: Maybe Text+ -- ^ A string representing what was happening in the application at the time+ -- of the error. This string could be used for grouping purposes, depending+ -- on the event. Usually this would represent the controller and action in+ -- a server based project. It could represent the screen that the user was+ -- interacting with in a client side project. For example:+ --+ -- - On Ruby on Rails the context could be @controller#action@.+ --+ -- - In Android, the context could be the top most Activity.+ --+ -- - In iOS, the context could be the name of the top most+ -- UIViewController.+ , groupingHash :: Maybe Text+ -- ^ The+ -- <https://docs.bugsnag.com/product/error-grouping default error grouping>+ -- can be overridden by specifying a custom grouping hash.+ , unhandled :: Maybe Bool+ -- ^ Whether the error was unhandled. If true, the error was detected by the+ -- notifier because it was not handled by the application. If false, the+ -- errors was handled and reported using Bugsnag.notify.+ , severity :: Maybe Severity+ -- ^ The severity of the error+ --+ -- - @error@ - The default for unhandled errors.+ --+ -- - @warning@ - The default when Bugsnag.notify is called.+ --+ -- - @info@ - Can be used in manual Bugsnag.notify calls.+ , severityReason :: Maybe SeverityReason+ , projectPackages :: Maybe [Text]+ -- ^ Sets which package names should be considered as a part of the running+ -- application. We mark stacktrace lines as in-project if they originate+ -- from any of these packages and this allows us to improve the visual+ -- display of the stacktrace on the dashboard.+ , user :: Maybe User+ , app :: Maybe Application+ , device :: Maybe Device+ , session :: Maybe Session+ , featureFlags :: Maybe [FeatureFlag]+ -- ^ Details of the feature flags (experiments) and associated variants that+ -- were active when the error occurred.+ , metaData :: Maybe (KeyMap (KeyMap Text))+ -- ^ An object containing any further data you wish to attach to this error+ -- event. This should contain one or more objects, with each object being+ -- displayed in its own tab on the event details on the dashboard.+ --+ -- > {+ -- > // Custom user data to be displayed in the User tab along with standard+ -- > // user fields on the dashboard.+ -- > "user": {+ -- > ...+ -- > },+ -- >+ -- > // Custom app data to be displayed in the App tab along with standard+ -- > // app fields on the dashboard.+ -- > "app": {+ -- > ...+ -- > },+ -- >+ -- > // Custom device data to be displayed in the Device tab along with+ -- > //standard device fields on the dashboard.+ -- > "device": {+ -- > ...+ -- > },+ -- >+ -- > Custom request data to be displayed in the Request tab along with+ -- > standard request fields on the dashboard.+ -- > "request": {+ -- > ...+ -- > },+ -- >+ -- > // This will be displayed as an extra tab on the dashboard.+ -- > "Some data": {+ -- >+ -- > // A key value pair that will be displayed in the first tab.+ -- > "key": "value",+ -- >+ -- > // Key value pairs can be contained in nested objects which helps+ -- > // to organize the information presented in the tab.+ -- > "setOfKeys": {+ -- > "key": "value",+ -- > "key2": "value"+ -- > }+ -- > },+ -- >+ -- > // This would be the second extra tab on the dashboard.+ -- > "Some more data": {+ -- > ...+ -- > }+ -- > }+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON Event where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON Event where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultEvent :: [Exception] -> Event+defaultEvent exceptions =+ Event+ { exceptions+ , breadcrumbs = Nothing+ , request = Nothing+ , threads = Nothing+ , context = Nothing+ , groupingHash = Nothing+ , unhandled = Nothing+ , severity = Nothing+ , severityReason = Nothing+ , projectPackages = Nothing+ , user = Nothing+ , app = Nothing+ , device = Nothing+ , session = Nothing+ , featureFlags = Nothing+ , metaData = Nothing+ }++exampleEvent :: Event+exampleEvent =+ Event+ { exceptions = [exampleException]+ , breadcrumbs = Just [exampleBreadcrumb]+ , request = Just exampleRequest+ , threads = Just [exampleThread]+ , context = Just "auth/session#create"+ , groupingHash = Just "buggy_file.rb"+ , unhandled = Just True+ , severity = Just exampleSeverity+ , severityReason = Just exampleSeverityReason+ , projectPackages = Just ["com.example.package1", "com.example.package2"]+ , user = Just exampleUser+ , app = Just exampleApplication+ , device = Just exampleDevice+ , session = Just exampleSession+ , featureFlags = Just [exampleFeatureFlag]+ , metaData = Nothing+ }
+ src/Data/Bugsnag/Types/Exception.hs view
@@ -0,0 +1,54 @@+module Data.Bugsnag.Types.Exception+ ( Exception (..)+ , exampleException+ , defaultException+ )+where++import Data.Bugsnag.Types.Prelude++import Data.Bugsnag.Types.ErrorType+import Data.Bugsnag.Types.Stackframe++data Exception = Exception+ { errorClass :: Text+ -- ^ The class of error which occurred. This field is used to group the+ -- errors together so should not contain any contextual information that+ -- would prevent correct grouping. This would ordinarily be the Exception+ -- name when dealing with an exception.+ , message :: Maybe Text+ -- ^ The error message associated with the error. Usually this will contain+ -- some information about this specific instance of the error and is not+ -- used to group the errors.+ , stacktrace :: [Stackframe]+ -- ^ An array of stackframe objects. Each object represents one line in the+ -- exception\'s stacktrace. This information is used to help with error+ -- grouping, as well as displaying it to the user.+ , type_ :: Maybe ErrorType+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON Exception where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON Exception where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultException :: Text -> [Stackframe] -> Exception+defaultException errorClass stacktrace =+ Exception+ { errorClass+ , stacktrace+ , message = Nothing+ , type_ = Nothing+ }++exampleException :: Exception+exampleException =+ Exception+ { errorClass = "NoMethodError"+ , message = Just "Unable to connect to database"+ , stacktrace = [exampleStackframe]+ , type_ = Just exampleErrorType+ }
+ src/Data/Bugsnag/Types/FeatureFlag.hs view
@@ -0,0 +1,37 @@+module Data.Bugsnag.Types.FeatureFlag+ ( FeatureFlag (..)+ , exampleFeatureFlag+ , defaultFeatureFlag+ )+where++import Data.Bugsnag.Types.Prelude++data FeatureFlag = FeatureFlag+ { featureFlag :: Text+ -- ^ The name of the feature flag.+ , variant :: Maybe Text+ -- ^ The name of the variant.+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON FeatureFlag where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON FeatureFlag where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultFeatureFlag :: Text -> FeatureFlag+defaultFeatureFlag featureFlag =+ FeatureFlag+ { featureFlag+ , variant = Nothing+ }++exampleFeatureFlag :: FeatureFlag+exampleFeatureFlag =+ FeatureFlag+ { featureFlag = "share_ios_photo_sharing_button"+ , variant = Just "blue_button"+ }
+ src/Data/Bugsnag/Types/Notifier.hs view
@@ -0,0 +1,51 @@+module Data.Bugsnag.Types.Notifier+ ( Notifier (..)+ , exampleNotifier+ , defaultNotifier+ )+where++import Data.Bugsnag.Types.Prelude++import Data.Bugsnag.Types.DependentNotifier++-- | Describes the notifier itself. These properties are used within BugSnag+-- to track error rates from a notifier.+data Notifier = Notifier+ { name :: Text+ -- ^ The notifier name.+ , version :: Text+ -- ^ The notifier\'s current version.+ , url :: Text+ -- ^ The URL associated with the notifier.+ , dependencies :: Maybe [DependentNotifier]+ -- ^ For platforms where multiple notifiers are used to capture an event, an+ -- optional array containing the details of the additional notifiers can be+ -- specified.+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON Notifier where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON Notifier where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultNotifier :: Text -> Text -> Text -> Notifier+defaultNotifier name version url =+ Notifier+ { name+ , version+ , url+ , dependencies = Nothing+ }++exampleNotifier :: Notifier+exampleNotifier =+ Notifier+ { name = "Bugsnag Ruby"+ , version = "1.0.11"+ , url = "https://github.com/bugsnag/bugsnag-ruby"+ , dependencies = Just [exampleDependentNotifier]+ }
+ src/Data/Bugsnag/Types/Payload.hs view
@@ -0,0 +1,54 @@+module Data.Bugsnag.Types.Payload+ ( Payload (..)+ , examplePayload+ , defaultPayload+ )+where++import Data.Bugsnag.Types.Prelude++import Data.Bugsnag.Types.Event+import Data.Bugsnag.Types.Notifier++data Payload = Payload+ { apiKey :: Maybe Text+ -- ^ The API Key associated with the project. Informs BugSnag which project+ -- has generated this error. This is provided for legacy notifiers. It is+ -- preferable to use the @Bugsnag-Api-Key@ header instead.+ , payloadVersion :: Text+ -- ^ The version number of the payload. This is currently @5@. The+ -- @Bugsnag-Payload-Version@ header should be included as well for+ -- compatibility reasons.+ , notifier :: Notifier+ , events :: [Event]+ -- ^ An array of error events that BugSnag should be notified of. A notifier+ -- can choose to group notices into an array to minimize network traffic,+ -- or can notify BugSnag each time an event occurs. Should contain at least+ -- 1 event.+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON Payload where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON Payload where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultPayload :: Text -> Notifier -> [Event] -> Payload+defaultPayload payloadVersion notifier events =+ Payload+ { payloadVersion+ , notifier+ , events+ , apiKey = Nothing+ }++examplePayload :: Payload+examplePayload =+ Payload+ { apiKey = Just "YOUR-NOTIFIER-API-KEY"+ , payloadVersion = "5"+ , notifier = exampleNotifier+ , events = [exampleEvent]+ }
+ src/Data/Bugsnag/Types/Prelude.hs view
@@ -0,0 +1,34 @@+module Data.Bugsnag.Types.Prelude+ ( module X+ , aesonOptions+ )+where++import Prelude as X hiding (id)++import Control.Monad as X (void)+import Data.Aeson (Options (..), defaultOptions)+import Data.Aeson as X+ ( FromJSON (..)+ , ToJSON (..)+ , genericParseJSON+ , genericToEncoding+ , genericToJSON+ )+import Data.Aeson.KeyMap as X (KeyMap)+import Data.Char (toLower)+import Data.Foldable as X (for_, traverse_)+import Data.Maybe as X (catMaybes, fromMaybe, mapMaybe)+import Data.Text as X (Text, pack, unpack)+import Data.Traversable as X (for)+import GHC.Generics as X (Generic)++aesonOptions :: Options+aesonOptions =+ defaultOptions+ { fieldLabelModifier = \case+ "type_" -> "type"+ x -> x+ , constructorTagModifier = map toLower+ , omitNothingFields = True+ }
+ src/Data/Bugsnag/Types/Request.hs view
@@ -0,0 +1,59 @@+module Data.Bugsnag.Types.Request+ ( Request (..)+ , exampleRequest+ , defaultRequest+ )+where++import Data.Bugsnag.Types.Prelude++-- | Details about the web request from the client that experienced the+-- error, if relevant. To display custom request data alongside these+-- standard fields on the dashboard, the custom data should be included in+-- the @metaData@ object in a @request@ object.+data Request = Request+ { clientIp :: Maybe Text+ -- ^ The IP address of the client that experienced the error.+ , headers :: Maybe (KeyMap Text)+ -- ^ The headers sent with the request.+ --+ -- > {+ -- > "Accept": "*/*",+ -- > "Accept-Encoding": "gzip, deflate, sdch, br",+ -- > "Accept-Language": "en-US,en;q=0.8"+ -- > }+ , httpMethod :: Maybe Text+ -- ^ The HTTP method used.+ , url :: Maybe Text+ -- ^ The URL of the request.+ , referer :: Maybe Text+ -- ^ The <https://en.wikipedia.org/wiki/HTTP_referer HTTP referer>+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON Request where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON Request where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultRequest :: Request+defaultRequest =+ Request+ { clientIp = Nothing+ , headers = Nothing+ , httpMethod = Nothing+ , url = Nothing+ , referer = Nothing+ }++exampleRequest :: Request+exampleRequest =+ Request+ { clientIp = Just "192.168.44.0"+ , headers = Nothing+ , httpMethod = Just "PUT"+ , url = Just "http://example.com/users/19/settings"+ , referer = Just "http://example.com?q=awesome"+ }
+ src/Data/Bugsnag/Types/RuntimeVersion.hs view
@@ -0,0 +1,239 @@+module Data.Bugsnag.Types.RuntimeVersion+ ( RuntimeVersion (..)+ , exampleRuntimeVersion+ , defaultRuntimeVersion+ )+where++import Data.Bugsnag.Types.Prelude++-- | The versions of the relevant runtimes, languages and\/or frameworks for+-- the platform.+data RuntimeVersion = RuntimeVersion+ { androidApiLevel :: Maybe Text+ -- ^ The Android API level (Android only).+ , bottle :: Maybe Text+ -- ^ Bottle framework version (Python only).+ , celery :: Maybe Text+ -- ^ Celery task queue version (Python only).+ , clangVersion :: Maybe Text+ -- ^ Clang compiler version (iOS\/tvOS\/macOS only).+ , cocos2dx :: Maybe Text+ -- ^ Cocos2d-x framework version (Cocos2d-x only).+ , delayedJob :: Maybe Text+ -- ^ Delayed Job framework version (Ruby only).+ , django :: Maybe Text+ -- ^ Django framework version (Python only).+ , dotnet :: Maybe Text+ -- ^ Description of the framework (.NET only).+ , dotnetApiCompatibility :: Maybe Text+ -- ^ .NET API compatibility level (Unity only).+ , dotnetClr :: Maybe Text+ -- ^ Version of .NET Common Language Runtime (.NET only).+ , dotnetScriptingRuntime :: Maybe Text+ -- ^ .NET scripting runtime version (Unity only).+ , electron :: Maybe Text+ -- ^ Electron platform version (Electron only).+ , eventMachine :: Maybe Text+ -- ^ EventMachine library version (Ruby only).+ , expoApp :: Maybe Text+ -- ^ Expo app version (Expo only).+ , expoSdk :: Maybe Text+ -- ^ Expo SDK version (Expo only).+ , flask :: Maybe Text+ -- ^ Flask framework version (Python only).+ , gin :: Maybe Text+ -- ^ Gin framework version (Go only).+ , go :: Maybe Text+ -- ^ Go language version (Go only).+ , javaType :: Maybe Text+ -- ^ Java platform implementation type (Java only).+ , javaVersion :: Maybe Text+ -- ^ Java runtime version (Java only).+ , jruby :: Maybe Text+ -- ^ Version of JRuby (Ruby only).+ , laravel :: Maybe Text+ -- ^ Laravel framework version (PHP only).+ , lumen :: Maybe Text+ -- ^ Lumen framework version (PHP only).+ , magento :: Maybe Text+ -- ^ Magento platform version (PHP only).+ , mailman :: Maybe Text+ -- ^ Mailman framework version (Ruby only).+ , martini :: Maybe Text+ -- ^ Martini framework version (Go only).+ , negroni :: Maybe Text+ -- ^ Negroni framework version (Go only).+ , node :: Maybe Text+ -- ^ Node.js version (Javascript only).+ , osBuild :: Maybe Text+ -- ^ Build number of the OS (iOS\/tvOS\/macOS only).+ , php :: Maybe Text+ -- ^ Version of PHP (PHP only).+ , python :: Maybe Text+ -- ^ Version of Python (Python only).+ , que :: Maybe Text+ -- ^ Que job queue version (Ruby only).+ , rack :: Maybe Text+ -- ^ Rack webserver version (Ruby only).+ , rails :: Maybe Text+ -- ^ Ruby on Rails version (Ruby only).+ , rake :: Maybe Text+ -- ^ Rake tool version (Ruby only).+ , reactNative :: Maybe Text+ -- ^ Version of React Native (React Native\/Expo only).+ , reactNativeJsEngine :: Maybe Text+ -- ^ Javascript engine type (React Native\/Expo only).+ , resque :: Maybe Text+ -- ^ Resque library version (Ruby only).+ , revel :: Maybe Text+ -- ^ Revel framework version (Go only).+ , ruby :: Maybe Text+ -- ^ Version of Ruby (Ruby only).+ , shoryoken :: Maybe Text+ -- ^ Shoryoken framework version (Ruby only).+ , sidekiq :: Maybe Text+ -- ^ Sidekiq scheduler version (Ruby only).+ , silex :: Maybe Text+ -- ^ Silex framework version (PHP only).+ , sinatra :: Maybe Text+ -- ^ Sinatra DSL version (Ruby only).+ , springBoot :: Maybe Text+ -- ^ Spring Boot framework version (Java only).+ , springFramework :: Maybe Text+ -- ^ Spring framework version (Java only).+ , swift :: Maybe Text+ -- ^ Swift language version (iOS\/tvOS\/macOS only).+ , symfony :: Maybe Text+ -- ^ Symfony framework version (PHP only).+ , tornado :: Maybe Text+ -- ^ Tornado framework version (Python only).+ , unity :: Maybe Text+ -- ^ Version of Unity.+ , unityScriptingBackend :: Maybe Text+ -- ^ The Unity scripting backend - Mono or IL2CPP (Unity only).+ , wordpress :: Maybe Text+ -- ^ Wordpress version (PHP only).+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON RuntimeVersion where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON RuntimeVersion where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultRuntimeVersion :: RuntimeVersion+defaultRuntimeVersion =+ RuntimeVersion+ { androidApiLevel = Nothing+ , bottle = Nothing+ , celery = Nothing+ , clangVersion = Nothing+ , cocos2dx = Nothing+ , delayedJob = Nothing+ , django = Nothing+ , dotnet = Nothing+ , dotnetApiCompatibility = Nothing+ , dotnetClr = Nothing+ , dotnetScriptingRuntime = Nothing+ , electron = Nothing+ , eventMachine = Nothing+ , expoApp = Nothing+ , expoSdk = Nothing+ , flask = Nothing+ , gin = Nothing+ , go = Nothing+ , javaType = Nothing+ , javaVersion = Nothing+ , jruby = Nothing+ , laravel = Nothing+ , lumen = Nothing+ , magento = Nothing+ , mailman = Nothing+ , martini = Nothing+ , negroni = Nothing+ , node = Nothing+ , osBuild = Nothing+ , php = Nothing+ , python = Nothing+ , que = Nothing+ , rack = Nothing+ , rails = Nothing+ , rake = Nothing+ , reactNative = Nothing+ , reactNativeJsEngine = Nothing+ , resque = Nothing+ , revel = Nothing+ , ruby = Nothing+ , shoryoken = Nothing+ , sidekiq = Nothing+ , silex = Nothing+ , sinatra = Nothing+ , springBoot = Nothing+ , springFramework = Nothing+ , swift = Nothing+ , symfony = Nothing+ , tornado = Nothing+ , unity = Nothing+ , unityScriptingBackend = Nothing+ , wordpress = Nothing+ }++exampleRuntimeVersion :: RuntimeVersion+exampleRuntimeVersion =+ RuntimeVersion+ { androidApiLevel = Just "28"+ , bottle = Just "0.12.8"+ , celery = Just "4.2.0"+ , clangVersion = Just "7.0.1"+ , cocos2dx = Just "3.17.2"+ , delayedJob = Just "4.1.8"+ , django = Just "2.1.7"+ , dotnet = Just ".NET Framework 4.7.3416.0"+ , dotnetApiCompatibility = Just ".NET 2.0 Subset"+ , dotnetClr = Just "4.0.30319.17379"+ , dotnetScriptingRuntime = Just ".NET 3.5 equivalent"+ , electron = Just "11.4.3"+ , eventMachine = Just "1.2.7"+ , expoApp = Just "2.10.0.105125"+ , expoSdk = Just "32.0.0"+ , flask = Just "1.0.2"+ , gin = Just "1.3.0"+ , go = Just "1.11.2"+ , javaType = Just "Java(TM) SE Runtime Environment"+ , javaVersion = Just "1.8.0_131-b11"+ , jruby = Just "9.2.5.0"+ , laravel = Just "5.7.22"+ , lumen = Just "5.7"+ , magento = Just "2.3.0"+ , mailman = Just "0.8.0"+ , martini = Just "1.0"+ , negroni = Just "1.0.0"+ , node = Just "10.14.1"+ , osBuild = Just "16D57"+ , php = Just "7.2.12"+ , python = Just "3.7.1"+ , que = Just "0.14.3"+ , rack = Just "2.0.6"+ , rails = Just "5.2.2"+ , rake = Just "12.3.2"+ , reactNative = Just "0.57.5"+ , reactNativeJsEngine = Just "hermes"+ , resque = Just "2.0.0"+ , revel = Just "0.21.0"+ , ruby = Just "2.5.3"+ , shoryoken = Just "5.0.1"+ , sidekiq = Just "5.1.3"+ , silex = Just "2.1.0"+ , sinatra = Just "2.0.3"+ , springBoot = Just "1.5.13.RELEASE"+ , springFramework = Just "4.2.13.RELEASE"+ , swift = Just "4.2"+ , symfony = Just "4.2.11"+ , tornado = Just "5.1.1"+ , unity = Just "2018.2.17"+ , unityScriptingBackend = Just "Mono"+ , wordpress = Just "5.1"+ }
+ src/Data/Bugsnag/Types/Session.hs view
@@ -0,0 +1,49 @@+module Data.Bugsnag.Types.Session+ ( Session (..)+ , exampleSession+ , defaultSession+ )+where++import Data.Bugsnag.Types.Prelude++import Data.Bugsnag.Types.SessionEvent++-- | Details of any session information associated with the event.+--+-- This can be used alongside the+-- <https://smartbear.portal.swaggerhub.com/bugsnag/default/bugsnag-session-reporting-api Session Tracking API>+-- to associate the event with a session so that a release\'s crash rate+-- can be determined.+data Session = Session+ { id :: Text+ -- ^ The unique identifier of the session.+ , startedAt :: Text+ -- ^ The time (in <https://en.wikipedia.org/wiki/ISO_8601 ISO 8601> format)+ -- at which the session started.+ , events :: SessionEvent+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON Session where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON Session where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultSession :: Text -> Text -> SessionEvent -> Session+defaultSession id startedAt events =+ Session+ { id+ , startedAt+ , events+ }++exampleSession :: Session+exampleSession =+ Session+ { id = "9f65c975-8155-456f-91e5-c4c4b3db0555"+ , startedAt = "2017-01-01T14:30:00.000Z"+ , events = exampleSessionEvent+ }
+ src/Data/Bugsnag/Types/SessionEvent.hs view
@@ -0,0 +1,41 @@+module Data.Bugsnag.Types.SessionEvent+ ( SessionEvent (..)+ , exampleSessionEvent+ , defaultSessionEvent+ )+where++import Data.Bugsnag.Types.Prelude++-- | Details of the number of handled and unhandled events that have occurred+-- so far in this session.+data SessionEvent = SessionEvent+ { handled :: Int+ -- ^ The number of handled events that have occurred in this session+ -- (including this event).+ , unhandled :: Int+ -- ^ The number of unhandled events that have occurred in this session+ -- (including this event)+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON SessionEvent where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON SessionEvent where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultSessionEvent :: Int -> Int -> SessionEvent+defaultSessionEvent handled unhandled =+ SessionEvent+ { handled+ , unhandled+ }++exampleSessionEvent :: SessionEvent+exampleSessionEvent =+ SessionEvent+ { handled = 1+ , unhandled = 1+ }
+ src/Data/Bugsnag/Types/Severity.hs view
@@ -0,0 +1,30 @@+module Data.Bugsnag.Types.Severity+ ( Severity (..)+ , exampleSeverity+ )+where++import Data.Bugsnag.Types.Prelude++-- | The severity of the error+--+-- - @error@ - The default for unhandled errors.+--+-- - @warning@ - The default when Bugsnag.notify is called.+--+-- - @info@ - Can be used in manual Bugsnag.notify calls.+data Severity+ = Error+ | Warning+ | Info+ deriving stock (Bounded, Enum, Eq, Generic, Show)++instance FromJSON Severity where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON Severity where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++exampleSeverity :: Severity+exampleSeverity = Error
+ src/Data/Bugsnag/Types/SeverityReason.hs view
@@ -0,0 +1,82 @@+module Data.Bugsnag.Types.SeverityReason+ ( SeverityReason (..)+ , exampleSeverityReason+ , defaultSeverityReason+ )+where++import Data.Bugsnag.Types.Prelude++import Data.Bugsnag.Types.SeverityReasonAttributes+import Data.Bugsnag.Types.SeverityReasonType++-- | Information about why the severity was picked.+data SeverityReason = SeverityReason+ { type_ :: Maybe SeverityReasonType+ -- ^ A type key that represents the reason for the assigned severity.+ --+ -- - @unhandledException@- Whenever an uncaught exception is discovered+ -- (generic).+ -- - @unhandledError@ - When an error is discovered (PHP).+ -- - @log@ - Whenever a log message is sent (generic).+ -- - @signal@ - Whenever a \"fatal\" signal is discovered (iOS).+ -- - @strictMode@ - Whenever a strictMode issue is discovered (Android).+ -- - @unhandledPromiseRejection@ Whenever an unhandled promise rejection+ -- is discovered (JS\/Node JS\/React Native).+ -- - @callbackErrorIntercept@- callbackErrorIntercept (Node JS).+ -- - @errorClass@ - Whenever an exception with a particular class is+ -- automatically sent (Ruby).+ -- - @exceptionClass@ - Whenever an exception with a particular class is+ -- automatically sent (Java).+ -- - @unhandledPanic@ - When a panic is unhandled and crashes the app+ -- (Go).+ -- - @unhandledErrorMiddleware@ - Unhandled errors in ${Negroni}+ -- middleware have a default severity:error.+ -- - @unhandledExceptionMiddleware@ - Unhandled exceptions in ${Rack}+ -- middleware have a default severity:error.+ -- - @userCallbackSetSeverity@ - Whenever a callback changes a report\'s+ -- severity (generic).+ -- - @userSpecifiedSeverity@ - Whenever a severity is set through a+ -- manual notify call (generic).+ -- - @handledException@ - Whenever a handled exception is sent through+ -- (generic).+ -- - @handledError@ - Whenever a handled error is sent through (PHP).+ -- - @handledPanic@ - Whenever a panic is handled through AutoNotify or+ -- Recover (Go).+ -- - @userContextSetSeverity@ - When a user creates a context which+ -- changes the severity (Python).+ -- - @anrError@ - Whenever an ANR is detected (Android).+ -- - @appHang@ - Whenever an app hang is detected (Cocoa).+ -- - @outOfMemory@ - When an app is terminated because it used too much+ -- memory (Cocoa).+ -- - @thermalKill@ - When an app is terminated because the device is+ -- overheating (Cocoa).+ , attributes :: Maybe SeverityReasonAttributes+ , unhandledOverridden :: Maybe Bool+ -- ^ Whether the event\'s @unhandled@ flag was overridden from the+ -- notifier\'s default value.+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON SeverityReason where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON SeverityReason where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultSeverityReason :: SeverityReason+defaultSeverityReason =+ SeverityReason+ { type_ = Nothing+ , attributes = Nothing+ , unhandledOverridden = Nothing+ }++exampleSeverityReason :: SeverityReason+exampleSeverityReason =+ SeverityReason+ { type_ = Just exampleSeverityReasonType+ , attributes = Just exampleSeverityReasonAttributes+ , unhandledOverridden = Just False+ }
+ src/Data/Bugsnag/Types/SeverityReasonAttributes.hs view
@@ -0,0 +1,65 @@+module Data.Bugsnag.Types.SeverityReasonAttributes+ ( SeverityReasonAttributes (..)+ , exampleSeverityReasonAttributes+ , defaultSeverityReasonAttributes+ )+where++import Data.Bugsnag.Types.Prelude++-- | Optional attributes to provide extra information about the severity+-- reason.+data SeverityReasonAttributes = SeverityReasonAttributes+ { errorType :: Maybe Text+ -- ^ Included for @unhandledError@ severity reason. See+ -- <http://php.net/manual/en/errorfunc.constants.php PHP Error Constants>.+ , level :: Maybe Text+ -- ^ Included for @log@ severity reason.+ , signalType :: Maybe Text+ -- ^ Included for @signal@ severity reason. See+ -- <https://en.wikipedia.org/wiki/C_signal_handling Signal Codes>.+ , violationType :: Maybe Text+ -- ^ Included for @strictMode@ severity reason. See+ -- <https://developer.android.com/reference/android/os/StrictMode.html Strict Mode>.+ , errorClass :: Maybe Text+ -- ^ Included for @errorClass@ severity reason. Specifies the error class+ -- that is automatically sent.+ , framework :: Maybe Text+ -- ^ Included for middleware severity reasons, specifies the middleware that+ -- had an error.+ , exceptionClass :: Maybe Text+ -- ^ Included for @exceptionClass@ severity reason. Specifies the error class+ -- that is automatically sent.+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON SeverityReasonAttributes where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON SeverityReasonAttributes where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultSeverityReasonAttributes :: SeverityReasonAttributes+defaultSeverityReasonAttributes =+ SeverityReasonAttributes+ { errorType = Nothing+ , level = Nothing+ , signalType = Nothing+ , violationType = Nothing+ , errorClass = Nothing+ , framework = Nothing+ , exceptionClass = Nothing+ }++exampleSeverityReasonAttributes :: SeverityReasonAttributes+exampleSeverityReasonAttributes =+ SeverityReasonAttributes+ { errorType = Just "E_ERROR"+ , level = Just "Error"+ , signalType = Just "SIGSEGV"+ , violationType = Just "NetworkOnMainThread"+ , errorClass = Just "ActiveRecord::RecordNotFound"+ , framework = Just "Rack"+ , exceptionClass = Just "TypeMismatchException"+ }
+ src/Data/Bugsnag/Types/SeverityReasonType.hs view
@@ -0,0 +1,80 @@+module Data.Bugsnag.Types.SeverityReasonType+ ( SeverityReasonType (..)+ , exampleSeverityReasonType+ )+where++import Data.Bugsnag.Types.Prelude++-- | A type key that represents the reason for the assigned severity.+--+-- - @unhandledException@- Whenever an uncaught exception is discovered+-- (generic).+-- - @unhandledError@ - When an error is discovered (PHP).+-- - @log@ - Whenever a log message is sent (generic).+-- - @signal@ - Whenever a \"fatal\" signal is discovered (iOS).+-- - @strictMode@ - Whenever a strictMode issue is discovered (Android).+-- - @unhandledPromiseRejection@ Whenever an unhandled promise rejection+-- is discovered (JS\/Node JS\/React Native).+-- - @callbackErrorIntercept@- callbackErrorIntercept (Node JS).+-- - @errorClass@ - Whenever an exception with a particular class is+-- automatically sent (Ruby).+-- - @exceptionClass@ - Whenever an exception with a particular class is+-- automatically sent (Java).+-- - @unhandledPanic@ - When a panic is unhandled and crashes the app+-- (Go).+-- - @unhandledErrorMiddleware@ - Unhandled errors in ${Negroni}+-- middleware have a default severity:error.+-- - @unhandledExceptionMiddleware@ - Unhandled exceptions in ${Rack}+-- middleware have a default severity:error.+-- - @userCallbackSetSeverity@ - Whenever a callback changes a report\'s+-- severity (generic).+-- - @userSpecifiedSeverity@ - Whenever a severity is set through a+-- manual notify call (generic).+-- - @handledException@ - Whenever a handled exception is sent through+-- (generic).+-- - @handledError@ - Whenever a handled error is sent through (PHP).+-- - @handledPanic@ - Whenever a panic is handled through AutoNotify or+-- Recover (Go).+-- - @userContextSetSeverity@ - When a user creates a context which+-- changes the severity (Python).+-- - @anrError@ - Whenever an ANR is detected (Android).+-- - @appHang@ - Whenever an app hang is detected (Cocoa).+-- - @outOfMemory@ - When an app is terminated because it used too much+-- memory (Cocoa).+-- - @thermalKill@ - When an app is terminated because the device is+-- overheating (Cocoa).+data SeverityReasonType+ = UnhandledException+ | UnhandledError+ | Log+ | Signal+ | StrictMode+ | UnhandledPromiseRejection+ | CallbackErrorIntercept+ | ErrorClass+ | ExceptionClass+ | UnhandledPanic+ | UnhandledErrorMiddleware+ | UnhandledExceptionMiddleware+ | UserCallbackSetSeverity+ | UserSpecifiedSeverity+ | HandledException+ | HandledError+ | HandledPanic+ | UserContextSetSeverity+ | AnrError+ | AppHang+ | OutOfMemory+ | ThermalKill+ deriving stock (Bounded, Enum, Eq, Generic, Show)++instance FromJSON SeverityReasonType where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON SeverityReasonType where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++exampleSeverityReasonType :: SeverityReasonType+exampleSeverityReasonType = UnhandledException
+ src/Data/Bugsnag/Types/Stackframe.hs view
@@ -0,0 +1,108 @@+module Data.Bugsnag.Types.Stackframe+ ( Stackframe (..)+ , exampleStackframe+ , defaultStackframe+ )+where++import Data.Bugsnag.Types.Prelude++data Stackframe = Stackframe+ { file :: Text+ -- ^ The file that this stack frame was executing. It is recommended that you+ -- strip any unnecessary or common information from the beginning of the+ -- path.+ , lineNumber :: Int+ -- ^ The line of the file that this frame of the stack was in.+ , columnNumber :: Maybe Int+ -- ^ The column of the file that this frame of the stack was in.+ , method :: Text+ -- ^ The method that this particular stack frame is within.+ , inProject :: Maybe Bool+ -- ^ If this stacktrace line is in the user\'s project code, set this to+ -- true. It is useful for developers to be able to see which lines of a+ -- stacktrace are within their own application, and which are within third+ -- party libraries. This information is shown in the stacktrace on the+ -- dashboard and is used to help group errors better.+ , code :: Maybe (KeyMap Text)+ , frameAddress :: Maybe Text+ -- ^ The run time memory address of the instruction being executed (for the+ -- first stack frame) or to which control will return after the function+ -- call or subroutine completes.+ , loadAddress :: Maybe Text+ -- ^ The address in memory where the binary has been loaded at run time.+ , isLR :: Maybe Bool+ -- ^ True if @frameAddress@ corresponds to value of the Link Register. This+ -- is sometimes the case for the second frame in a stack - e.g. for signals+ -- and mach exceptions.+ , isPC :: Maybe Bool+ -- ^ True if @frameAddress@ corresponds to the Program Counter.+ , symbolAddress :: Maybe Text+ -- ^ The run time memory address of the symbol that most closely matches+ -- @frameAddress@.+ , machoFile :: Maybe Text+ -- ^ The full path of the Mach-O binary (iOS\/macOS\/tvOS only).+ , machoLoadAddress :: Maybe Text+ -- ^ The address in memory where the Mach-O binary has been loaded at run+ -- time. This may differ from @machoVMAddress@ due to Address Space Layout+ -- Randomization. The difference between @machoLoadAddress@ and+ -- @machoVMAddress@ is known as the \"slide\" (iOS\/macOS\/tvOS only).+ , machoUUID :: Maybe Text+ -- ^ A UUID which uniquely identifies this Mach-O binary (iOS\/macOS\/tvOS+ -- only).+ , machoVMAddress :: Maybe Text+ -- ^ The memory address assigned to the Mach-O binary by the linker at build+ -- time (iOS\/macOS\/tvOS only).+ , codeIdentifier :: Maybe Text+ -- ^ The ID of the executable\/library that the frame relates to.+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON Stackframe where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON Stackframe where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultStackframe :: Text -> Int -> Text -> Stackframe+defaultStackframe file lineNumber method =+ Stackframe+ { file+ , lineNumber+ , method+ , columnNumber = Nothing+ , inProject = Nothing+ , code = Nothing+ , frameAddress = Nothing+ , loadAddress = Nothing+ , isLR = Nothing+ , isPC = Nothing+ , symbolAddress = Nothing+ , machoFile = Nothing+ , machoLoadAddress = Nothing+ , machoUUID = Nothing+ , machoVMAddress = Nothing+ , codeIdentifier = Nothing+ }++exampleStackframe :: Stackframe+exampleStackframe =+ Stackframe+ { file = "controllers/auth/session_controller.rb"+ , lineNumber = 1234+ , columnNumber = Just 123+ , method = "create"+ , inProject = Just True+ , code = Nothing+ , frameAddress = Just "0x000000010d131040"+ , loadAddress = Just "0x000000010d12e000"+ , isLR = Nothing+ , isPC = Just True+ , symbolAddress = Just "0x000000010d130fe6"+ , machoFile = Just "/System/Library/Frameworks/Foundation.framework/Foundation"+ , machoLoadAddress = Just "0x000000010d12e000"+ , machoUUID = Just "B3196052-BAF1-3EA5-AD28-F9E6ECCF0B03"+ , machoVMAddress = Just "0x0000000100000000"+ , codeIdentifier = Just "b6b529d5e58421a0fba0fa2c5c2c5f3e"+ }
+ src/Data/Bugsnag/Types/Thread.hs view
@@ -0,0 +1,57 @@+module Data.Bugsnag.Types.Thread+ ( Thread (..)+ , exampleThread+ , defaultThread+ )+where++import Data.Bugsnag.Types.Prelude++import Data.Bugsnag.Types.ErrorType+import Data.Bugsnag.Types.Stackframe++data Thread = Thread+ { id :: Maybe Text+ -- ^ The id of the thread in your application.+ , name :: Maybe Text+ -- ^ A human readable name for the thread.+ , errorReportingThread :: Maybe Bool+ -- ^ If this is the thread that the error was reported from (either an+ -- unhandled error or a call to bugsnag.notify), set this to true.+ , stacktrace :: Maybe [Stackframe]+ -- ^ An array of stacktrace objects. Each object represents one line in the+ -- stacktrace of the thread at the point that the error occurred.+ , state :: Maybe Text+ -- ^ The state of the thread at the time of the error.+ , type_ :: Maybe ErrorType+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON Thread where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON Thread where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultThread :: Thread+defaultThread =+ Thread+ { id = Nothing+ , name = Nothing+ , errorReportingThread = Nothing+ , stacktrace = Nothing+ , state = Nothing+ , type_ = Nothing+ }++exampleThread :: Thread+exampleThread =+ Thread+ { id = Just "thread_id"+ , name = Just "thread_name"+ , errorReportingThread = Just True+ , stacktrace = Just [exampleStackframe]+ , state = Just "WAITING"+ , type_ = Just exampleErrorType+ }
+ src/Data/Bugsnag/Types/User.hs view
@@ -0,0 +1,46 @@+module Data.Bugsnag.Types.User+ ( User (..)+ , exampleUser+ , defaultUser+ )+where++import Data.Bugsnag.Types.Prelude++-- | Information about the user affected by the error. These fields are+-- optional but highly recommended. To display custom user data alongside+-- these standard fields on the dashboard, the custom data should be+-- included in the @metaData@ object in a @user@ object.+data User = User+ { id :: Maybe Text+ -- ^ A unique identifier for a user affected by this event. This could be any+ -- distinct identifier that makes sense for your application\/platform.+ , name :: Maybe Text+ -- ^ The user\'s name, or a string you use to identify them.+ , email :: Maybe Text+ -- ^ The user\'s email address.+ }+ deriving stock (Eq, Generic, Show)++instance FromJSON User where+ parseJSON = genericParseJSON aesonOptions++instance ToJSON User where+ toJSON = genericToJSON aesonOptions+ toEncoding = genericToEncoding aesonOptions++defaultUser :: User+defaultUser =+ User+ { id = Nothing+ , name = Nothing+ , email = Nothing+ }++exampleUser :: User+exampleUser =+ User+ { id = Just "19"+ , name = Just "Robert Hawkins"+ , email = Just "bob@example.com"+ }
+ test/Data/Bugsnag/Types/PayloadSpec.hs view
@@ -0,0 +1,179 @@+module Data.Bugsnag.Types.PayloadSpec+ ( spec+ )+where++import Data.Bugsnag.Types.Prelude++import Data.Aeson+import Data.Bugsnag.Types.Payload+import Test.Hspec++spec :: Spec+spec = do+ describe "ToJSON" $ do+ it "renders" $ do+ encode examplePayload+ `shouldBe` mconcat+ [ "{\"apiKey\":\"YOUR-NOTIFIER-API-KEY\""+ , ",\"payloadVersion\":\"5\""+ , ",\"notifier\":{\"name\":\"Bugsnag Ruby\""+ , ",\"version\":\"1.0.11\""+ , ",\"url\":\"https://github.com/bugsnag/bugsnag-ruby\""+ , ",\"dependencies\":[{\"name\":\"Bugsnag Android\""+ , ",\"version\":\"2.1.10\""+ , ",\"url\":\"https://github.com/bugsnag/bugsnag-android\"}]}"+ , ",\"events\":[{\"exceptions\":[{\"errorClass\":\"NoMethodError\""+ , ",\"message\":\"Unable to connect to database\""+ , ",\"stacktrace\":[{\"file\":\"controllers/auth/session_controller.rb\""+ , ",\"lineNumber\":1234"+ , ",\"columnNumber\":123"+ , ",\"method\":\"create\""+ , ",\"inProject\":true"+ , ",\"frameAddress\":\"0x000000010d131040\""+ , ",\"loadAddress\":\"0x000000010d12e000\""+ , ",\"isPC\":true"+ , ",\"symbolAddress\":\"0x000000010d130fe6\""+ , ",\"machoFile\":\"/System/Library/Frameworks/Foundation.framework/Foundation\""+ , ",\"machoLoadAddress\":\"0x000000010d12e000\""+ , ",\"machoUUID\":\"B3196052-BAF1-3EA5-AD28-F9E6ECCF0B03\""+ , ",\"machoVMAddress\":\"0x0000000100000000\""+ , ",\"codeIdentifier\":\"b6b529d5e58421a0fba0fa2c5c2c5f3e\"}]"+ , ",\"type\":\"android\"}]"+ , ",\"breadcrumbs\":[{\"timestamp\":\"2016-07-19T12:17:27-0700\""+ , ",\"name\":\"Open menu\""+ , ",\"type\":\"navigation\"}]"+ , ",\"request\":{\"clientIp\":\"192.168.44.0\""+ , ",\"httpMethod\":\"PUT\""+ , ",\"url\":\"http://example.com/users/19/settings\""+ , ",\"referer\":\"http://example.com?q=awesome\"}"+ , ",\"threads\":[{\"id\":\"thread_id\""+ , ",\"name\":\"thread_name\""+ , ",\"errorReportingThread\":true"+ , ",\"stacktrace\":[{\"file\":\"controllers/auth/session_controller.rb\""+ , ",\"lineNumber\":1234"+ , ",\"columnNumber\":123"+ , ",\"method\":\"create\""+ , ",\"inProject\":true"+ , ",\"frameAddress\":\"0x000000010d131040\""+ , ",\"loadAddress\":\"0x000000010d12e000\""+ , ",\"isPC\":true"+ , ",\"symbolAddress\":\"0x000000010d130fe6\""+ , ",\"machoFile\":\"/System/Library/Frameworks/Foundation.framework/Foundation\""+ , ",\"machoLoadAddress\":\"0x000000010d12e000\""+ , ",\"machoUUID\":\"B3196052-BAF1-3EA5-AD28-F9E6ECCF0B03\""+ , ",\"machoVMAddress\":\"0x0000000100000000\""+ , ",\"codeIdentifier\":\"b6b529d5e58421a0fba0fa2c5c2c5f3e\"}]"+ , ",\"state\":\"WAITING\""+ , ",\"type\":\"android\"}]"+ , ",\"context\":\"auth/session#create\""+ , ",\"groupingHash\":\"buggy_file.rb\""+ , ",\"unhandled\":true"+ , ",\"severity\":\"error\""+ , ",\"severityReason\":{\"type\":\"unhandledexception\""+ , ",\"attributes\":{\"errorType\":\"E_ERROR\""+ , ",\"level\":\"Error\""+ , ",\"signalType\":\"SIGSEGV\""+ , ",\"violationType\":\"NetworkOnMainThread\""+ , ",\"errorClass\":\"ActiveRecord::RecordNotFound\""+ , ",\"framework\":\"Rack\""+ , ",\"exceptionClass\":\"TypeMismatchException\"}"+ , ",\"unhandledOverridden\":false}"+ , ",\"projectPackages\":[\"com.example.package1\""+ , ",\"com.example.package2\"]"+ , ",\"user\":{\"id\":\"19\""+ , ",\"name\":\"Robert Hawkins\""+ , ",\"email\":\"bob@example.com\"}"+ , ",\"app\":{\"id\":\"com.bugsnag.android.example.debug\""+ , ",\"version\":\"1.1.3\""+ , ",\"versionCode\":12"+ , ",\"bundleVersion\":\"1.0.2\""+ , ",\"codeBundleId\":\"1.0-1234\""+ , ",\"buildUUID\":\"BE5BA3D0-971C-4418-9ECF-E2D1ABCB66BE\""+ , ",\"releaseStage\":\"staging\""+ , ",\"type\":\"rails\""+ , ",\"dsymUUIDs\":[\"e6173678256785afd940392abee\"]"+ , ",\"duration\":1275"+ , ",\"durationInForeground\":983"+ , ",\"inForeground\":true"+ , ",\"isLaunching\":true"+ , ",\"binaryArch\":\"x86\""+ , ",\"runningOnRosetta\":true}"+ , ",\"device\":{\"hostname\":\"web1.internal\""+ , ",\"id\":\"fd124e87760c4281aef\""+ , ",\"manufacturer\":\"LGE\""+ , ",\"model\":\"Nexus 6P\""+ , ",\"modelNumber\":\"600\""+ , ",\"osName\":\"android\""+ , ",\"osVersion\":\"8.0.1\""+ , ",\"freeMemory\":183879616"+ , ",\"totalMemory\":201326592"+ , ",\"freeDisk\":13478064128"+ , ",\"browserName\":\"Chrome\""+ , ",\"browserVersion\":\"61.0.3163.100\""+ , ",\"orientation\":\"portrait\""+ , ",\"time\":\"2018-08-07T10:16:34.564Z\""+ , ",\"cpuAbi\":[\"x86_64\"]"+ , ",\"runtimeVersions\":{\"androidApiLevel\":\"28\""+ , ",\"bottle\":\"0.12.8\""+ , ",\"celery\":\"4.2.0\""+ , ",\"clangVersion\":\"7.0.1\""+ , ",\"cocos2dx\":\"3.17.2\""+ , ",\"delayedJob\":\"4.1.8\""+ , ",\"django\":\"2.1.7\""+ , ",\"dotnet\":\".NET Framework 4.7.3416.0\""+ , ",\"dotnetApiCompatibility\":\".NET 2.0 Subset\""+ , ",\"dotnetClr\":\"4.0.30319.17379\""+ , ",\"dotnetScriptingRuntime\":\".NET 3.5 equivalent\""+ , ",\"electron\":\"11.4.3\""+ , ",\"eventMachine\":\"1.2.7\""+ , ",\"expoApp\":\"2.10.0.105125\""+ , ",\"expoSdk\":\"32.0.0\""+ , ",\"flask\":\"1.0.2\""+ , ",\"gin\":\"1.3.0\""+ , ",\"go\":\"1.11.2\""+ , ",\"javaType\":\"Java(TM) SE Runtime Environment\""+ , ",\"javaVersion\":\"1.8.0_131-b11\""+ , ",\"jruby\":\"9.2.5.0\""+ , ",\"laravel\":\"5.7.22\""+ , ",\"lumen\":\"5.7\""+ , ",\"magento\":\"2.3.0\""+ , ",\"mailman\":\"0.8.0\""+ , ",\"martini\":\"1.0\""+ , ",\"negroni\":\"1.0.0\""+ , ",\"node\":\"10.14.1\""+ , ",\"osBuild\":\"16D57\""+ , ",\"php\":\"7.2.12\""+ , ",\"python\":\"3.7.1\""+ , ",\"que\":\"0.14.3\""+ , ",\"rack\":\"2.0.6\""+ , ",\"rails\":\"5.2.2\""+ , ",\"rake\":\"12.3.2\""+ , ",\"reactNative\":\"0.57.5\""+ , ",\"reactNativeJsEngine\":\"hermes\""+ , ",\"resque\":\"2.0.0\""+ , ",\"revel\":\"0.21.0\""+ , ",\"ruby\":\"2.5.3\""+ , ",\"shoryoken\":\"5.0.1\""+ , ",\"sidekiq\":\"5.1.3\""+ , ",\"silex\":\"2.1.0\""+ , ",\"sinatra\":\"2.0.3\""+ , ",\"springBoot\":\"1.5.13.RELEASE\""+ , ",\"springFramework\":\"4.2.13.RELEASE\""+ , ",\"swift\":\"4.2\""+ , ",\"symfony\":\"4.2.11\""+ , ",\"tornado\":\"5.1.1\""+ , ",\"unity\":\"2018.2.17\""+ , ",\"unityScriptingBackend\":\"Mono\""+ , ",\"wordpress\":\"5.1\"}"+ , ",\"macCatalystiOSVersion\":\"14.0\"}"+ , ",\"session\":{\"id\":\"9f65c975-8155-456f-91e5-c4c4b3db0555\""+ , ",\"startedAt\":\"2017-01-01T14:30:00.000Z\""+ , ",\"events\":{\"handled\":1"+ , ",\"unhandled\":1}}"+ , ",\"featureFlags\":[{\"featureFlag\":\"share_ios_photo_sharing_button\""+ , ",\"variant\":\"blue_button\"}]}]}"+ ]++ it "round-trips" $ do+ eitherDecode (encode examplePayload) `shouldBe` Right examplePayload
+ test/Spec.hs view
@@ -0,0 +1,2 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}+{-# OPTIONS_GHC -Wno-missing-export-lists #-}