@royaltics/tracker-sails 0.0.1
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/README.md +191 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +75 -0
- package/dist/types/index.d.ts +30 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# @royaltics/tracker-sails
|
|
2
|
+
|
|
3
|
+
> Sails.js hook for Royaltics Error Tracker
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✅ **Sails.js Integration**: Native hook implementation
|
|
8
|
+
- ✅ **Automatic Request Tracking**: Capture all HTTP requests
|
|
9
|
+
- ✅ **Error Middleware**: Automatic error capture
|
|
10
|
+
- ✅ **Route Filtering**: Ignore specific routes
|
|
11
|
+
- ✅ **Configurable**: Full control over what gets tracked
|
|
12
|
+
- ✅ **TypeScript Support**: Full type definitions
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm add @royaltics/tracker-sails
|
|
18
|
+
# or
|
|
19
|
+
npm install @royaltics/tracker-sails
|
|
20
|
+
# or
|
|
21
|
+
yarn add @royaltics/tracker-sails
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Configuration
|
|
25
|
+
|
|
26
|
+
Create or update `config/errorTracker.js`:
|
|
27
|
+
|
|
28
|
+
```javascript
|
|
29
|
+
module.exports.errorTracker = {
|
|
30
|
+
webhookUrl: process.env.ERROR_TRACKER_WEBHOOK_URL,
|
|
31
|
+
licenseId: process.env.ERROR_TRACKER_LICENSE_ID,
|
|
32
|
+
licenseDevice: process.env.ERROR_TRACKER_DEVICE || 'sails-server',
|
|
33
|
+
licenseName: 'My Company',
|
|
34
|
+
app: 'my-sails-app',
|
|
35
|
+
version: '1.0.0',
|
|
36
|
+
|
|
37
|
+
// Optional: Capture settings
|
|
38
|
+
captureRoutes: true,
|
|
39
|
+
captureQueries: true,
|
|
40
|
+
captureHeaders: false,
|
|
41
|
+
|
|
42
|
+
// Optional: Filtering
|
|
43
|
+
ignoredRoutes: [
|
|
44
|
+
'/health',
|
|
45
|
+
'/metrics',
|
|
46
|
+
'^/api/internal/.*'
|
|
47
|
+
],
|
|
48
|
+
|
|
49
|
+
ignoredErrors: [
|
|
50
|
+
'ValidationError',
|
|
51
|
+
'NotFoundError'
|
|
52
|
+
],
|
|
53
|
+
|
|
54
|
+
// Optional: Advanced settings
|
|
55
|
+
enabled: true,
|
|
56
|
+
maxRetries: 3,
|
|
57
|
+
timeout: 10000,
|
|
58
|
+
flushInterval: 5000,
|
|
59
|
+
maxQueueSize: 50
|
|
60
|
+
};
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Usage
|
|
64
|
+
|
|
65
|
+
### Install the Hook
|
|
66
|
+
|
|
67
|
+
In `config/hooks.js`:
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
module.exports.hooks = {
|
|
71
|
+
errorTracker: require('@royaltics/tracker-sails').errorTracker
|
|
72
|
+
};
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Automatic Error Tracking
|
|
76
|
+
|
|
77
|
+
The hook automatically captures:
|
|
78
|
+
|
|
79
|
+
- Uncaught exceptions
|
|
80
|
+
- Unhandled promise rejections
|
|
81
|
+
- Route errors
|
|
82
|
+
- Request errors
|
|
83
|
+
|
|
84
|
+
### Manual Error Tracking
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
// In a controller or service
|
|
88
|
+
module.exports = {
|
|
89
|
+
async someAction(req, res) {
|
|
90
|
+
try {
|
|
91
|
+
// Your code
|
|
92
|
+
} catch (error) {
|
|
93
|
+
sails.hooks.errorTracker.client.error(error, 'ERROR', {
|
|
94
|
+
userId: req.session.userId,
|
|
95
|
+
action: 'someAction'
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return res.serverError(error);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Track Custom Events
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
sails.hooks.errorTracker.client.event('User registered', 'INFO', {
|
|
108
|
+
userId: user.id,
|
|
109
|
+
email: user.email
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Configuration Options
|
|
114
|
+
|
|
115
|
+
### Required
|
|
116
|
+
|
|
117
|
+
| Option | Type | Description |
|
|
118
|
+
|--------|------|-------------|
|
|
119
|
+
| `webhookUrl` | `string` | HTTP/HTTPS webhook URL |
|
|
120
|
+
| `licenseId` | `string` | Your license ID |
|
|
121
|
+
| `licenseDevice` | `string` | Device identifier |
|
|
122
|
+
|
|
123
|
+
### Optional
|
|
124
|
+
|
|
125
|
+
| Option | Type | Default | Description |
|
|
126
|
+
|--------|------|---------|-------------|
|
|
127
|
+
| `licenseName` | `string` | `undefined` | License name |
|
|
128
|
+
| `app` | `string` | `undefined` | Application name |
|
|
129
|
+
| `version` | `string` | `undefined` | Application version |
|
|
130
|
+
| `captureRoutes` | `boolean` | `false` | Capture all route requests |
|
|
131
|
+
| `captureQueries` | `boolean` | `false` | Include query parameters |
|
|
132
|
+
| `captureHeaders` | `boolean` | `false` | Include request headers |
|
|
133
|
+
| `ignoredRoutes` | `string[]` | `[]` | Routes to ignore (regex patterns) |
|
|
134
|
+
| `ignoredErrors` | `string[]` | `[]` | Errors to ignore (regex patterns) |
|
|
135
|
+
| `enabled` | `boolean` | `true` | Enable/disable tracking |
|
|
136
|
+
| `maxRetries` | `number` | `3` | Max retry attempts |
|
|
137
|
+
| `timeout` | `number` | `10000` | Request timeout in ms |
|
|
138
|
+
| `flushInterval` | `number` | `5000` | Batch flush interval in ms |
|
|
139
|
+
| `maxQueueSize` | `number` | `50` | Max events before auto-flush |
|
|
140
|
+
|
|
141
|
+
## Examples
|
|
142
|
+
|
|
143
|
+
### Environment Variables
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
ERROR_TRACKER_WEBHOOK_URL=https://api.example.com/webhook
|
|
147
|
+
ERROR_TRACKER_LICENSE_ID=your-license-id
|
|
148
|
+
ERROR_TRACKER_DEVICE=production-server-01
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Ignore Health Check Routes
|
|
152
|
+
|
|
153
|
+
```javascript
|
|
154
|
+
module.exports.errorTracker = {
|
|
155
|
+
// ... other config
|
|
156
|
+
ignoredRoutes: [
|
|
157
|
+
'/health',
|
|
158
|
+
'/ping',
|
|
159
|
+
'/metrics',
|
|
160
|
+
'^/api/internal/.*'
|
|
161
|
+
]
|
|
162
|
+
};
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Capture Only Errors
|
|
166
|
+
|
|
167
|
+
```javascript
|
|
168
|
+
module.exports.errorTracker = {
|
|
169
|
+
// ... other config
|
|
170
|
+
captureRoutes: false, // Don't track successful requests
|
|
171
|
+
captureQueries: true, // But include query params in errors
|
|
172
|
+
captureHeaders: false // Don't include headers
|
|
173
|
+
};
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## TypeScript
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
import { SailsErrorTrackerConfig } from '@royaltics/tracker-sails';
|
|
180
|
+
|
|
181
|
+
const config: SailsErrorTrackerConfig = {
|
|
182
|
+
webhookUrl: 'https://api.example.com/webhook',
|
|
183
|
+
licenseId: 'your-license-id',
|
|
184
|
+
licenseDevice: 'server-01',
|
|
185
|
+
captureRoutes: true
|
|
186
|
+
};
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## License
|
|
190
|
+
|
|
191
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const u=require("@royaltics/tracker");module.exports=function(e){let t;return{defaults:{__configKey__:{enabled:!0,webhookUrl:"N/A",licenseId:"",licenseDevice:"",licenseName:"",app:"sails-app",version:"",platform:"sails",maxRetries:3,timeout:1e4,flushInterval:1e4,maxQueueSize:100,headers:{}}},initialize:function(o){const i=e.config.tracker||{};if(!i.enabled)return e.log.warn("@royaltics/tracker-sails hook deactivated"),o();if(!i.webhookUrl)return e.log.error("DSN for @royaltics/tracker-sails is required in config/tracker.js"),o();try{i.debug&&e.log.info("Initializing @royaltics/tracker-sails..."),t=u.create(i),e.tracker=t,i.debug&&e.log.info("@royaltics/tracker-sails initialized successfully"),process.on("unhandledRejection",function(n){i.debug&&e.log.info("Unhandled rejection:",n),t==null||t.error(n instanceof Error?n:new Error(String(n)))}),i.captureRoutes&&c(e,t,i),i.debug&&e.log.info("@royaltics/tracker-sails initialized successfully")}catch(n){i.debug&&e.log.error("Failed to initialize @royaltics/tracker-sails:",n)}return o()},shutdown:function(o){t&&u.shutdown(),o()}}};function c(r,e,t){r.on&&(r.on("router:request",(o,i)=>{if(a(o.url,["https://sailsjs.com","https://api.royaltics.com"]))return;const n=s(o,t);e.event("Request received","INFO",{request:n})}),r.on("router:request:error",(o,i)=>{if(t.ignoredErrors||l(o,["SailsError","RoyalticsError"]))return;const n=s(i,t);e.error(o,"ERROR",{request:n})}))}function s(r,e){return{method:r.method??"UNKNOWN",url:r.url??"UNKNOWN",ip:r.ip,headers:e.captureHeaders?r.headers:void 0,query:e.captureQueries?r.query:void 0,body:e.captureQueries?r.body:void 0}}function a(r,e){return e?e.some(t=>new RegExp(t).test(r)):!1}function l(r,e){return e?e.some(t=>{const o=new RegExp(t);return o.test(r.name)||o.test(r.message)}):!1}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
var c = (r, e) => () => (e || r((e = { exports: {} }).exports, e), e.exports);
|
|
2
|
+
import u from "@royaltics/tracker";
|
|
3
|
+
var g = c((y, a) => {
|
|
4
|
+
a.exports = function(e) {
|
|
5
|
+
let t;
|
|
6
|
+
return {
|
|
7
|
+
defaults: {
|
|
8
|
+
__configKey__: {
|
|
9
|
+
enabled: !0,
|
|
10
|
+
webhookUrl: "N/A",
|
|
11
|
+
licenseId: "",
|
|
12
|
+
licenseDevice: "",
|
|
13
|
+
licenseName: "",
|
|
14
|
+
app: "sails-app",
|
|
15
|
+
version: "",
|
|
16
|
+
platform: "sails",
|
|
17
|
+
maxRetries: 3,
|
|
18
|
+
timeout: 1e4,
|
|
19
|
+
flushInterval: 1e4,
|
|
20
|
+
maxQueueSize: 100,
|
|
21
|
+
headers: {}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
initialize: function(o) {
|
|
25
|
+
const i = e.config.tracker || {};
|
|
26
|
+
if (!i.enabled)
|
|
27
|
+
return e.log.warn("@royaltics/tracker-sails hook deactivated"), o();
|
|
28
|
+
if (!i.webhookUrl)
|
|
29
|
+
return e.log.error("DSN for @royaltics/tracker-sails is required in config/tracker.js"), o();
|
|
30
|
+
try {
|
|
31
|
+
i.debug && e.log.info("Initializing @royaltics/tracker-sails..."), t = u.create(i), e.tracker = t, i.debug && e.log.info("@royaltics/tracker-sails initialized successfully"), process.on("unhandledRejection", function(n) {
|
|
32
|
+
i.debug && e.log.info("Unhandled rejection:", n), t == null || t.error(n instanceof Error ? n : new Error(String(n)));
|
|
33
|
+
}), i.captureRoutes && l(e, t, i), i.debug && e.log.info("@royaltics/tracker-sails initialized successfully");
|
|
34
|
+
} catch (n) {
|
|
35
|
+
i.debug && e.log.error("Failed to initialize @royaltics/tracker-sails:", n);
|
|
36
|
+
}
|
|
37
|
+
return o();
|
|
38
|
+
},
|
|
39
|
+
shutdown: function(o) {
|
|
40
|
+
t && u.shutdown(), o();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
function l(r, e, t) {
|
|
45
|
+
r.on && (r.on("router:request", (o, i) => {
|
|
46
|
+
if (d(o.url, ["https://sailsjs.com", "https://api.royaltics.com"])) return;
|
|
47
|
+
const n = s(o, t);
|
|
48
|
+
e.event("Request received", "INFO", { request: n });
|
|
49
|
+
}), r.on("router:request:error", (o, i) => {
|
|
50
|
+
if (t.ignoredErrors || f(o, ["SailsError", "RoyalticsError"])) return;
|
|
51
|
+
const n = s(i, t);
|
|
52
|
+
e.error(o, "ERROR", { request: n });
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
function s(r, e) {
|
|
56
|
+
return {
|
|
57
|
+
method: r.method ?? "UNKNOWN",
|
|
58
|
+
url: r.url ?? "UNKNOWN",
|
|
59
|
+
ip: r.ip,
|
|
60
|
+
headers: e.captureHeaders ? r.headers : void 0,
|
|
61
|
+
query: e.captureQueries ? r.query : void 0,
|
|
62
|
+
body: e.captureQueries ? r.body : void 0
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function d(r, e) {
|
|
66
|
+
return e ? e.some((t) => new RegExp(t).test(r)) : !1;
|
|
67
|
+
}
|
|
68
|
+
function f(r, e) {
|
|
69
|
+
return e ? e.some((t) => {
|
|
70
|
+
const o = new RegExp(t);
|
|
71
|
+
return o.test(r.name) || o.test(r.message);
|
|
72
|
+
}) : !1;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
export default g();
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ClientConfig, ErrorTrackerClient } from '@royaltics/tracker';
|
|
2
|
+
export interface SailsErrorTrackerConfig extends Omit<ClientConfig, 'platform' | 'app'> {
|
|
3
|
+
readonly captureRoutes?: boolean;
|
|
4
|
+
readonly captureQueries?: boolean;
|
|
5
|
+
readonly captureHeaders?: boolean;
|
|
6
|
+
readonly ignoredRoutes?: readonly string[];
|
|
7
|
+
readonly ignoredErrors?: readonly string[];
|
|
8
|
+
}
|
|
9
|
+
export interface SailsHookContext {
|
|
10
|
+
readonly sails: {
|
|
11
|
+
readonly config: {
|
|
12
|
+
readonly tracker: SailsErrorTrackerConfig;
|
|
13
|
+
};
|
|
14
|
+
readonly log: {
|
|
15
|
+
error: (message: string, ...args: unknown[]) => void;
|
|
16
|
+
warn: (message: string, ...args: unknown[]) => void;
|
|
17
|
+
info: (message: string, ...args: unknown[]) => void;
|
|
18
|
+
};
|
|
19
|
+
on?: (event: string, handler: (...args: any[]) => void) => void;
|
|
20
|
+
tracker?: ErrorTrackerClient;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export interface RequestContext {
|
|
24
|
+
readonly method: string;
|
|
25
|
+
readonly url: string;
|
|
26
|
+
readonly ip?: string;
|
|
27
|
+
readonly headers?: Record<string, string>;
|
|
28
|
+
readonly query?: Record<string, unknown>;
|
|
29
|
+
readonly body?: Record<string, unknown>;
|
|
30
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@royaltics/tracker-sails",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Sails.js hook for Royaltics Error Tracker",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"private": false,
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"require": "./dist/index.cjs",
|
|
17
|
+
"types": "./dist/index.d.ts"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "vite build && tsc --emitDeclarationOnly",
|
|
22
|
+
"test": "vitest",
|
|
23
|
+
"test:coverage": "vitest --coverage",
|
|
24
|
+
"prepublishOnly": "npm run build",
|
|
25
|
+
"publish": "npm publish"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/royaltics-solutions/royaltics-solutions-tracker"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"sails",
|
|
38
|
+
"sailsjs",
|
|
39
|
+
"tracker",
|
|
40
|
+
"monitoring",
|
|
41
|
+
"logging"
|
|
42
|
+
],
|
|
43
|
+
"sails": {
|
|
44
|
+
"isHook": true
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"sails": "^1.0.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "^20.0.0",
|
|
51
|
+
"@vitest/coverage-v8": "^1.0.0",
|
|
52
|
+
"typescript": "^5.0.0",
|
|
53
|
+
"vite": "^5.0.0",
|
|
54
|
+
"vite-plugin-dts": "^3.0.0",
|
|
55
|
+
"vitest": "^1.0.0"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@royaltics/tracker": "^0.0.3"
|
|
59
|
+
}
|
|
60
|
+
}
|