@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,286 @@
1
+ /**
2
+ * @file packages/node-sdk/src/client.ts
3
+ * @description JustAnalyticsClient - the core SDK class managing configuration,
4
+ * lifecycle, span creation, error capture, context, and transport.
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
+ * The client is the central orchestrator:
12
+ * - Validates and stores configuration from `init()`
13
+ * - Creates spans via `startSpan()` and runs callbacks in AsyncLocalStorage context
14
+ * - Captures errors via `captureException()` and `captureMessage()`
15
+ * - Manages the BatchTransport for periodic flushing
16
+ * - Registers process exit handlers for graceful shutdown
17
+ * - Registers process error handlers for uncaughtException/unhandledRejection
18
+ * - Provides `setUser()`, `setTag()`, `getActiveSpan()`, `getTraceId()` context APIs
19
+ *
20
+ * When `enabled: false`, all methods become no-ops (spans are not created,
21
+ * errors are not captured, transport does not flush). This allows toggling
22
+ * the SDK off in environments where tracing is not desired.
23
+ *
24
+ * References:
25
+ * - src/app/api/ingest/spans/route.ts (target endpoint)
26
+ * - src/app/api/ingest/errors/route.ts (error ingestion endpoint)
27
+ * - Expansion Roadmap (architecture decisions, SDK design)
28
+ */
29
+ import { Span, SpanOptions } from './span';
30
+ import { UserContext } from './context';
31
+ import { CaptureOptions } from './errors';
32
+ import { Logger } from './logger';
33
+ import { HttpIntegrationOptions } from './integrations/http';
34
+ import { PgIntegrationOptions } from './integrations/pg';
35
+ import { RedisIntegrationOptions } from './integrations/redis';
36
+ import { MetricsIntegrationOptions } from './integrations/metrics';
37
+ import { expressMiddleware as createExpressMiddleware } from './integrations/express';
38
+ /**
39
+ * Configuration options for initializing the JustAnalytics SDK.
40
+ */
41
+ export interface JustAnalyticsOptions {
42
+ /** Site ID from JustAnalytics dashboard (required) */
43
+ siteId: string;
44
+ /** API key from JustAnalytics dashboard, format: ja_sk_... (required) */
45
+ apiKey: string;
46
+ /** Service name, e.g. "api-server", "worker" (required) */
47
+ serviceName: string;
48
+ /** Deployment environment, e.g. "production", "staging" */
49
+ environment?: string;
50
+ /** Release/version string, e.g. "1.2.3", git SHA */
51
+ release?: string;
52
+ /** Base URL of JustAnalytics server (default: JUSTANALYTICS_URL env or production URL) */
53
+ serverUrl?: string;
54
+ /** Enable debug logging to console.debug (default: false) */
55
+ debug?: boolean;
56
+ /** Flush interval in milliseconds (default: 2000) */
57
+ flushIntervalMs?: number;
58
+ /** Maximum spans per batch before immediate flush (default: 100) */
59
+ maxBatchSize?: number;
60
+ /** Enable/disable the SDK (default: true). When false, all methods are no-ops */
61
+ enabled?: boolean;
62
+ /**
63
+ * Register a process.on('uncaughtException') handler that captures the
64
+ * error, flushes pending data, and exits with code 1.
65
+ * (default: true)
66
+ */
67
+ enableUncaughtExceptionHandler?: boolean;
68
+ /**
69
+ * Register a process.on('unhandledRejection') handler that captures the
70
+ * rejection reason as an error event.
71
+ * (default: true)
72
+ */
73
+ enableUnhandledRejectionHandler?: boolean;
74
+ /**
75
+ * Integration configuration.
76
+ * - `http: true` enables HTTP auto-instrumentation with defaults
77
+ * - `http: false` disables HTTP auto-instrumentation
78
+ * - `http: { ... }` enables with custom options (HttpIntegrationOptions)
79
+ */
80
+ integrations?: {
81
+ http?: boolean | HttpIntegrationOptions;
82
+ pg?: boolean | PgIntegrationOptions;
83
+ redis?: boolean | RedisIntegrationOptions;
84
+ metrics?: boolean | MetricsIntegrationOptions;
85
+ };
86
+ }
87
+ /**
88
+ * JustAnalyticsClient manages the SDK lifecycle, span creation, error capture,
89
+ * context propagation, and batched transport.
90
+ */
91
+ export declare class JustAnalyticsClient {
92
+ private _initialized;
93
+ private _enabled;
94
+ private _serviceName;
95
+ private _environment;
96
+ private _release;
97
+ private _debug;
98
+ private _transport;
99
+ private _logger;
100
+ private _httpIntegration;
101
+ private _pgIntegration;
102
+ private _redisIntegration;
103
+ private _metricsIntegration;
104
+ private _exitHandlersRegistered;
105
+ private _boundBeforeExitHandler;
106
+ private _boundSigtermHandler;
107
+ private _boundSigintHandler;
108
+ private _boundUncaughtExceptionHandler;
109
+ private _boundUnhandledRejectionHandler;
110
+ private static _noopLogger;
111
+ /**
112
+ * Get a shared no-op Logger instance.
113
+ * Used when the SDK is not initialized or has been closed.
114
+ * All methods on this logger are no-ops (enabled: false, transport: null).
115
+ */
116
+ private static getNoopLogger;
117
+ /**
118
+ * Initialize the SDK with the given options.
119
+ *
120
+ * Must be called before any other method. Can only be called once;
121
+ * subsequent calls log a warning and are ignored (idempotent guard).
122
+ *
123
+ * @param options - SDK configuration
124
+ * @throws Error if required fields (siteId, apiKey, serviceName) are missing
125
+ */
126
+ init(options: JustAnalyticsOptions): void;
127
+ /**
128
+ * Whether `init()` has been called successfully.
129
+ */
130
+ isInitialized(): boolean;
131
+ /**
132
+ * Get the Logger instance.
133
+ *
134
+ * Returns a no-op Logger if init() has not been called yet,
135
+ * if the SDK is disabled, or after close() has been called.
136
+ * Never returns null -- always safe to call methods on the result.
137
+ */
138
+ get logger(): Logger;
139
+ /**
140
+ * Create and execute a span.
141
+ *
142
+ * Creates a new Span, runs the callback inside an AsyncLocalStorage context
143
+ * with the span as the active span, and ends the span when the callback
144
+ * completes (sync or async).
145
+ *
146
+ * If the callback throws, the span is ended with `status: 'error'` and the
147
+ * error is re-thrown.
148
+ *
149
+ * Supports two signatures:
150
+ * - `startSpan(name, callback)` -- default options
151
+ * - `startSpan(name, options, callback)` -- with SpanOptions
152
+ *
153
+ * @param name - Operation name for the span
154
+ * @param callbackOrOptions - Either the callback or SpanOptions
155
+ * @param maybeCallback - The callback (if options were provided)
156
+ * @returns The return value of the callback
157
+ */
158
+ startSpan<T>(name: string, callbackOrOptions: ((span: Span) => T) | SpanOptions, maybeCallback?: (span: Span) => T): T;
159
+ /**
160
+ * Capture an exception and send it to JustAnalytics.
161
+ *
162
+ * Automatically attaches the current traceId, spanId, user context,
163
+ * and tags from the AsyncLocalStorage context.
164
+ *
165
+ * @param error - Error object (or any value, which will be coerced)
166
+ * @param options - Optional tags, extra, user, level, fingerprint
167
+ * @returns A unique eventId string, or empty string if SDK is disabled
168
+ */
169
+ captureException(error: unknown, options?: CaptureOptions): string;
170
+ /**
171
+ * Capture a message and send it to JustAnalytics.
172
+ *
173
+ * @param message - The message string
174
+ * @param levelOrOptions - Severity level or CaptureOptions
175
+ * @param options - CaptureOptions (if level was provided as second arg)
176
+ * @returns A unique eventId string, or empty string if SDK is disabled
177
+ */
178
+ captureMessage(message: string, levelOrOptions?: 'debug' | 'info' | 'warning' | 'error' | 'fatal' | CaptureOptions, options?: CaptureOptions): string;
179
+ /**
180
+ * Set user context for the current async scope.
181
+ *
182
+ * The user context is available to all spans created within this scope.
183
+ * Uses copy-on-write semantics via AsyncLocalStorage.
184
+ *
185
+ * @param user - User context (id, email, username)
186
+ */
187
+ setUser(user: UserContext): void;
188
+ /**
189
+ * Set a tag for the current async scope.
190
+ *
191
+ * Tags are attached as attributes on all spans created within this scope.
192
+ * Uses copy-on-write semantics via AsyncLocalStorage.
193
+ *
194
+ * @param key - Tag key
195
+ * @param value - Tag value
196
+ */
197
+ setTag(key: string, value: string): void;
198
+ /**
199
+ * Get the currently active span from AsyncLocalStorage.
200
+ *
201
+ * @returns The active Span, or null if not in a traced context
202
+ */
203
+ getActiveSpan(): Span | null;
204
+ /**
205
+ * Get the current trace ID from AsyncLocalStorage.
206
+ *
207
+ * @returns The trace ID string, or null if not in a traced context
208
+ */
209
+ getTraceId(): string | null;
210
+ /**
211
+ * Get an Express middleware function that updates server span operation
212
+ * names with the matched Express route pattern.
213
+ *
214
+ * @returns Express-compatible middleware: `(req, res, next) => void`
215
+ */
216
+ expressMiddleware(): ReturnType<typeof createExpressMiddleware>;
217
+ /**
218
+ * Record a custom infrastructure metric.
219
+ *
220
+ * Constructs a MetricPayload with the provided name, value, and tags,
221
+ * plus serviceName, timestamp, and default tags (hostname, environment).
222
+ *
223
+ * @param metricName - Metric name using dot notation (e.g., 'custom.queue_size')
224
+ * @param value - Numeric value
225
+ * @param tags - Optional additional tags
226
+ */
227
+ recordMetric(metricName: string, value: number, tags?: Record<string, unknown>): void;
228
+ /**
229
+ * Manually flush all pending spans and errors to the server.
230
+ *
231
+ * @returns Promise that resolves when the flush completes
232
+ */
233
+ flush(): Promise<void>;
234
+ /**
235
+ * Shut down the SDK: flush remaining data, stop timers, deregister handlers.
236
+ *
237
+ * After calling `close()`, the SDK cannot be used again until `init()` is called.
238
+ */
239
+ close(): Promise<void>;
240
+ /**
241
+ * Enqueue an ended span for transport.
242
+ *
243
+ * @param span - The ended span to enqueue
244
+ */
245
+ private enqueueSpan;
246
+ /**
247
+ * Enqueue an error event payload for transport.
248
+ *
249
+ * @param payload - The error event payload to enqueue
250
+ */
251
+ private enqueueError;
252
+ /**
253
+ * Get tags from the current AsyncLocalStorage context.
254
+ *
255
+ * @returns Current context tags, or empty object if none
256
+ */
257
+ private getContextTags;
258
+ /**
259
+ * Register process error handlers for uncaught exceptions and unhandled rejections.
260
+ *
261
+ * These handlers capture the error via the SDK and ensure it is sent to the server.
262
+ * For uncaughtException, the process exits after a 2-second safety timeout.
263
+ * For unhandledRejection, the error is batched (process continues).
264
+ *
265
+ * @param options - SDK configuration options
266
+ */
267
+ private registerProcessErrorHandlers;
268
+ /**
269
+ * Deregister process error handlers.
270
+ *
271
+ * Called by `close()` to clean up uncaughtException and unhandledRejection listeners.
272
+ */
273
+ private deregisterProcessErrorHandlers;
274
+ /**
275
+ * Register process exit handlers to flush remaining spans on shutdown.
276
+ *
277
+ * Handlers are registered only once (tracked by `_exitHandlersRegistered`).
278
+ */
279
+ private registerExitHandlers;
280
+ /**
281
+ * Deregister process exit handlers.
282
+ *
283
+ * Called by `close()` to clean up all registered handlers.
284
+ */
285
+ private deregisterExitHandlers;
286
+ }