{"_id":"@sentry/node-native-stacktrace","_rev":"2-9febad397fa682d36dde377e0158259d","name":"@sentry/node-native-stacktrace","dist-tags":{"latest":"0.5.2"},"versions":{"0.5.1":{"name":"@sentry/node-native-stacktrace","version":"0.5.1","keywords":["stacktrace","native","nodejs","worker","sentry"],"author":{"name":"Sentry"},"license":"MIT","_id":"@sentry/node-native-stacktrace@0.5.1","maintainers":[{"name":"sentry-bot","email":"accounts@sentry.io"}],"homepage":"https://github.com/getsentry/sentry-javascript-node-native-stacktrace","bugs":{"url":"https://github.com/getsentry/sentry-javascript-node-native-stacktrace/issues"},"dist":{"shasum":"bb2309b3c9c3902b536613e29e3e6c5d44f4f22d","tarball":"https://registry.npmjs.org/@sentry/node-native-stacktrace/-/node-native-stacktrace-0.5.1.tgz","fileCount":47,"integrity":"sha512-tF8eI4Z5YP6l7piLcy4BeGv6J96Y2ttssAAVFPgdzxzsT9i+S2olqGWgA9qav6+Gzs6E5pC9PAkObp2eDftabQ==","signatures":[{"sig":"MEQCIFSrsA2435DGLmSzqYrUNaXFaFrJgRzPY35DQ/mL1CSTAiBz3BQnKeujY72yK4wuV2Q/lOV0BIhR+3AvTksiuniReA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":4267546},"main":"lib/index.js","_from":"file:/tmp/craft-ZQOlC6/sentry-node-native-stacktrace-0.5.1.tgz","types":"lib/index.d.ts","volta":{"node":"24.9.0"},"engines":{"node":">=18"},"scripts":{"fix":"yarn fix:eslint && yarn fix:clang","lint":"yarn lint:eslint && yarn lint:clang","test":"yarn test:install && yarn test:prepare && vitest run --poolOptions.forks.singleFork --silent=false --disable-console-intercept","build":"yarn clean && yarn build:lib && yarn build:bindings:configure && yarn build:bindings","clean":"node-gyp clean && rm -rf lib && rm -rf build && rm -f *.tgz","install":"node scripts/check-build.mjs","build:lib":"tsc","fix:clang":"node scripts/clang-format.mjs --fix","fix:eslint":"eslint . --format stylish --fix","lint:clang":"node scripts/clang-format.mjs","lint:eslint":"eslint . --format stylish","test:install":"cross-env ALWAYS_THROW=true yarn install","test:prepare":"node ./test/prepare.mjs","build:tarball":"npm pack","build:bindings":"node-gyp build && node scripts/copy-target.mjs","build:bindings:arm64":"node-gyp build --arch=arm64 && node scripts/copy-target.mjs","build:bindings:configure":"node-gyp configure","build:bindings:configure:arm64":"node-gyp configure --arch=arm64 --target_arch=arm64"},"_npmUser":{"name":"sentry-bot","email":"accounts@sentry.io"},"_resolved":"/tmp/craft-ZQOlC6/sentry-node-native-stacktrace-0.5.1.tgz","_integrity":"sha512-tF8eI4Z5YP6l7piLcy4BeGv6J96Y2ttssAAVFPgdzxzsT9i+S2olqGWgA9qav6+Gzs6E5pC9PAkObp2eDftabQ==","repository":{"url":"git://github.com/getsentry/sentry-javascript-node-native-stacktrace.git","type":"git"},"_npmVersion":"10.9.8","description":"A native Node.js module that can capture JavaScript stack traces from main and worker threads, even with blocked event loops.","directories":{},"_nodeVersion":"22.22.3","dependencies":{"node-abi":"^3.89.0","detect-libc":"^2.0.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^7.0.0","vitest":"^3.1.4","node-gyp":"^11.2.0","cross-env":"^7.0.3","typescript":"^5.8.3","@types/node":"^18.19.1","clang-format":"^1.8.0","@types/node-abi":"^3.0.3","@sentry-internal/eslint-config-sdk":"^9.22.0"},"_npmOperationalInternal":{"tmp":"tmp/node-native-stacktrace_0.5.1_1780942438239_0.47095865641308343","host":"s3://npm-registry-packages-npm-production"}},"0.5.2":{"name":"@sentry/node-native-stacktrace","version":"0.5.2","main":"lib/index.js","types":"lib/index.d.ts","repository":{"type":"git","url":"git://github.com/getsentry/sentry-javascript-node-native-stacktrace.git"},"homepage":"https://github.com/getsentry/sentry-javascript-node-native-stacktrace","author":{"name":"Sentry"},"license":"MIT","description":"A native Node.js module that can capture JavaScript stack traces from main and worker threads, even with blocked event loops.","keywords":["stacktrace","native","nodejs","worker","sentry"],"scripts":{"install":"node scripts/check-build.mjs","lint":"yarn lint:eslint && yarn lint:clang","lint:eslint":"eslint . --format stylish","lint:clang":"node scripts/clang-format.mjs","fix":"yarn fix:eslint && yarn fix:clang","fix:eslint":"eslint . --format stylish --fix","fix:clang":"node scripts/clang-format.mjs --fix","build":"yarn clean && yarn build:lib && yarn build:bindings:configure && yarn build:bindings","build:lib":"tsc","build:bindings:configure":"node-gyp configure","build:bindings:configure:arm64":"node-gyp configure --arch=arm64 --target_arch=arm64","build:bindings":"node-gyp build && node scripts/copy-target.mjs","build:bindings:arm64":"node-gyp build --arch=arm64 && node scripts/copy-target.mjs","build:tarball":"npm pack","clean":"node-gyp clean && rm -rf lib && rm -rf build && rm -f *.tgz","test":"yarn test:install && yarn test:prepare && vitest run --poolOptions.forks.singleFork --silent=false --disable-console-intercept","test:prepare":"node ./test/prepare.mjs","test:install":"cross-env ALWAYS_THROW=true yarn install"},"engines":{"node":">=18"},"dependencies":{"detect-libc":"^2.0.4","node-abi":"^3.89.0"},"devDependencies":{"@sentry-internal/eslint-config-sdk":"^9.22.0","@types/node":"^18.19.1","@types/node-abi":"^3.0.3","clang-format":"^1.8.0","cross-env":"^7.0.3","eslint":"^7.0.0","node-gyp":"^11.2.0","typescript":"^5.8.3","vitest":"^3.1.4"},"publishConfig":{"access":"public"},"volta":{"node":"24.9.0"},"_id":"@sentry/node-native-stacktrace@0.5.2","bugs":{"url":"https://github.com/getsentry/sentry-javascript-node-native-stacktrace/issues"},"_integrity":"sha512-p1Skk57ERpsLa/cUEFx9ePc/noCIoEXc3PnOy2bnl0r1Xkjla+hLzJKcvkVp+CuUX/4eMZ+/5AA4BJ3EJLrjZg==","_resolved":"/tmp/craft-F07HaV/sentry-node-native-stacktrace-0.5.2.tgz","_from":"file:/tmp/craft-F07HaV/sentry-node-native-stacktrace-0.5.2.tgz","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-p1Skk57ERpsLa/cUEFx9ePc/noCIoEXc3PnOy2bnl0r1Xkjla+hLzJKcvkVp+CuUX/4eMZ+/5AA4BJ3EJLrjZg==","shasum":"04cebe7349a0fdb70d54dbad0376f478c3c99a0c","tarball":"https://registry.npmjs.org/@sentry/node-native-stacktrace/-/node-native-stacktrace-0.5.2.tgz","fileCount":47,"unpackedSize":4267812,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIH0c41TVCnQNv+yrg44izwz+0p33Z2xkCrJC1v0X3mN5AiAphidJ1Q9QqHzKGYu7DP4HSYjf9aXmRXwgBpVygrGtvg=="}]},"_npmUser":{"name":"sentry-bot","email":"accounts@sentry.io"},"directories":{},"maintainers":[{"name":"sentry-bot","email":"accounts@sentry.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/node-native-stacktrace_0.5.2_1785252564394_0.1586646698531773"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-08T18:13:58.063Z","modified":"2026-07-28T15:29:24.710Z","0.5.1":"2026-06-08T18:13:58.399Z","0.5.2":"2026-07-28T15:29:24.569Z"},"bugs":{"url":"https://github.com/getsentry/sentry-javascript-node-native-stacktrace/issues"},"author":{"name":"Sentry"},"license":"MIT","homepage":"https://github.com/getsentry/sentry-javascript-node-native-stacktrace","keywords":["stacktrace","native","nodejs","worker","sentry"],"repository":{"type":"git","url":"git://github.com/getsentry/sentry-javascript-node-native-stacktrace.git"},"description":"A native Node.js module that can capture JavaScript stack traces from main and worker threads, even with blocked event loops.","maintainers":[{"name":"sentry-bot","email":"accounts@sentry.io"}],"readme":"# `@sentry/node-native-stacktrace`\n\nA native Node.js module that can capture JavaScript stack traces for registered\nmain or worker threads from any other thread, even if event loops are blocked.\n\nThe module also provides a means to create a watchdog system to track event loop\nblocking via periodic heartbeats. When the time from the last heartbeat crosses\na threshold, JavaScript stack traces can be captured.\n\nFor Node.js >= v24, this module can also capture state from `AsyncLocalStorage`\nat the time of stack trace capture, which can help provide context on what the\nthread was working on when it became blocked.\n\nThis native module is used for Sentry's\n[Event Loop Blocked Detection](https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/event-loop-block/)\nfeature.\n\n## Basic Usage\n\n### 1. Register threads you want to monitor\n\nIn your main thread or worker threads:\n\n```ts\nimport { registerThread } from \"@sentry/node-native-stacktrace\";\n\n// Register this thread for monitoring\nregisterThread();\n```\n\n### 2. Capture stack traces from any thread\n\n```ts\nimport { captureStackTrace } from \"@sentry/node-native-stacktrace\";\n\n// Capture stack traces from all registered threads\nconst stacks = captureStackTrace();\nconsole.log(stacks);\n```\n\n### Example Output\n\nStack traces show where each thread is currently executing:\n\n```js\n{\n  '0': { // Main thread has ID '0'\n    frames: [\n      {\n        function: 'from',\n        filename: 'node:buffer',\n        lineno: 298,\n        colno: 28\n      },\n      {\n        function: 'pbkdf2Sync',\n        filename: 'node:internal/crypto/pbkdf2',\n        lineno: 78,\n        colno: 17\n      },\n      {\n        function: 'longWork',\n        filename: '/app/test.js',\n        lineno: 20,\n        colno: 29\n      },\n      {\n        function: '?',\n        filename: '/app/test.js',\n        lineno: 24,\n        colno: 1\n      }\n    ]\n  },\n  '2': { // Worker thread\n    frames: [\n      {\n        function: 'from',\n        filename: 'node:buffer',\n        lineno: 298,\n        colno: 28\n      },\n      {\n        function: 'pbkdf2Sync',\n        filename: 'node:internal/crypto/pbkdf2',\n        lineno: 78,\n        colno: 17\n      },\n      {\n        function: 'longWork',\n        filename: '/app/worker.js',\n        lineno: 10,\n        colno: 29\n      },\n      {\n        function: '?',\n        filename: '/app/worker.js',\n        lineno: 14,\n        colno: 1\n      }\n    ]\n  }\n}\n```\n\n## Advanced Usage: Automatic blocked event loop Detection\n\nSet up automatic detection of blocked event loops:\n\n### 1. Register threads with `AsyncLocalStorage` state tracking and heartbeats\n\nSend regular heartbeats:\n\n```ts\nimport {\n  registerThread,\n  threadPoll,\n} from \"@sentry/node-native-stacktrace\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\n// Create async local storage for state tracking\nconst asyncLocalStorage = new AsyncLocalStorage();\n// Set some state in the async local storage\nasyncLocalStorage.enterWith({ someState: \"value\" });\n\n// Register this thread with async local storage\nregisterThread({ asyncLocalStorage });\n\n// Send heartbeats every 200ms\nsetInterval(() => {\n  threadPoll();\n}, 200);\n```\n\n### 2. Monitor from a watchdog thread\n\nMonitor all registered threads from a dedicated thread:\n\n```ts\nimport {\n  captureStackTrace,\n  getThreadsLastSeen,\n} from \"@sentry/node-native-stacktrace\";\n\nconst THRESHOLD = 1000; // 1 second\n\nsetInterval(() => {\n  const threadsLastSeen = getThreadsLastSeen();\n\n  for (const [threadId, timeSinceLastSeen] of Object.entries(threadsLastSeen)) {\n    if (timeSinceLastSeen > THRESHOLD) {\n      // Thread appears to be blocked - capture diagnostics\n      const stackTraces = captureStackTrace();\n      const blockedThread = stackTraces[threadId];\n\n      console.error(`🚨 Thread ${threadId} blocked for ${timeSinceLastSeen}ms`);\n      console.error(\"Stack trace:\", blockedThread.frames);\n      console.error(\"Async state:\", blockedThread.asyncState);\n    }\n  }\n}, 500); // Check every 500ms\n```\n\n## API Reference\n\n### Functions\n\n#### `registerThread(threadName?: string): void`\n\n#### `registerThread(asyncStorage: AsyncStorageArgs, threadName?: string): void`\n\nRegisters the current thread for stack trace capture. Must be called from each\nthread you want to capture stack traces from.\n\n- `threadName` (optional): Name for the thread. Defaults to the current thread\n  ID.\n- `asyncStorage` (optional): `AsyncStorageArgs` to fetch state from\n  `AsyncLocalStorage` on stack trace capture.\n\n```ts\ntype AsyncStorageArgs = {\n  /** AsyncLocalStorage instance to fetch state from */\n  asyncLocalStorage: AsyncLocalStorage<unknown>;\n  /**\n   * Optional array of keys to pick a specific property from the store.\n   * Key will be traversed in order through Objects/Maps to reach the desired property.\n   *\n   * This is useful if you want to capture Open Telemetry context values as state.\n   *\n   * To get this value:\n   * context.getValue(MY_UNIQUE_SYMBOL_REF)\n   *\n   * You would set:\n   * stateLookup: ['_currentContext', MY_UNIQUE_SYMBOL_REF]\n   */\n  stateLookup?: Array<string | symbol>;\n};\n```\n\n#### `captureStackTrace<State>(): Record<string, Thread<A, P>>`\n\nCaptures stack traces from all registered threads. Can be called from any thread\nbut will not capture a stack trace for the calling thread itself.\n\n```ts\ntype Thread<A = unknown, P = unknown> = {\n  frames: StackFrame[];\n  /** State captured from the AsyncLocalStorage */\n  asyncState?: A;\n  /** Optional state provided when calling threadPoll */\n  pollState?: P;\n};\n\ntype StackFrame = {\n  function: string;\n  filename: string;\n  lineno: number;\n  colno: number;\n};\n```\n\n#### `threadPoll<State>(disableLastSeen?: boolean, pollState?: object): void`\n\nSends a heartbeat from the current thread.\n\n- `disableLastSeen` (optional): If `true`, disables the tracking of the last\n  seen time for this thread.\n- `pollState` (optional): An object containing state to include with the next\n  stack trace capture. This can be used instead of or in addition to\n  `AsyncLocalStorage` based state tracking.\n\n#### `getThreadsLastSeen(): Record<string, number>`\n\nReturns the time in milliseconds since each registered thread called\n`threadPoll()`.\n","readmeFilename":"README.md"}