@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,480 @@
1
+ "use strict";
2
+ /**
3
+ * @file packages/node-sdk/src/integrations/next.ts
4
+ * @description Next.js integration for JustAnalytics Node.js SDK.
5
+ *
6
+ * Implements Story 044 - Next.js Integration
7
+ *
8
+ * Provides zero-config initialization via Next.js 15+ instrumentation.ts hook,
9
+ * API route tracing wrappers, middleware tracing, and Server Component helpers.
10
+ *
11
+ * Quick Start (Next.js 15+):
12
+ * ```typescript
13
+ * // instrumentation.ts
14
+ * export { register } from '@justanalyticsapp/node/next';
15
+ * ```
16
+ *
17
+ * With custom config:
18
+ * ```typescript
19
+ * // instrumentation.ts
20
+ * import { withJustAnalytics } from '@justanalyticsapp/node/next';
21
+ *
22
+ * export function register() {
23
+ * withJustAnalytics({
24
+ * siteId: 'site_abc123',
25
+ * apiKey: 'ja_sk_...',
26
+ * serviceName: 'my-next-app',
27
+ * environment: 'production',
28
+ * });
29
+ * }
30
+ * ```
31
+ *
32
+ * API Route Tracing:
33
+ * ```typescript
34
+ * // app/api/users/[id]/route.ts
35
+ * import { withTracing } from '@justanalyticsapp/node/next';
36
+ *
37
+ * export const GET = withTracing(async (req, { params }) => {
38
+ * const user = await db.users.findUnique({ where: { id: params.id } });
39
+ * return Response.json(user);
40
+ * });
41
+ * ```
42
+ *
43
+ * Middleware Tracing:
44
+ * ```typescript
45
+ * // middleware.ts
46
+ * import { withMiddlewareTracing } from '@justanalyticsapp/node/next';
47
+ *
48
+ * export default withMiddlewareTracing(async (req) => {
49
+ * // your middleware logic
50
+ * return NextResponse.next();
51
+ * });
52
+ * ```
53
+ *
54
+ * Server Component Tracing:
55
+ * ```typescript
56
+ * // app/users/[id]/page.tsx
57
+ * import { traceServerComponent } from '@justanalyticsapp/node/next';
58
+ *
59
+ * export default async function UserPage({ params }) {
60
+ * return traceServerComponent('UserPage', async () => {
61
+ * const user = await getUser(params.id);
62
+ * return <UserProfile user={user} />;
63
+ * });
64
+ * }
65
+ * ```
66
+ *
67
+ * References:
68
+ * - Story 035 - Node.js SDK Core (JA.init, JA.startSpan, context)
69
+ * - Story 036 - HTTP Auto-Instrumentation (parent span creation)
70
+ * - Next.js instrumentation.ts: https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation
71
+ */
72
+ Object.defineProperty(exports, "__esModule", { value: true });
73
+ exports.withJustAnalytics = withJustAnalytics;
74
+ exports.register = register;
75
+ exports.extractRoutePattern = extractRoutePattern;
76
+ exports.withTracing = withTracing;
77
+ exports.withMiddlewareTracing = withMiddlewareTracing;
78
+ exports.traceServerComponent = traceServerComponent;
79
+ // Import SDK functions lazily via require to avoid circular dependencies
80
+ // and to ensure we use the singleton from index.ts. We import the client
81
+ // class directly since the singleton is created in index.ts.
82
+ const client_1 = require("../client");
83
+ /**
84
+ * Internal reference to the singleton SDK client.
85
+ *
86
+ * We create our own singleton reference here rather than importing from
87
+ * index.ts to avoid circular dependency issues when this file is imported
88
+ * via the `./next` export path. The `withJustAnalytics()` function creates
89
+ * and initializes this client.
90
+ */
91
+ let _client = null;
92
+ /**
93
+ * Get the SDK client, creating it if necessary.
94
+ *
95
+ * @returns The JustAnalyticsClient instance, or null if not yet initialized
96
+ */
97
+ function getClient() {
98
+ return _client;
99
+ }
100
+ // ---------------------------------------------------------------------------
101
+ // withJustAnalytics()
102
+ // ---------------------------------------------------------------------------
103
+ /**
104
+ * Initialize JustAnalytics with Next.js-optimized defaults.
105
+ *
106
+ * Reads configuration from environment variables when not explicitly provided.
107
+ * Safe to call multiple times (idempotent -- delegates to JA.init()'s guard).
108
+ *
109
+ * Environment variables (in order of priority: explicit config > env var > default):
110
+ * - `JUSTANALYTICS_SITE_ID` -- site ID
111
+ * - `JUSTANALYTICS_API_KEY` -- API key
112
+ * - `JUSTANALYTICS_SERVICE_NAME` -- service name (default: `'next-app'`)
113
+ * - `JUSTANALYTICS_ENVIRONMENT` -- environment (default: `NODE_ENV || 'development'`)
114
+ * - `JUSTANALYTICS_URL` -- server URL
115
+ *
116
+ * If `siteId` or `apiKey` are missing after merging config and env vars,
117
+ * the function logs a warning and returns without calling `init()`.
118
+ *
119
+ * @param config - Optional configuration overrides
120
+ */
121
+ function withJustAnalytics(config) {
122
+ try {
123
+ // Skip initialization on edge runtime (SDK uses Node.js APIs)
124
+ if (typeof process !== 'undefined' && process.env.NEXT_RUNTIME === 'edge') {
125
+ return;
126
+ }
127
+ // Read environment variables
128
+ const envSiteId = typeof process !== 'undefined' ? process.env.JUSTANALYTICS_SITE_ID : undefined;
129
+ const envApiKey = typeof process !== 'undefined' ? process.env.JUSTANALYTICS_API_KEY : undefined;
130
+ const envServiceName = typeof process !== 'undefined' ? process.env.JUSTANALYTICS_SERVICE_NAME : undefined;
131
+ const envEnvironment = typeof process !== 'undefined' ? process.env.JUSTANALYTICS_ENVIRONMENT : undefined;
132
+ const envUrl = typeof process !== 'undefined' ? process.env.JUSTANALYTICS_URL : undefined;
133
+ const envNodeEnv = typeof process !== 'undefined' ? process.env.NODE_ENV : undefined;
134
+ // Merge: explicit config > env vars > defaults
135
+ const siteId = config?.siteId || envSiteId || '';
136
+ const apiKey = config?.apiKey || envApiKey || '';
137
+ const serviceName = config?.serviceName || envServiceName || 'next-app';
138
+ const environment = config?.environment || envEnvironment || envNodeEnv || 'development';
139
+ const serverUrl = config?.serverUrl || envUrl;
140
+ // Validate required fields
141
+ if (!siteId || !apiKey) {
142
+ console.warn('[JustAnalytics] Missing siteId or apiKey. SDK will not initialize.');
143
+ return;
144
+ }
145
+ // Create client if not already created
146
+ if (!_client) {
147
+ _client = new client_1.JustAnalyticsClient();
148
+ }
149
+ // Build init options, stripping Next.js-specific fields
150
+ const initOptions = {
151
+ siteId,
152
+ apiKey,
153
+ serviceName,
154
+ environment,
155
+ ...(serverUrl ? { serverUrl } : {}),
156
+ ...(config?.release ? { release: config.release } : {}),
157
+ ...(config?.debug !== undefined ? { debug: config.debug } : {}),
158
+ ...(config?.flushIntervalMs !== undefined ? { flushIntervalMs: config.flushIntervalMs } : {}),
159
+ ...(config?.maxBatchSize !== undefined ? { maxBatchSize: config.maxBatchSize } : {}),
160
+ ...(config?.enabled !== undefined ? { enabled: config.enabled } : {}),
161
+ ...(config?.integrations ? { integrations: config.integrations } : {}),
162
+ ...(config?.enableUncaughtExceptionHandler !== undefined
163
+ ? { enableUncaughtExceptionHandler: config.enableUncaughtExceptionHandler }
164
+ : {}),
165
+ ...(config?.enableUnhandledRejectionHandler !== undefined
166
+ ? { enableUnhandledRejectionHandler: config.enableUnhandledRejectionHandler }
167
+ : {}),
168
+ };
169
+ _client.init(initOptions);
170
+ }
171
+ catch {
172
+ // Never throw from initialization -- the user's app must not be affected
173
+ }
174
+ }
175
+ // ---------------------------------------------------------------------------
176
+ // register()
177
+ // ---------------------------------------------------------------------------
178
+ /**
179
+ * Next.js instrumentation.ts register() hook.
180
+ *
181
+ * Export this directly from your instrumentation.ts:
182
+ * ```typescript
183
+ * export { register } from '@justanalyticsapp/node/next';
184
+ * ```
185
+ *
186
+ * Only initializes on the Node.js runtime (skips edge runtime).
187
+ * Designed for Next.js 15+ where `instrumentation.ts` is stable.
188
+ * For Next.js 13-14, call `withJustAnalytics()` manually.
189
+ */
190
+ function register() {
191
+ try {
192
+ // Skip on edge runtime -- SDK uses Node.js-only APIs
193
+ if (typeof process !== 'undefined' && process.env.NEXT_RUNTIME === 'edge') {
194
+ return;
195
+ }
196
+ withJustAnalytics();
197
+ }
198
+ catch {
199
+ // Never throw from the register hook
200
+ }
201
+ }
202
+ // ---------------------------------------------------------------------------
203
+ // extractRoutePattern()
204
+ // ---------------------------------------------------------------------------
205
+ /**
206
+ * Extract the Next.js route pattern from a request.
207
+ *
208
+ * Checks Next.js internal headers in priority order:
209
+ * 1. `x-invoke-path` -- Next.js 14.1+ sets this to the file-system route
210
+ * 2. `x-matched-path` -- Some Next.js versions use this header
211
+ * 3. `x-nextjs-page` -- Older Next.js versions (13.x) may set this
212
+ * 4. Falls back to `req.nextUrl.pathname` or raw URL pathname
213
+ *
214
+ * Query strings are stripped from the returned pattern.
215
+ *
216
+ * @param req - The incoming request
217
+ * @returns The route pattern string (e.g., '/api/users/[id]')
218
+ */
219
+ function extractRoutePattern(req) {
220
+ try {
221
+ let pattern = null;
222
+ // Check Next.js internal headers in priority order
223
+ if (req.headers && typeof req.headers.get === 'function') {
224
+ pattern = req.headers.get('x-invoke-path');
225
+ if (!pattern) {
226
+ pattern = req.headers.get('x-matched-path');
227
+ }
228
+ if (!pattern) {
229
+ pattern = req.headers.get('x-nextjs-page');
230
+ }
231
+ }
232
+ // Fallback to nextUrl.pathname or raw URL pathname
233
+ if (!pattern) {
234
+ if (req.nextUrl?.pathname) {
235
+ pattern = req.nextUrl.pathname;
236
+ }
237
+ else if (req.url) {
238
+ try {
239
+ const url = new URL(req.url, 'http://localhost');
240
+ pattern = url.pathname;
241
+ }
242
+ catch {
243
+ pattern = req.url;
244
+ }
245
+ }
246
+ else {
247
+ pattern = '/';
248
+ }
249
+ }
250
+ // Strip query strings if present
251
+ const queryIndex = pattern.indexOf('?');
252
+ if (queryIndex !== -1) {
253
+ pattern = pattern.substring(0, queryIndex);
254
+ }
255
+ return pattern;
256
+ }
257
+ catch {
258
+ // Fallback: return root path on any error
259
+ return '/';
260
+ }
261
+ }
262
+ // ---------------------------------------------------------------------------
263
+ // withTracing()
264
+ // ---------------------------------------------------------------------------
265
+ /**
266
+ * Wrap a Next.js API route handler with tracing.
267
+ *
268
+ * Creates a server span wrapping the handler execution. The span is named
269
+ * `{METHOD} {routePattern}` (e.g., `GET /api/users/[id]`) and includes
270
+ * Next.js-specific attributes.
271
+ *
272
+ * If the SDK is not initialized, the handler is called directly (no-op pass-through).
273
+ * Never throws -- all instrumentation errors are caught silently.
274
+ *
275
+ * @param handler - The route handler function
276
+ * @returns A wrapped handler with automatic tracing
277
+ *
278
+ * @example
279
+ * ```typescript
280
+ * // app/api/users/[id]/route.ts
281
+ * import { withTracing } from '@justanalyticsapp/node/next';
282
+ *
283
+ * export const GET = withTracing(async (req, { params }) => {
284
+ * const user = await db.users.findUnique({ where: { id: params.id } });
285
+ * return Response.json(user);
286
+ * });
287
+ * ```
288
+ */
289
+ function withTracing(handler) {
290
+ return async function tracedHandler(req, context) {
291
+ // Pass through if SDK is not initialized
292
+ const client = getClient();
293
+ if (!client || !client.isInitialized()) {
294
+ try {
295
+ return await handler(req, context);
296
+ }
297
+ catch (err) {
298
+ throw err;
299
+ }
300
+ }
301
+ try {
302
+ // Extract route pattern and method
303
+ const routePattern = extractRoutePattern(req);
304
+ const method = (req.method || 'GET').toUpperCase();
305
+ const spanName = `${method} ${routePattern}`;
306
+ const runtime = typeof process !== 'undefined'
307
+ ? (process.env.NEXT_RUNTIME || 'nodejs')
308
+ : 'nodejs';
309
+ return await client.startSpan(spanName, { kind: 'server' }, async (span) => {
310
+ // Set Next.js-specific attributes
311
+ span.setAttribute('next.route', routePattern);
312
+ span.setAttribute('next.runtime', runtime);
313
+ span.setAttribute('http.method', method);
314
+ span.setAttribute('http.url', req.url || '');
315
+ span.setAttribute('http.route', routePattern);
316
+ let response;
317
+ try {
318
+ response = await handler(req, context);
319
+ }
320
+ catch (err) {
321
+ // Handler threw -- span will be auto-ended with error by startSpan
322
+ throw err;
323
+ }
324
+ // Set response attributes
325
+ const statusCode = response.status;
326
+ span.setAttribute('http.status_code', statusCode);
327
+ if (statusCode >= 500) {
328
+ span.setStatus('error', `HTTP ${statusCode}`);
329
+ }
330
+ return response;
331
+ });
332
+ }
333
+ catch (err) {
334
+ // If it's a handler error, re-throw it (startSpan already re-throws)
335
+ // If it's an instrumentation error, fall through to original handler
336
+ if (err instanceof Error && err.message === '[JustAnalytics] startSpan() requires a callback function.') {
337
+ return await handler(req, context);
338
+ }
339
+ throw err;
340
+ }
341
+ };
342
+ }
343
+ // ---------------------------------------------------------------------------
344
+ // withMiddlewareTracing()
345
+ // ---------------------------------------------------------------------------
346
+ /**
347
+ * Wrap Next.js middleware with tracing.
348
+ *
349
+ * Creates a span with operation name `middleware` and kind `'server'`.
350
+ * Captures the response status and any `x-middleware-rewrite` or
351
+ * `x-middleware-redirect` headers as span attributes.
352
+ *
353
+ * If the SDK is not initialized, the middleware is called directly (no-op pass-through).
354
+ * Never throws -- all instrumentation errors are caught silently.
355
+ *
356
+ * @param middleware - The middleware function
357
+ * @returns A wrapped middleware with automatic tracing
358
+ *
359
+ * @example
360
+ * ```typescript
361
+ * // middleware.ts
362
+ * import { withMiddlewareTracing } from '@justanalyticsapp/node/next';
363
+ *
364
+ * export default withMiddlewareTracing(async (req) => {
365
+ * // your middleware logic
366
+ * return NextResponse.next();
367
+ * });
368
+ * ```
369
+ */
370
+ function withMiddlewareTracing(middleware) {
371
+ return async function tracedMiddleware(req) {
372
+ // Pass through if SDK is not initialized
373
+ const client = getClient();
374
+ if (!client || !client.isInitialized()) {
375
+ try {
376
+ return await middleware(req);
377
+ }
378
+ catch (err) {
379
+ throw err;
380
+ }
381
+ }
382
+ try {
383
+ return await client.startSpan('middleware', { kind: 'server' }, async (span) => {
384
+ // Set middleware-specific attributes
385
+ span.setAttribute('next.middleware', true);
386
+ let response;
387
+ try {
388
+ response = await middleware(req);
389
+ }
390
+ catch (err) {
391
+ // Middleware threw -- span will be auto-ended with error by startSpan
392
+ throw err;
393
+ }
394
+ // Set response status
395
+ if (typeof response.status === 'number') {
396
+ span.setAttribute('http.status_code', response.status);
397
+ if (response.status >= 500) {
398
+ span.setStatus('error', `HTTP ${response.status}`);
399
+ }
400
+ }
401
+ // Capture middleware-specific headers
402
+ if (response.headers && typeof response.headers.get === 'function') {
403
+ const rewriteUrl = response.headers.get('x-middleware-rewrite');
404
+ if (rewriteUrl) {
405
+ span.setAttribute('next.middleware.rewrite', rewriteUrl);
406
+ }
407
+ const redirectUrl = response.headers.get('x-middleware-redirect');
408
+ if (redirectUrl) {
409
+ span.setAttribute('next.middleware.redirect', redirectUrl);
410
+ }
411
+ }
412
+ return response;
413
+ });
414
+ }
415
+ catch (err) {
416
+ // If it's a middleware error, re-throw it (startSpan already re-throws)
417
+ if (err instanceof Error && err.message === '[JustAnalytics] startSpan() requires a callback function.') {
418
+ return await middleware(req);
419
+ }
420
+ throw err;
421
+ }
422
+ };
423
+ }
424
+ // ---------------------------------------------------------------------------
425
+ // traceServerComponent()
426
+ // ---------------------------------------------------------------------------
427
+ /**
428
+ * Wrap an async Server Component render in a traced span.
429
+ *
430
+ * The span has kind `'internal'` and operation name `RSC {name}`
431
+ * (e.g., `RSC UserProfile`). It sets `next.rsc: true` to distinguish
432
+ * from API route spans.
433
+ *
434
+ * If the SDK is not initialized, the function is called directly (no-op pass-through).
435
+ * Never throws -- all instrumentation errors are caught silently.
436
+ *
437
+ * @param name - Component name for the span (e.g., 'UserProfile')
438
+ * @param fn - The async render function
439
+ * @returns The result of fn()
440
+ *
441
+ * @example
442
+ * ```typescript
443
+ * // app/users/[id]/page.tsx
444
+ * import { traceServerComponent } from '@justanalyticsapp/node/next';
445
+ *
446
+ * export default async function UserPage({ params }) {
447
+ * return traceServerComponent('UserPage', async () => {
448
+ * const user = await getUser(params.id);
449
+ * return <UserProfile user={user} />;
450
+ * });
451
+ * }
452
+ * ```
453
+ */
454
+ function traceServerComponent(name, fn) {
455
+ // Pass through if SDK is not initialized
456
+ const client = getClient();
457
+ if (!client || !client.isInitialized()) {
458
+ try {
459
+ return fn();
460
+ }
461
+ catch (err) {
462
+ throw err;
463
+ }
464
+ }
465
+ try {
466
+ return client.startSpan(`RSC ${name}`, { kind: 'internal' }, (span) => {
467
+ // Set RSC-specific attribute
468
+ span.setAttribute('next.rsc', true);
469
+ return fn();
470
+ });
471
+ }
472
+ catch (err) {
473
+ // If it's a user function error, re-throw it
474
+ if (err instanceof Error && err.message === '[JustAnalytics] startSpan() requires a callback function.') {
475
+ return fn();
476
+ }
477
+ throw err;
478
+ }
479
+ }
480
+ //# sourceMappingURL=next.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next.js","sourceRoot":"","sources":["../../src/integrations/next.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * @file packages/node-sdk/src/integrations/pg.ts
3
+ * @description PostgreSQL auto-instrumentation integration for the JustAnalytics Node.js SDK.
4
+ *
5
+ * Implements Story 039 - PostgreSQL Auto-Instrumentation
6
+ *
7
+ * Monkey-patches `pg.Client.prototype.query`, `pg.Pool.prototype.query`, and
8
+ * `pg.Pool.prototype.connect` to automatically create `db.query` and `db.connect`
9
+ * spans for all PostgreSQL operations. This captures all PostgreSQL traffic regardless
10
+ * of which ORM or query builder sits on top (Prisma, Knex, TypeORM, Sequelize, Drizzle).
11
+ *
12
+ * Follows the same monkey-patching pattern established in Story 036 (HTTP Auto-Instrumentation):
13
+ * - Integration class with `enable()`/`disable()` lifecycle methods
14
+ * - Original function preservation for clean teardown
15
+ * - Integration with AsyncLocalStorage context for automatic parent-child span relationships
16
+ * - Fail-open design: if instrumentation code fails, the original query executes normally
17
+ *
18
+ * SQL sanitization is a critical security requirement: all literal values (strings,
19
+ * numbers, booleans) are replaced with `$?` placeholders. Actual query parameter
20
+ * values are NEVER included in span attributes.
21
+ *
22
+ * References:
23
+ * - OpenTelemetry Database Semantic Conventions (db.system, db.statement, etc.)
24
+ * - Story 035 - Node.js SDK Core (Span, context, transport)
25
+ * - Story 036 - HTTP Auto-Instrumentation (integration pattern)
26
+ */
27
+ import { Span } from '../span';
28
+ /**
29
+ * Configuration for the PostgreSQL auto-instrumentation integration.
30
+ */
31
+ export interface PgIntegrationOptions {
32
+ /** Enable/disable the integration (default: true) */
33
+ enabled?: boolean;
34
+ /**
35
+ * Maximum character length for the db.statement attribute.
36
+ * SQL queries longer than this are truncated with '...' suffix.
37
+ * (default: 2048)
38
+ */
39
+ maxQueryLength?: number;
40
+ }
41
+ /**
42
+ * Sanitize a SQL query by replacing literal values with placeholders.
43
+ *
44
+ * Rules (applied in order):
45
+ * 1. Strip block comments (/* ... *​/)
46
+ * 2. Strip line comments (-- ...)
47
+ * 3. Replace string literals ('...') with $?
48
+ * 4. Replace numeric literals with $? (preserving $N parameter placeholders)
49
+ * 5. Replace boolean literals (TRUE/FALSE) with $?
50
+ * 6. Normalize whitespace (collapse multiple spaces, trim)
51
+ * 7. Truncate to maxLength
52
+ *
53
+ * @param sql - Raw SQL query string
54
+ * @param maxLength - Maximum length for the sanitized output (default: 2048)
55
+ * @returns Sanitized SQL with literals replaced
56
+ */
57
+ export declare function sanitizeSql(sql: string, maxLength?: number): string;
58
+ /**
59
+ * Extract the SQL operation keyword from a query string.
60
+ *
61
+ * Handles: SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, DROP,
62
+ * BEGIN, COMMIT, ROLLBACK, TRUNCATE, COPY, EXPLAIN, ANALYZE, WITH (CTE)
63
+ *
64
+ * @param sql - Raw or sanitized SQL query
65
+ * @returns Uppercase operation keyword (e.g., "SELECT"), or "UNKNOWN" if not recognized
66
+ */
67
+ export declare function extractSqlOperation(sql: string): string;
68
+ /**
69
+ * Extract the primary table name from a SQL query (best effort).
70
+ *
71
+ * Patterns handled:
72
+ * - SELECT ... FROM table_name
73
+ * - INSERT INTO table_name
74
+ * - UPDATE table_name
75
+ * - DELETE FROM table_name
76
+ * - Handles schema-qualified names: schema.table
77
+ * - Handles quoted identifiers: "table_name"
78
+ *
79
+ * @param sql - Raw or sanitized SQL query
80
+ * @returns Table name, or null if extraction fails
81
+ */
82
+ export declare function extractTableName(sql: string): string | null;
83
+ /**
84
+ * Build a sanitized connection string from pg client config.
85
+ * Replaces password with '***'.
86
+ *
87
+ * @param connStr - Raw connection string potentially containing a password
88
+ * @returns Sanitized connection string with password masked
89
+ */
90
+ export declare function sanitizeConnectionString(connStr: string): string;
91
+ /**
92
+ * PgIntegration monkey-patches pg.Client.prototype.query,
93
+ * pg.Pool.prototype.query, and pg.Pool.prototype.connect to auto-create
94
+ * db.query and db.connect spans for all PostgreSQL operations.
95
+ *
96
+ * Follows the same pattern as HttpIntegration (Story 036):
97
+ * - Constructor accepts serviceName, options, onSpanEnd callback
98
+ * - enable() patches, disable() restores
99
+ * - Original functions preserved for clean teardown
100
+ * - Fail-open design: instrumentation failures never crash the host process
101
+ */
102
+ export declare class PgIntegration {
103
+ private _enabled;
104
+ private _options;
105
+ private _serviceName;
106
+ private _onSpanEnd;
107
+ private _originalClientQuery;
108
+ private _originalPoolQuery;
109
+ private _originalPoolConnect;
110
+ private _pgClient;
111
+ private _pgPool;
112
+ /**
113
+ * Create a new PgIntegration.
114
+ *
115
+ * @param serviceName - The service name for span attribution
116
+ * @param options - Integration configuration options
117
+ * @param onSpanEnd - Callback invoked when a span ends (enqueues to transport)
118
+ */
119
+ constructor(serviceName: string, options: PgIntegrationOptions | undefined, onSpanEnd: (span: Span) => void);
120
+ /**
121
+ * Activate the integration: load pg module and patch prototypes.
122
+ *
123
+ * Calling enable() when already enabled is a no-op (idempotent).
124
+ */
125
+ enable(): void;
126
+ /**
127
+ * Deactivate: restore original pg functions.
128
+ *
129
+ * Calling disable() when not enabled is a no-op (idempotent).
130
+ */
131
+ disable(): void;
132
+ /**
133
+ * Restore all patched functions to their originals.
134
+ */
135
+ private _restoreOriginals;
136
+ /**
137
+ * Wrap pg.Client.prototype.query to create db.query spans.
138
+ *
139
+ * Handles all pg query signatures:
140
+ * 1. client.query(text, callback)
141
+ * 2. client.query(text, values, callback)
142
+ * 3. client.query(text) -- promise
143
+ * 4. client.query(text, values) -- promise
144
+ * 5. client.query(config) -- QueryConfig object, promise
145
+ * 6. client.query(config, callback) -- QueryConfig object, callback
146
+ *
147
+ * @param original - The original query function
148
+ * @returns A wrapped version of the query function
149
+ */
150
+ private _wrapClientQuery;
151
+ /**
152
+ * Wrap pg.Pool.prototype.query to create db.query spans.
153
+ *
154
+ * Pool.query is a convenience method that acquires a client, runs the query,
155
+ * and releases the client. We patch it separately to track pool-level queries.
156
+ *
157
+ * @param original - The original Pool.prototype.query function
158
+ * @returns A wrapped version of the query function
159
+ */
160
+ private _wrapPoolQuery;
161
+ /**
162
+ * Wrap pg.Pool.prototype.connect to create db.connect spans that measure
163
+ * the time to acquire a connection from the pool.
164
+ *
165
+ * @param original - The original Pool.prototype.connect function
166
+ * @returns A wrapped version of the connect function
167
+ */
168
+ private _wrapPoolConnect;
169
+ }