@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.
Files changed (52) hide show
  1. package/dist/client.d.ts +286 -0
  2. package/dist/client.js +681 -0
  3. package/dist/client.js.map +1 -0
  4. package/dist/context.d.ts +126 -0
  5. package/dist/context.js +170 -0
  6. package/dist/context.js.map +1 -0
  7. package/dist/errors.d.ts +135 -0
  8. package/dist/errors.js +180 -0
  9. package/dist/errors.js.map +1 -0
  10. package/dist/index.d.ts +301 -0
  11. package/dist/index.js +314 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/integrations/express.d.ts +77 -0
  14. package/dist/integrations/express.js +87 -0
  15. package/dist/integrations/express.js.map +1 -0
  16. package/dist/integrations/http.d.ts +129 -0
  17. package/dist/integrations/http.js +465 -0
  18. package/dist/integrations/http.js.map +1 -0
  19. package/dist/integrations/metrics.d.ts +110 -0
  20. package/dist/integrations/metrics.js +313 -0
  21. package/dist/integrations/metrics.js.map +1 -0
  22. package/dist/integrations/next.d.ts +252 -0
  23. package/dist/integrations/next.js +480 -0
  24. package/dist/integrations/next.js.map +1 -0
  25. package/dist/integrations/pg.d.ts +169 -0
  26. package/dist/integrations/pg.js +616 -0
  27. package/dist/integrations/pg.js.map +1 -0
  28. package/dist/integrations/pino.d.ts +52 -0
  29. package/dist/integrations/pino.js +153 -0
  30. package/dist/integrations/pino.js.map +1 -0
  31. package/dist/integrations/redis.d.ts +190 -0
  32. package/dist/integrations/redis.js +597 -0
  33. package/dist/integrations/redis.js.map +1 -0
  34. package/dist/integrations/winston.d.ts +48 -0
  35. package/dist/integrations/winston.js +99 -0
  36. package/dist/integrations/winston.js.map +1 -0
  37. package/dist/logger.d.ts +148 -0
  38. package/dist/logger.js +162 -0
  39. package/dist/logger.js.map +1 -0
  40. package/dist/span.d.ts +192 -0
  41. package/dist/span.js +197 -0
  42. package/dist/span.js.map +1 -0
  43. package/dist/transport.d.ts +246 -0
  44. package/dist/transport.js +654 -0
  45. package/dist/transport.js.map +1 -0
  46. package/dist/utils/headers.d.ts +60 -0
  47. package/dist/utils/headers.js +93 -0
  48. package/dist/utils/headers.js.map +1 -0
  49. package/dist/utils/id.d.ts +23 -0
  50. package/dist/utils/id.js +36 -0
  51. package/dist/utils/id.js.map +1 -0
  52. package/package.json +65 -0
@@ -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 {};