@reproapp/node-sdk 0.0.25 → 0.0.26

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
@@ -6325,6 +6325,7 @@ function patchKafkaJs(cfg) {
6325
6325
  }
6326
6326
  }
6327
6327
  exports.patchKafkaJs = patchKafkaJs;
6328
+ const AMQP_INTERNAL_PUBLISH_DEPTH = Symbol.for('repro.amqplib.internalPublishDepth');
6328
6329
  function decodeAmqpHeaderValue(value) {
6329
6330
  if (value === null || value === undefined)
6330
6331
  return null;
@@ -6726,6 +6727,9 @@ function patchAmqplibPublishMethod(channel, cfg, methodName) {
6726
6727
  const optionsIndex = methodName === 'publish' ? 3 : 2;
6727
6728
  const method = methodName === 'publish' ? 'AMQP_PUBLISH' : 'AMQP_SEND_TO_QUEUE';
6728
6729
  const wrapped = function reproPatchedAmqplibPublish(...args) {
6730
+ if (methodName === 'publish' && Number(this?.[AMQP_INTERNAL_PUBLISH_DEPTH] ?? 0) > 0) {
6731
+ return orig.apply(this, args);
6732
+ }
6729
6733
  const ctx = getCtx();
6730
6734
  const fallback = cfg.resolveContext?.() ?? {};
6731
6735
  const sid = ctx.sid ?? fallback.sid ?? null;
@@ -6797,7 +6801,12 @@ function patchAmqplibPublishMethod(channel, cfg, methodName) {
6797
6801
  : (wrappedCallback
6798
6802
  ? setAmqpPublishOptionsArg(args, optionsIndex, nextOptions, callbackIndex, wrappedCallback)
6799
6803
  : args);
6804
+ let bumpedInternalPublishDepth = false;
6800
6805
  try {
6806
+ if (methodName === 'sendToQueue' && this && typeof this === 'object') {
6807
+ this[AMQP_INTERNAL_PUBLISH_DEPTH] = Number(this?.[AMQP_INTERNAL_PUBLISH_DEPTH] ?? 0) + 1;
6808
+ bumpedInternalPublishDepth = true;
6809
+ }
6801
6810
  const result = orig.apply(this, nextArgs);
6802
6811
  if (!wrappedCallback) {
6803
6812
  finish(200, undefined, result);
@@ -6808,6 +6817,17 @@ function patchAmqplibPublishMethod(channel, cfg, methodName) {
6808
6817
  finish(500, error);
6809
6818
  throw error;
6810
6819
  }
6820
+ finally {
6821
+ if (bumpedInternalPublishDepth) {
6822
+ const nextDepth = Number(this?.[AMQP_INTERNAL_PUBLISH_DEPTH] ?? 0) - 1;
6823
+ if (nextDepth > 0) {
6824
+ this[AMQP_INTERNAL_PUBLISH_DEPTH] = nextDepth;
6825
+ }
6826
+ else if (this && typeof this === 'object') {
6827
+ delete this[AMQP_INTERNAL_PUBLISH_DEPTH];
6828
+ }
6829
+ }
6830
+ }
6811
6831
  };
6812
6832
  wrapped.__repro_amqplib_patched = true;
6813
6833
  channel[methodName] = wrapped;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reproapp/node-sdk",
3
- "version": "0.0.25",
3
+ "version": "0.0.26",
4
4
  "description": "Repro Nest SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/index.ts CHANGED
@@ -7389,6 +7389,7 @@ type AmqpPropagationContext = {
7389
7389
  parentSpanId: string | null;
7390
7390
  requestRid: string | null;
7391
7391
  };
7392
+ const AMQP_INTERNAL_PUBLISH_DEPTH = Symbol.for('repro.amqplib.internalPublishDepth');
7392
7393
 
7393
7394
  export type AmqplibPatchConfig = ReproMiddlewareConfig & {
7394
7395
  resolveContext?: AmqpContextResolver;
@@ -7859,6 +7860,10 @@ function patchAmqplibPublishMethod(
7859
7860
  const method = methodName === 'publish' ? 'AMQP_PUBLISH' : 'AMQP_SEND_TO_QUEUE';
7860
7861
 
7861
7862
  const wrapped = function reproPatchedAmqplibPublish(this: any, ...args: any[]) {
7863
+ if (methodName === 'publish' && Number(this?.[AMQP_INTERNAL_PUBLISH_DEPTH] ?? 0) > 0) {
7864
+ return orig.apply(this, args);
7865
+ }
7866
+
7862
7867
  const ctx = getCtx();
7863
7868
  const fallback = cfg.resolveContext?.() ?? {};
7864
7869
  const sid = ctx.sid ?? fallback.sid ?? null;
@@ -7933,8 +7938,13 @@ function patchAmqplibPublishMethod(
7933
7938
  : (wrappedCallback
7934
7939
  ? setAmqpPublishOptionsArg(args, optionsIndex, nextOptions, callbackIndex, wrappedCallback)
7935
7940
  : args);
7941
+ let bumpedInternalPublishDepth = false;
7936
7942
 
7937
7943
  try {
7944
+ if (methodName === 'sendToQueue' && this && typeof this === 'object') {
7945
+ this[AMQP_INTERNAL_PUBLISH_DEPTH] = Number(this?.[AMQP_INTERNAL_PUBLISH_DEPTH] ?? 0) + 1;
7946
+ bumpedInternalPublishDepth = true;
7947
+ }
7938
7948
  const result = orig.apply(this, nextArgs);
7939
7949
  if (!wrappedCallback) {
7940
7950
  finish(200, undefined, result);
@@ -7943,6 +7953,15 @@ function patchAmqplibPublishMethod(
7943
7953
  } catch (error) {
7944
7954
  finish(500, error);
7945
7955
  throw error;
7956
+ } finally {
7957
+ if (bumpedInternalPublishDepth) {
7958
+ const nextDepth = Number(this?.[AMQP_INTERNAL_PUBLISH_DEPTH] ?? 0) - 1;
7959
+ if (nextDepth > 0) {
7960
+ this[AMQP_INTERNAL_PUBLISH_DEPTH] = nextDepth;
7961
+ } else if (this && typeof this === 'object') {
7962
+ delete this[AMQP_INTERNAL_PUBLISH_DEPTH];
7963
+ }
7964
+ }
7946
7965
  }
7947
7966
  };
7948
7967
 
@@ -286,6 +286,55 @@ async function testCallbackApiConnectAndConfirmChannelArePatched() {
286
286
  });
287
287
  }
288
288
 
289
+ async function testSendToQueueDoesNotDoubleCaptureInternalPublish() {
290
+ await withCapturedFetch(async (capturedBodies) => {
291
+ __reproTestHooks.resetSdkBackgroundQueuesForTest();
292
+ const internalPublishes = [];
293
+ const channel = {
294
+ publish(exchange, routingKey, content, options) {
295
+ internalPublishes.push({ exchange, routingKey, content, options });
296
+ return true;
297
+ },
298
+ sendToQueue(queue, content, options) {
299
+ return this.publish('', queue, content, options);
300
+ },
301
+ };
302
+ const cfg = makeConfig('S_amqp_send', 'A_amqp_send');
303
+ __reproTestHooks.patchAmqplibChannelForTest(channel, cfg);
304
+
305
+ const result = channel.sendToQueue(
306
+ 'outbound-email',
307
+ Buffer.from(JSON.stringify({ subject: 'hello', html: '<p>full html</p>' })),
308
+ { contentType: 'application/json', headers: { existing: 'yes' } },
309
+ );
310
+
311
+ assert.strictEqual(result, true);
312
+ assert.strictEqual(internalPublishes.length, 1);
313
+ assert.strictEqual(internalPublishes[0].exchange, '');
314
+ assert.strictEqual(internalPublishes[0].routingKey, 'outbound-email');
315
+ assert.strictEqual(internalPublishes[0].options.headers.existing, 'yes');
316
+ assert.strictEqual(internalPublishes[0].options.headers['x-bug-session-id'], 'S_amqp_send');
317
+ assert.strictEqual(internalPublishes[0].options.headers['x-bug-action-id'], 'A_amqp_send');
318
+ assert(internalPublishes[0].options.headers['x-repro-request-rid']);
319
+
320
+ await waitFor(() => flattenEvents(capturedBodies)
321
+ .some((event) => event?.event_type === 'backend_request'));
322
+ await drainSdk();
323
+
324
+ const backendRequests = flattenEvents(capturedBodies)
325
+ .filter((event) => event?.event_type === 'backend_request');
326
+ assert.strictEqual(
327
+ backendRequests.length,
328
+ 1,
329
+ JSON.stringify(backendRequests.map((event) => event.payload?.request?.method)),
330
+ );
331
+ assert.strictEqual(backendRequests[0].payload.request.method, 'AMQP_SEND_TO_QUEUE');
332
+ assert.strictEqual(backendRequests[0].payload.request.path, 'amqp://queue/outbound-email');
333
+ assert.strictEqual(backendRequests[0].payload.request.body.message.value.subject, 'hello');
334
+ assert.strictEqual(backendRequests[0].payload.request.body.message.value.html, '<p>full html</p>');
335
+ });
336
+ }
337
+
289
338
  async function testNullConsumeMessagePassesThrough() {
290
339
  let received = 'not-called';
291
340
  const wrapped = __reproTestHooks.wrapAmqplibConsumeHandlerForTest((message) => {
@@ -329,6 +378,7 @@ async function main() {
329
378
  await testPublishInjectsHeadersWithoutMutatingOptions();
330
379
  await testConsumeCapturesRequestTraceAndManifest();
331
380
  await testCallbackApiConnectAndConfirmChannelArePatched();
381
+ await testSendToQueueDoesNotDoubleCaptureInternalPublish();
332
382
  await testNullConsumeMessagePassesThrough();
333
383
  await testSyncConsumeThrowIsNotRetried();
334
384
  console.log('amqplib integration OK');