@reproapp/node-sdk 0.0.3 → 0.0.4
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/README.md +36 -2
- package/dist/index.d.ts +140 -15
- package/dist/index.js +4927 -927
- package/dist/ingest/client.d.ts +10 -0
- package/dist/ingest/client.js +158 -0
- package/dist/ingest/mapper.d.ts +2 -0
- package/dist/ingest/mapper.js +92 -0
- package/dist/ingest/types.d.ts +40 -0
- package/dist/ingest/types.js +2 -0
- package/dist/ingest/worker.js +19 -0
- package/dist/integrations/sendgrid.d.ts +2 -4
- package/dist/integrations/sendgrid.js +4 -14
- package/dist/privacy-fallback.d.ts +1 -0
- package/dist/privacy-fallback.js +27 -0
- package/dist/privacy-redaction.d.ts +3 -0
- package/dist/privacy-redaction.js +38 -0
- package/dist/privacy.d.ts +108 -0
- package/dist/privacy.js +2868 -0
- package/dist/trace-materializer-worker.d.ts +1 -0
- package/dist/trace-materializer-worker.js +33 -0
- package/docs/tracing.md +1 -0
- package/package.json +8 -2
- package/src/index.ts +5583 -954
- package/src/ingest/client.ts +194 -0
- package/src/ingest/mapper.ts +104 -0
- package/src/ingest/types.ts +42 -0
- package/src/integrations/sendgrid.ts +6 -19
- package/src/privacy-fallback.ts +25 -0
- package/src/privacy-redaction.ts +37 -0
- package/src/privacy.ts +3593 -0
- package/src/trace-materializer-worker.ts +39 -0
- package/test/circular-capture.test.js +111 -0
- package/test/disable-subtree.test.js +154 -0
- package/test/integration-unawaited.js +183 -0
- package/test/kafka-runtime-privacy-policy.test.js +285 -0
- package/test/privacy-runtime-policy.test.js +2043 -0
- package/test/promise-map.test.js +72 -0
- package/test/unawaited.test.js +163 -0
- package/test/wrap-plugin-arrow-args.test.js +80 -0
- package/tracer/cjs-hook.js +0 -1
- package/tracer/wrap-plugin.js +96 -10
- package/dist/redaction.d.ts +0 -44
- package/dist/redaction.js +0 -167
- package/dist/server.js +0 -26
- /package/dist/{server.d.ts → ingest/worker.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
const reproConfig = {
|
|
40
40
|
appId: process.env.REPRO_APP_ID as string,
|
|
41
41
|
appName: process.env.REPRO_APP_NAME as string,
|
|
42
|
+
serviceName: process.env.REPRO_SERVICE_NAME as string,
|
|
42
43
|
tenantId: process.env.REPRO_TENANT_ID as string,
|
|
43
44
|
appSecret: process.env.REPRO_APP_SECRET as string,
|
|
44
45
|
};
|
|
@@ -66,8 +67,9 @@ bootstrap();
|
|
|
66
67
|
```
|
|
67
68
|
|
|
68
69
|
Configuration notes:
|
|
69
|
-
- `
|
|
70
|
+
- `REPRO_INGEST_BASE` (optional) overrides the log-collector base URL used to send ingest events.
|
|
70
71
|
- `REPRO_APP_NAME` (optional) sets `appName`, which is sent as `X-App-Name`.
|
|
72
|
+
- `REPRO_SERVICE_NAME` (optional) sets the backend service label stored on request, trace, DB, and email events. Defaults to `appName` when omitted.
|
|
71
73
|
|
|
72
74
|
### initReproTracing
|
|
73
75
|
|
|
@@ -155,6 +157,7 @@ include `x-bug-session-id` and `x-bug-action-id` headers to be captured.
|
|
|
155
157
|
Options (type -> purpose):
|
|
156
158
|
- `appId` (string): Repro app id.
|
|
157
159
|
- `appName` (string, optional): Repro app name (sent as `X-App-Name`).
|
|
160
|
+
- `serviceName` (string, optional): service label persisted with backend events.
|
|
158
161
|
- `tenantId` (string): Repro tenant id.
|
|
159
162
|
- `appSecret` (string): Repro app secret.
|
|
160
163
|
- `captureHeaders` (boolean | HeaderCaptureOptions): enable/disable header capture
|
|
@@ -197,6 +200,7 @@ import { reproMiddleware } from 'repro-nest';
|
|
|
197
200
|
app.use(reproMiddleware({
|
|
198
201
|
appId: process.env.REPRO_APP_ID as string,
|
|
199
202
|
appName: process.env.REPRO_APP_NAME as string,
|
|
203
|
+
serviceName: process.env.REPRO_SERVICE_NAME as string,
|
|
200
204
|
tenantId: process.env.REPRO_TENANT_ID as string,
|
|
201
205
|
appSecret: process.env.REPRO_APP_SECRET as string,
|
|
202
206
|
captureHeaders: {
|
|
@@ -259,6 +263,7 @@ document diffs. It emits data only when a Repro session is active (i.e., when
|
|
|
259
263
|
Arguments:
|
|
260
264
|
- `appId` (string): Repro app id
|
|
261
265
|
- `appName` (string, optional): Repro app name (sent as `X-App-Name`)
|
|
266
|
+
- `serviceName` (string, optional): service label persisted with backend events
|
|
262
267
|
- `tenantId` (string): Repro tenant id
|
|
263
268
|
- `appSecret` (string): Repro app secret
|
|
264
269
|
|
|
@@ -271,6 +276,7 @@ import { reproMongoosePlugin } from 'repro-nest';
|
|
|
271
276
|
mongoose.plugin(reproMongoosePlugin({
|
|
272
277
|
appId: process.env.REPRO_APP_ID as string,
|
|
273
278
|
appName: process.env.REPRO_APP_NAME as string,
|
|
279
|
+
serviceName: process.env.REPRO_SERVICE_NAME as string,
|
|
274
280
|
tenantId: process.env.REPRO_TENANT_ID as string,
|
|
275
281
|
appSecret: process.env.REPRO_APP_SECRET as string,
|
|
276
282
|
}));
|
|
@@ -287,6 +293,7 @@ MongooseModule.forRoot(process.env.MONGO_URL as string, {
|
|
|
287
293
|
connection.plugin(reproMongoosePlugin({
|
|
288
294
|
appId: process.env.REPRO_APP_ID as string,
|
|
289
295
|
appName: process.env.REPRO_APP_NAME as string,
|
|
296
|
+
serviceName: process.env.REPRO_SERVICE_NAME as string,
|
|
290
297
|
tenantId: process.env.REPRO_TENANT_ID as string,
|
|
291
298
|
appSecret: process.env.REPRO_APP_SECRET as string,
|
|
292
299
|
}));
|
|
@@ -305,11 +312,38 @@ const userSchema = new Schema({ email: String });
|
|
|
305
312
|
userSchema.plugin(reproMongoosePlugin({
|
|
306
313
|
appId: process.env.REPRO_APP_ID as string,
|
|
307
314
|
appName: process.env.REPRO_APP_NAME as string,
|
|
315
|
+
serviceName: process.env.REPRO_SERVICE_NAME as string,
|
|
308
316
|
tenantId: process.env.REPRO_TENANT_ID as string,
|
|
309
317
|
appSecret: process.env.REPRO_APP_SECRET as string,
|
|
310
318
|
}));
|
|
311
319
|
```
|
|
312
320
|
|
|
321
|
+
### KafkaJS integration
|
|
322
|
+
|
|
323
|
+
`patchKafkaJs` instruments `kafkajs` producers and consumers.
|
|
324
|
+
|
|
325
|
+
- Producer calls (`send`, `sendBatch`) propagate Repro trace/session headers.
|
|
326
|
+
- Consumer handlers (`eachMessage`, `eachBatch`) restore context and emit backend
|
|
327
|
+
request + trace batches for Kafka processing.
|
|
328
|
+
|
|
329
|
+
Call it once during bootstrap, before creating producers/consumers:
|
|
330
|
+
|
|
331
|
+
```ts
|
|
332
|
+
import { patchKafkaJs } from 'repro-nest';
|
|
333
|
+
|
|
334
|
+
patchKafkaJs({
|
|
335
|
+
appId: process.env.REPRO_APP_ID as string,
|
|
336
|
+
appName: process.env.REPRO_APP_NAME as string,
|
|
337
|
+
serviceName: process.env.REPRO_SERVICE_NAME as string,
|
|
338
|
+
tenantId: process.env.REPRO_TENANT_ID as string,
|
|
339
|
+
appSecret: process.env.REPRO_APP_SECRET as string,
|
|
340
|
+
});
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Notes:
|
|
344
|
+
- `kafkajs` must be installed in the host service.
|
|
345
|
+
- The integration is a no-op when `kafkajs` is not present.
|
|
346
|
+
|
|
313
347
|
## 3) Run
|
|
314
348
|
|
|
315
349
|
Run your Nest app as usual after wiring the SDK:
|
|
@@ -335,7 +369,7 @@ curl \
|
|
|
335
369
|
```
|
|
336
370
|
|
|
337
371
|
Verification tips:
|
|
338
|
-
- If the Repro UI does not show the session, confirm `
|
|
372
|
+
- If the Repro UI does not show the session, confirm `REPRO_INGEST_BASE` and
|
|
339
373
|
credentials are correct.
|
|
340
374
|
- Temporarily set `logFunctionCalls: true` in `initReproTracing` to see trace
|
|
341
375
|
enter/exit logs in your console.
|
package/dist/index.d.ts
CHANGED
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
/// <reference types="mongoose/types/inferrawdoctype" />
|
|
26
26
|
import type { Request, Response, NextFunction } from 'express';
|
|
27
27
|
import type { Schema } from 'mongoose';
|
|
28
|
+
import { type IngestClientConfig } from './ingest/client';
|
|
29
|
+
import { type NormalizedRuntimePrivacyPolicy, type RuntimePrivacyConfig } from './privacy';
|
|
28
30
|
type SpanContext = {
|
|
29
31
|
traceId: string | null;
|
|
30
32
|
spanId: string | number | null;
|
|
@@ -54,6 +56,68 @@ export type TraceEventForFilter = {
|
|
|
54
56
|
depth?: number;
|
|
55
57
|
library?: string | null;
|
|
56
58
|
};
|
|
59
|
+
type TraceEventRecord = {
|
|
60
|
+
t: number;
|
|
61
|
+
type: 'enter' | 'exit';
|
|
62
|
+
functionType?: string | null;
|
|
63
|
+
fn?: string;
|
|
64
|
+
file?: string;
|
|
65
|
+
line?: number | null;
|
|
66
|
+
depth?: number;
|
|
67
|
+
spanId?: string | number | null;
|
|
68
|
+
parentSpanId?: string | number | null;
|
|
69
|
+
args?: any;
|
|
70
|
+
returnValue?: any;
|
|
71
|
+
threw?: boolean;
|
|
72
|
+
error?: any;
|
|
73
|
+
unawaited?: boolean;
|
|
74
|
+
argsValueCapture?: TraceValueCaptureRef;
|
|
75
|
+
returnValueCapture?: TraceValueCaptureRef;
|
|
76
|
+
errorValueCapture?: TraceValueCaptureRef;
|
|
77
|
+
};
|
|
78
|
+
type PendingTraceEventRecord = TraceEventRecord & {
|
|
79
|
+
__reproPending?: {
|
|
80
|
+
candidate?: TraceEventForFilter;
|
|
81
|
+
argsRaw?: any;
|
|
82
|
+
returnValueRaw?: any;
|
|
83
|
+
errorRaw?: any;
|
|
84
|
+
};
|
|
85
|
+
__reproSourceFile?: string | null;
|
|
86
|
+
__reproTraceValueEntries?: TraceValueBatchEntry[];
|
|
87
|
+
};
|
|
88
|
+
type TraceValueCaptureRef = {
|
|
89
|
+
status: 'stored' | 'truncated-for-storage' | 'skipped-non-meaningful';
|
|
90
|
+
valueId?: string;
|
|
91
|
+
projectedKind?: string;
|
|
92
|
+
};
|
|
93
|
+
type TraceValueBatchEntry = {
|
|
94
|
+
id: string;
|
|
95
|
+
target: 'db.pk' | 'db.before' | 'db.after' | 'db.query' | 'db.resultMeta' | 'db.error' | 'request.headers' | 'request.body' | 'request.params' | 'request.query' | 'response.body' | 'trace.args' | 'trace.returnValue' | 'trace.error';
|
|
96
|
+
value: any;
|
|
97
|
+
truncatedForStorage?: boolean;
|
|
98
|
+
projectedKind?: string;
|
|
99
|
+
fn?: string;
|
|
100
|
+
file?: string;
|
|
101
|
+
line?: number | null;
|
|
102
|
+
spanId?: string | number | null;
|
|
103
|
+
parentSpanId?: string | number | null;
|
|
104
|
+
batchIndex?: number;
|
|
105
|
+
eventIndex?: number;
|
|
106
|
+
};
|
|
107
|
+
type TraceMaterializationConfig = {
|
|
108
|
+
appId: string;
|
|
109
|
+
appSecret?: string;
|
|
110
|
+
appName?: string;
|
|
111
|
+
privacy?: RuntimePrivacyConfig;
|
|
112
|
+
};
|
|
113
|
+
type TraceMaterializationWorkerPayload = {
|
|
114
|
+
events: PendingTraceEventRecord[];
|
|
115
|
+
cfg: TraceMaterializationConfig;
|
|
116
|
+
maskReq: MaskRequestContext;
|
|
117
|
+
masking: NormalizedMaskingConfig | null;
|
|
118
|
+
privacy: NormalizedRuntimePrivacyPolicy | null;
|
|
119
|
+
fullValueCaptureEnabled: boolean;
|
|
120
|
+
};
|
|
57
121
|
export type HeaderRule = string | RegExp;
|
|
58
122
|
export type HeaderCaptureOptions = {
|
|
59
123
|
/** When true, sensitive headers such as Authorization are kept unmasked; default masks them. */
|
|
@@ -120,7 +184,7 @@ export type DisableFunctionTraceRule = {
|
|
|
120
184
|
};
|
|
121
185
|
export type DisableFunctionTracePredicate = (event: TraceEventForFilter) => boolean;
|
|
122
186
|
export type DisableFunctionTraceConfig = DisableFunctionTraceRule | DisableFunctionTracePredicate;
|
|
123
|
-
export type ReproMaskTarget = 'request.headers' | 'request.body' | 'request.params' | 'request.query' | 'response.body' | 'trace.args' | 'trace.returnValue' | 'trace.error';
|
|
187
|
+
export type ReproMaskTarget = 'db.pk' | 'db.before' | 'db.after' | 'db.query' | 'db.resultMeta' | 'db.error' | 'request.headers' | 'request.body' | 'request.params' | 'request.query' | 'response.body' | 'trace.args' | 'trace.returnValue' | 'trace.error';
|
|
124
188
|
export type ReproMaskWhen = DisableFunctionTraceRule & {
|
|
125
189
|
/** Match HTTP method (e.g. `"GET"`, `/^post$/i`). */
|
|
126
190
|
method?: TraceRulePattern;
|
|
@@ -161,6 +225,11 @@ type TracerInitOpts = {
|
|
|
161
225
|
samplingMs?: number;
|
|
162
226
|
};
|
|
163
227
|
export type ReproTracingInitOptions = TracerInitOpts & {
|
|
228
|
+
/**
|
|
229
|
+
* When enabled, trace args/return values/errors that lose meaningful data in
|
|
230
|
+
* preview form are also persisted via sidecar refs for on-demand loading.
|
|
231
|
+
*/
|
|
232
|
+
fullValueCapture?: boolean;
|
|
164
233
|
/**
|
|
165
234
|
* Optional list of rules or predicates that suppress unwanted function
|
|
166
235
|
* trace events. When omitted, every instrumented function will be
|
|
@@ -193,29 +262,85 @@ export type ReproTracingInitOptions = TracerInitOpts & {
|
|
|
193
262
|
export declare function initReproTracing(opts?: ReproTracingInitOptions): TracerApi | null;
|
|
194
263
|
/** Optional helper if users want to check it. */
|
|
195
264
|
export declare function isReproTracingEnabled(): boolean;
|
|
196
|
-
export
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
265
|
+
export declare function __materializePendingTraceEventsForWorker(payload: TraceMaterializationWorkerPayload): Promise<PendingTraceEventRecord[]>;
|
|
266
|
+
type NormalizedMaskRule = {
|
|
267
|
+
when?: ReproMaskWhen;
|
|
268
|
+
targets: ReproMaskTarget[];
|
|
269
|
+
paths: string[][];
|
|
270
|
+
keys?: TraceRulePattern;
|
|
271
|
+
replacement: any;
|
|
272
|
+
};
|
|
273
|
+
type NormalizedMaskingConfig = {
|
|
274
|
+
replacement: any;
|
|
275
|
+
rules: NormalizedMaskRule[];
|
|
276
|
+
};
|
|
277
|
+
type MaskRequestContext = {
|
|
278
|
+
method: string;
|
|
279
|
+
path: string;
|
|
280
|
+
key: string;
|
|
281
|
+
};
|
|
282
|
+
declare function shareRuntimePrivacyState(source: ReproMiddlewareConfig, target: ReproMiddlewareConfig): void;
|
|
283
|
+
export type ReproMiddlewareConfig = IngestClientConfig & {
|
|
200
284
|
/** Configure header capture/masking. Defaults to capturing with sensitive headers masked. */
|
|
201
285
|
captureHeaders?: boolean | HeaderCaptureOptions;
|
|
202
286
|
/** Optional masking rules for request/response payloads and function traces. */
|
|
203
287
|
masking?: ReproMaskingConfig;
|
|
288
|
+
/** Optional privacy policy config for deterministic runtime transformations. */
|
|
289
|
+
privacy?: RuntimePrivacyConfig;
|
|
204
290
|
};
|
|
205
|
-
export
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
291
|
+
export type ReproInitConfig = ReproMiddlewareConfig & {
|
|
292
|
+
/**
|
|
293
|
+
* Tracing configuration for function/http instrumentation.
|
|
294
|
+
* Pass `false` to skip tracer initialization.
|
|
295
|
+
*/
|
|
296
|
+
tracing?: ReproTracingInitOptions | false;
|
|
297
|
+
/**
|
|
298
|
+
* Optional context resolver used by transport integrations when ALS context
|
|
299
|
+
* is not present.
|
|
300
|
+
*/
|
|
301
|
+
resolveContext?: () => {
|
|
302
|
+
sid?: string;
|
|
303
|
+
aid?: string;
|
|
304
|
+
} | undefined;
|
|
305
|
+
};
|
|
306
|
+
export declare function reproMiddleware(cfg: ReproMiddlewareConfig): (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
307
|
+
export declare function reproMongoosePlugin(cfg: ReproMiddlewareConfig): (schema: Schema) => void;
|
|
308
|
+
type KafkaContextResolver = () => {
|
|
309
|
+
sid?: string;
|
|
310
|
+
aid?: string;
|
|
311
|
+
} | undefined;
|
|
312
|
+
export type KafkaJsPatchConfig = ReproMiddlewareConfig & {
|
|
313
|
+
resolveContext?: KafkaContextResolver;
|
|
314
|
+
};
|
|
315
|
+
declare function recordKafkaTraceEventAsync(raw: any, sink: TraceEventRecord[], cfg: KafkaJsPatchConfig, maskReq: MaskRequestContext): Promise<void>;
|
|
316
|
+
declare function wrapKafkaEachMessageHandler(eachMessage: any, cfg: KafkaJsPatchConfig, consumer: any): (this: any, payload: any) => Promise<any>;
|
|
317
|
+
export declare function patchKafkaJs(cfg: KafkaJsPatchConfig): void;
|
|
318
|
+
export type RedisPatchConfig = ReproMiddlewareConfig & {
|
|
319
|
+
resolveContext?: () => {
|
|
320
|
+
sid?: string;
|
|
321
|
+
aid?: string;
|
|
322
|
+
} | undefined;
|
|
323
|
+
};
|
|
324
|
+
export declare function patchRedis(cfg: RedisPatchConfig): void;
|
|
325
|
+
export type SendgridPatchConfig = ReproMiddlewareConfig & {
|
|
215
326
|
resolveContext?: () => {
|
|
216
327
|
sid?: string;
|
|
217
328
|
aid?: string;
|
|
218
329
|
} | undefined;
|
|
219
330
|
};
|
|
220
331
|
export declare function patchSendgridMail(cfg: SendgridPatchConfig): void;
|
|
332
|
+
/**
|
|
333
|
+
* Datadog-style one-time init.
|
|
334
|
+
* Enables tracing, auto-patches integrations, auto-registers mongoose plugin,
|
|
335
|
+
* and auto-attaches middleware to Nest/Express applications.
|
|
336
|
+
*/
|
|
337
|
+
export declare function initRepro(cfg: ReproInitConfig): Promise<void>;
|
|
338
|
+
/** @internal Test hooks for runtime privacy policy wiring. */
|
|
339
|
+
export declare const __reproTestHooks: {
|
|
340
|
+
shareRuntimePrivacyStateForTest: typeof shareRuntimePrivacyState;
|
|
341
|
+
getRuntimePrivacyPolicyForTest(cfg: ReproMiddlewareConfig): NormalizedRuntimePrivacyPolicy | null;
|
|
342
|
+
setRuntimePrivacyPolicyForTest(cfg: ReproMiddlewareConfig, policy: NormalizedRuntimePrivacyPolicy | null): void;
|
|
343
|
+
recordKafkaTraceEventAsyncForTest: typeof recordKafkaTraceEventAsync;
|
|
344
|
+
wrapKafkaEachMessageHandlerForTest: typeof wrapKafkaEachMessageHandler;
|
|
345
|
+
};
|
|
221
346
|
export {};
|