@statly/observe 0.1.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 +21 -0
- package/README.md +341 -0
- package/dist/chunk-PETWPVHU.mjs +1090 -0
- package/dist/index.d.mts +273 -0
- package/dist/index.d.ts +273 -0
- package/dist/index.js +1138 -0
- package/dist/index.mjs +50 -0
- package/dist/integrations/express.d.mts +71 -0
- package/dist/integrations/express.d.ts +71 -0
- package/dist/integrations/express.js +861 -0
- package/dist/integrations/express.mjs +8 -0
- package/dist/integrations/fastify.d.mts +77 -0
- package/dist/integrations/fastify.d.ts +77 -0
- package/dist/integrations/fastify.js +870 -0
- package/dist/integrations/fastify.mjs +10 -0
- package/dist/integrations/nextjs.d.mts +179 -0
- package/dist/integrations/nextjs.d.ts +179 -0
- package/dist/integrations/nextjs.js +901 -0
- package/dist/integrations/nextjs.mjs +16 -0
- package/package.json +74 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Statly
|
|
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,341 @@
|
|
|
1
|
+
# Statly Observe SDK for Node.js
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@statly/observe)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
Error tracking and monitoring for JavaScript and TypeScript applications. Capture exceptions, track releases, and debug issues faster.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- Automatic error capturing with stack traces
|
|
11
|
+
- Breadcrumbs for debugging context
|
|
12
|
+
- User context tracking
|
|
13
|
+
- Release tracking
|
|
14
|
+
- Framework integrations (Express, Next.js, Fastify)
|
|
15
|
+
- TypeScript support
|
|
16
|
+
- Minimal overhead
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @statly/observe
|
|
22
|
+
# or
|
|
23
|
+
yarn add @statly/observe
|
|
24
|
+
# or
|
|
25
|
+
pnpm add @statly/observe
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Getting Your DSN
|
|
29
|
+
|
|
30
|
+
1. Go to [statly.live/dashboard/observe/setup](https://statly.live/dashboard/observe/setup)
|
|
31
|
+
2. Create an API key for Observe
|
|
32
|
+
3. Copy your DSN (format: `https://<api-key>@statly.live/<org-slug>`)
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { Statly } from '@statly/observe';
|
|
38
|
+
|
|
39
|
+
// Initialize the SDK
|
|
40
|
+
Statly.init({
|
|
41
|
+
dsn: 'https://sk_live_xxx@statly.live/your-org',
|
|
42
|
+
release: '1.0.0',
|
|
43
|
+
environment: 'production',
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Errors are captured automatically via global handlers
|
|
47
|
+
|
|
48
|
+
// Manual capture
|
|
49
|
+
try {
|
|
50
|
+
riskyOperation();
|
|
51
|
+
} catch (error) {
|
|
52
|
+
Statly.captureException(error);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Capture a message
|
|
56
|
+
Statly.captureMessage('User completed checkout', 'info');
|
|
57
|
+
|
|
58
|
+
// Set user context
|
|
59
|
+
Statly.setUser({
|
|
60
|
+
id: 'user-123',
|
|
61
|
+
email: 'user@example.com',
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Add breadcrumb for debugging
|
|
65
|
+
Statly.addBreadcrumb({
|
|
66
|
+
category: 'auth',
|
|
67
|
+
message: 'User logged in',
|
|
68
|
+
level: 'info',
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Flush before exit (important for serverless)
|
|
72
|
+
await Statly.close();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Framework Integrations
|
|
76
|
+
|
|
77
|
+
### Express
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import express from 'express';
|
|
81
|
+
import { Statly, requestHandler, expressErrorHandler } from '@statly/observe';
|
|
82
|
+
|
|
83
|
+
const app = express();
|
|
84
|
+
|
|
85
|
+
// Initialize first
|
|
86
|
+
Statly.init({
|
|
87
|
+
dsn: 'https://sk_live_xxx@statly.live/your-org',
|
|
88
|
+
environment: process.env.NODE_ENV,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Add request handler FIRST (before routes)
|
|
92
|
+
app.use(requestHandler());
|
|
93
|
+
|
|
94
|
+
// Your routes
|
|
95
|
+
app.get('/', (req, res) => {
|
|
96
|
+
res.send('Hello World');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
app.get('/error', (req, res) => {
|
|
100
|
+
throw new Error('Test error');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Add error handler LAST (after routes)
|
|
104
|
+
app.use(expressErrorHandler());
|
|
105
|
+
|
|
106
|
+
app.listen(3000);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Next.js (App Router)
|
|
110
|
+
|
|
111
|
+
**Route Handlers:**
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
// app/api/example/route.ts
|
|
115
|
+
import { withStatly } from '@statly/observe';
|
|
116
|
+
|
|
117
|
+
export const GET = withStatly(async (request) => {
|
|
118
|
+
// Errors are automatically captured
|
|
119
|
+
const data = await fetchData();
|
|
120
|
+
return Response.json({ data });
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Error Boundary:**
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// app/error.tsx
|
|
128
|
+
'use client';
|
|
129
|
+
|
|
130
|
+
import { useEffect } from 'react';
|
|
131
|
+
import { captureNextJsError } from '@statly/observe';
|
|
132
|
+
|
|
133
|
+
export default function Error({
|
|
134
|
+
error,
|
|
135
|
+
reset,
|
|
136
|
+
}: {
|
|
137
|
+
error: Error & { digest?: string };
|
|
138
|
+
reset: () => void;
|
|
139
|
+
}) {
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
captureNextJsError(error);
|
|
142
|
+
}, [error]);
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<div>
|
|
146
|
+
<h2>Something went wrong!</h2>
|
|
147
|
+
<button onClick={reset}>Try again</button>
|
|
148
|
+
</div>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Server Actions:**
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
'use server';
|
|
157
|
+
|
|
158
|
+
import { withStatlyServerAction } from '@statly/observe';
|
|
159
|
+
|
|
160
|
+
export const submitForm = withStatlyServerAction(
|
|
161
|
+
async (formData: FormData) => {
|
|
162
|
+
// Your action code - errors are captured automatically
|
|
163
|
+
const email = formData.get('email');
|
|
164
|
+
await saveToDatabase(email);
|
|
165
|
+
},
|
|
166
|
+
'submitForm' // Action name for grouping
|
|
167
|
+
);
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Fastify
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
import Fastify from 'fastify';
|
|
174
|
+
import { Statly, statlyFastifyPlugin } from '@statly/observe';
|
|
175
|
+
|
|
176
|
+
const fastify = Fastify();
|
|
177
|
+
|
|
178
|
+
Statly.init({
|
|
179
|
+
dsn: 'https://sk_live_xxx@statly.live/your-org',
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Register the plugin
|
|
183
|
+
fastify.register(statlyFastifyPlugin, {
|
|
184
|
+
captureValidationErrors: true,
|
|
185
|
+
skipStatusCodes: [400, 401, 403, 404], // Don't capture these as errors
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
fastify.get('/', async () => {
|
|
189
|
+
return { hello: 'world' };
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
fastify.listen({ port: 3000 });
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Configuration Options
|
|
196
|
+
|
|
197
|
+
| Option | Type | Default | Description |
|
|
198
|
+
|--------|------|---------|-------------|
|
|
199
|
+
| `dsn` | `string` | **Required** | Your project's Data Source Name |
|
|
200
|
+
| `environment` | `string` | `undefined` | Environment name (production, staging, development) |
|
|
201
|
+
| `release` | `string` | `undefined` | Release/version identifier for tracking |
|
|
202
|
+
| `debug` | `boolean` | `false` | Enable debug logging to console |
|
|
203
|
+
| `sampleRate` | `number` | `1.0` | Sample rate for events (0.0 to 1.0) |
|
|
204
|
+
| `maxBreadcrumbs` | `number` | `100` | Maximum breadcrumbs to store |
|
|
205
|
+
| `autoCapture` | `boolean` | `true` | Auto-attach global error handlers |
|
|
206
|
+
| `beforeSend` | `function` | `undefined` | Callback to modify/filter events before sending |
|
|
207
|
+
|
|
208
|
+
### beforeSend Example
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
Statly.init({
|
|
212
|
+
dsn: '...',
|
|
213
|
+
beforeSend: (event) => {
|
|
214
|
+
// Filter out specific errors
|
|
215
|
+
if (event.message?.includes('ResizeObserver')) {
|
|
216
|
+
return null; // Drop the event
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Scrub sensitive data
|
|
220
|
+
if (event.extra?.password) {
|
|
221
|
+
delete event.extra.password;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return event;
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## API Reference
|
|
230
|
+
|
|
231
|
+
### Statly.captureException(error, context?)
|
|
232
|
+
|
|
233
|
+
Capture an exception with optional additional context:
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
try {
|
|
237
|
+
await processPayment(order);
|
|
238
|
+
} catch (error) {
|
|
239
|
+
Statly.captureException(error, {
|
|
240
|
+
extra: {
|
|
241
|
+
orderId: order.id,
|
|
242
|
+
amount: order.total,
|
|
243
|
+
},
|
|
244
|
+
tags: {
|
|
245
|
+
paymentProvider: 'stripe',
|
|
246
|
+
},
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Statly.captureMessage(message, level?)
|
|
252
|
+
|
|
253
|
+
Capture a message event:
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
Statly.captureMessage('User signed up', 'info');
|
|
257
|
+
Statly.captureMessage('Payment failed after 3 retries', 'warning');
|
|
258
|
+
Statly.captureMessage('Database connection lost', 'error');
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Levels: `'debug'` | `'info'` | `'warning'` | `'error'` | `'fatal'`
|
|
262
|
+
|
|
263
|
+
### Statly.setUser(user)
|
|
264
|
+
|
|
265
|
+
Set user context for all subsequent events:
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
Statly.setUser({
|
|
269
|
+
id: 'user-123',
|
|
270
|
+
email: 'user@example.com',
|
|
271
|
+
username: 'johndoe',
|
|
272
|
+
// Custom fields
|
|
273
|
+
subscription: 'premium',
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Clear user on logout
|
|
277
|
+
Statly.setUser(null);
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Statly.setTag(key, value) / Statly.setTags(tags)
|
|
281
|
+
|
|
282
|
+
Set tags for filtering and searching:
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
Statly.setTag('version', '1.0.0');
|
|
286
|
+
|
|
287
|
+
Statly.setTags({
|
|
288
|
+
environment: 'production',
|
|
289
|
+
server: 'web-1',
|
|
290
|
+
region: 'us-east-1',
|
|
291
|
+
});
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Statly.addBreadcrumb(breadcrumb)
|
|
295
|
+
|
|
296
|
+
Add a breadcrumb for debugging context:
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
Statly.addBreadcrumb({
|
|
300
|
+
message: 'User clicked checkout button',
|
|
301
|
+
category: 'ui.click',
|
|
302
|
+
level: 'info',
|
|
303
|
+
data: {
|
|
304
|
+
buttonId: 'checkout-btn',
|
|
305
|
+
cartItems: 3,
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Statly.flush() / Statly.close()
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
// Flush pending events (keeps SDK running)
|
|
314
|
+
await Statly.flush();
|
|
315
|
+
|
|
316
|
+
// Flush and close (use before process exit)
|
|
317
|
+
await Statly.close();
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## TypeScript Support
|
|
321
|
+
|
|
322
|
+
Full TypeScript support with exported types:
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
import type {
|
|
326
|
+
StatlyOptions,
|
|
327
|
+
StatlyEvent,
|
|
328
|
+
User,
|
|
329
|
+
Breadcrumb,
|
|
330
|
+
EventLevel,
|
|
331
|
+
} from '@statly/observe';
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## Requirements
|
|
335
|
+
|
|
336
|
+
- Node.js 16+
|
|
337
|
+
- Works in browser environments (with bundler)
|
|
338
|
+
|
|
339
|
+
## License
|
|
340
|
+
|
|
341
|
+
MIT
|