@outloud/adonisjs-sentry 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025-present, Outloud
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,138 @@
1
+ # AdonisJS Sentry
2
+
3
+ Sentry integration for [AdonisJS](https://adonisjs.com/) version 6/7.
4
+
5
+ <p>
6
+
7
+ [![typescript-image]][typescript-url]
8
+ [![npm-image]][npm-url]
9
+ [![npm-download-image]][npm-download-url]
10
+ [![license-image]][license-url]
11
+
12
+ </p>
13
+
14
+ ---
15
+ ## Getting Started
16
+
17
+ Install the package from the npm registry and configure it.
18
+
19
+ ```bash
20
+ node ace add @outloud/adonisjs-sentry
21
+ ```
22
+
23
+ See `config/sentry.ts` for available configuration options.
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 '@outloud/adonisjs-sentry/service'
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 '@outloud/adonisjs-sentry/service'
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 '@outloud/adonisjs-sentry/service'
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 '@outloud/adonisjs-sentry/service'
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
+ [npm-image]: https://badgen.net/npm/v/@outloud/adonisjs-sentry/latest
129
+ [npm-url]: https://npmjs.org/package/@outloud/adonisjs-sentry "npm"
130
+
131
+ [npm-download-image]: https://badgen.net/npm/dm/@outloud/adonisjs-sentry
132
+ [npm-download-url]: https://npmcharts.com/compare/@outloud/adonisjs-sentry?minimal=true "downloads"
133
+
134
+ [typescript-image]: https://img.shields.io/badge/TypeScript-007ACC?logo=typescript&logoColor=white
135
+ [typescript-url]: https://www.typescriptlang.org "TypeScript"
136
+
137
+ [license-image]: https://img.shields.io/npm/l/@outloud/adonisjs-sentry.svg?sanitize=true
138
+ [license-url]: LICENSE.md "license"
@@ -0,0 +1,11 @@
1
+ import { ApplicationService } from "@adonisjs/core/types";
2
+
3
+ //#region providers/sentry.provider.d.ts
4
+ declare class SentryProvider {
5
+ protected app: ApplicationService;
6
+ constructor(app: ApplicationService);
7
+ register(): void;
8
+ boot(): void;
9
+ }
10
+ //#endregion
11
+ export { SentryProvider as default };
@@ -0,0 +1,18 @@
1
+ import * as Sentry from "@sentry/node";
2
+
3
+ //#region providers/sentry.provider.ts
4
+ var SentryProvider = class {
5
+ constructor(app) {
6
+ this.app = app;
7
+ }
8
+ register() {
9
+ this.app.container.singleton("sentry", () => Sentry);
10
+ }
11
+ boot() {
12
+ const config = this.app.config.get("sentry", {});
13
+ if (config.enabled && config.dsn) Sentry.init(config);
14
+ }
15
+ };
16
+
17
+ //#endregion
18
+ export { SentryProvider as default };
@@ -0,0 +1,6 @@
1
+ import { Sentry as SentryImpl } from "../src/types.js";
2
+
3
+ //#region services/sentry.d.ts
4
+ declare let sentry: SentryImpl;
5
+ //#endregion
6
+ export { sentry as default };
@@ -0,0 +1,10 @@
1
+ import app from "@adonisjs/core/services/app";
2
+
3
+ //#region services/sentry.ts
4
+ let sentry;
5
+ await app?.booted(async () => {
6
+ sentry = await app.container.make("sentry");
7
+ });
8
+
9
+ //#endregion
10
+ export { sentry as default };
@@ -0,0 +1,6 @@
1
+ import { SentryConfig } from "./types.js";
2
+
3
+ //#region src/config.d.ts
4
+ declare function defineConfig<T extends SentryConfig>(config: T): T;
5
+ //#endregion
6
+ export { defineConfig };
@@ -0,0 +1,7 @@
1
+ //#region src/config.ts
2
+ function defineConfig(config) {
3
+ return config;
4
+ }
5
+
6
+ //#endregion
7
+ export { defineConfig };
@@ -0,0 +1,9 @@
1
+ import Configure from "@adonisjs/core/commands/configure";
2
+
3
+ //#region src/configure.d.ts
4
+ /**
5
+ * Configures the package
6
+ */
7
+ declare function configure(command: Configure): Promise<void>;
8
+ //#endregion
9
+ export { configure };
@@ -0,0 +1,40 @@
1
+ import { stubsRoot } from "../stubs/main.js";
2
+
3
+ //#region src/configure.ts
4
+ /**
5
+ * Configures the package
6
+ */
7
+ async function configure(command) {
8
+ const codemods = await command.createCodemods();
9
+ /**
10
+ * Publish config file
11
+ */
12
+ await codemods.makeUsingStub(stubsRoot, "config/sentry.stub", {});
13
+ /**
14
+ * Define environment variables
15
+ */
16
+ await codemods.defineEnvVariables({ SENTRY_DSN: "<your_dsn_url>" });
17
+ /**
18
+ * Define environment variables validations
19
+ */
20
+ await codemods.defineEnvValidations({
21
+ variables: { SENTRY_DSN: "Env.schema.string.optional()" },
22
+ leadingComment: "Variables for configuring @outloud/adonisjs-sentry package"
23
+ });
24
+ /**
25
+ * Register middleware
26
+ */
27
+ await codemods.registerMiddleware("router", [{
28
+ path: "@outloud/adonisjs-sentry/middleware",
29
+ position: "before"
30
+ }]);
31
+ /**
32
+ * Register provider
33
+ */
34
+ await codemods.updateRcFile((rcFile) => {
35
+ rcFile.addProvider("@outloud/adonisjs-sentry/provider");
36
+ });
37
+ }
38
+
39
+ //#endregion
40
+ export { configure };
@@ -0,0 +1,3 @@
1
+ import { configure } from "./configure.js";
2
+ import { defineConfig } from "./config.js";
3
+ export { configure, defineConfig };
@@ -0,0 +1,4 @@
1
+ import { configure } from "./configure.js";
2
+ import { defineConfig } from "./config.js";
3
+
4
+ export { configure, defineConfig };
@@ -0,0 +1,9 @@
1
+ import { HttpContext } from "@adonisjs/core/http";
2
+ import { NextFn } from "@adonisjs/core/types/http";
3
+
4
+ //#region src/middleware.d.ts
5
+ declare class SentryMiddleware {
6
+ handle(ctx: HttpContext, next: NextFn): Promise<any>;
7
+ }
8
+ //#endregion
9
+ export { SentryMiddleware as default };
@@ -0,0 +1,14 @@
1
+ import * as Sentry from "@sentry/node";
2
+
3
+ //#region src/middleware.ts
4
+ var SentryMiddleware = class {
5
+ async handle(ctx, next) {
6
+ const activeSpan = Sentry.getActiveSpan();
7
+ const rootSpan = activeSpan && Sentry.getRootSpan(activeSpan);
8
+ if (rootSpan) Sentry.updateSpanName(rootSpan, ctx.routeKey || "unknown");
9
+ return next();
10
+ }
11
+ };
12
+
13
+ //#endregion
14
+ export { SentryMiddleware as default };
@@ -0,0 +1,16 @@
1
+ import * as Sentry from "@sentry/node";
2
+
3
+ //#region src/types.d.ts
4
+ type SentryImpl = typeof Sentry;
5
+ interface SentryConfig extends Sentry.NodeOptions {
6
+ /** Enable or disable Sentry */
7
+ enabled: boolean;
8
+ dsn?: string;
9
+ }
10
+ declare module '@adonisjs/core/types' {
11
+ interface ContainerBindings {
12
+ sentry: typeof Sentry;
13
+ }
14
+ }
15
+ //#endregion
16
+ export { type SentryImpl as Sentry, SentryConfig };
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,30 @@
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 '@outloud/adonisjs-sentry'
8
+
9
+ export default defineConfig({
10
+ /** Enable or disable Sentry */
11
+ enabled: app.inProduction,
12
+
13
+ /** The environment Sentry is running in */
14
+ environment: app.nodeEnvironment,
15
+
16
+ /** The DSN of the project */
17
+ dsn: env.get('SENTRY_DSN'),
18
+
19
+ /**
20
+ * Additional integrations to use with the Sentry SDK
21
+ * @see https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/#available-integrations
22
+ */
23
+ integrations: [],
24
+
25
+ /**
26
+ * The sample rate of traces to send to Sentry
27
+ * @see https://docs.sentry.io/platforms/javascript/guides/node/configuration/sampling
28
+ */
29
+ tracesSampleRate: 0.2,
30
+ })
@@ -0,0 +1,4 @@
1
+ //#region stubs/main.d.ts
2
+ declare const stubsRoot: string;
3
+ //#endregion
4
+ export { stubsRoot };
@@ -0,0 +1,5 @@
1
+ //#region stubs/main.ts
2
+ const stubsRoot = import.meta.dirname;
3
+
4
+ //#endregion
5
+ export { stubsRoot };
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@outloud/adonisjs-sentry",
3
+ "type": "module",
4
+ "version": "1.0.0",
5
+ "description": "Sentry integration for AdonisJS 6/7.",
6
+ "homepage": "https://github.com/madebyoutloud/adonisjs-sentry",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/madebyoutloud/adonisjs-sentry.git"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "imports": {
15
+ "#/*": "./src/*.js"
16
+ },
17
+ "exports": {
18
+ ".": "./dist/src/index.js",
19
+ "./middleware": "./dist/src/middleware.js",
20
+ "./provider": "./dist/providers/sentry.provider.js",
21
+ "./service": "./dist/services/sentry.js",
22
+ "./services/*": "./dist/services/*.js",
23
+ "./types": "./dist/src/types.js"
24
+ },
25
+ "peerDependencies": {
26
+ "@adonisjs/core": "^6 || ^7"
27
+ },
28
+ "devDependencies": {
29
+ "@adonisjs/core": "^6.19.0",
30
+ "@japa/assert": "^4.1.1",
31
+ "@japa/runner": "^4.4.0",
32
+ "@outloud/eslint-config": "^2.1.3",
33
+ "@poppinss/ts-exec": "^1.4.4",
34
+ "@types/node": "^22.2.0",
35
+ "copyfiles": "^2.4.1",
36
+ "eslint": "^9.39.2",
37
+ "reflect-metadata": "^0.2.2",
38
+ "release-it": "^19.2.4",
39
+ "tsdown": "^0.20.1"
40
+ },
41
+ "dependencies": {
42
+ "@sentry/node": "^10"
43
+ },
44
+ "scripts": {
45
+ "pretest": "pnpm lint && pnpm typecheck",
46
+ "test": "pnpm quick:test",
47
+ "quick:test": "node --enable-source-maps --import=@poppinss/ts-exec --no-warnings bin/test.ts",
48
+ "lint": "eslint . --ext=.ts",
49
+ "lint:fix": "eslint --fix . --ext=.ts",
50
+ "typecheck": "tsc --noEmit",
51
+ "copy:templates": "copyfiles \"stubs/**/*.stub\" dist",
52
+ "build": "tsdown && pnpm run copy:templates",
53
+ "release": "release-it"
54
+ }
55
+ }