mirror of
https://github.com/Gitlawb/openclaude.git
synced 2026-11-06 12:50:54 -04:00
chore(deps): upgrade @sentry/node to 11.9.0 (M-14) (#2402)
* chore(deps): upgrade @sentry/node to 11.9.0 (M-14) * fix(sentry): omit hostname from sanitized error reports * test(sentry): cover nonessential-traffic opt-out on its own * fix(sentry): bound Sentry flush before shutdown exit * fix(sentry): leave tracesSampleRate unset so spans stay disabled * fix(shutdown): include Sentry drain in failsafe budget and test pending-flush exits
This commit is contained in:
@@ -288,6 +288,15 @@ new watcher for subsequent subscriptions because closing is terminal. Its
|
||||
Node.js 22.22 minimum is covered by the supported Node.js `>=24.22.1` runtime.
|
||||
Regenerate `bun.lock` with `bun install` after updating the exact pin.
|
||||
|
||||
Keep `@sentry/node` pinned exactly to `11.9.0` and regenerate `bun.lock` with
|
||||
`bun install` after updating it. The optional reporter uses a lazy ESM import
|
||||
after trust is established. Keep default integrations and tracing disabled,
|
||||
set `attachStacktrace: false`, and explicitly disable `dataCollection` categories
|
||||
so only vetted messages are reported. Do not add automatic instrumentation or
|
||||
an OpenTelemetry provider to this path. Run `bun test src/utils/sentry.test.ts`
|
||||
when updating the SDK or initialization. Its Node.js minimum is covered by the
|
||||
supported runtime; self-hosted Sentry requires 26.4.2 or later.
|
||||
|
||||
The root `overrides` block also controls transitive resolutions:
|
||||
|
||||
- `ip-address`: `10.7.4` sets the security floor for the MCP SDK's
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"@grpc/grpc-js": "1.14.6",
|
||||
"@grpc/proto-loader": "0.8.1",
|
||||
"@modelcontextprotocol/sdk": "1.32.1",
|
||||
"@sentry/node": "10.70.0",
|
||||
"@sentry/node": "11.9.0",
|
||||
"@smithy/core": "3.36.2",
|
||||
"@smithy/node-http-handler": "4.12.1",
|
||||
"@types/bun": "1.4.4",
|
||||
@@ -121,12 +121,6 @@
|
||||
|
||||
"@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.137.0", "", { "dependencies": { "@opentelemetry/api": "^1.4.1", "json-schema-to-ts": "^3.1.1", "standardwebhooks": "^1.0.0" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-YpEnbPz8kWF1BWthwUCnRhci7OvDLSUO8NFKoevoPkjNkK9CJeibZITgxr9vhqOP8Le61e5tNDHFTxw1dc6Png=="],
|
||||
|
||||
"@apm-js-collab/code-transformer": ["@apm-js-collab/code-transformer@0.18.1", "", { "dependencies": { "@types/estree": "^1.0.8", "astring": "^1.9.0", "esquery": "^1.7.0", "meriyah": "^6.1.4", "semifies": "^1.0.0", "source-map": "^0.6.0" }, "bin": { "code-transformer": "cli.js" } }, "sha512-u1Hb6bHjWtkSpiprwVP6YaHC1DTN4RAU3zYkUDUe7WMnJwdyU1pwTL9dFKiSJB9IiLue/EQovmyx6xhU7FFtAQ=="],
|
||||
|
||||
"@apm-js-collab/code-transformer-bundler-plugins": ["@apm-js-collab/code-transformer-bundler-plugins@0.7.4", "", { "dependencies": { "@apm-js-collab/code-transformer": "^0.18.1", "es-module-lexer": "^2.1.0", "magic-string": "^0.30.21", "module-details-from-path": "^1.0.4" } }, "sha512-nAfOeZPSUAQvJa1iFT/5oCrTm5YQhMMrfCNthNnaXHZiOQhu1KGuLoIx7HtbAi3wfwaBYLaICPIeenIaEwcXIg=="],
|
||||
|
||||
"@apm-js-collab/tracing-hooks": ["@apm-js-collab/tracing-hooks@0.13.0", "", { "dependencies": { "@apm-js-collab/code-transformer": "^0.18.0", "debug": "^4.4.1", "module-details-from-path": "^1.0.4" } }, "sha512-mTvWz9rnQwx1U3h0XPTHaX7bgfkpipLLTQyjlC2cdhQpQEuoLT0AGzoydeoq2NxfEVv6fWOOETcSbb2nptleyw=="],
|
||||
|
||||
"@aws-crypto/crc32": ["@aws-crypto/crc32@3.0.0", "", { "dependencies": { "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", "tslib": "^1.11.1" } }, "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA=="],
|
||||
|
||||
"@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="],
|
||||
@@ -345,20 +339,6 @@
|
||||
|
||||
"@opentelemetry/api": ["@opentelemetry/api@1.9.1", "", {}, "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q=="],
|
||||
|
||||
"@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.220.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w=="],
|
||||
|
||||
"@opentelemetry/core": ["@opentelemetry/core@2.10.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-/wNZ8twnEQQA4HoHu22+vcsdru6pWPWxW+7w+FlxT6Id7PE/WIbZmVKkte+PF72e0F2dnImFeHD2syyE1Mw6MQ=="],
|
||||
|
||||
"@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.220.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.220.0", "import-in-the-middle": "^3.0.0", "require-in-the-middle": "^8.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-xQx3E2WxP1mDvKzxLxX+CTCtNLa560YJZ3087qYHerl2YmiKpv7AH+dAy7vmx+eVrZ5BwhfWUAVoKOoxCNHcpw=="],
|
||||
|
||||
"@opentelemetry/resources": ["@opentelemetry/resources@2.10.0", "", { "dependencies": { "@opentelemetry/core": "2.10.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-q6MMm2zhggzsHVNbabYwut+a6nbuQQe3URUoxaojM/8K1IBfwwPzvxIjNi2/lI1TFe+fMHMW9MWhrtDLEXEnkA=="],
|
||||
|
||||
"@opentelemetry/sdk-trace": ["@opentelemetry/sdk-trace@2.10.0", "", { "dependencies": { "@opentelemetry/core": "2.10.0", "@opentelemetry/resources": "2.10.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-MfQGq3GRmTh5fM/y+OjaO0vj6+luCB1XO2gfXCalKCfgKw0eHL++sm75DNweC6ohlp+aFvACqeE0fYayqdRaoQ=="],
|
||||
|
||||
"@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.10.0", "", { "dependencies": { "@opentelemetry/core": "2.10.0", "@opentelemetry/resources": "2.10.0", "@opentelemetry/sdk-trace": "2.10.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-GuYQQT7QD2EeO8lcZLRQzcbOyhqAzL+6WWTKTU9mSUBYBazkEDl+VrQcXQhbB08OWM9anD1aHleVadzulpOaUQ=="],
|
||||
|
||||
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.43.0", "", {}, "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="],
|
||||
|
||||
"@orama/orama": ["@orama/orama@3.1.18", "", {}, "sha512-a61ljmRVVyG5MC/698C8/FfFDw5a8LOIvyOLW5fztgUXqUpc1jOfQzOitSCbge657OgXXThmY3Tk8fpiDb4UcA=="],
|
||||
|
||||
"@orama/plugin-data-persistence": ["@orama/plugin-data-persistence@3.1.18", "", { "dependencies": { "@msgpack/msgpack": "^3.1.2", "@orama/orama": "3.1.18", "dpack": "^0.6.22", "seqproto": "^0.2.3" } }, "sha512-pfBbpK96VRW/7IkdMHn2HaW3/+4k2C9Uwyup0IONNuz5bG3L1orCNFZPBmu+zcokOU2YH+IAVuQz6MlvqOe3iw=="],
|
||||
@@ -465,17 +445,19 @@
|
||||
|
||||
"@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="],
|
||||
|
||||
"@sentry/conventions": ["@sentry/conventions@0.16.0", "", {}, "sha512-fO9PLmHdVURcSPUpWCItWAtgKiMwGdJHbovoSEyLplX5sxs2ugvI4CBPTrkkgqhObnZOD0CnWBKDzSVQYBKEyQ=="],
|
||||
"@sentry/bundler-plugins": ["@sentry/bundler-plugins@11.9.0", "", { "dependencies": { "@sentry/core": "11.9.0", "dotenv": "^17.4.2", "glob": "^13.0.6", "magic-string": "~0.30.8 || ^1.0.0", "oxc-parser": "^0.152.0", "sentry": "^0.45.0", "supports-color": "^8.1.1" }, "peerDependencies": { "rollup": ">=3.2.0", "webpack": ">=5.1.0" }, "optionalPeers": ["rollup", "webpack"] }, "sha512-wpz/gcM/6rld/wb4Mhf8kbDN9ngG5myKQSZC+45gzqR1w+GcdfVnYkp3sHL9AV4mrwL8skhTItdUghMwMTknKg=="],
|
||||
|
||||
"@sentry/core": ["@sentry/core@10.70.0", "", { "dependencies": { "@sentry/conventions": "^0.16.0" } }, "sha512-ozhCTDqg89oB4XmWfAwuHshABpvT7AkRpaPnogopPfMAaI61G1t8EKCJ4W7aum8JSBonlfyjPCyW5oYZFm0KvA=="],
|
||||
"@sentry/conventions": ["@sentry/conventions@0.27.0", "", {}, "sha512-Mrqd/o7n/z7qWSYfQQA7x4fFTA0IqOG6JNsbBpnC97khPwZk7n6DPtOO7YgaYplSl8R8QLRbBz9Xv2lVhToSAg=="],
|
||||
|
||||
"@sentry/node": ["@sentry/node@10.70.0", "", { "dependencies": { "@opentelemetry/api": "^1.9.1", "@opentelemetry/instrumentation": "^0.220.0", "@opentelemetry/sdk-trace-base": "^2.9.0", "@sentry/conventions": "^0.16.0", "@sentry/core": "10.70.0", "@sentry/node-core": "10.70.0", "@sentry/opentelemetry": "10.70.0", "@sentry/server-utils": "10.70.0", "import-in-the-middle": "^3.0.0" } }, "sha512-SPOOVxmKTVIEtqvOKkQT163e/pOwucjS7OPsCHyRs8sFR4nfBNu0EThplyqnvqd5BWBMTPH6WTBQfo+QWHV+HA=="],
|
||||
"@sentry/core": ["@sentry/core@11.9.0", "", { "dependencies": { "@sentry/conventions": "^0.27.0" } }, "sha512-t0dZyHILt2XVC4Fe9UmAty6YRfOuQv95cvWeNl+HlW4LphjF5/jkALV3cJCUMdhpblYELgIJC4U/S/GoYuI2bA=="],
|
||||
|
||||
"@sentry/node-core": ["@sentry/node-core@10.70.0", "", { "dependencies": { "@sentry/conventions": "^0.16.0", "@sentry/core": "10.70.0", "@sentry/opentelemetry": "10.70.0", "import-in-the-middle": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/exporter-trace-otlp-http": ">=0.57.0 <1", "@opentelemetry/instrumentation": ">=0.57.1 <1", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/core", "@opentelemetry/exporter-trace-otlp-http", "@opentelemetry/instrumentation", "@opentelemetry/sdk-trace-base"] }, "sha512-oPOEVVNxv5WHtckx2i06Wi9FLWyvOg/1DUeX732jZ4iqT2nupINaMH4nF4f4kSvUThFnxkFSRQxwqOxgzMKhKA=="],
|
||||
"@sentry/node": ["@sentry/node@11.9.0", "", { "dependencies": { "@opentelemetry/api": "^1.9.1", "@sentry/bundler-plugins": "11.9.0", "@sentry/conventions": "^0.27.0", "@sentry/core": "11.9.0", "@sentry/opentelemetry": "11.9.0", "@sentry/server-runtime-injection": "11.9.0", "@sentry/server-utils": "11.9.0" } }, "sha512-cz219PzVaAPTlQ4bRBTRBCOvxbZkXK0KkqyqWPV6OmSn6vWn935CTfOs+MKUc1A+locvB8i9OfBIbO6v03BBuQ=="],
|
||||
|
||||
"@sentry/opentelemetry": ["@sentry/opentelemetry@10.70.0", "", { "dependencies": { "@sentry/conventions": "^0.16.0", "@sentry/core": "10.70.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0" } }, "sha512-UNV/2tqypcUK6FDzerAsFJn1Km/c4VZCYkUZDNbnV5S0cwAq2BYKMo4M5vovaLDBQlxA+Wk9ovbxi5wYjjl9fw=="],
|
||||
"@sentry/opentelemetry": ["@sentry/opentelemetry@11.9.0", "", { "dependencies": { "@sentry/conventions": "^0.27.0", "@sentry/core": "11.9.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0" } }, "sha512-FMCkAbEfBpFterrkR7k4P8LEabUAEHjZMbu+ycDjbnI1U4pT22tpwcFJOt06orFkacoWNsYT9+EdfmkvaCKtSA=="],
|
||||
|
||||
"@sentry/server-utils": ["@sentry/server-utils@10.70.0", "", { "dependencies": { "@apm-js-collab/code-transformer-bundler-plugins": "^0.7.3", "@apm-js-collab/tracing-hooks": "^0.13.0", "@sentry/conventions": "^0.16.0", "@sentry/core": "10.70.0", "meriyah": "^6.1.4" } }, "sha512-rzegZjMFFgCp3o+N8+XU13rfSvz4B+f8rU0ijBGrQcHdMNyfsFDTu1UTm262JofmrV2u+s+D0u0vFTnqtOGkbA=="],
|
||||
"@sentry/server-runtime-injection": ["@sentry/server-runtime-injection@11.9.0", "", { "dependencies": { "@sentry/core": "11.9.0", "@sentry/server-utils": "11.9.0" } }, "sha512-Q2G5xaeoiYwGheCZyeqZ/v//SZYjRLlITlanTsZM/fox1qk7cmbDX7+o4q+JkApVV9VuXQZVxppaVCsBglfDKA=="],
|
||||
|
||||
"@sentry/server-utils": ["@sentry/server-utils@11.9.0", "", { "dependencies": { "@opentelemetry/api": "^1.9.1", "@sentry/conventions": "^0.27.0", "@sentry/core": "11.9.0" } }, "sha512-xHETix5jAjs/4tY+b9RCejEU7O49pNBiGgCWX0KFRMSpWbw9moqQ8i8N62bS7L+/BJnBcZ5SZ1nweXh7w787Qg=="],
|
||||
|
||||
"@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="],
|
||||
|
||||
@@ -619,8 +601,6 @@
|
||||
|
||||
"ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
|
||||
|
||||
"astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="],
|
||||
|
||||
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
|
||||
|
||||
"auto-bind": ["auto-bind@5.0.1", "", {}, "sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg=="],
|
||||
@@ -661,8 +641,6 @@
|
||||
|
||||
"chokidar": ["chokidar@6.0.0", "", { "dependencies": { "readdirp": "^5.1.1" } }, "sha512-Ec2Z7wpcKBiMpR7DxteoqS/sq5G5d2A4fpxzPv6+fD7xNNdrTghn7L11YwV5EN1B3i72Erc3XVT5FkWIDx90+A=="],
|
||||
|
||||
"cjs-module-lexer": ["cjs-module-lexer@2.2.1", "", {}, "sha512-Ca8swihM+/4yKecYHY52kgJd300hi2lADU/a1RxNTRe+RJ9jvqQlESpbz9DnG9mowez8qwXHB8qYdIUw9e+F5Q=="],
|
||||
|
||||
"cli-boxes": ["cli-boxes@4.0.1", "", {}, "sha512-5IOn+jcCEHEraYolBPs/sT4BxYCe2nHg374OPiItB1O96KZFseS2gthU4twyYzeDcFew4DaUM/xwc5BQf08JJw=="],
|
||||
|
||||
"cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
|
||||
@@ -715,6 +693,8 @@
|
||||
|
||||
"dijkstrajs": ["dijkstrajs@1.0.3", "", {}, "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA=="],
|
||||
|
||||
"dotenv": ["dotenv@17.4.2", "", {}, "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw=="],
|
||||
|
||||
"dpack": ["dpack@0.6.22", "", {}, "sha512-WGPNlW2OAE7Bj0eODMpAHUcEqxrlg01e9OFZDxQodminIgC194/cRHT7K04Z1j7AUEWTeeplYGrIv/xRdwU9Hg=="],
|
||||
|
||||
"duck-duck-scrape": ["duck-duck-scrape@2.2.7", "", { "dependencies": { "html-entities": "^2.3.3", "needle": "^3.2.0" } }, "sha512-BEcglwnfx5puJl90KQfX+Q2q5vCguqyMpZcSRPBWk8OY55qWwV93+E+7DbIkrGDW4qkqPfUvtOUdi0lXz6lEMQ=="],
|
||||
@@ -735,8 +715,6 @@
|
||||
|
||||
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
|
||||
|
||||
"es-module-lexer": ["es-module-lexer@2.3.2", "", {}, "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw=="],
|
||||
|
||||
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
|
||||
|
||||
"es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
|
||||
@@ -841,6 +819,8 @@
|
||||
|
||||
"get-tsconfig": ["get-tsconfig@4.14.3", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA=="],
|
||||
|
||||
"glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="],
|
||||
|
||||
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
|
||||
|
||||
"google-auth-library": ["google-auth-library@11.3.1", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^8.3.0", "gcp-metadata": "^9.0.0", "google-logging-utils": "^2.0.0", "jws": "^4.0.0" } }, "sha512-mQS0R2Ev/DKkzuWSYtDeq15uhDeaWuT2qzLYqJ41LmooxVKHmn5ut3pc6dlHY6wfHW/D7FBmOYjAtkjaD1A7qA=="],
|
||||
@@ -893,8 +873,6 @@
|
||||
|
||||
"ignore": ["ignore@7.0.13", "", {}, "sha512-2E8Q6rh+1RRSq/YdaGsNfXsEZy9FVqv6BSSrkmZJP7BnaoPnRfKL+YaofPvP+5rzdk144qSm6i4+hvPgUcbV4Q=="],
|
||||
|
||||
"import-in-the-middle": ["import-in-the-middle@3.3.3", "", { "dependencies": { "cjs-module-lexer": "^2.2.0", "es-module-lexer": "^2.2.0", "module-details-from-path": "^1.0.4" } }, "sha512-AiohS3H80sXO6owEltjGX+glb7qXaDhBoJb9XcQVH4UI207xu/bDLUcadVKp7Qe576reg9yr/PXZjV5qx8gfbA=="],
|
||||
|
||||
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
|
||||
|
||||
"indent-string": ["indent-string@5.0.0", "", {}, "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg=="],
|
||||
@@ -997,17 +975,15 @@
|
||||
|
||||
"merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
|
||||
|
||||
"meriyah": ["meriyah@6.1.4", "", {}, "sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ=="],
|
||||
|
||||
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||
|
||||
"mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="],
|
||||
|
||||
"minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="],
|
||||
|
||||
"mnemonist": ["mnemonist@0.39.8", "", { "dependencies": { "obliterator": "^2.0.1" } }, "sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ=="],
|
||||
"minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="],
|
||||
|
||||
"module-details-from-path": ["module-details-from-path@1.0.4", "", {}, "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w=="],
|
||||
"mnemonist": ["mnemonist@0.39.8", "", { "dependencies": { "obliterator": "^2.0.1" } }, "sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
@@ -1061,6 +1037,8 @@
|
||||
|
||||
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||
|
||||
"path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="],
|
||||
|
||||
"path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="],
|
||||
|
||||
"picomatch": ["picomatch@4.0.7", "", {}, "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA=="],
|
||||
@@ -1109,8 +1087,6 @@
|
||||
|
||||
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
|
||||
|
||||
"require-in-the-middle": ["require-in-the-middle@8.0.1", "", { "dependencies": { "debug": "^4.3.5", "module-details-from-path": "^1.0.3" } }, "sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ=="],
|
||||
|
||||
"require-main-filename": ["require-main-filename@2.0.0", "", {}, "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="],
|
||||
|
||||
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
|
||||
@@ -1129,12 +1105,12 @@
|
||||
|
||||
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
||||
|
||||
"semifies": ["semifies@1.0.0", "", {}, "sha512-xXR3KGeoxTNWPD4aBvL5NUpMTT7WMANr3EWnaS190QVkY52lqqcVRD7Q05UVbBhiWDGWMlJEUam9m7uFFGVScw=="],
|
||||
|
||||
"semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
||||
|
||||
"send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="],
|
||||
|
||||
"sentry": ["sentry@0.45.0", "", { "bin": { "sentry": "dist/bin.cjs" } }, "sha512-kgmEbLlC22lL7uneeUm9Sjz65rp5cvwYOMTxXbZCmBum4sbVre/lLT3zTV3kwXHJ9/BM8ZS0/GhZe9Cl1t6WyA=="],
|
||||
|
||||
"seqproto": ["seqproto@0.2.3", "", {}, "sha512-HpNyPYl7DJa2a6XQJ+MJAc6ft6Y9ZU+zRiuvTHFpLPeqvapcTAGFJyhMEIN7Y7VXhWT6NEdNVhbXFHwtaCOfCw=="],
|
||||
|
||||
"serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="],
|
||||
@@ -1163,8 +1139,6 @@
|
||||
|
||||
"smol-toml": ["smol-toml@1.9.1", "", {}, "sha512-j7WyPdf0CJoutMzMoPLF/bVXHtKZIT9Rb4eGeEbWw8X2t5oirjPgpL+OpaENZrILYaXqYwnVH+qgUwVbl+pUJQ=="],
|
||||
|
||||
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||
|
||||
"standardwebhooks": ["standardwebhooks@1.1.1", "", { "dependencies": { "@stablelib/base64": "^1.0.0", "fast-sha256": "^1.3.0" } }, "sha512-bCbX9ZEyFkWPsRz7Bl3NuQUJohmwGSev/yhr7vhaGPlc4AfIrspIRa6cPTBuI1ItmrTDJ4d/S2hCsfe4+vQGnQ=="],
|
||||
|
||||
"statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
|
||||
@@ -1437,6 +1411,10 @@
|
||||
|
||||
"@img/sharp-wasm32/@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser": ["oxc-parser@0.152.0", "", { "dependencies": { "@oxc-project/types": "^0.152.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm-eabi": "0.152.0", "@oxc-parser/binding-android-arm64": "0.152.0", "@oxc-parser/binding-darwin-arm64": "0.152.0", "@oxc-parser/binding-darwin-x64": "0.152.0", "@oxc-parser/binding-freebsd-x64": "0.152.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.152.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.152.0", "@oxc-parser/binding-linux-arm64-gnu": "0.152.0", "@oxc-parser/binding-linux-arm64-musl": "0.152.0", "@oxc-parser/binding-linux-ppc64-gnu": "0.152.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.152.0", "@oxc-parser/binding-linux-riscv64-musl": "0.152.0", "@oxc-parser/binding-linux-s390x-gnu": "0.152.0", "@oxc-parser/binding-linux-x64-gnu": "0.152.0", "@oxc-parser/binding-linux-x64-musl": "0.152.0", "@oxc-parser/binding-openharmony-arm64": "0.152.0", "@oxc-parser/binding-win32-arm64-msvc": "0.152.0", "@oxc-parser/binding-win32-ia32-msvc": "0.152.0", "@oxc-parser/binding-win32-x64-msvc": "0.152.0" } }, "sha512-ZztsZgaCWmPeKYMdoTT5e0oV/oxD1NeLWNR3kAtr/G707cUPYaaozRlVDHLCGnszHJRszN9mJwmPNpqgwloC0A=="],
|
||||
|
||||
"@sentry/bundler-plugins/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
|
||||
|
||||
"@smithy/core/@smithy/types": ["@smithy/types@4.19.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-r7jh49VJxGerfAcTQA6gXcKc+98zOp/tqRwzYjgOE+iSQsP6cEU1hq2QzbuipmP68QtYdY9wKEhiCQZIzHgZ4Q=="],
|
||||
|
||||
"@smithy/credential-provider-imds/@smithy/types": ["@smithy/types@4.19.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-r7jh49VJxGerfAcTQA6gXcKc+98zOp/tqRwzYjgOE+iSQsP6cEU1hq2QzbuipmP68QtYdY9wKEhiCQZIzHgZ4Q=="],
|
||||
@@ -1539,6 +1517,48 @@
|
||||
|
||||
"@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4": ["@smithy/signature-v4@5.7.4", "", { "dependencies": { "@smithy/core": "^3.35.0", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-tHy0K0VtqNd5Y7Y41h0a0Lhh0L1GzC08dTWg0F7vRJWFtTENg7IZikf3wQkanYIRdb7ngoIPMTmqgUi401fEeQ=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.152.0", "", { "os": "android", "cpu": "arm" }, "sha512-393VtirINkae4XHBTkq/yQxhOwEr4V+r0et37P2fp+sYZSdYgZTRDPo5Um8vBh0QjMZ+RmaMy4PP0qwr4cTMwA=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.152.0", "", { "os": "android", "cpu": "arm64" }, "sha512-iYFcExATJNZ0rZj0o02THbD1Nc9jAW0nVgIQPee6ejbSASpbZXlIMw8jxtpzaG14JQTWwGSZ6U5dEtRJXE6V3Q=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.152.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-fnU+DfUzi5/rFy0LzmipYRz06PAUUkOS8kCJQ3Eg6oqlunC1XZXoffFqxmdL51RmcbYtUG3P8DVG1U5fckoa2A=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.152.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Y3U2okryWTs7hDld6UhjJwLNf8/do+x4g4C+1U5SiGwrTLwbO83WJYJA8+l9iFSilWBgnfpd/+U76tfeNxUHzA=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.152.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-XkhkRrrPffEw+ZLv/d/5pEni0buxinm/E/N6fLbJCunD1DBbeCTtVP23ESV+4CWCWdSz397asks1ViGslpmWiQ=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.152.0", "", { "os": "linux", "cpu": "arm" }, "sha512-MLzsRRbdfmdzo6JEhbC1yKU9ItfvM8tEf18HM32jCiNYZEz6J3bRBRl3cTkKR0vBdrk9ZVlcARXtwHccs+epDA=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.152.0", "", { "os": "linux", "cpu": "arm" }, "sha512-HHerTEJz7Iy10Ji6BGsk4gqG6PU0UzFuBu91jIEOX89FnrI5ECWSEr7BLpkYQhp7U0QFtMnBhNfQKI0hYZK78w=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.152.0", "", { "os": "linux", "cpu": "arm64", "libc": "glibc" }, "sha512-9Bb8GyzZ2uSLzRDZ27usaKokr07mxiBe2dDF5b6bd2janmaJTT1gL51UfP7AU30yFiXrJvcRyFKREAgKwZYs0w=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.152.0", "", { "os": "linux", "cpu": "arm64", "libc": "musl" }, "sha512-om7iDMUroI74A/lfRRWY9/Ev3VWrVsrUZ4tyvyh8raBey/sdcfyAD7tYWc+iykAiotnmftyKTpUKFr1QnaBrAQ=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-linux-ppc64-gnu": ["@oxc-parser/binding-linux-ppc64-gnu@0.152.0", "", { "os": "linux", "cpu": "ppc64", "libc": "glibc" }, "sha512-Lf1OL2lMTqwDMFC6jnRb30B+WYHKV0XT+bPHcFM6xHtNVwxpobiTzUIvKH6a0LWpvfwyru8Yu6zCGHqqFHH+gg=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.152.0", "", { "os": "linux", "cpu": "none", "libc": "glibc" }, "sha512-BYWSMQK+YJ9ZILStPcmmiSVq8KEG9Qdq/c4BHPC3rUEq/fEDCVjUIwdj5ZzjgZ9P9is9PKu0tcAXzq1ZXg4urQ=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-linux-riscv64-musl": ["@oxc-parser/binding-linux-riscv64-musl@0.152.0", "", { "os": "linux", "cpu": "none", "libc": "musl" }, "sha512-d2LqHNNNqdH185sRK5dPKWZu201JrNu9/CRFuVEuT+ht7n/QaVblEMWT9MALQPrDWYvhG10P+NSKJFquDWZ09w=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.152.0", "", { "os": "linux", "cpu": "s390x", "libc": "glibc" }, "sha512-8gBeHt5rA/8+pKhHl+zLggfa3L/V/L2at96p7ty6pBE7id6lFO19nFUc15u2PcjC4OYeYK465MKy1fhhbpFIGw=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.152.0", "", { "os": "linux", "cpu": "x64", "libc": "glibc" }, "sha512-ltgrSF6L+yPTVsIdaAyqKq3zTqzj/1VlNbxWZuxAe8flR3sWdyNsKvdXukoO8/ucJbLickhmieRBge+o/e8Ugw=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.152.0", "", { "os": "linux", "cpu": "x64", "libc": "musl" }, "sha512-LcMp6BvrBnewSfdkLHoSqidhoAq4syKOTBV5TYHWd+2VnGkfD/nPRRVIzTBt/Lkbt7pfOFDGtkiTntFS0p6sQQ=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-openharmony-arm64": ["@oxc-parser/binding-openharmony-arm64@0.152.0", "", { "os": "none", "cpu": "arm64" }, "sha512-jbhoMCslVxzRCRNQ8TSHxjYdSKRvk8O6ciLVDkahJvmyHDzBqba/bMQHM6ULKj/rgHNNbSzlIiakdx8SEfkJzA=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.152.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-JZYVlhv36mr/nertnRB7vchJECOBb1Lz6lltalILsB+o9M/is+H6BEDRLQKdqA4JKs6NjJszo46+iM5sfwj6jQ=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-win32-ia32-msvc": ["@oxc-parser/binding-win32-ia32-msvc@0.152.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-1X9oganvVsunRH0lH10UU05N+H9atpX6WsOybByUjwnfcd3h/0tYwvuv16XuHglrIUOnxV2TodbLVEwwafd64g=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.152.0", "", { "os": "win32", "cpu": "x64" }, "sha512-sw0M80/dn9rcpu+Rqqph/C+MjvDDce6MlXmFjsNQtPEymha0eJy3ml6+foSUTqFfpDIDyHZZ4eoJ43IoMe8bJw=="],
|
||||
|
||||
"@sentry/bundler-plugins/oxc-parser/@oxc-project/types": ["@oxc-project/types@0.152.0", "", {}, "sha512-oM/5rLBm2tPkg0iBgkH/FOeR3PCDpY19GTgAZjMFM8h9WI9VW7cLgzp6nwtarYKmovavIQZ+Fe/RKX/8C8O/Rw=="],
|
||||
|
||||
"@sentry/bundler-plugins/supports-color/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
|
||||
|
||||
"@typespec/ts-http-runtime/https-proxy-agent/agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
|
||||
|
||||
"axios/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
|
||||
|
||||
@@ -407,7 +407,7 @@ missing. Install only what you need:
|
||||
| Azure Foundry | `CLAUDE_CODE_USE_FOUNDRY=1` | `npm i -g @anthropic-ai/foundry-sdk @azure/identity` |
|
||||
| Claude on Vertex AI / Gemini ADC | `CLAUDE_CODE_USE_VERTEX=1` / Gemini ADC auth | `npm i -g google-auth-library` |
|
||||
| Reading/processing images (clipboard paste, drag-and-drop paths, FileReadTool local decode) | local image decode — **not** pre-encoded URL/base64 passthrough | `npm i -g sharp` (intentionally opt-in; prebuilt releases load it externally only when processing requires it) |
|
||||
| Optional error reporting | `SENTRY_DSN` is set | `npm i -g @sentry/node`. Without this package installed, setting `SENTRY_DSN` has no effect and reporting is silently disabled. |
|
||||
| Optional error reporting | `SENTRY_DSN` is set | `npm i -g @sentry/node@11.9.0`. Without this package installed, setting `SENTRY_DSN` has no effect and reporting is silently disabled. |
|
||||
|
||||
When installing OpenClaude from source (`bun install`), all of these are
|
||||
already present as dev dependencies, so source/dev builds need no extra steps.
|
||||
@@ -693,6 +693,8 @@ Notes:
|
||||
- Reporting is skipped even when `SENTRY_DSN` is set if `DISABLE_TELEMETRY` or
|
||||
`CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` is set, matching the same privacy
|
||||
levels used for existing telemetry (see [Runtime Hardening](#runtime-hardening)).
|
||||
- Automatic integrations, tracing, message stack traces, and SDK data collection
|
||||
are disabled. Self-hosted Sentry requires version 26.4.2 or later.
|
||||
- Only sanitized, telemetry-safe error messages are sent — never raw error
|
||||
messages, which may contain file paths or other identifying information.
|
||||
- `@sentry/node` is an optional dev dependency and is **not included** in the
|
||||
@@ -702,7 +704,7 @@ Notes:
|
||||
disabled (no error, no crash). Install it explicitly with:
|
||||
|
||||
```bash
|
||||
npm i -g @sentry/node
|
||||
npm i -g @sentry/node@11.9.0
|
||||
```
|
||||
|
||||
Source builds (`bun install`) already include it as a dev dependency, so no
|
||||
|
||||
+1
-1
@@ -103,7 +103,7 @@
|
||||
"@grpc/grpc-js": "1.14.6",
|
||||
"@grpc/proto-loader": "0.8.1",
|
||||
"@modelcontextprotocol/sdk": "1.32.1",
|
||||
"@sentry/node": "10.70.0",
|
||||
"@sentry/node": "11.9.0",
|
||||
"@smithy/core": "3.36.2",
|
||||
"@smithy/node-http-handler": "4.12.1",
|
||||
"@types/bun": "1.4.4",
|
||||
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { jest, spyOn } from 'bun:test'
|
||||
import * as Sentry from '@sentry/node'
|
||||
import { snapshotEnv } from '../envSnapshot.js'
|
||||
import {
|
||||
getPendingShutdownForTesting,
|
||||
gracefulShutdown,
|
||||
gracefulShutdownSync,
|
||||
resetShutdownState,
|
||||
} from '../../utils/gracefulShutdown.js'
|
||||
import { initializeSentry } from '../../utils/sentry.js'
|
||||
import { registerCleanup } from '../../utils/cleanupRegistry.js'
|
||||
import { sleep } from '../../utils/sleep.js'
|
||||
|
||||
const mode = process.argv[2]
|
||||
const restoreEnv = snapshotEnv([
|
||||
'NODE_ENV',
|
||||
'SENTRY_DSN',
|
||||
'DISABLE_TELEMETRY',
|
||||
'CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC',
|
||||
'CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS',
|
||||
], { clear: true })
|
||||
const originalExit = process.exit
|
||||
const exitError = new Error('mocked process exit')
|
||||
let exitCode: number | undefined
|
||||
let flushCalls = 0
|
||||
let flushTimeout: number | undefined
|
||||
let flushed = false
|
||||
let flushedBeforeExit = false
|
||||
let unregisterCleanup: (() => void) | undefined
|
||||
let restoreHooks: (() => void) | undefined
|
||||
let sessionEndHooksStarted = false
|
||||
let notifyExit!: () => void
|
||||
const exitObserved = new Promise<void>(resolve => { notifyExit = resolve })
|
||||
let notifyFlushStarted!: () => void
|
||||
const flushStarted = new Promise<void>(resolve => { notifyFlushStarted = resolve })
|
||||
let releaseFlush!: () => void
|
||||
const pendingFlush = new Promise<boolean>(resolve => {
|
||||
releaseFlush = () => {
|
||||
flushed = true
|
||||
resolve(true)
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
process.env.NODE_ENV = 'test'
|
||||
process.env.SENTRY_DSN = 'https://example@o0.ingest.sentry.io/0'
|
||||
await initializeSentry()
|
||||
const client = Sentry.getClient()
|
||||
assert(client, 'SDK was not initialized')
|
||||
// Keep the real SDK and application modules, replacing only the flush I/O.
|
||||
// No events are sent to the network in this fixture.
|
||||
client.flush = timeout => {
|
||||
flushCalls++
|
||||
flushTimeout = timeout
|
||||
if (mode === 'enabled' || mode === 'blocked') jest.useFakeTimers()
|
||||
notifyFlushStarted()
|
||||
if (mode === 'throws') throw new Error('flush threw')
|
||||
if (mode === 'rejects') return Promise.reject(new Error('flush rejected'))
|
||||
return pendingFlush
|
||||
}
|
||||
if (mode === 'dsn-unset') delete process.env.SENTRY_DSN
|
||||
if (mode === 'telemetry-disabled') process.env.DISABLE_TELEMETRY = '1'
|
||||
if (mode === 'nonessential-disabled') {
|
||||
process.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = '1'
|
||||
}
|
||||
if (mode === 'default-budget') {
|
||||
const hooks = await import('../../utils/hooks.js')
|
||||
assert.equal(hooks.getSessionEndHookTimeoutMs(), 1500)
|
||||
// Consume the real cleanup and default hook budgets before the Sentry drain.
|
||||
const hookSpy = spyOn(hooks, 'executeSessionEndHooks')
|
||||
.mockImplementation(() => sleep(1500))
|
||||
restoreHooks = () => { hookSpy.mockRestore() }
|
||||
unregisterCleanup = registerCleanup(() => sleep(2000))
|
||||
jest.useFakeTimers()
|
||||
}
|
||||
if (mode === 'failsafe' || mode === 'sync-rejection') {
|
||||
const hooks = await import('../../utils/hooks.js')
|
||||
if (mode === 'failsafe') {
|
||||
// A hook that ignores its abort signal leaves only the failsafe able to exit.
|
||||
const hookSpy = spyOn(hooks, 'executeSessionEndHooks').mockImplementation(() => {
|
||||
sessionEndHooksStarted = true
|
||||
return new Promise<void>(() => {})
|
||||
})
|
||||
restoreHooks = () => { hookSpy.mockRestore() }
|
||||
} else {
|
||||
// Fail before the failsafe is armed or the normal-path flush can run.
|
||||
const timeoutSpy = spyOn(hooks, 'getSessionEndHookTimeoutMs').mockImplementation(() => {
|
||||
throw new Error('shutdown setup failed')
|
||||
})
|
||||
restoreHooks = () => { timeoutSpy.mockRestore() }
|
||||
}
|
||||
jest.useFakeTimers()
|
||||
}
|
||||
|
||||
process.exit = ((code?: number) => {
|
||||
exitCode = code
|
||||
flushedBeforeExit = flushed
|
||||
notifyExit()
|
||||
// The failsafe runs in an async timer callback; avoid an unhandled rejection.
|
||||
if (mode === 'failsafe') return undefined as never
|
||||
throw exitError
|
||||
}) as typeof process.exit
|
||||
|
||||
let shutdown: Promise<void>
|
||||
if (mode === 'sync-rejection') {
|
||||
gracefulShutdownSync(7)
|
||||
const pending = getPendingShutdownForTesting()
|
||||
assert(pending, 'sync shutdown must expose its catch-handler completion')
|
||||
shutdown = pending
|
||||
} else {
|
||||
shutdown = gracefulShutdown(7).catch(error => {
|
||||
if (error !== exitError) throw error
|
||||
})
|
||||
}
|
||||
if (mode === 'failsafe') {
|
||||
// Drive the actual armed timer while the normal shutdown stays in its hook.
|
||||
for (let elapsed = 0; elapsed < 10_000 && flushCalls === 0; elapsed += 10) {
|
||||
jest.advanceTimersByTime(10)
|
||||
for (let i = 0; i < 20; i++) await Promise.resolve()
|
||||
}
|
||||
assert(sessionEndHooksStarted, 'normal shutdown must be stuck in its hook')
|
||||
assert.equal(flushCalls, 1, 'failsafe must begin a Sentry drain')
|
||||
}
|
||||
if (mode === 'default-budget') {
|
||||
// Advance through shutdown until the normal-path flush signals readiness.
|
||||
// Yield between ticks so each awaited shutdown stage can schedule its timers.
|
||||
for (let elapsed = 0; elapsed < 5000 && flushCalls === 0; elapsed += 10) {
|
||||
jest.advanceTimersByTime(10)
|
||||
for (let i = 0; i < 20; i++) await Promise.resolve()
|
||||
}
|
||||
assert.equal(flushCalls, 1, 'normal-path Sentry flush must start')
|
||||
assert.equal(exitCode, undefined, 'shutdown must wait for flush')
|
||||
// Cross the old 5s failsafe deadline while the normal flush is still pending.
|
||||
jest.advanceTimersByTime(1999)
|
||||
for (let i = 0; i < 20; i++) await Promise.resolve()
|
||||
assert.equal(flushCalls, 1, 'failsafe must not start another flush during the normal drain')
|
||||
assert.equal(exitCode, undefined, 'shutdown must not exit before the normal flush finishes')
|
||||
releaseFlush()
|
||||
}
|
||||
if (mode === 'enabled' || mode === 'blocked' || mode === 'failsafe' || mode === 'sync-rejection') {
|
||||
await Promise.race([
|
||||
flushStarted,
|
||||
shutdown.then(() => { throw new Error('exited without flushing Sentry') }),
|
||||
])
|
||||
assert.equal(exitCode, undefined, 'shutdown must wait for flush')
|
||||
jest.advanceTimersByTime(1999)
|
||||
// Let an incorrectly early deadline propagate through the awaited helpers.
|
||||
for (let i = 0; i < 5; i++) await Promise.resolve()
|
||||
assert.equal(exitCode, undefined, 'flush deadline must not expire early')
|
||||
if (mode === 'blocked') jest.advanceTimersByTime(1)
|
||||
else releaseFlush()
|
||||
}
|
||||
// The failsafe exits despite the deliberately hung hook in normal shutdown.
|
||||
if (mode === 'failsafe') await exitObserved
|
||||
else await shutdown
|
||||
console.log(JSON.stringify({ flushCalls, flushTimeout, exitCode, flushedBeforeExit }))
|
||||
} finally {
|
||||
unregisterCleanup?.()
|
||||
restoreHooks?.()
|
||||
jest.useRealTimers()
|
||||
process.exit = originalExit
|
||||
process.exitCode = 0
|
||||
resetShutdownState()
|
||||
restoreEnv()
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { expect, test } from 'bun:test'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
test.each([
|
||||
['enabled', 1, true],
|
||||
['default-budget', 1, true],
|
||||
['failsafe', 1, true],
|
||||
['sync-rejection', 1, true],
|
||||
['dsn-unset', 0, false],
|
||||
['telemetry-disabled', 0, false],
|
||||
['nonessential-disabled', 0, false],
|
||||
['blocked', 1, false],
|
||||
['throws', 1, false],
|
||||
['rejects', 1, false],
|
||||
] as const)('graceful shutdown handles Sentry flush: %s', async (mode, flushCalls, flushedBeforeExit) => {
|
||||
// Isolate SDK state, process.exit, and fake timers from the shared test runner.
|
||||
// The test deadline leaves time to collect output after the child deadline.
|
||||
const child = Bun.spawn([
|
||||
process.execPath,
|
||||
fileURLToPath(new URL('../test/fixtures/sentryShutdown.fixture.ts', import.meta.url)),
|
||||
mode,
|
||||
], {
|
||||
cwd: fileURLToPath(new URL('../../', import.meta.url)),
|
||||
stdout: 'pipe',
|
||||
stderr: 'pipe',
|
||||
timeout: 10_000,
|
||||
})
|
||||
const [stdout, stderr, exitCode] = await Promise.all([
|
||||
new Response(child.stdout).text(),
|
||||
new Response(child.stderr).text(),
|
||||
child.exited,
|
||||
])
|
||||
expect(stderr).toBe('')
|
||||
expect(exitCode).toBe(0)
|
||||
expect(JSON.parse(stdout)).toEqual({
|
||||
flushCalls,
|
||||
...(flushCalls ? { flushTimeout: 2000 } : {}),
|
||||
exitCode: 7,
|
||||
flushedBeforeExit,
|
||||
})
|
||||
}, 15_000)
|
||||
@@ -30,7 +30,11 @@ import {
|
||||
wrapForMultiplexer,
|
||||
} from '../ink/termio/osc.js'
|
||||
import { shutdownDatadog } from '../services/analytics/datadog.js'
|
||||
import { reportErrorToSentry } from './sentry.js'
|
||||
import {
|
||||
flushSentry,
|
||||
reportErrorToSentry,
|
||||
SENTRY_FLUSH_TIMEOUT_MS,
|
||||
} from './sentry.js'
|
||||
import {
|
||||
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
||||
logEvent,
|
||||
@@ -370,10 +374,11 @@ export function gracefulShutdownSync(
|
||||
process.exitCode = exitCode
|
||||
|
||||
pendingShutdown = gracefulShutdown(exitCode, reason, options)
|
||||
.catch(error => {
|
||||
.catch(async error => {
|
||||
logForDebugging(`Graceful shutdown failed: ${error}`, { level: 'error' })
|
||||
cleanupTerminalModes()
|
||||
printResumeHint()
|
||||
await flushSentry()
|
||||
forceExit(exitCode)
|
||||
})
|
||||
// Prevent unhandled rejection: forceExit re-throws in test mode,
|
||||
@@ -441,14 +446,16 @@ export async function gracefulShutdown(
|
||||
|
||||
// Failsafe: guarantee process exits even if cleanup hangs (e.g., MCP connections).
|
||||
// Runs cleanupTerminalModes first so a hung cleanup doesn't leave the terminal dirty.
|
||||
// Budget = max(5s, hook budget + 3.5s headroom for cleanup + analytics flush).
|
||||
// Budget = max(5s, hook budget + 3.5s cleanup/analytics headroom + Sentry drain).
|
||||
// If cleanup hangs, the failsafe gives Sentry one bounded drain before exit.
|
||||
failsafeTimer = setTimeout(
|
||||
code => {
|
||||
async code => {
|
||||
cleanupTerminalModes(true)
|
||||
printResumeHint()
|
||||
await flushSentry()
|
||||
forceExit(code)
|
||||
},
|
||||
Math.max(5000, sessionEndTimeoutMs + 3500),
|
||||
Math.max(5000, sessionEndTimeoutMs + 3500 + SENTRY_FLUSH_TIMEOUT_MS),
|
||||
exitCode,
|
||||
)
|
||||
failsafeTimer.unref()
|
||||
@@ -558,6 +565,7 @@ export async function gracefulShutdown(
|
||||
flushInterruptionTrace('graceful_shutdown')
|
||||
await Promise.race([waitForInterruptionTraceFlush(), sleep(500)])
|
||||
|
||||
await flushSentry()
|
||||
forceExit(exitCode)
|
||||
}
|
||||
|
||||
|
||||
+73
-40
@@ -1,25 +1,20 @@
|
||||
import { afterEach, beforeEach, expect, mock, test } from 'bun:test'
|
||||
import { afterEach, beforeEach, expect, test } from 'bun:test'
|
||||
import { hostname } from 'node:os'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { snapshotEnv } from '../test/envSnapshot.js'
|
||||
|
||||
const ORIGINAL_SENTRY_DSN = process.env.SENTRY_DSN
|
||||
const ORIGINAL_DISABLE_TELEMETRY = process.env.DISABLE_TELEMETRY
|
||||
let restoreEnv: () => void
|
||||
|
||||
beforeEach(() => {
|
||||
delete process.env.SENTRY_DSN
|
||||
delete process.env.DISABLE_TELEMETRY
|
||||
restoreEnv = snapshotEnv([
|
||||
'SENTRY_DSN',
|
||||
'DISABLE_TELEMETRY',
|
||||
'CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC',
|
||||
], { clear: true })
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
if (ORIGINAL_SENTRY_DSN === undefined) {
|
||||
delete process.env.SENTRY_DSN
|
||||
} else {
|
||||
process.env.SENTRY_DSN = ORIGINAL_SENTRY_DSN
|
||||
}
|
||||
if (ORIGINAL_DISABLE_TELEMETRY === undefined) {
|
||||
delete process.env.DISABLE_TELEMETRY
|
||||
} else {
|
||||
process.env.DISABLE_TELEMETRY = ORIGINAL_DISABLE_TELEMETRY
|
||||
}
|
||||
mock.restore()
|
||||
restoreEnv()
|
||||
})
|
||||
|
||||
test('isSentryEnabled is false when SENTRY_DSN is unset', async () => {
|
||||
@@ -40,6 +35,13 @@ test('isSentryEnabled is false when SENTRY_DSN is set but DISABLE_TELEMETRY is s
|
||||
expect(isSentryEnabled()).toBe(false)
|
||||
})
|
||||
|
||||
test('isSentryEnabled is false when SENTRY_DSN is set but CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC is set', async () => {
|
||||
process.env.SENTRY_DSN = 'https://example@o0.ingest.sentry.io/0'
|
||||
process.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = '1'
|
||||
const { isSentryEnabled } = await import('./sentry.js')
|
||||
expect(isSentryEnabled()).toBe(false)
|
||||
})
|
||||
|
||||
test('reportErrorToSentry does not throw when Sentry is disabled', async () => {
|
||||
const { reportErrorToSentry } = await import('./sentry.js')
|
||||
const { TelemetrySafeError_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS: TelemetrySafeError } =
|
||||
@@ -60,28 +62,59 @@ test('reportErrorToSentry does not throw for a plain (non-sanitized) Error', asy
|
||||
).not.toThrow()
|
||||
})
|
||||
|
||||
test('reportErrorToSentry only reports TelemetrySafeError, never a raw Error message', async () => {
|
||||
process.env.SENTRY_DSN = 'https://example@o0.ingest.sentry.io/0'
|
||||
test('reportErrorToSentry only reports sanitized messages without stacks using the real SDK', async () => {
|
||||
// A fresh process avoids shared SDK state and module mocks from other tests.
|
||||
// Leave time for the child deadline and reading its output during cleanup.
|
||||
const child = Bun.spawn([process.execPath, '--eval', `
|
||||
import * as Sentry from '@sentry/node'
|
||||
import { flushSentry, initializeSentry, reportErrorToSentry } from '${new URL('./sentry.ts', import.meta.url).href}'
|
||||
import { TelemetrySafeError_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS as TelemetrySafeError } from '${new URL('./errors.ts', import.meta.url).href}'
|
||||
|
||||
const captureMessage = mock(() => {})
|
||||
mock.module('@sentry/node', () => ({
|
||||
init: mock(() => {}),
|
||||
captureMessage,
|
||||
}))
|
||||
|
||||
const { initializeSentry, reportErrorToSentry } = await import('./sentry.js')
|
||||
const { TelemetrySafeError_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS: TelemetrySafeError } =
|
||||
await import('./errors.js')
|
||||
|
||||
await initializeSentry()
|
||||
|
||||
// A plain Error must never be reported — its message may contain file paths.
|
||||
reportErrorToSentry(new Error('raw error with /some/file/path'))
|
||||
expect(captureMessage).not.toHaveBeenCalled()
|
||||
|
||||
// A TelemetrySafeError reports only its sanitized telemetryMessage.
|
||||
reportErrorToSentry(
|
||||
new TelemetrySafeError('full message with /some/file/path', 'sanitized message'),
|
||||
)
|
||||
expect(captureMessage).toHaveBeenCalledWith('sanitized message', 'error')
|
||||
})
|
||||
await initializeSentry()
|
||||
const client = Sentry.getClient()
|
||||
if (!client) throw new Error('SDK was not initialized')
|
||||
const transport = client.getTransport()
|
||||
if (!transport) throw new Error('SDK transport was not initialized')
|
||||
const events = []
|
||||
// Inspect outgoing envelopes without sending any network requests.
|
||||
transport.send = async envelope => {
|
||||
for (const [header, event] of envelope[1]) {
|
||||
if (header.type === 'event') events.push(event)
|
||||
}
|
||||
return { statusCode: 200 }
|
||||
}
|
||||
reportErrorToSentry(new Error('raw error with /some/file/path'))
|
||||
reportErrorToSentry(new TelemetrySafeError('full message with /some/file/path', 'sanitized message'))
|
||||
await flushSentry()
|
||||
const options = client.getOptions()
|
||||
console.log(JSON.stringify({ events, integrations: options.integrations.map(i => i.name), tracesSampleRate: options.tracesSampleRate }))
|
||||
await Sentry.close(1000)
|
||||
`], {
|
||||
cwd: fileURLToPath(new URL('../../', import.meta.url)),
|
||||
env: { ...process.env, SENTRY_DSN: 'https://example@o0.ingest.sentry.io/0' },
|
||||
stdout: 'pipe',
|
||||
stderr: 'pipe',
|
||||
timeout: 10_000,
|
||||
})
|
||||
const [stdout, stderr, exitCode] = await Promise.all([
|
||||
new Response(child.stdout).text(),
|
||||
new Response(child.stderr).text(),
|
||||
child.exited,
|
||||
])
|
||||
expect(stderr).toBe('')
|
||||
expect(exitCode).toBe(0)
|
||||
const result = JSON.parse(stdout)
|
||||
expect(result.integrations).toEqual([])
|
||||
expect(result.tracesSampleRate).toBeUndefined()
|
||||
expect(result.events).toHaveLength(1)
|
||||
expect(result.events[0].message).toBe('sanitized message')
|
||||
expect(result.events[0].level).toBe('error')
|
||||
expect(result.events[0].exception).toBeUndefined()
|
||||
expect(result.events[0].stacktrace).toBeUndefined()
|
||||
expect(result.events[0].user).toBeUndefined()
|
||||
expect(result.events[0].request).toBeUndefined()
|
||||
expect(result.events[0].server_name).toBeUndefined()
|
||||
expect(result.events[0].hostname).toBeUndefined()
|
||||
expect(stdout).not.toContain(hostname())
|
||||
expect(stdout).not.toContain('/some/file/path')
|
||||
}, 15_000)
|
||||
|
||||
+48
-2
@@ -9,6 +9,9 @@
|
||||
*/
|
||||
import { isTelemetryDisabled } from './privacyLevel.js'
|
||||
import { TelemetrySafeError_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS as TelemetrySafeError } from './errors.js'
|
||||
import { sleep } from './sleep.js'
|
||||
|
||||
export const SENTRY_FLUSH_TIMEOUT_MS = 2000
|
||||
|
||||
let sentryInitialized = false
|
||||
let sentryModule: typeof import('@sentry/node') | null = null
|
||||
@@ -36,7 +39,30 @@ export async function initializeSentry(): Promise<void> {
|
||||
sentryModule.init({
|
||||
dsn: process.env.SENTRY_DSN,
|
||||
environment: process.env.NODE_ENV ?? 'production',
|
||||
tracesSampleRate: 0,
|
||||
// Leave tracing sample options unset; even a zero rate enables span recording.
|
||||
// Keep v11's span streaming and runtime instrumentation out of this path.
|
||||
traceLifecycle: 'static',
|
||||
enableOpenTelemetrySetup: false,
|
||||
enableRuntimeChannelInjection: false,
|
||||
// v11 attaches synthetic stacks to messages and collects more data by
|
||||
// default. Keep this reporter limited to the vetted message.
|
||||
attachStacktrace: false,
|
||||
// The SDK otherwise adds os.hostname() as server_name to every event.
|
||||
includeServerName: false,
|
||||
dataCollection: {
|
||||
userInfo: false,
|
||||
cookies: false,
|
||||
httpHeaders: false,
|
||||
httpBodies: [],
|
||||
urlQueryParams: false,
|
||||
graphQL: { document: false, variables: false },
|
||||
genAI: { inputs: false, outputs: false },
|
||||
mcp: { inputs: false, outputs: false },
|
||||
databaseQueryData: false,
|
||||
queues: false,
|
||||
stackFrameVariables: false,
|
||||
frameContextLines: 0,
|
||||
},
|
||||
// Disable Sentry's automatic uncaughtException/unhandledRejection
|
||||
// integrations. Those hooks report raw error content, bypassing the
|
||||
// TelemetrySafeError sanitization in reportErrorToSentry(). Only
|
||||
@@ -69,4 +95,24 @@ export function reportErrorToSentry(error: unknown): void {
|
||||
} catch {
|
||||
// Reporting must never throw.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Drain opted-in reports before exit, without allowing the SDK to delay shutdown indefinitely. */
|
||||
export async function flushSentry(): Promise<void> {
|
||||
if (!sentryModule || !isSentryEnabled()) {
|
||||
return
|
||||
}
|
||||
|
||||
const deadline = new AbortController()
|
||||
try {
|
||||
// The SDK timeout does not bound every stage of its flush pipeline.
|
||||
await Promise.race([
|
||||
sentryModule.flush(SENTRY_FLUSH_TIMEOUT_MS),
|
||||
sleep(SENTRY_FLUSH_TIMEOUT_MS, deadline.signal),
|
||||
])
|
||||
} catch {
|
||||
// Reporting failures must never prevent process exit.
|
||||
} finally {
|
||||
deadline.abort()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user