@reproapp/node-sdk
v0.0.3
Published
Repro Nest SDK
Readme
Repro Nest SDK
Capture NestJS request/response data, function traces, and Mongoose activity for Repro sessions. This SDK is designed for Nest apps running on Express, with optional tracing and masking controls.
1) Install
Requirements:
- Node.js 18+
- NestJS app using Express (default) and optionally Mongoose 6+
Install the package:
npm install repro-nest
# or
yarn add repro-nest
# or
pnpm add repro-nest2) Configure
At minimum, provide your Repro credentials and wire the middleware. If you want
function tracing, call initReproTracing before importing your AppModule so
Nest classes are instrumented at load time.
import 'reflect-metadata';
import { NestFactory } from '@nestjs/core';
import mongoose from 'mongoose';
import {
initReproTracing,
reproMiddleware,
reproMongoosePlugin,
} from 'repro-nest';
const reproConfig = {
appId: process.env.REPRO_APP_ID as string,
appName: process.env.REPRO_APP_NAME as string,
tenantId: process.env.REPRO_TENANT_ID as string,
appSecret: process.env.REPRO_APP_SECRET as string,
};
async function bootstrap() {
// Enable function tracing before loading your modules.
initReproTracing({
disableFunctionTypes: ['constructor'],
logFunctionCalls: false,
});
// Optional: capture MongoDB queries + document diffs.
mongoose.plugin(reproMongoosePlugin(reproConfig));
const { AppModule } = await import('./app.module');
const app = await NestFactory.create(AppModule);
// Capture request/response payloads for tagged Repro sessions.
app.use(reproMiddleware(reproConfig));
await app.listen(3000);
}
bootstrap();Configuration notes:
REPRO_API_BASE(optional) overrides the backend base URL used to send data.REPRO_APP_NAME(optional) setsappName, which is sent asX-App-Name.
initReproTracing
Enables function tracing. Call this before importing AppModule so Nest classes
are loaded through the tracer.
Options (type -> purpose):
instrument(boolean): enable or disable instrumentation of loaded modules.include(RegExp[]): file path include patterns for instrumentation.exclude(RegExp[]): file path exclude patterns for instrumentation.mode(string): tracer mode (defaults toTRACE_MODEortrace).samplingMs(number): sampling interval in milliseconds.disableFunctionTraces(DisableFunctionTraceConfig[] | null): drop trace events that match rule objects or predicates.disableFunctionTypes(TraceRulePattern | null): drop events for matching function kinds (for example, constructors).disableTraceFiles(DisableTraceFileConfig | DisableTraceFileConfig[] | null): drop events emitted from matching files.traceInterceptors(boolean): include Nest interceptors in traces (default false).logFunctionCalls(boolean): log enter/exit events to console.
Type reference:
TraceRulePattern:string | number | RegExp | Array<string | number | RegExp>DisableFunctionTraceConfig:DisableFunctionTraceRule | DisableFunctionTracePredicateDisableFunctionTracePredicate:(event: TraceEventForFilter) => booleanDisableFunctionTraceRulefields (all acceptTraceRulePattern):fn/functionName: function name substring/regexwrapper/wrapperClass/className/owner: wrapper/owner namefile: source filenameline: source line numberlib/library: npm package name inferred from pathtype/functionType: function kind (method,constructor, etc.)event/eventType: trace phase (enterorexit)
DisableTraceByFilename:{ file: TraceRulePattern }DisableTraceFileConfig:TraceRulePattern | DisableTraceByFilename | null | undefined
Full config example (shows every option; aliases are interchangeable, use one per group in real configs):
import { initReproTracing } from 'repro-nest';
initReproTracing({
instrument: true,
include: [/^\/app\/src\//],
exclude: [/node_modules\//, /dist\//],
mode: process.env.TRACE_MODE || 'trace',
samplingMs: 10,
disableFunctionTraces: [
{
fn: 'findAll',
wrapper: 'TasksService',
file: 'src/tasks/tasks.service.ts',
line: 27,
lib: 'mongoose',
type: 'method',
event: 'exit',
},
{
functionName: 'formatSensitiveData',
wrapperClass: 'AuthService',
className: 'AuthService',
owner: 'AuthService',
library: 'bcrypt',
functionType: 'method',
eventType: 'enter',
},
(event) => event.fn?.startsWith('debug') ?? false,
],
disableFunctionTypes: ['constructor', /getter/i],
disableTraceFiles: [
/node_modules\/some-logger\//,
{ file: 'dist/health.check.js' },
'dist/generated.js',
],
traceInterceptors: true,
logFunctionCalls: false,
});reproMiddleware
Captures request/response payloads for active Repro sessions. Requests must
include x-bug-session-id and x-bug-action-id headers to be captured.
Options (type -> purpose):
appId(string): Repro app id.appName(string, optional): Repro app name (sent asX-App-Name).tenantId(string): Repro tenant id.appSecret(string): Repro app secret.captureHeaders(boolean | HeaderCaptureOptions): enable/disable header capture and masking.masking(ReproMaskingConfig): mask request/response bodies and trace args/returns.
Header capture options (HeaderCaptureOptions):
allowSensitiveHeaders(boolean): keep default sensitive headers unmasked.maskHeaders(HeaderRule | HeaderRule[]): header names to mask.dropHeaders(HeaderRule | HeaderRule[]): alias formaskHeaders.unmaskHeaders(HeaderRule | HeaderRule[]): header names to keep unmasked.keepHeaders(HeaderRule | HeaderRule[]): alias forunmaskHeaders.HeaderRule:string | RegExp
Masking options (ReproMaskingConfig):
replacement(any): default replacement value (defaults to"[REDACTED]").rules(ReproMaskRule[] | null): list of masking rules.
Masking rule options (ReproMaskRule):
when(ReproMaskWhen): scope rules by request or function trace fields.target(ReproMaskTarget | ReproMaskTarget[]): where to apply the mask.paths(string | string[]): dot/bracket paths to mask.keys(TraceRulePattern): mask keys anywhere in the payload.replacement(any): override replacement value for this rule.
ReproMaskTarget values:
request.headers,request.body,request.params,request.queryresponse.body,trace.args,trace.returnValue,trace.error
ReproMaskWhen fields (all accept TraceRulePattern unless noted):
- Request scope:
method,path,key - Function scope:
fn/functionName,wrapper/wrapperClass/className/owner,file,line,lib/library,type/functionType,event/eventType
Full config example (shows every option; aliases are interchangeable, use one per group in real configs):
import { reproMiddleware } from 'repro-nest';
app.use(reproMiddleware({
appId: process.env.REPRO_APP_ID as string,
appName: process.env.REPRO_APP_NAME as string,
tenantId: process.env.REPRO_TENANT_ID as string,
appSecret: process.env.REPRO_APP_SECRET as string,
captureHeaders: {
allowSensitiveHeaders: false,
maskHeaders: [/authorization/i, /cookie/i],
dropHeaders: ['x-api-key'],
unmaskHeaders: ['x-request-id'],
keepHeaders: ['x-trace-id'],
},
masking: {
replacement: '[REDACTED]',
rules: [
{
when: { method: 'POST', path: '/api/auth/login', key: 'POST /api/auth/login' },
target: ['request.body', 'response.body'],
paths: ['password'],
keys: [/token/i],
replacement: '[FILTERED]',
},
{
when: {
functionName: 'findAll',
wrapperClass: 'TasksService',
file: 'src/tasks/tasks.service.ts',
line: 27,
library: 'mongoose',
functionType: 'method',
eventType: 'exit',
},
target: ['trace.args', 'trace.returnValue', 'trace.error'],
paths: ['0.user.token'],
keys: ['password'],
},
{
when: {
fn: 'create',
wrapper: 'UsersService',
className: 'UsersService',
owner: 'UsersService',
lib: 'mongoose',
type: 'method',
event: 'enter',
},
target: 'trace.args',
paths: ['0.password'],
},
],
},
}));See docs/tracing.md for full masking and trace filtering details.
Mongoose plugin
reproMongoosePlugin attaches schema middleware to capture query activity and
document diffs. It emits data only when a Repro session is active (i.e., when
reproMiddleware has set the session context for the current request).
Arguments:
appId(string): Repro app idappName(string, optional): Repro app name (sent asX-App-Name)tenantId(string): Repro tenant idappSecret(string): Repro app secret
Example: global plugin (all schemas)
import mongoose from 'mongoose';
import { reproMongoosePlugin } from 'repro-nest';
mongoose.plugin(reproMongoosePlugin({
appId: process.env.REPRO_APP_ID as string,
appName: process.env.REPRO_APP_NAME as string,
tenantId: process.env.REPRO_TENANT_ID as string,
appSecret: process.env.REPRO_APP_SECRET as string,
}));Example: Nest MongooseModule connection factory
import { MongooseModule } from '@nestjs/mongoose';
import { reproMongoosePlugin } from 'repro-nest';
MongooseModule.forRoot(process.env.MONGO_URL as string, {
connectionFactory: (connection) => {
connection.plugin(reproMongoosePlugin({
appId: process.env.REPRO_APP_ID as string,
appName: process.env.REPRO_APP_NAME as string,
tenantId: process.env.REPRO_TENANT_ID as string,
appSecret: process.env.REPRO_APP_SECRET as string,
}));
return connection;
},
});Example: schema-level plugin (single model)
import { Schema } from 'mongoose';
import { reproMongoosePlugin } from 'repro-nest';
const userSchema = new Schema({ email: String });
userSchema.plugin(reproMongoosePlugin({
appId: process.env.REPRO_APP_ID as string,
appName: process.env.REPRO_APP_NAME as string,
tenantId: process.env.REPRO_TENANT_ID as string,
appSecret: process.env.REPRO_APP_SECRET as string,
}));3) Run
Run your Nest app as usual after wiring the SDK:
npm run start:dev
# or
node dist/main.jsIf you use initReproTracing, keep it at the top of your bootstrap so modules
load after instrumentation is enabled.
4) Verify It Works
Send a request with Repro headers and confirm the session shows up in Repro.
curl \
-H "x-bug-session-id: session-123" \
-H "x-bug-action-id: action-123" \
http://localhost:3000/healthVerification tips:
- If the Repro UI does not show the session, confirm
REPRO_API_BASEand credentials are correct. - Temporarily set
logFunctionCalls: trueininitReproTracingto see trace enter/exit logs in your console. - If you use Mongoose, exercise a query/mutation and verify DB entries appear in the session trace.
