@reproapp/node-sdk 0.0.35 → 0.0.37
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/dist/index.js
CHANGED
|
@@ -330,7 +330,7 @@ let disabledFunctionTraceRules = computeDisabledFunctionTraceRules();
|
|
|
330
330
|
let disabledFunctionTypePatterns = [];
|
|
331
331
|
let disabledTraceFilePatterns = [];
|
|
332
332
|
let __TRACE_LOG_PREF = null;
|
|
333
|
-
let __FULL_VALUE_CAPTURE_ENABLED =
|
|
333
|
+
let __FULL_VALUE_CAPTURE_ENABLED = true;
|
|
334
334
|
function setInterceptorTracingEnabled(enabled) {
|
|
335
335
|
const next = !!enabled;
|
|
336
336
|
if (interceptorTracingEnabled === next)
|
|
@@ -581,9 +581,9 @@ function defaultTracerInitOpts() {
|
|
|
581
581
|
/** Call this from the client app to enable tracing. Safe to call multiple times. */
|
|
582
582
|
function initReproTracing(opts) {
|
|
583
583
|
const options = opts ?? {};
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
584
|
+
__FULL_VALUE_CAPTURE_ENABLED = hasOwn(options, 'fullValueCapture')
|
|
585
|
+
? options.fullValueCapture === true
|
|
586
|
+
: true;
|
|
587
587
|
if (hasOwn(options, 'traceInterceptors')) {
|
|
588
588
|
setInterceptorTracingEnabled(!!options.traceInterceptors);
|
|
589
589
|
}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -604,7 +604,7 @@ let disabledFunctionTraceRules: DisableFunctionTraceConfig[] = computeDisabledFu
|
|
|
604
604
|
let disabledFunctionTypePatterns: Array<string | number | RegExp> = [];
|
|
605
605
|
let disabledTraceFilePatterns: Array<string | number | RegExp> = [];
|
|
606
606
|
let __TRACE_LOG_PREF: boolean | null = null;
|
|
607
|
-
let __FULL_VALUE_CAPTURE_ENABLED =
|
|
607
|
+
let __FULL_VALUE_CAPTURE_ENABLED = true;
|
|
608
608
|
|
|
609
609
|
function setInterceptorTracingEnabled(enabled: boolean) {
|
|
610
610
|
const next = !!enabled;
|
|
@@ -929,9 +929,9 @@ function defaultTracerInitOpts(): TracerInitOpts {
|
|
|
929
929
|
export function initReproTracing(opts?: ReproTracingInitOptions) {
|
|
930
930
|
const options = opts ?? {};
|
|
931
931
|
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
932
|
+
__FULL_VALUE_CAPTURE_ENABLED = hasOwn(options, 'fullValueCapture')
|
|
933
|
+
? options.fullValueCapture === true
|
|
934
|
+
: true;
|
|
935
935
|
|
|
936
936
|
if (hasOwn(options, 'traceInterceptors')) {
|
|
937
937
|
setInterceptorTracingEnabled(!!options.traceInterceptors);
|
|
@@ -170,10 +170,28 @@ async function main() {
|
|
|
170
170
|
event?.returnValue,
|
|
171
171
|
);
|
|
172
172
|
assert(largeReturnExit, JSON.stringify(traceEvents));
|
|
173
|
-
assert
|
|
174
|
-
largeReturnExit.returnValue,
|
|
175
|
-
|
|
173
|
+
assert(
|
|
174
|
+
Buffer.byteLength(JSON.stringify(largeReturnExit.returnValue), 'utf8') <= 2048,
|
|
175
|
+
JSON.stringify(largeReturnExit.returnValue),
|
|
176
176
|
);
|
|
177
|
+
assert.equal(
|
|
178
|
+
largeReturnExit.returnValueCapture?.status,
|
|
179
|
+
'stored',
|
|
180
|
+
JSON.stringify(largeReturnExit),
|
|
181
|
+
);
|
|
182
|
+
assert(
|
|
183
|
+
typeof largeReturnExit.returnValueCapture?.valueId === 'string' &&
|
|
184
|
+
largeReturnExit.returnValueCapture.valueId.length > 0,
|
|
185
|
+
JSON.stringify(largeReturnExit),
|
|
186
|
+
);
|
|
187
|
+
const traceValues = eventsOf(capturedBodies, 'trace_batch')
|
|
188
|
+
.flatMap((event) => Array.isArray(event?.payload?.traceValues) ? event.payload.traceValues : []);
|
|
189
|
+
const capturedReturnValue = traceValues.find((entry) =>
|
|
190
|
+
entry?.id === largeReturnExit.returnValueCapture.valueId &&
|
|
191
|
+
entry?.target === 'trace.returnValue'
|
|
192
|
+
);
|
|
193
|
+
assert(capturedReturnValue, JSON.stringify(traceValues));
|
|
194
|
+
assert.equal(capturedReturnValue.value?.rows?.length, 400, JSON.stringify(capturedReturnValue));
|
|
177
195
|
|
|
178
196
|
console.log('client performance regression guards OK');
|
|
179
197
|
} finally {
|
|
@@ -332,6 +332,151 @@ async function testMongoClientDbCollectionChainIsPatchedWithoutCollectionExport(
|
|
|
332
332
|
});
|
|
333
333
|
}
|
|
334
334
|
|
|
335
|
+
async function testClientScreenNativeMongoInsertOneShapeIsCaptured() {
|
|
336
|
+
await withCapturedFetch(async (capturedBodies) => {
|
|
337
|
+
__reproTestHooks.resetSdkBackgroundQueuesForTest();
|
|
338
|
+
const sessionId = 'S_client_screen_native_insert';
|
|
339
|
+
const actionId = 'A_client_screen_native_insert';
|
|
340
|
+
const cfg = {
|
|
341
|
+
...makeConfig(sessionId, actionId),
|
|
342
|
+
privacy: { environment: 'dev', captureRaw: true },
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
class FakeCollection {
|
|
346
|
+
constructor(dbName, collectionName) {
|
|
347
|
+
this.dbName = dbName;
|
|
348
|
+
this.collectionName = collectionName;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
async insertOne(doc, options) {
|
|
352
|
+
assert.strictEqual(options.session.id, 'screen-transaction-session-1');
|
|
353
|
+
doc._id = doc._id ?? 'subject-screen-1';
|
|
354
|
+
return { acknowledged: true, insertedId: doc._id };
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
class FakeDb {
|
|
359
|
+
constructor(dbName) {
|
|
360
|
+
this.databaseName = dbName;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
collection(collectionName) {
|
|
364
|
+
return new FakeCollection(this.databaseName, collectionName);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
class FakeMongoClient {
|
|
369
|
+
db(dbName) {
|
|
370
|
+
return new FakeDb(dbName);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
__reproTestHooks.patchMongoDbModuleForTest({
|
|
375
|
+
MongoClient: FakeMongoClient,
|
|
376
|
+
Db: FakeDb,
|
|
377
|
+
}, cfg);
|
|
378
|
+
|
|
379
|
+
const dbClient = new FakeMongoClient();
|
|
380
|
+
const connectionDictionary = {
|
|
381
|
+
pulmovant: {
|
|
382
|
+
db: {
|
|
383
|
+
databaseName: 'dev-configure-pulmovant',
|
|
384
|
+
},
|
|
385
|
+
},
|
|
386
|
+
};
|
|
387
|
+
const collectionNames = {
|
|
388
|
+
SUBJECTS: 'subjects',
|
|
389
|
+
};
|
|
390
|
+
const completeVisitTypeLimitChecks = async () => null;
|
|
391
|
+
|
|
392
|
+
async function screen(req, newSubjectRecord, openUserTransaction) {
|
|
393
|
+
newSubjectRecord.lastUserTransactionId = openUserTransaction._id;
|
|
394
|
+
|
|
395
|
+
const dbName = connectionDictionary[req.query.tenantId].db.databaseName;
|
|
396
|
+
const subjectsCollection = await dbClient.db(dbName).collection(collectionNames.SUBJECTS);
|
|
397
|
+
|
|
398
|
+
const checkResult = await completeVisitTypeLimitChecks();
|
|
399
|
+
if (checkResult) return { success: false, message: checkResult };
|
|
400
|
+
|
|
401
|
+
const subjectSaveResult = await subjectsCollection.insertOne(newSubjectRecord, {
|
|
402
|
+
session: req.mongoSession,
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
if (!subjectSaveResult.acknowledged) {
|
|
406
|
+
throw new Error('Error creating subject');
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return { success: true, insertedId: subjectSaveResult.insertedId };
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const newSubjectRecord = {
|
|
413
|
+
activityLog: {
|
|
414
|
+
createdBy: '678a70921acd637a6de91c1f',
|
|
415
|
+
createdByUserName: "Pat O'Brien",
|
|
416
|
+
createdOn: '2026-06-22 10:14:13.151000000',
|
|
417
|
+
},
|
|
418
|
+
demographics: [
|
|
419
|
+
{ key: 'age', type: 'Number', value: '35' },
|
|
420
|
+
{ key: 'dateOfBirth', type: 'String', value: '1990' },
|
|
421
|
+
{ key: 'gender', type: 'String', value: 'Female' },
|
|
422
|
+
],
|
|
423
|
+
protocolId: '69e77c77ab541cfac917b36b',
|
|
424
|
+
site: {
|
|
425
|
+
id: '69f0c10256a07ef2204a6ef6',
|
|
426
|
+
number: '1001',
|
|
427
|
+
},
|
|
428
|
+
status: 'Active',
|
|
429
|
+
subjectFlags: {
|
|
430
|
+
isRescreen: false,
|
|
431
|
+
},
|
|
432
|
+
subjectNumber: '10013060',
|
|
433
|
+
subjectStatus: 'Screened',
|
|
434
|
+
subjectStatusOption: 'Screened',
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
await runCapturedRequest(cfg, sessionId, actionId, async () => {
|
|
438
|
+
const result = await screen(
|
|
439
|
+
{
|
|
440
|
+
query: { tenantId: 'pulmovant' },
|
|
441
|
+
mongoSession: {
|
|
442
|
+
id: 'screen-transaction-session-1',
|
|
443
|
+
hasEnded: false,
|
|
444
|
+
inTransaction: () => true,
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
newSubjectRecord,
|
|
448
|
+
{ _id: '6a390af395744083f43fd484' },
|
|
449
|
+
);
|
|
450
|
+
assert.deepStrictEqual(result, {
|
|
451
|
+
success: true,
|
|
452
|
+
insertedId: 'subject-screen-1',
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
await waitFor(() => dbChanges(flattenEvents(capturedBodies)).length === 1);
|
|
457
|
+
await waitFor(() => requestCaptureManifests(flattenEvents(capturedBodies)).length === 1);
|
|
458
|
+
await drainSdk();
|
|
459
|
+
|
|
460
|
+
const [change] = dbChanges(flattenEvents(capturedBodies));
|
|
461
|
+
const [manifest] = requestCaptureManifests(flattenEvents(capturedBodies));
|
|
462
|
+
assert.strictEqual(change.type, 'mongo');
|
|
463
|
+
assert.strictEqual(change.collection, 'subjects');
|
|
464
|
+
assert.strictEqual(change.op, 'insertOne');
|
|
465
|
+
assert.strictEqual(change.pk._id, 'subject-screen-1');
|
|
466
|
+
assert.strictEqual(change.query.driver, 'mongodb');
|
|
467
|
+
assert.strictEqual(change.query.db, 'dev-configure-pulmovant');
|
|
468
|
+
assert.strictEqual(change.query.doc.subjectNumber, '10013060');
|
|
469
|
+
assert.strictEqual(change.query.doc.lastUserTransactionId, '6a390af395744083f43fd484');
|
|
470
|
+
assert.strictEqual(change.query.options.session.__kind, 'mongodb_client_session');
|
|
471
|
+
assert.strictEqual(change.query.options.session.id, 'screen-transaction-session-1');
|
|
472
|
+
assert.strictEqual(change.query.options.session.inTransaction, true);
|
|
473
|
+
assert.strictEqual(change.after.subjectNumber, '10013060');
|
|
474
|
+
assert.strictEqual(change.resultMeta.insertedId, 'subject-screen-1');
|
|
475
|
+
assert.strictEqual(change.resultMeta.acknowledged, true);
|
|
476
|
+
assert.strictEqual(manifest.expected.dbChange, 1);
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
|
|
335
480
|
async function testNativeInsertOneIsCaptured() {
|
|
336
481
|
await withCapturedFetch(async (capturedBodies) => {
|
|
337
482
|
__reproTestHooks.resetSdkBackgroundQueuesForTest();
|
|
@@ -596,6 +741,7 @@ async function testNativeOperationFailureIsCapturedAndRethrown() {
|
|
|
596
741
|
await testMongooseSuppressionDoesNotHideExplicitNativeInsertOne();
|
|
597
742
|
await testReproMiddlewarePatchesPreloadedNativeMongoClientInsertOne();
|
|
598
743
|
await testMongoClientDbCollectionChainIsPatchedWithoutCollectionExport();
|
|
744
|
+
await testClientScreenNativeMongoInsertOneShapeIsCaptured();
|
|
599
745
|
await testNativeInsertOneIsCaptured();
|
|
600
746
|
await testCaptureRawNativeInsertOneUsesJsonSafeTransportValues();
|
|
601
747
|
await testNativeUpdateOneUpsertIsCaptured();
|