├── .eslintignore ├── .eslintrc.js ├── .github ├── FUNDING.yml ├── issue_template.md └── workflows │ └── release.yml ├── .gitignore ├── .gitmodules ├── .npmrc ├── .prettierignore ├── .prettierrc ├── .prettierrc.js ├── .travis.yml ├── .vscode ├── launch.json └── settings.json ├── .yarnrc.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── config.json ├── demo-snippets ├── package.json ├── vue │ ├── Basic.ts │ └── install.ts └── webpack.config.vue.js ├── docs ├── .nojekyll ├── assets │ ├── hierarchy.js │ ├── highlight.css │ ├── icons.js │ ├── icons.svg │ ├── main.js │ ├── navigation.js │ ├── search.js │ └── style.css ├── classes │ ├── Integrations.DebugSymbolicator.html │ ├── Integrations.DeviceContext.html │ ├── Integrations.NativescriptErrorHandlers.html │ ├── Integrations.Release.html │ ├── NativescriptClient.html │ └── NativescriptTracing.html ├── enums │ └── CLogTypes.html ├── functions │ ├── CLog.html │ ├── captureUserFeedback.html │ ├── close.html │ ├── crashedLastRun.html │ ├── flush.html │ ├── init.html │ ├── nativeCrash.html │ ├── setDist.html │ ├── setRelease.html │ └── withScope.html ├── index.html ├── interfaces │ └── NativescriptOptions.html ├── modules.html ├── modules │ └── Integrations.html └── variables │ ├── SDK_NAME.html │ ├── SDK_VERSION.html │ └── SentryTraceCategory.html ├── images └── preview.png ├── lerna.json ├── package.json ├── packages └── sentry │ ├── .npmignore │ ├── CHANGELOG.md │ ├── README.md │ ├── breadcrumb.d.ts │ ├── breadcrumb.js │ ├── integrations │ ├── debugsymbolicator.d.ts │ ├── debugsymbolicator.js │ ├── default.d.ts │ ├── devicecontext.d.ts │ ├── devicecontext.js │ ├── eventorigin.d.ts │ ├── eventorigin.js │ ├── factory.d.ts │ ├── factory.js │ ├── index.d.ts │ ├── index.js │ ├── nativescripterrorhandlers.d.ts │ ├── nativescripterrorhandlers.js │ ├── release.d.ts │ ├── release.js │ ├── rewriteframe.d.ts │ ├── rewriteframe.js │ ├── screenshot.d.ts │ ├── screenshot.js │ ├── sdkinfo.d.ts │ └── sdkinfo.js │ ├── package.json │ ├── platforms │ ├── android │ │ ├── AndroidManifest.xml │ │ ├── buildscript.gradle │ │ ├── include.gradle │ │ └── native-api-usage.json │ └── ios │ │ ├── Podfile │ │ └── src │ │ ├── Info.plist │ │ ├── NSSentry.h │ │ ├── NSSentry.m │ │ └── module.modulemap │ ├── scope.d.ts │ ├── scope.js │ ├── tracing │ ├── addTracingExtensions.d.ts │ ├── addTracingExtensions.js │ ├── index.d.ts │ ├── index.js │ ├── nativeframes.d.ts │ ├── nativeframes.js │ ├── nstracing.d.ts │ ├── nstracing.js │ ├── ops.d.ts │ ├── ops.js │ ├── routingInstrumentation.d.ts │ ├── routingInstrumentation.js │ ├── stalltracking.d.ts │ ├── stalltracking.js │ ├── transaction.d.ts │ ├── transaction.js │ ├── types.d.ts │ ├── types.js │ ├── utils.d.ts │ └── utils.js │ ├── transports │ ├── TextEncoder.d.ts │ ├── TextEncoder.js │ ├── native.d.ts │ └── native.js │ ├── tsconfig.json │ ├── utils │ ├── environment.d.ts │ ├── environment.js │ ├── outcome.d.ts │ ├── outcome.js │ ├── safe.d.ts │ └── safe.js │ ├── vendor │ ├── buffer │ │ ├── index.d.ts │ │ ├── index.js │ │ ├── utf8ToBytes.d.ts │ │ └── utf8ToBytes.js │ ├── index.d.ts │ └── index.js │ ├── version.d.ts │ ├── version.js │ ├── wrapper.android.d.ts │ └── wrapper.d.ts ├── pnpm-workspace.yaml ├── references.d.ts ├── src └── sentry │ ├── breadcrumb.ts │ ├── client.ts │ ├── index.ts │ ├── integrations │ ├── debugsymbolicator.ts │ ├── default.ts │ ├── devicecontext.ts │ ├── eventorigin.ts │ ├── factory.ts │ ├── index.ts │ ├── nativescripterrorhandlers.ts │ ├── release.ts │ ├── rewriteframe.ts │ ├── screenshot.ts │ └── sdkinfo.ts │ ├── measurements.ts │ ├── misc.ts │ ├── options.ts │ ├── process.ts │ ├── references.d.ts │ ├── scope.ts │ ├── sdk.ts │ ├── tracing │ ├── addTracingExtensions.ts │ ├── index.ts │ ├── nativeframes.ts │ ├── nstracing.ts │ ├── ops.ts │ ├── routingInstrumentation.ts │ ├── stalltracking.ts │ ├── transaction.ts │ ├── types.ts │ └── utils.ts │ ├── transports │ ├── TextEncoder.ts │ └── native.ts │ ├── typings │ ├── android.d.ts │ ├── ios.d.ts │ └── ns.ios.d.ts │ ├── utils │ ├── envelope.ts │ ├── environment.ts │ ├── normalize.ts │ ├── outcome.ts │ └── safe.ts │ ├── vendor │ ├── buffer │ │ ├── index.ts │ │ └── utf8ToBytes.ts │ └── index.ts │ ├── version.ts │ ├── wrapper.android.ts │ ├── wrapper.d.ts │ └── wrapper.ios.ts ├── svelte.config.js ├── test.mjs ├── tsconfig.json ├── tsconfig.vue3.json └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | **/node_modules/** 2 | **/platforms/** -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: './tools/.eslintrc.js' 3 | }; 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [farfromrefug] 2 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | ### Make sure to check the demo app(s) for sample usage 2 | 3 | ### Make sure to check the existing issues in this repository 4 | 5 | ### If the demo apps cannot help and there is no issue for your problem, tell us about it 6 | Please, ensure your title is less than 63 characters long and starts with a capital 7 | letter. 8 | 9 | ### Which platform(s) does your issue occur on? 10 | - iOS/Android/Both 11 | - iOS/Android versions 12 | - emulator or device. What type of device? 13 | 14 | ### Please, provide the following version numbers that your issue occurs with: 15 | 16 | - CLI: (run `tns --version` to fetch it) 17 | - Cross-platform modules: (check the 'version' attribute in the 18 | `node_modules/tns-core-modules/package.json` file in your project) 19 | - Runtime(s): (look for the `"tns-android"` and `"tns-ios"` properties in the `package.json` file of your project) 20 | - Plugin(s): (look for the version numbers in the `package.json` file of your 21 | project and paste your dependencies and devDependencies here) 22 | 23 | ### Please, tell us how to recreate the issue in as much detail as possible. 24 | Describe the steps to reproduce it. 25 | 26 | ### Is there any code involved? 27 | - provide a code example to recreate the problem 28 | - (EVEN BETTER) provide a .zip with application or refer to a repository with application where the problem is reproducible. 29 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: 'release' 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | release_type: 7 | type: choice 8 | default: auto 9 | description: What kind of version upgrade 10 | options: 11 | - auto 12 | - patch 13 | - minor 14 | - major 15 | 16 | jobs: 17 | release: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Checkout repository 21 | uses: actions/checkout@v4 22 | with: 23 | fetch-depth: "0" 24 | submodules: true 25 | 26 | - name: setup node 27 | uses: actions/setup-node@v4 28 | with: 29 | node-version: lts/* 30 | registry-url: 'https://registry.npmjs.org' 31 | 32 | 33 | - uses: oNaiPs/secrets-to-env-action@v1 34 | with: 35 | secrets: ${{ toJSON(secrets) }} 36 | 37 | 38 | - uses: oleksiyrudenko/gha-git-credentials@v2-latest 39 | with: 40 | token: '${{ secrets.GITHUB_TOKEN }}' 41 | name: Martin Guillon 42 | email: dev@akylas.fr 43 | 44 | - name: install jq 45 | run: sudo apt install jq 46 | 47 | - name: Enable CorePack 48 | run: | 49 | corepack enable 50 | yarn config get globalFolder # the yarn command will ensure the correct yarn version is downloaded and installed 51 | 52 | - name: Get yarn cache directory path 53 | id: yarn-cache-dir-path 54 | run: echo "::set-output name=dir::$(yarn config get globalFolder)" 55 | 56 | - name: Remove package.json resolutions 57 | run: echo "`jq 'delpaths([["resolutions"]])' package.json`" > package.json 58 | 59 | - uses: actions/cache@v4 60 | name: Handle node_modules Cache 61 | id: yarn-node_modules # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) 62 | with: 63 | path: node_modules 64 | key: ${{ runner.os }}-yarn-node_modules-${{ hashFiles('**/yarn.lock') }} 65 | restore-keys: | 66 | ${{ runner.os }}-node_modules- 67 | 68 | - uses: actions/cache@v4 69 | if: steps.yarn-node_modules.outputs.cache-hit != 'true' 70 | name: Handle Yarn cache 71 | id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) 72 | with: 73 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 74 | key: ${{ runner.os }}-yarn-cache-${{ hashFiles('**/yarn.lock') }} 75 | restore-keys: | 76 | ${{ runner.os }}-yarn- 77 | 78 | - name: Install deps 79 | if: steps.yarn-node_modules.outputs.cache-hit != 'true' 80 | uses: bahmutov/npm-install@v1 81 | with: 82 | install-command: yarn install --silent 83 | env: 84 | YARN_ENABLE_IMMUTABLE_INSTALLS: false 85 | 86 | - name: run setup 87 | run: | 88 | npm run setup 89 | 90 | - name: "NPM Identity" 91 | env: 92 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 93 | run: | 94 | echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > .npmrc 95 | 96 | - name: publish auto 97 | if: github.event.inputs.release_type == 'auto' 98 | run: | 99 | npm run publish -- --force-publish --no-verify-access --no-private --no-commit-hooks --yes 100 | env: 101 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 102 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 103 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 104 | 105 | - name: publish 106 | if: github.event.inputs.release_type != 'auto' 107 | run: | 108 | npm run publish -- --force-publish --no-verify-access --no-private --no-commit-hooks --yes --bump ${{ github.event.inputs.release_type }} 109 | env: 110 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 111 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 112 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # NativeScript 2 | hooks/ 3 | node_modules/ 4 | platforms 5 | 6 | # NativeScript Template 7 | *.js.map 8 | !ngcc.config.js 9 | !webpack.config.js 10 | 11 | # Logs 12 | logs 13 | *.log 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | 18 | # General 19 | .DS_Store 20 | .AppleDouble 21 | .LSOverride 22 | .idea 23 | .cloud 24 | .gradle 25 | .project 26 | .yarn 27 | .cxx 28 | tmp/ 29 | 30 | !.eslintrc.js 31 | !.prettierrc.js 32 | 33 | !e2e/*.js 34 | !detox.config.js 35 | devices.js 36 | 37 | *.framework 38 | *.xcframework 39 | **/*.js.map 40 | src/**/*.js 41 | packages/**/*.js 42 | packages/**/*.d.ts 43 | bin 44 | build 45 | Pods 46 | !packages/*/platforms 47 | /packages/**/*.aar 48 | /packages/**/*.framework 49 | /packages/**/*.xcframework 50 | /demo-snippets/**/*.aar 51 | *.xcuserdatad 52 | /packages/README.md 53 | packages/**/*js.map 54 | packages/**/*js 55 | packages/angular 56 | packages/typings 57 | packages/**/angular/*.json 58 | packages/**/*.ngsummary.json 59 | packages/**/*.metadata.json 60 | 61 | .vscode/settings.json 62 | 63 | /blueprint.md -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "demo-vue"] 2 | path = demo-vue 3 | url = https://github.com/nativescript-community/plugin-seed-demo-vue.git 4 | [submodule "tools"] 5 | path = tools 6 | url = https://github.com/nativescript-community/plugin-seed-tools.git 7 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | public-hoist-pattern[]=*eslint* 3 | public-hoist-pattern[]=source-map-support 4 | public-hoist-pattern[]=ts-patch 5 | public-hoist-pattern[]=typescript 6 | public-hoist-pattern[]=cpy-cli 7 | strict-peer-dependencies=false 8 | shell-emulator=true 9 | auto-install-peers=false 10 | loglevel=error 11 | engine-strict=true 12 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules/ 3 | plugin/ 4 | docs/ 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 200, 3 | "semi": true, 4 | "tabWidth": 4, 5 | "singleQuote": true, 6 | "trailingComma": "none" 7 | } -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 200, 3 | semi: true, 4 | tabWidth: 4, 5 | trailingComma: 'none', 6 | singleQuote: true 7 | }; 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | matrix: 2 | include: 3 | - stage: "Lint" 4 | language: node_js 5 | os: linux 6 | node_js: "6" 7 | script: cd src && npm run ci.tslint && cd ../demo && npm run ci.tslint 8 | - stage: "WebPack" 9 | os: osx 10 | env: 11 | - Platform="iOS" 12 | osx_image: xcode8.3 13 | language: node_js 14 | node_js: "6" 15 | jdk: oraclejdk8 16 | script: cd demo && npm run build.plugin && npm i && npm run build-ios-bundle 17 | - language: android 18 | os: linux 19 | env: 20 | - Platform="Android" 21 | jdk: oraclejdk8 22 | before_install: nvm install 6.10.3 23 | script: cd demo && npm run build.plugin && npm i && npm run build-android-bundle 24 | - stage: "Build and Test" 25 | env: 26 | - BuildAndroid="25" 27 | language: android 28 | os: linux 29 | jdk: oraclejdk8 30 | before_install: nvm install stable 31 | script: 32 | - cd src && npm i && npm run tsc && cd ../demo && tns build android 33 | - os: osx 34 | env: 35 | - BuildiOS="10.3" 36 | - Xcode="8.3" 37 | osx_image: xcode8.3 38 | language: node_js 39 | node_js: "6" 40 | jdk: oraclejdk8 41 | script: 42 | - cd src && npm i && npm run tsc && cd ../demo && tns build ios 43 | - os: linux 44 | language: android 45 | dist: precise 46 | sudo: required 47 | jdk: oraclejdk8 48 | before_script: 49 | - echo no | android create avd --force -n test -t android-21 -b armeabi-v7a 50 | - emulator -avd test -no-audio -no-window & 51 | - android-wait-for-emulator 52 | before_install: 53 | - nvm install 6 54 | script: cd src && npm run test.android 55 | - os: osx 56 | language: node_js 57 | node_js: "6" 58 | jdk: oraclejdk8 59 | osx_image: xcode8.3 60 | script: cd src && npm run test.ios 61 | 62 | android: 63 | components: 64 | - tools 65 | - platform-tools 66 | - build-tools-25.0.2 67 | - android-25 68 | - extra-android-m2repository 69 | - sys-img-armeabi-v7a-android-21 70 | 71 | install: 72 | - echo no | npm install -g nativescript 73 | - tns usage-reporting disable 74 | - tns error-reporting disable -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch on iOS", 9 | "type": "nativescript", 10 | "request": "launch", 11 | "platform": "ios", 12 | "appRoot": "${workspaceRoot}", 13 | "sourceMaps": true, 14 | "watch": true 15 | }, 16 | { 17 | "name": "Attach on iOS", 18 | "type": "nativescript", 19 | "request": "attach", 20 | "platform": "ios", 21 | "appRoot": "${workspaceRoot}", 22 | "sourceMaps": true, 23 | "watch": false 24 | }, 25 | { 26 | "name": "Launch on Android", 27 | "type": "nativescript", 28 | "request": "launch", 29 | "platform": "android", 30 | "appRoot": "${workspaceRoot}", 31 | "sourceMaps": true, 32 | "watch": true 33 | }, 34 | { 35 | "name": "Attach on Android", 36 | "type": "nativescript", 37 | "request": "attach", 38 | "platform": "android", 39 | "appRoot": "${workspaceRoot}", 40 | "sourceMaps": true, 41 | "watch": false 42 | } 43 | ] 44 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "terminal.integrated.env.osx": { 3 | "SENTRY_DSN": "https://f749f6c54aa80fd6622f817867048b22@bugs.akylas.fr/3", 4 | "SENTRY_PREFIX": "app:///", 5 | "SOURCEMAP_REL_DIR": "../../sourcemaps", 6 | "SENTRY_URL": "https://bugs.akylas.fr", 7 | "SENTRY_PROJECT": "demoapp", 8 | "SENTRY_AUTH_TOKEN": "12b4fe0499218b528bf51c2bf148674505e3d571d47683b497ff2bdaa3d7312c", 9 | "SENTRY_ORG": "akylas" 10 | }, 11 | "terminal.integrated.env.linux": { 12 | "SENTRY_DSN": "https://f749f6c54aa80fd6622f817867048b22@bugs.akylas.fr/3", 13 | "SENTRY_PREFIX": "app:///", 14 | "SOURCEMAP_REL_DIR": "../../sourcemaps", 15 | "SENTRY_URL": "https://bugs.akylas.fr", 16 | "SENTRY_PROJECT": "demoapp", 17 | "SENTRY_AUTH_TOKEN": "12b4fe0499218b528bf51c2bf148674505e3d571d47683b497ff2bdaa3d7312c", 18 | "SENTRY_ORG": "akylas" 19 | }, 20 | } 21 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | compressionLevel: mixed 2 | 3 | nmHoistingLimits: workspaces 4 | 5 | nodeLinker: node-modules 6 | 7 | yarnPath: tools/.yarn/releases/yarn-4.0.1.cjs 8 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": true, 3 | "angular": false, 4 | "demos": [ 5 | "vue" 6 | ] 7 | } -------------------------------------------------------------------------------- /demo-snippets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nativescript-community/template-snippet", 3 | "private": true, 4 | "version": "0.0.1", 5 | "dependencies": { 6 | "@nativescript-community/sentry": "*" 7 | }, 8 | "devDependencies": { 9 | "@sentry/webpack-plugin": "2.14.2" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /demo-snippets/vue/install.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'nativescript-vue'; 2 | import * as Sentry from '@nativescript-community/sentry'; 3 | import * as Tracing from '@nativescript-community/sentry/tracing'; 4 | import { Application, NavigatedData, Page, Trace, TraceErrorHandler, Utils, View } from '@nativescript/core'; 5 | import { on as applicationOn, launchEvent } from '@nativescript/core/application'; 6 | import Basic from './Basic'; 7 | 8 | Trace.addCategories(Sentry.SentryTraceCategory); 9 | Trace.enable(); 10 | 11 | declare const SENTRY_DSN: string; 12 | declare const SENTRY_PREFIX: string; 13 | declare const __APP_ID__: string; 14 | declare const __APP_VERSION__: string; 15 | declare const __APP_BUILD_NUMBER__: string; 16 | async function startSentry() { 17 | try { 18 | Sentry.init({ 19 | dsn: SENTRY_DSN, 20 | debug: true, 21 | enablePerformanceV2: true, 22 | appPrefix: '~/', 23 | release: `${__APP_ID__}@${__APP_VERSION__}+${__APP_BUILD_NUMBER__}`, 24 | dist: `${__APP_BUILD_NUMBER__}.${__ANDROID__ ? 'android' : 'ios'}`, 25 | flushSendEvent: true, 26 | enableNativeCrashHandling: true, 27 | attachScreenshot: true, 28 | // tracesSampleRate: 1.0, 29 | // sampleRate: 1.0, 30 | enableCrashHandler: false, // iOS 31 | // enableAutoPerformanceTracking: true, 32 | // enableAutoSessionTracking: true, 33 | // integrations: [ 34 | // new Tracing.NativescriptTracing({ 35 | // enableAppStartTracking: true, 36 | // enableNativeFramesTracking: true, 37 | // // routingInstrumentation: HttpService.sentryTracing, 38 | // enableStallTracking: true 39 | // }) 40 | // ], 41 | enableUIViewControllerTracing: false, 42 | enableUserInteractionTracing: false, 43 | enableAutoBreadcrumbTracking: false 44 | }); 45 | Page.on('navigatingTo', (event: NavigatedData) => { 46 | Sentry.addBreadcrumb({ 47 | category: 'navigation', 48 | type: 'navigation', 49 | // We assume that context.name is the name of the route. 50 | message: `Navigation to ${event.object}`, 51 | data: { 52 | isBackNavigation: event.isBackNavigation, 53 | from: `${(event.object as Page).frame?.currentPage}`, 54 | to: `${event.object}` 55 | } 56 | }); 57 | }); 58 | View.on('showingModally', (event: NavigatedData) => { 59 | Sentry.addBreadcrumb({ 60 | category: 'navigation', 61 | type: 'navigation', 62 | // We assume that context.name is the name of the route. 63 | message: `Navigation to Modal ${event.object}`, 64 | data: { 65 | from: `${(event.object as View)._modalParent}`, 66 | to: `${event.object}` 67 | } 68 | }); 69 | }); 70 | View.on('closingModally', (event: NavigatedData) => { 71 | Sentry.addBreadcrumb({ 72 | category: 'navigation', 73 | type: 'navigation', 74 | // We assume that context.name is the name of the route. 75 | message: `Closing modal ${event.object}`, 76 | data: { 77 | from: `${event.object as View}` 78 | } 79 | }); 80 | }); 81 | const errorHandler: TraceErrorHandler = { 82 | handlerError(err) { 83 | Sentry.captureException(err); 84 | } 85 | }; 86 | Application.on(Application.uncaughtErrorEvent, (event) => { 87 | Sentry.captureException(event.error); 88 | }); 89 | Application.on(Application.discardedErrorEvent, (event) => { 90 | Sentry.captureException(event.error); 91 | }); 92 | Trace.setErrorHandler(errorHandler); 93 | setTimeout(() => { 94 | Sentry.withScope((scope) => { 95 | try { 96 | scope.setTag('myTag', 'tag-value'); 97 | scope.setExtra('myExtra', 'extra-value'); 98 | scope.addBreadcrumb({ message: 'test' }); 99 | Sentry.captureMessage('Hello Sentry!'); 100 | } catch (error) { 101 | console.error(error); 102 | } 103 | }); 104 | }, 1000); 105 | } catch (err) { 106 | console.error(err, err.stack); 107 | } 108 | } 109 | 110 | export function installPlugin() { 111 | if (!__ANDROID__ || Utils.android.getApplicationContext()) { 112 | startSentry(); 113 | } else { 114 | applicationOn(launchEvent, startSentry); 115 | } 116 | } 117 | 118 | export const demos = [{ name: 'Basic', path: 'Basic', component: Basic }]; 119 | -------------------------------------------------------------------------------- /demo-snippets/webpack.config.vue.js: -------------------------------------------------------------------------------- 1 | const { sentryWebpackPlugin } = require('@sentry/webpack-plugin'); 2 | const nsWebpack = require('@nativescript/webpack'); 3 | const { dirname, join, relative, resolve, sep } = require('path'); 4 | const { readdirSync, readFileSync } = require('fs'); 5 | 6 | module.exports = (env, webpack) => { 7 | const platform = env && ((env.android && 'android') || (env.ios && 'ios')); 8 | webpack.chainWebpack((config) => {}); 9 | }; 10 | 11 | module.exports.onWebpackConfig = function (config, env, params) { 12 | const platform = env && ((env.android && 'android') || (env.ios && 'ios')); 13 | const dist = nsWebpack.Utils.platform.getDistPath(); 14 | console.log('test', env, params, dist); 15 | const projectRoot = nsWebpack.Utils.project.getProjectRootPath(); 16 | const appResourcesPath = env.appResourcesPath; 17 | let appVersion; 18 | let buildNumber; 19 | if (platform === 'android') { 20 | const gradlePath = resolve(projectRoot, appResourcesPath, 'Android/app.gradle'); 21 | const gradleData = readFileSync(gradlePath, 'utf8'); 22 | appVersion = gradleData.match(/versionName "((?:[0-9]+\.?)+)"/)[1]; 23 | buildNumber = gradleData.match(/versionCode ([0-9]+)/)[1]; 24 | } else if (platform === 'ios') { 25 | const plistPath = resolve(projectRoot, appResourcesPath, 'iOS/Info.plist'); 26 | const plistData = readFileSync(plistPath, 'utf8'); 27 | appVersion = plistData.match(/CFBundleShortVersionString<\/key>[\s\n]*(.*?)<\/string>/)[1]; 28 | buildNumber = plistData.match(/CFBundleVersion<\/key>[\s\n]*([0-9]*)<\/string>/)[1]; 29 | } 30 | // nsWebpack.chainWebpack(config=>{ 31 | // config.entry('bundle').prepend('@nativescript-community/sentry/process'); 32 | // }); 33 | const definitions = config.plugins.find((p) => p.constructor.name === 'DefinePlugin').definitions; 34 | delete definitions['process']; 35 | Object.assign(definitions, { 36 | SENTRY_DSN: `"${process.env.SENTRY_DSN}"`, 37 | SENTRY_PREFIX: `"${process.env.SENTRY_PREFIX}"`, 38 | __APP_ID__: `"${env.appId}"`, 39 | __APP_VERSION__: `"${appVersion}"`, 40 | __APP_BUILD_NUMBER__: `"${buildNumber}"` 41 | }); 42 | config.resolve.symlinks = false; 43 | config.devtool = 'source-map'; 44 | config.plugins.push( 45 | sentryWebpackPlugin({ 46 | org: process.env.SENTRY_ORG, 47 | url: process.env.SENTRY_URL, 48 | project: process.env.SENTRY_PROJECT, 49 | authToken: process.env.SENTRY_AUTH_TOKEN, 50 | release: { 51 | name: `${config.id}@${appVersion}+${buildNumber}`, 52 | dist: `${buildNumber}.${platform}`, 53 | setCommits: false, 54 | create: true, 55 | cleanArtifacts: true 56 | }, 57 | sourcemaps: { 58 | rewriteSources: (source, map) => source.replace('webpack:///', '~/'), 59 | ignore: ['tns-java-classes', 'hot-update'], 60 | assets: [dist + '/**/*.js', join(dist, process.env.SOURCEMAP_REL_DIR) + '/*.map'] 61 | } 62 | }) 63 | ); 64 | return config; 65 | }; 66 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. -------------------------------------------------------------------------------- /docs/assets/hierarchy.js: -------------------------------------------------------------------------------- 1 | window.hierarchyData = "data:application/octet-stream;base64,H4sIAAAAAAAAA6tWKsrPLylWsoqO1VEqSk3LSU0uyczPK1ayqq6tBQAWeT+5HQAAAA==" -------------------------------------------------------------------------------- /docs/assets/highlight.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --light-hl-0: #AF00DB; 3 | --dark-hl-0: #C586C0; 4 | --light-hl-1: #000000; 5 | --dark-hl-1: #D4D4D4; 6 | --light-hl-2: #001080; 7 | --dark-hl-2: #9CDCFE; 8 | --light-hl-3: #0000FF; 9 | --dark-hl-3: #569CD6; 10 | --light-hl-4: #795E26; 11 | --dark-hl-4: #DCDCAA; 12 | --light-hl-5: #A31515; 13 | --dark-hl-5: #CE9178; 14 | --light-hl-6: #EE0000; 15 | --dark-hl-6: #D7BA7D; 16 | --light-hl-7: #000000FF; 17 | --dark-hl-7: #D4D4D4; 18 | --light-hl-8: #0070C1; 19 | --dark-hl-8: #4FC1FF; 20 | --light-hl-9: #811F3F; 21 | --dark-hl-9: #D16969; 22 | --light-hl-10: #D16969; 23 | --dark-hl-10: #CE9178; 24 | --light-hl-11: #000000; 25 | --dark-hl-11: #D7BA7D; 26 | --light-hl-12: #098658; 27 | --dark-hl-12: #B5CEA8; 28 | --light-hl-13: #008000; 29 | --dark-hl-13: #6A9955; 30 | --light-hl-14: #267F99; 31 | --dark-hl-14: #4EC9B0; 32 | --light-hl-15: #000000; 33 | --dark-hl-15: #C8C8C8; 34 | --light-code-background: #FFFFFF; 35 | --dark-code-background: #1E1E1E; 36 | } 37 | 38 | @media (prefers-color-scheme: light) { :root { 39 | --hl-0: var(--light-hl-0); 40 | --hl-1: var(--light-hl-1); 41 | --hl-2: var(--light-hl-2); 42 | --hl-3: var(--light-hl-3); 43 | --hl-4: var(--light-hl-4); 44 | --hl-5: var(--light-hl-5); 45 | --hl-6: var(--light-hl-6); 46 | --hl-7: var(--light-hl-7); 47 | --hl-8: var(--light-hl-8); 48 | --hl-9: var(--light-hl-9); 49 | --hl-10: var(--light-hl-10); 50 | --hl-11: var(--light-hl-11); 51 | --hl-12: var(--light-hl-12); 52 | --hl-13: var(--light-hl-13); 53 | --hl-14: var(--light-hl-14); 54 | --hl-15: var(--light-hl-15); 55 | --code-background: var(--light-code-background); 56 | } } 57 | 58 | @media (prefers-color-scheme: dark) { :root { 59 | --hl-0: var(--dark-hl-0); 60 | --hl-1: var(--dark-hl-1); 61 | --hl-2: var(--dark-hl-2); 62 | --hl-3: var(--dark-hl-3); 63 | --hl-4: var(--dark-hl-4); 64 | --hl-5: var(--dark-hl-5); 65 | --hl-6: var(--dark-hl-6); 66 | --hl-7: var(--dark-hl-7); 67 | --hl-8: var(--dark-hl-8); 68 | --hl-9: var(--dark-hl-9); 69 | --hl-10: var(--dark-hl-10); 70 | --hl-11: var(--dark-hl-11); 71 | --hl-12: var(--dark-hl-12); 72 | --hl-13: var(--dark-hl-13); 73 | --hl-14: var(--dark-hl-14); 74 | --hl-15: var(--dark-hl-15); 75 | --code-background: var(--dark-code-background); 76 | } } 77 | 78 | :root[data-theme='light'] { 79 | --hl-0: var(--light-hl-0); 80 | --hl-1: var(--light-hl-1); 81 | --hl-2: var(--light-hl-2); 82 | --hl-3: var(--light-hl-3); 83 | --hl-4: var(--light-hl-4); 84 | --hl-5: var(--light-hl-5); 85 | --hl-6: var(--light-hl-6); 86 | --hl-7: var(--light-hl-7); 87 | --hl-8: var(--light-hl-8); 88 | --hl-9: var(--light-hl-9); 89 | --hl-10: var(--light-hl-10); 90 | --hl-11: var(--light-hl-11); 91 | --hl-12: var(--light-hl-12); 92 | --hl-13: var(--light-hl-13); 93 | --hl-14: var(--light-hl-14); 94 | --hl-15: var(--light-hl-15); 95 | --code-background: var(--light-code-background); 96 | } 97 | 98 | :root[data-theme='dark'] { 99 | --hl-0: var(--dark-hl-0); 100 | --hl-1: var(--dark-hl-1); 101 | --hl-2: var(--dark-hl-2); 102 | --hl-3: var(--dark-hl-3); 103 | --hl-4: var(--dark-hl-4); 104 | --hl-5: var(--dark-hl-5); 105 | --hl-6: var(--dark-hl-6); 106 | --hl-7: var(--dark-hl-7); 107 | --hl-8: var(--dark-hl-8); 108 | --hl-9: var(--dark-hl-9); 109 | --hl-10: var(--dark-hl-10); 110 | --hl-11: var(--dark-hl-11); 111 | --hl-12: var(--dark-hl-12); 112 | --hl-13: var(--dark-hl-13); 113 | --hl-14: var(--dark-hl-14); 114 | --hl-15: var(--dark-hl-15); 115 | --code-background: var(--dark-code-background); 116 | } 117 | 118 | .hl-0 { color: var(--hl-0); } 119 | .hl-1 { color: var(--hl-1); } 120 | .hl-2 { color: var(--hl-2); } 121 | .hl-3 { color: var(--hl-3); } 122 | .hl-4 { color: var(--hl-4); } 123 | .hl-5 { color: var(--hl-5); } 124 | .hl-6 { color: var(--hl-6); } 125 | .hl-7 { color: var(--hl-7); } 126 | .hl-8 { color: var(--hl-8); } 127 | .hl-9 { color: var(--hl-9); } 128 | .hl-10 { color: var(--hl-10); } 129 | .hl-11 { color: var(--hl-11); } 130 | .hl-12 { color: var(--hl-12); } 131 | .hl-13 { color: var(--hl-13); } 132 | .hl-14 { color: var(--hl-14); } 133 | .hl-15 { color: var(--hl-15); } 134 | pre, code { background: var(--code-background); } 135 | -------------------------------------------------------------------------------- /docs/assets/navigation.js: -------------------------------------------------------------------------------- 1 | window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAA42UUU/CMBSF/0ufF4mIxOzNDIxEhATQF2JM1122hq5d2juUGP+7GZnQbaXwuJ5zvtvdnHT9QxC+kYRkIhFSTZEraUhACooZCUmuklKA6dnqTYa5IAHZcpmQcBAQlnGRaJAkXB9xI4jLdLnPYyU4o6j0ickENabN7PibU277D7+BBd9xBpGSh+9LYMvrg84o8h0YpnmBY62VfqYyEaDNhQFnc75hCxBADVxA164u6MNCRVOVrvYFWPcEWeamdxSa+XP/HAkO0rHNrufaLa40ZVymfmRtupY5L1oN5RJBbyhrYWtfE9u/H1rY5ejlc/b4Oj6xdlRzGld9/9ea+bt+K/4+Xiwn89k5Qi37ICBR76sdQEQRUqX3TljX5oEyWmCp4c2AfgJIYsq2J+imlOywmp7D1oQOB62auSjVuSfGhLJrbk2vBF9QU5NBMqUGF6V0EhoOD2ojSpO5CAfBE+SSoytXnXti8tDDqLqeK23JHogBHHHjHF9L/nDnhWnknS9LA/HFMVsyVTgJR7ED+PgDQLm8OVIGAAA=" -------------------------------------------------------------------------------- /docs/assets/search.js: -------------------------------------------------------------------------------- 1 | window.searchData = "data:application/octet-stream;base64,H4sIAAAAAAAAA8WdXZObOBaG/wu59XRaEiDou6lMspPamSSbzsxcdKVSNMhtNjZ4AXc605X/viUB5hzrYAt/7F652nBevRLPkWQB6mevKr/V3s3ds/c1LzLvRvCZVyQr5d14t6poqu+fqiRVr5JGPZTVd2/mbaqld+M9JlWe3C9V/ZI462rRrJbezEuXSV2r2rvxvB+zvoBoq//qt/Lh0/e1qreqqtis6pfb7/fqsHArtCwf9kq8aE8AMjNvnVSqaJALUjsv5uV+8e6Mo9S/JVWRFwfcDycdVYaqqrLaX0J/irt+6KPLuJWfb4q0ycuiLWLvBeTB4PFd0uSPqk6rfN28XxuBrWReNKqaJ6mqXxKn7Wfkmg8+FyrJVDVJ98UQQzcN5Rs0UhCIoY5fvjTf1+qY4reRziaueuMjbZGs1x8qNc+fJtlJ1ut1H3VMeyAL8+WmXtyqInv9qGOn+DChtSoy1YWebOa+UkmWVpvV/TQ+cNz/hRFg4QhOYAVG2iYti7pcnmhqEDnK21VXtRGLWbk6zV4rcAlrc9Wki9PM9RKXsLfI6waO60cZHEQuYbE2E4zTHG41LmHwaVGd5q4VuIQ1VehJWqsxyWMbWPSBg7emzn7K65/yYqGqvFHZkR0uNPaqSurFr0mRLeFUaKrLVKssBpWzW87yWpeWtSFvi0Y9VMnkqcqLXqZ1nWOZs5tONk35tsibPFnmf3ftfZt9nTbsb5oy32q0vmujcVEs3iUPD2paZkEeij78QiZ/3jTlrarrvCz0j5+vx7Gr27ZuVZpB5eyWa2xUw1s9Jsvf8+Uyn4bvjtm8U1r1SpdCYiKzHQkXpTT7epuWa3X7vUiP81br8LoNP3/mN02SLj4t9Fgx7RK3kc028uzWyuKjSrJpQ3pZVF3MOeycPOvu7Bwx4+4rf7Bz+aCqeVmtkiJVJ3Yw60Hpkp1MW+BfSZMusvLhk6pWeWFGthPsf+vUmkHtklVYJU+vknSh3jZqNS1pVslTqiPzLvJSo856/WtSPJwCxHq9SIqHS7Zi0pqsP+UrVW6afrSZutagbdZNq5EPGpe46P/aqI26zf+e1gmskqf/6MC6DTy7sbRcFuX7+bxW09ZHTFzZx11oZLlNK6WKelFO89YG1zD4Qgb/zNW3X3NVJVW6mDbWtPGPufq2APEXyuhXybrZVOpNki9V9lH9Z6PqZlrX0+qkrc7c6FSDzoVs367LZpk/LKZd/Ta2BrHnn+r24rd5ptKk+qOa1vFs4+s2flNdpNMpC7wu7zbpsBfqz2ZnU5gfz5qdfyuzhj/RGylwdqNrPSH4x7K8T5YfqnKV19O6bBP+YMLX2/CzmOTDjS145qtlDpe3u6Je2qfsvZERMA5GhaJuqk3aAHoOyL7AMYcnq51rcLPm2h/qZ5bd31Tl6vVTqtYIlUNGTOi8KlcKhJ7Nz++qrpMHNd3Naht4qpdiWNJytgEWsM7gIF2WtXsT9GefWqq5J+Ncan/2yXVtB70/alW9USq7T9Kv7jVvYze1quZD7KmOatVs1uTi4CE/JnJ0PfA4N1/0XbLXxaNalmt3JkyUGqKs/nFdlY1K9/SPlitwv1gvJRL3i/XXe/vAEC5nNb/kNaXSHZkg9FEtVQISBml1B13lqOQf9MBRV0GcVYOU+d5VBHcIg4j53llkT6YBSfss1wK+5c3CrKcRsttjzm51I6vst6RuPm4Kyig6Yf9DBCMju/4NDn+CU1nVneP+kEKeOeu9MOce7iF6n6fNJlDJU6cTtgVUafPhXHh39smlluvD/TMqeAg4Q431qW+qZKXqt6YtV6pokoNTqZ2G0AfmRiS3RE72WDfJcjncMTjSpFEZ7hac3eWm1mtit01SNX/lzeJDVc7zpZrA8qbWS2K1FtDdzHoQOMabPRd4X6QT4DYhZRtycvlm5bWoE9PnmSaaALteZ+1j6y72vI7e5EV+YM44bmneB5/BUw/QdEM9OedzY+T0+GlWTdu6gjablHhVoye3+SDUIKFjvA6JR85xV2W20Q+FwoPOg+sv6n7zcPt9dV8u8zShBiQka51OFATqhfy6j74ORe4biPeHHzEmu/hxGZ6djR0eqV0s7R20nb049q4uhg53tO4thBh+zFP1qiwa9WT3tjuS4NT/Bbu7xU3gFlbqZGYtH0fwShuazKplZQqntIfjGLWMTOZzpEVGfry81gvJ5pkr+Eg0aW407PLM7i/amd/xip/I8gF/k7l2MTqR8QMW3Xl38XYM+wcMTsyDyS3YPzH4JmnAHepjnPZK807pXG5BBu+uVZE2x9eszpydsCDnXOyrcGLmobIn55ltYmJWoeLdc8gu95iMQYVPzA/bAXzh65d/fnn38++vqbe8ukN7J/M7Un++/nj79v27EbXuKCX4eeblRaaevJtn71FV+nlD78bjV+Iq9mbePFfLTL+y1l+nVN+/MffYsjI1qwve5+60P5WGQp/cnv3y2pvdXc98fiWi+PPn2V0fbA6YL3qN4RsTyLzZHaMCmRXIUCD3ZnecCuRWIEeBwpvdCSpQWIECBfre7M6nAn0r0EeBgTe7C6jAwAoMUGDoze5CKjC0AkMUKL3ZnaQCpRUoUWDkze4iKjCyAiMUGHuzu3gmxFXMQhQYW4ExBkDzwEh2mA0P26HH4EPzQwCECWKaC0YyxGyIGKaIibEKM5sjhkFiGg9GMshslhiGiWlEGMkhs3liGCimMWEki8xmimGomEaFkTwymyuGwWIaF0YyyWy2GIaLaWQYySWz+WIYMG4Ai8muwgaMY8C4RoaTdHIbML7TRZk+iqSTE70UBoxrZjjdw9mEcUwY18xwkjBuE8YxYVwzw0nCuE0Yx4RxzQwnCeM2YRwTxjUznCSM24RxTBjXzHCSMG4TxjFhXDPDScK4TRjHhAnNDCcJEzZhAhMm2FhHImzABAZMaGQESaewARM746AZCEk6BTEUYsCERkaQdAobMIEBExoZQY/BNmACAyY0MoKkU9iACQyY0MgIkk5hAyYwYEIjI0g6hQ2YwIAJjYwg6RQ2YAID5mtkBEmnbwPmY8B8zYwg6fRtwnxMmK+Z8UnCfJswHxPma2Z8kjDfJszfmW2Z6RZJmE9MuDBhvmbGJwnzbcJ8TJivmfHpmZ5NmI8J8zUzPkmYbxPmY8J8zYwfzri8khx3Br5NmI8J8zUzPkmYbxPmY8ICzYxPEhbYhAWYsEAz48czIa94xHCwTViACQs0M8E1GWwTFmDCAs1MwMhgm7AAExZoZgJOBtuEBTtzejOpJwkLiGk9JizQzAQkYYFNWIAJCzQzAf17wiYswIQFmpmA7MMCm7AAExZoZgKSsMAmLMCEhdejkIQ2YSEmLGSj1zm0CQsxYeE4YaFNWIgJC8UoJKFNWIgJCw1hZFaFNmEhJiw0hJH9dmgTFu78cjQ/Hcl+OyR+PGLCQs1MyGY8vhIx7oZCm7AQExaO92GhTViICQs1MyEnS7YJCzFhUjMTkikpbcIkJkxqZkIyJaVNmMSESc1MSKaktAmTmDCpmQnJlJQ2YRITJjUzoaQaTNqESUyY1MyEJJ7SJkxiwqQhjMRT2oTJnfUJs0BB4imJJQpMmNTMSHJaIW3CJCZMamYkOa2QNmESExZpZiRJWGQTFmHCIjaaVZFNWIQJi/hoVkU2YREmLBKjWRXZhEWYsGicsMgmLMKERZoZSWZVZBMWYcKicLzBbMIiTFgkxxvMJizaWQWLxhuMWAjDhEXxeIPZhEWYsNgQRvYksU1YjAmLxwmLbcJiTFg8TlhsExZjwuJxwmKbsBgTFo8TFtuExZiw2BBG9p6xTViMCYs1M5Kc0MQ2YTEmLB4fJWObsBgTFo+PkrFNWLyz1jo+SsbEcuvueuv1aHO3x3A4+K6L19xIejHumlh0vd5Zdb3W6Ehy4GiP7ca335mbF4+qalT2tr2JcXe3fcP82fvS3dmI+1slz17s3Tz/mHlMtJ+C6c8fw30N8+321oY+pgveeUh/UA78QToInbRGX7YdVAVQFc6q/XZhgw67HnTYtZuO9coosCWBrXiC3HZ7g0FruNH67PEpWjtvigJ3QNF3rOzYZivAJwc+hZPqPdynDFwMoMS4kxL51gyADygGfqsRunlMzS6Ng1Q4KLnxpgWadj9JUEVQQ1eVGucTIDbgXZUcGwu+iA2wAFUTkaNSt38aqJkAVfOdVbY3ygclH/jxo66G3WfU1TiS7Wfc/R07+m7fs1gmutwCNSvoAcPASSzTD+HV6AHRQU+C5ojcci0zD02l/cN6QAt0dpGjtz3bOoHUBThyN4bM1nTgqgNrzM3ayL4PgEfQdGKS5tjmIkAbZI9wq/GenZFAS4J24FM8j7wnDxwDMH23PgPvlgYuFpDibkzu2dIMVB40Kp9usd8aCwgCArhbXwJ2WAI6oCfhcpoO2A0JCILxnbt1OdYeA6CjA+3mT4Fx7zY0AB2Q3sJt1Ove6Af9Ihht3BSIV6pBlUED+m6TGvutaCAHZjSBG9Hd9pUgK0AVmdvQ3r0HCVoJtHTQTZxDt0zY3T0WGIOTBTexnYf+wBACMiF2u5DbzYYHFdDabvBvt+IEtQJOmFtO6of5wEQMNEvYTQMi1n2G3XSg+zt2LMDsmQ0SB+SNo0COLl0A08bVAz1GSzCFlW4ZszNzhfNzp/idzaNAuwAp4dYv402JgBRoIeHWQuZ0CAJwE3a/WqMu+aJuvhh3f8duLYe2PgDdDBg4gw6t0K272ftWJKgLmD9It1wvwNO6abetB7AM2td3bd9B0IwDi+0D+QBHoBtPaYJWd/vSKlAENZ+s1/RvPYOmBKNq6Naf22/OAXtATroZ3G6MAy4HYNV3y5ztFoMgkwGHwq3xybcUQWMBRenaWParmEAQjBHSbaCh9+oBbQe6Y99R0sYsBCrSre2o3XmALZCyvlvTVf0D8wAvgH/splJnX7/s9oUSNLteOnTV6Z9nhlIxlHIbMfoNrcEwD+rF3CYLrYjOaJVu/8HHoAjy0O3yHdgbFqQV6NO44zVQTWa2/ABjPpjYBK41bggkAtB0gdu4RWzWAvQA+YFb/oDH+EEGwZ66W0yL+s9u/I27v/Xyt1NB1PZmIMfAXM93m4rtf8Mf1AZcdOlI+aF3mEESAePSDYbRN/+BZ4CYdGuO7X9rAY0K2tRNI28Wdbq7rg96nNBNx2wsD7oI2Gc5cP555q3ztVrmhfJu7j7/+PFfq6a8Ni5oAAA="; -------------------------------------------------------------------------------- /docs/functions/close.html: -------------------------------------------------------------------------------- 1 | close | @nativescript-community/sentry
  • Closes the SDK, stops sending events.

    2 |

    Returns Promise<void>

