@reproapp/node-sdk 0.0.46 → 0.0.48

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
@@ -9,6 +9,7 @@ const path_1 = require("path");
9
9
  const url_1 = require("url");
10
10
  const client_1 = require("./ingest/client");
11
11
  const privacy_1 = require("./privacy");
12
+ const semantic_serialization_1 = require("./semantic-serialization");
12
13
  /**
13
14
  * ============================= IMPORTANT =============================
14
15
  * We snapshot Mongoose core methods BEFORE tracer init, then re-apply them
@@ -817,16 +818,46 @@ function attachSpanContext(target, span) {
817
818
  }
818
819
  return target;
819
820
  }
820
- function createRequestCaptureScope(requestRid, transport) {
821
+ function createRequestCaptureScope(requestRid, transport, cfg) {
822
+ const privacy = cfg ? getRuntimePrivacyState(cfg).policy ?? null : null;
823
+ const privacyMode = cfg && shouldCapturePrivacyRaw(cfg)
824
+ ? 'raw'
825
+ : privacy
826
+ ? 'policy'
827
+ : 'fallback';
821
828
  return {
822
829
  requestRid,
823
830
  transport,
824
- backendRequestCount: 0,
831
+ // Every scope represents one captured transport request. This is an
832
+ // observed expectation, not a count of successful enqueue operations.
833
+ backendRequestCount: 1,
825
834
  traceBatchCount: 0,
826
835
  dbChangeCount: 0,
827
836
  emailEventCount: 0,
837
+ captureFailures: [],
838
+ privacyMode,
839
+ privacyPolicyFingerprint: privacy?.fingerprint,
840
+ privacyStatementCount: privacy?.statements.length ?? 0,
841
+ emittedValueDefinitionIds: new Set(),
828
842
  };
829
843
  }
844
+ function recordRequestCaptureFailure(scope, stage, target, reason) {
845
+ if (!scope)
846
+ return;
847
+ const normalized = {
848
+ stage: String(stage || 'capture').slice(0, 80),
849
+ target: String(target || 'unknown').slice(0, 120),
850
+ reason: String(reason || 'capture_failed').slice(0, 120),
851
+ };
852
+ if (scope.captureFailures.some((failure) => failure.stage === normalized.stage &&
853
+ failure.target === normalized.target &&
854
+ failure.reason === normalized.reason)) {
855
+ return;
856
+ }
857
+ if (scope.captureFailures.length < 25) {
858
+ scope.captureFailures.push(normalized);
859
+ }
860
+ }
830
861
  function buildRequestCaptureManifestPayload(scope, traceBatchTotal, closedAtMs) {
831
862
  const expectedTraceBatches = Math.max(0, Math.trunc(traceBatchTotal));
832
863
  const closedAt = typeof closedAtMs === 'number' && Number.isFinite(closedAtMs)
@@ -848,6 +879,19 @@ function buildRequestCaptureManifestPayload(scope, traceBatchTotal, closedAtMs)
848
879
  to: expectedTraceBatches - 1,
849
880
  }
850
881
  : undefined,
882
+ privacy: {
883
+ mode: scope.privacyMode,
884
+ status: scope.captureFailures.length > 0
885
+ ? 'failed'
886
+ : scope.privacyMode === 'raw'
887
+ ? 'bypassed'
888
+ : 'applied',
889
+ policyFingerprint: scope.privacyPolicyFingerprint,
890
+ statementCount: scope.privacyStatementCount,
891
+ },
892
+ captureFailures: scope.captureFailures.length
893
+ ? scope.captureFailures.map((failure) => ({ ...failure }))
894
+ : undefined,
851
895
  closedAt,
852
896
  };
853
897
  }
@@ -1024,12 +1068,6 @@ const SDK_BACKGROUND_MAX_DEFER_MS = (() => {
1024
1068
  return Math.trunc(env);
1025
1069
  return Number.POSITIVE_INFINITY;
1026
1070
  })();
1027
- const SDK_BACKGROUND_WORK_TIMEOUT_MS = (() => {
1028
- const env = Number(process.env.REPRO_SDK_BACKGROUND_WORK_TIMEOUT_MS);
1029
- if (Number.isFinite(env) && env >= 0)
1030
- return Math.trunc(env);
1031
- return 20000;
1032
- })();
1033
1071
  const TRACE_MATERIALIZE_OFFTHREAD_ENABLED = (() => {
1034
1072
  const env = String(process.env.REPRO_TRACE_MATERIALIZE_OFFTHREAD || '').trim().toLowerCase();
1035
1073
  if (!env)
@@ -1378,28 +1416,9 @@ function scheduleSdkBackgroundDrain(delayMs = 0) {
1378
1416
  catch { }
1379
1417
  }
1380
1418
  async function runSdkBackgroundWork(work) {
1381
- if (!Number.isFinite(SDK_BACKGROUND_WORK_TIMEOUT_MS) || SDK_BACKGROUND_WORK_TIMEOUT_MS <= 0) {
1382
- await work();
1383
- return;
1384
- }
1385
- let timeout = null;
1386
- const workPromise = Promise.resolve()
1419
+ await Promise.resolve()
1387
1420
  .then(work)
1388
1421
  .catch(() => undefined);
1389
- const timeoutPromise = new Promise((resolve) => {
1390
- timeout = setTimeout(resolve, SDK_BACKGROUND_WORK_TIMEOUT_MS);
1391
- try {
1392
- timeout.unref?.();
1393
- }
1394
- catch { }
1395
- });
1396
- await Promise.race([workPromise, timeoutPromise]);
1397
- if (timeout) {
1398
- try {
1399
- clearTimeout(timeout);
1400
- }
1401
- catch { }
1402
- }
1403
1422
  }
1404
1423
  async function drainQueuedIngestBeforeBackgroundWork() {
1405
1424
  (0, client_1.kickIngestQueueDrain)();
@@ -2258,7 +2277,11 @@ const TRACE_MAX_BATCHES_PER_REQUEST = (() => {
2258
2277
  const env = Number(process.env.REPRO_TRACE_MAX_BATCHES_PER_REQUEST);
2259
2278
  if (Number.isFinite(env) && env > 0)
2260
2279
  return Math.trunc(env);
2261
- return 8;
2280
+ // Byte-based splitting can legitimately produce one batch per event when
2281
+ // every event owns a distinct large value. The event limit remains the
2282
+ // hard upper bound; deriving this from the count-only batch size silently
2283
+ // dropped otherwise valid events after ten batches.
2284
+ return TRACE_MAX_EVENTS_PER_REQUEST;
2262
2285
  })();
2263
2286
  const TRACE_FLUSH_DELAY_MS = 20;
2264
2287
  // Choose how to order trace events in payloads.
@@ -2586,6 +2609,10 @@ function sanitizeTraceValue(value, depth = 0, seen = new WeakMap(), options = {}
2586
2609
  const mongoPlaceholder = describeMongoPlaceholder(value);
2587
2610
  if (mongoPlaceholder)
2588
2611
  return mongoPlaceholder;
2612
+ const semanticProjection = (0, semantic_serialization_1.projectSemanticInfrastructureValue)(value);
2613
+ if (semanticProjection) {
2614
+ return sanitizeTraceValue(semanticProjection.value, depth, seen, options, valuePath);
2615
+ }
2589
2616
  if (isThenable(value)) {
2590
2617
  return { __type: 'Promise', state: 'pending' };
2591
2618
  }
@@ -2807,6 +2834,7 @@ async function materializePendingTraceEvents(events, params) {
2807
2834
  trace: candidate,
2808
2835
  masking: params.masking,
2809
2836
  privacy: activePrivacy,
2837
+ valueNamespace: params.valueNamespace,
2810
2838
  };
2811
2839
  const traceValueMetadata = {
2812
2840
  fn: evt.fn,
@@ -2828,7 +2856,7 @@ async function materializePendingTraceEvents(events, params) {
2828
2856
  previewValue: evt.args,
2829
2857
  capture: captureContext,
2830
2858
  metadata: traceValueMetadata,
2831
- });
2859
+ }, params.captureScope);
2832
2860
  if (argsValueCapture?.entry) {
2833
2861
  attachTraceValueEntry(evt, argsValueCapture.entry);
2834
2862
  }
@@ -2850,7 +2878,7 @@ async function materializePendingTraceEvents(events, params) {
2850
2878
  previewValue: evt.returnValue,
2851
2879
  capture: captureContext,
2852
2880
  metadata: traceValueMetadata,
2853
- });
2881
+ }, params.captureScope);
2854
2882
  if (returnValueCapture?.entry) {
2855
2883
  attachTraceValueEntry(evt, returnValueCapture.entry);
2856
2884
  }
@@ -2872,7 +2900,7 @@ async function materializePendingTraceEvents(events, params) {
2872
2900
  previewValue: evt.error,
2873
2901
  capture: captureContext,
2874
2902
  metadata: traceValueMetadata,
2875
- });
2903
+ }, params.captureScope);
2876
2904
  if (errorValueCapture?.entry) {
2877
2905
  attachTraceValueEntry(evt, errorValueCapture.entry);
2878
2906
  }
@@ -2886,8 +2914,21 @@ async function materializePendingTraceEvents(events, params) {
2886
2914
  }
2887
2915
  function stripPendingTraceValues(events, reason) {
2888
2916
  for (const evt of events) {
2889
- if (!evt.__reproPending)
2917
+ const pending = evt.__reproPending;
2918
+ if (!pending)
2890
2919
  continue;
2920
+ if (pending.argsRaw !== undefined) {
2921
+ evt.args = makeOmittedValue(reason);
2922
+ evt.argsValueCapture = { status: 'failed-policy' };
2923
+ }
2924
+ if (pending.returnValueRaw !== undefined) {
2925
+ evt.returnValue = makeOmittedValue(reason);
2926
+ evt.returnValueCapture = { status: 'failed-policy' };
2927
+ }
2928
+ if (pending.errorRaw !== undefined) {
2929
+ evt.error = makeOmittedValue(reason);
2930
+ evt.errorValueCapture = { status: 'failed-policy' };
2931
+ }
2891
2932
  delete evt.__reproPending;
2892
2933
  }
2893
2934
  return events;
@@ -2908,6 +2949,7 @@ async function materializePendingTraceEventsAsync(events, params) {
2908
2949
  });
2909
2950
  }
2910
2951
  catch {
2952
+ recordRequestCaptureFailure(params.captureScope ?? getCtx().captureScope, 'privacy.trace', 'trace.values', 'main_thread_materialization_failed');
2911
2953
  return stripPendingTraceValues(events, 'main_thread_failed');
2912
2954
  }
2913
2955
  }
@@ -2915,6 +2957,7 @@ async function materializePendingTraceEventsAsync(events, params) {
2915
2957
  return await materializePendingTraceEventsOffThread(events, {
2916
2958
  events,
2917
2959
  cfg: {
2960
+ tenantId: params.cfg.tenantId,
2918
2961
  appId: params.cfg.appId,
2919
2962
  appSecret: params.cfg.appSecret,
2920
2963
  appName: params.cfg.appName,
@@ -2924,12 +2967,10 @@ async function materializePendingTraceEventsAsync(events, params) {
2924
2967
  masking: params.masking,
2925
2968
  privacy,
2926
2969
  fullValueCaptureEnabled: __FULL_VALUE_CAPTURE_ENABLED,
2970
+ valueNamespace: params.valueNamespace,
2927
2971
  });
2928
2972
  }
2929
2973
  catch (err) {
2930
- if (isTraceMaterializerTimeoutError(err)) {
2931
- return stripPendingTraceValues(events, 'worker_timeout');
2932
- }
2933
2974
  try {
2934
2975
  return await materializePendingTraceEvents(events, {
2935
2976
  ...params,
@@ -2937,7 +2978,10 @@ async function materializePendingTraceEventsAsync(events, params) {
2937
2978
  });
2938
2979
  }
2939
2980
  catch {
2940
- return stripPendingTraceValues(events, 'worker_failed');
2981
+ recordRequestCaptureFailure(params.captureScope ?? getCtx().captureScope, 'privacy.trace', 'trace.values', isTraceMaterializerTimeoutError(err)
2982
+ ? 'worker_timeout_fallback_failed'
2983
+ : 'worker_and_fallback_failed');
2984
+ return stripPendingTraceValues(events, isTraceMaterializerTimeoutError(err) ? 'worker_timeout_fallback_failed' : 'worker_failed');
2941
2985
  }
2942
2986
  }
2943
2987
  }
@@ -2950,6 +2994,7 @@ async function __materializePendingTraceEventsForWorker(payload) {
2950
2994
  maskReq: payload.maskReq,
2951
2995
  masking: payload.masking,
2952
2996
  resolvePrivacy: () => payload.privacy,
2997
+ valueNamespace: payload.valueNamespace,
2953
2998
  });
2954
2999
  return materialized.map((event) => {
2955
3000
  const entries = getEventTraceValueEntries(event);
@@ -3404,7 +3449,7 @@ function limitRawInlinePrivacyValue(target, value) {
3404
3449
  const limited = limitInlinePrivacyValue(target, value);
3405
3450
  return limited.skipped ? limited : null;
3406
3451
  }
3407
- function materializeInlinePrivacyValue(target, value, cfg, req, trace, masking, privacy, db) {
3452
+ function materializeInlinePrivacyValue(target, value, cfg, req, trace, masking, privacy, db, captureScope) {
3408
3453
  if (value === undefined) {
3409
3454
  return { value };
3410
3455
  }
@@ -3416,6 +3461,7 @@ function materializeInlinePrivacyValue(target, value, cfg, req, trace, masking,
3416
3461
  return { value: valueAfterPrivacy };
3417
3462
  }
3418
3463
  catch {
3464
+ recordRequestCaptureFailure(captureScope ?? getCtx().captureScope, 'privacy.inline', target, 'privacy_transform_failed');
3419
3465
  return {
3420
3466
  value: undefined,
3421
3467
  skipped: {
@@ -3426,7 +3472,7 @@ function materializeInlinePrivacyValue(target, value, cfg, req, trace, masking,
3426
3472
  };
3427
3473
  }
3428
3474
  }
3429
- async function materializeInlinePrivacyValueAsync(target, value, cfg, req, trace, masking, privacy, db) {
3475
+ async function materializeInlinePrivacyValueAsync(target, value, cfg, req, trace, masking, privacy, db, captureScope) {
3430
3476
  if (value === undefined) {
3431
3477
  return { value };
3432
3478
  }
@@ -3438,6 +3484,7 @@ async function materializeInlinePrivacyValueAsync(target, value, cfg, req, trace
3438
3484
  return { value: valueAfterPrivacy };
3439
3485
  }
3440
3486
  catch {
3487
+ recordRequestCaptureFailure(captureScope ?? getCtx().captureScope, 'privacy.inline', target, 'privacy_transform_failed');
3441
3488
  return {
3442
3489
  value: undefined,
3443
3490
  skipped: {
@@ -3949,6 +3996,10 @@ function cloneFullValueCandidate(value, ctx, limits, depth = 0, seen = new WeakM
3949
3996
  const mongoPlaceholder = describeMongoPlaceholder(value);
3950
3997
  if (mongoPlaceholder)
3951
3998
  return undefined;
3999
+ const semanticProjection = (0, semantic_serialization_1.projectSemanticInfrastructureValue)(value);
4000
+ if (semanticProjection) {
4001
+ return cloneFullValueCandidate(semanticProjection.value, ctx, limits, depth, seen, valuePath);
4002
+ }
3952
4003
  if (isThenable(value))
3953
4004
  return undefined;
3954
4005
  if (shouldSkipFullValueObject(value))
@@ -4133,6 +4184,10 @@ async function cloneFullValueCandidateAsync(value, ctx, limits, depth = 0, seen
4133
4184
  const mongoPlaceholder = describeMongoPlaceholder(value);
4134
4185
  if (mongoPlaceholder)
4135
4186
  return undefined;
4187
+ const semanticProjection = (0, semantic_serialization_1.projectSemanticInfrastructureValue)(value);
4188
+ if (semanticProjection) {
4189
+ return cloneFullValueCandidateAsync(semanticProjection.value, ctx, limits, depth, seen, valuePath);
4190
+ }
4136
4191
  if (isThenable(value))
4137
4192
  return undefined;
4138
4193
  if (shouldSkipFullValueObject(value))
@@ -4281,13 +4336,16 @@ function getEventTraceValueEntries(event) {
4281
4336
  }
4282
4337
  return undefined;
4283
4338
  }
4284
- function collectBatchTraceValueEntries(batch, batchIndex) {
4339
+ function collectBatchTraceValueEntries(batch, batchIndex, emittedValueIds = new Set()) {
4285
4340
  const collected = [];
4286
4341
  batch.forEach((event, eventIndex) => {
4287
4342
  const entries = getEventTraceValueEntries(event);
4288
4343
  if (!Array.isArray(entries) || !entries.length)
4289
4344
  return;
4290
4345
  entries.forEach((entry) => {
4346
+ if (emittedValueIds.has(entry.id))
4347
+ return;
4348
+ emittedValueIds.add(entry.id);
4291
4349
  collected.push({
4292
4350
  ...entry,
4293
4351
  batchIndex,
@@ -4305,8 +4363,25 @@ function serializedByteLength(value) {
4305
4363
  return Number.MAX_SAFE_INTEGER;
4306
4364
  }
4307
4365
  }
4308
- function estimateTraceBatchSerializedBytes(batch, requestRid, actionId, batchIndex) {
4309
- const traceValues = collectBatchTraceValueEntries(batch, batchIndex);
4366
+ function contentAddressedValueId(target, candidateSerialized, capture) {
4367
+ const config = capture.runtimeConfig;
4368
+ const signingKey = String(config.appSecret ||
4369
+ `${config.tenantId || 'tenant'}:${config.appId || 'app'}`);
4370
+ const namespace = String(capture.valueNamespace ||
4371
+ `${config.tenantId || 'tenant'}:${config.appId || 'app'}`);
4372
+ const digest = (0, crypto_1.createHmac)('sha256', signingKey)
4373
+ .update('repro-captured-value-v1\0')
4374
+ .update(namespace)
4375
+ .update('\0')
4376
+ .update(target)
4377
+ .update('\0')
4378
+ .update(candidateSerialized)
4379
+ .digest('hex')
4380
+ .slice(0, 40);
4381
+ return `rv1_${digest}`;
4382
+ }
4383
+ function estimateTraceBatchSerializedBytes(batch, requestRid, actionId, batchIndex, previouslyEmittedValueIds = new Set()) {
4384
+ const traceValues = collectBatchTraceValueEntries(batch, batchIndex, new Set(previouslyEmittedValueIds));
4310
4385
  return serializedByteLength({
4311
4386
  actionId: actionId ?? null,
4312
4387
  trace: batch,
@@ -4325,19 +4400,32 @@ function chunkTraceEventsForTransport(events, requestRid, actionId) {
4325
4400
  const boundedEvents = boundTraceEventsForTransport(events);
4326
4401
  const countBatches = chunkArray(boundedEvents, TRACE_BATCH_SIZE);
4327
4402
  const sizedBatches = [];
4403
+ const emittedValueIds = new Set();
4328
4404
  let current = [];
4405
+ const commitCurrent = () => {
4406
+ if (!current.length)
4407
+ return;
4408
+ collectBatchTraceValueEntries(current, sizedBatches.length, emittedValueIds);
4409
+ sizedBatches.push(current);
4410
+ current = [];
4411
+ };
4329
4412
  for (const event of countBatches.flat()) {
4330
4413
  if (sizedBatches.length >= TRACE_MAX_BATCHES_PER_REQUEST) {
4331
4414
  break;
4332
4415
  }
4416
+ if (current.length >= TRACE_BATCH_SIZE) {
4417
+ commitCurrent();
4418
+ if (sizedBatches.length >= TRACE_MAX_BATCHES_PER_REQUEST) {
4419
+ break;
4420
+ }
4421
+ }
4333
4422
  const candidate = current.concat(event);
4334
4423
  const batchIndex = sizedBatches.length;
4335
- const estimatedBytes = estimateTraceBatchSerializedBytes(candidate, requestRid, actionId, batchIndex);
4424
+ const estimatedBytes = estimateTraceBatchSerializedBytes(candidate, requestRid, actionId, batchIndex, emittedValueIds);
4336
4425
  if (current.length > 0 &&
4337
4426
  estimatedBytes > TRACE_BATCH_MAX_SERIALIZED_BYTES) {
4338
- sizedBatches.push(current);
4427
+ commitCurrent();
4339
4428
  if (sizedBatches.length >= TRACE_MAX_BATCHES_PER_REQUEST) {
4340
- current = [];
4341
4429
  break;
4342
4430
  }
4343
4431
  current = [event];
@@ -4347,7 +4435,7 @@ function chunkTraceEventsForTransport(events, requestRid, actionId) {
4347
4435
  }
4348
4436
  if (current.length > 0 &&
4349
4437
  sizedBatches.length < TRACE_MAX_BATCHES_PER_REQUEST) {
4350
- sizedBatches.push(current);
4438
+ commitCurrent();
4351
4439
  }
4352
4440
  return sizedBatches;
4353
4441
  }
@@ -4384,7 +4472,7 @@ function createCapturedValueEntry(params) {
4384
4472
  if (!candidateSerialized || candidateSerialized === previewSerialized) {
4385
4473
  return undefined;
4386
4474
  }
4387
- const valueId = (0, crypto_1.randomUUID)();
4475
+ const valueId = contentAddressedValueId(params.target, candidateSerialized, params.capture);
4388
4476
  const projectedKind = candidate && typeof candidate === 'object'
4389
4477
  ? (candidate.__kind || candidate.__type)
4390
4478
  : undefined;
@@ -4431,7 +4519,7 @@ async function createCapturedValueEntryAsync(params) {
4431
4519
  if (!candidateSerialized || candidateSerialized === previewSerialized) {
4432
4520
  return undefined;
4433
4521
  }
4434
- const valueId = (0, crypto_1.randomUUID)();
4522
+ const valueId = contentAddressedValueId(params.target, candidateSerialized, params.capture);
4435
4523
  const projectedKind = candidate && typeof candidate === 'object'
4436
4524
  ? (candidate.__kind || candidate.__type)
4437
4525
  : undefined;
@@ -4452,46 +4540,67 @@ async function createCapturedValueEntryAsync(params) {
4452
4540
  entry,
4453
4541
  };
4454
4542
  }
4543
+ function appendCapturedValueDefinition(sink, entry, captureScope) {
4544
+ if (!entry)
4545
+ return;
4546
+ const emitted = captureScope?.emittedValueDefinitionIds;
4547
+ if (emitted?.has(entry.id))
4548
+ return;
4549
+ emitted?.add(entry.id);
4550
+ sink.push(entry);
4551
+ }
4455
4552
  function maybeCaptureRequestValue(params, sink) {
4456
4553
  const result = createCapturedValueEntry(params);
4457
4554
  if (!result)
4458
4555
  return undefined;
4459
- if (result.entry) {
4460
- sink.push(result.entry);
4461
- }
4556
+ appendCapturedValueDefinition(sink, result.entry);
4462
4557
  return result.captureRef;
4463
4558
  }
4464
- async function maybeCaptureRequestValueAsync(params, sink) {
4465
- const result = await createCapturedValueEntryAsync(params);
4559
+ async function maybeCaptureRequestValueAsync(params, sink, captureScope) {
4560
+ let result;
4561
+ try {
4562
+ result = await createCapturedValueEntryAsync(params);
4563
+ }
4564
+ catch {
4565
+ recordRequestCaptureFailure(captureScope ?? getCtx().captureScope, 'privacy.full_value', params.target, 'privacy_transform_failed');
4566
+ return { status: 'failed-policy' };
4567
+ }
4466
4568
  if (!result)
4467
4569
  return undefined;
4468
- if (result.entry) {
4469
- sink.push(result.entry);
4470
- }
4570
+ appendCapturedValueDefinition(sink, result.entry, captureScope);
4471
4571
  return result.captureRef;
4472
4572
  }
4473
4573
  function maybeCaptureTraceValue(params) {
4474
4574
  return createCapturedValueEntry(params);
4475
4575
  }
4476
- async function maybeCaptureTraceValueAsync(params) {
4477
- return await createCapturedValueEntryAsync(params);
4576
+ async function maybeCaptureTraceValueAsync(params, captureScope) {
4577
+ try {
4578
+ return await createCapturedValueEntryAsync(params);
4579
+ }
4580
+ catch {
4581
+ recordRequestCaptureFailure(captureScope ?? getCtx().captureScope, 'privacy.full_value', params.target, 'privacy_transform_failed');
4582
+ return { captureRef: { status: 'failed-policy' } };
4583
+ }
4478
4584
  }
4479
4585
  function maybeCaptureDbValue(params, sink) {
4480
4586
  const result = createCapturedValueEntry(params);
4481
4587
  if (!result)
4482
4588
  return undefined;
4483
- if (result.entry) {
4484
- sink.push(result.entry);
4485
- }
4589
+ appendCapturedValueDefinition(sink, result.entry);
4486
4590
  return result.captureRef;
4487
4591
  }
4488
- async function maybeCaptureDbValueAsync(params, sink) {
4489
- const result = await createCapturedValueEntryAsync(params);
4592
+ async function maybeCaptureDbValueAsync(params, sink, captureScope) {
4593
+ let result;
4594
+ try {
4595
+ result = await createCapturedValueEntryAsync(params);
4596
+ }
4597
+ catch {
4598
+ recordRequestCaptureFailure(captureScope ?? getCtx().captureScope, 'privacy.full_value', params.target, 'privacy_transform_failed');
4599
+ return { status: 'failed-policy' };
4600
+ }
4490
4601
  if (!result)
4491
4602
  return undefined;
4492
- if (result.entry) {
4493
- sink.push(result.entry);
4494
- }
4603
+ appendCapturedValueDefinition(sink, result.entry, captureScope);
4495
4604
  return result.captureRef;
4496
4605
  }
4497
4606
  function pushUniqueCaptureCandidate(candidates, value) {
@@ -4512,19 +4621,26 @@ function buildResultMetaFullValueCandidates(resultMetaRaw, resultMetaSource) {
4512
4621
  pushUniqueCaptureCandidate(candidates, resultMetaSource);
4513
4622
  return candidates;
4514
4623
  }
4515
- async function maybeCaptureDbValueFromCandidatesAsync(params, sink) {
4624
+ async function maybeCaptureDbValueFromCandidatesAsync(params, sink, captureScope) {
4516
4625
  let skippedRef;
4517
4626
  for (const rawValue of params.rawValues) {
4518
- const result = await createCapturedValueEntryAsync({
4519
- target: params.target,
4520
- rawValue,
4521
- previewValue: params.previewValue,
4522
- capture: params.capture,
4523
- });
4627
+ let result;
4628
+ try {
4629
+ result = await createCapturedValueEntryAsync({
4630
+ target: params.target,
4631
+ rawValue,
4632
+ previewValue: params.previewValue,
4633
+ capture: params.capture,
4634
+ });
4635
+ }
4636
+ catch {
4637
+ recordRequestCaptureFailure(captureScope ?? getCtx().captureScope, 'privacy.full_value', params.target, 'privacy_transform_failed');
4638
+ return { status: 'failed-policy' };
4639
+ }
4524
4640
  if (!result)
4525
4641
  continue;
4526
4642
  if (result.entry) {
4527
- sink.push(result.entry);
4643
+ appendCapturedValueDefinition(sink, result.entry, captureScope);
4528
4644
  return result.captureRef;
4529
4645
  }
4530
4646
  if (!skippedRef) {
@@ -4690,7 +4806,7 @@ function reproMiddleware(cfg) {
4690
4806
  const resolvePrivacy = () => getRuntimePrivacyState(captureCfg).policy ?? null;
4691
4807
  const clockSkewMs = headerTs !== null ? headerTs - requestStartRaw : 0;
4692
4808
  const rid = nextRequestId(requestEpochMs);
4693
- const captureScope = createRequestCaptureScope(rid, 'http');
4809
+ const captureScope = createRequestCaptureScope(rid, 'http', captureCfg);
4694
4810
  emitRequestCaptureStart(captureCfg, sid, aid, captureScope, requestEpochMs);
4695
4811
  const t0 = requestStartRaw;
4696
4812
  const url = req.originalUrl || req.url || '/';
@@ -4893,15 +5009,18 @@ function reproMiddleware(cfg) {
4893
5009
  const activePrivacy = resolvePrivacy();
4894
5010
  const requestBodyRaw = req.body;
4895
5011
  const requestBodyMaterialization = limitRawInlinePrivacyValue('request.body', requestBodyRaw)
4896
- ?? await materializeInlinePrivacyValueAsync('request.body', sanitizeRequestSnapshot(requestBodyRaw), captureCfg, maskReq, endpointTraceCtx, masking, activePrivacy);
5012
+ ?? await materializeInlinePrivacyValueAsync('request.body', sanitizeRequestSnapshot(requestBodyRaw), captureCfg, maskReq, endpointTraceCtx, masking, activePrivacy, undefined, captureScope);
4897
5013
  const requestBody = requestBodyMaterialization.value;
4898
- const requestParams = await applyPrivacyThenMaskAsync('request.params', sanitizeRequestSnapshot(req.params), captureCfg, maskReq, endpointTraceCtx, masking, activePrivacy);
4899
- const requestQuery = await applyPrivacyThenMaskAsync('request.query', sanitizeRequestSnapshot(req.query), captureCfg, maskReq, endpointTraceCtx, masking, activePrivacy);
4900
- const maskedHeaders = await applyPrivacyThenMaskAsync('request.headers', requestHeaders, captureCfg, maskReq, endpointTraceCtx, masking, activePrivacy);
5014
+ const requestParamsMaterialization = await materializeInlinePrivacyValueAsync('request.params', sanitizeRequestSnapshot(req.params), captureCfg, maskReq, endpointTraceCtx, masking, activePrivacy, undefined, captureScope);
5015
+ const requestParams = requestParamsMaterialization.value;
5016
+ const requestQueryMaterialization = await materializeInlinePrivacyValueAsync('request.query', sanitizeRequestSnapshot(req.query), captureCfg, maskReq, endpointTraceCtx, masking, activePrivacy, undefined, captureScope);
5017
+ const requestQuery = requestQueryMaterialization.value;
5018
+ const requestHeadersMaterialization = await materializeInlinePrivacyValueAsync('request.headers', requestHeaders, captureCfg, maskReq, endpointTraceCtx, masking, activePrivacy, undefined, captureScope);
5019
+ const maskedHeaders = requestHeadersMaterialization.value;
4901
5020
  const responseBodyMaterialization = capturedBody === undefined
4902
5021
  ? { value: undefined }
4903
5022
  : limitRawInlinePrivacyValue('response.body', capturedBody)
4904
- ?? await materializeInlinePrivacyValueAsync('response.body', sanitizeRequestSnapshot(capturedBody), captureCfg, maskReq, endpointTraceCtx, masking, activePrivacy);
5023
+ ?? await materializeInlinePrivacyValueAsync('response.body', sanitizeRequestSnapshot(capturedBody), captureCfg, maskReq, endpointTraceCtx, masking, activePrivacy, undefined, captureScope);
4905
5024
  const responseBody = responseBodyMaterialization.value;
4906
5025
  const requestValueEntries = [];
4907
5026
  const bodyValueCapture = requestBodyRaw === undefined
@@ -4917,8 +5036,9 @@ function reproMiddleware(cfg) {
4917
5036
  trace: endpointTraceCtx,
4918
5037
  masking,
4919
5038
  privacy: activePrivacy,
5039
+ valueNamespace: sid,
4920
5040
  },
4921
- }, requestValueEntries);
5041
+ }, requestValueEntries, captureScope);
4922
5042
  const paramsValueCapture = await maybeCaptureRequestValueAsync({
4923
5043
  target: 'request.params',
4924
5044
  rawValue: req.params,
@@ -4930,8 +5050,9 @@ function reproMiddleware(cfg) {
4930
5050
  trace: endpointTraceCtx,
4931
5051
  masking,
4932
5052
  privacy: activePrivacy,
5053
+ valueNamespace: sid,
4933
5054
  },
4934
- }, requestValueEntries);
5055
+ }, requestValueEntries, captureScope);
4935
5056
  const queryValueCapture = await maybeCaptureRequestValueAsync({
4936
5057
  target: 'request.query',
4937
5058
  rawValue: req.query,
@@ -4943,8 +5064,9 @@ function reproMiddleware(cfg) {
4943
5064
  trace: endpointTraceCtx,
4944
5065
  masking,
4945
5066
  privacy: activePrivacy,
5067
+ valueNamespace: sid,
4946
5068
  },
4947
- }, requestValueEntries);
5069
+ }, requestValueEntries, captureScope);
4948
5070
  const headersValueCapture = await maybeCaptureRequestValueAsync({
4949
5071
  target: 'request.headers',
4950
5072
  rawValue: req.headers,
@@ -4956,8 +5078,9 @@ function reproMiddleware(cfg) {
4956
5078
  trace: endpointTraceCtx,
4957
5079
  masking,
4958
5080
  privacy: activePrivacy,
5081
+ valueNamespace: sid,
4959
5082
  },
4960
- }, requestValueEntries);
5083
+ }, requestValueEntries, captureScope);
4961
5084
  const respBodyValueCapture = capturedBody === undefined
4962
5085
  ? undefined
4963
5086
  : await maybeCaptureRequestValueAsync({
@@ -4971,8 +5094,9 @@ function reproMiddleware(cfg) {
4971
5094
  trace: endpointTraceCtx,
4972
5095
  masking,
4973
5096
  privacy: activePrivacy,
5097
+ valueNamespace: sid,
4974
5098
  },
4975
- }, requestValueEntries);
5099
+ }, requestValueEntries, captureScope);
4976
5100
  const responseDurationMs = finishedAt !== null && Number.isFinite(finishedAt)
4977
5101
  ? Math.max(0, finishedAt - t0)
4978
5102
  : Date.now() - t0;
@@ -5034,10 +5158,38 @@ function reproMiddleware(cfg) {
5034
5158
  t: requestEpochMs,
5035
5159
  }]
5036
5160
  });
5037
- captureScope.backendRequestCount += 1;
5038
5161
  }
5039
5162
  catch {
5040
- // never break user code
5163
+ recordRequestCaptureFailure(captureScope, 'request.capture', 'backend_request', 'request_materialization_failed');
5164
+ // Preserve non-sensitive request metadata so the manifest cannot
5165
+ // silently turn a failed policy capture into a zero-request scope.
5166
+ post(captureCfg, sid, {
5167
+ entries: [{
5168
+ actionId: aid,
5169
+ request: {
5170
+ rid,
5171
+ method: req.method,
5172
+ url,
5173
+ path,
5174
+ status: res.statusCode,
5175
+ durMs: finishedAt !== null && Number.isFinite(finishedAt)
5176
+ ? Math.max(0, finishedAt - t0)
5177
+ : Date.now() - t0,
5178
+ key,
5179
+ bodyMaterialization: {
5180
+ status: 'skipped',
5181
+ reason: 'request_materialization_failed',
5182
+ target: 'request.body',
5183
+ },
5184
+ respBodyMaterialization: {
5185
+ status: 'skipped',
5186
+ reason: 'request_materialization_failed',
5187
+ target: 'response.body',
5188
+ },
5189
+ },
5190
+ t: requestEpochMs,
5191
+ }],
5192
+ });
5041
5193
  }
5042
5194
  };
5043
5195
  const emitRequestCaptureManifest = (traceBatchTotal) => {
@@ -5151,6 +5303,8 @@ function reproMiddleware(cfg) {
5151
5303
  maskReq,
5152
5304
  masking,
5153
5305
  resolvePrivacy,
5306
+ captureScope,
5307
+ valueNamespace: sid,
5154
5308
  });
5155
5309
  const baseEvents = balanceTraceEvents(materializedEvents.slice());
5156
5310
  const orderedEvents = TRACE_ORDER_MODE === 'tree'
@@ -5165,16 +5319,19 @@ function reproMiddleware(cfg) {
5165
5319
  }
5166
5320
  }
5167
5321
  catch {
5322
+ recordRequestCaptureFailure(captureScope, 'trace.capture', 'trace.batches', 'trace_capture_failed');
5168
5323
  captureScope.traceBatchCount = 0;
5169
5324
  traceBatches = [];
5170
5325
  }
5171
- finally {
5172
- emitRequestCaptureManifest(traceBatches.length);
5173
- }
5326
+ // Finalize policy/materialization status before publishing the
5327
+ // high-priority manifest. The manifest must lead its evidence
5328
+ // on the wire so a large trace queue cannot starve completion.
5329
+ emitRequestCaptureManifest(traceBatches.length);
5174
5330
  try {
5331
+ const emittedValueIds = new Set();
5175
5332
  for (let i = 0; i < traceBatches.length; i++) {
5176
5333
  const batch = traceBatches[i];
5177
- const traceValues = collectBatchTraceValueEntries(batch, i);
5334
+ const traceValues = collectBatchTraceValueEntries(batch, i, emittedValueIds);
5178
5335
  post(captureCfg, sid, {
5179
5336
  entries: [{
5180
5337
  actionId: aid,
@@ -5191,7 +5348,7 @@ function reproMiddleware(cfg) {
5191
5348
  }
5192
5349
  }
5193
5350
  catch {
5194
- // never break user code
5351
+ recordRequestCaptureFailure(captureScope, 'trace.enqueue', 'trace.batches', 'trace_enqueue_failed');
5195
5352
  }
5196
5353
  };
5197
5354
  }
@@ -5745,12 +5902,6 @@ function dehydrateComplexValue(value) {
5745
5902
  }
5746
5903
  }
5747
5904
  catch { }
5748
- const ctor = value?.constructor?.name;
5749
- if (ctor && ctor !== 'Object') {
5750
- const plain = safeJson(value);
5751
- if (plain !== undefined)
5752
- return plain;
5753
- }
5754
5905
  return value;
5755
5906
  }
5756
5907
  function emitDbQuery(cfg, sid, aid, payload) {
@@ -5758,6 +5909,11 @@ function emitDbQuery(cfg, sid, aid, payload) {
5758
5909
  const spanContext = payload?.spanContext ?? captureSpanContextFromTracer();
5759
5910
  if (!shouldCaptureDbSpan(spanContext))
5760
5911
  return;
5912
+ if (sid && ctx.captureScope) {
5913
+ // Count the observed database operation before asynchronous privacy
5914
+ // materialization. A later failure must remain visible to completeness.
5915
+ ctx.captureScope.dbChangeCount += 1;
5916
+ }
5761
5917
  const runCtx = {
5762
5918
  sid: ctx.sid,
5763
5919
  aid: ctx.aid,
@@ -5769,7 +5925,9 @@ function emitDbQuery(cfg, sid, aid, payload) {
5769
5925
  };
5770
5926
  scheduleSdkBackgroundWork(async () => {
5771
5927
  await als.run(runCtx, async () => {
5772
- await emitDbQueryAsync(cfg, sid, aid, payload).catch(() => undefined);
5928
+ await emitDbQueryAsync(cfg, sid, aid, payload).catch(() => {
5929
+ recordRequestCaptureFailure(runCtx.captureScope, 'db.capture', 'db.change', 'db_capture_failed');
5930
+ });
5773
5931
  });
5774
5932
  }, { priority: 'high' });
5775
5933
  }
@@ -5814,6 +5972,7 @@ async function emitDbQueryAsync(cfg, sid, aid, payload) {
5814
5972
  masking: null,
5815
5973
  privacy,
5816
5974
  db: dbContext,
5975
+ valueNamespace: sid,
5817
5976
  };
5818
5977
  const dbValues = [];
5819
5978
  const pkValueCapture = pkMaterialization.skipped ? undefined : await maybeCaptureDbValueAsync({
@@ -5821,37 +5980,37 @@ async function emitDbQueryAsync(cfg, sid, aid, payload) {
5821
5980
  rawValue: payload.pk,
5822
5981
  previewValue: pkPreview,
5823
5982
  capture,
5824
- }, dbValues);
5983
+ }, dbValues, ctx.captureScope);
5825
5984
  const beforeValueCapture = beforeMaterialization.skipped ? undefined : await maybeCaptureDbValueAsync({
5826
5985
  target: 'db.before',
5827
5986
  rawValue: payload.before,
5828
5987
  previewValue: beforePreview,
5829
5988
  capture,
5830
- }, dbValues);
5989
+ }, dbValues, ctx.captureScope);
5831
5990
  const afterValueCapture = afterMaterialization.skipped ? undefined : await maybeCaptureDbValueAsync({
5832
5991
  target: 'db.after',
5833
5992
  rawValue: payload.after,
5834
5993
  previewValue: afterPreview,
5835
5994
  capture,
5836
- }, dbValues);
5995
+ }, dbValues, ctx.captureScope);
5837
5996
  const queryValueCapture = queryMaterialization.skipped ? undefined : await maybeCaptureDbValueAsync({
5838
5997
  target: 'db.query',
5839
5998
  rawValue: querySource,
5840
5999
  previewValue: queryPreview,
5841
6000
  capture,
5842
- }, dbValues);
6001
+ }, dbValues, ctx.captureScope);
5843
6002
  const resultMetaValueCapture = resultMetaMaterialization.skipped ? undefined : await maybeCaptureDbValueFromCandidatesAsync({
5844
6003
  target: 'db.resultMeta',
5845
6004
  rawValues: buildResultMetaFullValueCandidates(payload.resultMetaRaw, resultMetaSource),
5846
6005
  previewValue: resultMetaPreview,
5847
6006
  capture,
5848
- }, dbValues);
6007
+ }, dbValues, ctx.captureScope);
5849
6008
  const errorValueCapture = errorMaterialization.skipped ? undefined : await maybeCaptureDbValueAsync({
5850
6009
  target: 'db.error',
5851
6010
  rawValue: payload.error,
5852
6011
  previewValue: errorPreview,
5853
6012
  capture,
5854
- }, dbValues);
6013
+ }, dbValues, ctx.captureScope);
5855
6014
  const dbEntry = attachSpanContext({
5856
6015
  type: payload.type ?? 'mongo',
5857
6016
  collection: payload.collection,
@@ -5885,8 +6044,8 @@ async function emitDbQueryAsync(cfg, sid, aid, payload) {
5885
6044
  t: payload.t,
5886
6045
  }]
5887
6046
  });
5888
- if (enqueued && ctx.captureScope) {
5889
- ctx.captureScope.dbChangeCount += 1;
6047
+ if (!enqueued) {
6048
+ recordRequestCaptureFailure(ctx.captureScope, 'db.enqueue', 'db.change', 'db_enqueue_failed');
5890
6049
  }
5891
6050
  }
5892
6051
  function buildMinimalUpdate(before, after) {
@@ -6293,8 +6452,8 @@ function cloneKafkaTelemetryValue(value) {
6293
6452
  return value;
6294
6453
  }
6295
6454
  }
6296
- async function materializeKafkaRequestBody(cfg, maskReq, body) {
6297
- return materializeInlinePrivacyValueAsync('request.body', sanitizeInlinePrivacyValue(body), cfg, maskReq, null, normalizeMaskingConfig(cfg.masking), getRuntimePrivacyState(cfg).policy ?? null);
6455
+ async function materializeKafkaRequestBody(cfg, maskReq, body, captureScope) {
6456
+ return materializeInlinePrivacyValueAsync('request.body', sanitizeInlinePrivacyValue(body), cfg, maskReq, null, normalizeMaskingConfig(cfg.masking), getRuntimePrivacyState(cfg).policy ?? null, undefined, captureScope);
6298
6457
  }
6299
6458
  function summarizeKafkaError(error) {
6300
6459
  const message = typeof error?.message === 'string'
@@ -6393,6 +6552,7 @@ function recordKafkaTraceEvent(raw, sink, cfg, maskReq) {
6393
6552
  trace: candidate,
6394
6553
  masking,
6395
6554
  privacy,
6555
+ valueNamespace: getCtx().sid,
6396
6556
  };
6397
6557
  const traceValueMetadata = {
6398
6558
  fn: evt.fn,
@@ -6530,6 +6690,7 @@ async function recordKafkaTraceEventAsync(raw, sink, cfg, maskReq) {
6530
6690
  maskReq,
6531
6691
  masking,
6532
6692
  resolvePrivacy: () => getRuntimePrivacyState(cfg).policy ?? null,
6693
+ valueNamespace: getCtx().sid,
6533
6694
  });
6534
6695
  sink.push(...materializedEvents);
6535
6696
  }
@@ -6541,10 +6702,11 @@ function buildKafkaTraceEntries(actionId, requestRid, events) {
6541
6702
  ? reorderTraceEvents(baseEvents)
6542
6703
  : sortTraceEventsChronologically(baseEvents);
6543
6704
  const batches = chunkTraceEventsForTransport(orderedEvents, requestRid, actionId);
6705
+ const emittedValueIds = new Set();
6544
6706
  return batches.map((batch, index) => ({
6545
6707
  actionId: actionId ?? null,
6546
6708
  trace: batch,
6547
- traceValues: collectBatchTraceValueEntries(batch, index),
6709
+ traceValues: collectBatchTraceValueEntries(batch, index, emittedValueIds),
6548
6710
  traceBatch: {
6549
6711
  rid: requestRid,
6550
6712
  index,
@@ -6567,23 +6729,28 @@ function scheduleKafkaTraceFlush(cfg, kafkaCtx, actionId, requestRid, rawTraceEv
6567
6729
  if (evt)
6568
6730
  pendingEvents.push(evt);
6569
6731
  }
6570
- if (!pendingEvents.length)
6571
- return;
6572
- const masking = normalizeMaskingConfig(cfg.masking);
6573
- const preparedEvents = preparePendingTraceEventsForFlush(pendingEvents);
6574
- const materializedEvents = await materializePendingTraceEventsAsync(preparedEvents, {
6575
- cfg,
6576
- maskReq,
6577
- masking,
6578
- resolvePrivacy: () => getRuntimePrivacyState(cfg).policy ?? null,
6579
- });
6580
- const entries = buildKafkaTraceEntries(actionId, requestRid, materializedEvents);
6732
+ let entries = [];
6733
+ try {
6734
+ if (pendingEvents.length) {
6735
+ const masking = normalizeMaskingConfig(cfg.masking);
6736
+ const preparedEvents = preparePendingTraceEventsForFlush(pendingEvents);
6737
+ const materializedEvents = await materializePendingTraceEventsAsync(preparedEvents, {
6738
+ cfg,
6739
+ maskReq,
6740
+ masking,
6741
+ resolvePrivacy: () => getRuntimePrivacyState(cfg).policy ?? null,
6742
+ captureScope,
6743
+ valueNamespace: sid,
6744
+ });
6745
+ entries = buildKafkaTraceEntries(actionId, requestRid, materializedEvents);
6746
+ }
6747
+ }
6748
+ catch {
6749
+ recordRequestCaptureFailure(captureScope, 'trace.capture', 'trace.batches', 'trace_capture_failed');
6750
+ }
6581
6751
  if (captureScope) {
6582
6752
  captureScope.traceBatchCount = entries.length;
6583
6753
  }
6584
- if (entries.length) {
6585
- post(cfg, sid, { entries });
6586
- }
6587
6754
  if (captureScope) {
6588
6755
  post(cfg, sid, {
6589
6756
  entries: [{
@@ -6592,7 +6759,10 @@ function scheduleKafkaTraceFlush(cfg, kafkaCtx, actionId, requestRid, rawTraceEv
6592
6759
  requestCaptureManifest: buildRequestCaptureManifestPayload(captureScope, entries.length),
6593
6760
  t: alignedNow(),
6594
6761
  }],
6595
- });
6762
+ }, { priority: 'high' });
6763
+ }
6764
+ if (entries.length) {
6765
+ post(cfg, sid, { entries });
6596
6766
  }
6597
6767
  });
6598
6768
  }, { priority: 'high' });
@@ -6610,7 +6780,7 @@ function patchKafkaProducerInstance(producer, cfg) {
6610
6780
  const aid = ctx.aid ?? fallback.aid ?? null;
6611
6781
  const span = captureSpanContextFromTracer();
6612
6782
  const publishRid = nextRequestId(alignedNow());
6613
- const captureScope = createRequestCaptureScope(publishRid, 'kafka');
6783
+ const captureScope = createRequestCaptureScope(publishRid, 'kafka', cfg);
6614
6784
  emitRequestCaptureStart(cfg, sid, aid, captureScope);
6615
6785
  const payloadObj = payload && typeof payload === 'object' ? payload : {};
6616
6786
  const topic = sanitizeKafkaTopic(payloadObj.topic);
@@ -6669,7 +6839,7 @@ function patchKafkaProducerInstance(producer, cfg) {
6669
6839
  traceId: span?.traceId ?? null,
6670
6840
  spanId: span?.spanId ?? null,
6671
6841
  parentSpanId: span?.parentSpanId ?? null,
6672
- });
6842
+ }, captureScope);
6673
6843
  const requestPayload = {
6674
6844
  rid: publishRid,
6675
6845
  method: 'KAFKA_PUBLISH',
@@ -6698,7 +6868,6 @@ function patchKafkaProducerInstance(producer, cfg) {
6698
6868
  },
6699
6869
  ],
6700
6870
  });
6701
- captureScope.backendRequestCount += 1;
6702
6871
  post(cfg, sid, {
6703
6872
  entries: [{
6704
6873
  actionId: aid ?? null,
@@ -6719,7 +6888,7 @@ function patchKafkaProducerInstance(producer, cfg) {
6719
6888
  const aid = ctx.aid ?? fallback.aid ?? null;
6720
6889
  const span = captureSpanContextFromTracer();
6721
6890
  const publishRid = nextRequestId(alignedNow());
6722
- const captureScope = createRequestCaptureScope(publishRid, 'kafka');
6891
+ const captureScope = createRequestCaptureScope(publishRid, 'kafka', cfg);
6723
6892
  emitRequestCaptureStart(cfg, sid, aid, captureScope);
6724
6893
  const payloadObj = payload && typeof payload === 'object' ? payload : {};
6725
6894
  const topicMessages = Array.isArray(payloadObj.topicMessages)
@@ -6809,7 +6978,7 @@ function patchKafkaProducerInstance(producer, cfg) {
6809
6978
  traceId: span?.traceId ?? null,
6810
6979
  spanId: span?.spanId ?? null,
6811
6980
  parentSpanId: span?.parentSpanId ?? null,
6812
- });
6981
+ }, captureScope);
6813
6982
  const requestPayload = {
6814
6983
  rid: publishRid,
6815
6984
  method: 'KAFKA_PUBLISH_BATCH',
@@ -6838,7 +7007,6 @@ function patchKafkaProducerInstance(producer, cfg) {
6838
7007
  },
6839
7008
  ],
6840
7009
  });
6841
- captureScope.backendRequestCount += 1;
6842
7010
  post(cfg, sid, {
6843
7011
  entries: [{
6844
7012
  actionId: aid ?? null,
@@ -6861,7 +7029,7 @@ function wrapKafkaEachMessageHandler(eachMessage, cfg, consumer) {
6861
7029
  const aid = runtime.aid;
6862
7030
  const consumeRid = nextRequestId(`${topic}-${message?.offset ?? alignedNow()}`);
6863
7031
  const traceId = consumeRid;
6864
- const captureScope = createRequestCaptureScope(consumeRid, 'kafka');
7032
+ const captureScope = createRequestCaptureScope(consumeRid, 'kafka', cfg);
6865
7033
  emitRequestCaptureStart(cfg, sid, aid, captureScope);
6866
7034
  const rawTraceEvents = [];
6867
7035
  const maskReq = {
@@ -6939,7 +7107,7 @@ function wrapKafkaEachMessageHandler(eachMessage, cfg, consumer) {
6939
7107
  valueEncoding: messagePayload.valueEncoding,
6940
7108
  valueBytes: messagePayload.valueBytes,
6941
7109
  message: messagePayload,
6942
- });
7110
+ }, captureScope);
6943
7111
  const requestPayload = {
6944
7112
  rid: consumeRid,
6945
7113
  method: 'KAFKA_CONSUME',
@@ -6960,7 +7128,6 @@ function wrapKafkaEachMessageHandler(eachMessage, cfg, consumer) {
6960
7128
  t: alignedNow(),
6961
7129
  }],
6962
7130
  });
6963
- captureScope.backendRequestCount += 1;
6964
7131
  scheduleKafkaTraceFlush(cfg, kafkaCtx, aid, consumeRid, rawTraceEvents, maskReq, captureScope);
6965
7132
  }
6966
7133
  };
@@ -6976,7 +7143,7 @@ function wrapKafkaEachBatchHandler(eachBatch, cfg, consumer) {
6976
7143
  const aid = runtime.aid;
6977
7144
  const consumeRid = nextRequestId(`${topic}-batch-${alignedNow()}`);
6978
7145
  const traceId = consumeRid;
6979
- const captureScope = createRequestCaptureScope(consumeRid, 'kafka');
7146
+ const captureScope = createRequestCaptureScope(consumeRid, 'kafka', cfg);
6980
7147
  emitRequestCaptureStart(cfg, sid, aid, captureScope);
6981
7148
  const rawTraceEvents = [];
6982
7149
  const maskReq = {
@@ -7052,7 +7219,7 @@ function wrapKafkaEachBatchHandler(eachBatch, cfg, consumer) {
7052
7219
  parentSpanId: runtime.parentSpanId,
7053
7220
  firstMessageKey: firstMessagePayload?.key ?? null,
7054
7221
  messages: messages.map((message) => buildKafkaMessagePayload(message)),
7055
- });
7222
+ }, captureScope);
7056
7223
  const requestPayload = {
7057
7224
  rid: consumeRid,
7058
7225
  method: 'KAFKA_CONSUME_BATCH',
@@ -7073,7 +7240,6 @@ function wrapKafkaEachBatchHandler(eachBatch, cfg, consumer) {
7073
7240
  t: alignedNow(),
7074
7241
  }],
7075
7242
  });
7076
- captureScope.backendRequestCount += 1;
7077
7243
  scheduleKafkaTraceFlush(cfg, kafkaCtx, aid, consumeRid, rawTraceEvents, maskReq, captureScope);
7078
7244
  }
7079
7245
  };
@@ -7453,24 +7619,24 @@ function scheduleAmqpTraceFlush(cfg, amqpCtx, actionId, requestRid, rawTraceEven
7453
7619
  pendingEvents.push(evt);
7454
7620
  }
7455
7621
  let entries = [];
7456
- if (pendingEvents.length) {
7457
- const masking = normalizeMaskingConfig(cfg.masking);
7458
- const preparedEvents = preparePendingTraceEventsForFlush(pendingEvents);
7459
- const materializedEvents = await materializePendingTraceEventsAsync(preparedEvents, {
7460
- cfg,
7461
- maskReq,
7462
- masking,
7463
- resolvePrivacy: () => getRuntimePrivacyState(cfg).policy ?? null,
7464
- });
7465
- entries = buildAmqpTraceEntries(actionId, requestRid, materializedEvents);
7466
- captureScope.traceBatchCount = entries.length;
7467
- if (entries.length) {
7468
- post(cfg, sid, { entries });
7622
+ try {
7623
+ if (pendingEvents.length) {
7624
+ const masking = normalizeMaskingConfig(cfg.masking);
7625
+ const preparedEvents = preparePendingTraceEventsForFlush(pendingEvents);
7626
+ const materializedEvents = await materializePendingTraceEventsAsync(preparedEvents, {
7627
+ cfg,
7628
+ maskReq,
7629
+ masking,
7630
+ resolvePrivacy: () => getRuntimePrivacyState(cfg).policy ?? null,
7631
+ captureScope,
7632
+ });
7633
+ entries = buildAmqpTraceEntries(actionId, requestRid, materializedEvents);
7469
7634
  }
7470
7635
  }
7471
- else {
7472
- captureScope.traceBatchCount = 0;
7636
+ catch {
7637
+ recordRequestCaptureFailure(captureScope, 'trace.capture', 'trace.batches', 'trace_capture_failed');
7473
7638
  }
7639
+ captureScope.traceBatchCount = entries.length;
7474
7640
  post(cfg, sid, {
7475
7641
  entries: [{
7476
7642
  actionId: actionId ?? null,
@@ -7478,7 +7644,10 @@ function scheduleAmqpTraceFlush(cfg, amqpCtx, actionId, requestRid, rawTraceEven
7478
7644
  requestCaptureManifest: buildRequestCaptureManifestPayload(captureScope, entries.length),
7479
7645
  t: alignedNow(),
7480
7646
  }],
7481
- });
7647
+ }, { priority: 'high' });
7648
+ if (entries.length) {
7649
+ post(cfg, sid, { entries });
7650
+ }
7482
7651
  });
7483
7652
  }, { priority: 'high' });
7484
7653
  }
@@ -7524,7 +7693,7 @@ function scheduleAmqpPublishCapture(params) {
7524
7693
  parentSpanId: params.span?.parentSpanId ?? null,
7525
7694
  };
7526
7695
  scheduleSdkBackgroundWork(async () => {
7527
- const bodyMaterialization = await materializeKafkaRequestBody(params.cfg, maskReq, body);
7696
+ const bodyMaterialization = await materializeKafkaRequestBody(params.cfg, maskReq, body, params.captureScope);
7528
7697
  const requestPayload = {
7529
7698
  rid: params.publishRid,
7530
7699
  method: params.method,
@@ -7554,7 +7723,6 @@ function scheduleAmqpPublishCapture(params) {
7554
7723
  t: alignedNow(),
7555
7724
  }],
7556
7725
  });
7557
- params.captureScope.backendRequestCount += 1;
7558
7726
  post(params.cfg, params.sid, {
7559
7727
  entries: [{
7560
7728
  actionId: params.aid ?? null,
@@ -7605,7 +7773,7 @@ function patchAmqplibPublishMethod(channel, cfg, methodName) {
7605
7773
  : `amqp://queue/${queue}`;
7606
7774
  const key = `${method} ${methodName === 'publish' ? `${exchange || 'default'}/${routingKey}` : queue}`;
7607
7775
  const content = methodName === 'publish' ? args[2] : args[1];
7608
- const captureScope = createRequestCaptureScope(publishRid, 'amqp');
7776
+ const captureScope = createRequestCaptureScope(publishRid, 'amqp', cfg);
7609
7777
  emitRequestCaptureStart(cfg, sid, aid, captureScope);
7610
7778
  const t0 = Date.now();
7611
7779
  let finished = false;
@@ -7692,7 +7860,7 @@ function wrapAmqplibConsumeHandler(onMessage, cfg, queue) {
7692
7860
  const deliveryTag = message?.fields?.deliveryTag ?? alignedNow();
7693
7861
  const consumeRid = nextRequestId(`${queueName}-${deliveryTag}`);
7694
7862
  const traceId = consumeRid;
7695
- const captureScope = createRequestCaptureScope(consumeRid, 'amqp');
7863
+ const captureScope = createRequestCaptureScope(consumeRid, 'amqp', cfg);
7696
7864
  emitRequestCaptureStart(cfg, sid, aid, captureScope);
7697
7865
  const rawTraceEvents = [];
7698
7866
  const maskReq = {
@@ -7782,7 +7950,7 @@ function wrapAmqplibConsumeHandler(onMessage, cfg, queue) {
7782
7950
  properties: buildAmqpMessagePropertiesPayload(properties),
7783
7951
  };
7784
7952
  scheduleSdkBackgroundWork(async () => {
7785
- const bodyMaterialization = await materializeKafkaRequestBody(cfg, maskReq, body);
7953
+ const bodyMaterialization = await materializeKafkaRequestBody(cfg, maskReq, body, captureScope);
7786
7954
  const requestPayload = {
7787
7955
  rid: consumeRid,
7788
7956
  method: 'AMQP_CONSUME',
@@ -7803,7 +7971,6 @@ function wrapAmqplibConsumeHandler(onMessage, cfg, queue) {
7803
7971
  t: alignedNow(),
7804
7972
  }],
7805
7973
  });
7806
- captureScope.backendRequestCount += 1;
7807
7974
  scheduleAmqpTraceFlush(cfg, amqpCtx, aid, consumeRid, rawTraceEvents, maskReq, captureScope);
7808
7975
  }, { priority: 'high' });
7809
7976
  };
@@ -9978,5 +10145,6 @@ exports.__reproTestHooks = {
9978
10145
  estimateTraceBatchSerializedBytesForTest: estimateTraceBatchSerializedBytes,
9979
10146
  sanitizeTraceValueForPrivacyForTest: sanitizeTraceValueForPrivacy,
9980
10147
  sanitizeMaterializedTraceValueForTest: sanitizeMaterializedTraceValue,
10148
+ projectSemanticInfrastructureValueForTest: semantic_serialization_1.projectSemanticInfrastructureValue,
9981
10149
  getEventTraceValueEntriesForTest: getEventTraceValueEntries,
9982
10150
  };