@justanalyticsapp/node 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/dist/client.d.ts +286 -0
- package/dist/client.js +681 -0
- package/dist/client.js.map +1 -0
- package/dist/context.d.ts +126 -0
- package/dist/context.js +170 -0
- package/dist/context.js.map +1 -0
- package/dist/errors.d.ts +135 -0
- package/dist/errors.js +180 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +301 -0
- package/dist/index.js +314 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/express.d.ts +77 -0
- package/dist/integrations/express.js +87 -0
- package/dist/integrations/express.js.map +1 -0
- package/dist/integrations/http.d.ts +129 -0
- package/dist/integrations/http.js +465 -0
- package/dist/integrations/http.js.map +1 -0
- package/dist/integrations/metrics.d.ts +110 -0
- package/dist/integrations/metrics.js +313 -0
- package/dist/integrations/metrics.js.map +1 -0
- package/dist/integrations/next.d.ts +252 -0
- package/dist/integrations/next.js +480 -0
- package/dist/integrations/next.js.map +1 -0
- package/dist/integrations/pg.d.ts +169 -0
- package/dist/integrations/pg.js +616 -0
- package/dist/integrations/pg.js.map +1 -0
- package/dist/integrations/pino.d.ts +52 -0
- package/dist/integrations/pino.js +153 -0
- package/dist/integrations/pino.js.map +1 -0
- package/dist/integrations/redis.d.ts +190 -0
- package/dist/integrations/redis.js +597 -0
- package/dist/integrations/redis.js.map +1 -0
- package/dist/integrations/winston.d.ts +48 -0
- package/dist/integrations/winston.js +99 -0
- package/dist/integrations/winston.js.map +1 -0
- package/dist/logger.d.ts +148 -0
- package/dist/logger.js +162 -0
- package/dist/logger.js.map +1 -0
- package/dist/span.d.ts +192 -0
- package/dist/span.js +197 -0
- package/dist/span.js.map +1 -0
- package/dist/transport.d.ts +246 -0
- package/dist/transport.js +654 -0
- package/dist/transport.js.map +1 -0
- package/dist/utils/headers.d.ts +60 -0
- package/dist/utils/headers.js +93 -0
- package/dist/utils/headers.js.map +1 -0
- package/dist/utils/id.d.ts +23 -0
- package/dist/utils/id.js +36 -0
- package/dist/utils/id.js.map +1 -0
- package/package.json +65 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/node-sdk/src/index.ts
|
|
3
|
+
* @description Public API surface for @justanalyticsapp/node SDK.
|
|
4
|
+
*
|
|
5
|
+
* Implements Story 035 - Node.js SDK Core
|
|
6
|
+
* Updated for Story 041 - Server-Side Error Tracking via SDK
|
|
7
|
+
* Updated for Story 046 - SDK Log Integration
|
|
8
|
+
* Updated for Story 048 - Infrastructure Metrics Collection
|
|
9
|
+
*
|
|
10
|
+
* This module creates a singleton JustAnalyticsClient instance and exports
|
|
11
|
+
* both a default namespace object (`JA`) and individual named exports for
|
|
12
|
+
* tree-shaking.
|
|
13
|
+
*
|
|
14
|
+
* Usage (default import):
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import JA from '@justanalyticsapp/node';
|
|
17
|
+
* JA.init({ siteId: '...', apiKey: '...', serviceName: 'api-server' });
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* Usage (named imports):
|
|
21
|
+
* ```typescript
|
|
22
|
+
* import { init, startSpan, setUser, flush, captureException } from '@justanalyticsapp/node';
|
|
23
|
+
* init({ siteId: '...', apiKey: '...', serviceName: 'api-server' });
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* References:
|
|
27
|
+
* - Expansion Roadmap: "SDK auto-instruments by default. Users get value with two lines of code."
|
|
28
|
+
*/
|
|
29
|
+
import { JustAnalyticsOptions } from './client';
|
|
30
|
+
import { Span, SpanOptions, SpanKind, SpanStatus, SpanPayload, SpanEvent } from './span';
|
|
31
|
+
import { UserContext, TraceContext } from './context';
|
|
32
|
+
import { CaptureOptions, ServerErrorPayload } from './errors';
|
|
33
|
+
import { Logger, LogPayload, LogLevel } from './logger';
|
|
34
|
+
import { parseTraceparent, serializeTraceparent, TraceparentData } from './utils/headers';
|
|
35
|
+
import { generateTraceId, generateSpanId } from './utils/id';
|
|
36
|
+
import { HttpIntegrationOptions } from './integrations/http';
|
|
37
|
+
import { PgIntegrationOptions } from './integrations/pg';
|
|
38
|
+
import { RedisIntegrationOptions } from './integrations/redis';
|
|
39
|
+
import { MetricsIntegrationOptions, MetricPayload } from './integrations/metrics';
|
|
40
|
+
import { expressMiddleware as createExpressMiddleware } from './integrations/express';
|
|
41
|
+
import type { NextJustAnalyticsOptions, NextRequestLike, NextResponseLike, NextRouteHandler, NextMiddlewareFunction, ServerComponentFunction } from './integrations/next';
|
|
42
|
+
/**
|
|
43
|
+
* Initialize the JustAnalytics SDK.
|
|
44
|
+
*
|
|
45
|
+
* Must be called before any other SDK method. Can only be called once;
|
|
46
|
+
* subsequent calls log a warning and are ignored.
|
|
47
|
+
*
|
|
48
|
+
* @param options - SDK configuration (siteId, apiKey, serviceName are required)
|
|
49
|
+
* @throws Error if required fields are missing
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* import JA from '@justanalyticsapp/node';
|
|
54
|
+
*
|
|
55
|
+
* JA.init({
|
|
56
|
+
* siteId: 'site_abc123',
|
|
57
|
+
* apiKey: 'ja_sk_your_api_key_here',
|
|
58
|
+
* serviceName: 'api-server',
|
|
59
|
+
* environment: 'production',
|
|
60
|
+
* debug: false,
|
|
61
|
+
* });
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
declare function init(options: JustAnalyticsOptions): void;
|
|
65
|
+
/**
|
|
66
|
+
* Whether `init()` has been called successfully.
|
|
67
|
+
*
|
|
68
|
+
* @returns true if the SDK is initialized, false otherwise
|
|
69
|
+
*/
|
|
70
|
+
declare function isInitialized(): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Create and execute a span.
|
|
73
|
+
*
|
|
74
|
+
* The callback runs inside an AsyncLocalStorage context with the span
|
|
75
|
+
* as the active span. Nested `startSpan()` calls automatically create
|
|
76
|
+
* parent-child relationships.
|
|
77
|
+
*
|
|
78
|
+
* @param name - Operation name for the span
|
|
79
|
+
* @param callback - Function to execute within the span
|
|
80
|
+
* @returns The return value of the callback
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* // Simple sync span
|
|
85
|
+
* const result = JA.startSpan('process-order', (span) => {
|
|
86
|
+
* span.setAttribute('order.id', '12345');
|
|
87
|
+
* return processOrder();
|
|
88
|
+
* });
|
|
89
|
+
*
|
|
90
|
+
* // Async span
|
|
91
|
+
* const data = await JA.startSpan('fetch-user', async (span) => {
|
|
92
|
+
* span.setAttribute('user.id', userId);
|
|
93
|
+
* return await db.users.findUnique({ where: { id: userId } });
|
|
94
|
+
* });
|
|
95
|
+
*
|
|
96
|
+
* // With options
|
|
97
|
+
* JA.startSpan('http-call', { kind: 'client' }, async (span) => {
|
|
98
|
+
* return await fetch('https://api.example.com/data');
|
|
99
|
+
* });
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
declare function startSpan<T>(name: string, callback: (span: Span) => T): T;
|
|
103
|
+
declare function startSpan<T>(name: string, options: SpanOptions, callback: (span: Span) => T): T;
|
|
104
|
+
/**
|
|
105
|
+
* Capture an exception and send it to JustAnalytics.
|
|
106
|
+
*
|
|
107
|
+
* Automatically attaches the current traceId, spanId, user context,
|
|
108
|
+
* and tags from the AsyncLocalStorage context.
|
|
109
|
+
*
|
|
110
|
+
* @param error - Error object or any value (non-Error values are coerced to string)
|
|
111
|
+
* @param options - Optional tags, extra, user, level, fingerprint
|
|
112
|
+
* @returns A unique eventId for correlation, or empty string if SDK is disabled
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* try {
|
|
117
|
+
* await riskyOperation();
|
|
118
|
+
* } catch (error) {
|
|
119
|
+
* JA.captureException(error, { tags: { module: 'payments' } });
|
|
120
|
+
* }
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
declare function captureException(error: unknown, options?: CaptureOptions): string;
|
|
124
|
+
/**
|
|
125
|
+
* Capture a message and send it to JustAnalytics.
|
|
126
|
+
*
|
|
127
|
+
* @param message - The message string
|
|
128
|
+
* @param level - Severity level (default: 'info')
|
|
129
|
+
* @param options - Optional tags, extra, user, fingerprint
|
|
130
|
+
* @returns A unique eventId for correlation, or empty string if SDK is disabled
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```typescript
|
|
134
|
+
* JA.captureMessage('User exceeded rate limit', 'warning', {
|
|
135
|
+
* tags: { userId: user.id },
|
|
136
|
+
* extra: { requestCount: count },
|
|
137
|
+
* });
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
declare function captureMessage(message: string, level?: 'debug' | 'info' | 'warning' | 'error' | 'fatal', options?: CaptureOptions): string;
|
|
141
|
+
/**
|
|
142
|
+
* Set user context for the current async scope.
|
|
143
|
+
*
|
|
144
|
+
* User information is attached as attributes on all spans created
|
|
145
|
+
* within the current AsyncLocalStorage scope.
|
|
146
|
+
*
|
|
147
|
+
* @param user - User context (id, email, username)
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```typescript
|
|
151
|
+
* JA.setUser({ id: 'user-123', email: 'alice@example.com' });
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
declare function setUser(user: UserContext): void;
|
|
155
|
+
/**
|
|
156
|
+
* Set a tag for the current async scope.
|
|
157
|
+
*
|
|
158
|
+
* Tags are attached as attributes on all spans created within the
|
|
159
|
+
* current AsyncLocalStorage scope.
|
|
160
|
+
*
|
|
161
|
+
* @param key - Tag key
|
|
162
|
+
* @param value - Tag value
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* JA.setTag('feature', 'checkout');
|
|
167
|
+
* JA.setTag('region', 'us-east-1');
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
declare function setTag(key: string, value: string): void;
|
|
171
|
+
/**
|
|
172
|
+
* Get the currently active span from AsyncLocalStorage.
|
|
173
|
+
*
|
|
174
|
+
* @returns The active Span, or null if not in a traced context
|
|
175
|
+
*/
|
|
176
|
+
declare function getActiveSpan(): Span | null;
|
|
177
|
+
/**
|
|
178
|
+
* Get the current trace ID from AsyncLocalStorage.
|
|
179
|
+
*
|
|
180
|
+
* @returns The trace ID string, or null if not in a traced context
|
|
181
|
+
*/
|
|
182
|
+
declare function getTraceId(): string | null;
|
|
183
|
+
/**
|
|
184
|
+
* Manually flush all pending spans and errors to the server.
|
|
185
|
+
*
|
|
186
|
+
* Useful for ensuring data is sent before a serverless function
|
|
187
|
+
* completes, or in tests.
|
|
188
|
+
*
|
|
189
|
+
* @returns Promise that resolves when the flush completes
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```typescript
|
|
193
|
+
* // In a serverless handler
|
|
194
|
+
* export async function handler(event) {
|
|
195
|
+
* const result = await JA.startSpan('handler', async (span) => {
|
|
196
|
+
* return await processEvent(event);
|
|
197
|
+
* });
|
|
198
|
+
* await JA.flush(); // Ensure spans are sent
|
|
199
|
+
* return result;
|
|
200
|
+
* }
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
declare function flush(): Promise<void>;
|
|
204
|
+
/**
|
|
205
|
+
* Get an Express middleware function that updates server span operation
|
|
206
|
+
* names with the matched Express route pattern.
|
|
207
|
+
*
|
|
208
|
+
* Register with `app.use(JA.expressMiddleware())` to have span names
|
|
209
|
+
* reflect Express route patterns (e.g., `GET /api/users/:id`) instead
|
|
210
|
+
* of raw URL paths (e.g., `GET /api/users/42`).
|
|
211
|
+
*
|
|
212
|
+
* @returns Express-compatible middleware: `(req, res, next) => void`
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```typescript
|
|
216
|
+
* import JA from '@justanalyticsapp/node';
|
|
217
|
+
* import express from 'express';
|
|
218
|
+
*
|
|
219
|
+
* JA.init({ siteId: '...', apiKey: '...', serviceName: 'api' });
|
|
220
|
+
*
|
|
221
|
+
* const app = express();
|
|
222
|
+
* app.use(JA.expressMiddleware());
|
|
223
|
+
*
|
|
224
|
+
* app.get('/api/users/:id', handler);
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
227
|
+
declare function expressMiddleware(): ReturnType<typeof createExpressMiddleware>;
|
|
228
|
+
/**
|
|
229
|
+
* Shut down the SDK: flush remaining spans, stop timers, deregister handlers.
|
|
230
|
+
*
|
|
231
|
+
* Call this during graceful shutdown of your application.
|
|
232
|
+
*
|
|
233
|
+
* @returns Promise that resolves when shutdown is complete
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* ```typescript
|
|
237
|
+
* process.on('SIGTERM', async () => {
|
|
238
|
+
* await JA.close();
|
|
239
|
+
* process.exit(0);
|
|
240
|
+
* });
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
243
|
+
declare function close(): Promise<void>;
|
|
244
|
+
/**
|
|
245
|
+
* Record a custom infrastructure metric.
|
|
246
|
+
*
|
|
247
|
+
* @param metricName - Metric name using dot notation (e.g., 'custom.queue_size')
|
|
248
|
+
* @param value - Numeric value
|
|
249
|
+
* @param tags - Optional additional tags
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```typescript
|
|
253
|
+
* JA.recordMetric('custom.queue_size', 42, { queue: 'emails' });
|
|
254
|
+
* JA.recordMetric('custom.request_duration_ms', 150.5);
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
257
|
+
declare function recordMetric(metricName: string, value: number, tags?: Record<string, unknown>): void;
|
|
258
|
+
/**
|
|
259
|
+
* JustAnalytics SDK namespace object.
|
|
260
|
+
*
|
|
261
|
+
* Provides all SDK methods as a single object for convenient default import:
|
|
262
|
+
* ```typescript
|
|
263
|
+
* import JA from '@justanalyticsapp/node';
|
|
264
|
+
* JA.init({ ... });
|
|
265
|
+
* JA.startSpan('op', (span) => { ... });
|
|
266
|
+
* JA.captureException(error);
|
|
267
|
+
* JA.captureMessage('hello', 'info');
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
270
|
+
declare const JA: {
|
|
271
|
+
init: typeof init;
|
|
272
|
+
isInitialized: typeof isInitialized;
|
|
273
|
+
startSpan: typeof startSpan;
|
|
274
|
+
captureException: typeof captureException;
|
|
275
|
+
captureMessage: typeof captureMessage;
|
|
276
|
+
setUser: typeof setUser;
|
|
277
|
+
setTag: typeof setTag;
|
|
278
|
+
getActiveSpan: typeof getActiveSpan;
|
|
279
|
+
getTraceId: typeof getTraceId;
|
|
280
|
+
expressMiddleware: typeof expressMiddleware;
|
|
281
|
+
flush: typeof flush;
|
|
282
|
+
close: typeof close;
|
|
283
|
+
recordMetric: typeof recordMetric;
|
|
284
|
+
/**
|
|
285
|
+
* Logger instance for structured logging with automatic trace correlation.
|
|
286
|
+
*
|
|
287
|
+
* Returns a no-op Logger before `init()` is called or after `close()`.
|
|
288
|
+
* Safe to access at any time -- never null, never throws.
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* ```typescript
|
|
292
|
+
* JA.logger.info('User logged in', { userId: 'u123' });
|
|
293
|
+
* JA.logger.error('Payment failed', { orderId, reason });
|
|
294
|
+
* ```
|
|
295
|
+
*/
|
|
296
|
+
readonly logger: Logger;
|
|
297
|
+
};
|
|
298
|
+
export default JA;
|
|
299
|
+
export { init, isInitialized, startSpan, captureException, captureMessage, setUser, setTag, getActiveSpan, getTraceId, expressMiddleware, flush, close, recordMetric, };
|
|
300
|
+
export type { JustAnalyticsOptions, SpanOptions, SpanKind, SpanStatus, SpanPayload, SpanEvent, UserContext, TraceContext, TraceparentData, HttpIntegrationOptions, PgIntegrationOptions, RedisIntegrationOptions, CaptureOptions, ServerErrorPayload, NextJustAnalyticsOptions, NextRequestLike, NextResponseLike, NextRouteHandler, NextMiddlewareFunction, ServerComponentFunction, LogPayload, LogLevel, MetricPayload, MetricsIntegrationOptions, };
|
|
301
|
+
export { Span, parseTraceparent, serializeTraceparent, generateTraceId, generateSpanId, Logger };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file packages/node-sdk/src/index.ts
|
|
4
|
+
* @description Public API surface for @justanalyticsapp/node SDK.
|
|
5
|
+
*
|
|
6
|
+
* Implements Story 035 - Node.js SDK Core
|
|
7
|
+
* Updated for Story 041 - Server-Side Error Tracking via SDK
|
|
8
|
+
* Updated for Story 046 - SDK Log Integration
|
|
9
|
+
* Updated for Story 048 - Infrastructure Metrics Collection
|
|
10
|
+
*
|
|
11
|
+
* This module creates a singleton JustAnalyticsClient instance and exports
|
|
12
|
+
* both a default namespace object (`JA`) and individual named exports for
|
|
13
|
+
* tree-shaking.
|
|
14
|
+
*
|
|
15
|
+
* Usage (default import):
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import JA from '@justanalyticsapp/node';
|
|
18
|
+
* JA.init({ siteId: '...', apiKey: '...', serviceName: 'api-server' });
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* Usage (named imports):
|
|
22
|
+
* ```typescript
|
|
23
|
+
* import { init, startSpan, setUser, flush, captureException } from '@justanalyticsapp/node';
|
|
24
|
+
* init({ siteId: '...', apiKey: '...', serviceName: 'api-server' });
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* References:
|
|
28
|
+
* - Expansion Roadmap: "SDK auto-instruments by default. Users get value with two lines of code."
|
|
29
|
+
*/
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
exports.Logger = exports.generateSpanId = exports.generateTraceId = exports.serializeTraceparent = exports.parseTraceparent = exports.Span = void 0;
|
|
32
|
+
exports.init = init;
|
|
33
|
+
exports.isInitialized = isInitialized;
|
|
34
|
+
exports.startSpan = startSpan;
|
|
35
|
+
exports.captureException = captureException;
|
|
36
|
+
exports.captureMessage = captureMessage;
|
|
37
|
+
exports.setUser = setUser;
|
|
38
|
+
exports.setTag = setTag;
|
|
39
|
+
exports.getActiveSpan = getActiveSpan;
|
|
40
|
+
exports.getTraceId = getTraceId;
|
|
41
|
+
exports.expressMiddleware = expressMiddleware;
|
|
42
|
+
exports.flush = flush;
|
|
43
|
+
exports.close = close;
|
|
44
|
+
exports.recordMetric = recordMetric;
|
|
45
|
+
const client_1 = require("./client");
|
|
46
|
+
const span_1 = require("./span");
|
|
47
|
+
Object.defineProperty(exports, "Span", { enumerable: true, get: function () { return span_1.Span; } });
|
|
48
|
+
const logger_1 = require("./logger");
|
|
49
|
+
Object.defineProperty(exports, "Logger", { enumerable: true, get: function () { return logger_1.Logger; } });
|
|
50
|
+
const headers_1 = require("./utils/headers");
|
|
51
|
+
Object.defineProperty(exports, "parseTraceparent", { enumerable: true, get: function () { return headers_1.parseTraceparent; } });
|
|
52
|
+
Object.defineProperty(exports, "serializeTraceparent", { enumerable: true, get: function () { return headers_1.serializeTraceparent; } });
|
|
53
|
+
const id_1 = require("./utils/id");
|
|
54
|
+
Object.defineProperty(exports, "generateTraceId", { enumerable: true, get: function () { return id_1.generateTraceId; } });
|
|
55
|
+
Object.defineProperty(exports, "generateSpanId", { enumerable: true, get: function () { return id_1.generateSpanId; } });
|
|
56
|
+
// ---------- Singleton Client ----------
|
|
57
|
+
/** Singleton client instance */
|
|
58
|
+
const client = new client_1.JustAnalyticsClient();
|
|
59
|
+
// ---------- Public API Functions ----------
|
|
60
|
+
/**
|
|
61
|
+
* Initialize the JustAnalytics SDK.
|
|
62
|
+
*
|
|
63
|
+
* Must be called before any other SDK method. Can only be called once;
|
|
64
|
+
* subsequent calls log a warning and are ignored.
|
|
65
|
+
*
|
|
66
|
+
* @param options - SDK configuration (siteId, apiKey, serviceName are required)
|
|
67
|
+
* @throws Error if required fields are missing
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* import JA from '@justanalyticsapp/node';
|
|
72
|
+
*
|
|
73
|
+
* JA.init({
|
|
74
|
+
* siteId: 'site_abc123',
|
|
75
|
+
* apiKey: 'ja_sk_your_api_key_here',
|
|
76
|
+
* serviceName: 'api-server',
|
|
77
|
+
* environment: 'production',
|
|
78
|
+
* debug: false,
|
|
79
|
+
* });
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
function init(options) {
|
|
83
|
+
client.init(options);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Whether `init()` has been called successfully.
|
|
87
|
+
*
|
|
88
|
+
* @returns true if the SDK is initialized, false otherwise
|
|
89
|
+
*/
|
|
90
|
+
function isInitialized() {
|
|
91
|
+
return client.isInitialized();
|
|
92
|
+
}
|
|
93
|
+
function startSpan(name, callbackOrOptions, maybeCallback) {
|
|
94
|
+
return client.startSpan(name, callbackOrOptions, maybeCallback);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Capture an exception and send it to JustAnalytics.
|
|
98
|
+
*
|
|
99
|
+
* Automatically attaches the current traceId, spanId, user context,
|
|
100
|
+
* and tags from the AsyncLocalStorage context.
|
|
101
|
+
*
|
|
102
|
+
* @param error - Error object or any value (non-Error values are coerced to string)
|
|
103
|
+
* @param options - Optional tags, extra, user, level, fingerprint
|
|
104
|
+
* @returns A unique eventId for correlation, or empty string if SDK is disabled
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* try {
|
|
109
|
+
* await riskyOperation();
|
|
110
|
+
* } catch (error) {
|
|
111
|
+
* JA.captureException(error, { tags: { module: 'payments' } });
|
|
112
|
+
* }
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
function captureException(error, options) {
|
|
116
|
+
return client.captureException(error, options);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Capture a message and send it to JustAnalytics.
|
|
120
|
+
*
|
|
121
|
+
* @param message - The message string
|
|
122
|
+
* @param level - Severity level (default: 'info')
|
|
123
|
+
* @param options - Optional tags, extra, user, fingerprint
|
|
124
|
+
* @returns A unique eventId for correlation, or empty string if SDK is disabled
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* JA.captureMessage('User exceeded rate limit', 'warning', {
|
|
129
|
+
* tags: { userId: user.id },
|
|
130
|
+
* extra: { requestCount: count },
|
|
131
|
+
* });
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
function captureMessage(message, level, options) {
|
|
135
|
+
return client.captureMessage(message, level, options);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Set user context for the current async scope.
|
|
139
|
+
*
|
|
140
|
+
* User information is attached as attributes on all spans created
|
|
141
|
+
* within the current AsyncLocalStorage scope.
|
|
142
|
+
*
|
|
143
|
+
* @param user - User context (id, email, username)
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* JA.setUser({ id: 'user-123', email: 'alice@example.com' });
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
function setUser(user) {
|
|
151
|
+
client.setUser(user);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Set a tag for the current async scope.
|
|
155
|
+
*
|
|
156
|
+
* Tags are attached as attributes on all spans created within the
|
|
157
|
+
* current AsyncLocalStorage scope.
|
|
158
|
+
*
|
|
159
|
+
* @param key - Tag key
|
|
160
|
+
* @param value - Tag value
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```typescript
|
|
164
|
+
* JA.setTag('feature', 'checkout');
|
|
165
|
+
* JA.setTag('region', 'us-east-1');
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
function setTag(key, value) {
|
|
169
|
+
client.setTag(key, value);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get the currently active span from AsyncLocalStorage.
|
|
173
|
+
*
|
|
174
|
+
* @returns The active Span, or null if not in a traced context
|
|
175
|
+
*/
|
|
176
|
+
function getActiveSpan() {
|
|
177
|
+
return client.getActiveSpan();
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Get the current trace ID from AsyncLocalStorage.
|
|
181
|
+
*
|
|
182
|
+
* @returns The trace ID string, or null if not in a traced context
|
|
183
|
+
*/
|
|
184
|
+
function getTraceId() {
|
|
185
|
+
return client.getTraceId();
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Manually flush all pending spans and errors to the server.
|
|
189
|
+
*
|
|
190
|
+
* Useful for ensuring data is sent before a serverless function
|
|
191
|
+
* completes, or in tests.
|
|
192
|
+
*
|
|
193
|
+
* @returns Promise that resolves when the flush completes
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* ```typescript
|
|
197
|
+
* // In a serverless handler
|
|
198
|
+
* export async function handler(event) {
|
|
199
|
+
* const result = await JA.startSpan('handler', async (span) => {
|
|
200
|
+
* return await processEvent(event);
|
|
201
|
+
* });
|
|
202
|
+
* await JA.flush(); // Ensure spans are sent
|
|
203
|
+
* return result;
|
|
204
|
+
* }
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
function flush() {
|
|
208
|
+
return client.flush();
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Get an Express middleware function that updates server span operation
|
|
212
|
+
* names with the matched Express route pattern.
|
|
213
|
+
*
|
|
214
|
+
* Register with `app.use(JA.expressMiddleware())` to have span names
|
|
215
|
+
* reflect Express route patterns (e.g., `GET /api/users/:id`) instead
|
|
216
|
+
* of raw URL paths (e.g., `GET /api/users/42`).
|
|
217
|
+
*
|
|
218
|
+
* @returns Express-compatible middleware: `(req, res, next) => void`
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* ```typescript
|
|
222
|
+
* import JA from '@justanalyticsapp/node';
|
|
223
|
+
* import express from 'express';
|
|
224
|
+
*
|
|
225
|
+
* JA.init({ siteId: '...', apiKey: '...', serviceName: 'api' });
|
|
226
|
+
*
|
|
227
|
+
* const app = express();
|
|
228
|
+
* app.use(JA.expressMiddleware());
|
|
229
|
+
*
|
|
230
|
+
* app.get('/api/users/:id', handler);
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
function expressMiddleware() {
|
|
234
|
+
return client.expressMiddleware();
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Shut down the SDK: flush remaining spans, stop timers, deregister handlers.
|
|
238
|
+
*
|
|
239
|
+
* Call this during graceful shutdown of your application.
|
|
240
|
+
*
|
|
241
|
+
* @returns Promise that resolves when shutdown is complete
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* ```typescript
|
|
245
|
+
* process.on('SIGTERM', async () => {
|
|
246
|
+
* await JA.close();
|
|
247
|
+
* process.exit(0);
|
|
248
|
+
* });
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
function close() {
|
|
252
|
+
return client.close();
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Record a custom infrastructure metric.
|
|
256
|
+
*
|
|
257
|
+
* @param metricName - Metric name using dot notation (e.g., 'custom.queue_size')
|
|
258
|
+
* @param value - Numeric value
|
|
259
|
+
* @param tags - Optional additional tags
|
|
260
|
+
*
|
|
261
|
+
* @example
|
|
262
|
+
* ```typescript
|
|
263
|
+
* JA.recordMetric('custom.queue_size', 42, { queue: 'emails' });
|
|
264
|
+
* JA.recordMetric('custom.request_duration_ms', 150.5);
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
267
|
+
function recordMetric(metricName, value, tags) {
|
|
268
|
+
client.recordMetric(metricName, value, tags);
|
|
269
|
+
}
|
|
270
|
+
// ---------- Default Export: JA namespace object ----------
|
|
271
|
+
/**
|
|
272
|
+
* JustAnalytics SDK namespace object.
|
|
273
|
+
*
|
|
274
|
+
* Provides all SDK methods as a single object for convenient default import:
|
|
275
|
+
* ```typescript
|
|
276
|
+
* import JA from '@justanalyticsapp/node';
|
|
277
|
+
* JA.init({ ... });
|
|
278
|
+
* JA.startSpan('op', (span) => { ... });
|
|
279
|
+
* JA.captureException(error);
|
|
280
|
+
* JA.captureMessage('hello', 'info');
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
const JA = {
|
|
284
|
+
init,
|
|
285
|
+
isInitialized,
|
|
286
|
+
startSpan,
|
|
287
|
+
captureException,
|
|
288
|
+
captureMessage,
|
|
289
|
+
setUser,
|
|
290
|
+
setTag,
|
|
291
|
+
getActiveSpan,
|
|
292
|
+
getTraceId,
|
|
293
|
+
expressMiddleware,
|
|
294
|
+
flush,
|
|
295
|
+
close,
|
|
296
|
+
recordMetric,
|
|
297
|
+
/**
|
|
298
|
+
* Logger instance for structured logging with automatic trace correlation.
|
|
299
|
+
*
|
|
300
|
+
* Returns a no-op Logger before `init()` is called or after `close()`.
|
|
301
|
+
* Safe to access at any time -- never null, never throws.
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```typescript
|
|
305
|
+
* JA.logger.info('User logged in', { userId: 'u123' });
|
|
306
|
+
* JA.logger.error('Payment failed', { orderId, reason });
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
get logger() {
|
|
310
|
+
return client.logger;
|
|
311
|
+
},
|
|
312
|
+
};
|
|
313
|
+
exports.default = JA;
|
|
314
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/node-sdk/src/integrations/express.ts
|
|
3
|
+
* @description Express middleware for route pattern extraction in JustAnalytics spans.
|
|
4
|
+
*
|
|
5
|
+
* Implements Story 036 - HTTP Auto-Instrumentation
|
|
6
|
+
*
|
|
7
|
+
* When the HTTP integration creates a server span for an incoming request,
|
|
8
|
+
* the operation name defaults to `{method} {raw URL}` (e.g., `GET /api/users/42`).
|
|
9
|
+
* This middleware updates the operation name to use Express route patterns
|
|
10
|
+
* (e.g., `GET /api/users/:id`) for more meaningful span names.
|
|
11
|
+
*
|
|
12
|
+
* The middleware uses `res.on('finish')` to read `req.route` after Express
|
|
13
|
+
* completes route matching, ensuring it works regardless of middleware ordering.
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import JA from '@justanalyticsapp/node';
|
|
18
|
+
* import express from 'express';
|
|
19
|
+
*
|
|
20
|
+
* const app = express();
|
|
21
|
+
* app.use(JA.expressMiddleware());
|
|
22
|
+
*
|
|
23
|
+
* app.get('/api/users/:id', (req, res) => {
|
|
24
|
+
* // Span operation name will be updated to "GET /api/users/:id"
|
|
25
|
+
* res.json({ id: req.params.id });
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* References:
|
|
30
|
+
* - Express routing: req.route is populated after route matching
|
|
31
|
+
* - Story 035 - Node.js SDK Core (Span class, context module)
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Minimal Express types to avoid a runtime dependency on the express package.
|
|
35
|
+
* We only need the shapes for req, res, and next.
|
|
36
|
+
*/
|
|
37
|
+
interface ExpressRequest {
|
|
38
|
+
method?: string;
|
|
39
|
+
path?: string;
|
|
40
|
+
route?: {
|
|
41
|
+
path?: string;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
interface ExpressResponse {
|
|
45
|
+
on(event: string, listener: (...args: unknown[]) => void): void;
|
|
46
|
+
}
|
|
47
|
+
type ExpressNextFunction = (err?: unknown) => void;
|
|
48
|
+
/**
|
|
49
|
+
* Express middleware that extracts `req.route.path` and updates the
|
|
50
|
+
* active span's operation name to use the route pattern instead
|
|
51
|
+
* of the raw URL.
|
|
52
|
+
*
|
|
53
|
+
* Must be registered via `app.use()` so it runs for all routes.
|
|
54
|
+
* The route pattern extraction happens in `res.on('finish')`,
|
|
55
|
+
* which fires after route matching is complete.
|
|
56
|
+
*
|
|
57
|
+
* If the SDK is not initialized or no active span exists, the
|
|
58
|
+
* middleware is a no-op and simply calls `next()`.
|
|
59
|
+
*
|
|
60
|
+
* @returns Express-compatible middleware function: `(req, res, next) => void`
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* import JA from '@justanalyticsapp/node';
|
|
65
|
+
* import express from 'express';
|
|
66
|
+
*
|
|
67
|
+
* JA.init({ siteId: '...', apiKey: '...', serviceName: 'api' });
|
|
68
|
+
*
|
|
69
|
+
* const app = express();
|
|
70
|
+
* app.use(JA.expressMiddleware());
|
|
71
|
+
*
|
|
72
|
+
* app.get('/api/users/:id', handler);
|
|
73
|
+
* // Span operationName: "GET /api/users/:id" (instead of "GET /api/users/42")
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export declare function expressMiddleware(): (req: ExpressRequest, res: ExpressResponse, next: ExpressNextFunction) => void;
|
|
77
|
+
export {};
|