3 | -------------------------------------------------------------------------------- /docs/functions/nativeCrash.html: -------------------------------------------------------------------------------- 1 | nativeCrash | @nativescript-community/sentry
  • If native client is available it will trigger a native crash. 2 | Use this only for testing purposes.

    3 |

    Returns void

4 | -------------------------------------------------------------------------------- /docs/functions/setDist.html: -------------------------------------------------------------------------------- 1 | setDist | @nativescript-community/sentry
  • Sets the dist on the event.

    2 |

    Parameters

    • dist: string

    Returns void

3 | -------------------------------------------------------------------------------- /docs/functions/setRelease.html: -------------------------------------------------------------------------------- 1 | setRelease | @nativescript-community/sentry
  • Sets the release on the event.

    2 |

    Parameters

    • release: string

    Returns void

3 | -------------------------------------------------------------------------------- /docs/variables/SDK_NAME.html: -------------------------------------------------------------------------------- 1 | SDK_NAME | @nativescript-community/sentry
SDK_NAME: "sentry.nativescript"
2 | -------------------------------------------------------------------------------- /docs/variables/SDK_VERSION.html: -------------------------------------------------------------------------------- 1 | SDK_VERSION | @nativescript-community/sentry
SDK_VERSION: any
2 | -------------------------------------------------------------------------------- /docs/variables/SentryTraceCategory.html: -------------------------------------------------------------------------------- 1 | SentryTraceCategory | @nativescript-community/sentry

Variable SentryTraceCategoryConst

