├── .editorconfig ├── .github ├── renovate.json5 └── workflows │ └── checks.yml ├── .gitignore ├── .yarnrc.yml ├── LICENSE.md ├── README.md ├── bin └── test.ts ├── configure.ts ├── eslint.config.js ├── index.ts ├── package.json ├── providers └── sentry_provider.ts ├── src ├── define_config.ts ├── middleware.ts ├── sentry.ts └── types │ └── main.ts ├── stubs ├── config │ └── sentry.stub └── main.ts ├── tests ├── configure.spec.ts └── fixtures │ ├── base_fixture.ts │ └── configure_fixture.ts ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.json] 12 | insert_final_newline = false 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | extends: ["config:recommended", "schedule:weekly", "group:allNonMajor"], 4 | labels: ["dependencies"], 5 | rangeStrategy: "bump", 6 | packageRules: [ 7 | { 8 | matchDepTypes: ["peerDependencies"], 9 | enabled: false, 10 | }, 11 | ], 12 | ignoreDeps: [ 13 | // manually bumping 14 | "node", 15 | "@types/node" 16 | ], 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/checks.yml: -------------------------------------------------------------------------------- 1 | name: checks 2 | on: 3 | - push 4 | - pull_request 5 | 6 | jobs: 7 | test: 8 | uses: boringnode/.github/.github/workflows/test.yml@main 9 | 10 | lint: 11 | uses: boringnode/.github/.github/workflows/lint.yml@main 12 | 13 | typecheck: 14 | uses: boringnode/.github/.github/workflows/typecheck.yml@main 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build 2 | build 3 | 4 | # Node & Dependencies 5 | node_modules 6 | coverage 7 | 8 | # Build tools specific 9 | .yarn/* 10 | !.yarn/patches 11 | !.yarn/plugins 12 | !.yarn/releases 13 | !.yarn/sdks 14 | !.yarn/versions 15 | npm-debug.log 16 | yarn-error.log 17 | 18 | # Editors specific 19 | .fleet 20 | .idea 21 | .vscode 22 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | 3 | Copyright 2023 Romain Lanz, contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | @rlanz/sentry 3 |
4 | 5 |
6 | 7 | [![typescript-image]][typescript-url] 8 | [![gh-workflow-image]][gh-workflow-url] 9 | [![npm-image]][npm-url] 10 | [![npm-download-image]][npm-download-url] 11 | [![license-image]][license-url] 12 | 13 |
14 | 15 |
16 | 17 | `@rlanz/sentry` is a simple wrapper around the Sentry SDK to make it easier to use in a AdonisJS application. 18 | 19 | ## Installation 20 | 21 | ```sh 22 | node ace add @rlanz/sentry 23 | ``` 24 | 25 | ## Usage 26 | 27 | The package will automatically register a middleware and configure the Sentry SDK. 28 | 29 | ```ts 30 | import type { HttpContext } from '@adonisjs/core/http' 31 | import { Sentry } from '@rlanz/sentry' 32 | 33 | export default class HelloController { 34 | greet({ params, response}: HttpContext) { 35 | Sentry.captureMessage(`Hello, ${params.name}!`) 36 | 37 | return response.ok({ message: `Hello, ${params.name}!` }) 38 | } 39 | } 40 | ``` 41 | 42 | The SDK is automatically scoped to the current request. 43 | 44 | ```ts 45 | import { inject } from '@adonisjs/core' 46 | import { Sentry } from '@rlanz/sentry' 47 | 48 | @inject() 49 | export class GreetingService { 50 | greet(name: string) { 51 | Sentry.captureMessage(`Hello, ${name}!`) 52 | 53 | return `Hello, ${name}!` 54 | } 55 | } 56 | ``` 57 | 58 | ### Capturing Errors 59 | 60 | You can capture errors by calling the `captureException` method on the SDK inside your exception handler. 61 | 62 | ```ts 63 | import { Sentry } from '@rlanz/sentry' 64 | 65 | export default class HttpExceptionHandler extends ExceptionHandler { 66 | // ... 67 | 68 | async report(error: unknown, ctx: HttpContext) { 69 | if (this.shouldReport(error as any)) { 70 | Sentry.captureException(error) 71 | } 72 | 73 | return super.report(error, ctx) 74 | } 75 | } 76 | ``` 77 | 78 | ### Assigning User Context 79 | 80 | You can assign user context to the Sentry SDK by calling the `setUser` method on the SDK once you are logged in. 81 | 82 | ```ts 83 | import { Sentry } from '@rlanz/sentry' 84 | 85 | export default class SilentAuthMiddleware { 86 | async handle(ctx: HttpContext, next: NextFn) { 87 | // We are authenticating the user 88 | await ctx.auth.check() 89 | 90 | // If the user is authenticated, we assign the user context to Sentry 91 | if (ctx.auth.isAuthenticated) { 92 | const user = ctx.auth.getUserOrFail() 93 | 94 | Sentry.setUser({ 95 | id: user.id, 96 | email: user.email, 97 | username: user.username, 98 | }); 99 | } 100 | 101 | return await next(); 102 | } 103 | } 104 | ``` 105 | 106 | ### Adding Integrations 107 | 108 | Sentry provides multiple integrations to enhance the data captured by the SDK. You can add integrations by changing the `integrations` array inside the configuration `config/sentry.ts`. 109 | 110 | For example, if you want to add profiling to your application, you can add the `Profiler` integration. 111 | 112 | ```sh 113 | npm install @sentry/profiling-node 114 | ``` 115 | 116 | ```ts 117 | // config/sentry.ts 118 | 119 | import { nodeProfilingIntegration } from '@sentry/profiling-node'; 120 | 121 | export default defineConfig({ 122 | // ... 123 | integrations: [nodeProfilingIntegration()], 124 | profilesSampleRate: 0.2, 125 | }) 126 | ``` 127 | 128 | [gh-workflow-image]: https://img.shields.io/github/actions/workflow/status/RomainLanz/sentry/checks.yml?branch=0.3&style=for-the-badge 129 | [gh-workflow-url]: https://github.com/RomainLanz/sentry/actions/workflows/checks.yml 130 | [npm-image]: https://img.shields.io/npm/v/@rlanz/sentry.svg?style=for-the-badge&logo=npm 131 | [npm-url]: https://www.npmjs.com/package/@rlanz/sentry 132 | [npm-download-image]: https://img.shields.io/npm/dm/@rlanz/sentry?style=for-the-badge 133 | [npm-download-url]: https://www.npmjs.com/package/@rlanz/sentry 134 | [typescript-image]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript 135 | [typescript-url]: https://www.typescriptlang.org 136 | [license-image]: https://img.shields.io/npm/l/@rlanz/sentry?color=blueviolet&style=for-the-badge 137 | [license-url]: LICENSE.md 138 | -------------------------------------------------------------------------------- /bin/test.ts: -------------------------------------------------------------------------------- 1 | import { assert } from '@japa/assert' 2 | import { fileSystem } from '@japa/file-system' 3 | import { processCLIArgs, configure, run } from '@japa/runner' 4 | 5 | /* 6 | |-------------------------------------------------------------------------- 7 | | Configure tests 8 | |-------------------------------------------------------------------------- 9 | | 10 | | The configure method accepts the configuration to configure the Japa 11 | | tests runner. 12 | | 13 | | The first method call "processCLIArgs" process the command line arguments 14 | | and turns them into a config object. Using this method is not mandatory. 15 | | 16 | | Please consult japa.dev/runner-config for the config docs. 17 | */ 18 | processCLIArgs(process.argv.slice(2)) 19 | configure({ 20 | files: ['tests/**/*.spec.ts'], 21 | plugins: [assert(), fileSystem({ autoClean: true })], 22 | }) 23 | 24 | /* 25 | |-------------------------------------------------------------------------- 26 | | Run tests 27 | |-------------------------------------------------------------------------- 28 | | 29 | | The following "run" method is required to execute all the tests. 30 | | 31 | */ 32 | await run() 33 | -------------------------------------------------------------------------------- /configure.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @rlanz/sentry 3 | * 4 | * (c) Romain Lanz 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import { stubsRoot } from './stubs/main.js' 11 | import type Configure from '@adonisjs/core/commands/configure' 12 | 13 | /** 14 | * Configures the package 15 | */ 16 | export async function configure(command: Configure) { 17 | const codemods = await command.createCodemods() 18 | 19 | /** 20 | * Publish config file 21 | */ 22 | await codemods.makeUsingStub(stubsRoot, 'config/sentry.stub', {}) 23 | 24 | /** 25 | * Define environment variables 26 | */ 27 | await codemods.defineEnvVariables({ SENTRY_DSN: '' }) 28 | /** 29 | * Define environment variables validations 30 | */ 31 | await codemods.defineEnvValidations({ 32 | variables: { 33 | SENTRY_DSN: 'Env.schema.string()', 34 | }, 35 | leadingComment: 'Variables for configuring @rlanz/sentry package', 36 | }) 37 | 38 | /** 39 | * Register middleware 40 | */ 41 | await codemods.registerMiddleware('router', [ 42 | { 43 | path: '@rlanz/sentry/middleware', 44 | position: 'before', 45 | }, 46 | ]) 47 | 48 | /** 49 | * Register provider 50 | */ 51 | await codemods.updateRcFile((rcFile) => { 52 | rcFile.addProvider('@rlanz/sentry/provider') 53 | }) 54 | } 55 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import { configPkg } from '@adonisjs/eslint-config' 2 | 3 | export default configPkg({ 4 | ignores: ['coverage'], 5 | }) 6 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @rlanz/sentry 3 | * 4 | * (c) Romain Lanz 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | export { Sentry } from './src/sentry.js' 11 | export { configure } from './configure.js' 12 | export { stubsRoot } from './stubs/main.js' 13 | export { defineConfig } from './src/define_config.js' 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rlanz/sentry", 3 | "description": "A wrapper around the Sentry SDK to make it easier to use in a AdonisJS application", 4 | "version": "0.3.3", 5 | "engines": { 6 | "node": ">= 20.11.0" 7 | }, 8 | "main": "build/index.js", 9 | "type": "module", 10 | "files": [ 11 | "build" 12 | ], 13 | "exports": { 14 | ".": "./build/index.js", 15 | "./middleware": "./build/src/middleware.js", 16 | "./provider": "./build/providers/sentry_provider.js" 17 | }, 18 | "scripts": { 19 | "build": "yarn clean && tsc && yarn copy:templates", 20 | "clean": "del-cli build", 21 | "copy:templates": "copyfiles \"stubs/**/*.stub\" --up=\"1\" build", 22 | "format": "prettier --write .", 23 | "lint": "eslint . --ext=.ts", 24 | "prepublishOnly": "yarn build", 25 | "release": "release-it", 26 | "quick:test": "node --enable-source-maps --import=ts-node-maintained/register/esm bin/test.ts", 27 | "test": "c8 yarn quick:test", 28 | "typecheck": "tsc --noEmit" 29 | }, 30 | "dependencies": { 31 | "@poppinss/utils": "^6.9.2", 32 | "@sentry/node": "^9.8.0" 33 | }, 34 | "devDependencies": { 35 | "@adonisjs/assembler": "^7.8.2", 36 | "@adonisjs/core": "^6.17.2", 37 | "@adonisjs/eslint-config": "^2.0.0", 38 | "@adonisjs/prettier-config": "^1.4.4", 39 | "@adonisjs/tsconfig": "^1.4.0", 40 | "@japa/assert": "^4.0.1", 41 | "@japa/file-system": "^2.3.2", 42 | "@japa/runner": "^4.2.0", 43 | "@swc/core": "1.11.13", 44 | "@types/node": "^20.17.22", 45 | "c8": "^10.1.3", 46 | "copyfiles": "^2.4.1", 47 | "del-cli": "^6.0.0", 48 | "eslint": "^9.23.0", 49 | "prettier": "^3.5.3", 50 | "release-it": "^18.1.2", 51 | "ts-node-maintained": "^10.9.5", 52 | "typescript": "^5.8.2" 53 | }, 54 | "author": "Romain Lanz ", 55 | "license": "MIT", 56 | "keywords": [ 57 | "sentry", 58 | "adonisjs", 59 | "adonis" 60 | ], 61 | "prettier": "@adonisjs/prettier-config", 62 | "publishConfig": { 63 | "access": "public", 64 | "tag": "latest" 65 | }, 66 | "release-it": { 67 | "git": { 68 | "commitMessage": "chore(release): ${version}", 69 | "tagAnnotation": "v${version}", 70 | "tagName": "v${version}" 71 | }, 72 | "github": { 73 | "release": true, 74 | "releaseName": "v${version}", 75 | "web": true 76 | } 77 | }, 78 | "packageManager": "yarn@4.7.0" 79 | } 80 | -------------------------------------------------------------------------------- /providers/sentry_provider.ts: -------------------------------------------------------------------------------- 1 | import { Sentry } from '../src/sentry.js' 2 | import type { ApplicationService } from '@adonisjs/core/types' 3 | import type { SentryConfig } from '../src/types/main.js' 4 | 5 | export default class SentryProvider { 6 | constructor(protected app: ApplicationService) {} 7 | 8 | async boot() { 9 | const config = this.app.config.get('sentry', {}) 10 | 11 | if (config.enabled) { 12 | Sentry.init(config) 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/define_config.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @rlanz/sentry 3 | * 4 | * (c) Romain Lanz 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import type { SentryConfig } from './types/main.js' 11 | 12 | export function defineConfig(config: T): T { 13 | return config 14 | } 15 | -------------------------------------------------------------------------------- /src/middleware.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @rlanz/sentry 3 | * 4 | * (c) Romain Lanz 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import { Sentry } from './sentry.js' 11 | import type { HttpContext } from '@adonisjs/core/http' 12 | import type { NextFn } from '@adonisjs/core/types/http' 13 | 14 | export default class SentryMiddleware { 15 | async handle(ctx: HttpContext, next: NextFn) { 16 | const activeSpan = Sentry.getActiveSpan() 17 | const rootSpan = activeSpan && Sentry.getRootSpan(activeSpan) 18 | 19 | if (rootSpan) { 20 | Sentry.updateSpanName(rootSpan, ctx.routeKey || 'unknown') 21 | } 22 | 23 | return next() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/sentry.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @rlanz/sentry 3 | * 4 | * (c) Romain Lanz 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import * as Sentry from '@sentry/node' 11 | 12 | export { Sentry } 13 | -------------------------------------------------------------------------------- /src/types/main.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @rlanz/sentry 3 | * 4 | * (c) Romain Lanz 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import * as Sentry from '@sentry/node' 11 | 12 | export interface SentryConfig extends Sentry.NodeOptions { 13 | /** 14 | * Enable or disable Sentry 15 | */ 16 | enabled: boolean 17 | 18 | dsn: string 19 | } 20 | -------------------------------------------------------------------------------- /stubs/config/sentry.stub: -------------------------------------------------------------------------------- 1 | {{{ 2 | exports({ to: app.configPath('sentry.ts') }) 3 | }}} 4 | 5 | import env from '#start/env' 6 | import app from '@adonisjs/core/services/app' 7 | import { defineConfig } from '@rlanz/sentry' 8 | 9 | export default defineConfig({ 10 | /** 11 | * Enable or disable Sentry 12 | */ 13 | enabled: app.inProduction, 14 | 15 | /** 16 | * The environment Sentry is running in 17 | */ 18 | environment: app.nodeEnvironment, 19 | 20 | /** 21 | * The DSN of the project 22 | */ 23 | dsn: env.get('SENTRY_DSN'), 24 | 25 | /** 26 | * Additional integrations to use with the Sentry SDK 27 | * @see https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/#available-integrations 28 | */ 29 | integrations: [], 30 | 31 | /** 32 | * The sample rate of traces to send to Sentry 33 | * @see https://docs.sentry.io/platforms/javascript/guides/node/configuration/sampling 34 | */ 35 | tracesSampleRate: 0.2, 36 | }) 37 | -------------------------------------------------------------------------------- /stubs/main.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @rlanz/sentry 3 | * 4 | * (c) Romain Lanz 5 | * 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | import { getDirname } from '@poppinss/utils' 12 | 13 | export const stubsRoot = getDirname(import.meta.url) 14 | -------------------------------------------------------------------------------- /tests/configure.spec.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @rlanz/sentry 3 | * 4 | * (c) Romain Lanz 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import { test } from '@japa/runner' 11 | import { ConfigureFixture } from './fixtures/configure_fixture.js' 12 | 13 | test.group('Configure', (group) => { 14 | group.tap((t) => t.timeout(10_000)) 15 | 16 | let fixture: ConfigureFixture 17 | 18 | group.each.setup(async () => { 19 | fixture = new ConfigureFixture() 20 | }) 21 | 22 | test('should register provider', async () => { 23 | await fixture.givenIHaveAnApplication() 24 | 25 | await fixture.whenIRunConfigure() 26 | 27 | await fixture.thenShouldRegisterProvider() 28 | }) 29 | 30 | test('should create configuration file', async () => { 31 | await fixture.givenIHaveAnApplication() 32 | 33 | await fixture.whenIRunConfigure() 34 | 35 | await fixture.thenConfigurationShouldBeCreated() 36 | }) 37 | 38 | test('should register middleware', async () => { 39 | await fixture.givenIHaveAnApplication() 40 | 41 | await fixture.whenIRunConfigure() 42 | 43 | await fixture.thenShouldRegisterMiddleware() 44 | }) 45 | 46 | test('should add environment variables', async () => { 47 | await fixture.givenIHaveAnApplication() 48 | 49 | await fixture.whenIRunConfigure() 50 | 51 | await fixture.thenEnvironmentVariablesShouldBeAdded() 52 | }) 53 | }) 54 | -------------------------------------------------------------------------------- /tests/fixtures/base_fixture.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @rlanz/sentry 3 | * 4 | * (c) Romain Lanz 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import { IgnitorFactory } from '@adonisjs/core/factories' 11 | import { getActiveTest } from '@japa/runner' 12 | import type { Test } from '@japa/runner/core' 13 | import { assertExists } from '@poppinss/utils/assert' 14 | import { Application } from '@adonisjs/core/app' 15 | 16 | export const BASE_URL = new URL('./tmp/', import.meta.url) 17 | 18 | export class BaseFixture { 19 | protected context: { app: Application | undefined } = { 20 | app: undefined, 21 | } 22 | 23 | protected test: Test | undefined 24 | 25 | getActiveTest() { 26 | if (this.test) { 27 | return this.test 28 | } 29 | 30 | this.test = getActiveTest() 31 | 32 | assertExists(this.test, 'Cannot access test context outside of a test') 33 | 34 | return this.test 35 | } 36 | 37 | async givenIHaveAnApplication() { 38 | this.getActiveTest().context.fs.baseUrl = BASE_URL 39 | this.getActiveTest().context.fs.basePath = BASE_URL.pathname 40 | 41 | await this.getActiveTest().context.fs.create('.env', '') 42 | await this.getActiveTest().context.fs.createJson('tsconfig.json', {}) 43 | await this.getActiveTest().context.fs.create( 44 | 'start/env.ts', 45 | `export default Env.create(new URL('./'), {})` 46 | ) 47 | await this.getActiveTest().context.fs.create( 48 | 'start/kernel.ts', 49 | ` 50 | import router from '@adonisjs/core/services/router' 51 | import server from '@adonisjs/core/services/server' 52 | 53 | router.use([ 54 | () => import('@adonisjs/core/bodyparser_middleware'), 55 | ]) 56 | 57 | server.use([]) 58 | ` 59 | ) 60 | await this.getActiveTest().context.fs.create('adonisrc.ts', `export default defineConfig({})`) 61 | 62 | const ignitor = new IgnitorFactory() 63 | .withCoreProviders() 64 | .withCoreConfig() 65 | .create(BASE_URL, { 66 | importer: (filePath) => { 67 | if (filePath.startsWith('./') || filePath.startsWith('../')) { 68 | return import(new URL(filePath, BASE_URL).href) 69 | } 70 | 71 | return import(filePath) 72 | }, 73 | }) 74 | 75 | const app = ignitor.createApp('web') 76 | await app.init().then(() => app.boot()) 77 | 78 | this.context.app = app 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /tests/fixtures/configure_fixture.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @rlanz/sentry 3 | * 4 | * (c) Romain Lanz 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import { assertExists } from '@poppinss/utils/assert' 11 | import { BaseFixture } from './base_fixture.js' 12 | import Configure from '@adonisjs/core/commands/configure' 13 | 14 | export class ConfigureFixture extends BaseFixture { 15 | async whenIRunConfigure() { 16 | assertExists(this.context.app, 'Cannot access app context without initializing it') 17 | 18 | const ace = await this.context.app.container.make('ace') 19 | ace.ui.switchMode('raw') 20 | 21 | const command = await ace.create(Configure, ['../../../index.js']) 22 | await command.exec() 23 | } 24 | 25 | async thenShouldRegisterProvider() { 26 | await this.getActiveTest().context.assert.fileExists('adonisrc.ts') 27 | await this.getActiveTest().context.assert.fileContains('adonisrc.ts', '@rlanz/sentry/provider') 28 | } 29 | 30 | async thenShouldRegisterMiddleware() { 31 | await this.getActiveTest().context.assert.fileExists('start/kernel.ts') 32 | await this.getActiveTest().context.assert.fileContains( 33 | 'start/kernel.ts', 34 | '@rlanz/sentry/middleware' 35 | ) 36 | } 37 | 38 | async thenConfigurationShouldBeCreated() { 39 | await this.getActiveTest().context.assert.fileExists('config/sentry.ts') 40 | } 41 | 42 | async thenEnvironmentVariablesShouldBeAdded() { 43 | await this.getActiveTest().context.assert.fileContains('.env', 'SENTRY_DSN') 44 | await this.getActiveTest().context.assert.fileContains( 45 | 'start/env.ts', 46 | 'SENTRY_DSN: Env.schema.string()' 47 | ) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@adonisjs/tsconfig/tsconfig.package.json", 3 | "compilerOptions": { 4 | "rootDir": "./", 5 | "outDir": "./build" 6 | } 7 | } 8 | --------------------------------------------------------------------------------