SentryTraceCategory: "Sentry"
2 | -------------------------------------------------------------------------------- /images/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/sentry/4919940f8eae59341140b897999862de282c0934/images/preview.png -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "4.6.40", 3 | "$schema": "node_modules/@lerna-lite/cli/schemas/lerna-schema.json", 4 | "packages": [ 5 | "packages/*" 6 | ], 7 | "npmClient": "yarn", 8 | "useWorkspaces": true, 9 | "command": { 10 | "publish": { 11 | "cleanupTempFiles": true 12 | } 13 | }, 14 | "npmClientArgs": [ 15 | "--no-package-lock" 16 | ], 17 | "commitHooks": false, 18 | "createRelease": "github", 19 | "conventionalCommits": true, 20 | "private": false, 21 | "message": "chore(release): publish new version %v", 22 | "changelogPreset": "conventional-changelog-conventionalcommits", 23 | "ignoreChanges": [ 24 | "**/__fixtures__/**", 25 | "**/__tests__/**", 26 | "**/*.md" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0", 3 | "scripts": { 4 | "build": "lerna run build", 5 | "build.watch": "lerna run build.watch", 6 | "build.all": "npm run build", 7 | "build.all.win": "lerna run build.all.win", 8 | "clean": "rimraf 'packages/**/*.d.ts' 'packages/**/*.js' 'packages/**/*.js.map' 'packages/**/*.metada' 'packages/**/angular/ng-package.json'", 9 | "commit_readme_doc_changes": "git add docs/** *.md ; git commit -m \"readme/doc\" ; echo \"commit readme doc done\"", 10 | "commitmsg": "commitlint -e $GIT_PARAMS", 11 | "demo.ng.android.dev": "cd ./demo-ng && ns run android --no-hmr --env.development", 12 | "demo.ng.ios.dev": "cd ./demo-ng && ns run ios --no-hmr --env.development", 13 | "demo.react.android.dev": "npm run build && cd ./demo-react && ns run android --no-hmr --env.development", 14 | "demo.react.ios.dev": "npm run build && cd ./demo-react && ns run ios --no-hmr --env.development", 15 | "demo.setup": "node ./tools/setup-demos.js", 16 | "demo.svelte.android.dev": "npm run build && cd ./demo-svelte && ns run android --no-hmr --env.development", 17 | "demo.svelte.ios.dev": "npm run build && cd ./demo-svelte && ns run ios --no-hmr --env.development", 18 | "demo.vue.android": "cd ./demo-vue && ns run android --no-hmr --env.watchNodeModules", 19 | "demo.vue.android.dev": "npm run build && cd ./demo-vue && ns run android --no-hmr --env.development", 20 | "demo.vue.clean": "cd ./demo-vue && ns clean", 21 | "demo.vue.ios": "cd ./demo-vue && ns run ios --no-hmr --env.watchNodeModules", 22 | "demo.vue.ios.dev": "npm run build && cd ./demo-vue && ns run ios --no-hmr --env.development", 23 | "doc": "node tools/builddoc.mjs", 24 | "fullclean": "npm run clean && rimraf 'packages/**/node_modules' 'demo-*/hooks' 'demo-*/node_modules' 'package-lock.json' 'pnpm-lock.yaml' 'node_modules'", 25 | "postinstall": "npm run setup", 26 | "publish": "npm run setup && npm run clean && npm run build.all && npm run readme && npm run doc && npm run commit_readme_doc_changes && lerna publish", 27 | "readme": "lerna run readme && node ./tools/readme.js", 28 | "setup": "npm run submodules && ts-patch install", 29 | "start": "./node_modules/.bin/ntl -A -s 15 -o", 30 | "submodules": "git submodule update --init", 31 | "sync": "node ./tools/sync.js", 32 | "sync.test": "node ./tools/sync.js", 33 | "tsc": "cpy '**/*.d.ts' '../plugin' --parents --cwd=src && tsc -skipLibCheck -d", 34 | "update": "node ./tools/update.js" 35 | }, 36 | "dependencies": { 37 | "@nativescript-community/arraybuffers": "^1.1.5", 38 | "@nativescript-community/plugin-seed-tools": "file:tools", 39 | "@sentry/browser": "7.111.0", 40 | "@sentry/core": "7.111.0", 41 | "@sentry/hub": "7.111.0", 42 | "@sentry/integrations": "7.111.0", 43 | "@sentry/tracing": "7.111.0", 44 | "@sentry/types": "7.111.0", 45 | "@sentry/utils": "8.0.0-beta.3" 46 | }, 47 | "repository": { 48 | "type": "git", 49 | "url": "git+https://github.com/nativescript-community/sentry.git" 50 | }, 51 | "author": { 52 | "name": "Martin Guillon", 53 | "email": "martin@akylas.fr" 54 | }, 55 | "license": "ISC", 56 | "bugs": { 57 | "url": "https://github.com/nativescript-community/sentry/issues" 58 | }, 59 | "homepage": "https://github.com/nativescript-community/sentry#readme", 60 | "commitlint": { 61 | "extends": [ 62 | "@commitlint/config-conventional" 63 | ] 64 | }, 65 | "workspaces": [ 66 | "packages/*", 67 | "demo*" 68 | ], 69 | "ntl": { 70 | "descriptions": { 71 | "build": "Build the plugin", 72 | "build.all": "Build the plugin for all platforms", 73 | "clean": "Clean the local environment.", 74 | "demo.vue.android": "Runs the Vue demo on Android.", 75 | "demo.vue.ios": "Runs the Vue demo on iOS.", 76 | "watch": "Watch for changes in the plugin source and re-build." 77 | } 78 | }, 79 | "engines": { 80 | "npm": "please use yarn or pnpm", 81 | "yarn": ">=1.19.1", 82 | "pnpm": ">=7.0.0", 83 | "node": "^14.20.0 || ^16.13.0 || >=18.10.0" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /packages/sentry/.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | tsconfig.json 3 | node_modules/ 4 | pnpm-global/ 5 | CHANGELOG.md 6 | blueprint.md 7 | *.aar 8 | *.jar -------------------------------------------------------------------------------- /packages/sentry/breadcrumb.d.ts: -------------------------------------------------------------------------------- 1 | import type { Breadcrumb, SeverityLevel } from '@sentry/types'; 2 | export declare const DEFAULT_BREADCRUMB_LEVEL: SeverityLevel; 3 | type BreadcrumbCandidate = { 4 | [K in keyof Partial]: unknown; 5 | }; 6 | /** 7 | * Convert plain object to a valid Breadcrumb 8 | */ 9 | export declare function breadcrumbFromObject(candidate: BreadcrumbCandidate): Breadcrumb; 10 | export {}; 11 | -------------------------------------------------------------------------------- /packages/sentry/breadcrumb.js: -------------------------------------------------------------------------------- 1 | import { severityLevelFromString } from '@sentry/utils'; 2 | export const DEFAULT_BREADCRUMB_LEVEL = 'info'; 3 | /** 4 | * Convert plain object to a valid Breadcrumb 5 | */ 6 | export function breadcrumbFromObject(candidate) { 7 | const breadcrumb = {}; 8 | if (typeof candidate.type === 'string') { 9 | breadcrumb.type = candidate.type; 10 | } 11 | if (typeof candidate.level === 'string') { 12 | breadcrumb.level = severityLevelFromString(candidate.level); 13 | } 14 | if (typeof candidate.event_id === 'string') { 15 | breadcrumb.event_id = candidate.event_id; 16 | } 17 | if (typeof candidate.category === 'string') { 18 | breadcrumb.category = candidate.category; 19 | } 20 | if (typeof candidate.message === 'string') { 21 | breadcrumb.message = candidate.message; 22 | } 23 | if (typeof candidate.data === 'object' && candidate.data !== null) { 24 | breadcrumb.data = candidate.data; 25 | } 26 | if (typeof candidate.timestamp === 'string') { 27 | const timestampSeconds = Date.parse(candidate.timestamp) / 1000; // breadcrumb timestamp is in seconds 28 | if (!isNaN(timestampSeconds)) { 29 | breadcrumb.timestamp = timestampSeconds; 30 | } 31 | } 32 | return breadcrumb; 33 | } 34 | //# sourceMappingURL=breadcrumb.js.map -------------------------------------------------------------------------------- /packages/sentry/integrations/debugsymbolicator.d.ts: -------------------------------------------------------------------------------- 1 | import { Integration, StackFrame } from '@sentry/types'; 2 | /** 3 | * React Native Error 4 | */ 5 | type NativescriptError = Error & { 6 | stackTrace?: string; 7 | framesToPop?: number; 8 | jsEngine?: string; 9 | preventSymbolication?: boolean; 10 | componentStack?: string; 11 | }; 12 | export interface NativescriptStackFrame extends StackFrame { 13 | native?: boolean; 14 | } 15 | export declare function parseErrorStack(e: NativescriptError): StackFrame[]; 16 | /** Tries to symbolicate the JS stack trace on the device. */ 17 | export declare class DebugSymbolicator implements Integration { 18 | /** 19 | * @inheritDoc 20 | */ 21 | name: string; 22 | /** 23 | * @inheritDoc 24 | */ 25 | static id: string; 26 | /** 27 | * @inheritDoc 28 | */ 29 | setupOnce(): void; 30 | /** 31 | * Symbolicates the stack on the device talking to local dev server. 32 | * Mutates the passed event. 33 | */ 34 | private _symbolicate; 35 | /** 36 | * Replaces the frames in the exception of a error. 37 | * @param event Event 38 | * @param frames StackFrame[] 39 | */ 40 | private _replaceFramesInEvent; 41 | } 42 | export {}; 43 | -------------------------------------------------------------------------------- /packages/sentry/integrations/debugsymbolicator.js: -------------------------------------------------------------------------------- 1 | import { addGlobalEventProcessor, getCurrentHub } from '@sentry/core'; 2 | import { logger, stackParserFromStackParserOptions } from '@sentry/utils'; 3 | // xport type ExtendedError = Error & { 4 | // jsEngine?: string, 5 | // preventSymbolication?: boolean, 6 | // componentStack?: string, 7 | // forceRedbox?: boolean, 8 | // isComponentError?: boolean, 9 | // ... 10 | // }; 11 | const UNKNOWN_FUNCTION = undefined; 12 | // function createFrame(filename, func, lineno, colno) { 13 | function createFrame(frame) { 14 | frame.in_app = (frame.filename && !frame.filename.includes('node_modules')) || (!!frame.colno && !!frame.lineno); 15 | frame.platform = frame.filename.endsWith('.js') ? 'javascript' : 'android'; 16 | return frame; 17 | } 18 | const nativescriptRegex = /^\s*at (?:(.*\).*?|.*?) ?\()?((?:file|native|webpack||[-a-z]+:|.*bundle|\/)?.*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i; 19 | const nativescriptFunc = (line) => { 20 | const parts = nativescriptRegex.exec(line); 21 | if (parts) { 22 | return createFrame({ 23 | filename: parts[2], 24 | platform: 'javascript', 25 | function: parts[1] || UNKNOWN_FUNCTION, 26 | lineno: parts[3] ? +parts[3] : undefined, 27 | colno: parts[4] ? +parts[4] : undefined 28 | }); 29 | } 30 | return null; 31 | }; 32 | const nativescriptLineParser = [30, nativescriptFunc]; 33 | const androidRegex = /^\s*(?:(.*\).*?|.*?) ?\()?((?:Native Method|[-a-z]+:)?.*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i; 34 | const androidFunc = (line) => { 35 | const parts = androidRegex.exec(line); 36 | if (parts) { 37 | let func = UNKNOWN_FUNCTION, mod; 38 | if (parts[1]) { 39 | const splitted = parts[1].split('.'); 40 | func = splitted[splitted.length - 1]; 41 | mod = splitted.slice(0, -1).join('.'); 42 | } 43 | if (!parts[2].endsWith('.java')) { 44 | return null; 45 | } 46 | return createFrame({ 47 | filename: parts[2], 48 | function: func, 49 | module: mod, 50 | native: func && func.indexOf('Native Method') !== -1, 51 | lineno: parts[3] ? +parts[3] : undefined, 52 | colno: parts[4] ? +parts[4] : undefined 53 | }); 54 | } 55 | return null; 56 | }; 57 | const androidLineParser = [50, androidFunc]; 58 | const stackParser = stackParserFromStackParserOptions([nativescriptLineParser, androidLineParser]); 59 | export function parseErrorStack(e) { 60 | const stack = e?.['stackTrace'] || e?.stack; 61 | if (!stack) { 62 | return []; 63 | } 64 | return stackParser(stack); 65 | } 66 | /** Tries to symbolicate the JS stack trace on the device. */ 67 | export class DebugSymbolicator { 68 | constructor() { 69 | /** 70 | * @inheritDoc 71 | */ 72 | this.name = DebugSymbolicator.id; 73 | } 74 | /** 75 | * @inheritDoc 76 | */ 77 | setupOnce() { 78 | addGlobalEventProcessor(async (event, hint) => { 79 | const self = getCurrentHub().getIntegration(DebugSymbolicator); 80 | if (!self || hint === undefined || hint.originalException === undefined) { 81 | return event; 82 | } 83 | // @ts-ignore 84 | const error = hint.originalException; 85 | // const parseErrorStack = require('react-native/Libraries/Core/Devtools/parseErrorStack'); 86 | const stack = parseErrorStack(error); 87 | // Ideally this should go into contexts but android sdk doesn't support it 88 | event.extra = { 89 | ...event.extra, 90 | componentStack: error.componentStack, 91 | jsEngine: error.jsEngine 92 | }; 93 | await self._symbolicate(event, stack); 94 | event.platform = 'node'; // Setting platform node makes sure we do not show source maps errors 95 | return event; 96 | }); 97 | } 98 | /** 99 | * Symbolicates the stack on the device talking to local dev server. 100 | * Mutates the passed event. 101 | */ 102 | async _symbolicate(event, stack) { 103 | try { 104 | // eslint-disable-next-line @typescript-eslint/no-var-requires 105 | this._replaceFramesInEvent(event, stack); 106 | } 107 | catch (error) { 108 | if (error instanceof Error) { 109 | logger.warn(`Unable to symbolicate stack trace: ${error.message}`); 110 | } 111 | } 112 | } 113 | /** 114 | * Replaces the frames in the exception of a error. 115 | * @param event Event 116 | * @param frames StackFrame[] 117 | */ 118 | _replaceFramesInEvent(event, frames) { 119 | if (event.exception?.values?.[0].stacktrace) { 120 | event.exception.values[0].stacktrace.frames = frames.reverse(); 121 | } 122 | } 123 | } 124 | /** 125 | * @inheritDoc 126 | */ 127 | DebugSymbolicator.id = 'DebugSymbolicator'; 128 | //# sourceMappingURL=debugsymbolicator.js.map -------------------------------------------------------------------------------- /packages/sentry/integrations/default.d.ts: -------------------------------------------------------------------------------- 1 | import type { Integration, StackFrame } from '@sentry/types'; 2 | import type { NativescriptClientOptions, NativescriptOptions } from '../options'; 3 | export declare let rewriteFrameIntegration: { 4 | _iteratee: (frame: StackFrame) => StackFrame; 5 | }; 6 | /** 7 | * Returns the default ReactNative integrations based on the current environment. 8 | * 9 | * Native integrations are only returned when native is enabled. 10 | * 11 | * Web integrations are only returned when running on web. 12 | */ 13 | export declare function getDefaultIntegrations(options: NativescriptClientOptions & NativescriptOptions): Integration[]; 14 | -------------------------------------------------------------------------------- /packages/sentry/integrations/devicecontext.d.ts: -------------------------------------------------------------------------------- 1 | import { Integration } from '@sentry/types'; 2 | /** Load device context from native. */ 3 | export declare class DeviceContext implements Integration { 4 | /** 5 | * @inheritDoc 6 | */ 7 | name: string; 8 | /** 9 | * @inheritDoc 10 | */ 11 | static id: string; 12 | /** 13 | * @inheritDoc 14 | */ 15 | setupOnce(): void; 16 | } 17 | -------------------------------------------------------------------------------- /packages/sentry/integrations/devicecontext.js: -------------------------------------------------------------------------------- 1 | import { addEventProcessor, getCurrentHub } from '@sentry/core'; 2 | import { logger, severityLevelFromString } from '@sentry/utils'; 3 | import { NATIVE } from '../wrapper'; 4 | import { breadcrumbFromObject } from '../breadcrumb'; 5 | import { Application } from '@nativescript/core'; 6 | /** Load device context from native. */ 7 | export class DeviceContext { 8 | constructor() { 9 | /** 10 | * @inheritDoc 11 | */ 12 | this.name = DeviceContext.id; 13 | } 14 | /** 15 | * @inheritDoc 16 | */ 17 | setupOnce() { 18 | addEventProcessor(async (event) => { 19 | const self = getCurrentHub().getIntegration(DeviceContext); 20 | if (!self) { 21 | return event; 22 | } 23 | let native = null; 24 | try { 25 | native = await NATIVE.fetchNativeDeviceContexts(); 26 | } 27 | catch (e) { 28 | logger.log(`Failed to get device context from native: ${e}`); 29 | } 30 | if (!native) { 31 | return event; 32 | } 33 | const nativeUser = native.user; 34 | if (!event.user && nativeUser) { 35 | event.user = nativeUser; 36 | } 37 | let nativeContexts = native.contexts; 38 | // if (AppState.currentState !== 'unknown') { 39 | nativeContexts = nativeContexts || {}; 40 | nativeContexts.app = { 41 | ...nativeContexts.app, 42 | in_foreground: !Application.inBackground 43 | }; 44 | // } 45 | if (nativeContexts) { 46 | event.contexts = { ...nativeContexts, ...event.contexts }; 47 | if (nativeContexts.app) { 48 | event.contexts.app = { ...nativeContexts.app, ...event.contexts.app }; 49 | } 50 | } 51 | const nativeTags = native.tags; 52 | if (nativeTags) { 53 | event.tags = { ...nativeTags, ...event.tags }; 54 | } 55 | const nativeExtra = native.extra; 56 | if (nativeExtra) { 57 | event.extra = { ...nativeExtra, ...event.extra }; 58 | } 59 | const nativeFingerprint = native.fingerprint; 60 | if (nativeFingerprint) { 61 | event.fingerprint = (event.fingerprint ?? []).concat(nativeFingerprint.filter((item) => (event.fingerprint ?? []).indexOf(item) < 0)); 62 | } 63 | const nativeLevel = typeof native['level'] === 'string' ? severityLevelFromString(native['level']) : undefined; 64 | if (!event.level && nativeLevel) { 65 | event.level = nativeLevel; 66 | } 67 | const nativeEnvironment = native['environment']; 68 | if (!event.environment && nativeEnvironment) { 69 | event.environment = nativeEnvironment; 70 | } 71 | const nativeBreadcrumbs = Array.isArray(native['breadcrumbs']) ? native['breadcrumbs'].map(breadcrumbFromObject) : undefined; 72 | if (nativeBreadcrumbs) { 73 | event.breadcrumbs = nativeBreadcrumbs.concat(event.breadcrumbs || []); 74 | } 75 | return event; 76 | }); 77 | } 78 | } 79 | /** 80 | * @inheritDoc 81 | */ 82 | DeviceContext.id = 'DeviceContext'; 83 | //# sourceMappingURL=devicecontext.js.map -------------------------------------------------------------------------------- /packages/sentry/integrations/eventorigin.d.ts: -------------------------------------------------------------------------------- 1 | import { EventProcessor, Integration } from '@sentry/types'; 2 | /** Default EventOrigin instrumentation */ 3 | export declare class EventOrigin implements Integration { 4 | /** 5 | * @inheritDoc 6 | */ 7 | static id: string; 8 | /** 9 | * @inheritDoc 10 | */ 11 | name: string; 12 | /** 13 | * @inheritDoc 14 | */ 15 | setupOnce(addGlobalEventProcessor: (e: EventProcessor) => void): void; 16 | } 17 | -------------------------------------------------------------------------------- /packages/sentry/integrations/eventorigin.js: -------------------------------------------------------------------------------- 1 | /** Default EventOrigin instrumentation */ 2 | export class EventOrigin { 3 | constructor() { 4 | /** 5 | * @inheritDoc 6 | */ 7 | this.name = EventOrigin.id; 8 | } 9 | /** 10 | * @inheritDoc 11 | */ 12 | setupOnce(addGlobalEventProcessor) { 13 | addGlobalEventProcessor((event) => { 14 | event.tags = event.tags ?? {}; 15 | event.tags['event.origin'] = __ANDROID__ ? 'android' : __IOS__ ? 'ios' : 'javascript'; 16 | event.tags['event.environment'] = 'nativescript'; 17 | return event; 18 | }); 19 | } 20 | } 21 | /** 22 | * @inheritDoc 23 | */ 24 | EventOrigin.id = 'EventOrigin'; 25 | //# sourceMappingURL=eventorigin.js.map -------------------------------------------------------------------------------- /packages/sentry/integrations/factory.d.ts: -------------------------------------------------------------------------------- 1 | import type { Integration } from '@sentry/types'; 2 | /** 3 | * Creates an integration out of the provided name and setup function. 4 | * @hidden 5 | */ 6 | export declare function createIntegration(name: Integration['name'], setupOnce?: Integration['setupOnce']): Integration; 7 | -------------------------------------------------------------------------------- /packages/sentry/integrations/factory.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creates an integration out of the provided name and setup function. 3 | * @hidden 4 | */ 5 | export function createIntegration(name, setupOnce = () => { 6 | /* noop */ 7 | }) { 8 | return { 9 | name, 10 | setupOnce, 11 | }; 12 | } 13 | //# sourceMappingURL=factory.js.map -------------------------------------------------------------------------------- /packages/sentry/integrations/index.d.ts: -------------------------------------------------------------------------------- 1 | export { DebugSymbolicator } from './debugsymbolicator'; 2 | export { DeviceContext } from './devicecontext'; 3 | export { NativescriptErrorHandlers as NativescriptErrorHandlers } from './nativescripterrorhandlers'; 4 | export { Release } from './release'; 5 | -------------------------------------------------------------------------------- /packages/sentry/integrations/index.js: -------------------------------------------------------------------------------- 1 | export { DebugSymbolicator } from './debugsymbolicator'; 2 | export { DeviceContext } from './devicecontext'; 3 | export { NativescriptErrorHandlers as NativescriptErrorHandlers } from './nativescripterrorhandlers'; 4 | export { Release } from './release'; 5 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /packages/sentry/integrations/nativescripterrorhandlers.d.ts: -------------------------------------------------------------------------------- 1 | import { Integration } from '@sentry/types'; 2 | /** NativescriptErrorHandlers Options */ 3 | export interface NativescriptErrorHandlersOptions { 4 | onerror?: boolean; 5 | onunhandledrejection?: boolean; 6 | /** 7 | * When enabled, Sentry will overwrite the global Promise instance to ensure that unhandled rejections are correctly tracked. 8 | * If you run into issues with Promise polyfills such as `core-js`, make sure you polyfill after Sentry is initialized. 9 | * Read more at https://docs.sentry.io/platforms/react-native/troubleshooting/#unhandled-promise-rejections 10 | * 11 | * When disabled, this option will not disable unhandled rejection tracking. Set `onunhandledrejection: false` on the `ReactNativeErrorHandlers` integration instead. 12 | * 13 | * @default true 14 | */ 15 | patchGlobalPromise?: boolean; 16 | } 17 | /** NativescriptErrorHandlers Integration */ 18 | export declare class NativescriptErrorHandlers implements Integration { 19 | /** 20 | * @inheritDoc 21 | */ 22 | static id: string; 23 | /** 24 | * @inheritDoc 25 | */ 26 | name: string; 27 | /** NativescriptOptions */ 28 | private readonly _options; 29 | /** Constructor */ 30 | constructor(options?: NativescriptErrorHandlersOptions); 31 | /** 32 | * @inheritDoc 33 | */ 34 | setupOnce(): void; 35 | /** 36 | * Handle Promises 37 | */ 38 | private _handleUnhandledRejections; 39 | private globalHanderEvent; 40 | handlingFatal: boolean; 41 | private globalHander; 42 | /** 43 | * Handle erros 44 | */ 45 | private _handleOnError; 46 | } 47 | -------------------------------------------------------------------------------- /packages/sentry/integrations/nativescripterrorhandlers.js: -------------------------------------------------------------------------------- 1 | import { getCurrentHub } from '@sentry/core'; 2 | import { eventFromUnknownInput } from '@sentry/browser/esm/eventbuilder'; 3 | import { addExceptionMechanism, logger } from '@sentry/utils'; 4 | import { Application } from '@nativescript/core'; 5 | import { Screenshot } from './screenshot'; 6 | /** NativescriptErrorHandlers Integration */ 7 | export class NativescriptErrorHandlers { 8 | /** Constructor */ 9 | constructor(options) { 10 | /** 11 | * @inheritDoc 12 | */ 13 | this.name = NativescriptErrorHandlers.id; 14 | this.handlingFatal = false; 15 | this._options = { 16 | // uncaughtErrors: false, 17 | onerror: false, 18 | onunhandledrejection: false, 19 | patchGlobalPromise: true, 20 | ...options 21 | }; 22 | } 23 | /** 24 | * @inheritDoc 25 | */ 26 | setupOnce() { 27 | this._handleUnhandledRejections(); 28 | this._handleOnError(); 29 | } 30 | /** 31 | * Handle Promises 32 | */ 33 | _handleUnhandledRejections() { 34 | if (this._options.onunhandledrejection) { 35 | // if (this._options.uncaughtErrors) { 36 | Application.on(Application.uncaughtErrorEvent, this.globalHanderEvent, this); 37 | // } 38 | // if (this._options.patchGlobalPromise) { 39 | // this._polyfillPromise(); 40 | // } 41 | // this._attachUnhandledRejectionHandler(); 42 | // this._checkPromiseAndWarn(); 43 | } 44 | } 45 | globalHanderEvent(event) { 46 | this.globalHander(event.error); 47 | } 48 | globalHander(error, isFatal) { 49 | try { 50 | // We want to handle fatals, but only in production mode. 51 | const shouldHandleFatal = isFatal && !__DEV__; 52 | if (shouldHandleFatal) { 53 | if (this.handlingFatal) { 54 | logger.log('Encountered multiple fatals in a row. The latest:', error); 55 | return; 56 | } 57 | this.handlingFatal = true; 58 | } 59 | const currentHub = getCurrentHub(); 60 | const client = currentHub.getClient(); 61 | if (!client) { 62 | logger.error('Sentry client is missing, the error event might be lost.', error); 63 | // If there is no client something is fishy, anyway we call the default handler 64 | // defaultHandler(error, isFatal); 65 | return; 66 | } 67 | // We override client.eventFromException because it is async function 68 | // while not needed and we want to be sync 69 | if (error['stackTrace']) { 70 | error['stacktrace'] = error['stackTrace']; 71 | } 72 | let hint = { 73 | originalException: error 74 | }; 75 | const syntheticException = (hint && hint.syntheticException) || undefined; 76 | hint = Screenshot.attachScreenshotToEventHint(hint, client.getOptions()); 77 | const event = eventFromUnknownInput(client.getOptions().stackParser, error, syntheticException, client.getOptions().attachStacktrace); 78 | addExceptionMechanism(event); // defaults to { type: 'generic', handled: true } 79 | event.level = 'error'; 80 | if (hint && hint.event_id) { 81 | event.event_id = hint.event_id; 82 | } 83 | if (isFatal) { 84 | event.level = 'fatal'; 85 | addExceptionMechanism(event, { 86 | handled: false, 87 | type: 'onerror' 88 | }); 89 | } 90 | client.captureEvent(event); 91 | } 92 | catch (error) { 93 | console.error(error); 94 | } 95 | // if (!__DEV__) { 96 | // void client.flush(options.shutdownTimeout || 2000).then(() => { 97 | // defaultHandler(error, isFatal); 98 | // }); 99 | // } else { 100 | // // If in dev, we call the default handler anyway and hope the error will be sent 101 | // // Just for a better dev experience 102 | // defaultHandler(error, isFatal); 103 | // } 104 | } 105 | /** 106 | * Handle erros 107 | */ 108 | _handleOnError() { 109 | if (this._options.onerror) { 110 | // let handlingFatal = false; 111 | // Application.on(Application.uncaughtErrorEvent, this.globalHanderEvent, this); 112 | Application.on(Application.discardedErrorEvent, this.globalHanderEvent, this); 113 | // Trace.setErrorHandler({ 114 | // handlerError: this.globalHander 115 | // }); 116 | // const defaultHandler = ErrorUtils.getGlobalHandler && ErrorUtils.getGlobalHandler(); 117 | // ErrorUtils.setGlobalHandler); 118 | } 119 | } 120 | } 121 | /** 122 | * @inheritDoc 123 | */ 124 | NativescriptErrorHandlers.id = 'NativescriptErrorHandlers'; 125 | //# sourceMappingURL=nativescripterrorhandlers.js.map -------------------------------------------------------------------------------- /packages/sentry/integrations/release.d.ts: -------------------------------------------------------------------------------- 1 | import { Integration } from '@sentry/types'; 2 | /** Release integration responsible to load release from file. */ 3 | export declare class Release implements Integration { 4 | /** 5 | * @inheritDoc 6 | */ 7 | name: string; 8 | /** 9 | * @inheritDoc 10 | */ 11 | static id: string; 12 | /** 13 | * @inheritDoc 14 | */ 15 | setupOnce(): void; 16 | } 17 | -------------------------------------------------------------------------------- /packages/sentry/integrations/release.js: -------------------------------------------------------------------------------- 1 | import { addGlobalEventProcessor, getCurrentHub } from '@sentry/core'; 2 | import { NATIVE } from '../wrapper'; 3 | /** Release integration responsible to load release from file. */ 4 | export class Release { 5 | constructor() { 6 | /** 7 | * @inheritDoc 8 | */ 9 | this.name = Release.id; 10 | } 11 | /** 12 | * @inheritDoc 13 | */ 14 | setupOnce() { 15 | addGlobalEventProcessor(async (event) => { 16 | const self = getCurrentHub().getIntegration(Release); 17 | if (!self) { 18 | return event; 19 | } 20 | const options = getCurrentHub().getClient()?.getOptions(); 21 | /* 22 | __sentry_release and __sentry_dist is set by the user with setRelease and setDist. If this is used then this is the strongest. 23 | Otherwise we check for the release and dist in the options passed on init, as this is stronger than the release/dist from the native build. 24 | */ 25 | if (typeof event.extra?.__sentry_release === 'string') { 26 | event.release = `${event.extra.__sentry_release}`; 27 | } 28 | else if (typeof options?.release === 'string') { 29 | event.release = options.release; 30 | } 31 | if (typeof event.extra?.__sentry_dist === 'string') { 32 | event.dist = `${event.extra.__sentry_dist}`; 33 | } 34 | else if (typeof options?.dist === 'string') { 35 | event.dist = options.dist; 36 | } 37 | if (event.release && event.dist) { 38 | return event; 39 | } 40 | try { 41 | const nativeRelease = (await NATIVE.fetchNativeRelease()); 42 | if (!event.release) { 43 | event.release = `${nativeRelease.id}@${nativeRelease.version}+${nativeRelease.build}`; 44 | } 45 | if (!event.dist) { 46 | event.dist = `${nativeRelease.build}.${__IOS__ ? 'ios' : 'android'}`; 47 | } 48 | } 49 | catch (_Oo) { 50 | // Something went wrong, we just continue 51 | } 52 | return event; 53 | }); 54 | } 55 | } 56 | /** 57 | * @inheritDoc 58 | */ 59 | Release.id = 'Release'; 60 | //# sourceMappingURL=release.js.map -------------------------------------------------------------------------------- /packages/sentry/integrations/rewriteframe.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/sentry/4919940f8eae59341140b897999862de282c0934/packages/sentry/integrations/rewriteframe.d.ts -------------------------------------------------------------------------------- /packages/sentry/integrations/rewriteframe.js: -------------------------------------------------------------------------------- 1 | //# sourceMappingURL=rewriteframe.js.map -------------------------------------------------------------------------------- /packages/sentry/integrations/screenshot.d.ts: -------------------------------------------------------------------------------- 1 | import { EventHint, Integration } from '@sentry/types'; 2 | /** Adds screenshots to error events */ 3 | export declare class Screenshot implements Integration { 4 | /** 5 | * @inheritDoc 6 | */ 7 | static id: string; 8 | /** 9 | * @inheritDoc 10 | */ 11 | name: string; 12 | /** 13 | * If enabled attaches a screenshot to the event hint. 14 | */ 15 | static attachScreenshotToEventHint(hint: EventHint, { attachScreenshot }: { 16 | attachScreenshot?: boolean; 17 | }): EventHint; 18 | /** 19 | * @inheritDoc 20 | */ 21 | setupOnce(): void; 22 | } 23 | -------------------------------------------------------------------------------- /packages/sentry/integrations/screenshot.js: -------------------------------------------------------------------------------- 1 | import { NATIVE } from '../wrapper'; 2 | /** Adds screenshots to error events */ 3 | export class Screenshot { 4 | constructor() { 5 | /** 6 | * @inheritDoc 7 | */ 8 | this.name = Screenshot.id; 9 | } 10 | /** 11 | * If enabled attaches a screenshot to the event hint. 12 | */ 13 | static attachScreenshotToEventHint(hint, { attachScreenshot }) { 14 | if (!attachScreenshot) { 15 | return hint; 16 | } 17 | const screenshots = NATIVE.captureScreenshot(); 18 | if (screenshots !== null && screenshots.length > 0) { 19 | hint.attachments = [...screenshots, ...(hint?.attachments || [])]; 20 | } 21 | return hint; 22 | } 23 | /** 24 | * @inheritDoc 25 | */ 26 | // eslint-disable-next-line @typescript-eslint/no-empty-function 27 | setupOnce() { } 28 | } 29 | /** 30 | * @inheritDoc 31 | */ 32 | Screenshot.id = 'Screenshot'; 33 | //# sourceMappingURL=screenshot.js.map -------------------------------------------------------------------------------- /packages/sentry/integrations/sdkinfo.d.ts: -------------------------------------------------------------------------------- 1 | import { EventProcessor, Integration, SdkInfo as SdkInfoType } from '@sentry/types'; 2 | type DefaultSdkInfo = Pick, 'name' | 'packages' | 'version'>; 3 | export declare const defaultSdkInfo: DefaultSdkInfo; 4 | /** Default SdkInfo instrumentation */ 5 | export declare class SdkInfo implements Integration { 6 | /** 7 | * @inheritDoc 8 | */ 9 | static id: string; 10 | /** 11 | * @inheritDoc 12 | */ 13 | name: string; 14 | private _nativeSdkInfo; 15 | /** 16 | * @inheritDoc 17 | */ 18 | setupOnce(addGlobalEventProcessor: (e: EventProcessor) => void): void; 19 | } 20 | export {}; 21 | -------------------------------------------------------------------------------- /packages/sentry/integrations/sdkinfo.js: -------------------------------------------------------------------------------- 1 | import { logger } from '@sentry/utils'; 2 | import { SDK_NAME, SDK_PACKAGE_NAME, SDK_VERSION } from '../version'; 3 | import { NATIVE } from '../wrapper'; 4 | export const defaultSdkInfo = { 5 | name: SDK_NAME, 6 | packages: [ 7 | { 8 | name: SDK_PACKAGE_NAME, 9 | version: SDK_VERSION 10 | } 11 | ], 12 | version: SDK_VERSION 13 | }; 14 | /** Default SdkInfo instrumentation */ 15 | export class SdkInfo { 16 | constructor() { 17 | /** 18 | * @inheritDoc 19 | */ 20 | this.name = SdkInfo.id; 21 | this._nativeSdkInfo = null; 22 | } 23 | /** 24 | * @inheritDoc 25 | */ 26 | setupOnce(addGlobalEventProcessor) { 27 | addGlobalEventProcessor(async (event) => { 28 | // The native SDK info package here is only used on iOS as `beforeSend` is not called on `captureEnvelope`. 29 | // this._nativeSdkInfo should be defined a following time so this call won't always be awaited. 30 | if (this._nativeSdkInfo === null) { 31 | try { 32 | this._nativeSdkInfo = await NATIVE.fetchNativeSdkInfo(); 33 | } 34 | catch (e) { 35 | // If this fails, go ahead as usual as we would rather have the event be sent with a package missing. 36 | logger.warn('[SdkInfo] Native SDK Info retrieval failed...something could be wrong with your Sentry installation:'); 37 | logger.warn(e); 38 | } 39 | } 40 | event.platform = event.platform || 'javascript'; 41 | event.sdk = { 42 | ...(event.sdk ?? {}), 43 | ...defaultSdkInfo, 44 | packages: [...((event.sdk && event.sdk.packages) || []), ...((this._nativeSdkInfo && [this._nativeSdkInfo]) || []), ...defaultSdkInfo.packages] 45 | }; 46 | return event; 47 | }); 48 | } 49 | } 50 | /** 51 | * @inheritDoc 52 | */ 53 | SdkInfo.id = 'SdkInfo'; 54 | //# sourceMappingURL=sdkinfo.js.map -------------------------------------------------------------------------------- /packages/sentry/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nativescript-community/sentry", 3 | "version": "4.6.40", 4 | "description": "A cross-platform application monitoring tool, with a focus on error reporting.", 5 | "main": "./index", 6 | "typings": "./index.d.ts", 7 | "sideEffects": false, 8 | "nativescript": { 9 | "platforms": { 10 | "android": "6.1.0", 11 | "ios": "6.1.0" 12 | } 13 | }, 14 | "scripts": { 15 | "build": "npm run tsc", 16 | "build.all": "npm run build", 17 | "build.angular": "ng-packagr -p ../../src/sentry/angular/ng-package.json -c ../../src/sentry/angular/tsconfig.json && rm angular/.npmignore", 18 | "readme": "readme generate -c ../../tools/readme/blueprint.json", 19 | "tsc": "cpy '**/*.d.ts' '../../packages/sentry' --parents --cwd=../../src/sentry && tsc -skipLibCheck -d", 20 | "clean": "rimraf ./*.d.ts ./*.js ./*.js.map" 21 | }, 22 | "keywords": [ 23 | "NativeScript", 24 | "JavaScript", 25 | "Android", 26 | "iOS", 27 | "Vue", 28 | "preview|https://raw.githubusercontent.com/nativescript-community/sentry/master/images/preview.png" 29 | ], 30 | "author": { 31 | "name": "Martin Guillon", 32 | "email": "martin@akylas.fr" 33 | }, 34 | "license": "ISC", 35 | "bugs": { 36 | "url": "https://github.com/nativescript-community/sentry/issues" 37 | }, 38 | "repository": { 39 | "type": "git", 40 | "url": "https://github.com/nativescript-community/sentry" 41 | }, 42 | "dependencies": { 43 | "@nativescript-community/arraybuffers": "^1.1.5", 44 | "@sentry/browser": "7.111.0", 45 | "@sentry/core": "7.111.0", 46 | "@sentry/hub": "7.111.0", 47 | "@sentry/integrations": "7.111.0", 48 | "@sentry/tracing": "7.111.0", 49 | "@sentry/types": "7.111.0", 50 | "@sentry/utils": "7.111.0", 51 | "stacktrace-parser": "^0.1.10" 52 | }, 53 | "gitHead": "1e799d9f3a3eeb19c0fc4188be82a6cded4ea727" 54 | } 55 | -------------------------------------------------------------------------------- /packages/sentry/platforms/android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/sentry/platforms/android/buildscript.gradle: -------------------------------------------------------------------------------- 1 | // buildscript { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | dependencies { 7 | def sentryGradleVersion = hasProperty("sentryGradleVersion") ? sentryGradleVersion : "4.3.0" 8 | println "sentryGradleVersion $sentryGradleVersion" 9 | classpath "io.sentry:sentry-android-gradle-plugin:$sentryGradleVersion" 10 | } 11 | // } -------------------------------------------------------------------------------- /packages/sentry/platforms/android/include.gradle: -------------------------------------------------------------------------------- 1 | // Add compatibility options to be comptible with Java 1.8 2 | apply plugin: 'io.sentry.android.gradle' 3 | android { 4 | compileOptions { 5 | sourceCompatibility = JavaVersion.VERSION_1_8 6 | targetCompatibility = JavaVersion.VERSION_1_8 7 | } 8 | } 9 | dependencies { 10 | def sentryVersion = project.hasProperty("sentryVersion") ? project.sentryVersion : "7.4.0" 11 | println("sentryVersion $sentryVersion") 12 | implementation "io.sentry:sentry-android:$sentryVersion" 13 | } 14 | -------------------------------------------------------------------------------- /packages/sentry/platforms/android/native-api-usage.json: -------------------------------------------------------------------------------- 1 | { 2 | "uses": [ 3 | "androidx.core.app:FrameMetricsAggregator", 4 | "io.sentry.android.core.internal.util:ScreenshotUtils", 5 | "io.sentry.android.core:AndroidLogger", 6 | "io.sentry.android.core:AnrIntegration", 7 | "io.sentry.android.core:AppStartState", 8 | "io.sentry.android.core:BuildInfoProvider", 9 | "io.sentry.android.core:InternalSentrySdk", 10 | "io.sentry.android.core:CurrentActivityHolder", 11 | "io.sentry.android.core:NdkIntegration", 12 | "io.sentry.android.core:SentryAndroid", 13 | "io.sentry.android.core:SentryAndroidOptions", 14 | "io.sentry.exception:ExceptionMechanismException", 15 | "io.sentry.protocol:Message", 16 | "io.sentry.protocol:SdkVersion", 17 | "io.sentry.protocol:SentryException", 18 | "io.sentry.protocol:SentryId", 19 | "io.sentry.protocol:SentryPackage", 20 | "io.sentry.protocol:SentryStackFrame", 21 | "io.sentry.protocol:SentryStackTrace", 22 | "io.sentry.protocol:User", 23 | "io.sentry.transport:AsyncHttpTransport", 24 | "io.sentry.transport:ITransportGate", 25 | "io.sentry.transport:RateLimiter", 26 | "io.sentry:Breadcrumb", 27 | "io.sentry:HubAdapter", 28 | "io.sentry:Integration", 29 | "io.sentry:ILogger", 30 | "io.sentry:IScope", 31 | "io.sentry:ITransportFactory", 32 | "io.sentry:RequestDetails", 33 | "io.sentry:ScopeCallback", 34 | "io.sentry:Sentry", 35 | "io.sentry:Sentry.OptionsConfiguration", 36 | "io.sentry:SentryBaseEvent", 37 | "io.sentry:SentryEvent", 38 | "io.sentry:SentryLevel", 39 | "io.sentry:SentryOptions", 40 | "io.sentry:SentryOptions.BeforeBreadcrumbCallback", 41 | "io.sentry:SentryOptions.BeforeSendCallback", 42 | "io.sentry:UncaughtExceptionHandlerIntegration", 43 | "io.sentry:UserFeedback", 44 | "io.sentry.android.fragment:FragmentLifecycleIntegration", 45 | "java.lang:Boolean", 46 | "java.lang:Integer", 47 | "java.lang:Long", 48 | "java.lang:Thread", 49 | "java.nio.charset:Charset", 50 | "java.nio:CharBuffer", 51 | "java.util:Collection", 52 | "java.util:Map", 53 | "java.util:UUID" 54 | ] 55 | } -------------------------------------------------------------------------------- /packages/sentry/platforms/ios/Podfile: -------------------------------------------------------------------------------- 1 | pod 'Sentry/HybridSDK', :git => 'https://github.com/getsentry/sentry-cocoa.git', :tag => '8.52.1' 2 | -------------------------------------------------------------------------------- /packages/sentry/platforms/ios/src/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/sentry/4919940f8eae59341140b897999862de282c0934/packages/sentry/platforms/ios/src/Info.plist -------------------------------------------------------------------------------- /packages/sentry/platforms/ios/src/NSSentry.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | 6 | @interface NSSentrySDK: SentrySDK 7 | + (void)captureEnvelope:(SentryEnvelope *)envelope; 8 | + (void)storeEnvelope:(SentryEnvelope *)envelope; 9 | + (nullable SentryEnvelope *)envelopeWithData:(NSData *)data; 10 | 11 | @property (class, nonatomic, readonly, copy) NSString *installationID; 12 | @property (class, nonatomic, assign, readonly) BOOL isFramesTrackingRunning; 13 | 14 | @property (class, nonatomic, assign, readonly) SentryScreenFrames *currentScreenFrames; 15 | @property (class, nullable, nonatomic, readonly) SentryAppStartMeasurement *appStartMeasurement; 16 | @property (class, nonatomic, assign) BOOL appStartMeasurementHybridSDKMode; 17 | @property (class, nonatomic, assign) BOOL framesTrackingMeasurementHybridSDKMode; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /packages/sentry/platforms/ios/src/NSSentry.m: -------------------------------------------------------------------------------- 1 | #import "NSSentry.h" 2 | #import 3 | #import 4 | 5 | @implementation NSSentrySDK 6 | 7 | + (void)captureEnvelope:(SentryEnvelope *)envelope 8 | { 9 | return [PrivateSentrySDKOnly captureEnvelope:envelope]; 10 | } 11 | + (void)storeEnvelope:(SentryEnvelope *)envelope 12 | { 13 | return [PrivateSentrySDKOnly storeEnvelope:envelope]; 14 | } 15 | + (nullable SentryEnvelope *)envelopeWithData:(NSData *)data 16 | { 17 | return [PrivateSentrySDKOnly envelopeWithData:data]; 18 | } 19 | 20 | + (NSString *)installationID 21 | { 22 | return [PrivateSentrySDKOnly installationID]; 23 | } 24 | 25 | + (nullable SentryAppStartMeasurement *)appStartMeasurement 26 | { 27 | return [PrivateSentrySDKOnly appStartMeasurement]; 28 | } 29 | 30 | + (SentryScreenFrames *)currentScreenFrames 31 | { 32 | return [PrivateSentrySDKOnly currentScreenFrames]; 33 | } 34 | 35 | + (BOOL)isFramesTrackingRunning 36 | { 37 | return [PrivateSentrySDKOnly isFramesTrackingRunning]; 38 | } 39 | + (void)setAppStartMeasurementHybridSDKMode:(BOOL)appStartMeasurementHybridSDKMode 40 | { 41 | [PrivateSentrySDKOnly setAppStartMeasurementHybridSDKMode:appStartMeasurementHybridSDKMode]; 42 | } 43 | + (void)setFramesTrackingMeasurementHybridSDKMode:(BOOL)framesTrackingMeasurementHybridSDKMode 44 | { 45 | [PrivateSentrySDKOnly setFramesTrackingMeasurementHybridSDKMode:framesTrackingMeasurementHybridSDKMode]; 46 | } 47 | @end 48 | -------------------------------------------------------------------------------- /packages/sentry/platforms/ios/src/module.modulemap: -------------------------------------------------------------------------------- 1 | module NSSentry { 2 | header "NSSentry.h" 3 | export * 4 | } -------------------------------------------------------------------------------- /packages/sentry/scope.d.ts: -------------------------------------------------------------------------------- 1 | import { Scope } from '@sentry/core'; 2 | import type { Attachment, Breadcrumb, User } from '@sentry/types'; 3 | /** 4 | * Extends the scope methods to set scope on the Native SDKs 5 | */ 6 | export declare class NativescriptScope extends Scope { 7 | /** 8 | * @inheritDoc 9 | */ 10 | setUser(user: User | null): this; 11 | /** 12 | * @inheritDoc 13 | */ 14 | setTag(key: string, value: string): this; 15 | /** 16 | * @inheritDoc 17 | */ 18 | setTags(tags: { 19 | [key: string]: string; 20 | }): this; 21 | /** 22 | * @inheritDoc 23 | */ 24 | setExtras(extras: { 25 | [key: string]: any; 26 | }): this; 27 | /** 28 | * @inheritDoc 29 | */ 30 | setExtra(key: string, extra: any): this; 31 | /** 32 | * @inheritDoc 33 | */ 34 | addBreadcrumb(breadcrumb: Breadcrumb, maxBreadcrumbs?: number): this; 35 | /** 36 | * @inheritDoc 37 | */ 38 | clearBreadcrumbs(): this; 39 | /** 40 | * @inheritDoc 41 | */ 42 | setContext(key: string, context: { 43 | [key: string]: any; 44 | } | null): this; 45 | /** 46 | * @inheritDoc 47 | */ 48 | addAttachment(attachment: Attachment): this; 49 | /** 50 | * @inheritDoc 51 | */ 52 | clearAttachments(): this; 53 | } 54 | -------------------------------------------------------------------------------- /packages/sentry/scope.js: -------------------------------------------------------------------------------- 1 | import { Scope } from '@sentry/core'; 2 | import { DEFAULT_BREADCRUMB_LEVEL } from './breadcrumb'; 3 | import { convertToNormalizedObject } from './utils/normalize'; 4 | import { NATIVE } from './wrapper'; 5 | /** 6 | * Extends the scope methods to set scope on the Native SDKs 7 | */ 8 | export class NativescriptScope extends Scope { 9 | /** 10 | * @inheritDoc 11 | */ 12 | setUser(user) { 13 | NATIVE.setUser(user); 14 | return super.setUser(user); 15 | } 16 | /** 17 | * @inheritDoc 18 | */ 19 | setTag(key, value) { 20 | NATIVE.setTag(key, value); 21 | return super.setTag(key, value); 22 | } 23 | /** 24 | * @inheritDoc 25 | */ 26 | setTags(tags) { 27 | // As native only has setTag, we just loop through each tag key. 28 | Object.keys(tags).forEach((key) => { 29 | NATIVE.setTag(key, tags[key]); 30 | }); 31 | return super.setTags(tags); 32 | } 33 | /** 34 | * @inheritDoc 35 | */ 36 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 37 | setExtras(extras) { 38 | Object.keys(extras).forEach((key) => { 39 | NATIVE.setExtra(key, extras[key]); 40 | }); 41 | return super.setExtras(extras); 42 | } 43 | /** 44 | * @inheritDoc 45 | */ 46 | // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types,@typescript-eslint/no-explicit-any 47 | setExtra(key, extra) { 48 | NATIVE.setExtra(key, extra); 49 | return super.setExtra(key, extra); 50 | } 51 | /** 52 | * @inheritDoc 53 | */ 54 | addBreadcrumb(breadcrumb, maxBreadcrumbs) { 55 | const mergedBreadcrumb = { 56 | ...breadcrumb, 57 | level: breadcrumb.level || DEFAULT_BREADCRUMB_LEVEL, 58 | data: breadcrumb.data ? convertToNormalizedObject(breadcrumb.data) : undefined 59 | }; 60 | super.addBreadcrumb(mergedBreadcrumb, maxBreadcrumbs); 61 | const finalBreadcrumb = this._breadcrumbs[this._breadcrumbs.length - 1]; 62 | NATIVE.addBreadcrumb(finalBreadcrumb); 63 | return this; 64 | } 65 | /** 66 | * @inheritDoc 67 | */ 68 | clearBreadcrumbs() { 69 | NATIVE.clearBreadcrumbs(); 70 | return super.clearBreadcrumbs(); 71 | } 72 | /** 73 | * @inheritDoc 74 | */ 75 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 76 | setContext(key, context) { 77 | NATIVE.setContext(key, context); 78 | return super.setContext(key, context); 79 | } 80 | /** 81 | * @inheritDoc 82 | */ 83 | addAttachment(attachment) { 84 | return super.addAttachment(attachment); 85 | } 86 | /** 87 | * @inheritDoc 88 | */ 89 | clearAttachments() { 90 | return super.clearAttachments(); 91 | } 92 | } 93 | //# sourceMappingURL=scope.js.map -------------------------------------------------------------------------------- /packages/sentry/tracing/addTracingExtensions.d.ts: -------------------------------------------------------------------------------- 1 | import type { Hub, Transaction } from '@sentry/core'; 2 | import type { CustomSamplingContext, TransactionContext } from '@sentry/types'; 3 | /** 4 | * Adds React Native's extensions. Needs to be called before any transactions are created. 5 | */ 6 | export declare function _addTracingExtensions(): void; 7 | export type StartTransactionFunction = (this: Hub, transactionContext: TransactionContext, customSamplingContext?: CustomSamplingContext) => Transaction; 8 | -------------------------------------------------------------------------------- /packages/sentry/tracing/addTracingExtensions.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-duplicate-imports 2 | import { addTracingExtensions, getCurrentHub, getMainCarrier } from '@sentry/core'; 3 | import { NativescriptTracing } from './nstracing'; 4 | import { DEFAULT } from './ops'; 5 | /** 6 | * Adds React Native's extensions. Needs to be called before any transactions are created. 7 | */ 8 | export function _addTracingExtensions() { 9 | addTracingExtensions(); 10 | const carrier = getMainCarrier(); 11 | if (carrier.__SENTRY__) { 12 | carrier.__SENTRY__.extensions = carrier.__SENTRY__.extensions || {}; 13 | if (carrier.__SENTRY__.extensions.startTransaction) { 14 | const originalStartTransaction = carrier.__SENTRY__.extensions.startTransaction; 15 | /* 16 | Overwrites the transaction start and finish to start and finish stall tracking. 17 | Preferably instead of overwriting add a callback method for this in the Transaction itself. 18 | */ 19 | const _startTransaction = _patchStartTransaction(originalStartTransaction); 20 | carrier.__SENTRY__.extensions.startTransaction = _startTransaction; 21 | } 22 | } 23 | } 24 | /** 25 | * Overwrite the startTransaction extension method to start and end stall tracking. 26 | */ 27 | const _patchStartTransaction = (originalStartTransaction) => { 28 | /** 29 | * Method to overwrite with 30 | */ 31 | function _startTransaction(transactionContext, customSamplingContext) { 32 | // Native SDKs require op to be set - for JS Relay sets `default` 33 | if (!transactionContext.op) { 34 | transactionContext.op = DEFAULT; 35 | } 36 | const transaction = originalStartTransaction.apply(this, [transactionContext, customSamplingContext]); 37 | const originalStartChild = transaction.startChild.bind(transaction); 38 | transaction.startChild = (spanContext) => originalStartChild({ 39 | ...spanContext, 40 | // Native SDKs require op to be set 41 | op: spanContext?.op || DEFAULT, 42 | }); 43 | const reactNativeTracing = getCurrentHub().getIntegration(NativescriptTracing); 44 | if (reactNativeTracing) { 45 | reactNativeTracing.onTransactionStart(transaction); 46 | // eslint-disable-next-line @typescript-eslint/unbound-method 47 | const originalFinish = transaction.finish; 48 | transaction.finish = (endTimestamp) => { 49 | if (reactNativeTracing) { 50 | reactNativeTracing.onTransactionFinish(transaction); 51 | } 52 | return originalFinish.apply(transaction, [endTimestamp]); 53 | }; 54 | } 55 | return transaction; 56 | } 57 | return _startTransaction; 58 | }; 59 | //# sourceMappingURL=addTracingExtensions.js.map -------------------------------------------------------------------------------- /packages/sentry/tracing/index.d.ts: -------------------------------------------------------------------------------- 1 | export { NativescriptTracing } from './nstracing'; 2 | export { RoutingInstrumentation, RoutingInstrumentationInstance, } from './routingInstrumentation'; 3 | -------------------------------------------------------------------------------- /packages/sentry/tracing/index.js: -------------------------------------------------------------------------------- 1 | export { NativescriptTracing } from './nstracing'; 2 | export { RoutingInstrumentation, } from './routingInstrumentation'; 3 | // export { 4 | // ReactNavigationInstrumentation, 5 | // // eslint-disable-next-line deprecation/deprecation 6 | // ReactNavigationV5Instrumentation, 7 | // } from './reactnavigation'; 8 | // export { ReactNavigationV4Instrumentation } from './reactnavigationv4'; 9 | // export { NativescriptNavigationInstrumentation } from './reactnativenavigation'; 10 | // export { 11 | // ReactNavigationCurrentRoute, 12 | // ReactNavigationRoute, 13 | // ReactNavigationTransactionContext, 14 | // } from './types'; 15 | // export { NativescriptProfiler } from './reactnativeprofiler'; 16 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /packages/sentry/tracing/nativeframes.d.ts: -------------------------------------------------------------------------------- 1 | import { Transaction } from '@sentry/tracing'; 2 | import { EventProcessor, MeasurementUnit, Measurements } from '@sentry/types'; 3 | export interface NativeFramesResponse { 4 | totalFrames: number; 5 | slowFrames: number; 6 | frozenFrames: number; 7 | } 8 | export interface FramesMeasurements extends Measurements { 9 | frames_total: { 10 | value: number; 11 | unit: MeasurementUnit; 12 | }; 13 | frames_slow: { 14 | value: number; 15 | unit: MeasurementUnit; 16 | }; 17 | frames_frozen: { 18 | value: number; 19 | unit: MeasurementUnit; 20 | }; 21 | } 22 | /** 23 | * Instrumentation to add native slow/frozen frames measurements onto transactions. 24 | */ 25 | export declare class NativeFramesInstrumentation { 26 | /** The native frames at the transaction finish time, keyed by traceId. */ 27 | private _finishFrames; 28 | /** The listeners for each native frames response, keyed by traceId */ 29 | private _framesListeners; 30 | /** The native frames at the finish time of the most recent span. */ 31 | private _lastSpanFinishFrames?; 32 | constructor(addGlobalEventProcessor: (e: EventProcessor) => void, doesExist: () => boolean); 33 | /** 34 | * To be called when a transaction is started. 35 | * Logs the native frames at this start point and instruments child span finishes. 36 | */ 37 | onTransactionStart(transaction: Transaction): void; 38 | /** 39 | * To be called when a transaction is finished 40 | */ 41 | onTransactionFinish(transaction: Transaction): void; 42 | /** 43 | * Called on a span finish to fetch native frames to support transactions with trimEnd. 44 | * Only to be called when a span does not have an end timestamp. 45 | */ 46 | private _onSpanFinish; 47 | /** 48 | * Returns the computed frames measurements and awaits for them if they are not ready yet. 49 | */ 50 | private _getFramesMeasurements; 51 | /** 52 | * Returns the computed frames measurements given ready data 53 | */ 54 | private _prepareMeasurements; 55 | /** 56 | * Fetch finish frames for a transaction at the current time. Calls any awaiting listeners. 57 | */ 58 | private _fetchFramesForTransaction; 59 | /** 60 | * On a finish frames failure, we cancel the await. 61 | */ 62 | private _cancelFinishFrames; 63 | /** 64 | * Adds frames measurements to an event. Called from a valid event processor. 65 | * Awaits for finish frames if needed. 66 | */ 67 | private _processEvent; 68 | } 69 | -------------------------------------------------------------------------------- /packages/sentry/tracing/ops.d.ts: -------------------------------------------------------------------------------- 1 | export declare const DEFAULT = "default"; 2 | export declare const NAVIGATION = "navigation"; 3 | export declare const UI_LOAD = "ui.load"; 4 | export declare const UI_ACTION = "ui.action"; 5 | export declare const UI_ACTION_TOUCH = "ui.action.touch"; 6 | export declare const APP_START_COLD = "app.start.cold"; 7 | export declare const APP_START_WARM = "app.start.warm"; 8 | -------------------------------------------------------------------------------- /packages/sentry/tracing/ops.js: -------------------------------------------------------------------------------- 1 | export const DEFAULT = 'default'; 2 | export const NAVIGATION = 'navigation'; 3 | export const UI_LOAD = 'ui.load'; 4 | export const UI_ACTION = 'ui.action'; 5 | export const UI_ACTION_TOUCH = 'ui.action.touch'; 6 | export const APP_START_COLD = 'app.start.cold'; 7 | export const APP_START_WARM = 'app.start.warm'; 8 | //# sourceMappingURL=ops.js.map -------------------------------------------------------------------------------- /packages/sentry/tracing/routingInstrumentation.d.ts: -------------------------------------------------------------------------------- 1 | import { Hub } from '@sentry/hub'; 2 | import { Transaction, TransactionContext } from '@sentry/types'; 3 | import { BeforeNavigate } from './types'; 4 | export type TransactionCreator = (context: TransactionContext) => Transaction | undefined; 5 | export type OnConfirmRoute = (context: TransactionContext) => void; 6 | export interface RoutingInstrumentationInstance { 7 | /** 8 | * Name of the routing instrumentation 9 | */ 10 | readonly name: string; 11 | /** 12 | * Registers a listener that's called on every route change with a `TransactionContext`. 13 | * 14 | * Do not overwrite this unless you know what you are doing. 15 | * 16 | * @param listener A `RouteListener` 17 | * @param beforeNavigate BeforeNavigate 18 | * @param inConfirmRoute OnConfirmRoute 19 | */ 20 | registerRoutingInstrumentation(listener: TransactionCreator, beforeNavigate: BeforeNavigate, onConfirmRoute: OnConfirmRoute): void; 21 | /** 22 | * To be called when the route changes, BEFORE the new route mounts. 23 | * If this is called after a route mounts the child spans will not be correctly attached. 24 | * 25 | * @param context A `TransactionContext` used to initialize the transaction. 26 | */ 27 | onRouteWillChange(context: TransactionContext): Transaction | undefined; 28 | } 29 | /** 30 | * Base Routing Instrumentation. Can be used by users to manually instrument custom routers. 31 | * Pass this to the tracing integration, and call `onRouteWillChange` every time before a route changes. 32 | */ 33 | export declare class RoutingInstrumentation implements RoutingInstrumentationInstance { 34 | static instrumentationName: string; 35 | readonly name: string; 36 | protected _getCurrentHub?: () => Hub; 37 | protected _beforeNavigate?: BeforeNavigate; 38 | protected _onConfirmRoute?: OnConfirmRoute; 39 | protected _tracingListener?: TransactionCreator; 40 | /** @inheritdoc */ 41 | registerRoutingInstrumentation(listener: TransactionCreator, beforeNavigate: BeforeNavigate, onConfirmRoute: OnConfirmRoute): void; 42 | /** @inheritdoc */ 43 | onRouteWillChange(context: TransactionContext): Transaction | undefined; 44 | } 45 | /** 46 | * Internal base routing instrumentation where `_onConfirmRoute` is not called in onRouteWillChange 47 | */ 48 | export declare class InternalRoutingInstrumentation extends RoutingInstrumentation { 49 | /** @inheritdoc */ 50 | onRouteWillChange(context: TransactionContext): Transaction | undefined; 51 | } 52 | -------------------------------------------------------------------------------- /packages/sentry/tracing/routingInstrumentation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Base Routing Instrumentation. Can be used by users to manually instrument custom routers. 3 | * Pass this to the tracing integration, and call `onRouteWillChange` every time before a route changes. 4 | */ 5 | export class RoutingInstrumentation { 6 | constructor() { 7 | this.name = RoutingInstrumentation.instrumentationName; 8 | } 9 | /** @inheritdoc */ 10 | registerRoutingInstrumentation(listener, beforeNavigate, onConfirmRoute) { 11 | this._tracingListener = listener; 12 | this._beforeNavigate = beforeNavigate; 13 | this._onConfirmRoute = onConfirmRoute; 14 | } 15 | /** @inheritdoc */ 16 | onRouteWillChange(context) { 17 | const transaction = this._tracingListener?.(context); 18 | if (transaction) { 19 | this._onConfirmRoute?.(context); 20 | } 21 | return transaction; 22 | } 23 | } 24 | RoutingInstrumentation.instrumentationName = 'base-routing-instrumentation'; 25 | /** 26 | * Internal base routing instrumentation where `_onConfirmRoute` is not called in onRouteWillChange 27 | */ 28 | export class InternalRoutingInstrumentation extends RoutingInstrumentation { 29 | /** @inheritdoc */ 30 | onRouteWillChange(context) { 31 | return this._tracingListener?.(context); 32 | } 33 | } 34 | //# sourceMappingURL=routingInstrumentation.js.map -------------------------------------------------------------------------------- /packages/sentry/tracing/stalltracking.d.ts: -------------------------------------------------------------------------------- 1 | import { IdleTransaction, Transaction } from '@sentry/tracing'; 2 | import { MeasurementUnit, Measurements } from '@sentry/types'; 3 | export interface StallMeasurements extends Measurements { 4 | 'stall_count': { 5 | value: number; 6 | unit: MeasurementUnit; 7 | }; 8 | 'stall_total_time': { 9 | value: number; 10 | unit: MeasurementUnit; 11 | }; 12 | 'stall_longest_time': { 13 | value: number; 14 | unit: MeasurementUnit; 15 | }; 16 | } 17 | export interface StallTrackingOptions { 18 | /** 19 | * How long in milliseconds an event loop iteration can be delayed for before being considered a "stall." 20 | * @default 100 21 | */ 22 | minimumStallThreshold: number; 23 | } 24 | /** 25 | * Stall measurement tracker inspired by the `JSEventLoopWatchdog` used internally in React Native: 26 | * https://github.com/facebook/react-native/blob/006f5afe120c290a37cf6ff896748fbc062bf7ed/Libraries/Interaction/JSEventLoopWatchdog.js 27 | * 28 | * However, we modified the interval implementation to instead have a fixed loop timeout interval of `LOOP_TIMEOUT_INTERVAL_MS`. 29 | * We then would consider that iteration a stall when the total time for that interval to run is greater than `LOOP_TIMEOUT_INTERVAL_MS + minimumStallThreshold` 30 | */ 31 | export declare class StallTrackingInstrumentation { 32 | isTracking: boolean; 33 | private _minimumStallThreshold; 34 | /** Total amount of time of all stalls that occurred during the current tracking session */ 35 | private _totalStallTime; 36 | /** Total number of stalls that occurred during the current tracking session */ 37 | private _stallCount; 38 | /** The last timestamp the iteration ran in milliseconds */ 39 | private _lastIntervalMs; 40 | private _timeout; 41 | private _statsByTransaction; 42 | constructor(options?: StallTrackingOptions); 43 | /** 44 | * @inheritDoc 45 | * Not used for this integration. Instead call `registerTransactionStart` to start tracking. 46 | */ 47 | setupOnce(): void; 48 | /** 49 | * Register a transaction as started. Starts stall tracking if not already running. 50 | * @returns A finish method that returns the stall measurements. 51 | */ 52 | onTransactionStart(transaction: Transaction): void; 53 | /** 54 | * Logs a transaction as finished. 55 | * Stops stall tracking if no more transactions are running. 56 | * @returns The stall measurements 57 | */ 58 | onTransactionFinish(transaction: Transaction | IdleTransaction, passedEndTimestamp?: number): void; 59 | /** 60 | * Logs the finish time of the span for use in `trimEnd: true` transactions. 61 | */ 62 | private _markSpanFinish; 63 | /** 64 | * Get the current stats for a transaction at a given time. 65 | */ 66 | private _getCurrentStats; 67 | /** 68 | * Start tracking stalls 69 | */ 70 | private _startTracking; 71 | /** 72 | * Stops the stall tracking interval and calls reset(). 73 | */ 74 | private _stopTracking; 75 | /** 76 | * Will stop tracking if there are no more transactions. 77 | */ 78 | private _shouldStopTracking; 79 | /** 80 | * Clears all the collected stats 81 | */ 82 | private _reset; 83 | /** 84 | * Iteration of the stall tracking interval. Measures how long the timer strayed from its expected time of running, and how 85 | * long the stall is for. 86 | */ 87 | private _iteration; 88 | /** 89 | * Deletes leaked transactions (Earliest transactions when we have more than MAX_RUNNING_TRANSACTIONS transactions.) 90 | */ 91 | private _flushLeakedTransactions; 92 | } 93 | -------------------------------------------------------------------------------- /packages/sentry/tracing/transaction.d.ts: -------------------------------------------------------------------------------- 1 | import { type BeforeFinishCallback, type IdleTransaction } from '@sentry/core'; 2 | /** 3 | * Idle Transaction callback to only sample transactions with child spans. 4 | * To avoid side effects of other callbacks this should be hooked as the last callback. 5 | */ 6 | export declare const onlySampleIfChildSpans: BeforeFinishCallback; 7 | /** 8 | * Hooks on AppState change to cancel the transaction if the app goes background. 9 | */ 10 | export declare const cancelInBackground: (transaction: IdleTransaction) => void; 11 | -------------------------------------------------------------------------------- /packages/sentry/tracing/transaction.js: -------------------------------------------------------------------------------- 1 | import { Application } from '@nativescript/core'; 2 | import { logger } from '@sentry/utils'; 3 | // import type { AppStateStatus } from 'react-native'; 4 | // import { AppState } from 'react-native'; 5 | /** 6 | * Idle Transaction callback to only sample transactions with child spans. 7 | * To avoid side effects of other callbacks this should be hooked as the last callback. 8 | */ 9 | export const onlySampleIfChildSpans = (transaction) => { 10 | const spansCount = transaction.spanRecorder && 11 | transaction.spanRecorder.spans.filter(span => span.spanId !== transaction.spanId).length; 12 | if (!spansCount || spansCount <= 0) { 13 | logger.log(`Not sampling as ${transaction.op} transaction has no child spans.`); 14 | transaction.sampled = false; 15 | } 16 | }; 17 | /** 18 | * Hooks on AppState change to cancel the transaction if the app goes background. 19 | */ 20 | export const cancelInBackground = (transaction) => { 21 | function onBackground() { 22 | logger.debug(`Setting ${transaction.op} transaction to cancelled because the app is in the background.`); 23 | transaction.setStatus('cancelled'); 24 | transaction.finish(); 25 | } 26 | Application.on(Application.backgroundEvent, onBackground); 27 | // const subscription = AppState.addEventListener('change', (newState: AppStateStatus) => { 28 | // if (newState === 'background') { 29 | // } 30 | // }); 31 | transaction.registerBeforeFinishCallback(() => { 32 | logger.debug(`Removing AppState listener for ${transaction.op} transaction.`); 33 | Application.off(Application.backgroundEvent, onBackground); 34 | }); 35 | }; 36 | //# sourceMappingURL=transaction.js.map -------------------------------------------------------------------------------- /packages/sentry/tracing/types.d.ts: -------------------------------------------------------------------------------- 1 | import { TransactionContext } from '@sentry/types'; 2 | export interface RouteChangeContextData { 3 | previousRoute?: { 4 | [key: string]: unknown; 5 | name: string; 6 | } | null; 7 | route: { 8 | [key: string]: unknown; 9 | name: string; 10 | hasBeenSeen: boolean; 11 | }; 12 | } 13 | export type BeforeNavigate = (context: TransactionContext) => TransactionContext; 14 | -------------------------------------------------------------------------------- /packages/sentry/tracing/types.js: -------------------------------------------------------------------------------- 1 | export {}; 2 | //# sourceMappingURL=types.js.map -------------------------------------------------------------------------------- /packages/sentry/tracing/utils.d.ts: -------------------------------------------------------------------------------- 1 | import { IdleTransaction, Span, Transaction } from '@sentry/tracing'; 2 | import { TransactionContext, TransactionSource } from '@sentry/types'; 3 | export declare const defaultTransactionSource: TransactionSource; 4 | export declare const customTransactionSource: TransactionSource; 5 | export declare const getBlankTransactionContext: (name: string) => TransactionContext; 6 | /** 7 | * A margin of error of 50ms is allowed for the async native bridge call. 8 | * Anything larger would reduce the accuracy of our frames measurements. 9 | */ 10 | export declare const MARGIN_OF_ERROR_SECONDS = 0.05; 11 | /** 12 | * 13 | */ 14 | export declare function adjustTransactionDuration(maxDuration: number, // in seconds 15 | transaction: IdleTransaction, endTimestamp: number): void; 16 | /** 17 | * Returns the timestamp where the JS global scope was initialized. 18 | */ 19 | export declare function getTimeOriginMilliseconds(): number; 20 | /** 21 | * Calls the callback every time a child span of the transaction is finished. 22 | */ 23 | export declare function instrumentChildSpanFinish(transaction: Transaction, callback: (span: Span, endTimestamp?: number) => void): void; 24 | /** 25 | * Determines if the timestamp is now or within the specified margin of error from now. 26 | */ 27 | export declare function isNearToNow(timestamp: number): boolean; 28 | -------------------------------------------------------------------------------- /packages/sentry/tracing/utils.js: -------------------------------------------------------------------------------- 1 | import { timestampInSeconds } from '@sentry/utils'; 2 | export const defaultTransactionSource = 'component'; 3 | export const customTransactionSource = 'custom'; 4 | export const getBlankTransactionContext = (name) => ({ 5 | name: 'Route Change', 6 | op: 'navigation', 7 | tags: { 8 | 'routing.instrumentation': name, 9 | }, 10 | data: {}, 11 | metadata: { 12 | source: defaultTransactionSource, 13 | }, 14 | }); 15 | /** 16 | * A margin of error of 50ms is allowed for the async native bridge call. 17 | * Anything larger would reduce the accuracy of our frames measurements. 18 | */ 19 | export const MARGIN_OF_ERROR_SECONDS = 0.05; 20 | const timeOriginMilliseconds = Date.now(); 21 | /** 22 | * Converts from seconds to milliseconds 23 | * @param time time in seconds 24 | */ 25 | function secToMs(time) { 26 | return time * 1000; 27 | } 28 | /** 29 | * 30 | */ 31 | export function adjustTransactionDuration(maxDuration, // in seconds 32 | transaction, endTimestamp) { 33 | const diff = endTimestamp - transaction.startTimestamp; 34 | const isOutdatedTransaction = endTimestamp && (diff > secToMs(maxDuration) || diff < 0); 35 | if (isOutdatedTransaction) { 36 | transaction.setStatus('deadline_exceeded'); 37 | transaction.setTag('maxTransactionDurationExceeded', 'true'); 38 | } 39 | } 40 | /** 41 | * Returns the timestamp where the JS global scope was initialized. 42 | */ 43 | export function getTimeOriginMilliseconds() { 44 | return timeOriginMilliseconds; 45 | } 46 | /** 47 | * Calls the callback every time a child span of the transaction is finished. 48 | */ 49 | export function instrumentChildSpanFinish(transaction, callback) { 50 | if (transaction.spanRecorder) { 51 | // eslint-disable-next-line @typescript-eslint/unbound-method 52 | const originalAdd = transaction.spanRecorder.add; 53 | transaction.spanRecorder.add = (span) => { 54 | originalAdd.apply(transaction.spanRecorder, [span]); 55 | // eslint-disable-next-line @typescript-eslint/unbound-method 56 | const originalSpanFinish = span.finish; 57 | span.finish = (endTimestamp) => { 58 | originalSpanFinish.apply(span, [endTimestamp]); 59 | callback(span, endTimestamp); 60 | }; 61 | }; 62 | } 63 | } 64 | /** 65 | * Determines if the timestamp is now or within the specified margin of error from now. 66 | */ 67 | export function isNearToNow(timestamp) { 68 | return Math.abs(timestampInSeconds() - timestamp) <= MARGIN_OF_ERROR_SECONDS; 69 | } 70 | //# sourceMappingURL=utils.js.map -------------------------------------------------------------------------------- /packages/sentry/transports/TextEncoder.d.ts: -------------------------------------------------------------------------------- 1 | import { TextEncoderInternal } from '@sentry/types'; 2 | export declare const makeUtf8TextEncoder: () => TextEncoderInternal; 3 | -------------------------------------------------------------------------------- /packages/sentry/transports/TextEncoder.js: -------------------------------------------------------------------------------- 1 | import { utf8ToBytes } from '../vendor'; 2 | export const makeUtf8TextEncoder = () => { 3 | const textEncoder = { 4 | encode: (text) => 5 | // const bytes = new Uint8Array(NATIVE.utf8ToBytes(text)); 6 | // NATIVE.utf8ToBytes(text) 7 | new Uint8Array(utf8ToBytes(text)), 8 | encoding: 'utf-8', 9 | }; 10 | return textEncoder; 11 | }; 12 | //# sourceMappingURL=TextEncoder.js.map -------------------------------------------------------------------------------- /packages/sentry/transports/native.d.ts: -------------------------------------------------------------------------------- 1 | import { BaseTransportOptions, Envelope, Transport } from '@sentry/types'; 2 | import { PromiseBuffer } from '@sentry/utils'; 3 | export declare const DEFAULT_BUFFER_SIZE = 30; 4 | export type BaseNativeTransport = BaseTransportOptions; 5 | export interface BaseNativeTransportOptions { 6 | bufferSize?: number; 7 | } 8 | /** Native Transport class implementation */ 9 | export declare class NativeTransport implements Transport { 10 | /** A simple buffer holding all requests. */ 11 | protected readonly _buffer: PromiseBuffer; 12 | constructor(options?: BaseNativeTransportOptions); 13 | /** 14 | * Sends the envelope to the Store endpoint in Sentry. 15 | * 16 | * @param envelope Envelope that should be sent to Sentry. 17 | */ 18 | send(envelope: Envelope): PromiseLike; 19 | /** 20 | * Wait for all envelopes to be sent or the timeout to expire, whichever comes first. 21 | * 22 | * @param timeout Maximum time in ms the transport should wait for envelopes to be flushed. Omitting this parameter will 23 | * cause the transport to wait until all events are sent before resolving the promise. 24 | * @returns A promise that will resolve with `true` if all events are sent before the timeout, or `false` if there are 25 | * still events in the queue when the timeout is reached. 26 | */ 27 | flush(timeout?: number): PromiseLike; 28 | } 29 | /** 30 | * Creates a Native Transport. 31 | */ 32 | export declare function makeNativescriptTransport(options?: BaseNativeTransportOptions): NativeTransport; 33 | -------------------------------------------------------------------------------- /packages/sentry/transports/native.js: -------------------------------------------------------------------------------- 1 | import { makePromiseBuffer } from '@sentry/utils'; 2 | import { NATIVE } from '../wrapper'; 3 | export const DEFAULT_BUFFER_SIZE = 30; 4 | /** Native Transport class implementation */ 5 | export class NativeTransport { 6 | constructor(options = {}) { 7 | this._buffer = makePromiseBuffer(options.bufferSize || DEFAULT_BUFFER_SIZE); 8 | } 9 | /** 10 | * Sends the envelope to the Store endpoint in Sentry. 11 | * 12 | * @param envelope Envelope that should be sent to Sentry. 13 | */ 14 | send(envelope) { 15 | return this._buffer.add(() => NATIVE.sendEnvelope(envelope)); 16 | } 17 | /** 18 | * Wait for all envelopes to be sent or the timeout to expire, whichever comes first. 19 | * 20 | * @param timeout Maximum time in ms the transport should wait for envelopes to be flushed. Omitting this parameter will 21 | * cause the transport to wait until all events are sent before resolving the promise. 22 | * @returns A promise that will resolve with `true` if all events are sent before the timeout, or `false` if there are 23 | * still events in the queue when the timeout is reached. 24 | */ 25 | flush(timeout) { 26 | return this._buffer.drain(timeout); 27 | } 28 | } 29 | /** 30 | * Creates a Native Transport. 31 | */ 32 | export function makeNativescriptTransport(options = {}) { return new NativeTransport(options); } 33 | //# sourceMappingURL=native.js.map -------------------------------------------------------------------------------- /packages/sentry/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "../../src/sentry", 5 | "outDir": "./" 6 | }, 7 | "include": ["../../src/sentry/**/*", "../../references.d.ts", "../../tools/references.d.ts", "../../src/references.d.ts"], 8 | "exclude": ["node_modules", "node_modules", "../../src/sentry/hooks"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/sentry/utils/environment.d.ts: -------------------------------------------------------------------------------- 1 | /** Returns default environment based on __DEV__ */ 2 | export declare function getDefaultEnvironment(): 'development' | 'production'; 3 | -------------------------------------------------------------------------------- /packages/sentry/utils/environment.js: -------------------------------------------------------------------------------- 1 | /** Returns default environment based on __DEV__ */ 2 | export function getDefaultEnvironment() { 3 | return typeof __DEV__ !== 'undefined' && __DEV__ ? 'development' : 'production'; 4 | } 5 | //# sourceMappingURL=environment.js.map -------------------------------------------------------------------------------- /packages/sentry/utils/outcome.d.ts: -------------------------------------------------------------------------------- 1 | import { Outcome } from '@sentry/types'; 2 | /** 3 | * Merges buffer with new outcomes. 4 | */ 5 | export declare function mergeOutcomes(...merge: Outcome[][]): Outcome[]; 6 | -------------------------------------------------------------------------------- /packages/sentry/utils/outcome.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Merges buffer with new outcomes. 3 | */ 4 | export function mergeOutcomes(...merge) { 5 | const map = new Map(); 6 | const process = (outcome) => { 7 | const key = `${outcome.reason}:${outcome.category}`; 8 | const existing = map.get(key); 9 | if (existing) { 10 | existing.quantity += outcome.quantity; 11 | } 12 | else { 13 | map.set(key, outcome); 14 | } 15 | }; 16 | merge.forEach((outcomes) => outcomes.forEach(process)); 17 | return [...map.values()]; 18 | } 19 | //# sourceMappingURL=outcome.js.map -------------------------------------------------------------------------------- /packages/sentry/utils/safe.d.ts: -------------------------------------------------------------------------------- 1 | import { NativescriptOptions } from '../options'; 2 | type DangerTypesWithoutCallSignature = Object | null | undefined; 3 | /** 4 | * Returns callback factory wrapped with try/catch 5 | * or the original passed value is it's not a function. 6 | * 7 | * If the factory fails original data are returned as it. 8 | * They might be partially modified by the failed function. 9 | */ 10 | export declare function safeFactory(danger: ((...args: A) => R) | T, options?: { 11 | loggerMessage?: string; 12 | }): ((...args: A) => R) | T; 13 | /** 14 | * Returns sage tracesSampler that returns 0 if the original failed. 15 | */ 16 | export declare function safeTracesSampler(tracesSampler: NativescriptOptions['tracesSampler']): NativescriptOptions['tracesSampler']; 17 | export {}; 18 | -------------------------------------------------------------------------------- /packages/sentry/utils/safe.js: -------------------------------------------------------------------------------- 1 | import { logger } from '@sentry/utils'; 2 | /** 3 | * Returns callback factory wrapped with try/catch 4 | * or the original passed value is it's not a function. 5 | * 6 | * If the factory fails original data are returned as it. 7 | * They might be partially modified by the failed function. 8 | */ 9 | export function safeFactory(danger, options = {}) { 10 | if (typeof danger === 'function') { 11 | return (...args) => { 12 | try { 13 | return danger(...args); 14 | } 15 | catch (error) { 16 | logger.error(options.loggerMessage 17 | ? options.loggerMessage 18 | : `The ${danger.name} callback threw an error`, error); 19 | return args[0]; 20 | } 21 | }; 22 | } 23 | else { 24 | return danger; 25 | } 26 | } 27 | /** 28 | * Returns sage tracesSampler that returns 0 if the original failed. 29 | */ 30 | export function safeTracesSampler(tracesSampler) { 31 | if (tracesSampler) { 32 | return (...args) => { 33 | try { 34 | return tracesSampler(...args); 35 | } 36 | catch (error) { 37 | logger.error('The tracesSampler callback threw an error', error); 38 | return 0; 39 | } 40 | }; 41 | } 42 | else { 43 | return tracesSampler; 44 | } 45 | } 46 | //# sourceMappingURL=safe.js.map -------------------------------------------------------------------------------- /packages/sentry/vendor/buffer/index.d.ts: -------------------------------------------------------------------------------- 1 | export { utf8ToBytes, } from './utf8ToBytes'; 2 | -------------------------------------------------------------------------------- /packages/sentry/vendor/buffer/index.js: -------------------------------------------------------------------------------- 1 | export { utf8ToBytes, } from './utf8ToBytes'; 2 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /packages/sentry/vendor/buffer/utf8ToBytes.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Convert a string to a byte array 3 | * 4 | * This is a utf8ToBytes function from the buffer module (with added types) 5 | * https://github.com/feross/buffer/blob/795bbb5bda1b39f1370ebd784bea6107b087e3a7/index.js#L1956 6 | * 7 | * License: MIT (https://github.com/feross/buffer) 8 | */ 9 | export declare function utf8ToBytes(string: string, units?: number): number[]; 10 | -------------------------------------------------------------------------------- /packages/sentry/vendor/buffer/utf8ToBytes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Convert a string to a byte array 3 | * 4 | * This is a utf8ToBytes function from the buffer module (with added types) 5 | * https://github.com/feross/buffer/blob/795bbb5bda1b39f1370ebd784bea6107b087e3a7/index.js#L1956 6 | * 7 | * License: MIT (https://github.com/feross/buffer) 8 | */ 9 | export function utf8ToBytes(string, units) { 10 | units = units || Infinity; 11 | let codePoint; 12 | const length = string.length; 13 | let leadSurrogate = null; 14 | const bytes = []; 15 | for (let i = 0; i < length; ++i) { 16 | codePoint = string.charCodeAt(i); 17 | // is surrogate component 18 | if (codePoint > 0xD7FF && codePoint < 0xE000) { 19 | // last char was a lead 20 | if (!leadSurrogate) { 21 | // no lead yet 22 | if (codePoint > 0xDBFF) { 23 | // unexpected trail 24 | if ((units -= 3) > -1) 25 | bytes.push(0xEF, 0xBF, 0xBD); 26 | continue; 27 | } 28 | else if (i + 1 === length) { 29 | // unpaired lead 30 | if ((units -= 3) > -1) 31 | bytes.push(0xEF, 0xBF, 0xBD); 32 | continue; 33 | } 34 | // valid lead 35 | leadSurrogate = codePoint; 36 | continue; 37 | } 38 | // 2 leads in a row 39 | if (codePoint < 0xDC00) { 40 | if ((units -= 3) > -1) 41 | bytes.push(0xEF, 0xBF, 0xBD); 42 | leadSurrogate = codePoint; 43 | continue; 44 | } 45 | // valid surrogate pair 46 | codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000; 47 | } 48 | else if (leadSurrogate) { 49 | // valid bmp char, but last char was a lead 50 | if ((units -= 3) > -1) 51 | bytes.push(0xEF, 0xBF, 0xBD); 52 | } 53 | leadSurrogate = null; 54 | // encode utf8 55 | if (codePoint < 0x80) { 56 | if ((units -= 1) < 0) 57 | break; 58 | bytes.push(codePoint); 59 | } 60 | else if (codePoint < 0x800) { 61 | if ((units -= 2) < 0) 62 | break; 63 | bytes.push(codePoint >> 0x6 | 0xC0, codePoint & 0x3F | 0x80); 64 | } 65 | else if (codePoint < 0x10000) { 66 | if ((units -= 3) < 0) 67 | break; 68 | bytes.push(codePoint >> 0xC | 0xE0, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80); 69 | } 70 | else if (codePoint < 0x110000) { 71 | if ((units -= 4) < 0) 72 | break; 73 | bytes.push(codePoint >> 0x12 | 0xF0, codePoint >> 0xC & 0x3F | 0x80, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80); 74 | } 75 | else { 76 | throw new Error('Invalid code point'); 77 | } 78 | } 79 | return bytes; 80 | } 81 | //# sourceMappingURL=utf8ToBytes.js.map -------------------------------------------------------------------------------- /packages/sentry/vendor/index.d.ts: -------------------------------------------------------------------------------- 1 | export { utf8ToBytes, } from './buffer'; 2 | -------------------------------------------------------------------------------- /packages/sentry/vendor/index.js: -------------------------------------------------------------------------------- 1 | export { utf8ToBytes, } from './buffer'; 2 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /packages/sentry/version.d.ts: -------------------------------------------------------------------------------- 1 | export declare const SDK_PACKAGE_NAME = "npm:@nativescript-community/sentry"; 2 | export declare const SDK_NAME = "sentry.nativescript"; 3 | export declare const SDK_VERSION: any; 4 | -------------------------------------------------------------------------------- /packages/sentry/version.js: -------------------------------------------------------------------------------- 1 | export const SDK_PACKAGE_NAME = 'npm:@nativescript-community/sentry'; 2 | export const SDK_NAME = 'sentry.nativescript'; 3 | export const SDK_VERSION = require('./package.json').version; 4 | //# sourceMappingURL=version.js.map -------------------------------------------------------------------------------- /packages/sentry/wrapper.android.d.ts: -------------------------------------------------------------------------------- 1 | import { Breadcrumb, Envelope, User } from '@sentry/types'; 2 | import { NativescriptOptions } from './options'; 3 | export declare namespace NATIVE { 4 | function isNativeTransportAvailable(): boolean; 5 | function sendEnvelope(envelope: Envelope): Promise; 6 | function prepareEnvelope(envelope: Envelope): number[]; 7 | function prepareEnvelopeNative(envelope: Envelope): Uint8Array; 8 | function captureEnvelope(envelope: string | Uint8Array | number[], { store }?: { 9 | store?: boolean; 10 | }): Promise; 11 | function flush(timeout?: number): void; 12 | function initNativeSdk(originalOptions?: NativescriptOptions): Promise; 13 | function disableNativeFramesTracking(): void; 14 | function enableNativeFramesTracking(): void; 15 | function fetchNativeSdkInfo(): { 16 | name: string; 17 | version: string; 18 | }; 19 | function fetchNativeRelease(): any; 20 | function closeNativeSdk(): Promise; 21 | function nativeCrash(): void; 22 | function fetchNativeDeviceContexts(): Promise; 23 | function captureScreenshot(fileName?: string): { 24 | contentType: string; 25 | data: Uint8Array; 26 | filename: string; 27 | }[]; 28 | function fetchNativeFrames(): Promise<{ 29 | totalFrames: number; 30 | slowFrames: number; 31 | frozenFrames: number; 32 | }>; 33 | function fetchNativeAppStart(): Promise<{ 34 | appStartTime: number; 35 | isColdStart: java.lang.Boolean; 36 | didFetchAppStart: boolean; 37 | }>; 38 | function setUser(user: User | null, otherUserKeys: any): void; 39 | function setTag(key: string, value: string): void; 40 | function setExtra(key: string, extra: any): void; 41 | function addBreadcrumb(breadcrumb: Breadcrumb, maxBreadcrumbs?: number): void; 42 | function clearBreadcrumbs(): void; 43 | function setContext(key: string, context: { 44 | [key: string]: any; 45 | } | null): void; 46 | function crashedLastRun(): Promise; 47 | } 48 | -------------------------------------------------------------------------------- /packages/sentry/wrapper.d.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Attachment, 3 | AttachmentItem, 4 | BaseEnvelopeItemHeaders, 5 | Breadcrumb, 6 | ClientReportItem, 7 | Envelope, 8 | Event, 9 | EventItem, 10 | Package, 11 | SessionItem, 12 | SeverityLevel, 13 | User, 14 | UserFeedbackItem 15 | } from '@sentry/types'; 16 | import { NativescriptOptions } from './options'; 17 | import { SentryError, logger } from '@sentry/utils'; 18 | import { Hub, Scope } from '@sentry/core'; 19 | 20 | export interface NativeAppStartResponse { 21 | isColdStart: boolean; 22 | appStartTime: number; 23 | didFetchAppStart: boolean; 24 | } 25 | 26 | export interface NativeFramesResponse { 27 | totalFrames: number; 28 | slowFrames: number; 29 | frozenFrames: number; 30 | } 31 | 32 | export interface NativeReleaseResponse { 33 | build: string; 34 | id: string; 35 | version: string; 36 | } 37 | export interface UserFeedback { 38 | eventId: string; 39 | comments?: string; 40 | email?: string; 41 | name?: string; 42 | } 43 | /** 44 | * This type describes serialized scope from sentry-cocoa and sentry-android 45 | * https://github.com/getsentry/sentry-cocoa/blob/master/Sources/Sentry/SentryScope.m 46 | * https://github.com/getsentry/sentry-java/blob/a461f7e125b65240004e6162b341f383ce2e1394/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java#L32 47 | */ 48 | export interface NativeDeviceContextsResponse { 49 | [key: string]: unknown; 50 | tags?: Record; 51 | extra?: Record; 52 | contexts?: Record>; 53 | user?: { 54 | userId?: string; 55 | email?: string; 56 | username?: string; 57 | ipAddress?: string; 58 | segment?: string; 59 | data?: Record; 60 | }; 61 | dist?: string; 62 | environment?: string; 63 | fingerprint?: string[]; 64 | level?: string; 65 | breadcrumbs?: { 66 | level?: string; 67 | timestamp?: string; 68 | category?: string; 69 | type?: string; 70 | message?: string; 71 | data?: Record; 72 | }[]; 73 | } 74 | 75 | export interface NativeScreenshot { 76 | data: Uint8Array; 77 | contentType: string; 78 | filename: string; 79 | } 80 | 81 | export namespace NATIVE { 82 | const nativeClientAvailable: boolean; 83 | const nativeTransport: boolean; 84 | let enableNative: boolean; 85 | function sendEvent(event: Event, hint?): Promise; 86 | function sendEnvelope(envelope: Envelope): Promise; 87 | function initNativeSdk(options: NativescriptOptions): Promise; 88 | function closeNativeSdk(): Promise; 89 | function nativeCrash(); 90 | function flush(timeout: number); 91 | function fetchNativeDeviceContexts(): Promise; 92 | function captureUserFeedback(feedback: UserFeedback); 93 | function isNativeTransportAvailable(): boolean; 94 | 95 | function enableNativeFramesTracking(); 96 | function disableNativeFramesTracking(); 97 | function fetchNativeSdkInfo(): any; 98 | function fetchNativeRelease(): any; 99 | function fetchNativeFrames(): Promise<{ 100 | totalFrames; 101 | slowFrames; 102 | frozenFrames; 103 | }>; 104 | function fetchNativeAppStart(): Promise<{ 105 | isColdStart; 106 | appStartTime; 107 | didFetchAppStart; 108 | }>; 109 | 110 | function setUser(user: User | null); 111 | function setTag(key: string, value: string); 112 | 113 | function setExtra(key: string, extra: any); 114 | 115 | function addBreadcrumb(breadcrumb: Breadcrumb, maxBreadcrumbs?: number); 116 | function addAttachment(attachment: Attachment); 117 | 118 | function clearBreadcrumbs(); 119 | 120 | function setContext(key: string, context: { [key: string]: any } | null); 121 | 122 | function withScope(callback: (scope: Scope) => void): ReturnType; 123 | 124 | function utf8ToBytes(str: string): Uint8Array; 125 | 126 | function captureScreenshot(fileName?: string): NativeScreenshot[]; 127 | } 128 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - packages/* 3 | - demo-* -------------------------------------------------------------------------------- /references.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/sentry/4919940f8eae59341140b897999862de282c0934/references.d.ts -------------------------------------------------------------------------------- /src/sentry/breadcrumb.ts: -------------------------------------------------------------------------------- 1 | import type { Breadcrumb, SeverityLevel } from '@sentry/types'; 2 | import { severityLevelFromString } from '@sentry/utils'; 3 | 4 | export const DEFAULT_BREADCRUMB_LEVEL: SeverityLevel = 'info'; 5 | 6 | type BreadcrumbCandidate = { 7 | [K in keyof Partial]: unknown; 8 | }; 9 | 10 | /** 11 | * Convert plain object to a valid Breadcrumb 12 | */ 13 | export function breadcrumbFromObject(candidate: BreadcrumbCandidate): Breadcrumb { 14 | const breadcrumb: Breadcrumb = {}; 15 | 16 | if (typeof candidate.type === 'string') { 17 | breadcrumb.type = candidate.type; 18 | } 19 | if (typeof candidate.level === 'string') { 20 | breadcrumb.level = severityLevelFromString(candidate.level); 21 | } 22 | if (typeof candidate.event_id === 'string') { 23 | breadcrumb.event_id = candidate.event_id; 24 | } 25 | if (typeof candidate.category === 'string') { 26 | breadcrumb.category = candidate.category; 27 | } 28 | if (typeof candidate.message === 'string') { 29 | breadcrumb.message = candidate.message; 30 | } 31 | if (typeof candidate.data === 'object' && candidate.data !== null) { 32 | breadcrumb.data = candidate.data; 33 | } 34 | if (typeof candidate.timestamp === 'string') { 35 | const timestampSeconds = Date.parse(candidate.timestamp) / 1000; // breadcrumb timestamp is in seconds 36 | if (!isNaN(timestampSeconds)) { 37 | breadcrumb.timestamp = timestampSeconds; 38 | } 39 | } 40 | 41 | return breadcrumb; 42 | } 43 | -------------------------------------------------------------------------------- /src/sentry/index.ts: -------------------------------------------------------------------------------- 1 | export { Breadcrumb, Request, SdkInfo, Event, Exception, StackFrame, Stacktrace, Thread, User } from '@sentry/types'; 2 | 3 | export { 4 | addGlobalEventProcessor, 5 | addBreadcrumb, 6 | captureException, 7 | captureEvent, 8 | captureMessage, 9 | getHubFromCarrier, 10 | getCurrentHub, 11 | Hub, 12 | Scope, 13 | setContext, 14 | setExtra, 15 | setExtras, 16 | setTag, 17 | setTags, 18 | setUser, 19 | startTransaction 20 | } from '@sentry/core'; 21 | 22 | import { _addTracingExtensions } from './tracing/addTracingExtensions'; 23 | _addTracingExtensions(); 24 | 25 | // export { 26 | // Integrations as BrowserIntegrations, 27 | // ErrorBoundary, 28 | // withErrorBoundary, 29 | // createReduxEnhancer, 30 | // Profiler, 31 | // useProfiler, 32 | // withProfiler, 33 | // } from '@sentry/react'; 34 | 35 | import * as Integrations from './integrations'; 36 | import { SDK_NAME, SDK_VERSION } from './version'; 37 | import { Trace } from '@nativescript/core'; 38 | export { NativescriptOptions } from './options'; 39 | export { NativescriptClient } from './client'; 40 | 41 | export { init, setDist, setRelease, nativeCrash, flush, close, captureUserFeedback, withScope, crashedLastRun } from './sdk'; 42 | // export { TouchEventBoundary, withTouchEventBoundary } from './touchevents'; 43 | 44 | export { 45 | NativescriptTracing 46 | // ReactNavigationV4Instrumentation, 47 | // // eslint-disable-next-line deprecation/deprecation 48 | // ReactNavigationV5Instrumentation, 49 | // ReactNavigationInstrumentation, 50 | // NativescriptNavigationInstrumentation, 51 | // RoutingInstrumentation, 52 | // ReactNavigationTransactionContext, 53 | } from './tracing'; 54 | 55 | export { Integrations, SDK_NAME, SDK_VERSION }; 56 | 57 | export const SentryTraceCategory = 'Sentry'; 58 | 59 | export enum CLogTypes { 60 | log = Trace.messageType.log, 61 | info = Trace.messageType.info, 62 | warning = Trace.messageType.warn, 63 | error = Trace.messageType.error 64 | } 65 | 66 | export const CLog = (type: CLogTypes, ...args) => { 67 | Trace.write(args.map((a) => (a && typeof a === 'object' ? JSON.stringify(a) : a)).join(' '), SentryTraceCategory, type); 68 | }; 69 | -------------------------------------------------------------------------------- /src/sentry/integrations/devicecontext.ts: -------------------------------------------------------------------------------- 1 | import { addEventProcessor, addGlobalEventProcessor, getCurrentHub } from '@sentry/core'; 2 | import { Contexts, Event, Integration } from '@sentry/types'; 3 | import { logger, severityLevelFromString } from '@sentry/utils'; 4 | import { NATIVE, NativeDeviceContextsResponse } from '../wrapper'; 5 | 6 | import { breadcrumbFromObject } from '../breadcrumb'; 7 | import { Application } from '@nativescript/core'; 8 | 9 | /** Load device context from native. */ 10 | export class DeviceContext implements Integration { 11 | /** 12 | * @inheritDoc 13 | */ 14 | public name: string = DeviceContext.id; 15 | /** 16 | * @inheritDoc 17 | */ 18 | public static id: string = 'DeviceContext'; 19 | 20 | /** 21 | * @inheritDoc 22 | */ 23 | public setupOnce(): void { 24 | addEventProcessor(async (event: Event) => { 25 | const self = getCurrentHub().getIntegration(DeviceContext); 26 | if (!self) { 27 | return event; 28 | } 29 | 30 | let native: NativeDeviceContextsResponse | null = null; 31 | try { 32 | native = await NATIVE.fetchNativeDeviceContexts(); 33 | } catch (e) { 34 | logger.log(`Failed to get device context from native: ${e}`); 35 | } 36 | 37 | if (!native) { 38 | return event; 39 | } 40 | 41 | const nativeUser = native.user; 42 | if (!event.user && nativeUser) { 43 | event.user = nativeUser; 44 | } 45 | 46 | let nativeContexts = native.contexts; 47 | // if (AppState.currentState !== 'unknown') { 48 | nativeContexts = nativeContexts || {}; 49 | nativeContexts.app = { 50 | ...nativeContexts.app, 51 | in_foreground: !Application.inBackground 52 | }; 53 | // } 54 | if (nativeContexts) { 55 | event.contexts = { ...nativeContexts, ...event.contexts }; 56 | if (nativeContexts.app) { 57 | event.contexts.app = { ...nativeContexts.app, ...event.contexts.app }; 58 | } 59 | } 60 | 61 | const nativeTags = native.tags; 62 | if (nativeTags) { 63 | event.tags = { ...nativeTags, ...event.tags }; 64 | } 65 | 66 | const nativeExtra = native.extra; 67 | if (nativeExtra) { 68 | event.extra = { ...nativeExtra, ...event.extra }; 69 | } 70 | 71 | const nativeFingerprint = native.fingerprint; 72 | if (nativeFingerprint) { 73 | event.fingerprint = (event.fingerprint ?? []).concat(nativeFingerprint.filter((item) => (event.fingerprint ?? []).indexOf(item) < 0)); 74 | } 75 | 76 | const nativeLevel = typeof native['level'] === 'string' ? severityLevelFromString(native['level']) : undefined; 77 | if (!event.level && nativeLevel) { 78 | event.level = nativeLevel; 79 | } 80 | 81 | const nativeEnvironment = native['environment']; 82 | if (!event.environment && nativeEnvironment) { 83 | event.environment = nativeEnvironment; 84 | } 85 | 86 | const nativeBreadcrumbs = Array.isArray(native['breadcrumbs']) ? native['breadcrumbs'].map(breadcrumbFromObject) : undefined; 87 | if (nativeBreadcrumbs) { 88 | event.breadcrumbs = nativeBreadcrumbs.concat(event.breadcrumbs || []); 89 | } 90 | 91 | return event; 92 | }); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/sentry/integrations/eventorigin.ts: -------------------------------------------------------------------------------- 1 | import { EventProcessor, Integration } from '@sentry/types'; 2 | 3 | /** Default EventOrigin instrumentation */ 4 | export class EventOrigin implements Integration { 5 | /** 6 | * @inheritDoc 7 | */ 8 | public static id: string = 'EventOrigin'; 9 | 10 | /** 11 | * @inheritDoc 12 | */ 13 | public name: string = EventOrigin.id; 14 | 15 | /** 16 | * @inheritDoc 17 | */ 18 | public setupOnce(addGlobalEventProcessor: (e: EventProcessor) => void): void { 19 | addGlobalEventProcessor((event) => { 20 | event.tags = event.tags ?? {}; 21 | 22 | event.tags['event.origin'] = __ANDROID__?'android' : __IOS__ ? 'ios' : 'javascript'; 23 | event.tags['event.environment'] = 'nativescript'; 24 | 25 | return event; 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/sentry/integrations/factory.ts: -------------------------------------------------------------------------------- 1 | import type { Integration } from '@sentry/types'; 2 | 3 | /** 4 | * Creates an integration out of the provided name and setup function. 5 | * @hidden 6 | */ 7 | export function createIntegration( 8 | name: Integration['name'], 9 | setupOnce: Integration['setupOnce'] = () => { 10 | /* noop */ 11 | }, 12 | ): Integration { 13 | return { 14 | name, 15 | setupOnce, 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /src/sentry/integrations/index.ts: -------------------------------------------------------------------------------- 1 | export { DebugSymbolicator } from './debugsymbolicator'; 2 | export { DeviceContext } from './devicecontext'; 3 | export { NativescriptErrorHandlers as NativescriptErrorHandlers } from './nativescripterrorhandlers'; 4 | export { Release } from './release'; 5 | -------------------------------------------------------------------------------- /src/sentry/integrations/release.ts: -------------------------------------------------------------------------------- 1 | import { addGlobalEventProcessor, getCurrentHub } from '@sentry/core'; 2 | import { Event, Integration } from '@sentry/types'; 3 | import { NATIVE } from '../wrapper'; 4 | 5 | /** Release integration responsible to load release from file. */ 6 | export class Release implements Integration { 7 | /** 8 | * @inheritDoc 9 | */ 10 | public name: string = Release.id; 11 | /** 12 | * @inheritDoc 13 | */ 14 | public static id: string = 'Release'; 15 | 16 | /** 17 | * @inheritDoc 18 | */ 19 | public setupOnce(): void { 20 | addGlobalEventProcessor(async (event: Event) => { 21 | const self = getCurrentHub().getIntegration(Release); 22 | if (!self) { 23 | return event; 24 | } 25 | const options = getCurrentHub().getClient()?.getOptions(); 26 | /* 27 | __sentry_release and __sentry_dist is set by the user with setRelease and setDist. If this is used then this is the strongest. 28 | Otherwise we check for the release and dist in the options passed on init, as this is stronger than the release/dist from the native build. 29 | */ 30 | if (typeof event.extra?.__sentry_release === 'string') { 31 | event.release = `${event.extra.__sentry_release}`; 32 | } else if (typeof options?.release === 'string') { 33 | event.release = options.release; 34 | } 35 | 36 | if (typeof event.extra?.__sentry_dist === 'string') { 37 | event.dist = `${event.extra.__sentry_dist}`; 38 | } else if (typeof options?.dist === 'string') { 39 | event.dist = options.dist; 40 | } 41 | 42 | if (event.release && event.dist) { 43 | return event; 44 | } 45 | try { 46 | const nativeRelease = (await NATIVE.fetchNativeRelease()) as { 47 | build: string; 48 | id: string; 49 | version: string; 50 | }; 51 | if (!event.release) { 52 | event.release = `${nativeRelease.id}@${nativeRelease.version}+${nativeRelease.build}`; 53 | } 54 | if (!event.dist) { 55 | event.dist = `${nativeRelease.build}.${__IOS__ ? 'ios' : 'android'}`; 56 | } 57 | } catch (_Oo) { 58 | // Something went wrong, we just continue 59 | } 60 | return event; 61 | }); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/sentry/integrations/rewriteframe.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/sentry/4919940f8eae59341140b897999862de282c0934/src/sentry/integrations/rewriteframe.ts -------------------------------------------------------------------------------- /src/sentry/integrations/screenshot.ts: -------------------------------------------------------------------------------- 1 | import { EventHint, Integration } from '@sentry/types'; 2 | import { resolvedSyncPromise } from '@sentry/utils'; 3 | 4 | import { NATIVE } from '../wrapper'; 5 | 6 | /** Adds screenshots to error events */ 7 | export class Screenshot implements Integration { 8 | /** 9 | * @inheritDoc 10 | */ 11 | public static id: string = 'Screenshot'; 12 | 13 | /** 14 | * @inheritDoc 15 | */ 16 | public name: string = Screenshot.id; 17 | 18 | /** 19 | * If enabled attaches a screenshot to the event hint. 20 | */ 21 | public static attachScreenshotToEventHint(hint: EventHint, { attachScreenshot }: { attachScreenshot?: boolean }): EventHint { 22 | if (!attachScreenshot) { 23 | return hint; 24 | } 25 | 26 | const screenshots = NATIVE.captureScreenshot(); 27 | if (screenshots !== null && screenshots.length > 0) { 28 | hint.attachments = [...screenshots, ...(hint?.attachments || [])]; 29 | } 30 | return hint; 31 | } 32 | 33 | /** 34 | * @inheritDoc 35 | */ 36 | // eslint-disable-next-line @typescript-eslint/no-empty-function 37 | public setupOnce(): void {} 38 | } 39 | -------------------------------------------------------------------------------- /src/sentry/integrations/sdkinfo.ts: -------------------------------------------------------------------------------- 1 | import { EventProcessor, Integration, Package, SdkInfo as SdkInfoType } from '@sentry/types'; 2 | import { logger } from '@sentry/utils'; 3 | 4 | import { SDK_NAME, SDK_PACKAGE_NAME, SDK_VERSION } from '../version'; 5 | 6 | import { NATIVE } from '../wrapper'; 7 | 8 | type DefaultSdkInfo = Pick, 'name' | 'packages' | 'version'>; 9 | 10 | export const defaultSdkInfo: DefaultSdkInfo = { 11 | name: SDK_NAME, 12 | packages: [ 13 | { 14 | name: SDK_PACKAGE_NAME, 15 | version: SDK_VERSION 16 | } 17 | ], 18 | version: SDK_VERSION 19 | }; 20 | 21 | /** Default SdkInfo instrumentation */ 22 | export class SdkInfo implements Integration { 23 | /** 24 | * @inheritDoc 25 | */ 26 | public static id: string = 'SdkInfo'; 27 | 28 | /** 29 | * @inheritDoc 30 | */ 31 | public name: string = SdkInfo.id; 32 | 33 | private _nativeSdkInfo: Package | null = null; 34 | 35 | /** 36 | * @inheritDoc 37 | */ 38 | public setupOnce(addGlobalEventProcessor: (e: EventProcessor) => void): void { 39 | addGlobalEventProcessor(async (event) => { 40 | // The native SDK info package here is only used on iOS as `beforeSend` is not called on `captureEnvelope`. 41 | // this._nativeSdkInfo should be defined a following time so this call won't always be awaited. 42 | if (this._nativeSdkInfo === null) { 43 | try { 44 | this._nativeSdkInfo = await NATIVE.fetchNativeSdkInfo(); 45 | } catch (e) { 46 | // If this fails, go ahead as usual as we would rather have the event be sent with a package missing. 47 | logger.warn('[SdkInfo] Native SDK Info retrieval failed...something could be wrong with your Sentry installation:'); 48 | logger.warn(e); 49 | } 50 | } 51 | 52 | event.platform = event.platform || 'javascript'; 53 | event.sdk = { 54 | ...(event.sdk ?? {}), 55 | ...defaultSdkInfo, 56 | packages: [...((event.sdk && event.sdk.packages) || []), ...((this._nativeSdkInfo && [this._nativeSdkInfo]) || []), ...defaultSdkInfo.packages] 57 | }; 58 | return event; 59 | }); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/sentry/measurements.ts: -------------------------------------------------------------------------------- 1 | export const APP_START_WARM = 'app_start_warm'; 2 | export const APP_START_COLD = 'app_start_cold'; 3 | 4 | export const STALL_COUNT = 'stall_count'; 5 | export const STALL_TOTAL_TIME = 'stall_total_time'; 6 | export const STALL_LONGEST_TIME = 'stall_longest_time'; 7 | -------------------------------------------------------------------------------- /src/sentry/misc.ts: -------------------------------------------------------------------------------- 1 | import { EnvelopeItem, Exception } from '@sentry/types'; 2 | 3 | type EnvelopeItemPayload = EnvelopeItem[1]; 4 | 5 | /** 6 | * Extracts the hard crash information from the event exceptions. 7 | * No exceptions or undefined handled are not hard crashes. 8 | */ 9 | export function isHardCrash(payload: EnvelopeItemPayload): boolean { 10 | const values: Exception[] = typeof payload !== 'string' && 'exception' in payload && payload.exception?.values ? payload.exception.values : []; 11 | for (const exception of values) { 12 | if (!(exception.mechanism?.handled !== false)) { 13 | return true; 14 | } 15 | } 16 | return false; 17 | } 18 | -------------------------------------------------------------------------------- /src/sentry/process.ts: -------------------------------------------------------------------------------- 1 | class Process {} 2 | Process.prototype[Symbol.toStringTag] = 'process'; 3 | 4 | module.exports = global.process = new Process() as any; 5 | -------------------------------------------------------------------------------- /src/sentry/references.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable spaced-comment */ 2 | /// 3 | /// 4 | /// 5 | 6 | declare const TNS_ENV: string; 7 | -------------------------------------------------------------------------------- /src/sentry/scope.ts: -------------------------------------------------------------------------------- 1 | import { Scope } from '@sentry/core'; 2 | import type { Attachment, Breadcrumb, User } from '@sentry/types'; 3 | 4 | import { DEFAULT_BREADCRUMB_LEVEL } from './breadcrumb'; 5 | import { convertToNormalizedObject } from './utils/normalize'; 6 | import { NATIVE } from './wrapper'; 7 | 8 | /** 9 | * Extends the scope methods to set scope on the Native SDKs 10 | */ 11 | export class NativescriptScope extends Scope { 12 | /** 13 | * @inheritDoc 14 | */ 15 | public setUser(user: User | null): this { 16 | NATIVE.setUser(user); 17 | return super.setUser(user); 18 | } 19 | 20 | /** 21 | * @inheritDoc 22 | */ 23 | public setTag(key: string, value: string): this { 24 | NATIVE.setTag(key, value); 25 | return super.setTag(key, value); 26 | } 27 | 28 | /** 29 | * @inheritDoc 30 | */ 31 | public setTags(tags: { [key: string]: string }): this { 32 | // As native only has setTag, we just loop through each tag key. 33 | Object.keys(tags).forEach((key) => { 34 | NATIVE.setTag(key, tags[key]); 35 | }); 36 | return super.setTags(tags); 37 | } 38 | 39 | /** 40 | * @inheritDoc 41 | */ 42 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 43 | public setExtras(extras: { [key: string]: any }): this { 44 | Object.keys(extras).forEach((key) => { 45 | NATIVE.setExtra(key, extras[key]); 46 | }); 47 | return super.setExtras(extras); 48 | } 49 | 50 | /** 51 | * @inheritDoc 52 | */ 53 | // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types,@typescript-eslint/no-explicit-any 54 | public setExtra(key: string, extra: any): this { 55 | NATIVE.setExtra(key, extra); 56 | return super.setExtra(key, extra); 57 | } 58 | 59 | /** 60 | * @inheritDoc 61 | */ 62 | public addBreadcrumb(breadcrumb: Breadcrumb, maxBreadcrumbs?: number): this { 63 | const mergedBreadcrumb: Breadcrumb = { 64 | ...breadcrumb, 65 | level: breadcrumb.level || DEFAULT_BREADCRUMB_LEVEL, 66 | data: breadcrumb.data ? convertToNormalizedObject(breadcrumb.data) : undefined 67 | }; 68 | 69 | super.addBreadcrumb(mergedBreadcrumb, maxBreadcrumbs); 70 | 71 | const finalBreadcrumb = this._breadcrumbs[this._breadcrumbs.length - 1]; 72 | NATIVE.addBreadcrumb(finalBreadcrumb); 73 | return this; 74 | } 75 | 76 | /** 77 | * @inheritDoc 78 | */ 79 | public clearBreadcrumbs(): this { 80 | NATIVE.clearBreadcrumbs(); 81 | return super.clearBreadcrumbs(); 82 | } 83 | 84 | /** 85 | * @inheritDoc 86 | */ 87 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 88 | public setContext(key: string, context: { [key: string]: any } | null): this { 89 | NATIVE.setContext(key, context); 90 | return super.setContext(key, context); 91 | } 92 | 93 | /** 94 | * @inheritDoc 95 | */ 96 | public addAttachment(attachment: Attachment): this { 97 | return super.addAttachment(attachment); 98 | } 99 | 100 | /** 101 | * @inheritDoc 102 | */ 103 | public clearAttachments(): this { 104 | return super.clearAttachments(); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/sentry/tracing/addTracingExtensions.ts: -------------------------------------------------------------------------------- 1 | import type { Hub, Transaction } from '@sentry/core'; 2 | // eslint-disable-next-line no-duplicate-imports 3 | import { addTracingExtensions, getCurrentHub, getMainCarrier } from '@sentry/core'; 4 | import type { CustomSamplingContext, Span, SpanContext, TransactionContext } from '@sentry/types'; 5 | 6 | import { NativescriptTracing } from './nstracing'; 7 | import { DEFAULT } from './ops'; 8 | 9 | /** 10 | * Adds React Native's extensions. Needs to be called before any transactions are created. 11 | */ 12 | export function _addTracingExtensions(): void { 13 | addTracingExtensions(); 14 | const carrier = getMainCarrier(); 15 | if (carrier.__SENTRY__) { 16 | carrier.__SENTRY__.extensions = carrier.__SENTRY__.extensions || {}; 17 | if (carrier.__SENTRY__.extensions.startTransaction) { 18 | const originalStartTransaction = carrier.__SENTRY__.extensions.startTransaction as StartTransactionFunction; 19 | 20 | /* 21 | Overwrites the transaction start and finish to start and finish stall tracking. 22 | Preferably instead of overwriting add a callback method for this in the Transaction itself. 23 | */ 24 | const _startTransaction = _patchStartTransaction(originalStartTransaction); 25 | 26 | carrier.__SENTRY__.extensions.startTransaction = _startTransaction; 27 | } 28 | } 29 | } 30 | 31 | export type StartTransactionFunction = ( 32 | this: Hub, 33 | transactionContext: TransactionContext, 34 | customSamplingContext?: CustomSamplingContext, 35 | ) => Transaction; 36 | 37 | /** 38 | * Overwrite the startTransaction extension method to start and end stall tracking. 39 | */ 40 | const _patchStartTransaction = (originalStartTransaction: StartTransactionFunction): StartTransactionFunction => { 41 | /** 42 | * Method to overwrite with 43 | */ 44 | function _startTransaction( 45 | this: Hub, 46 | transactionContext: TransactionContext, 47 | customSamplingContext?: CustomSamplingContext, 48 | ): Transaction { 49 | // Native SDKs require op to be set - for JS Relay sets `default` 50 | if (!transactionContext.op) { 51 | transactionContext.op = DEFAULT; 52 | } 53 | 54 | const transaction: Transaction = originalStartTransaction.apply(this, [transactionContext, customSamplingContext]); 55 | const originalStartChild: Transaction['startChild'] = transaction.startChild.bind(transaction); 56 | transaction.startChild = ( 57 | spanContext?: Pick>, 58 | ): Span => originalStartChild({ 59 | ...spanContext, 60 | // Native SDKs require op to be set 61 | op: spanContext?.op || DEFAULT, 62 | }); 63 | 64 | const reactNativeTracing = getCurrentHub().getIntegration(NativescriptTracing); 65 | 66 | if (reactNativeTracing) { 67 | reactNativeTracing.onTransactionStart(transaction); 68 | 69 | // eslint-disable-next-line @typescript-eslint/unbound-method 70 | const originalFinish = transaction.finish; 71 | 72 | transaction.finish = (endTimestamp: number | undefined) => { 73 | if (reactNativeTracing) { 74 | reactNativeTracing.onTransactionFinish(transaction); 75 | } 76 | 77 | return originalFinish.apply(transaction, [endTimestamp]); 78 | }; 79 | } 80 | 81 | return transaction; 82 | } 83 | 84 | return _startTransaction; 85 | }; 86 | -------------------------------------------------------------------------------- /src/sentry/tracing/index.ts: -------------------------------------------------------------------------------- 1 | export { NativescriptTracing } from './nstracing'; 2 | 3 | export { 4 | RoutingInstrumentation, 5 | RoutingInstrumentationInstance, 6 | } from './routingInstrumentation'; 7 | 8 | // export { 9 | // ReactNavigationInstrumentation, 10 | // // eslint-disable-next-line deprecation/deprecation 11 | // ReactNavigationV5Instrumentation, 12 | // } from './reactnavigation'; 13 | // export { ReactNavigationV4Instrumentation } from './reactnavigationv4'; 14 | // export { NativescriptNavigationInstrumentation } from './reactnativenavigation'; 15 | 16 | // export { 17 | // ReactNavigationCurrentRoute, 18 | // ReactNavigationRoute, 19 | // ReactNavigationTransactionContext, 20 | // } from './types'; 21 | 22 | // export { NativescriptProfiler } from './reactnativeprofiler'; 23 | -------------------------------------------------------------------------------- /src/sentry/tracing/ops.ts: -------------------------------------------------------------------------------- 1 | export const DEFAULT = 'default'; 2 | export const NAVIGATION = 'navigation'; 3 | 4 | export const UI_LOAD = 'ui.load'; 5 | export const UI_ACTION = 'ui.action'; 6 | export const UI_ACTION_TOUCH = 'ui.action.touch'; 7 | 8 | export const APP_START_COLD = 'app.start.cold'; 9 | export const APP_START_WARM = 'app.start.warm'; 10 | -------------------------------------------------------------------------------- /src/sentry/tracing/routingInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { Hub } from '@sentry/hub'; 2 | import { Transaction, TransactionContext } from '@sentry/types'; 3 | 4 | import { BeforeNavigate } from './types'; 5 | 6 | export type TransactionCreator = ( 7 | context: TransactionContext 8 | ) => Transaction | undefined; 9 | 10 | export type OnConfirmRoute = (context: TransactionContext) => void; 11 | 12 | export interface RoutingInstrumentationInstance { 13 | /** 14 | * Name of the routing instrumentation 15 | */ 16 | readonly name: string; 17 | /** 18 | * Registers a listener that's called on every route change with a `TransactionContext`. 19 | * 20 | * Do not overwrite this unless you know what you are doing. 21 | * 22 | * @param listener A `RouteListener` 23 | * @param beforeNavigate BeforeNavigate 24 | * @param inConfirmRoute OnConfirmRoute 25 | */ 26 | registerRoutingInstrumentation( 27 | listener: TransactionCreator, 28 | beforeNavigate: BeforeNavigate, 29 | onConfirmRoute: OnConfirmRoute 30 | ): void; 31 | /** 32 | * To be called when the route changes, BEFORE the new route mounts. 33 | * If this is called after a route mounts the child spans will not be correctly attached. 34 | * 35 | * @param context A `TransactionContext` used to initialize the transaction. 36 | */ 37 | onRouteWillChange(context: TransactionContext): Transaction | undefined; 38 | } 39 | 40 | /** 41 | * Base Routing Instrumentation. Can be used by users to manually instrument custom routers. 42 | * Pass this to the tracing integration, and call `onRouteWillChange` every time before a route changes. 43 | */ 44 | export class RoutingInstrumentation implements RoutingInstrumentationInstance { 45 | public static instrumentationName: string = 'base-routing-instrumentation'; 46 | 47 | public readonly name: string = RoutingInstrumentation.instrumentationName; 48 | 49 | protected _getCurrentHub?: () => Hub; 50 | protected _beforeNavigate?: BeforeNavigate; 51 | protected _onConfirmRoute?: OnConfirmRoute; 52 | protected _tracingListener?: TransactionCreator; 53 | 54 | /** @inheritdoc */ 55 | public registerRoutingInstrumentation( 56 | listener: TransactionCreator, 57 | beforeNavigate: BeforeNavigate, 58 | onConfirmRoute: OnConfirmRoute 59 | ): void { 60 | this._tracingListener = listener; 61 | this._beforeNavigate = beforeNavigate; 62 | this._onConfirmRoute = onConfirmRoute; 63 | } 64 | 65 | /** @inheritdoc */ 66 | public onRouteWillChange( 67 | context: TransactionContext 68 | ): Transaction | undefined { 69 | const transaction = this._tracingListener?.(context); 70 | 71 | if (transaction) { 72 | this._onConfirmRoute?.(context); 73 | } 74 | 75 | return transaction; 76 | } 77 | } 78 | 79 | /** 80 | * Internal base routing instrumentation where `_onConfirmRoute` is not called in onRouteWillChange 81 | */ 82 | export class InternalRoutingInstrumentation extends RoutingInstrumentation { 83 | /** @inheritdoc */ 84 | public onRouteWillChange( 85 | context: TransactionContext 86 | ): Transaction | undefined { 87 | return this._tracingListener?.(context); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/sentry/tracing/transaction.ts: -------------------------------------------------------------------------------- 1 | import { Application } from '@nativescript/core'; 2 | import { type BeforeFinishCallback, type IdleTransaction } from '@sentry/core'; 3 | import { logger } from '@sentry/utils'; 4 | // import type { AppStateStatus } from 'react-native'; 5 | // import { AppState } from 'react-native'; 6 | 7 | /** 8 | * Idle Transaction callback to only sample transactions with child spans. 9 | * To avoid side effects of other callbacks this should be hooked as the last callback. 10 | */ 11 | export const onlySampleIfChildSpans: BeforeFinishCallback = (transaction: IdleTransaction): void => { 12 | const spansCount = 13 | transaction.spanRecorder && 14 | transaction.spanRecorder.spans.filter(span => span.spanId !== transaction.spanId).length; 15 | 16 | if (!spansCount || spansCount <= 0) { 17 | logger.log(`Not sampling as ${transaction.op} transaction has no child spans.`); 18 | transaction.sampled = false; 19 | } 20 | }; 21 | 22 | /** 23 | * Hooks on AppState change to cancel the transaction if the app goes background. 24 | */ 25 | export const cancelInBackground = (transaction: IdleTransaction): void => { 26 | function onBackground(){ 27 | logger.debug(`Setting ${transaction.op} transaction to cancelled because the app is in the background.`); 28 | transaction.setStatus('cancelled'); 29 | transaction.finish(); 30 | } 31 | Application.on(Application.backgroundEvent, onBackground); 32 | // const subscription = AppState.addEventListener('change', (newState: AppStateStatus) => { 33 | // if (newState === 'background') { 34 | 35 | // } 36 | // }); 37 | transaction.registerBeforeFinishCallback(() => { 38 | logger.debug(`Removing AppState listener for ${transaction.op} transaction.`); 39 | Application.off(Application.backgroundEvent, onBackground); 40 | }); 41 | }; 42 | -------------------------------------------------------------------------------- /src/sentry/tracing/types.ts: -------------------------------------------------------------------------------- 1 | import { TransactionContext } from '@sentry/types'; 2 | 3 | // export interface ReactNavigationRoute { 4 | // name: string; 5 | // key: string; 6 | // // eslint-disable-next-line @typescript-eslint/no-explicit-any 7 | // params: Record; 8 | // } 9 | 10 | // export interface ReactNavigationCurrentRoute extends ReactNavigationRoute { 11 | // hasBeenSeen: boolean; 12 | // } 13 | 14 | export interface RouteChangeContextData { 15 | previousRoute?: { 16 | [key: string]: unknown; 17 | name: string; 18 | } | null; 19 | route: { 20 | [key: string]: unknown; 21 | name: string; 22 | hasBeenSeen: boolean; 23 | }; 24 | } 25 | 26 | // export interface ReactNavigationTransactionContext extends TransactionContext { 27 | // tags: { 28 | // 'routing.instrumentation': string; 29 | // 'routing.route.name': string; 30 | // }; 31 | // data: RouteChangeContextData; 32 | // } 33 | 34 | export type BeforeNavigate = ( 35 | context: TransactionContext 36 | ) => TransactionContext; 37 | -------------------------------------------------------------------------------- /src/sentry/tracing/utils.ts: -------------------------------------------------------------------------------- 1 | import { IdleTransaction, Span, Transaction } from '@sentry/tracing'; 2 | import { TransactionContext, TransactionSource } from '@sentry/types'; 3 | import { timestampInSeconds } from '@sentry/utils'; 4 | 5 | export const defaultTransactionSource: TransactionSource = 'component'; 6 | export const customTransactionSource: TransactionSource = 'custom'; 7 | 8 | export const getBlankTransactionContext = ( 9 | name: string 10 | ): TransactionContext => ({ 11 | name: 'Route Change', 12 | op: 'navigation', 13 | tags: { 14 | 'routing.instrumentation': name, 15 | }, 16 | data: {}, 17 | metadata: { 18 | source: defaultTransactionSource, 19 | }, 20 | }); 21 | 22 | /** 23 | * A margin of error of 50ms is allowed for the async native bridge call. 24 | * Anything larger would reduce the accuracy of our frames measurements. 25 | */ 26 | export const MARGIN_OF_ERROR_SECONDS = 0.05; 27 | 28 | const timeOriginMilliseconds = Date.now(); 29 | 30 | /** 31 | * Converts from seconds to milliseconds 32 | * @param time time in seconds 33 | */ 34 | function secToMs(time: number): number { 35 | return time * 1000; 36 | } 37 | 38 | /** 39 | * 40 | */ 41 | export function adjustTransactionDuration( 42 | maxDuration: number, // in seconds 43 | transaction: IdleTransaction, 44 | endTimestamp: number 45 | ): void { 46 | const diff = endTimestamp - transaction.startTimestamp; 47 | const isOutdatedTransaction = 48 | endTimestamp && (diff > secToMs(maxDuration) || diff < 0); 49 | if (isOutdatedTransaction) { 50 | transaction.setStatus('deadline_exceeded'); 51 | transaction.setTag('maxTransactionDurationExceeded', 'true'); 52 | } 53 | } 54 | 55 | /** 56 | * Returns the timestamp where the JS global scope was initialized. 57 | */ 58 | export function getTimeOriginMilliseconds(): number { 59 | return timeOriginMilliseconds; 60 | } 61 | 62 | /** 63 | * Calls the callback every time a child span of the transaction is finished. 64 | */ 65 | export function instrumentChildSpanFinish( 66 | transaction: Transaction, 67 | callback: (span: Span, endTimestamp?: number) => void 68 | ): void { 69 | if (transaction.spanRecorder) { 70 | // eslint-disable-next-line @typescript-eslint/unbound-method 71 | const originalAdd = transaction.spanRecorder.add; 72 | 73 | transaction.spanRecorder.add = (span: Span): void => { 74 | originalAdd.apply(transaction.spanRecorder, [span]); 75 | 76 | // eslint-disable-next-line @typescript-eslint/unbound-method 77 | const originalSpanFinish = span.finish; 78 | 79 | span.finish = (endTimestamp?: number) => { 80 | originalSpanFinish.apply(span, [endTimestamp]); 81 | 82 | callback(span, endTimestamp); 83 | }; 84 | }; 85 | } 86 | } 87 | 88 | /** 89 | * Determines if the timestamp is now or within the specified margin of error from now. 90 | */ 91 | export function isNearToNow(timestamp: number): boolean { 92 | return Math.abs(timestampInSeconds() - timestamp) <= MARGIN_OF_ERROR_SECONDS; 93 | } 94 | -------------------------------------------------------------------------------- /src/sentry/transports/TextEncoder.ts: -------------------------------------------------------------------------------- 1 | import { TextEncoderInternal } from '@sentry/types'; 2 | import { utf8ToBytes } from '../vendor'; 3 | 4 | import { NATIVE } from '../wrapper'; 5 | 6 | export const makeUtf8TextEncoder = (): TextEncoderInternal => { 7 | const textEncoder = { 8 | encode: (text: string) => 9 | // const bytes = new Uint8Array(NATIVE.utf8ToBytes(text)); 10 | // NATIVE.utf8ToBytes(text) 11 | new Uint8Array(utf8ToBytes(text)) 12 | , 13 | encoding: 'utf-8', 14 | }; 15 | return textEncoder; 16 | }; 17 | -------------------------------------------------------------------------------- /src/sentry/transports/native.ts: -------------------------------------------------------------------------------- 1 | import { BaseTransportOptions, Envelope, Event, Transport } from '@sentry/types'; 2 | import { PromiseBuffer, makePromiseBuffer } from '@sentry/utils'; 3 | 4 | import { NATIVE } from '../wrapper'; 5 | 6 | export const DEFAULT_BUFFER_SIZE = 30; 7 | 8 | export type BaseNativeTransport = BaseTransportOptions; 9 | 10 | export interface BaseNativeTransportOptions { 11 | bufferSize?: number; 12 | } 13 | 14 | /** Native Transport class implementation */ 15 | export class NativeTransport implements Transport { 16 | /** A simple buffer holding all requests. */ 17 | protected readonly _buffer: PromiseBuffer; 18 | 19 | public constructor(options: BaseNativeTransportOptions = {}) { 20 | this._buffer = makePromiseBuffer(options.bufferSize || DEFAULT_BUFFER_SIZE); 21 | } 22 | 23 | /** 24 | * Sends the envelope to the Store endpoint in Sentry. 25 | * 26 | * @param envelope Envelope that should be sent to Sentry. 27 | */ 28 | public send(envelope: Envelope): PromiseLike { 29 | return this._buffer.add(() => NATIVE.sendEnvelope(envelope)); 30 | } 31 | 32 | /** 33 | * Wait for all envelopes to be sent or the timeout to expire, whichever comes first. 34 | * 35 | * @param timeout Maximum time in ms the transport should wait for envelopes to be flushed. Omitting this parameter will 36 | * cause the transport to wait until all events are sent before resolving the promise. 37 | * @returns A promise that will resolve with `true` if all events are sent before the timeout, or `false` if there are 38 | * still events in the queue when the timeout is reached. 39 | */ 40 | public flush(timeout?: number): PromiseLike { 41 | return this._buffer.drain(timeout); 42 | } 43 | } 44 | 45 | /** 46 | * Creates a Native Transport. 47 | */ 48 | export function makeNativescriptTransport(options: BaseNativeTransportOptions = {}): NativeTransport { return new NativeTransport(options); } 49 | -------------------------------------------------------------------------------- /src/sentry/typings/ns.ios.d.ts: -------------------------------------------------------------------------------- 1 | 2 | declare class NSSentrySDK extends SentrySDK { 3 | 4 | static alloc(): NSSentrySDK; // inherited from NSObject 5 | 6 | static captureEnvelope(envelope: SentryEnvelope): void; 7 | 8 | static envelopeWithData(data: NSData): SentryEnvelope; 9 | 10 | static new(): NSSentrySDK; // inherited from NSObject 11 | 12 | static storeEnvelope(envelope: SentryEnvelope): void; 13 | 14 | static readonly appStartMeasurement: SentryAppStartMeasurement; 15 | 16 | static appStartMeasurementHybridSDKMode: boolean; 17 | 18 | static readonly currentScreenFrames: SentryScreenFrames; 19 | 20 | static framesTrackingMeasurementHybridSDKMode: boolean; 21 | 22 | static readonly installationID: string; 23 | 24 | static readonly isFramesTrackingRunning: boolean; 25 | } 26 | -------------------------------------------------------------------------------- /src/sentry/utils/envelope.ts: -------------------------------------------------------------------------------- 1 | import { DsnComponents, EventEnvelope, SdkMetadata, UserFeedback, UserFeedbackItem } from '@sentry/types'; 2 | import { createEnvelope, dsnToString } from '@sentry/utils'; 3 | 4 | export const header = 0; 5 | export const items = 1; 6 | 7 | /** 8 | * Creates an envelope from a user feedback. 9 | */ 10 | export function createUserFeedbackEnvelope( 11 | feedback: UserFeedback, 12 | { 13 | metadata, 14 | tunnel, 15 | dsn 16 | }: { 17 | metadata: SdkMetadata | undefined; 18 | tunnel: string | undefined; 19 | dsn: DsnComponents | undefined; 20 | } 21 | ): EventEnvelope { 22 | const headers: EventEnvelope[0] = { 23 | event_id: feedback.event_id, 24 | sent_at: new Date().toISOString(), 25 | ...(metadata && 26 | metadata.sdk && { 27 | sdk: { 28 | name: metadata.sdk.name, 29 | version: metadata.sdk.version 30 | } 31 | }), 32 | ...(!!tunnel && !!dsn && { dsn: dsnToString(dsn) }) 33 | }; 34 | const item = createUserFeedbackEnvelopeItem(feedback); 35 | 36 | return createEnvelope(headers, [item]); 37 | } 38 | 39 | function createUserFeedbackEnvelopeItem(feedback: UserFeedback): UserFeedbackItem { 40 | const feedbackHeaders: UserFeedbackItem[0] = { 41 | type: 'user_report' 42 | }; 43 | return [feedbackHeaders, feedback]; 44 | } 45 | -------------------------------------------------------------------------------- /src/sentry/utils/environment.ts: -------------------------------------------------------------------------------- 1 | /** Returns default environment based on __DEV__ */ 2 | export function getDefaultEnvironment(): 'development' | 'production' { 3 | return typeof __DEV__ !== 'undefined' && __DEV__ ? 'development' : 'production'; 4 | } 5 | -------------------------------------------------------------------------------- /src/sentry/utils/normalize.ts: -------------------------------------------------------------------------------- 1 | import { normalize } from '@sentry/utils'; 2 | 3 | const KEY = 'value'; 4 | 5 | /** 6 | * Converts any input into a valid record with string keys. 7 | */ 8 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 9 | export function convertToNormalizedObject(data: unknown): Record { 10 | const normalized: unknown = normalize(data); 11 | if (normalized === null || typeof normalized !== 'object') { 12 | return { 13 | [KEY]: normalized 14 | }; 15 | } else { 16 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 17 | return normalized as Record; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/sentry/utils/outcome.ts: -------------------------------------------------------------------------------- 1 | import { Outcome } from '@sentry/types'; 2 | 3 | /** 4 | * Merges buffer with new outcomes. 5 | */ 6 | export function mergeOutcomes(...merge: Outcome[][]): Outcome[] { 7 | const map = new Map(); 8 | 9 | const process = (outcome: Outcome): void => { 10 | const key = `${outcome.reason}:${outcome.category}`; 11 | const existing = map.get(key); 12 | if (existing) { 13 | existing.quantity += outcome.quantity; 14 | } else { 15 | map.set(key, outcome); 16 | } 17 | }; 18 | 19 | merge.forEach((outcomes) => outcomes.forEach(process)); 20 | 21 | return [...map.values()]; 22 | } 23 | -------------------------------------------------------------------------------- /src/sentry/utils/safe.ts: -------------------------------------------------------------------------------- 1 | import { logger } from '@sentry/utils'; 2 | 3 | import { NativescriptOptions } from '../options'; 4 | 5 | type DangerTypesWithoutCallSignature = 6 | // eslint-disable-next-line @typescript-eslint/ban-types 7 | | Object 8 | | null 9 | | undefined; 10 | 11 | /** 12 | * Returns callback factory wrapped with try/catch 13 | * or the original passed value is it's not a function. 14 | * 15 | * If the factory fails original data are returned as it. 16 | * They might be partially modified by the failed function. 17 | */ 18 | export function safeFactory( 19 | danger: ((...args: A) => R) | T, 20 | options: { 21 | loggerMessage?: string; 22 | } = {}, 23 | ): ((...args: A) => R) | T { 24 | if (typeof danger === 'function') { 25 | return (...args) => { 26 | try { 27 | return danger(...args); 28 | } catch (error) { 29 | logger.error( 30 | options.loggerMessage 31 | ? options.loggerMessage 32 | : `The ${danger.name} callback threw an error`, 33 | error, 34 | ); 35 | return args[0]; 36 | } 37 | }; 38 | } else { 39 | return danger; 40 | } 41 | } 42 | 43 | type TracesSampler = Required['tracesSampler']; 44 | 45 | /** 46 | * Returns sage tracesSampler that returns 0 if the original failed. 47 | */ 48 | export function safeTracesSampler( 49 | tracesSampler: NativescriptOptions['tracesSampler'], 50 | ): NativescriptOptions['tracesSampler'] { 51 | if (tracesSampler) { 52 | return ( 53 | ...args: Parameters 54 | ): ReturnType => { 55 | try { 56 | return tracesSampler(...args); 57 | } catch (error) { 58 | logger.error('The tracesSampler callback threw an error', error); 59 | return 0; 60 | } 61 | }; 62 | } else { 63 | return tracesSampler; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/sentry/vendor/buffer/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | utf8ToBytes, 3 | } from './utf8ToBytes'; 4 | -------------------------------------------------------------------------------- /src/sentry/vendor/buffer/utf8ToBytes.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Convert a string to a byte array 3 | * 4 | * This is a utf8ToBytes function from the buffer module (with added types) 5 | * https://github.com/feross/buffer/blob/795bbb5bda1b39f1370ebd784bea6107b087e3a7/index.js#L1956 6 | * 7 | * License: MIT (https://github.com/feross/buffer) 8 | */ 9 | export function utf8ToBytes(string: string, units?: number): number[] { 10 | units = units || Infinity; 11 | let codePoint; 12 | const length = string.length; 13 | let leadSurrogate = null; 14 | const bytes: number[] = []; 15 | 16 | for (let i = 0; i < length; ++i) { 17 | codePoint = string.charCodeAt(i); 18 | 19 | // is surrogate component 20 | if (codePoint > 0xD7FF && codePoint < 0xE000) { 21 | // last char was a lead 22 | if (!leadSurrogate) { 23 | // no lead yet 24 | if (codePoint > 0xDBFF) { 25 | // unexpected trail 26 | if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); 27 | continue; 28 | } else if (i + 1 === length) { 29 | // unpaired lead 30 | if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); 31 | continue; 32 | } 33 | 34 | // valid lead 35 | leadSurrogate = codePoint; 36 | 37 | continue; 38 | } 39 | 40 | // 2 leads in a row 41 | if (codePoint < 0xDC00) { 42 | if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); 43 | leadSurrogate = codePoint; 44 | continue; 45 | } 46 | 47 | // valid surrogate pair 48 | codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000; 49 | } else if (leadSurrogate) { 50 | // valid bmp char, but last char was a lead 51 | if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); 52 | } 53 | 54 | leadSurrogate = null; 55 | 56 | // encode utf8 57 | if (codePoint < 0x80) { 58 | if ((units -= 1) < 0) break; 59 | bytes.push(codePoint); 60 | } else if (codePoint < 0x800) { 61 | if ((units -= 2) < 0) break; 62 | bytes.push( 63 | codePoint >> 0x6 | 0xC0, 64 | codePoint & 0x3F | 0x80 65 | ); 66 | } else if (codePoint < 0x10000) { 67 | if ((units -= 3) < 0) break; 68 | bytes.push( 69 | codePoint >> 0xC | 0xE0, 70 | codePoint >> 0x6 & 0x3F | 0x80, 71 | codePoint & 0x3F | 0x80 72 | ); 73 | } else if (codePoint < 0x110000) { 74 | if ((units -= 4) < 0) break; 75 | bytes.push( 76 | codePoint >> 0x12 | 0xF0, 77 | codePoint >> 0xC & 0x3F | 0x80, 78 | codePoint >> 0x6 & 0x3F | 0x80, 79 | codePoint & 0x3F | 0x80 80 | ); 81 | } else { 82 | throw new Error('Invalid code point'); 83 | } 84 | } 85 | 86 | return bytes; 87 | } 88 | -------------------------------------------------------------------------------- /src/sentry/vendor/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | utf8ToBytes, 3 | } from './buffer'; 4 | -------------------------------------------------------------------------------- /src/sentry/version.ts: -------------------------------------------------------------------------------- 1 | export const SDK_PACKAGE_NAME = 'npm:@nativescript-community/sentry'; 2 | export const SDK_NAME = 'sentry.nativescript'; 3 | export const SDK_VERSION = require('./package.json').version; 4 | -------------------------------------------------------------------------------- /src/sentry/wrapper.d.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Attachment, 3 | AttachmentItem, 4 | BaseEnvelopeItemHeaders, 5 | Breadcrumb, 6 | ClientReportItem, 7 | Envelope, 8 | Event, 9 | EventItem, 10 | Package, 11 | SessionItem, 12 | SeverityLevel, 13 | User, 14 | UserFeedbackItem 15 | } from '@sentry/types'; 16 | import { NativescriptOptions } from './options'; 17 | import { SentryError, logger } from '@sentry/utils'; 18 | import { Hub, Scope } from '@sentry/core'; 19 | 20 | export interface NativeAppStartResponse { 21 | isColdStart: boolean; 22 | appStartTime: number; 23 | didFetchAppStart: boolean; 24 | } 25 | 26 | export interface NativeFramesResponse { 27 | totalFrames: number; 28 | slowFrames: number; 29 | frozenFrames: number; 30 | } 31 | 32 | export interface NativeReleaseResponse { 33 | build: string; 34 | id: string; 35 | version: string; 36 | } 37 | export interface UserFeedback { 38 | eventId: string; 39 | comments?: string; 40 | email?: string; 41 | name?: string; 42 | } 43 | /** 44 | * This type describes serialized scope from sentry-cocoa and sentry-android 45 | * https://github.com/getsentry/sentry-cocoa/blob/master/Sources/Sentry/SentryScope.m 46 | * https://github.com/getsentry/sentry-java/blob/a461f7e125b65240004e6162b341f383ce2e1394/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java#L32 47 | */ 48 | export interface NativeDeviceContextsResponse { 49 | [key: string]: unknown; 50 | tags?: Record; 51 | extra?: Record; 52 | contexts?: Record>; 53 | user?: { 54 | userId?: string; 55 | email?: string; 56 | username?: string; 57 | ipAddress?: string; 58 | segment?: string; 59 | data?: Record; 60 | }; 61 | dist?: string; 62 | environment?: string; 63 | fingerprint?: string[]; 64 | level?: string; 65 | breadcrumbs?: { 66 | level?: string; 67 | timestamp?: string; 68 | category?: string; 69 | type?: string; 70 | message?: string; 71 | data?: Record; 72 | }[]; 73 | } 74 | 75 | export interface NativeScreenshot { 76 | data: Uint8Array; 77 | contentType: string; 78 | filename: string; 79 | } 80 | 81 | export namespace NATIVE { 82 | const nativeClientAvailable: boolean; 83 | const nativeTransport: boolean; 84 | let enableNative: boolean; 85 | function sendEvent(event: Event, hint?): Promise; 86 | function sendEnvelope(envelope: Envelope): Promise; 87 | function initNativeSdk(options: NativescriptOptions): Promise; 88 | function closeNativeSdk(): Promise; 89 | function nativeCrash(); 90 | function flush(timeout: number); 91 | function fetchNativeDeviceContexts(): Promise; 92 | function captureUserFeedback(feedback: UserFeedback); 93 | function isNativeTransportAvailable(): boolean; 94 | 95 | function enableNativeFramesTracking(); 96 | function disableNativeFramesTracking(); 97 | function fetchNativeSdkInfo(): any; 98 | function fetchNativeRelease(): any; 99 | function fetchNativeFrames(): Promise<{ 100 | totalFrames; 101 | slowFrames; 102 | frozenFrames; 103 | }>; 104 | function fetchNativeAppStart(): Promise<{ 105 | isColdStart; 106 | appStartTime; 107 | didFetchAppStart; 108 | }>; 109 | 110 | function setUser(user: User | null); 111 | function setTag(key: string, value: string); 112 | 113 | function setExtra(key: string, extra: any); 114 | 115 | function addBreadcrumb(breadcrumb: Breadcrumb, maxBreadcrumbs?: number); 116 | function addAttachment(attachment: Attachment); 117 | 118 | function clearBreadcrumbs(); 119 | 120 | function setContext(key: string, context: { [key: string]: any } | null); 121 | 122 | function withScope(callback: (scope: Scope) => void): ReturnType; 123 | 124 | function utf8ToBytes(str: string): Uint8Array; 125 | 126 | function captureScreenshot(fileName?: string): NativeScreenshot[]; 127 | } 128 | -------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | const sveltePreprocess = require('svelte-preprocess'); 2 | // const svelteNativePreprocessor = require('svelte-native-preprocessor'); 3 | 4 | module.exports = { 5 | compilerOptions: { 6 | namespace: 'foreign' 7 | }, 8 | preprocess: [ 9 | sveltePreprocess({ 10 | typescript: { 11 | compilerOptions: { 12 | target: 'es2020' 13 | } 14 | } 15 | }) 16 | // svelteNativePreprocessor() 17 | ] 18 | }; 19 | -------------------------------------------------------------------------------- /test.mjs: -------------------------------------------------------------------------------- 1 | import { stackParserFromStackParserOptions } from '@sentry/utils'; 2 | 3 | const UNKNOWN_FUNCTION = undefined; 4 | 5 | // function createFrame(filename, func, lineno, colno) { 6 | 7 | function createFrame(frame) { 8 | frame.in_app = (frame.filename && !frame.filename.includes('node_modules')) || (!!frame.colno && !!frame.lineno); 9 | frame.platform = frame.filename.endsWith('.js') ? 'javascript' : 'android'; 10 | 11 | return frame; 12 | } 13 | 14 | const nativescriptRegex = 15 | /^\s*at (?:(.*\).*?|.*?) ?\()?((?:file|native|webpack||[-a-z]+:|.*bundle|\/)?.*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i; 16 | 17 | const nativescriptFunc = line => { 18 | const parts = nativescriptRegex.exec(line); 19 | if (parts) { 20 | return createFrame({ 21 | filename:parts[2], 22 | function:parts[1] || UNKNOWN_FUNCTION, 23 | lineno:parts[3] ? +parts[3] : undefined, 24 | colno:parts[4] ? +parts[4] : undefined 25 | }); 26 | } 27 | return null; 28 | }; 29 | 30 | const nativescriptLineParser = [30, nativescriptFunc]; 31 | 32 | const androidRegex = 33 | /^\s*(?:(.*\).*?|.*?) ?\()?((?:Native Method|[-a-z]+:)?.*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i; 34 | 35 | const androidFunc = line => { 36 | const parts = androidRegex.exec(line); 37 | if (parts) { 38 | let func = UNKNOWN_FUNCTION, mod; 39 | if (parts[1]) { 40 | const splitted = parts[1].split('.'); 41 | func = splitted[splitted.length-1]; 42 | mod = splitted.slice(0, -1).join('.'); 43 | } 44 | return createFrame({ 45 | filename:parts[2], 46 | function:func, 47 | module:mod, 48 | lineno:parts[3] ? +parts[3] : undefined, 49 | colno:parts[4] ? +parts[4] : undefined 50 | }); 51 | } 52 | return null; 53 | }; 54 | 55 | const androidLineParser = [50, androidFunc]; 56 | 57 | const stackParser = stackParserFromStackParserOptions([nativescriptLineParser, androidLineParser]); 58 | 59 | console.log('stackParser', stackParser(`at androidNativeCrashTest(file:///data/data/org.nativescript.demovuesentry/files/app/bundle.js:184:92) 60 | at invokeWithErrorHandling(file:///data/data/org.nativescript.demovuesentry/files/app/vendor.js:73859:26) 61 | at invoker(file:///data/data/org.nativescript.demovuesentry/files/app/vendor.js:74513:14) 62 | at _handleEvent(file:///data/data/org.nativescript.demovuesentry/files/app/vendor.js:23374:37) 63 | at notify(file:///data/data/org.nativescript.demovuesentry/files/app/vendor.js:23356:24) 64 | at _emit(file:///data/data/org.nativescript.demovuesentry/files/app/vendor.js:23403:18) 65 | at ClickListenerImpl.onClick(file:///data/data/org.nativescript.demovuesentry/files/app/vendor.js:33101:19) 66 | com.nativescript.sentry.ClassExample.helloWorld(ClassExample.java:5) 67 | com.tns.Runtime.callJSMethodNative(Native Method) 68 | com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:1302) 69 | com.tns.Runtime.callJSMethodImpl(Runtime.java:1188) 70 | com.tns.Runtime.callJSMethod(Runtime.java:1175) 71 | com.tns.Runtime.callJSMethod(Runtime.java:1153) 72 | com.tns.Runtime.callJSMethod(Runtime.java:1149) 73 | java.lang.Object_vendor_33094_28_ClickListenerImpl.onClick(Unknown Source:10) 74 | android.view.View.performClick(View.java:7441) 75 | android.view.View.performClickInternal(View.java:7418) 76 | android.view.View.access$3700(View.java:835) 77 | android.view.View$PerformClick.run(View.java:28676) 78 | android.os.Handler.handleCallback(Handler.java:938) 79 | android.os.Handler.dispatchMessage(Handler.java:99) 80 | android.os.Looper.loopOnce(Looper.java:201) 81 | android.os.Looper.loop(Looper.java:288) 82 | android.app.ActivityThread.main(ActivityThread.java:7839) 83 | java.lang.reflect.Method.invoke(Native Method) 84 | com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) 85 | com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)`)); 86 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tools/tsconfig", 3 | "compilerOptions": { 4 | "paths": { 5 | "@nativescript-community/sentry": ["src/sentry/index"], 6 | "@nativescript-community/sentry/*": ["src/sentry/*"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.vue3.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "composite": true, 5 | "paths": { 6 | "nativescript-vue": ["./node_modules/nativescript-vue3"] 7 | } 8 | }, 9 | "include": [ 10 | "./demo-snippets/vue3" 11 | ] 12 | } --------------------------------------------------------------------------------